/*
 * Copyright (c) 2003-2011
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 *
 * $Id: icx.h 2528 2011-09-23 21:54:05Z brachman $
 */

/*
 * DACS InfoCard XML support
 *
 * This depends on support from libxml2 (the XML toolkit from the GNOME
 * project) and xmlsec1 (the XMLSec Library); the latter is configured to use
 * OpenSSL.
 */

#ifndef _ICX_H
#define _ICX_H

#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/xmlschemas.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

#include <xmlsec/xmlsec.h>
#include <xmlsec/xmltree.h>
#include <xmlsec/xmlenc.h>
#include <xmlsec/xmldsig.h>
#include <xmlsec/x509.h>
#include <xmlsec/crypto.h>
#include <xmlsec/errors.h>

#include "dacs.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include <openssl/ssl.h>

#define SAML_TOKEN_MAJOR_VERSION	"1"
#define SAML_TOKEN_MINOR_VERSION	"1"

/*
 * Note: xmlChar is defined as 'unsigned char' in
 * include/libxml2/libxml/xmlstring.h from libxml2.
 */

/* The namespace URI for standard InfoCard claims. */
#define ICX_STANDARD_CLAIM_URI	\
  "http://schemas.xmlsoap.org/ws/2005/05/identity/claims"

/* The namespace URI for a DACS-specific InfoCard claim. */
#define ICX_DACS_CLAIM_URI		"http://dacs.dss.ca/claims"

/* The namespace URI for a DACS-specific InfoCard claim set. */
#define ICX_DACS_CLAIMSET_URI	"http://dacs.dss.ca/claimset"

/* */
#define ICX_SELF_ISSUED_ISSUER_URI \
  (xmlChar *) "http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self"

typedef enum {
  ICX_STANDARD_CLAIM  = 0,
  ICX_DACS_CLAIM      = 1,
  ICX_USER_CLAIM      = 2,
  ICX_PSEUDO_CLAIM    = 3,
  ICX_UNDEF_CLAIM     = 4
} Icx_claim_type;

typedef struct Icx_claim {
  Icx_claim_type type;
  char *uri;
  char *name;
  char *label;			/* ic:DisplayTag */
  char *description;	/* ic:Description or NULL */
  char *value;			/* saml:AttributeValue, ic:DisplayValue, or NULL */
} Icx_claim;

/*
 * Managed InfoCard definitions returned by INFOCARD_CARD_DEFS_URL.
 */
typedef struct Icx_card_defs {
  char *ppid;			/* Unique, presumably */
  char *card_id;		/* Any URI */
  char *card_version;
  char *card_name;		/* Needs to be short */
  Dsvec *claims;
} Icx_card_defs;

typedef enum {
  STS_REQUEST_MESSAGE_ID    = 0,
  STS_REQUEST_TO            = 1,
  STS_REQUEST_EXPIRES       = 2,
  STS_REQUEST_USERNAME      = 3,
  STS_REQUEST_PASSWORD      = 4,
  STS_REQUEST_SECTOKEN      = 5,
  STS_REQUEST_CARDID        = 6,
  STS_REQUEST_CARDVERSION   = 7,
  STS_REQUEST_PPID          = 8,
  STS_REQUEST_ENCDATA       = 9,
  STS_REQUEST_APPLIES_TO    = 10,
  STS_REQUEST_KEY_TYPE      = 11,
  STS_REQUEST_USE_KEY       = 12,
  STS_REQUEST_BINARY_SECRET = 13,
  STS_REQUEST_UNDEF         = 14
} Sts_request_el;

typedef enum {
  STS_REQUEST_REQ_INFO    = 1,	/* Required element content */
  STS_REQUEST_OPT_INFO    = 2,	/* Optional element content */
  STS_REQUEST_REQ_NODE    = 3,	/* A required element */
  STS_REQUEST_OPT_NODE    = 4,	/* An optional element */
  STS_REQUEST_ERR_INFO    = 5
} Sts_request_status;

typedef struct Sts_request {
  Sts_request_el el;
  Sts_request_status status;
  xmlChar *name;
  xmlChar *value;
  xmlNodePtr node;
} Sts_request;

/*
 * All error codes must be negative.
 */
typedef enum {
  STS_NO_ERR           = 0,
  STS_APPLIES_TO_ERR   = -1,
  STS_PROOF_KEY_ERR    = -2,
  STS_INFOCARD_REF_ERR = -3,
  STS_REQ_CLAIMS_ERR   = -4,
  STS_REFRESH_ERR      = -5,
  STS_CUSTOM_ERR       = -6
} Sts_error_type;

enum {
  ICX_DEFAULT_DRIFT_SECS       = (5 * 60),
  ICX_DEFAULT_MAX_TOKEN_SIZE   = 16384
};

typedef struct Icx_time_conditions {
  int max_fast_clock_adj_secs;		/* How much too fast our clock can be */
  int max_slow_clock_adj_secs;		/* How much too slow our clock can be */
} Icx_time_conditions;

typedef struct Icx_context_t Icx_ctx;
typedef int (*Icx_replay_detection_func)(Icx_ctx *ctx,
										const xmlChar *replay_value,
										time_t not_on_or_after,
										void *detector_context);
typedef int (*Icx_token_processing_func)(Icx_ctx *ctx, const xmlChar *input,
										size_t input_len);

struct Icx_context_t {
  time_t now;						/* Instant at which to evaluate validity */
  xmlSecKeysMngrPtr key_manager;
  Icx_replay_detection_func replay_detector;
  void *replay_detector_arg;
  Icx_token_processing_func processor;
  size_t max_token_size;
  Dsvec *audience;					/* Vector of (char *) */
  Icx_time_conditions time_conditions;
  int validate_token_replay;
  int validate_message_conditions;
  int validate_self_issued;
  xmlChar *issuer;					/* self-issued (NULL) or managed */
  int enable_signature_validation;
  Ic_token *token;
};

static inline int
xmlStreq(const xmlChar *p, const xmlChar *q)
{

  return(xmlStrcmp(p, q) == 0);
}

static inline int
xmlStrneq(const xmlChar *p, const xmlChar *q, int n)
{

  return(xmlStrncmp(p, q, n) == 0);
}

static inline xmlChar *
xmlStrprefix(const xmlChar *str, const xmlChar *prefix)
{
  int len;

  len = xmlStrlen(prefix);
  if (xmlStrneq(str, prefix, len))
	return((xmlChar *) (str + len));
  return(NULL);
}

#ifdef __cplusplus
extern "C" {
#endif

extern Icx_ctx *icx_ctx_create(void);
extern void icx_ctx_destroy(Icx_ctx *ctx);
extern void icx_free(void);

extern time_t icx_get_current_time(Icx_ctx *ctx);
extern Ds *icx_friendly_identifier(Ds *xppid, int do_decode);
extern time_t icx_get_current_time(Icx_ctx *ctx);
extern int icx_init(void);
extern int icx_is_in_audience(Icx_ctx *ctx, const xmlChar *audience);
extern int icx_load_certificate(Icx_ctx *ctx, const char *cert_file_name);
extern int icx_load_key(Icx_ctx *ctx, const char *key_file_name,
						const char *password);
extern int icx_load_pkcs12(Icx_ctx *ctx, const char *pkcs12_file_name,
						   const char *password);
extern int icx_process_token(Icx_ctx *ctx, const xmlChar *token,
							 size_t token_len);
extern int icx_sam1l_process_token(Icx_ctx *ctx, const unsigned char *input,
								   size_t input_len);
extern int icx_add_audience(Icx_ctx *ctx, char *audience);
extern Dsvec *icx_get_audience(Icx_ctx *ctx);
extern void icx_set_audience(Icx_ctx *ctx, Dsvec *audience);
extern int icx_set_config_audience(Icx_ctx *ctx);
extern int icx_match_uri(char *pat, char *uri_str);
extern void icx_set_current_time(Icx_ctx *ctx, time_t current);
extern void icx_set_max_token_size(Icx_ctx *ctx, size_t max_token_size);
extern void icx_set_replay_detection(Icx_ctx *ctx,
									 Icx_replay_detection_func detector,
									 void *detector_arg);
extern void icx_set_time_conditions(Icx_ctx *ctx, int max_slow_clock_adj_secs,
									int max_fast_clock_adj_secs);
extern void icx_set_token_processor(Icx_ctx *ctx,
									Icx_token_processing_func processor);
extern void icx_set_current_time(Icx_ctx *ctx, time_t current);

extern Icx_claim *icx_new_claim(void);
extern Sts_error_type icx_fill_claim_values(Sts_request *req, char *item_type,
											char *card_id, char *ppid,
											char *federation_name,
											char *jurisdiction_name,
											Dsvec *claims);
extern Icx_claim *icx_lookup_claim(Dsvec *claims, char *uri, char *name);
extern Icx_claim *icx_find_standard_claim(char *name);
extern int icx_get_card_defs(char *identity, Icx_card_defs *cd,
							 char *federation_name, char *jurisdiction_name);
extern Icx_claim *icx_get_claim_value(char *username, char *claim_name);
extern Icx_claim_type icx_lookup_claim_type(char *uri);

extern Ds *icx_canonicalize_xml(Ds *xml);

extern char *icx_gmdatetime(time_t t, long delta_secs);

extern Icx_ctx *ic_init(Ic_config *conf);
extern Ic_token *ic_parse_token(Icx_ctx *ctx, char *xmlToken);

extern char *xmlPathStr(xmlNodePtr node);
extern xmlNodePtr xmlGetChild(xmlNodePtr el, xmlChar *el_name);
extern char *xmlGetChildText(xmlNodePtr el, xmlChar *el_name);
extern char *xmlGetAttrValue(xmlNodePtr el, xmlChar *attr_name);

#ifdef __cplusplus
}
#endif

#endif
