diff options
Diffstat (limited to 'source4/heimdal')
176 files changed, 30855 insertions, 2843 deletions
diff --git a/source4/heimdal/cf/check-var.m4 b/source4/heimdal/cf/check-var.m4 index 41401f6dd9..b33b5c6e28 100644 --- a/source4/heimdal/cf/check-var.m4 +++ b/source4/heimdal/cf/check-var.m4 @@ -23,3 +23,5 @@ if test "$ac_foo" = yes; then fi ]) +AC_WARNING_ENABLE([obsolete]) +AU_DEFUN([AC_CHECK_VAR], [rk_CHECK_VAR([$2], [$1])], [foo]) diff --git a/source4/heimdal/kdc/digest.c b/source4/heimdal/kdc/digest.c index a5517fb896..2c012a2ead 100644 --- a/source4/heimdal/kdc/digest.c +++ b/source4/heimdal/kdc/digest.c @@ -32,10 +32,112 @@ */ #include "kdc_locl.h" -#include <digest_asn1.h> #include <hex.h> -RCSID("$Id: digest.c,v 1.7 2006/10/22 20:11:44 lha Exp $"); +RCSID("$Id: digest.c,v 1.19 2006/12/28 17:03:51 lha Exp $"); + +#define CHAP_MD5 0x10 +#define DIGEST_MD5 0x08 +#define NTLM_V2 0x04 +#define NTLM_V1_SESSION 0x02 +#define NTLM_V1 0x01 + +const struct units _kdc_digestunits[] = { + {"chap-md5", 1U << 4}, + {"digest-md5", 1U << 3}, + {"ntlm-v2", 1U << 2}, + {"ntlm-v1-session", 1U << 1}, + {"ntlm-v1", 1U << 0}, + {NULL, 0} +}; + + +static krb5_error_code +get_digest_key(krb5_context context, + krb5_kdc_configuration *config, + hdb_entry_ex *server, + krb5_crypto *crypto) +{ + krb5_error_code ret; + krb5_enctype enctype; + Key *key; + + ret = _kdc_get_preferred_key(context, + config, + server, + "digest-service", + &enctype, + &key); + if (ret) + return ret; + return krb5_crypto_init(context, &key->key, 0, crypto); +} + +/* + * + */ + +static char * +get_ntlm_targetname(krb5_context context, + hdb_entry_ex *client) +{ + char *targetname, *p; + + targetname = strdup(krb5_principal_get_realm(context, + client->entry.principal)); + if (targetname == NULL) + return NULL; + + p = strchr(targetname, '.'); + if (p) + *p = '\0'; + + strupr(targetname); + return targetname; +} + +static krb5_error_code +fill_targetinfo(krb5_context context, + char *targetname, + hdb_entry_ex *client, + krb5_data *data) +{ + struct ntlm_targetinfo ti; + krb5_error_code ret; + struct ntlm_buf d; + krb5_principal p; + const char *str; + + memset(&ti, 0, sizeof(ti)); + + ti.domainname = targetname; + p = client->entry.principal; + str = krb5_principal_get_comp_string(context, p, 0); + if (str != NULL && + (strcmp("host", str) == 0 || + strcmp("ftp", str) == 0 || + strcmp("imap", str) == 0 || + strcmp("pop", str) == 0 || + strcmp("smtp", str))) + { + str = krb5_principal_get_comp_string(context, p, 1); + ti.dnsservername = rk_UNCONST(str); + } + + ret = heim_ntlm_encode_targetinfo(&ti, 1, &d); + if (ret) + return ret; + + data->data = d.data; + data->length = d.length; + + return 0; +} + + +/* + * + */ krb5_error_code _kdc_do_digest(krb5_context context, @@ -57,11 +159,13 @@ _kdc_do_digest(krb5_context context, krb5_storage *sp = NULL; Checksum res; hdb_entry_ex *server = NULL, *user = NULL; - char *password = NULL; + hdb_entry_ex *client = NULL; + char *client_name = NULL, *password = NULL; krb5_data serverNonce; if(!config->enable_digest) { - kdc_log(context, config, 0, "Rejected digest request from %s", from); + kdc_log(context, config, 0, + "Rejected digest request (disabled) from %s", from); return KRB5KDC_ERR_POLICY; } @@ -125,6 +229,7 @@ _kdc_do_digest(krb5_context context, krb5_free_principal(context, principal); goto out; } + krb5_clear_error_string(context); ret = _kdc_db_fetch(context, config, principal, HDB_F_GET_SERVER, NULL, &server); @@ -137,12 +242,17 @@ _kdc_do_digest(krb5_context context, /* check the client is allowed to do digest auth */ { krb5_principal principal = NULL; - hdb_entry_ex *client; ret = krb5_ticket_get_client(context, ticket, &principal); if (ret) goto out; + ret = krb5_unparse_name(context, principal, &client_name); + if (ret) { + krb5_free_principal(context, principal); + goto out; + } + ret = _kdc_db_fetch(context, config, principal, HDB_F_GET_CLIENT, NULL, &client); krb5_free_principal(context, principal); @@ -150,13 +260,15 @@ _kdc_do_digest(krb5_context context, goto out; if (client->entry.flags.allow_digest == 0) { + kdc_log(context, config, 0, + "Client %s tried to use digest " + "but is not allowed to", + client_name); krb5_set_error_string(context, "Client is not permitted to use digest"); ret = KRB5KDC_ERR_POLICY; - _kdc_free_ent (context, client); goto out; } - _kdc_free_ent (context, client); } /* unpack request */ @@ -192,6 +304,9 @@ _kdc_do_digest(krb5_context context, goto out; } + kdc_log(context, config, 0, "Valid digest request from %s (%s)", + client_name, from); + /* * Process the inner request */ @@ -289,22 +404,9 @@ _kdc_do_digest(krb5_context context, goto out; } - { - Key *key; - krb5_enctype enctype; - - ret = _kdc_get_preferred_key(context, - config, - server, - "digest-service", - &enctype, - &key); - if (ret) - goto out; - ret = krb5_crypto_init(context, &key->key, 0, &crypto); - if (ret) - goto out; - } + ret = get_digest_key(context, config, server, &crypto); + if (ret) + goto out; ret = krb5_create_checksum(context, crypto, @@ -337,6 +439,9 @@ _kdc_do_digest(krb5_context context, goto out; } + kdc_log(context, config, 0, "Digest %s init request successful from %s", + ireq.u.init.type, from); + break; } case choice_DigestReqInner_digestRequest: { @@ -349,7 +454,11 @@ _kdc_do_digest(krb5_context context, krb5_set_error_string(context, "out of memory"); goto out; } - krb5_store_stringz(sp, ireq.u.digestRequest.type); + ret = krb5_store_stringz(sp, ireq.u.digestRequest.type); + if (ret) { + krb5_clear_error_string(context); + goto out; + } krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce); if (ireq.u.digestRequest.identifier) { @@ -421,22 +530,9 @@ _kdc_do_digest(krb5_context context, serverNonce.length = ssize; } - { - Key *key; - krb5_enctype enctype; - - ret = _kdc_get_preferred_key(context, - config, - server, - "digest-service", - &enctype, - &key); - if (ret) - goto out; - ret = krb5_crypto_init(context, &key->key, 0, &crypto); - if (ret) - goto out; - } + ret = get_digest_key(context, config, server, &crypto); + if (ret) + goto out; ret = krb5_verify_checksum(context, crypto, KRB5_KU_DIGEST_OPAQUE, @@ -493,6 +589,11 @@ _kdc_do_digest(krb5_context context, unsigned char md[MD5_DIGEST_LENGTH]; char id; + if ((config->digests_allowed & CHAP_MD5) == 0) { + kdc_log(context, config, 0, "Digest CHAP MD5 not allowed"); + goto out; + } + if (ireq.u.digestRequest.identifier == NULL) { krb5_set_error_string(context, "Identifier missing " "from CHAP request"); @@ -524,6 +625,11 @@ _kdc_do_digest(krb5_context context, unsigned char md[MD5_DIGEST_LENGTH]; char *A1, *A2; + if ((config->digests_allowed & DIGEST_MD5) == 0) { + kdc_log(context, config, 0, "Digest SASL MD5 not allowed"); + goto out; + } + if (ireq.u.digestRequest.nonceCount == NULL) goto out; if (ireq.u.digestRequest.clientNonce == NULL) @@ -627,6 +733,358 @@ _kdc_do_digest(krb5_context context, r.u.error.code = EINVAL; } + kdc_log(context, config, 0, "Digest %s request successful %s", + ireq.u.digestRequest.type, from); + + break; + } + case choice_DigestReqInner_ntlmInit: + + if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) { + kdc_log(context, config, 0, "NTLM not allowed"); + goto out; + } + + + r.element = choice_DigestRepInner_ntlmInitReply; + + r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE; + + if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) { + kdc_log(context, config, 0, "NTLM client have no unicode"); + goto out; + } + + if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM) + r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM; + else { + kdc_log(context, config, 0, "NTLM client doesn't support NTLM"); + goto out; + } + + r.u.ntlmInitReply.flags |= + NTLM_NEG_TARGET_DOMAIN | + NTLM_ENC_128; + +#define ALL \ + NTLM_NEG_SIGN| \ + NTLM_NEG_SEAL| \ + NTLM_NEG_ALWAYS_SIGN| \ + NTLM_NEG_NTLM2_SESSION| \ + NTLM_NEG_KEYEX + + r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL)); + +#undef ALL + + r.u.ntlmInitReply.targetname = + get_ntlm_targetname(context, client); + if (r.u.ntlmInitReply.targetname == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + r.u.ntlmInitReply.challange.data = malloc(8); + if (r.u.ntlmInitReply.challange.data == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + r.u.ntlmInitReply.challange.length = 8; + if (RAND_bytes(r.u.ntlmInitReply.challange.data, + r.u.ntlmInitReply.challange.length) != 1) + { + krb5_set_error_string(context, "out of random error"); + ret = ENOMEM; + goto out; + } + /* XXX fix targetinfo */ + ALLOC(r.u.ntlmInitReply.targetinfo); + if (r.u.ntlmInitReply.targetinfo == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + + ret = fill_targetinfo(context, + r.u.ntlmInitReply.targetname, + client, + r.u.ntlmInitReply.targetinfo); + if (ret) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + + /* + * Save data encryted in opaque for the second part of the + * ntlm authentication + */ + sp = krb5_storage_emem(); + if (sp == NULL) { + ret = ENOMEM; + krb5_set_error_string(context, "out of memory"); + goto out; + } + + ret = krb5_storage_write(sp, r.u.ntlmInitReply.challange.data, 8); + if (ret != 8) { + ret = ENOMEM; + krb5_set_error_string(context, "storage write challange"); + goto out; + } + ret = krb5_store_uint32(sp, r.u.ntlmInitReply.flags); + if (ret) { + krb5_clear_error_string(context); + goto out; + } + + ret = krb5_storage_to_data(sp, &buf); + if (ret) { + krb5_clear_error_string(context); + goto out; + } + + ret = get_digest_key(context, config, server, &crypto); + if (ret) + goto out; + + ret = krb5_encrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, + buf.data, buf.length, &r.u.ntlmInitReply.opaque); + krb5_data_free(&buf); + krb5_crypto_destroy(context, crypto); + crypto = NULL; + if (ret) + goto out; + + kdc_log(context, config, 0, "NTLM init from %s", from); + + break; + + case choice_DigestReqInner_ntlmRequest: { + krb5_principal clientprincipal; + unsigned char sessionkey[16]; + unsigned char challange[8]; + uint32_t flags; + Key *key = NULL; + int version; + + r.element = choice_DigestRepInner_ntlmResponse; + r.u.ntlmResponse.success = 0; + r.u.ntlmResponse.flags = 0; + r.u.ntlmResponse.sessionkey = NULL; + r.u.ntlmResponse.tickets = NULL; + + /* get username */ + ret = krb5_parse_name(context, + ireq.u.ntlmRequest.username, + &clientprincipal); + if (ret) + goto out; + + ret = _kdc_db_fetch(context, config, clientprincipal, + HDB_F_GET_CLIENT, NULL, &user); + krb5_free_principal(context, clientprincipal); + if (ret) { + krb5_set_error_string(context, "NTLM user %s not in database", + ireq.u.ntlmRequest.username); + goto out; + } + + ret = get_digest_key(context, config, server, &crypto); + if (ret) + goto out; + + ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, + ireq.u.ntlmRequest.opaque.data, + ireq.u.ntlmRequest.opaque.length, &buf); + krb5_crypto_destroy(context, crypto); + crypto = NULL; + if (ret) + goto out; + + sp = krb5_storage_from_data(&buf); + if (sp == NULL) { + ret = ENOMEM; + krb5_set_error_string(context, "out of memory"); + goto out; + } + + ret = krb5_storage_read(sp, challange, sizeof(challange)); + if (ret != sizeof(challange)) { + krb5_set_error_string(context, "NTLM storage read challange"); + ret = ENOMEM; + goto out; + } + ret = krb5_ret_uint32(sp, &flags); + if (ret) { + krb5_set_error_string(context, "NTLM storage read flags"); + goto out; + } + krb5_data_free(&buf); + + if ((flags & NTLM_NEG_NTLM) == 0) { + ret = EINVAL; + krb5_set_error_string(context, "NTLM not negotiated"); + goto out; + } + + ret = hdb_enctype2key(context, &user->entry, + ETYPE_ARCFOUR_HMAC_MD5, &key); + if (ret) { + krb5_set_error_string(context, "NTLM missing arcfour key"); + goto out; + } + + /* check if this is NTLMv2 */ + if (ireq.u.ntlmRequest.ntlm.length != 24) { + struct ntlm_buf infotarget, answer; + char *targetname; + + if ((config->digests_allowed & NTLM_V2) == 0) { + kdc_log(context, config, 0, "NTLM v2 not allowed"); + goto out; + } + + version = 2; + + targetname = get_ntlm_targetname(context, client); + if (targetname == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + + answer.length = ireq.u.ntlmRequest.ntlm.length; + answer.data = ireq.u.ntlmRequest.ntlm.data; + + ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, + key->key.keyvalue.length, + ireq.u.ntlmRequest.username, + targetname, + 0, + challange, + &answer, + &infotarget, + sessionkey); + free(targetname); + if (ret) { + krb5_set_error_string(context, "NTLM v2 verify failed"); + goto out; + } + + /* XXX verify infotarget matches client (checksum ?) */ + + free(infotarget.data); + /* */ + + } else { + struct ntlm_buf answer; + + version = 1; + + if (flags & NTLM_NEG_NTLM2_SESSION) { + char sessionhash[MD5_DIGEST_LENGTH]; + MD5_CTX md5ctx; + + if ((config->digests_allowed & NTLM_V1_SESSION) == 0) { + kdc_log(context, config, 0, "NTLM v1-session not allowed"); + goto out; + } + + if (ireq.u.ntlmRequest.lm.length != 24) { + krb5_set_error_string(context, "LM hash have wrong length " + "for NTLM session key"); + ret = EINVAL; + goto out; + } + + MD5_Init(&md5ctx); + MD5_Update(&md5ctx, challange, sizeof(challange)); + MD5_Update(&md5ctx, ireq.u.ntlmRequest.lm.data, 8); + MD5_Final(sessionhash, &md5ctx); + memcpy(challange, sessionhash, sizeof(challange)); + } else { + if ((config->digests_allowed & NTLM_V1) == 0) { + kdc_log(context, config, 0, "NTLM v1 not allowed"); + goto out; + } + } + + ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, + key->key.keyvalue.length, + challange, &answer); + if (ret) { + krb5_set_error_string(context, "NTLM missing arcfour key"); + goto out; + } + + if (ireq.u.ntlmRequest.ntlm.length != answer.length || + memcmp(ireq.u.ntlmRequest.ntlm.data, answer.data, answer.length) != 0) + { + free(answer.data); + ret = EINVAL; + krb5_set_error_string(context, "NTLM hash mismatch"); + goto out; + } + free(answer.data); + + { + MD4_CTX ctx; + + MD4_Init(&ctx); + MD4_Update(&ctx, + key->key.keyvalue.data, key->key.keyvalue.length); + MD4_Final(sessionkey, &ctx); + } + } + + if (ireq.u.ntlmRequest.sessionkey) { + unsigned char masterkey[MD4_DIGEST_LENGTH]; + RC4_KEY rc4; + size_t len; + + if ((flags & NTLM_NEG_KEYEX) == 0) { + krb5_set_error_string(context, + "NTLM client failed to neg key " + "exchange but still sent key"); + goto out; + } + + len = ireq.u.ntlmRequest.sessionkey->length; + if (len != sizeof(masterkey)){ + krb5_set_error_string(context, + "NTLM master key wrong length: %lu", + (unsigned long)len); + goto out; + } + + RC4_set_key(&rc4, sizeof(sessionkey), sessionkey); + + RC4(&rc4, sizeof(masterkey), + ireq.u.ntlmRequest.sessionkey->data, + masterkey); + memset(&rc4, 0, sizeof(rc4)); + + r.u.ntlmResponse.sessionkey = + malloc(sizeof(*r.u.ntlmResponse.sessionkey)); + if (r.u.ntlmResponse.sessionkey == NULL) { + krb5_set_error_string(context, "out of memory"); + goto out; + } + + ret = krb5_data_copy(r.u.ntlmResponse.sessionkey, + masterkey, sizeof(masterkey)); + if (ret) { + krb5_set_error_string(context, "out of memory"); + goto out; + } + } + + r.u.ntlmResponse.success = 1; + kdc_log(context, config, 0, "NTLM version %d successful for %s", + version, ireq.u.ntlmRequest.username); + break; } default: @@ -698,10 +1156,14 @@ out: _kdc_free_ent (context, user); if (server) _kdc_free_ent (context, server); + if (client) + _kdc_free_ent (context, client); if (password) { memset(password, 0, strlen(password)); free (password); } + if (client_name) + free (client_name); krb5_data_free(&buf); krb5_data_free(&serverNonce); free_DigestREP(&rep); diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h index 87d713b076..56ddc8090b 100644 --- a/source4/heimdal/kdc/headers.h +++ b/source4/heimdal/kdc/headers.h @@ -32,7 +32,7 @@ */ /* - * $Id: headers.h,v 1.18 2006/10/17 02:22:17 lha Exp $ + * $Id: headers.h,v 1.22 2007/01/04 00:15:34 lha Exp $ */ #ifndef __HEADERS_H__ @@ -72,6 +72,9 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif #ifdef HAVE_NETDB_H #include <netdb.h> #endif @@ -89,10 +92,14 @@ #include <krb5.h> #include <krb5_locl.h> #include <digest_asn1.h> +#include <kx509_asn1.h> #include <hdb.h> #include <hdb_err.h> #include <der.h> +#include <heimntlm.h> +#include <windc_plugin.h> + #undef ALLOC #define ALLOC(X) ((X) = malloc(sizeof(*(X)))) #undef ALLOC_SEQ diff --git a/source4/heimdal/kdc/kdc-private.h b/source4/heimdal/kdc/kdc-private.h index 6d4fd2a29b..d896bd10e9 100644 --- a/source4/heimdal/kdc/kdc-private.h +++ b/source4/heimdal/kdc/kdc-private.h @@ -15,6 +15,13 @@ _kdc_add_KRB5SignedPath ( EncTicketPart */*tkt*/); krb5_error_code +_kdc_add_inital_verified_cas ( + krb5_context /*context*/, + krb5_kdc_configuration */*config*/, + pk_client_params */*params*/, + EncTicketPart */*tkt*/); + +krb5_error_code _kdc_as_rep ( krb5_context /*context*/, krb5_kdc_configuration */*config*/, @@ -90,6 +97,15 @@ _kdc_do_kaserver ( struct sockaddr_in */*addr*/); krb5_error_code +_kdc_do_kx509 ( + krb5_context /*context*/, + krb5_kdc_configuration */*config*/, + const Kx509Request */*req*/, + krb5_data */*reply*/, + const char */*from*/, + struct sockaddr */*addr*/); + +krb5_error_code _kdc_do_version4 ( krb5_context /*context*/, krb5_kdc_configuration */*config*/, @@ -183,6 +199,20 @@ _kdc_maybe_version4 ( int /*len*/); krb5_error_code +_kdc_pac_generate ( + krb5_context /*context*/, + hdb_entry_ex */*client*/, + krb5_pac */*pac*/); + +krb5_error_code +_kdc_pac_verify ( + krb5_context /*context*/, + const krb5_principal /*client_principal*/, + hdb_entry_ex */*client*/, + hdb_entry_ex */*server*/, + krb5_pac */*pac*/); + +krb5_error_code _kdc_pk_check_client ( krb5_context /*context*/, krb5_kdc_configuration */*config*/, @@ -230,6 +260,30 @@ _kdc_tgs_rep ( KDC_REQ */*req*/, krb5_data */*data*/, const char */*from*/, - struct sockaddr */*from_addr*/); + struct sockaddr */*from_addr*/, + int /*datagram_reply*/); + +krb5_error_code +_kdc_tkt_add_if_relevant_ad ( + krb5_context /*context*/, + EncTicketPart */*tkt*/, + int /*type*/, + const krb5_data */*data*/); + +krb5_error_code +_kdc_try_kx509_request ( + void */*ptr*/, + size_t /*len*/, + Kx509Request */*req*/, + size_t */*size*/); + +krb5_error_code +_kdc_windc_client_access ( + krb5_context /*context*/, + struct hdb_entry_ex */*client*/, + KDC_REQ */*req*/); + +krb5_error_code +_kdc_windc_init (krb5_context /*context*/); #endif /* __kdc_private_h__ */ diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h index 043b6de47d..ea9eb7125e 100644 --- a/source4/heimdal/kdc/kdc.h +++ b/source4/heimdal/kdc/kdc.h @@ -35,7 +35,7 @@ */ /* - * $Id: kdc.h,v 1.9 2006/10/09 15:34:07 lha Exp $ + * $Id: kdc.h,v 1.11 2006/12/28 21:06:56 lha Exp $ */ #ifndef __KDC_H__ @@ -81,8 +81,12 @@ typedef struct krb5_kdc_configuration { int pkinit_dh_min_bits; int enable_digest; + int digests_allowed; + size_t max_datagram_reply_length; + int enable_kx509; + } krb5_kdc_configuration; #include <kdc-protos.h> diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h index ca8672c062..ed3010b673 100644 --- a/source4/heimdal/kdc/kdc_locl.h +++ b/source4/heimdal/kdc/kdc_locl.h @@ -32,7 +32,7 @@ */ /* - * $Id: kdc_locl.h,v 1.74 2005/12/12 12:23:33 lha Exp $ + * $Id: kdc_locl.h,v 1.76 2006/12/26 17:18:14 lha Exp $ */ #ifndef __KDC_LOCL_H__ @@ -55,6 +55,8 @@ extern int enable_http; extern int detach_from_console; +extern const struct units _kdc_digestunits[]; + #define _PATH_KDC_CONF HDB_DB_DIR "/kdc.conf" #define DEFAULT_LOG_DEST "0-1/FILE:" HDB_DB_DIR "/kdc.log" diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index dd88e2ea50..bf727ee739 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: kerberos5.c,v 1.225 2006/11/10 03:36:32 lha Exp $"); +RCSID("$Id: kerberos5.c,v 1.231 2007/01/04 13:27:27 lha Exp $"); #define MAX_TIME ((time_t)((1U << 31) - 1)) @@ -635,6 +635,69 @@ get_pa_etype_info2(krb5_context context, } /* + * + */ + +static void +log_as_req(krb5_context context, + krb5_kdc_configuration *config, + krb5_enctype cetype, + krb5_enctype setype, + const KDC_REQ_BODY *b) +{ + krb5_error_code ret; + struct rk_strpool *p = NULL; + char *str; + int i; + + for (i = 0; i < b->etype.len; i++) { + ret = krb5_enctype_to_string(context, b->etype.val[i], &str); + if (ret == 0) { + p = rk_strpoolprintf(p, "%s", str); + free(str); + } else + p = rk_strpoolprintf(p, "%d", b->etype.val[i]); + if (p && i + 1 < b->etype.len) + p = rk_strpoolprintf(p, ", "); + if (p == NULL) { + kdc_log(context, config, 0, "out of memory"); + return; + } + } + if (p == NULL) + p = rk_strpoolprintf(p, "no encryption types"); + + str = rk_strpoolcollect(p); + kdc_log(context, config, 0, "Client supported enctypes: %s", str); + free(str); + + { + char *cet; + char *set; + + ret = krb5_enctype_to_string(context, cetype, &cet); + if(ret == 0) { + ret = krb5_enctype_to_string(context, setype, &set); + if (ret == 0) { + kdc_log(context, config, 5, "Using %s/%s", cet, set); + free(set); + } + free(cet); + } + if (ret != 0) + kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype); + } + + { + char str[128]; + unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(), + str, sizeof(str)); + if(*str) + kdc_log(context, config, 2, "Requested flags: %s", str); + } +} + +/* * verify the flags on `client' and `server', returning 0 * if they are OK and generating an error messages and returning * and error code otherwise. @@ -798,6 +861,39 @@ _kdc_check_addresses(krb5_context context, return result; } +/* + * + */ + +static krb5_boolean +send_pac_p(krb5_context context, KDC_REQ *req) +{ + krb5_error_code ret; + PA_PAC_REQUEST pacreq; + PA_DATA *pa; + int i = 0; + + pa = _kdc_find_padata(req, &i, KRB5_PADATA_PA_PAC_REQUEST); + if (pa == NULL) + return TRUE; + + ret = decode_PA_PAC_REQUEST(pa->padata_value.data, + pa->padata_value.length, + &pacreq, + NULL); + if (ret) + return TRUE; + i = pacreq.include_pac; + free_PA_PAC_REQUEST(&pacreq); + if (i == 0) + return FALSE; + return TRUE; +} + +/* + * + */ + krb5_error_code _kdc_as_rep(krb5_context context, krb5_kdc_configuration *config, @@ -882,6 +978,10 @@ _kdc_as_rep(krb5_context context, goto out; } + ret = _kdc_windc_client_access(context, client, req); + if(ret) + goto out; + ret = _kdc_check_flags(context, config, client, client_name, server, server_name, @@ -889,13 +989,6 @@ _kdc_as_rep(krb5_context context, if(ret) goto out; - if (client->check_client_access) { - ret = client->check_client_access(context, client, - b->addresses); - if(ret) - goto out; - } - memset(&et, 0, sizeof(et)); memset(&ek, 0, sizeof(ek)); @@ -1224,57 +1317,7 @@ _kdc_as_rep(krb5_context context, } } - { - struct rk_strpool *p = NULL; - char *str; - int i; - - for (i = 0; i < b->etype.len; i++) { - ret = krb5_enctype_to_string(context, b->etype.val[i], &str); - if (ret == 0) { - p = rk_strpoolprintf(p, "%s", str); - free(str); - } else - p = rk_strpoolprintf(p, "%d", b->etype.val[i]); - if (p && i + 1 < b->etype.len) - p = rk_strpoolprintf(p, ", "); - if (p == NULL) { - kdc_log(context, config, 0, "out of memory"); - goto out; - } - } - if (p == NULL) - p = rk_strpoolprintf(p, "no encryption types"); - - str = rk_strpoolcollect(p); - kdc_log(context, config, 0, "Client supported enctypes: %s", str); - free(str); - } - { - char *cet; - char *set; - - ret = krb5_enctype_to_string(context, cetype, &cet); - if(ret == 0) { - ret = krb5_enctype_to_string(context, setype, &set); - if (ret == 0) { - kdc_log(context, config, 5, "Using %s/%s", cet, set); - free(set); - } - free(cet); - } - if (ret != 0) - kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype); - } - - { - char str[128]; - unparse_flags(KDCOptions2int(f), asn1_KDCOptions_units(), - str, sizeof(str)); - if(*str) - kdc_log(context, config, 2, "Requested flags: %s", str); - } - + log_as_req(context, config, cetype, setype, b); if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey || (f.request_anonymous && !config->allow_anonymous)) { @@ -1330,7 +1373,9 @@ _kdc_as_rep(krb5_context context, goto out; } - krb5_generate_random_keyblock(context, sessionetype, &et.key); + ret = krb5_generate_random_keyblock(context, sessionetype, &et.key); + if (ret) + goto out; copy_PrincipalName(&rep.cname, &et.cname); copy_Realm(&rep.crealm, &et.crealm); @@ -1469,6 +1514,12 @@ _kdc_as_rep(krb5_context context, &reply_key, rep.padata); if (ret) goto out; + ret = _kdc_add_inital_verified_cas(context, + config, + pkp, + &et); + if (ret) + goto out; } #endif @@ -1479,16 +1530,37 @@ _kdc_as_rep(krb5_context context, rep.padata = NULL; } - /* Add the PAC, via a HDB abstraction */ - if (client->authz_data_as_req) { - ret = client->authz_data_as_req(context, client, - req->padata, - et.authtime, - &skey->key, - &et.key, - &et.authorization_data); - if (ret) - goto out; + /* Add the PAC */ + if (send_pac_p(context, req)) { + krb5_pac p = NULL; + krb5_data data; + + ret = _kdc_pac_generate(context, client, &p); + if (ret) { + kdc_log(context, config, 0, "PAC generation failed for -- %s", + client_name); + goto out; + } + if (p != NULL) { + ret = _krb5_pac_sign(context, p, et.authtime, + client->entry.principal, + &skey->key, /* Server key */ + &skey->key, /* FIXME: should be krbtgt key */ + &data); + krb5_pac_free(context, p); + if (ret) { + kdc_log(context, config, 0, "PAC signing failed for -- %s", + client_name); + goto out; + } + + ret = _kdc_tkt_add_if_relevant_ad(context, &et, + KRB5_AUTHDATA_WIN2K_PAC, + &data); + krb5_data_free(&data); + if (ret) + goto out; + } } _kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, @@ -1552,3 +1624,64 @@ out2: _kdc_free_ent(context, server); return ret; } + +/* + * Add the AuthorizationData `data´ of `type´ to the last element in + * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT + */ + +krb5_error_code +_kdc_tkt_add_if_relevant_ad(krb5_context context, + EncTicketPart *tkt, + int type, + const krb5_data *data) +{ + krb5_error_code ret; + size_t size; + + if (tkt->authorization_data == NULL) { + tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data)); + if (tkt->authorization_data == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + } + + /* add the entry to the last element */ + { + AuthorizationData ad = { 0, NULL }; + AuthorizationDataElement ade; + + ade.ad_type = type; + ade.ad_data = *data; + + ret = add_AuthorizationData(&ad, &ade); + if (ret) { + krb5_set_error_string(context, "add AuthorizationData failed"); + return ret; + } + + ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT; + + ASN1_MALLOC_ENCODE(AuthorizationData, + ade.ad_data.data, ade.ad_data.length, + &ad, &size, ret); + free_AuthorizationData(&ad); + if (ret) { + krb5_set_error_string(context, "ASN.1 encode of " + "AuthorizationData failed"); + return ret; + } + if (ade.ad_data.length != size) + krb5_abortx(context, "internal asn.1 encoder error"); + + ret = add_AuthorizationData(tkt->authorization_data, &ade); + der_free_octet_string(&ade.ad_data); + if (ret) { + krb5_set_error_string(context, "add AuthorizationData failed"); + return ret; + } + } + + return 0; +} diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index dcf29eb6e9..a056839e5f 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: krb5tgs.c,v 1.16 2006/10/22 15:54:37 lha Exp $"); +RCSID("$Id: krb5tgs.c,v 1.25 2007/01/04 12:49:45 lha Exp $"); /* * return the realm of a krbtgt-ticket or NULL @@ -119,7 +119,7 @@ _kdc_add_KRB5SignedPath(krb5_context context, if (server && principals) { ret = add_KRB5SignedPathPrincipals(principals, server); if (ret) - goto out; + return ret; } { @@ -131,7 +131,7 @@ _kdc_add_KRB5SignedPath(krb5_context context, ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, &spd, &size, ret); if (ret) - goto out; + return ret; if (data.length != size) krb5_abortx(context, "internal asn.1 encoder error"); } @@ -159,12 +159,12 @@ _kdc_add_KRB5SignedPath(krb5_context context, krb5_crypto_destroy(context, crypto); free(data.data); if (ret) - goto out; + return ret; ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret); free_Checksum(&sp.cksum); if (ret) - goto out; + return ret; if (data.length != size) krb5_abortx(context, "internal asn.1 encoder error"); @@ -174,46 +174,11 @@ _kdc_add_KRB5SignedPath(krb5_context context, * authorization data field. */ - if (tkt->authorization_data == NULL) { - tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data)); - if (tkt->authorization_data == NULL) { - ret = ENOMEM; - goto out; - } - } - - /* add the entry to the last element */ - { - AuthorizationData ad = { 0, NULL }; - AuthorizationDataElement ade; - - ade.ad_type = KRB5_AUTHDATA_SIGNTICKET; - ade.ad_data = data; - - ret = add_AuthorizationData(&ad, &ade); - krb5_data_free(&data); - if (ret) - return ret; - - ASN1_MALLOC_ENCODE(AuthorizationData, data.data, data.length, - &ad, &size, ret); - free_AuthorizationData(&ad); - if (ret) - return ret; - if (data.length != size) - krb5_abortx(context, "internal asn.1 encoder error"); - - ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT; - ade.ad_data = data; - - ret = add_AuthorizationData(tkt->authorization_data, &ade); - krb5_data_free(&data); - if (ret) - return ret; - } + ret = _kdc_tkt_add_if_relevant_ad(context, tkt, + KRB5_AUTHDATA_SIGNTICKET, &data); + krb5_data_free(&data); -out: - return 0; + return ret; } static krb5_error_code @@ -307,6 +272,87 @@ check_KRB5SignedPath(krb5_context context, return 0; } +/* + * + */ + +static krb5_error_code +check_PAC(krb5_context context, + krb5_kdc_configuration *config, + const krb5_principal client_principal, + hdb_entry_ex *client, + hdb_entry_ex *server, + const EncryptionKey *server_key, + const EncryptionKey *krbtgt_key, + EncTicketPart *tkt, + krb5_data *rspac, + int *require_signedpath) +{ + AuthorizationData *ad = tkt->authorization_data; + unsigned i, j; + krb5_error_code ret; + + if (ad == NULL || ad->len == 0) + return 0; + + for (i = 0; i < ad->len; i++) { + AuthorizationData child; + + if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) + continue; + + ret = decode_AuthorizationData(ad->val[i].ad_data.data, + ad->val[i].ad_data.length, + &child, + NULL); + if (ret) { + krb5_set_error_string(context, "Failed to decode " + "IF_RELEVANT with %d", ret); + return ret; + } + for (j = 0; j < child.len; j++) { + + if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { + krb5_pac pac; + + /* Found PAC */ + ret = krb5_pac_parse(context, + child.val[j].ad_data.data, + child.val[j].ad_data.length, + &pac); + free_AuthorizationData(&child); + if (ret) + return ret; + + ret = krb5_pac_verify(context, pac, tkt->authtime, + client_principal, + krbtgt_key, NULL); + if (ret) { + krb5_pac_free(context, pac); + return ret; + } + + ret = _kdc_pac_verify(context, client_principal, + client, server, &pac); + if (ret) { + krb5_pac_free(context, pac); + return ret; + } + *require_signedpath = 0; + + ret = _krb5_pac_sign(context, pac, tkt->authtime, + client_principal, + server_key, krbtgt_key, rspac); + + krb5_pac_free(context, pac); + + return ret; + } + } + free_AuthorizationData(&child); + } + return 0; +} /* * @@ -610,9 +656,10 @@ tgs_make_reply(krb5_context context, KDC_REQ_BODY *b, krb5_const_principal tgt_name, const EncTicketPart *tgt, - const EncTicketPart *adtkt, + const EncryptionKey *ekey, + const krb5_keyblock *sessionkey, + krb5_kvno kvno, AuthorizationData *auth_data, - krb5_ticket *tgs_ticket, hdb_entry_ex *server, const char *server_name, hdb_entry_ex *client, @@ -620,7 +667,7 @@ tgs_make_reply(krb5_context context, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, KRB5SignedPathPrincipals *spp, - EncryptionKey *tgtkey, + const krb5_data *rspac, const char **e_text, krb5_data *reply) { @@ -629,32 +676,6 @@ tgs_make_reply(krb5_context context, EncTicketPart et; KDCOptions f = b->kdc_options; krb5_error_code ret; - krb5_enctype etype; - Key *skey; - const EncryptionKey *ekey; - AuthorizationData *new_auth_data = NULL; - - if(adtkt) { - int i; - ekey = &adtkt->key; - for(i = 0; i < b->etype.len; i++) - if (b->etype.val[i] == adtkt->key.keytype) - break; - if(i == b->etype.len) { - krb5_clear_error_string(context); - return KRB5KDC_ERR_ETYPE_NOSUPP; - } - etype = b->etype.val[i]; - }else{ - ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len, - &skey, &etype); - if(ret) { - kdc_log(context, config, 0, - "Server (%s) has no support for etypes", server_name); - return ret; - } - ekey = &skey->key; - } memset(&rep, 0, sizeof(rep)); memset(&et, 0, sizeof(et)); @@ -768,26 +789,47 @@ tgs_make_reply(krb5_context context, et.flags.anonymous = tgt->flags.anonymous; et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate; - - krb5_generate_random_keyblock(context, etype, &et.key); - - if (server->authz_data_tgs_req) { - ret = server->authz_data_tgs_req(context, server, - client_principal, - tgs_ticket->ticket.authorization_data, - tgs_ticket->ticket.authtime, - tgtkey, - ekey, - &et.key, - &new_auth_data); - if (ret) { - new_auth_data = NULL; + if (auth_data) { + /* XXX Check enc-authorization-data */ + et.authorization_data = calloc(1, sizeof(*et.authorization_data)); + if (et.authorization_data == NULL) { + ret = ENOMEM; + goto out; + } + ret = copy_AuthorizationData(auth_data, et.authorization_data); + if (ret) + goto out; + + /* Filter out type KRB5SignedPath */ + ret = find_KRB5SignedPath(context, et.authorization_data, NULL); + if (ret == 0) { + if (et.authorization_data->len == 1) { + free_AuthorizationData(et.authorization_data); + free(et.authorization_data); + et.authorization_data = NULL; + } else { + AuthorizationData *ad = et.authorization_data; + free_AuthorizationDataElement(&ad->val[ad->len - 1]); + ad->len--; } + } } - /* XXX Check enc-authorization-data */ - et.authorization_data = new_auth_data; + if(rspac->length) { + /* + * No not need to filter out the any PAC from the + * auth_data since its signed by the KDC. + */ + ret = _kdc_tkt_add_if_relevant_ad(context, &et, + KRB5_AUTHDATA_WIN2K_PAC, + rspac); + if (ret) + goto out; + } + ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key); + if (ret) + goto out; et.crealm = tgt->crealm; et.cname = tgt_name->name; @@ -795,6 +837,10 @@ tgs_make_reply(krb5_context context, /* MIT must have at least one last_req */ ek.last_req.len = 1; ek.last_req.val = calloc(1, sizeof(*ek.last_req.val)); + if (ek.last_req.val == NULL) { + ret = ENOMEM; + goto out; + } ek.nonce = b->nonce; ek.flags = et.flags; ek.authtime = et.authtime; @@ -817,7 +863,7 @@ tgs_make_reply(krb5_context context, krbtgt, krbtgt_etype, NULL, - NULL, + spp, &et); if (ret) goto out; @@ -835,8 +881,8 @@ tgs_make_reply(krb5_context context, etype list, even if we don't want a session key with DES3? */ ret = _kdc_encode_reply(context, config, - &rep, &et, &ek, etype, - adtkt ? 0 : server->entry.kvno, + &rep, &et, &ek, et.key.keytype, + kvno, ekey, 0, &tgt->key, e_text, reply); out: free_TGS_REP(&rep); @@ -973,8 +1019,7 @@ tgs_parse_request(krb5_context context, const struct sockaddr *from_addr, time_t **csec, int **cusec, - AuthorizationData **auth_data, - EncryptionKey **tgtkey) + AuthorizationData **auth_data) { krb5_ap_req ap_req; krb5_error_code ret; @@ -1060,8 +1105,6 @@ tgs_parse_request(krb5_context context, ret = KRB5KRB_AP_ERR_BADKEYVER; goto out; } - - *tgtkey = &tkey->key; if (b->kdc_options.validate) verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID; @@ -1201,8 +1244,8 @@ tgs_build_reply(krb5_context context, const char *from, const char **e_text, AuthorizationData *auth_data, - EncryptionKey *tgtkey, - const struct sockaddr *from_addr) + const struct sockaddr *from_addr, + int datagram_reply) { krb5_error_code ret; krb5_principal cp = NULL, sp = NULL; @@ -1211,6 +1254,10 @@ tgs_build_reply(krb5_context context, hdb_entry_ex *server = NULL, *client = NULL; EncTicketPart *tgt = &ticket->ticket; KRB5SignedPathPrincipals *spp = NULL; + const EncryptionKey *ekey; + krb5_keyblock sessionkey; + krb5_kvno kvno; + krb5_data rspac; PrincipalName *s; Realm r; @@ -1219,7 +1266,9 @@ tgs_build_reply(krb5_context context, char opt_str[128]; int require_signedpath = 0; + memset(&sessionkey, 0, sizeof(sessionkey)); memset(&adtkt, 0, sizeof(adtkt)); + krb5_data_zero(&rspac); s = b->sname; r = b->realm; @@ -1436,7 +1485,7 @@ server_lookup: ret = krb5_verify_checksum(context, crypto, - KRB5_KU_TGS_IMPERSONATE, + KRB5_KU_OTHER_CKSUM, datack.data, datack.length, &self.cksum); @@ -1617,6 +1666,67 @@ server_lookup: goto out; } + /* + * Select enctype, return key and kvno. + */ + + { + krb5_enctype etype; + + if(b->kdc_options.enc_tkt_in_skey) { + int i; + ekey = &adtkt.key; + for(i = 0; i < b->etype.len; i++) + if (b->etype.val[i] == adtkt.key.keytype) + break; + if(i == b->etype.len) { + krb5_clear_error_string(context); + return KRB5KDC_ERR_ETYPE_NOSUPP; + } + etype = b->etype.val[i]; + kvno = 0; + } else { + Key *skey; + + ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len, + &skey, &etype); + if(ret) { + kdc_log(context, config, 0, + "Server (%s) has no support for etypes", spp); + return ret; + } + ekey = &skey->key; + kvno = server->entry.kvno; + } + + ret = krb5_generate_random_keyblock(context, etype, &sessionkey); + if (ret) + goto out; + } + + /* check PAC if there is one */ + { + Key *tkey; + + ret = hdb_enctype2key(context, &krbtgt->entry, + krbtgt_etype, &tkey); + if(ret) { + kdc_log(context, config, 0, + "Failed to find key for krbtgt PAC check"); + goto out; + } + + ret = check_PAC(context, config, client_principal, + client, server, ekey, &tkey->key, + tgt, &rspac, &require_signedpath); + if (ret) { + kdc_log(context, config, 0, + "check_PAC check failed for %s (%s) from %s with %s", + spn, cpn, from, krb5_get_err_text(context, ret)); + goto out; + } + } + /* also check the krbtgt for signature */ ret = check_KRB5SignedPath(context, config, @@ -1640,9 +1750,10 @@ server_lookup: b, client_principal, tgt, - b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, + ekey, + &sessionkey, + kvno, auth_data, - ticket, server, spn, client, @@ -1650,7 +1761,7 @@ server_lookup: krbtgt, krbtgt_etype, spp, - tgtkey, + &rspac, e_text, reply); @@ -1658,6 +1769,8 @@ out: free(spn); free(cpn); + krb5_data_free(&rspac); + krb5_free_keyblock_contents(context, &sessionkey); if(server) _kdc_free_ent(context, server); if(client) @@ -1685,7 +1798,8 @@ _kdc_tgs_rep(krb5_context context, KDC_REQ *req, krb5_data *data, const char *from, - struct sockaddr *from_addr) + struct sockaddr *from_addr, + int datagram_reply) { AuthorizationData *auth_data = NULL; krb5_error_code ret; @@ -1696,8 +1810,6 @@ _kdc_tgs_rep(krb5_context context, krb5_ticket *ticket = NULL; const char *e_text = NULL; krb5_enctype krbtgt_etype = ETYPE_NULL; - EncryptionKey *tgtkey = NULL; - time_t *csec = NULL; int *cusec = NULL; @@ -1726,8 +1838,7 @@ _kdc_tgs_rep(krb5_context context, &e_text, from, from_addr, &csec, &cusec, - &auth_data, - &tgtkey); + &auth_data); if (ret) { kdc_log(context, config, 0, "Failed parsing TGS-REQ from %s", from); @@ -1745,14 +1856,21 @@ _kdc_tgs_rep(krb5_context context, from, &e_text, auth_data, - tgtkey, - from_addr); + from_addr, + datagram_reply); if (ret) { kdc_log(context, config, 0, "Failed building TGS-REP to %s", from); goto out; } + /* */ + if (datagram_reply && data->length > config->max_datagram_reply_length) { + krb5_data_free(data); + ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; + e_text = "Reply packet too large"; + } + out: if(ret && data->data == NULL){ krb5_mk_error(context, diff --git a/source4/heimdal/kdc/kx509.c b/source4/heimdal/kdc/kx509.c new file mode 100644 index 0000000000..d817338f73 --- /dev/null +++ b/source4/heimdal/kdc/kx509.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" +#include <hex.h> + +RCSID("$Id: kx509.c,v 1.1 2006/12/28 21:03:53 lha Exp $"); + +/* + * + */ + +krb5_error_code +_kdc_try_kx509_request(void *ptr, size_t len, Kx509Request *req, size_t *size) +{ + if (len < 4) + return -1; + if (memcmp("\x00\x00\x02\x00", ptr, 4) != 0) + return -1; + return decode_Kx509Request(((unsigned char *)ptr) + 4, len - 4, req, size); +} + +/* + * + */ + +static const char version_2_0[4] = {0 , 0, 2, 0}; + +static krb5_error_code +verify_req_hash(krb5_context context, + const Kx509Request *req, + krb5_keyblock *key) +{ + unsigned char digest[SHA_DIGEST_LENGTH]; + HMAC_CTX ctx; + + if (req->pk_hash.length != sizeof(digest)) { + krb5_set_error_string(context, "pk-hash have wrong length: %lu", + (unsigned long)req->pk_hash.length); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + + HMAC_CTX_init(&ctx); + HMAC_Init_ex(&ctx, + key->keyvalue.data, key->keyvalue.length, + EVP_sha1(), NULL); + if (sizeof(digest) != HMAC_size(&ctx)) + krb5_abortx(context, "runtime error, hmac buffer wrong size in kx509"); + HMAC_Update(&ctx, version_2_0, sizeof(version_2_0)); + HMAC_Update(&ctx, req->pk_key.data, req->pk_key.length); + HMAC_Final(&ctx, digest, 0); + HMAC_CTX_cleanup(&ctx); + + if (memcmp(req->pk_hash.data, digest, sizeof(digest)) != 0) { + krb5_set_error_string(context, "pk-hash is not correct"); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + return 0; +} + +static krb5_error_code +calculate_reply_hash(krb5_context context, + krb5_keyblock *key, + Kx509Response *rep) +{ + HMAC_CTX ctx; + + HMAC_CTX_init(&ctx); + + HMAC_Init_ex(&ctx, + key->keyvalue.data, key->keyvalue.length, + EVP_sha1(), NULL); + rep->hash->length = HMAC_size(&ctx); + rep->hash->data = malloc(rep->hash->length); + if (rep->hash->data == NULL) { + HMAC_CTX_cleanup(&ctx); + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + + HMAC_Update(&ctx, version_2_0, sizeof(version_2_0)); + if (rep->error_code) { + int32_t t = *rep->error_code; + do { + unsigned char p = (t & 0xff); + HMAC_Update(&ctx, &p, 1); + t >>= 8; + } while (t); + } + if (rep->certificate) + HMAC_Update(&ctx, rep->certificate->data, rep->certificate->length); + if (rep->e_text) + HMAC_Update(&ctx, *rep->e_text, strlen(*rep->e_text)); + + HMAC_Final(&ctx, rep->hash->data, 0); + HMAC_CTX_cleanup(&ctx); + + return 0; +} + +/* + * Build a certifate for `principal´ that will expire at `endtime´. + */ + +static krb5_error_code +build_certificate(krb5_context context, + krb5_kdc_configuration *config, + const krb5_data *key, + time_t endtime, + krb5_principal principal, + krb5_data *certificate) +{ + /* XXX write code here to generate certificates */ + FILE *in, *out; + krb5_error_code ret; + const char *program; + char *str, *strkey; + char tstr[64]; + pid_t pid; + + snprintf(tstr, sizeof(tstr), "%lu", (unsigned long)endtime); + + ret = base64_encode(key->data, key->length, &strkey); + if (ret < 0) { + krb5_set_error_string(context, "failed to base64 encode key"); + return ENOMEM; + } + + program = krb5_config_get_string(context, + NULL, + "kdc", + "kx509_cert_program", + NULL); + if (program == NULL) { + free(strkey); + krb5_set_error_string(context, "no certificate program configured"); + return ENOENT; + } + + ret = krb5_unparse_name(context, principal, &str); + if (ret) { + free(strkey); + return ret; + } + + pid = pipe_execv(&in, &out, NULL, program, str, tstr, NULL); + free(str); + if (pid <= 0) { + free(strkey); + krb5_set_error_string(context, + "Failed to run the cert program %s", + program); + return ret; + } + fprintf(in, "%s\n", strkey); + fclose(in); + free(strkey); + + { + unsigned buf[1024 * 10]; + size_t len; + + len = fread(buf, 1, sizeof(buf), out); + fclose(out); + if(len == 0) { + krb5_set_error_string(context, + "Certificate program returned no data"); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + ret = krb5_data_copy(certificate, buf, len); + if (ret) { + krb5_set_error_string(context, "Failed To copy certificate"); + return ret; + } + } + kill(pid, SIGKILL); + waitpid(pid, NULL, 0); + return 0; +} + +/* + * + */ + +krb5_error_code +_kdc_do_kx509(krb5_context context, + krb5_kdc_configuration *config, + const Kx509Request *req, krb5_data *reply, + const char *from, struct sockaddr *addr) +{ + krb5_error_code ret; + krb5_ticket *ticket = NULL; + krb5_flags ap_req_options; + krb5_auth_context ac = NULL; + krb5_keytab id = NULL; + krb5_principal sprincipal = NULL, cprincipal = NULL; + char *cname = NULL; + Kx509Response rep; + size_t size; + krb5_keyblock *key = NULL; + + krb5_data_zero(reply); + memset(&rep, 0, sizeof(rep)); + + if(!config->enable_kx509) { + kdc_log(context, config, 0, + "Rejected kx509 request (disabled) from %s", from); + return KRB5KDC_ERR_POLICY; + } + + kdc_log(context, config, 0, "Kx509 request from %s", from); + + ret = krb5_kt_resolve(context, "HDB:", &id); + if (ret) { + kdc_log(context, config, 0, "Can't open database for digest"); + goto out; + } + + ret = krb5_rd_req(context, + &ac, + &req->authenticator, + NULL, + id, + &ap_req_options, + &ticket); + if (ret) + goto out; + + ret = krb5_ticket_get_client(context, ticket, &cprincipal); + if (ret) + goto out; + + ret = krb5_unparse_name(context, cprincipal, &cname); + if (ret) + goto out; + + /* verify server principal */ + + ret = krb5_sname_to_principal(context, NULL, "kca_service", + KRB5_NT_UNKNOWN, &sprincipal); + if (ret) + goto out; + + { + krb5_principal principal = NULL; + + ret = krb5_ticket_get_server(context, ticket, &principal); + if (ret) + goto out; + + ret = krb5_principal_compare(context, sprincipal, principal); + krb5_free_principal(context, principal); + if (ret != TRUE) { + ret = KRB5KDC_ERR_SERVER_NOMATCH; + krb5_set_error_string(context, + "User %s used wrong Kx509 service principal", + cname); + goto out; + } + } + + ret = krb5_auth_con_getkey(context, ac, &key); + if (ret || key == NULL) { + krb5_set_error_string(context, "Kx509 can't get session key"); + goto out; + } + + ret = verify_req_hash(context, req, key); + if (ret) + goto out; + + ALLOC(rep.certificate); + if (rep.certificate == NULL) + goto out; + krb5_data_zero(rep.certificate); + ALLOC(rep.hash); + if (rep.hash == NULL) + goto out; + krb5_data_zero(rep.hash); + + ret = build_certificate(context, config, &req->pk_key, + krb5_ticket_get_endtime(context, ticket), + cprincipal, rep.certificate); + if (ret) + goto out; + + ret = calculate_reply_hash(context, key, &rep); + if (ret) + goto out; + + /* + * Encode reply, [ version | Kx509Response ] + */ + + { + krb5_data data; + + ASN1_MALLOC_ENCODE(Kx509Response, data.data, data.length, &rep, + &size, ret); + if (ret) { + krb5_set_error_string(context, "Failed to encode kx509 reply"); + goto out; + } + if (size != data.length) + krb5_abortx(context, "ASN1 internal error"); + + ret = krb5_data_alloc(reply, data.length + sizeof(version_2_0)); + if (ret) { + free(data.data); + goto out; + } + memcpy(reply->data, version_2_0, sizeof(version_2_0)); + memcpy(((unsigned char *)reply->data) + sizeof(version_2_0), + data.data, data.length); + free(data.data); + } + + kdc_log(context, config, 0, "Successful Kx509 request for %s", cname); + +out: + if (ac) + krb5_auth_con_free(context, ac); + if (ret) + krb5_warn(context, ret, "Kx509 request from %s failed", from); + if (ticket) + krb5_free_ticket(context, ticket); + if (id) + krb5_kt_close(context, id); + if (sprincipal) + krb5_free_principal(context, sprincipal); + if (cprincipal) + krb5_free_principal(context, cprincipal); + if (key) + krb5_free_keyblock (context, key); + if (cname) + free(cname); + free_Kx509Response(&rep); + + return 0; +} diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c index 6657ab7c44..418a38d030 100755 --- a/source4/heimdal/kdc/pkinit.c +++ b/source4/heimdal/kdc/pkinit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan + * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: pkinit.c,v 1.74 2006/11/10 03:37:43 lha Exp $"); +RCSID("$Id: pkinit.c,v 1.86 2007/01/04 12:54:09 lha Exp $"); #ifdef PKINIT @@ -68,6 +68,8 @@ struct pk_client_params { DH *dh; EncryptionKey reply_key; char *dh_group_name; + hx509_peer_info peer; + hx509_certs client_anchors; }; struct pk_principal_mapping { @@ -180,6 +182,10 @@ _kdc_pk_free_client_param(krb5_context context, krb5_free_keyblock_contents(context, &client_params->reply_key); if (client_params->dh_group_name) free(client_params->dh_group_name); + if (client_params->peer) + hx509_peer_info_free(client_params->peer); + if (client_params->client_anchors) + hx509_certs_free(&client_params->client_anchors); memset(client_params, 0, sizeof(*client_params)); free(client_params); } @@ -302,8 +308,10 @@ get_dh_param(krb5_context context, ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits, &dhparam.p, &dhparam.g, &dhparam.q, moduli, &client_params->dh_group_name); - if (ret) + if (ret) { + /* XXX send back proposal of better group */ goto out; + } dh = DH_new(); if (dh == NULL) { @@ -354,64 +362,6 @@ get_dh_param(krb5_context context, return ret; } -#if 0 -/* - * XXX We only need this function if there are several certs for the - * KDC to choose from, and right now, we can't handle that so punt for - * now. - * - * If client has sent a list of CA's trusted by him, make sure our - * CA is in the list. - * - */ - -static void -verify_trusted_ca(PA_PK_AS_REQ_19 *r) -{ - - if (r.trustedCertifiers != NULL) { - X509_NAME *kdc_issuer; - X509 *kdc_cert; - - kdc_cert = sk_X509_value(kdc_identity->cert, 0); - kdc_issuer = X509_get_issuer_name(kdc_cert); - - /* XXX will work for heirarchical CA's ? */ - /* XXX also serial_number should be compared */ - - ret = KRB5_KDC_ERR_KDC_NOT_TRUSTED; - for (i = 0; i < r.trustedCertifiers->len; i++) { - TrustedCA_19 *ca = &r.trustedCertifiers->val[i]; - - switch (ca->element) { - case choice_TrustedCA_19_caName: { - X509_NAME *name; - unsigned char *p; - - p = ca->u.caName.data; - name = d2i_X509_NAME(NULL, &p, ca->u.caName.length); - if (name == NULL) /* XXX should this be a failure instead ? */ - break; - if (X509_NAME_cmp(name, kdc_issuer) == 0) - ret = 0; - X509_NAME_free(name); - break; - } - case choice_TrustedCA_19_issuerAndSerial: - /* IssuerAndSerialNumber issuerAndSerial */ - break; - default: - break; - } - if (ret == 0) - break; - } - if (ret) - goto out; - } -} -#endif /* 0 */ - krb5_error_code _kdc_pk_rd_padata(krb5_context context, krb5_kdc_configuration *config, @@ -483,7 +433,61 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - /* XXX look at r.trustedCertifiers and r.kdcPkId */ + /* XXX look at r.kdcPkId */ + if (r.trustedCertifiers) { + ExternalPrincipalIdentifiers *edi = r.trustedCertifiers; + unsigned int i; + + ret = hx509_certs_init(kdc_identity->hx509ctx, + "MEMORY:client-anchors", + 0, NULL, + &client_params->client_anchors); + if (ret) { + krb5_set_error_string(context, "Can't allocate client anchors: %d", ret); + goto out; + + } + for (i = 0; i < edi->len; i++) { + IssuerAndSerialNumber iasn; + hx509_query *q; + hx509_cert cert; + size_t size; + + if (edi->val[i].issuerAndSerialNumber == NULL) + continue; + + ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); + if (ret) { + krb5_set_error_string(context, + "Failed to allocate hx509_query"); + goto out; + } + + ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data, + edi->val[i].issuerAndSerialNumber->length, + &iasn, + &size); + if (ret || size != 0) { + hx509_query_free(kdc_identity->hx509ctx, q); + continue; + } + ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber); + free_IssuerAndSerialNumber(&iasn); + if (ret) + continue; + + ret = hx509_certs_find(kdc_identity->hx509ctx, + kdc_identity->certs, + q, + &cert); + hx509_query_free(kdc_identity->hx509ctx, q); + if (ret) + continue; + hx509_certs_add(kdc_identity->hx509ctx, + client_params->client_anchors, cert); + hx509_cert_free(cert); + } + } ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack, &contentInfoOid, @@ -611,6 +615,23 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } } + + if (ap.supportedCMSTypes) { + ret = hx509_peer_info_alloc(kdc_identity->hx509ctx, + &client_params->peer); + if (ret) { + free_AuthPack(&ap); + goto out; + } + ret = hx509_peer_info_set_cms_algs(kdc_identity->hx509ctx, + client_params->peer, + ap.supportedCMSTypes->val, + ap.supportedCMSTypes->len); + if (ret) { + free_AuthPack(&ap); + goto out; + } + } free_AuthPack(&ap); } else krb5_abortx(context, "internal pkinit error"); @@ -752,7 +773,8 @@ pk_mk_pa_reply_enckey(krb5_context context, buf.length, NULL, cert, - kdc_identity->anchors, + client_params->peer, + client_params->client_anchors, kdc_identity->certpool, &signed_data); hx509_cert_free(cert); @@ -864,7 +886,8 @@ pk_mk_pa_reply_dh(krb5_context context, buf.length, NULL, cert, - kdc_identity->anchors, + client_params->peer, + client_params->client_anchors, kdc_identity->certpool, &signed_data); *kdc_cert = cert; @@ -948,8 +971,12 @@ _kdc_pk_mk_pa_reply(krb5_context context, rep.element = choice_PA_PK_AS_REP_encKeyPack; - krb5_generate_random_keyblock(context, enctype, - &client_params->reply_key); + ret = krb5_generate_random_keyblock(context, enctype, + &client_params->reply_key); + if (ret) { + free_PA_PK_AS_REP(&rep); + goto out; + } ret = pk_mk_pa_reply_enckey(context, client_params, req, @@ -1039,8 +1066,12 @@ _kdc_pk_mk_pa_reply(krb5_context context, pa_type = KRB5_PADATA_PK_AS_REP_19; rep.element = choice_PA_PK_AS_REP_encKeyPack; - krb5_generate_random_keyblock(context, enctype, - &client_params->reply_key); + ret = krb5_generate_random_keyblock(context, enctype, + &client_params->reply_key); + if (ret) { + free_PA_PK_AS_REP_Win2k(&rep); + goto out; + } ret = pk_mk_pa_reply_enckey(context, client_params, req, @@ -1337,6 +1368,35 @@ add_principal_mapping(krb5_context context, return 0; } +krb5_error_code +_kdc_add_inital_verified_cas(krb5_context context, + krb5_kdc_configuration *config, + pk_client_params *params, + EncTicketPart *tkt) +{ + AD_INITIAL_VERIFIED_CAS cas; + krb5_error_code ret; + krb5_data data; + size_t size; + + memset(&cas, 0, sizeof(cas)); + + /* XXX add CAs to cas here */ + + ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length, + &cas, &size, ret); + if (ret) + return ret; + if (data.length != size) + krb5_abortx(context, "internal asn.1 encoder error"); + + ret = _kdc_tkt_add_if_relevant_ad(context, tkt, + ad_initial_verified_cas, &data); + krb5_data_free(&data); + return ret; +} + + krb5_error_code _kdc_pk_initialize(krb5_context context, @@ -1372,7 +1432,7 @@ _kdc_pk_initialize(krb5_context context, NULL, NULL); if (ret) { - krb5_warn(context, ret, "PKINIT: failed to load"); + krb5_warn(context, ret, "PKINIT: "); config->enable_pkinit = 0; return ret; } @@ -1411,7 +1471,7 @@ _kdc_pk_initialize(krb5_context context, NULL, FALSE, "kdc", - "pki-allow-proxy-certificate", + "pkinit_allow_proxy_certificate", NULL); _krb5_pk_allow_proxy_certificate(kdc_identity, ret); @@ -1419,7 +1479,7 @@ _kdc_pk_initialize(krb5_context context, NULL, HDB_DB_DIR "/pki-mapping", "kdc", - "pki-mappings-file", + "pkinit_mappings_file", NULL); f = fopen(file, "r"); if (f == NULL) { diff --git a/source4/heimdal/kdc/process.c b/source4/heimdal/kdc/process.c index ed5cb3d651..a64efaa05d 100644 --- a/source4/heimdal/kdc/process.c +++ b/source4/heimdal/kdc/process.c @@ -34,7 +34,7 @@ #include "kdc_locl.h" -RCSID("$Id: process.c,v 1.5 2006/10/09 15:37:39 lha Exp $"); +RCSID("$Id: process.c,v 1.7 2006/12/28 21:09:35 lha Exp $"); /* * handle the request in `buf, len', from `addr' (or `from' as a string), @@ -55,6 +55,7 @@ krb5_kdc_process_request(krb5_context context, KDC_REQ req; Ticket ticket; DigestREQ digestreq; + Kx509Request kx509req; krb5_error_code ret; size_t i; @@ -70,7 +71,7 @@ krb5_kdc_process_request(krb5_context context, free_AS_REQ(&req); return ret; }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ - ret = _kdc_tgs_rep(context, config, &req, reply, from, addr); + ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply); free_TGS_REQ(&req); return ret; }else if(decode_Ticket(buf, len, &ticket, &i) == 0){ @@ -81,6 +82,10 @@ krb5_kdc_process_request(krb5_context context, ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr); free_DigestREQ(&digestreq); return ret; + } else if (_kdc_try_kx509_request(buf, len, &kx509req, &i) == 0) { + ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr); + free_Kx509Request(&kx509req); + return ret; } else if(_kdc_maybe_version4(buf, len)){ *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */ _kdc_do_version4(context, config, buf, len, reply, from, @@ -128,7 +133,7 @@ krb5_kdc_process_krb5_request(krb5_context context, free_AS_REQ(&req); return ret; }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ - ret = _kdc_tgs_rep(context, config, &req, reply, from, addr); + ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply); free_TGS_REQ(&req); return ret; } diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c new file mode 100644 index 0000000000..41e4ad1bbc --- /dev/null +++ b/source4/heimdal/kdc/windc.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: windc.c,v 1.3 2007/01/04 11:10:06 lha Exp $"); + +static krb5plugin_windc_ftable *windcft; +static void *windcctx; + +/* + * Pick the first WINDC module that we find. + */ + +krb5_error_code +_kdc_windc_init(krb5_context context) +{ + struct krb5_plugin *list = NULL, *e; + krb5_error_code ret; + + ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "windc", &list); + if(ret != 0 || list == NULL) + return 0; + + for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) { + + windcft = _krb5_plugin_get_symbol(e); + if (windcft->minor_version < KRB5_WINDC_PLUGING_MINOR) + continue; + + (*windcft->init)(context, &windcctx); + break; + } + if (e == NULL) { + _krb5_plugin_free(list); + krb5_set_error_string(context, "Did not find any WINDC plugin"); + windcft = NULL; + return ENOENT; + } + + return 0; +} + + +krb5_error_code +_kdc_pac_generate(krb5_context context, + hdb_entry_ex *client, + krb5_pac *pac) +{ + *pac = NULL; + if (windcft == NULL) + return 0; + return (windcft->pac_generate)(windcctx, context, client, pac); +} + +krb5_error_code +_kdc_pac_verify(krb5_context context, + const krb5_principal client_principal, + hdb_entry_ex *client, + hdb_entry_ex *server, + krb5_pac *pac) +{ + if (windcft == NULL) { + krb5_set_error_string(context, "Can't verify WINDC, no function"); + return EINVAL; + } + return (windcft->pac_verify)(windcctx, context, client_principal, client, server, pac); +} + +krb5_error_code +_kdc_windc_client_access(krb5_context context, + struct hdb_entry_ex *client, + KDC_REQ *req) +{ + if (windcft == NULL) + return 0; + return (windcft->client_access)(windcctx, context, client, req); +} diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h new file mode 100644 index 0000000000..a3b7534480 --- /dev/null +++ b/source4/heimdal/kdc/windc_plugin.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: windc_plugin.h,v 1.2 2007/01/04 11:13:51 lha Exp $ */ + +#ifndef HEIMDAL_KRB5_PAC_PLUGIN_H +#define HEIMDAL_KRB5_PAC_PLUGIN_H 1 + +#include <krb5.h> + +/* + * The PAC generate function should allocate a krb5_pac using + * krb5_pac_init and fill in the PAC structure for the principal using + * krb5_pac_add_buffer. + * + * The PAC verify function should verify all components in the PAC + * using krb5_pac_get_types and krb5_pac_get_buffer for all types. + * + * Check client access function check if the client is authorized. + */ + +struct hdb_entry_ex; + +typedef krb5_error_code +(*krb5plugin_windc_pac_generate)(void *, krb5_context, + struct hdb_entry_ex *, krb5_pac *); + +typedef krb5_error_code +(*krb5plugin_windc_pac_verify)(void *, krb5_context, + const krb5_principal, + struct hdb_entry_ex *, struct hdb_entry_ex *, krb5_pac *); + +typedef krb5_error_code +(*krb5plugin_windc_client_access)( + void *, krb5_context, struct hdb_entry_ex *, KDC_REQ *); + + +#define KRB5_WINDC_PLUGING_MINOR 2 + +typedef struct krb5plugin_windc_ftable { + int minor_version; + krb5_error_code (*init)(krb5_context, void **); + void (*fini)(void *); + krb5plugin_windc_pac_generate pac_generate; + krb5plugin_windc_pac_verify pac_verify; + krb5plugin_windc_client_access client_access; +} krb5plugin_windc_ftable; + +#endif /* HEIMDAL_KRB5_PAC_PLUGIN_H */ + diff --git a/source4/heimdal/lib/asn1/asn1-common.h b/source4/heimdal/lib/asn1/asn1-common.h index ab06ae79dd..5f09cd6794 100644 --- a/source4/heimdal/lib/asn1/asn1-common.h +++ b/source4/heimdal/lib/asn1/asn1-common.h @@ -1,4 +1,4 @@ -/* $Id: asn1-common.h,v 1.6 2006/10/14 05:09:47 lha Exp $ */ +/* $Id: asn1-common.h,v 1.7 2006/12/28 17:14:10 lha Exp $ */ #include <stddef.h> #include <time.h> @@ -32,6 +32,7 @@ typedef struct heim_universal_string { uint32_t *data; } heim_universal_string; +typedef char *heim_visible_string; typedef struct heim_oid { size_t length; diff --git a/source4/heimdal/lib/asn1/der-protos.h b/source4/heimdal/lib/asn1/der-protos.h index 3aee392c96..7bfe02ebb4 100644 --- a/source4/heimdal/lib/asn1/der-protos.h +++ b/source4/heimdal/lib/asn1/der-protos.h @@ -82,6 +82,11 @@ der_copy_utf8string ( const heim_utf8_string */*from*/, heim_utf8_string */*to*/); +int +der_copy_visible_string ( + const heim_visible_string */*from*/, + heim_visible_string */*to*/); + void der_free_bit_string (heim_bit_string */*k*/); @@ -112,6 +117,9 @@ der_free_universal_string (heim_universal_string */*k*/); void der_free_utf8string (heim_utf8_string */*str*/); +void +der_free_visible_string (heim_visible_string */*str*/); + int der_get_bit_string ( const unsigned char */*p*/, @@ -252,6 +260,13 @@ der_get_utf8string ( size_t */*size*/); int +der_get_visible_string ( + const unsigned char */*p*/, + size_t /*len*/, + heim_visible_string */*str*/, + size_t */*size*/); + +int der_heim_bit_string_cmp ( const heim_bit_string */*p*/, const heim_bit_string */*q*/); @@ -332,6 +347,9 @@ der_length_utctime (const time_t */*t*/); size_t der_length_utf8string (const heim_utf8_string */*data*/); +size_t +der_length_visible_string (const heim_visible_string */*data*/); + int der_match_tag ( const unsigned char */*p*/, @@ -505,6 +523,13 @@ der_put_utf8string ( size_t */*size*/); int +der_put_visible_string ( + unsigned char */*p*/, + size_t /*len*/, + const heim_visible_string */*str*/, + size_t */*size*/); + +int encode_heim_any ( unsigned char */*p*/, size_t /*len*/, diff --git a/source4/heimdal/lib/asn1/der_copy.c b/source4/heimdal/lib/asn1/der_copy.c index 96eea9c6d7..15e7b817a0 100644 --- a/source4/heimdal/lib/asn1/der_copy.c +++ b/source4/heimdal/lib/asn1/der_copy.c @@ -33,7 +33,7 @@ #include "der_locl.h" -RCSID("$Id: der_copy.c,v 1.16 2006/10/14 05:30:02 lha Exp $"); +RCSID("$Id: der_copy.c,v 1.17 2006/12/28 17:14:17 lha Exp $"); int der_copy_general_string (const heim_general_string *from, @@ -89,6 +89,13 @@ der_copy_universal_string (const heim_universal_string *from, } int +der_copy_visible_string (const heim_visible_string *from, + heim_visible_string *to) +{ + return der_copy_general_string(from, to); +} + +int der_copy_octet_string (const heim_octet_string *from, heim_octet_string *to) { to->length = from->length; diff --git a/source4/heimdal/lib/asn1/der_format.c b/source4/heimdal/lib/asn1/der_format.c index 9655269356..32cf23cb39 100644 --- a/source4/heimdal/lib/asn1/der_format.c +++ b/source4/heimdal/lib/asn1/der_format.c @@ -34,7 +34,7 @@ #include "der_locl.h" #include <hex.h> -RCSID("$Id: der_format.c,v 1.6 2006/10/21 18:24:15 lha Exp $"); +RCSID("$Id: der_format.c,v 1.8 2006/11/27 10:32:21 lha Exp $"); int der_parse_hex_heim_integer (const char *p, heim_integer *data) @@ -110,10 +110,13 @@ der_print_heim_oid (const heim_oid *oid, char delim, char **str) struct rk_strpool *p = NULL; int i; + if (oid->length == 0) + return EINVAL; + for (i = 0; i < oid->length ; i++) { - p = rk_strpoolprintf(p, "%d%s", - oid->components[i], - i < oid->length - 1 ? " " : ""); + p = rk_strpoolprintf(p, "%d", oid->components[i]); + if (p && i < oid->length - 1) + p = rk_strpoolprintf(p, "%c", delim); if (p == NULL) { *str = NULL; return ENOMEM; diff --git a/source4/heimdal/lib/asn1/der_free.c b/source4/heimdal/lib/asn1/der_free.c index c3a6a17fff..6827486d9f 100644 --- a/source4/heimdal/lib/asn1/der_free.c +++ b/source4/heimdal/lib/asn1/der_free.c @@ -33,7 +33,7 @@ #include "der_locl.h" -RCSID("$Id: der_free.c,v 1.13 2006/10/14 05:30:47 lha Exp $"); +RCSID("$Id: der_free.c,v 1.14 2006/12/28 17:14:21 lha Exp $"); void der_free_general_string (heim_general_string *str) @@ -80,6 +80,13 @@ der_free_universal_string (heim_universal_string *k) } void +der_free_visible_string (heim_visible_string *str) +{ + free(*str); + *str = NULL; +} + +void der_free_octet_string (heim_octet_string *k) { free(k->data); diff --git a/source4/heimdal/lib/asn1/der_get.c b/source4/heimdal/lib/asn1/der_get.c index 7808fa8165..a1ed23f10b 100644 --- a/source4/heimdal/lib/asn1/der_get.c +++ b/source4/heimdal/lib/asn1/der_get.c @@ -33,7 +33,7 @@ #include "der_locl.h" -RCSID("$Id: der_get.c,v 1.50 2006/10/19 16:27:44 lha Exp $"); +RCSID("$Id: der_get.c,v 1.51 2006/12/28 17:14:25 lha Exp $"); #include <version.h> @@ -215,6 +215,13 @@ der_get_universal_string (const unsigned char *p, size_t len, } int +der_get_visible_string (const unsigned char *p, size_t len, + heim_visible_string *str, size_t *size) +{ + return der_get_general_string(p, len, str, size); +} + +int der_get_octet_string (const unsigned char *p, size_t len, heim_octet_string *data, size_t *size) { diff --git a/source4/heimdal/lib/asn1/der_length.c b/source4/heimdal/lib/asn1/der_length.c index 9b2e9f0998..93cabe466c 100644 --- a/source4/heimdal/lib/asn1/der_length.c +++ b/source4/heimdal/lib/asn1/der_length.c @@ -33,7 +33,7 @@ #include "der_locl.h" -RCSID("$Id: der_length.c,v 1.19 2006/10/14 05:26:06 lha Exp $"); +RCSID("$Id: der_length.c,v 1.20 2006/12/28 17:14:28 lha Exp $"); size_t _heim_len_unsigned (unsigned val) @@ -167,6 +167,12 @@ der_length_universal_string (const heim_universal_string *data) } size_t +der_length_visible_string (const heim_visible_string *data) +{ + return strlen(*data); +} + +size_t der_length_octet_string (const heim_octet_string *k) { return k->length; diff --git a/source4/heimdal/lib/asn1/der_put.c b/source4/heimdal/lib/asn1/der_put.c index b006f233ca..9ed8f21906 100644 --- a/source4/heimdal/lib/asn1/der_put.c +++ b/source4/heimdal/lib/asn1/der_put.c @@ -33,7 +33,7 @@ #include "der_locl.h" -RCSID("$Id: der_put.c,v 1.33 2005/07/12 06:27:23 lha Exp $"); +RCSID("$Id: der_put.c,v 1.34 2006/12/28 17:14:33 lha Exp $"); /* * All encoding functions take a pointer `p' to first position in @@ -231,6 +231,13 @@ der_put_universal_string (unsigned char *p, size_t len, } int +der_put_visible_string (unsigned char *p, size_t len, + const heim_visible_string *str, size_t *size) +{ + return der_put_general_string(p, len, str, size); +} + +int der_put_octet_string (unsigned char *p, size_t len, const heim_octet_string *data, size_t *size) { diff --git a/source4/heimdal/lib/asn1/digest.asn1 b/source4/heimdal/lib/asn1/digest.asn1 index 1f8f18b5cd..92bfb23234 100644 --- a/source4/heimdal/lib/asn1/digest.asn1 +++ b/source4/heimdal/lib/asn1/digest.asn1 @@ -1,4 +1,4 @@ --- $Id: digest.asn1,v 1.9 2006/08/25 11:57:54 lha Exp $ +-- $Id: digest.asn1,v 1.10 2006/12/15 19:13:39 lha Exp $ DIGEST DEFINITIONS ::= BEGIN @@ -58,9 +58,43 @@ DigestResponse ::= SEQUENCE { hash-a1 [3] OCTET STRING OPTIONAL } +NTLMInit ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + hostname [1] UTF8String OPTIONAL, + domain [1] UTF8String OPTIONAL +} + +NTLMInitReply ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + opaque [1] OCTET STRING, + targetname [2] UTF8String, + challange [3] OCTET STRING, + targetinfo [4] OCTET STRING OPTIONAL +} + +NTLMRequest ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + opaque [1] OCTET STRING, + username [2] UTF8String, + targetname [3] UTF8String, + targetinfo [4] OCTET STRING OPTIONAL, + lm [5] OCTET STRING, + ntlm [6] OCTET STRING, + sessionkey [7] OCTET STRING OPTIONAL +} + +NTLMResponse ::= SEQUENCE { + success [0] BOOLEAN, + flags [1] INTEGER (0..4294967295), + sessionkey [2] OCTET STRING OPTIONAL, + tickets [3] SEQUENCE OF OCTET STRING OPTIONAL +} + DigestReqInner ::= CHOICE { init [0] DigestInit, - digestRequest [1] DigestRequest + digestRequest [1] DigestRequest, + ntlmInit [2] NTLMInit, + ntlmRequest [3] NTLMRequest } DigestREQ ::= [APPLICATION 128] SEQUENCE { @@ -71,7 +105,9 @@ DigestREQ ::= [APPLICATION 128] SEQUENCE { DigestRepInner ::= CHOICE { error [0] DigestError, initReply [1] DigestInitReply, - response [2] DigestResponse + response [2] DigestResponse, + ntlmInitReply [3] NTLMInitReply, + ntlmResponse [4] NTLMResponse } DigestREP ::= [APPLICATION 129] SEQUENCE { diff --git a/source4/heimdal/lib/asn1/gen.c b/source4/heimdal/lib/asn1/gen.c index c3af316c88..3bb9022be8 100644 --- a/source4/heimdal/lib/asn1/gen.c +++ b/source4/heimdal/lib/asn1/gen.c @@ -33,7 +33,7 @@ #include "gen_locl.h" -RCSID("$Id: gen.c,v 1.69 2006/10/14 05:11:52 lha Exp $"); +RCSID("$Id: gen.c,v 1.70 2006/12/28 17:14:37 lha Exp $"); FILE *headerfile, *codefile, *logfile; @@ -136,6 +136,9 @@ init_generate (const char *filename, const char *base) " uint32_t *data;\n" "} heim_universal_string;\n\n"); fprintf (headerfile, + "typedef char *heim_visible_string;\n\n" + ); + fprintf (headerfile, "typedef struct heim_oid {\n" " size_t length;\n" " unsigned *components;\n" @@ -504,6 +507,10 @@ define_asn1 (int level, Type *t) space(level); fprintf (headerfile, "UniversalString"); break; + case TVisibleString: + space(level); + fprintf (headerfile, "VisibleString"); + break; case TOID : space(level); fprintf(headerfile, "OBJECT IDENTIFIER"); @@ -736,6 +743,10 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) space(level); fprintf (headerfile, "heim_universal_string %s;\n", name); break; + case TVisibleString: + space(level); + fprintf (headerfile, "heim_visible_string %s;\n", name); + break; case TOID : space(level); fprintf (headerfile, "heim_oid %s;\n", name); diff --git a/source4/heimdal/lib/asn1/gen_copy.c b/source4/heimdal/lib/asn1/gen_copy.c index 9455f33c6f..95646d0a3c 100644 --- a/source4/heimdal/lib/asn1/gen_copy.c +++ b/source4/heimdal/lib/asn1/gen_copy.c @@ -33,7 +33,7 @@ #include "gen_locl.h" -RCSID("$Id: gen_copy.c,v 1.18 2006/10/14 05:34:19 lha Exp $"); +RCSID("$Id: gen_copy.c,v 1.19 2006/12/28 17:14:42 lha Exp $"); static int used_fail; @@ -202,6 +202,9 @@ copy_type (const char *from, const char *to, const Type *t, int preserve) case TUniversalString: copy_primitive ("universal_string", from, to); break; + case TVisibleString: + copy_primitive ("visible_string", from, to); + break; case TTag: copy_type (from, to, t->subtype, preserve); break; diff --git a/source4/heimdal/lib/asn1/gen_decode.c b/source4/heimdal/lib/asn1/gen_decode.c index 193dab40e1..19ddbb46db 100644 --- a/source4/heimdal/lib/asn1/gen_decode.c +++ b/source4/heimdal/lib/asn1/gen_decode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -34,7 +34,7 @@ #include "gen_locl.h" #include "lex.h" -RCSID("$Id: gen_decode.c,v 1.30 2006/09/24 09:13:12 lha Exp $"); +RCSID("$Id: gen_decode.c,v 1.32 2006/12/29 17:30:32 lha Exp $"); static void decode_primitive (const char *typename, const char *name, const char *forwstr) @@ -74,6 +74,7 @@ is_primitive_type(int type) case TIA5String: case TBMPString: case TUniversalString: + case TVisibleString: case TNull: return 1; default: @@ -191,6 +192,11 @@ find_tag (const Type *t, *ty = PRIM; *tag = UT_UniversalString; break; + case TVisibleString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_VisibleString; + break; default: abort(); } @@ -580,6 +586,9 @@ decode_type (const char *name, const Type *t, int optional, case TUniversalString: decode_primitive ("universal_string", name, forwstr); break; + case TVisibleString: + decode_primitive ("visible_string", name, forwstr); + break; case TNull: fprintf (codefile, "/* NULL */\n"); break; @@ -620,6 +629,7 @@ generate_type_decode (const Symbol *s) case TIA5String: case TBMPString: case TUniversalString: + case TVisibleString: case TUTCTime: case TNull: case TEnumerated: diff --git a/source4/heimdal/lib/asn1/gen_encode.c b/source4/heimdal/lib/asn1/gen_encode.c index 4099fbf643..bc2aff86e5 100644 --- a/source4/heimdal/lib/asn1/gen_encode.c +++ b/source4/heimdal/lib/asn1/gen_encode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "gen_locl.h" -RCSID("$Id: gen_encode.c,v 1.19 2005/08/23 11:52:16 lha Exp $"); +RCSID("$Id: gen_encode.c,v 1.22 2006/12/29 17:30:03 lha Exp $"); static void encode_primitive (const char *typename, const char *name) @@ -151,7 +151,6 @@ encode_type (const char *name, const Type *t, const char *tmpstr) case TBitString: { Member *m; int pos; - int rest; if (ASN1_TAILQ_EMPTY(t->members)) { encode_primitive("bit_string", name); @@ -163,6 +162,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) "unsigned char c = 0;\n"); if (!rfc1510_bitstring) fprintf (codefile, + "int rest = 0;\n" "int bit_set = 0;\n"); #if 0 pos = t->members->prev->val; @@ -181,9 +181,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) if (rfc1510_bitstring) { if (pos < 31) pos = 31; - rest = 7 - (pos % 8); - } else - rest = 0; + } ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { while (m->val / 8 < pos / 8) { @@ -192,20 +190,27 @@ encode_type (const char *name, const Type *t, const char *tmpstr) "if (c != 0 || bit_set) {\n"); fprintf (codefile, "if (len < 1) return ASN1_OVERFLOW;\n" - "*p-- = c; len--; ret++;\n" - "c = 0;\n"); + "*p-- = c; len--; ret++;\n"); if (!rfc1510_bitstring) fprintf (codefile, + "if (!bit_set) {\n" + "rest = 0;\n" + "while(c) { \n" + "if (c & 1) break;\n" + "c = c >> 1;\n" + "rest++;\n" + "}\n" "bit_set = 1;\n" + "}\n" "}\n"); + fprintf (codefile, + "c = 0;\n"); pos -= 8; } fprintf (codefile, "if((%s)->%s) {\n" "c |= 1<<%d;\n", name, m->gen_name, 7 - m->val % 8); - if (!rfc1510_bitstring) - rest = 7 - m->val % 8; fprintf (codefile, "}\n"); } @@ -218,15 +223,25 @@ encode_type (const char *name, const Type *t, const char *tmpstr) "*p-- = c; len--; ret++;\n"); if (!rfc1510_bitstring) fprintf (codefile, + "if (!bit_set) {\n" + "rest = 0;\n" + "if(c) { \n" + "while(c) { \n" + "if (c & 1) break;\n" + "c = c >> 1;\n" + "rest++;\n" + "}\n" + "}\n" + "}\n" "}\n"); - + fprintf (codefile, "if (len < 1) return ASN1_OVERFLOW;\n" - "*p-- = %d;\n" + "*p-- = %s;\n" "len -= 1;\n" "ret += 1;\n" "}\n\n", - rest); + rfc1510_bitstring ? "0" : "rest"); constructed = 0; break; } @@ -467,6 +482,10 @@ encode_type (const char *name, const Type *t, const char *tmpstr) encode_primitive ("universal_string", name); constructed = 0; break; + case TVisibleString: + encode_primitive ("visible_string", name); + constructed = 0; + break; case TNull: fprintf (codefile, "/* NULL */\n"); constructed = 0; @@ -503,6 +522,7 @@ generate_type_encode (const Symbol *s) case TIA5String: case TBMPString: case TUniversalString: + case TVisibleString: case TNull: case TBitString: case TEnumerated: diff --git a/source4/heimdal/lib/asn1/gen_free.c b/source4/heimdal/lib/asn1/gen_free.c index 2b143bf818..26e02e39dd 100644 --- a/source4/heimdal/lib/asn1/gen_free.c +++ b/source4/heimdal/lib/asn1/gen_free.c @@ -33,7 +33,7 @@ #include "gen_locl.h" -RCSID("$Id: gen_free.c,v 1.16 2006/10/14 05:33:58 lha Exp $"); +RCSID("$Id: gen_free.c,v 1.17 2006/12/28 17:14:54 lha Exp $"); static void free_primitive (const char *typename, const char *name) @@ -160,6 +160,9 @@ free_type (const char *name, const Type *t, int preserve) case TUniversalString: free_primitive ("universal_string", name); break; + case TVisibleString: + free_primitive ("visible_string", name); + break; case TTag: free_type (name, t->subtype, preserve); break; diff --git a/source4/heimdal/lib/asn1/gen_length.c b/source4/heimdal/lib/asn1/gen_length.c index 0c92225b92..7f9dc7257b 100644 --- a/source4/heimdal/lib/asn1/gen_length.c +++ b/source4/heimdal/lib/asn1/gen_length.c @@ -33,7 +33,7 @@ #include "gen_locl.h" -RCSID("$Id: gen_length.c,v 1.21 2006/10/14 05:28:28 lha Exp $"); +RCSID("$Id: gen_length.c,v 1.22 2006/12/28 17:14:57 lha Exp $"); static void length_primitive (const char *typename, @@ -238,6 +238,9 @@ length_type (const char *name, const Type *t, case TUniversalString: length_primitive ("universal_string", name, variable); break; + case TVisibleString: + length_primitive ("visible_string", name, variable); + break; case TNull: fprintf (codefile, "/* NULL */\n"); break; diff --git a/source4/heimdal/lib/asn1/k5.asn1 b/source4/heimdal/lib/asn1/k5.asn1 index 3f501f0592..a86df38a99 100644 --- a/source4/heimdal/lib/asn1/k5.asn1 +++ b/source4/heimdal/lib/asn1/k5.asn1 @@ -1,4 +1,4 @@ --- $Id: k5.asn1,v 1.50 2006/09/11 13:28:59 lha Exp $ +-- $Id: k5.asn1,v 1.51 2006/11/21 05:17:47 lha Exp $ KERBEROS5 DEFINITIONS ::= BEGIN @@ -70,11 +70,11 @@ PADATA-TYPE ::= INTEGER { KRB5-PADATA-TD-REQ-NONCE(107), -- INTEGER KRB5-PADATA-TD-REQ-SEQ(108), -- INTEGER KRB5-PADATA-PA-PAC-REQUEST(128), -- jbrezak@exchange.microsoft.com - KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to + KRB5-PADATA-S4U2SELF(129), + KRB5-PADATA-PK-AS-09-BINDING(132) -- client send this to -- tell KDC that is supports -- the asCheckSum in the -- PK-AS-REP - KRB5-PADATA-S4U2SELF(-17) } AUTHDATA-TYPE ::= INTEGER { diff --git a/source4/heimdal/lib/asn1/kx509.asn1 b/source4/heimdal/lib/asn1/kx509.asn1 new file mode 100644 index 0000000000..9706b061c3 --- /dev/null +++ b/source4/heimdal/lib/asn1/kx509.asn1 @@ -0,0 +1,20 @@ +-- $Id: kx509.asn1,v 1.1 2006/12/28 21:05:23 lha Exp $ + +KX509 DEFINITIONS ::= +BEGIN + +Kx509Request ::= SEQUENCE { + authenticator OCTET STRING, + pk-hash OCTET STRING, + pk-key OCTET STRING +} + +Kx509Response ::= SEQUENCE { + error-code[0] INTEGER (-2147483648..2147483647) + OPTIONAL -- DEFAULT 0 --, + hash[1] OCTET STRING OPTIONAL, + certificate[2] OCTET STRING OPTIONAL, + e-text[3] VisibleString OPTIONAL +} + +END diff --git a/source4/heimdal/lib/asn1/lex.l b/source4/heimdal/lib/asn1/lex.l index 4b2c5af062..6ec7b67bb9 100644 --- a/source4/heimdal/lib/asn1/lex.l +++ b/source4/heimdal/lib/asn1/lex.l @@ -32,7 +32,7 @@ * SUCH DAMAGE. */ -/* $Id: lex.l,v 1.27 2005/09/13 18:17:16 lha Exp $ */ +/* $Id: lex.l,v 1.31 2006/10/21 11:57:22 lha Exp $ */ #ifdef HAVE_CONFIG_H #include <config.h> @@ -58,6 +58,12 @@ static void unterminated(const char *, unsigned); %} +/* This is for broken old lexes (solaris 10 and hpux) */ +%e 2000 +%p 5000 +%a 5000 +%n 1000 +%o 10000 %% ABSENT { return kw_ABSENT; } diff --git a/source4/heimdal/lib/asn1/parse.c b/source4/heimdal/lib/asn1/parse.c index 29d13ed68d..fc9f195e1f 100644 --- a/source4/heimdal/lib/asn1/parse.c +++ b/source4/heimdal/lib/asn1/parse.c @@ -251,7 +251,7 @@ #include "gen_locl.h" #include "der.h" -RCSID("$Id: parse.y,v 1.28 2006/04/28 10:51:35 lha Exp $"); +RCSID("$Id: parse.y,v 1.29 2006/12/28 17:15:02 lha Exp $"); static Type *new_type (Typetype t); static struct constraint_spec *new_constraint_spec(enum ctype); @@ -466,16 +466,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 4 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 168 +#define YYLAST 169 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 98 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 67 /* YYNRULES -- Number of rules. */ -#define YYNRULES 130 +#define YYNRULES 131 /* YYNRULES -- Number of states. */ -#define YYNSTATES 201 +#define YYNSTATES 202 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 @@ -538,11 +538,11 @@ static const unsigned short int yyprhs[] = 167, 171, 176, 180, 184, 189, 191, 193, 195, 197, 199, 202, 206, 208, 210, 212, 215, 219, 225, 230, 234, 239, 240, 242, 244, 246, 247, 249, 251, 256, - 258, 260, 262, 264, 266, 268, 270, 272, 276, 280, - 283, 285, 288, 292, 294, 298, 303, 305, 306, 310, - 311, 314, 319, 321, 323, 325, 327, 329, 331, 333, + 258, 260, 262, 264, 266, 268, 270, 272, 274, 278, + 282, 285, 287, 290, 294, 296, 300, 305, 307, 308, + 312, 313, 316, 321, 323, 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, - 355 + 355, 357 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ @@ -574,16 +574,16 @@ static const short int yyrhs[] = 139, 141, 111, -1, 96, 140, 89, 97, -1, -1, 76, -1, 6, -1, 60, -1, -1, 27, -1, 38, -1, 86, 111, 84, 154, -1, 144, -1, 33, -1, - 78, -1, 61, -1, 36, -1, 10, -1, 79, -1, - 147, -1, 145, 91, 147, -1, 145, 91, 85, -1, - 86, 111, -1, 146, -1, 146, 54, -1, 146, 20, - 154, -1, 149, -1, 148, 91, 149, -1, 86, 92, - 89, 93, -1, 151, -1, -1, 94, 152, 95, -1, - -1, 153, 152, -1, 86, 92, 89, 93, -1, 86, - -1, 89, -1, 155, -1, 156, -1, 160, -1, 159, - -1, 161, -1, 164, -1, 163, -1, 157, -1, 158, - -1, 86, -1, 88, -1, 71, -1, 31, -1, 162, - -1, 89, -1, 49, -1, 151, -1 + 78, -1, 61, -1, 81, -1, 36, -1, 10, -1, + 79, -1, 147, -1, 145, 91, 147, -1, 145, 91, + 85, -1, 86, 111, -1, 146, -1, 146, 54, -1, + 146, 20, 154, -1, 149, -1, 148, 91, 149, -1, + 86, 92, 89, 93, -1, 151, -1, -1, 94, 152, + 95, -1, -1, 153, 152, -1, 86, 92, 89, 93, + -1, 86, -1, 89, -1, 155, -1, 156, -1, 160, + -1, 159, -1, 161, -1, 164, -1, 163, -1, 157, + -1, 158, -1, 86, -1, 88, -1, 71, -1, 31, + -1, 162, -1, 89, -1, 49, -1, 151, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ @@ -598,11 +598,11 @@ static const unsigned short int yyrline[] = 456, 464, 470, 478, 486, 493, 494, 497, 508, 513, 520, 536, 542, 545, 546, 549, 555, 563, 573, 579, 592, 601, 604, 608, 612, 619, 622, 626, 633, 644, - 647, 652, 657, 662, 667, 672, 680, 686, 691, 702, - 713, 719, 725, 733, 739, 746, 759, 760, 763, 770, - 773, 784, 788, 799, 805, 806, 809, 810, 811, 812, - 813, 816, 819, 822, 833, 841, 847, 855, 863, 866, - 871 + 647, 652, 657, 662, 667, 672, 677, 685, 691, 696, + 707, 718, 724, 730, 738, 744, 751, 764, 765, 768, + 775, 778, 789, 793, 804, 810, 811, 814, 815, 816, + 817, 818, 821, 824, 827, 838, 846, 852, 860, 868, + 871, 876 }; #endif @@ -682,11 +682,11 @@ static const unsigned char yyr1[] = 125, 126, 126, 127, 128, 129, 129, 130, 131, 131, 132, 133, 134, 135, 135, 136, 136, 136, 137, 138, 139, 140, 140, 140, 140, 141, 141, 141, 142, 143, - 144, 144, 144, 144, 144, 144, 145, 145, 145, 146, - 147, 147, 147, 148, 148, 149, 150, 150, 151, 152, - 152, 153, 153, 153, 154, 154, 155, 155, 155, 155, - 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, - 164 + 144, 144, 144, 144, 144, 144, 144, 145, 145, 145, + 146, 147, 147, 147, 148, 148, 149, 150, 150, 151, + 152, 152, 153, 153, 153, 154, 154, 155, 155, 155, + 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, + 163, 164 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -701,11 +701,11 @@ static const unsigned char yyr2[] = 3, 4, 3, 3, 4, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 2, 3, 5, 4, 3, 4, 0, 1, 1, 1, 0, 1, 1, 4, 1, - 1, 1, 1, 1, 1, 1, 1, 3, 3, 2, - 1, 2, 3, 1, 3, 4, 1, 0, 3, 0, - 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 2, 1, 2, 3, 1, 3, 4, 1, 0, 3, + 0, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1 + 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -716,76 +716,76 @@ static const unsigned char yydefact[] = 0, 0, 0, 6, 1, 0, 0, 0, 8, 5, 3, 4, 0, 0, 7, 0, 10, 14, 0, 0, 23, 0, 13, 15, 0, 2, 0, 9, 18, 20, - 21, 0, 11, 16, 0, 0, 94, 42, 0, 0, - 90, 68, 93, 44, 57, 0, 0, 92, 0, 0, - 69, 91, 95, 0, 67, 81, 0, 25, 29, 33, - 32, 28, 35, 36, 34, 37, 38, 39, 40, 31, - 26, 65, 66, 27, 41, 85, 30, 89, 19, 22, - 107, 53, 0, 0, 0, 0, 45, 55, 56, 0, - 0, 0, 0, 24, 83, 84, 82, 0, 0, 0, - 70, 86, 87, 0, 109, 17, 106, 0, 0, 0, - 100, 96, 0, 52, 47, 0, 126, 129, 125, 123, - 124, 128, 130, 0, 114, 115, 121, 122, 117, 116, - 118, 127, 120, 119, 0, 60, 59, 0, 63, 62, - 0, 0, 88, 0, 0, 0, 0, 72, 73, 74, - 79, 112, 113, 0, 109, 0, 0, 103, 99, 0, - 64, 0, 101, 0, 0, 51, 0, 46, 58, 61, - 80, 0, 75, 0, 71, 0, 108, 110, 0, 0, - 54, 98, 97, 102, 0, 49, 48, 0, 0, 0, - 76, 0, 0, 104, 50, 43, 78, 0, 111, 105, - 77 + 21, 0, 11, 16, 0, 0, 95, 42, 0, 0, + 90, 68, 94, 44, 57, 0, 0, 92, 0, 0, + 69, 91, 96, 93, 0, 67, 81, 0, 25, 29, + 33, 32, 28, 35, 36, 34, 37, 38, 39, 40, + 31, 26, 65, 66, 27, 41, 85, 30, 89, 19, + 22, 108, 53, 0, 0, 0, 0, 45, 55, 56, + 0, 0, 0, 0, 24, 83, 84, 82, 0, 0, + 0, 70, 86, 87, 0, 110, 17, 107, 0, 0, + 0, 101, 97, 0, 52, 47, 0, 127, 130, 126, + 124, 125, 129, 131, 0, 115, 116, 122, 123, 118, + 117, 119, 128, 121, 120, 0, 60, 59, 0, 63, + 62, 0, 0, 88, 0, 0, 0, 0, 72, 73, + 74, 79, 113, 114, 0, 110, 0, 0, 104, 100, + 0, 64, 0, 102, 0, 0, 51, 0, 46, 58, + 61, 80, 0, 75, 0, 71, 0, 109, 111, 0, + 0, 54, 99, 98, 103, 0, 49, 48, 0, 0, + 0, 76, 0, 0, 105, 50, 43, 78, 0, 112, + 106, 77 }; /* YYDEFGOTO[NTERM-NUM]. */ static const short int yydefgoto[] = { -1, 2, 8, 13, 18, 19, 21, 22, 23, 27, - 28, 24, 29, 56, 57, 58, 86, 59, 113, 114, - 60, 115, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 100, 146, 147, 148, 149, - 74, 75, 97, 103, 30, 76, 77, 109, 110, 111, - 156, 157, 105, 122, 153, 154, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133 + 28, 24, 29, 57, 58, 59, 87, 60, 114, 115, + 61, 116, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 101, 147, 148, 149, 150, + 75, 76, 98, 104, 30, 77, 78, 110, 111, 112, + 157, 158, 106, 123, 154, 155, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -99 +#define YYPACT_NINF -100 static const short int yypact[] = { - -46, 20, 13, 21, -99, 11, 23, 25, 54, -99, - -99, -99, 58, 6, -99, 90, -34, 15, 80, 19, - 16, 18, 15, -99, 74, -99, -7, -99, 19, -99, - -99, 15, -99, -99, 24, 42, -99, -99, 17, 26, - -99, -99, -99, -73, -99, 76, 50, -99, -45, -44, - -99, -99, -99, 51, -99, 4, -67, -99, -99, -99, - -99, -99, -99, -99, -99, -99, -99, -99, -99, -99, - -99, -99, -99, -99, -99, -16, -99, -99, -99, -99, - 27, 28, 33, 37, 47, 37, -99, -99, -99, 51, - -72, 51, -71, 22, -99, -99, -99, 35, 47, 12, - -99, -99, -99, 51, 2, -99, -99, 39, 51, -75, - -8, -99, 34, 36, -99, 43, -99, -99, -99, -99, - -99, -99, -99, 48, -99, -99, -99, -99, -99, -99, - -99, -99, -99, -99, -57, 22, -99, -48, 22, -99, - -22, 45, -99, 120, 51, 122, 46, -99, -99, -99, - 22, 52, -99, 53, 2, 57, -9, -99, 22, -53, - -99, 47, -99, 56, -19, -99, 47, -99, -99, -99, - -99, 49, -18, 47, -99, 61, -99, -99, 62, 39, - -99, -99, -99, -99, 59, -99, -99, 60, 63, 128, - -99, 64, 66, -99, -99, -99, -99, 47, -99, -99, - -99 + -65, 19, 33, 5, -100, -29, -17, 11, 53, -100, + -100, -100, 47, 13, -100, 90, -34, 18, 81, 20, + 16, 21, 18, -100, 76, -100, -7, -100, 20, -100, + -100, 18, -100, -100, 23, 43, -100, -100, 24, 25, + -100, -100, -100, -4, -100, 77, 46, -100, -48, -45, + -100, -100, -100, -100, 51, -100, 4, -64, -100, -100, + -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, + -100, -100, -100, -100, -100, -100, -16, -100, -100, -100, + -100, 26, 27, 31, 36, 52, 36, -100, -100, -100, + 51, -71, 51, -70, 32, -100, -100, -100, 37, 52, + 12, -100, -100, -100, 51, -39, -100, -100, 39, 51, + -78, -6, -100, 35, 40, -100, 38, -100, -100, -100, + -100, -100, -100, -100, 56, -100, -100, -100, -100, -100, + -100, -100, -100, -100, -100, -72, 32, -100, -57, 32, + -100, -36, 45, -100, 122, 51, 123, 50, -100, -100, + -100, 32, 44, -100, 49, -39, 57, -22, -100, 32, + -19, -100, 52, -100, 59, 10, -100, 52, -100, -100, + -100, -100, 58, -14, 52, -100, 61, -100, -100, 62, + 39, -100, -100, -100, -100, 60, -100, -100, 63, 64, + 133, -100, 65, 67, -100, -100, -100, -100, 52, -100, + -100, -100 }; /* YYPGOTO[NTERM-NUM]. */ -static const yysigned_char yypgoto[] = +static const short int yypgoto[] = { - -99, -99, -99, -99, -99, -99, -99, -99, 124, 126, - -99, 125, -99, -52, -99, -99, -99, -99, 70, -4, - -99, -99, -99, -99, -99, -99, -99, -99, -99, -99, - -99, -99, -99, -99, -99, -99, -99, -99, -99, -99, - -99, -99, -99, -99, -99, -99, -99, -37, -99, 3, - -99, -15, -99, 81, 9, -99, -98, -99, -99, -99, - -99, -99, -99, -99, 5, -99, -99 + -100, -100, -100, -100, -100, -100, -100, -100, 132, 127, + -100, 126, -100, -53, -100, -100, -100, -100, 75, -3, + -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, + -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, + -100, -100, -100, -100, -100, -100, -100, 0, -100, 3, + -100, -15, -100, 83, 14, -100, -99, -100, -100, -100, + -100, -100, -100, -100, 2, -100, -100 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -795,44 +795,44 @@ static const yysigned_char yypgoto[] = #define YYTABLE_NINF -13 static const short int yytable[] = { - 142, 93, 35, 36, 37, 189, 17, 38, 89, 91, - 94, 101, 161, 4, 108, 108, 159, 98, 39, 84, - 160, 85, 102, 136, 139, 99, 40, 41, 5, 42, - 143, 144, 181, 108, 164, 145, 43, 135, 167, 138, - 1, 3, 44, 159, 45, 46, 162, 168, 6, 90, - 92, 150, -12, 137, 47, 140, 158, 48, 49, 7, - 35, 36, 37, 183, 95, 38, 185, 112, 187, 159, - 50, 51, 52, 169, 99, 190, 39, 53, 116, 54, - 96, 9, 179, 12, 40, 41, 180, 42, 151, 55, - 15, 152, 172, 10, 43, 11, 117, 14, 16, 200, - 44, 20, 45, 46, 25, 26, 34, 31, 32, 81, - 80, 82, 47, 87, 99, 48, 49, 88, 118, 108, - 83, 104, 107, 112, 141, 155, 163, 164, 50, 51, - 52, 166, 171, 119, 173, 120, 121, 54, 165, 174, - 197, 104, 170, 188, 175, 121, 33, 55, 176, 178, - 191, 192, 194, 195, 78, 134, 79, 198, 196, 199, - 186, 106, 182, 177, 193, 0, 0, 0, 184 + 143, 94, 35, 36, 37, 90, 17, 38, 92, 190, + 95, 102, 5, 160, 162, 109, 109, 161, 39, 165, + 99, 1, 103, 168, 137, 140, 40, 41, 100, 42, + 144, 145, 6, 4, 160, 146, 43, 136, 169, 139, + 3, 9, 44, 7, 45, 46, 91, 152, 163, 93, + 153, 151, -12, 10, 47, 160, 159, 48, 49, 170, + 35, 36, 37, 184, 96, 38, 182, 109, 188, 180, + 50, 51, 52, 181, 53, 191, 39, 54, 100, 55, + 97, 11, 12, 117, 40, 41, 14, 42, 85, 56, + 86, 138, 173, 141, 43, 186, 113, 15, 16, 201, + 44, 118, 45, 46, 20, 25, 26, 31, 34, 81, + 82, 32, 47, 89, 88, 48, 49, 109, 83, 84, + 105, 108, 113, 119, 100, 156, 142, 164, 50, 51, + 52, 165, 53, 166, 172, 174, 176, 55, 120, 167, + 121, 122, 171, 175, 177, 198, 105, 56, 122, 179, + 192, 193, 189, 195, 33, 79, 196, 80, 199, 197, + 200, 135, 187, 183, 107, 194, 185, 0, 0, 178 }; static const short int yycheck[] = { - 98, 53, 9, 10, 11, 23, 40, 14, 53, 53, - 6, 27, 20, 0, 86, 86, 91, 84, 25, 92, - 95, 94, 38, 95, 95, 92, 33, 34, 7, 36, - 18, 19, 85, 86, 91, 23, 43, 89, 95, 91, - 86, 21, 49, 91, 51, 52, 54, 95, 27, 94, - 94, 103, 86, 90, 61, 92, 108, 64, 65, 38, - 9, 10, 11, 161, 60, 14, 85, 86, 166, 91, - 77, 78, 79, 95, 92, 173, 25, 84, 31, 86, - 76, 70, 91, 29, 33, 34, 95, 36, 86, 96, - 84, 89, 144, 70, 43, 70, 49, 39, 8, 197, - 49, 86, 51, 52, 24, 86, 32, 91, 90, 67, - 86, 94, 61, 37, 92, 64, 65, 67, 71, 86, - 94, 94, 94, 86, 89, 86, 92, 91, 77, 78, - 79, 83, 12, 86, 12, 88, 89, 86, 95, 93, - 12, 94, 97, 94, 92, 89, 22, 96, 95, 92, - 89, 89, 93, 93, 28, 85, 31, 93, 95, 93, - 164, 80, 159, 154, 179, -1, -1, -1, 163 + 99, 54, 9, 10, 11, 53, 40, 14, 53, 23, + 6, 27, 7, 91, 20, 86, 86, 95, 25, 91, + 84, 86, 38, 95, 95, 95, 33, 34, 92, 36, + 18, 19, 27, 0, 91, 23, 43, 90, 95, 92, + 21, 70, 49, 38, 51, 52, 94, 86, 54, 94, + 89, 104, 86, 70, 61, 91, 109, 64, 65, 95, + 9, 10, 11, 162, 60, 14, 85, 86, 167, 91, + 77, 78, 79, 95, 81, 174, 25, 84, 92, 86, + 76, 70, 29, 31, 33, 34, 39, 36, 92, 96, + 94, 91, 145, 93, 43, 85, 86, 84, 8, 198, + 49, 49, 51, 52, 86, 24, 86, 91, 32, 86, + 67, 90, 61, 67, 37, 64, 65, 86, 94, 94, + 94, 94, 86, 71, 92, 86, 89, 92, 77, 78, + 79, 91, 81, 95, 12, 12, 92, 86, 86, 83, + 88, 89, 97, 93, 95, 12, 94, 96, 89, 92, + 89, 89, 94, 93, 22, 28, 93, 31, 93, 95, + 93, 86, 165, 160, 81, 180, 164, -1, -1, 155 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -844,22 +844,22 @@ static const unsigned char yystos[] = 86, 104, 105, 106, 109, 24, 86, 107, 108, 110, 142, 91, 90, 106, 32, 9, 10, 11, 14, 25, 33, 34, 36, 43, 49, 51, 52, 61, 64, 65, - 77, 78, 79, 84, 86, 96, 111, 112, 113, 115, - 118, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 138, 139, 143, 144, 107, 109, - 86, 67, 94, 94, 92, 94, 114, 37, 67, 53, - 94, 53, 94, 111, 6, 60, 76, 140, 84, 92, - 133, 27, 38, 141, 94, 150, 151, 94, 86, 145, - 146, 147, 86, 116, 117, 119, 31, 49, 71, 86, - 88, 89, 151, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 116, 111, 95, 145, 111, 95, - 145, 89, 154, 18, 19, 23, 134, 135, 136, 137, - 111, 86, 89, 152, 153, 86, 148, 149, 111, 91, - 95, 20, 54, 92, 91, 95, 83, 95, 95, 95, - 97, 12, 111, 12, 93, 92, 95, 152, 92, 91, - 95, 85, 147, 154, 162, 85, 117, 154, 94, 23, - 154, 89, 89, 149, 93, 93, 95, 12, 93, 93, - 154 + 77, 78, 79, 81, 84, 86, 96, 111, 112, 113, + 115, 118, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 138, 139, 143, 144, 107, + 109, 86, 67, 94, 94, 92, 94, 114, 37, 67, + 53, 94, 53, 94, 111, 6, 60, 76, 140, 84, + 92, 133, 27, 38, 141, 94, 150, 151, 94, 86, + 145, 146, 147, 86, 116, 117, 119, 31, 49, 71, + 86, 88, 89, 151, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 116, 111, 95, 145, 111, + 95, 145, 89, 154, 18, 19, 23, 134, 135, 136, + 137, 111, 86, 89, 152, 153, 86, 148, 149, 111, + 91, 95, 20, 54, 92, 91, 95, 83, 95, 95, + 95, 97, 12, 111, 12, 93, 92, 95, 152, 92, + 91, 95, 85, 147, 154, 162, 85, 117, 154, 94, + 23, 154, 89, 89, 149, 93, 93, 95, 12, 93, + 93, 154 }; #define yyerrok (yyerrstatus = 0) @@ -1987,29 +1987,37 @@ yyreduce: case 93: #line 663 "parse.y" { - (yyval.type) = new_tag(ASN1_C_UNIV, UT_IA5String, - TE_EXPLICIT, new_type(TIA5String)); + (yyval.type) = new_tag(ASN1_C_UNIV, UT_VisibleString, + TE_EXPLICIT, new_type(TVisibleString)); } break; case 94: #line 668 "parse.y" { - (yyval.type) = new_tag(ASN1_C_UNIV, UT_BMPString, - TE_EXPLICIT, new_type(TBMPString)); + (yyval.type) = new_tag(ASN1_C_UNIV, UT_IA5String, + TE_EXPLICIT, new_type(TIA5String)); } break; case 95: #line 673 "parse.y" { + (yyval.type) = new_tag(ASN1_C_UNIV, UT_BMPString, + TE_EXPLICIT, new_type(TBMPString)); + } + break; + + case 96: +#line 678 "parse.y" + { (yyval.type) = new_tag(ASN1_C_UNIV, UT_UniversalString, TE_EXPLICIT, new_type(TUniversalString)); } break; - case 96: -#line 681 "parse.y" + case 97: +#line 686 "parse.y" { (yyval.members) = emalloc(sizeof(*(yyval.members))); ASN1_TAILQ_INIT((yyval.members)); @@ -2017,16 +2025,16 @@ yyreduce: } break; - case 97: -#line 687 "parse.y" + case 98: +#line 692 "parse.y" { ASN1_TAILQ_INSERT_TAIL((yyvsp[-2].members), (yyvsp[0].member), members); (yyval.members) = (yyvsp[-2].members); } break; - case 98: -#line 692 "parse.y" + case 99: +#line 697 "parse.y" { struct member *m = ecalloc(1, sizeof(*m)); m->name = estrdup("..."); @@ -2037,8 +2045,8 @@ yyreduce: } break; - case 99: -#line 703 "parse.y" + case 100: +#line 708 "parse.y" { (yyval.member) = emalloc(sizeof(*(yyval.member))); (yyval.member)->name = (yyvsp[-1].name); @@ -2049,8 +2057,8 @@ yyreduce: } break; - case 100: -#line 714 "parse.y" + case 101: +#line 719 "parse.y" { (yyval.member) = (yyvsp[0].member); (yyval.member)->optional = 0; @@ -2058,8 +2066,8 @@ yyreduce: } break; - case 101: -#line 720 "parse.y" + case 102: +#line 725 "parse.y" { (yyval.member) = (yyvsp[-1].member); (yyval.member)->optional = 1; @@ -2067,8 +2075,8 @@ yyreduce: } break; - case 102: -#line 726 "parse.y" + case 103: +#line 731 "parse.y" { (yyval.member) = (yyvsp[-2].member); (yyval.member)->optional = 0; @@ -2076,8 +2084,8 @@ yyreduce: } break; - case 103: -#line 734 "parse.y" + case 104: +#line 739 "parse.y" { (yyval.members) = emalloc(sizeof(*(yyval.members))); ASN1_TAILQ_INIT((yyval.members)); @@ -2085,16 +2093,16 @@ yyreduce: } break; - case 104: -#line 740 "parse.y" + case 105: +#line 745 "parse.y" { ASN1_TAILQ_INSERT_TAIL((yyvsp[-2].members), (yyvsp[0].member), members); (yyval.members) = (yyvsp[-2].members); } break; - case 105: -#line 747 "parse.y" + case 106: +#line 752 "parse.y" { (yyval.member) = emalloc(sizeof(*(yyval.member))); (yyval.member)->name = (yyvsp[-3].name); @@ -2107,27 +2115,27 @@ yyreduce: } break; - case 107: -#line 760 "parse.y" + case 108: +#line 765 "parse.y" { (yyval.objid) = NULL; } break; - case 108: -#line 764 "parse.y" + case 109: +#line 769 "parse.y" { (yyval.objid) = (yyvsp[-1].objid); } break; - case 109: -#line 770 "parse.y" + case 110: +#line 775 "parse.y" { (yyval.objid) = NULL; } break; - case 110: -#line 774 "parse.y" + case 111: +#line 779 "parse.y" { if ((yyvsp[0].objid)) { (yyval.objid) = (yyvsp[0].objid); @@ -2138,15 +2146,15 @@ yyreduce: } break; - case 111: -#line 785 "parse.y" + case 112: +#line 790 "parse.y" { (yyval.objid) = new_objid((yyvsp[-3].name), (yyvsp[-1].constant)); } break; - case 112: -#line 789 "parse.y" + case 113: +#line 794 "parse.y" { Symbol *s = addsym((yyvsp[0].name)); if(s->stype != SValue || @@ -2159,15 +2167,15 @@ yyreduce: } break; - case 113: -#line 800 "parse.y" + case 114: +#line 805 "parse.y" { (yyval.objid) = new_objid(NULL, (yyvsp[0].constant)); } break; - case 123: -#line 823 "parse.y" + case 124: +#line 828 "parse.y" { Symbol *s = addsym((yyvsp[0].name)); if(s->stype != SValue) @@ -2178,8 +2186,8 @@ yyreduce: } break; - case 124: -#line 834 "parse.y" + case 125: +#line 839 "parse.y" { (yyval.value) = emalloc(sizeof(*(yyval.value))); (yyval.value)->type = stringvalue; @@ -2187,8 +2195,8 @@ yyreduce: } break; - case 125: -#line 842 "parse.y" + case 126: +#line 847 "parse.y" { (yyval.value) = emalloc(sizeof(*(yyval.value))); (yyval.value)->type = booleanvalue; @@ -2196,8 +2204,8 @@ yyreduce: } break; - case 126: -#line 848 "parse.y" + case 127: +#line 853 "parse.y" { (yyval.value) = emalloc(sizeof(*(yyval.value))); (yyval.value)->type = booleanvalue; @@ -2205,8 +2213,8 @@ yyreduce: } break; - case 127: -#line 856 "parse.y" + case 128: +#line 861 "parse.y" { (yyval.value) = emalloc(sizeof(*(yyval.value))); (yyval.value)->type = integervalue; @@ -2214,14 +2222,14 @@ yyreduce: } break; - case 129: -#line 867 "parse.y" + case 130: +#line 872 "parse.y" { } break; - case 130: -#line 872 "parse.y" + case 131: +#line 877 "parse.y" { (yyval.value) = emalloc(sizeof(*(yyval.value))); (yyval.value)->type = objectidentifiervalue; @@ -2234,7 +2242,7 @@ yyreduce: } /* Line 1126 of yacc.c. */ -#line 2238 "parse.c" +#line 2246 "parse.c" yyvsp -= yylen; yyssp -= yylen; @@ -2502,7 +2510,7 @@ yyreturn: } -#line 879 "parse.y" +#line 884 "parse.y" void diff --git a/source4/heimdal/lib/asn1/parse.y b/source4/heimdal/lib/asn1/parse.y index 2238478284..029cef9f0f 100644 --- a/source4/heimdal/lib/asn1/parse.y +++ b/source4/heimdal/lib/asn1/parse.y @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: parse.y,v 1.27 2005/12/14 09:44:36 lha Exp $ */ +/* $Id: parse.y,v 1.29 2006/12/28 17:15:02 lha Exp $ */ %{ #ifdef HAVE_CONFIG_H @@ -45,7 +45,7 @@ #include "gen_locl.h" #include "der.h" -RCSID("$Id: parse.y,v 1.27 2005/12/14 09:44:36 lha Exp $"); +RCSID("$Id: parse.y,v 1.29 2006/12/28 17:15:02 lha Exp $"); static Type *new_type (Typetype t); static struct constraint_spec *new_constraint_spec(enum ctype); @@ -537,8 +537,10 @@ Constraint : '(' ConstraintSpec ')' { $$ = $2; } + ; ConstraintSpec : GeneralConstraint + ; GeneralConstraint: ContentsConstraint | UserDefinedConstraint @@ -657,6 +659,11 @@ RestrictedCharactedStringType: kw_GeneralString $$ = new_tag(ASN1_C_UNIV, UT_PrintableString, TE_EXPLICIT, new_type(TPrintableString)); } + | kw_VisibleString + { + $$ = new_tag(ASN1_C_UNIV, UT_VisibleString, + TE_EXPLICIT, new_type(TVisibleString)); + } | kw_IA5String { $$ = new_tag(ASN1_C_UNIV, UT_IA5String, diff --git a/source4/heimdal/lib/asn1/rfc2459.asn1 b/source4/heimdal/lib/asn1/rfc2459.asn1 index eebbc3211b..430674a5ee 100644 --- a/source4/heimdal/lib/asn1/rfc2459.asn1 +++ b/source4/heimdal/lib/asn1/rfc2459.asn1 @@ -406,13 +406,31 @@ CRLReason ::= ENUMERATED { aACompromise (10) } +id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + dod(6) internet(1) security(5) mechanisms(5) pkix(7) } + +id-pkix-on OBJECT IDENTIFIER ::= { id-pkix 8 } +id-pkix-on-dnsSRV OBJECT IDENTIFIER ::= { id-pkix-on 7 } + +id-pkix-kp OBJECT IDENTIFIER ::= { id-pkix 3 } +id-pkix-kp-serverAuth OBJECT IDENTIFIER ::= { id-pkix-kp 1 } +id-pkix-kp-clientAuth OBJECT IDENTIFIER ::= { id-pkix-kp 2 } +id-pkix-kp-emailProtection OBJECT IDENTIFIER ::= { id-pkix-kp 4 } +id-pkix-kp-timeStamping OBJECT IDENTIFIER ::= { id-pkix-kp 8 } +id-pkix-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-pkix-kp 9 } + -- RFC 3820 Proxy Certificate Profile -id-pkix-pe OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) - dod(6) internet(1) security(5) mechanisms(5) pkix(7) 1 } +id-pkix-pe OBJECT IDENTIFIER ::= { id-pkix 1 } id-pe-proxyCertInfo OBJECT IDENTIFIER ::= { id-pkix-pe 14 } +id-pkix-ppl OBJECT IDENTIFIER ::= { id-pkix 21 } + +id-pkix-ppl-anyLanguage OBJECT IDENTIFIER ::= { id-pkix-ppl 0 } +id-pkix-ppl-inheritAll OBJECT IDENTIFIER ::= { id-pkix-ppl 1 } +id-pkix-ppl-independent OBJECT IDENTIFIER ::= { id-pkix-ppl 2 } + ProxyPolicy ::= SEQUENCE { policyLanguage OBJECT IDENTIFIER, policy OCTET STRING OPTIONAL diff --git a/source4/heimdal/lib/asn1/symbol.h b/source4/heimdal/lib/asn1/symbol.h index 93a6e019bd..436bd043a1 100644 --- a/source4/heimdal/lib/asn1/symbol.h +++ b/source4/heimdal/lib/asn1/symbol.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: symbol.h,v 1.13 2005/12/06 19:59:52 lha Exp $ */ +/* $Id: symbol.h,v 1.14 2006/12/28 17:15:05 lha Exp $ */ #ifndef _SYMBOL_H #define _SYMBOL_H @@ -60,7 +60,8 @@ enum typetype { TUTCTime, TUTF8String, TBMPString, - TUniversalString + TUniversalString, + TVisibleString }; typedef enum typetype Typetype; diff --git a/source4/heimdal/lib/com_err/lex.c b/source4/heimdal/lib/com_err/lex.c index 30b44d0c19..8b7113baa2 100644 --- a/source4/heimdal/lib/com_err/lex.c +++ b/source4/heimdal/lib/com_err/lex.c @@ -1,7 +1,8 @@ -/* A lexical scanner generated by flex */ +#include "config.h" +/* A lexical scanner generated by flex*/ /* Scanner skeleton version: - * $Header: /cvs/root/flex/flex/skel.c,v 1.2 2004/05/07 00:28:17 jkh Exp $ + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ */ #define FLEX_SCANNER @@ -9,6 +10,7 @@ #define YY_FLEX_MINOR_VERSION 5 #include <stdio.h> +#include <unistd.h> /* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ @@ -22,7 +24,6 @@ #ifdef __cplusplus #include <stdlib.h> -#include <unistd.h> /* Use prototypes in function declarations. */ #define YY_USE_PROTOS @@ -134,6 +135,15 @@ extern FILE *yyin, *yyout; #define unput(c) yyunput( c, yytext_ptr ) +/* Some routines like yy_flex_realloc() are emitted as static but are + not called by all lexers. This generates warnings in some compilers, + notably GCC. Arrange to suppress these. */ +#ifdef __GNUC__ +#define YY_MAY_BE_UNUSED __attribute__((unused)) +#else +#define YY_MAY_BE_UNUSED +#endif + /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). @@ -240,7 +250,7 @@ YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )) YY_MAY_BE_UNUSED; static void yy_flex_free YY_PROTO(( void * )); #define yy_new_buffer yy_create_buffer @@ -385,9 +395,9 @@ static char *yy_last_accepting_cpos; #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; -#line 1 "../../../lib/com_err/lex.l" +#line 1 "lex.l" #define INITIAL 0 -#line 2 "../../../lib/com_err/lex.l" +#line 2 "lex.l" /* * Copyright (c) 1998 - 2000 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). @@ -442,7 +452,7 @@ static int getstring(void); #undef ECHO -#line 446 "lex.c" +#line 455 "lex.yy.c" /* Macros after this point can all be overridden by user definitions in * section 1. @@ -590,12 +600,12 @@ YY_MALLOC_DECL YY_DECL { register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; + register char *yy_cp = NULL, *yy_bp = NULL; register int yy_act; -#line 59 "../../../lib/com_err/lex.l" +#line 59 "lex.l" -#line 599 "lex.c" +#line 608 "lex.yy.c" if ( yy_init ) { @@ -680,85 +690,85 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 60 "../../../lib/com_err/lex.l" +#line 60 "lex.l" { return ET; } YY_BREAK case 2: YY_RULE_SETUP -#line 61 "../../../lib/com_err/lex.l" +#line 61 "lex.l" { return ET; } YY_BREAK case 3: YY_RULE_SETUP -#line 62 "../../../lib/com_err/lex.l" +#line 62 "lex.l" { return EC; } YY_BREAK case 4: YY_RULE_SETUP -#line 63 "../../../lib/com_err/lex.l" +#line 63 "lex.l" { return EC; } YY_BREAK case 5: YY_RULE_SETUP -#line 64 "../../../lib/com_err/lex.l" +#line 64 "lex.l" { return PREFIX; } YY_BREAK case 6: YY_RULE_SETUP -#line 65 "../../../lib/com_err/lex.l" +#line 65 "lex.l" { return INDEX; } YY_BREAK case 7: YY_RULE_SETUP -#line 66 "../../../lib/com_err/lex.l" +#line 66 "lex.l" { return ID; } YY_BREAK case 8: YY_RULE_SETUP -#line 67 "../../../lib/com_err/lex.l" +#line 67 "lex.l" { return END; } YY_BREAK case 9: YY_RULE_SETUP -#line 68 "../../../lib/com_err/lex.l" +#line 68 "lex.l" { yylval.number = atoi(yytext); return NUMBER; } YY_BREAK case 10: YY_RULE_SETUP -#line 69 "../../../lib/com_err/lex.l" +#line 69 "lex.l" ; YY_BREAK case 11: YY_RULE_SETUP -#line 70 "../../../lib/com_err/lex.l" +#line 70 "lex.l" ; YY_BREAK case 12: YY_RULE_SETUP -#line 71 "../../../lib/com_err/lex.l" +#line 71 "lex.l" { lineno++; } YY_BREAK case 13: YY_RULE_SETUP -#line 72 "../../../lib/com_err/lex.l" +#line 72 "lex.l" { return getstring(); } YY_BREAK case 14: YY_RULE_SETUP -#line 73 "../../../lib/com_err/lex.l" +#line 73 "lex.l" { yylval.string = strdup(yytext); return STRING; } YY_BREAK case 15: YY_RULE_SETUP -#line 74 "../../../lib/com_err/lex.l" +#line 74 "lex.l" { return *yytext; } YY_BREAK case 16: YY_RULE_SETUP -#line 75 "../../../lib/com_err/lex.l" +#line 75 "lex.l" ECHO; YY_BREAK -#line 762 "lex.c" +#line 771 "lex.yy.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1140,6 +1150,7 @@ register char *yy_bp; #endif /* ifndef YY_NO_UNPUT */ +#ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput() #else @@ -1211,7 +1222,7 @@ static int input() return c; } - +#endif /* YY_NO_INPUT */ #ifdef YY_USE_PROTOS void yyrestart( FILE *input_file ) @@ -1322,11 +1333,6 @@ YY_BUFFER_STATE b; } -#ifndef YY_ALWAYS_INTERACTIVE -#ifndef YY_NEVER_INTERACTIVE -extern int isatty YY_PROTO(( int )); -#endif -#endif #ifdef YY_USE_PROTOS void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) @@ -1644,7 +1650,7 @@ int main() return 0; } #endif -#line 75 "../../../lib/com_err/lex.l" +#line 75 "lex.l" #ifndef yywrap /* XXX */ diff --git a/source4/heimdal/lib/com_err/parse.c b/source4/heimdal/lib/com_err/parse.c index a7160a4d42..4cef0c492d 100644 --- a/source4/heimdal/lib/com_err/parse.c +++ b/source4/heimdal/lib/com_err/parse.c @@ -1,19 +1,86 @@ +/* A Bison parser, made by GNU Bison 2.1. */ -/* A Bison parser, made from ../../../lib/com_err/parse.y - by GNU Bison version 1.28 */ +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. -#define YYBISON 1 /* Identify Bison output. */ + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" -#define ET 257 -#define INDEX 258 -#define PREFIX 259 -#define EC 260 -#define ID 261 -#define END 262 -#define STRING 263 -#define NUMBER 264 +/* Pure parsers. */ +#define YYPURE 0 -#line 1 "../../../lib/com_err/parse.y" +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ET = 258, + INDEX = 259, + PREFIX = 260, + EC = 261, + ID = 262, + END = 263, + STRING = 264, + NUMBER = 265 + }; +#endif +/* Tokens. */ +#define ET 258 +#define INDEX 259 +#define PREFIX 260 +#define EC 261 +#define ID 262 +#define END 263 +#define STRING 264 +#define NUMBER 265 + + + + +/* Copy the first part of user declarations. */ +#line 1 "parse.y" /* * Copyright (c) 1998 - 2000 Kungliga Tekniska Högskolan @@ -65,425 +132,834 @@ extern char *yytext; #endif -#line 53 "../../../lib/com_err/parse.y" -typedef union { + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 53 "parse.y" +typedef union YYSTYPE { char *string; int number; } YYSTYPE; -#include <stdio.h> - -#ifndef __cplusplus -#ifndef __STDC__ -#define const -#endif +/* Line 196 of yacc.c. */ +#line 162 "$base.c" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif -#define YYFINAL 24 -#define YYFLAG -32768 -#define YYNTBASE 12 - -#define YYTRANSLATE(x) ((unsigned)(x) <= 264 ? yytranslate[x] : 18) - -static const char yytranslate[] = { 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, - 7, 8, 9, 10 -}; +/* Copy the second part of user declarations. */ -#if YYDEBUG != 0 -static const short yyprhs[] = { 0, - 0, 1, 4, 7, 9, 12, 15, 19, 21, 24, - 27, 30, 32, 37 -}; -static const short yyrhs[] = { -1, - 13, 16, 0, 14, 15, 0, 15, 0, 7, 9, - 0, 3, 9, 0, 3, 9, 9, 0, 17, 0, - 16, 17, 0, 4, 10, 0, 5, 9, 0, 5, - 0, 6, 9, 11, 9, 0, 8, 0 -}; +/* Line 219 of yacc.c. */ +#line 174 "$base.c" +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus)) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int #endif -#if YYDEBUG != 0 -static const short yyrline[] = { 0, - 64, 65, 68, 69, 72, 78, 84, 93, 94, 97, - 101, 109, 116, 136 -}; +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif #endif +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# else +# define YYSTACK_ALLOC alloca +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYINCLUDED_STDLIB_H +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1) +# endif +# ifdef __cplusplus +extern "C" { +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \ + && (defined (__STDC__) || defined (__cplusplus))) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \ + && (defined (__STDC__) || defined (__cplusplus))) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifdef __cplusplus +} +# endif +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ -#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) -static const char * const yytname[] = { "$","error","$undefined.","ET","INDEX", -"PREFIX","EC","ID","END","STRING","NUMBER","','","file","header","id","et","statements", -"statement", NULL -}; +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short int yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined (__GNUC__) && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + #endif -static const short yyr1[] = { 0, - 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, - 17, 17, 17, 17 -}; +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short int yysigned_char; +#endif -static const short yyr2[] = { 0, - 0, 2, 2, 1, 2, 2, 3, 1, 2, 2, - 2, 1, 4, 1 +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 9 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 23 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 12 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 7 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 15 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 24 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 265 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 11, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10 }; -static const short yydefact[] = { 1, - 0, 0, 0, 0, 4, 6, 5, 0, 12, 0, - 14, 2, 8, 3, 7, 10, 11, 0, 9, 0, - 13, 0, 0, 0 +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned char yyprhs[] = +{ + 0, 0, 3, 4, 7, 10, 12, 15, 18, 22, + 24, 27, 30, 33, 35, 40 }; -static const short yydefgoto[] = { 22, - 3, 4, 5, 12, 13 +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yysigned_char yyrhs[] = +{ + 13, 0, -1, -1, 14, 17, -1, 15, 16, -1, + 16, -1, 7, 9, -1, 3, 9, -1, 3, 9, + 9, -1, 18, -1, 17, 18, -1, 4, 10, -1, + 5, 9, -1, 5, -1, 6, 9, 11, 9, -1, + 8, -1 }; -static const short yypact[] = { 0, - -3, -1, -4, 2,-32768, 1,-32768, 3, 5, 6, --32768, -4,-32768,-32768,-32768,-32768,-32768, -2,-32768, 7, --32768, 11, 12,-32768 +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned char yyrline[] = +{ + 0, 64, 64, 65, 68, 69, 72, 78, 84, 93, + 94, 97, 101, 109, 116, 136 }; +#endif -static const short yypgoto[] = {-32768, --32768,-32768, 13,-32768, 8 +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "ET", "INDEX", "PREFIX", "EC", "ID", + "END", "STRING", "NUMBER", "','", "$accept", "file", "header", "id", + "et", "statements", "statement", 0 }; +#endif +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short int yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 44 +}; +# endif -#define YYLAST 20 - - -static const short yytable[] = { 8, - 9, 10, 1, 11, 1, 6, 2, 7, 20, 15, - 23, 24, 16, 17, 18, 21, 14, 0, 0, 19 +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 12, 13, 13, 14, 14, 15, 16, 16, 17, + 17, 18, 18, 18, 18, 18 }; -static const short yycheck[] = { 4, - 5, 6, 3, 8, 3, 9, 7, 9, 11, 9, - 0, 0, 10, 9, 9, 9, 4, -1, -1, 12 +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 0, 2, 2, 1, 2, 2, 3, 1, + 2, 2, 2, 1, 4, 1 }; -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/share/bison.simple" -/* This file comes from bison-1.28. */ -/* Skeleton output parser for bison, - Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 2, 0, 0, 0, 0, 0, 5, 7, 6, 1, + 0, 13, 0, 15, 3, 9, 4, 8, 11, 12, + 0, 10, 0, 14 +}; - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. +/* YYDEFGOTO[NTERM-NUM]. */ +static const yysigned_char yydefgoto[] = +{ + -1, 3, 4, 5, 6, 14, 15 +}; - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -5 +static const yysigned_char yypact[] = +{ + 0, -3, -1, 5, -4, 6, -5, 1, -5, -5, + 2, 4, 7, -5, -4, -5, -5, -5, -5, -5, + 3, -5, 8, -5 +}; - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ +/* YYPGOTO[NTERM-NUM]. */ +static const yysigned_char yypgoto[] = +{ + -5, -5, -5, -5, 10, -5, 9 +}; -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const unsigned char yytable[] = +{ + 10, 11, 12, 1, 13, 9, 7, 2, 8, 1, + 17, 0, 18, 19, 22, 16, 20, 23, 0, 0, + 0, 0, 0, 21 +}; -/* This is the parser code that is written into each bison parser - when the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -#ifndef YYSTACK_USE_ALLOCA -#ifdef alloca -#define YYSTACK_USE_ALLOCA -#else /* alloca not defined */ -#ifdef __GNUC__ -#define YYSTACK_USE_ALLOCA -#define alloca __builtin_alloca -#else /* not GNU C. */ -#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) -#define YYSTACK_USE_ALLOCA -#include <alloca.h> -#else /* not sparc */ -/* We think this test detects Watcom and Microsoft C. */ -/* This used to test MSDOS, but that is a bad idea - since that symbol is in the user namespace. */ -#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) -#if 0 /* No need for malloc.h, which pollutes the namespace; - instead, just don't use alloca. */ -#include <malloc.h> -#endif -#else /* not MSDOS, or __TURBOC__ */ -#if defined(_AIX) -/* I don't know what this was needed for, but it pollutes the namespace. - So I turned it off. rms, 2 May 1997. */ -/* #include <malloc.h> */ - #pragma alloca -#define YYSTACK_USE_ALLOCA -#else /* not MSDOS, or __TURBOC__, or _AIX */ -#if 0 -#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, - and on HPUX 10. Eventually we can turn this on. */ -#define YYSTACK_USE_ALLOCA -#define alloca __builtin_alloca -#endif /* __hpux */ -#endif -#endif /* not _AIX */ -#endif /* not MSDOS, or __TURBOC__ */ -#endif /* not sparc */ -#endif /* not GNU C */ -#endif /* alloca not defined */ -#endif /* YYSTACK_USE_ALLOCA not defined */ - -#ifdef YYSTACK_USE_ALLOCA -#define YYSTACK_ALLOC alloca -#else -#define YYSTACK_ALLOC malloc -#endif +static const yysigned_char yycheck[] = +{ + 4, 5, 6, 3, 8, 0, 9, 7, 9, 3, + 9, -1, 10, 9, 11, 5, 9, 9, -1, -1, + -1, -1, -1, 14 +}; -/* Note: there must be only one dollar sign in this file. - It is replaced by the list of actions, each action - as one case of the switch. */ +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 3, 7, 13, 14, 15, 16, 9, 9, 0, + 4, 5, 6, 8, 17, 18, 16, 9, 10, 9, + 9, 18, 11, 9 +}; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) -#define YYEMPTY -2 +#define YYEMPTY (-2) #define YYEOF 0 + #define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrlab1 -/* Like YYERROR except do call yyerror. - This remains here temporarily to ease the - transition to the new meaning of YYERROR, for GCC. +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ + #define YYFAIL goto yyerrlab + #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(token, value) \ + +#define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ - { yychar = (token), yylval = (value); \ - yychar1 = YYTRANSLATE (yychar); \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK; \ goto yybackup; \ } \ else \ - { yyerror ("syntax error: cannot back up"); YYERROR; } \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ while (0) + #define YYTERROR 1 #define YYERRCODE 256 -#ifndef YYPURE -#define YYLEX yylex() + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) #endif -#ifdef YYPURE -#ifdef YYLSP_NEEDED -#ifdef YYLEX_PARAM -#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) -#else -#define YYLEX yylex(&yylval, &yylloc) + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif #endif -#else /* not YYLSP_NEEDED */ + + +/* YYLEX -- calling `yylex' with the right arguments. */ + #ifdef YYLEX_PARAM -#define YYLEX yylex(&yylval, YYLEX_PARAM) +# define YYLEX yylex (YYLEX_PARAM) #else -#define YYLEX yylex(&yylval) +# define YYLEX yylex () #endif -#endif /* not YYLSP_NEEDED */ + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short int *bottom, short int *top) +#else +static void +yy_stack_print (bottom, top) + short int *bottom; + short int *top; #endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} -/* If nonreentrant, generate the variables here */ +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) -#ifndef YYPURE -int yychar; /* the lookahead symbol */ -YYSTYPE yylval; /* the semantic value of the */ - /* lookahead symbol */ +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ -#ifdef YYLSP_NEEDED -YYLTYPE yylloc; /* location data for the lookahead */ - /* symbol */ +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; #endif +{ + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ", + yyrule - 1, yylno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]); +} -int yynerrs; /* number of parse errors so far */ -#endif /* not YYPURE */ +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) -#if YYDEBUG != 0 -int yydebug; /* nonzero means print parse trace */ -/* Since this is uninitialized, it does not stop multiple parsers - from coexisting. */ -#endif +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ -/* YYINITDEPTH indicates the initial size of the parser's stacks */ +/* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH -#define YYINITDEPTH 200 +# define YYINITDEPTH 200 #endif -/* YYMAXDEPTH is the maximum size the stacks can grow to - (effective only if the built-in stack extension method is used). */ +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). -#if YYMAXDEPTH == 0 -#undef YYMAXDEPTH -#endif + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH -#define YYMAXDEPTH 10000 +# define YYMAXDEPTH 10000 #endif + -/* Define __yy_memcpy. Note that the size argument - should be passed with type unsigned int, because that is what the non-GCC - definitions require. With GCC, __builtin_memcpy takes an arg - of type size_t, but it can handle unsigned int. */ - -#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ -#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) -#else /* not GNU C or C++ */ -#ifndef __cplusplus - -/* This is the most reliable way to avoid incompatibilities - in available built-in functions on various systems. */ -static void -__yy_memcpy (to, from, count) - char *to; - char *from; - unsigned int count; + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif { - register char *f = from; - register char *t = to; - register int i = count; + const char *yys = yystr; - while (i-- > 0) - *t++ = *f++; + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; } +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + char *yyd = yydest; + const char *yys = yysrc; -#else /* __cplusplus */ + while ((*yyd++ = *yys++) != '\0') + continue; -/* This is the most reliable way to avoid incompatibilities - in available built-in functions on various systems. */ -static void -__yy_memcpy (char *to, char *from, unsigned int count) + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) { - register char *t = to; - register char *f = from; - register int i = count; + if (*yystr == '"') + { + size_t yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); - while (i-- > 0) - *t++ = *f++; + return yystpcpy (yyres, yystr) - yyres; } +# endif + +#endif /* YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; #endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; #endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} -#line 217 "/usr/share/bison.simple" -/* The user can define YYPARSE_PARAM as the name of an argument to be passed - into yyparse. The argument should have type void *. - It should actually point to an object. - Grammar actions can access the variable by casting it - to the proper pointer type. */ +/* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM -#ifdef __cplusplus -#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM -#define YYPARSE_PARAM_DECL -#else /* not __cplusplus */ -#define YYPARSE_PARAM_ARG YYPARSE_PARAM -#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; -#endif /* not __cplusplus */ -#else /* not YYPARSE_PARAM */ -#define YYPARSE_PARAM_ARG -#define YYPARSE_PARAM_DECL -#endif /* not YYPARSE_PARAM */ - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -#ifdef YYPARSE_PARAM -int yyparse (void *); -#else +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) int yyparse (void); +#else +int yyparse (); #endif -#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else int -yyparse(YYPARSE_PARAM_ARG) - YYPARSE_PARAM_DECL +yyparse () + +#endif +#endif { - register int yystate; - register int yyn; - register short *yyssp; - register YYSTYPE *yyvsp; - int yyerrstatus; /* number of tokens to shift before error messages enabled */ - int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; - short yyssa[YYINITDEPTH]; /* the state stack */ - YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short int yyssa[YYINITDEPTH]; + short int *yyss = yyssa; + short int *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; - short *yyss = yyssa; /* refer to the stacks thru separate pointers */ - YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ -#ifdef YYLSP_NEEDED - YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; -#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else #define YYPOPSTACK (yyvsp--, yyssp--) -#endif - int yystacksize = YYINITDEPTH; - int yyfree_stacks = 0; + YYSIZE_T yystacksize = YYINITDEPTH; -#ifdef YYPURE - int yychar; - YYSTYPE yylval; - int yynerrs; -#ifdef YYLSP_NEEDED - YYLTYPE yylloc; -#endif -#endif + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; - YYSTYPE yyval; /* the variable used to return */ - /* semantic values from the action */ - /* routines */ + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ int yylen; -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Starting parse\n"); -#endif + YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; @@ -495,295 +971,251 @@ yyparse(YYPARSE_PARAM_ARG) so that they stay on the same level as the state stack. The wasted elements are never initialized. */ - yyssp = yyss - 1; + yyssp = yyss; yyvsp = yyvs; -#ifdef YYLSP_NEEDED - yylsp = yyls; -#endif -/* Push a new state, which is found in yystate . */ -/* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. */ -yynewstate: + goto yysetstate; - *++yyssp = yystate; +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; - if (yyssp >= yyss + yystacksize - 1) - { - /* Give user a chance to reallocate the stack */ - /* Use copies of these so that the &'s don't force the real ones into memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; -#ifdef YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; -#endif + yysetstate: + *yyssp = yystate; + if (yyss + yystacksize - 1 <= yyssp) + { /* Get the current used size of the three stacks, in elements. */ - int size = yyssp - yyss + 1; + YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow - /* Each stack pointer address is followed by the size of - the data in use in that stack, in bytes. */ -#ifdef YYLSP_NEEDED - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow("parser stack overflow", - &yyss1, size * sizeof (*yyssp), - &yyvs1, size * sizeof (*yyvsp), - &yyls1, size * sizeof (*yylsp), - &yystacksize); -#else - yyoverflow("parser stack overflow", - &yyss1, size * sizeof (*yyssp), - &yyvs1, size * sizeof (*yyvsp), - &yystacksize); -#endif - - yyss = yyss1; yyvs = yyvs1; -#ifdef YYLSP_NEEDED - yyls = yyls1; -#endif + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short int *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } #else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - { - yyerror("parser stack overflow"); - if (yyfree_stacks) - { - free (yyss); - free (yyvs); -#ifdef YYLSP_NEEDED - free (yyls); -#endif - } - return 2; - } + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) + if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; -#ifndef YYSTACK_USE_ALLOCA - yyfree_stacks = 1; -#endif - yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); - __yy_memcpy ((char *)yyss, (char *)yyss1, - size * (unsigned int) sizeof (*yyssp)); - yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); - __yy_memcpy ((char *)yyvs, (char *)yyvs1, - size * (unsigned int) sizeof (*yyvsp)); -#ifdef YYLSP_NEEDED - yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); - __yy_memcpy ((char *)yyls, (char *)yyls1, - size * (unsigned int) sizeof (*yylsp)); -#endif + + { + short int *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif #endif /* no yyoverflow */ - yyssp = yyss + size - 1; - yyvsp = yyvs + size - 1; -#ifdef YYLSP_NEEDED - yylsp = yyls + size - 1; -#endif + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Stack size increased to %d\n", yystacksize); -#endif - if (yyssp >= yyss + yystacksize - 1) + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) YYABORT; } -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Entering state %d\n", yystate); -#endif + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); goto yybackup; - yybackup: + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: /* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ +/* Read a look-ahead token if we need one and don't already have one. */ /* yyresume: */ - /* First try to decide what to do without reference to lookahead token. */ + /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; - if (yyn == YYFLAG) + if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ + /* Not known => get a look-ahead token if don't already have one. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Reading a token: "); -#endif + YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ + if (yychar <= YYEOF) { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Now at end of input.\n"); -#endif + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); } else { - yychar1 = YYTRANSLATE(yychar); - -#if YYDEBUG != 0 - if (yydebug) - { - fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise meaning - of a token, for further debugging info. */ -#ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -#endif - fprintf (stderr, ")\n"); - } -#endif + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) + if (yyn <= 0) { - if (yyn == YYFLAG) + if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } - else if (yyn == 0) - goto yyerrlab; if (yyn == YYFINAL) YYACCEPT; - /* Shift the lookahead token. */ - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); -#endif + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the token being shifted unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; *++yyvsp = yylval; -#ifdef YYLSP_NEEDED - *++yylsp = yylloc; -#endif - /* count tokens shifted since error; after three, turn off error status. */ - if (yyerrstatus) yyerrstatus--; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; yystate = yyn; goto yynewstate; -/* Do the default action for the current state. */ -yydefault: +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; + goto yyreduce; + -/* Do a reduction. yyn is the number of a rule to reduce with. */ +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ yyreduce: + /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; - if (yylen > 0) - yyval = yyvsp[1-yylen]; /* implement default value of the action */ -#if YYDEBUG != 0 - if (yydebug) - { - int i; + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. - fprintf (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; - /* Print the symbols being reduced, and their result. */ - for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) - fprintf (stderr, "%s ", yytname[yyrhs[i]]); - fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 6: +#line 73 "parse.y" + { + id_str = (yyvsp[0].string); + } + break; - switch (yyn) { + case 7: +#line 79 "parse.y" + { + base_id = name2number((yyvsp[0].string)); + strlcpy(name, (yyvsp[0].string), sizeof(name)); + free((yyvsp[0].string)); + } + break; -case 5: -#line 73 "../../../lib/com_err/parse.y" -{ - id_str = yyvsp[0].string; - ; - break;} -case 6: -#line 79 "../../../lib/com_err/parse.y" -{ - base_id = name2number(yyvsp[0].string); - strlcpy(name, yyvsp[0].string, sizeof(name)); - free(yyvsp[0].string); - ; - break;} -case 7: -#line 85 "../../../lib/com_err/parse.y" -{ - base_id = name2number(yyvsp[-1].string); - strlcpy(name, yyvsp[0].string, sizeof(name)); - free(yyvsp[-1].string); - free(yyvsp[0].string); - ; - break;} -case 10: -#line 98 "../../../lib/com_err/parse.y" -{ - number = yyvsp[0].number; - ; - break;} -case 11: -#line 102 "../../../lib/com_err/parse.y" -{ + case 8: +#line 85 "parse.y" + { + base_id = name2number((yyvsp[-1].string)); + strlcpy(name, (yyvsp[0].string), sizeof(name)); + free((yyvsp[-1].string)); + free((yyvsp[0].string)); + } + break; + + case 11: +#line 98 "parse.y" + { + number = (yyvsp[0].number); + } + break; + + case 12: +#line 102 "parse.y" + { free(prefix); - asprintf (&prefix, "%s_", yyvsp[0].string); + asprintf (&prefix, "%s_", (yyvsp[0].string)); if (prefix == NULL) errx(1, "malloc"); - free(yyvsp[0].string); - ; - break;} -case 12: -#line 110 "../../../lib/com_err/parse.y" -{ + free((yyvsp[0].string)); + } + break; + + case 13: +#line 110 "parse.y" + { prefix = realloc(prefix, 1); if (prefix == NULL) errx(1, "malloc"); *prefix = '\0'; - ; - break;} -case 13: -#line 117 "../../../lib/com_err/parse.y" -{ + } + break; + + case 14: +#line 117 "parse.y" + { struct error_code *ec = malloc(sizeof(*ec)); if (ec == NULL) @@ -792,246 +1224,299 @@ case 13: ec->next = NULL; ec->number = number; if(prefix && *prefix != '\0') { - asprintf (&ec->name, "%s%s", prefix, yyvsp[-2].string); + asprintf (&ec->name, "%s%s", prefix, (yyvsp[-2].string)); if (ec->name == NULL) errx(1, "malloc"); - free(yyvsp[-2].string); + free((yyvsp[-2].string)); } else - ec->name = yyvsp[-2].string; - ec->string = yyvsp[0].string; + ec->name = (yyvsp[-2].string); + ec->string = (yyvsp[0].string); APPEND(codes, ec); number++; - ; - break;} -case 14: -#line 137 "../../../lib/com_err/parse.y" -{ + } + break; + + case 15: +#line 137 "parse.y" + { YYACCEPT; - ; - break;} -} - /* the action file gets copied in in place of this dollarsign */ -#line 543 "/usr/share/bison.simple" + } + break; + + + default: break; + } + +/* Line 1126 of yacc.c. */ +#line 1252 "$base.c" yyvsp -= yylen; yyssp -= yylen; -#ifdef YYLSP_NEEDED - yylsp -= yylen; -#endif -#if YYDEBUG != 0 - if (yydebug) - { - short *ssp1 = yyss - 1; - fprintf (stderr, "state stack now"); - while (ssp1 != yyssp) - fprintf (stderr, " %d", *++ssp1); - fprintf (stderr, "\n"); - } -#endif + + YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; -#ifdef YYLSP_NEEDED - yylsp++; - if (yylen == 0) - { - yylsp->first_line = yylloc.first_line; - yylsp->first_column = yylloc.first_column; - yylsp->last_line = (yylsp-1)->last_line; - yylsp->last_column = (yylsp-1)->last_column; - yylsp->text = 0; - } - else - { - yylsp->last_line = (yylsp+yylen-1)->last_line; - yylsp->last_column = (yylsp+yylen-1)->last_column; - } -#endif - /* Now "shift" the result of the reduction. - Determine what state that goes to, - based on the state we popped back to - and the rule number reduced by. */ + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ yyn = yyr1[yyn]; - yystate = yypgoto[yyn - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else - yystate = yydefgoto[yyn - YYNTBASE]; + yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; -yyerrlab: /* here on detecting error */ - if (! yyerrstatus) - /* If not already recovering from an error, report this error. */ +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) { ++yynerrs; - -#ifdef YYERROR_VERBOSE +#if YYERROR_VERBOSE yyn = yypact[yystate]; - if (yyn > YYFLAG && yyn < YYLAST) + if (YYPACT_NINF < yyn && yyn < YYLAST) { - int size = 0; - char *msg; - int x, count; - - count = 0; - /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ - for (x = (yyn < 0 ? -yyn : 0); - x < (sizeof(yytname) / sizeof(char *)); x++) - if (yycheck[x + yyn] == x) - size += strlen(yytname[x]) + 15, count++; - msg = (char *) malloc(size + 15); - if (msg != 0) - { - strcpy(msg, "parse error"); + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + char *yymsg = 0; +# define YYERROR_VERBOSE_ARGS_MAXIMUM 5 + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; - if (count < 5) +#if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +#endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= yysize1 < yysize; + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= yysize1 < yysize; + yysize = yysize1; + + if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM) + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yymsg; + int yyi = 0; + while ((*yyp = *yyf)) { - count = 0; - for (x = (yyn < 0 ? -yyn : 0); - x < (sizeof(yytname) / sizeof(char *)); x++) - if (yycheck[x + yyn] == x) - { - strcat(msg, count == 0 ? ", expecting `" : " or `"); - strcat(msg, yytname[x]); - strcat(msg, "'"); - count++; - } + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } } - yyerror(msg); - free(msg); + yyerror (yymsg); + YYSTACK_FREE (yymsg); } else - yyerror ("parse error; also virtual memory exceeded"); + { + yyerror (YY_("syntax error")); + goto yyexhaustedlab; + } } else #endif /* YYERROR_VERBOSE */ - yyerror("parse error"); + yyerror (YY_("syntax error")); } - goto yyerrlab1; -yyerrlab1: /* here on error raised explicitly by an action */ + if (yyerrstatus == 3) { - /* if just tried and failed to reuse lookahead token after an error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); -#endif - - yychar = YYEMPTY; + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", yytoken, &yylval); + yychar = YYEMPTY; + } } - /* Else will try to reuse lookahead token - after shifting the error token. */ + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; - yyerrstatus = 3; /* Each real token shifted decrements this */ - goto yyerrhandle; +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: -yyerrdefault: /* current state does not do anything special for the error token. */ + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (0) + goto yyerrorlab; -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ - if (yyn) goto yydefault; -#endif +yyvsp -= yylen; + yyssp -= yylen; + yystate = *yyssp; + goto yyerrlab1; -yyerrpop: /* pop the current state because it cannot handle the error token */ - if (yyssp == yyss) YYABORT; - yyvsp--; - yystate = *--yyssp; -#ifdef YYLSP_NEEDED - yylsp--; -#endif +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ -#if YYDEBUG != 0 - if (yydebug) + for (;;) { - short *ssp1 = yyss - 1; - fprintf (stderr, "Error: state stack now"); - while (ssp1 != yyssp) - fprintf (stderr, " %d", *++ssp1); - fprintf (stderr, "\n"); - } -#endif - -yyerrhandle: + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; + yydestruct ("Error: popping", yystos[yystate], yyvsp); + YYPOPSTACK; + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); } - else if (yyn == 0) - goto yyerrpop; if (yyn == YYFINAL) YYACCEPT; -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Shifting error token, "); -#endif - *++yyvsp = yylval; -#ifdef YYLSP_NEEDED - *++yylsp = yylloc; -#endif + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; - yyacceptlab: - /* YYACCEPT comes here. */ - if (yyfree_stacks) - { - free (yyss); - free (yyvs); -#ifdef YYLSP_NEEDED - free (yyls); + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ #endif - } - return 0; - yyabortlab: - /* YYABORT comes here. */ - if (yyfree_stacks) +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + while (yyssp != yyss) { - free (yyss); - free (yyvs); -#ifdef YYLSP_NEEDED - free (yyls); -#endif + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK; } - return 1; +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; } -#line 142 "../../../lib/com_err/parse.y" + + +#line 142 "parse.y" static long @@ -1064,3 +1549,4 @@ yyerror (char *s) { error_message ("%s\n", s); } + diff --git a/source4/heimdal/lib/com_err/parse.h b/source4/heimdal/lib/com_err/parse.h index 07e33790d3..2f9755e19b 100644 --- a/source4/heimdal/lib/com_err/parse.h +++ b/source4/heimdal/lib/com_err/parse.h @@ -1,15 +1,71 @@ -typedef union { +/* A Bison parser, made by GNU Bison 2.1. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ET = 258, + INDEX = 259, + PREFIX = 260, + EC = 261, + ID = 262, + END = 263, + STRING = 264, + NUMBER = 265 + }; +#endif +/* Tokens. */ +#define ET 258 +#define INDEX 259 +#define PREFIX 260 +#define EC 261 +#define ID 262 +#define END 263 +#define STRING 264 +#define NUMBER 265 + + + + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 53 "parse.y" +typedef union YYSTYPE { char *string; int number; } YYSTYPE; -#define ET 257 -#define INDEX 258 -#define PREFIX 259 -#define EC 260 -#define ID 261 -#define END 262 -#define STRING 263 -#define NUMBER 264 - +/* Line 1447 of yacc.c. */ +#line 63 "parse.h" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif extern YYSTYPE yylval; + + + diff --git a/source4/heimdal/lib/des/bn.c b/source4/heimdal/lib/des/bn.c new file mode 100644 index 0000000000..c4230b6abc --- /dev/null +++ b/source4/heimdal/lib/des/bn.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$Id: bn.c,v 1.9 2006/10/14 09:21:09 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include <krb5-types.h> +#include <rfc2459_asn1.h> /* XXX */ +#include <der.h> + +#include <bn.h> +#include <rand.h> +#include <hex.h> + +BIGNUM * +BN_new(void) +{ + heim_integer *hi; + hi = calloc(1, sizeof(*hi)); + return (BIGNUM *)hi; +} + +void +BN_free(BIGNUM *bn) +{ + BN_clear(bn); + free(bn); +} + +void +BN_clear(BIGNUM *bn) +{ + heim_integer *hi = (heim_integer *)bn; + if (hi->data) { + memset(hi->data, 0, hi->length); + free(hi->data); + } + memset(hi, 0, sizeof(*hi)); +} + +void +BN_clear_free(BIGNUM *bn) +{ + BN_free(bn); +} + +BIGNUM * +BN_dup(const BIGNUM *bn) +{ + BIGNUM *b = BN_new(); + if (der_copy_heim_integer((const heim_integer *)bn, (heim_integer *)b)) { + BN_free(b); + return NULL; + } + return b; +} + +/* + * If the caller really want to know the number of bits used, subtract + * one from the length, multiply by 8, and then lookup in the table + * how many bits the hightest byte uses. + */ +int +BN_num_bits(const BIGNUM *bn) +{ + static unsigned char num2bits[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + }; + const heim_integer *i = (const void *)bn; + if (i->length == 0) + return 0; + return (i->length - 1) * 8 + num2bits[((unsigned char *)i->data)[0]]; +} + +int +BN_num_bytes(const BIGNUM *bn) +{ + return ((const heim_integer *)bn)->length; +} + +/* + * Ignore negative flag. + */ + +BIGNUM * +BN_bin2bn(const void *s, int len, BIGNUM *bn) +{ + heim_integer *hi = (void *)bn; + + if (len < 0) + return NULL; + + if (hi == NULL) { + hi = (heim_integer *)BN_new(); + if (hi == NULL) + return NULL; + } + if (hi->data) + BN_clear((BIGNUM *)hi); + hi->negative = 0; + hi->data = malloc(len); + if (hi->data == NULL && len != 0) { + if (bn == NULL) + BN_free((BIGNUM *)hi); + return NULL; + } + hi->length = len; + memcpy(hi->data, s, len); + return (BIGNUM *)hi; +} + +int +BN_bn2bin(const BIGNUM *bn, void *to) +{ + const heim_integer *hi = (const void *)bn; + memcpy(to, hi->data, hi->length); + return hi->length; +} + +int +BN_hex2bn(BIGNUM **bnp, const char *in) +{ + int negative; + ssize_t ret; + size_t len; + void *data; + + len = strlen(in); + data = malloc(len); + if (data == NULL) + return 0; + + if (*in == '-') { + negative = 1; + in++; + } else + negative = 0; + + ret = hex_decode(in, data, len); + if (ret < 0) { + free(data); + return 0; + } + + *bnp = BN_bin2bn(data, ret, NULL); + free(data); + if (*bnp == NULL) + return 0; + BN_set_negative(*bnp, negative); + return 1; +} + +char * +BN_bn2hex(const BIGNUM *bn) +{ + ssize_t ret; + size_t len; + void *data; + char *str; + + len = BN_num_bytes(bn); + data = malloc(len); + if (data == NULL) + return 0; + + len = BN_bn2bin(bn, data); + + ret = hex_encode(data, len, &str); + free(data); + if (ret < 0) + return 0; + + return str; +} + +int +BN_cmp(const BIGNUM *bn1, const BIGNUM *bn2) +{ + return der_heim_integer_cmp((const heim_integer *)bn1, + (const heim_integer *)bn2); +} + +void +BN_set_negative(BIGNUM *bn, int flag) +{ + ((heim_integer *)bn)->negative = (flag ? 1 : 0); +} + +int +BN_is_negative(BIGNUM *bn) +{ + return ((heim_integer *)bn)->negative ? 1 : 0; +} + +static const unsigned char is_set[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +int +BN_is_bit_set(const BIGNUM *bn, int bit) +{ + heim_integer *hi = (heim_integer *)bn; + unsigned char *p = hi->data; + + if ((bit / 8) > hi->length || hi->length == 0) + return 0; + + return p[hi->length - 1 - (bit / 8)] & is_set[bit % 8]; +} + +int +BN_set_bit(BIGNUM *bn, int bit) +{ + heim_integer *hi = (heim_integer *)bn; + unsigned char *p; + + if ((bit / 8) > hi->length || hi->length == 0) { + size_t len = (bit + 7) / 8; + void *d = realloc(hi->data, len); + if (d == NULL) + return 0; + hi->data = d; + p = hi->data; + memset(&p[hi->length], 0, len); + hi->length = len; + } else + p = hi->data; + + p[hi->length - 1 - (bit / 8)] |= is_set[bit % 8]; + return 1; +} + +int +BN_clear_bit(BIGNUM *bn, int bit) +{ + heim_integer *hi = (heim_integer *)bn; + unsigned char *p = hi->data; + + if ((bit / 8) > hi->length || hi->length == 0) + return 0; + + p[hi->length - 1 - (bit / 8)] &= (unsigned char)(~(is_set[bit % 8])); + + return 1; +} + +int +BN_set_word(BIGNUM *bn, unsigned long num) +{ + unsigned char p[sizeof(num)]; + unsigned long num2; + int i, len; + + for (num2 = num, i = 0; num2 > 0; i++) + num2 = num2 >> 8; + + len = i - 1; + for (; i > 0; i--) { + p[i - 1] = (num & 0xff); + num = num >> 8; + } + + bn = BN_bin2bn(p, len + 1, bn); + return bn != NULL; +} + +unsigned long +BN_get_word(const BIGNUM *bn) +{ + heim_integer *hi = (heim_integer *)bn; + unsigned long num = 0; + int i; + + if (hi->negative || hi->length > sizeof(num)) + return ULONG_MAX; + + for (i = 0; i < hi->length; i++) + num = ((unsigned char *)hi->data)[i] | (num << 8); + return num; +} + +int +BN_rand(BIGNUM *bn, int bits, int top, int bottom) +{ + size_t len = (bits + 7) / 8; + heim_integer *i = (heim_integer *)bn; + + BN_clear(bn); + + i->negative = 0; + i->data = malloc(len); + if (i->data == NULL && len != 0) + return 0; + i->length = len; + + if (RAND_bytes(i->data, i->length) != 1) { + free(i->data); + i->data = NULL; + return 0; + } + + { + size_t j = len * 8; + while(j > bits) { + BN_clear_bit(bn, j - 1); + j--; + } + } + + if (top == -1) { + ; + } else if (top == 0 && bits > 0) { + BN_set_bit(bn, bits - 1); + } else if (top == 1 && bits > 1) { + BN_set_bit(bn, bits - 1); + BN_set_bit(bn, bits - 2); + } else { + BN_clear(bn); + return 0; + } + + if (bottom && bits > 0) + BN_set_bit(bn, 0); + + return 1; +} + +/* + * + */ + +int +BN_uadd(BIGNUM *res, const BIGNUM *a, const BIGNUM *b) +{ + const heim_integer *ai = (const heim_integer *)a; + const heim_integer *bi = (const heim_integer *)b; + const unsigned char *ap, *bp; + unsigned char *cp; + heim_integer ci; + int carry = 0; + ssize_t len; + + if (ai->negative && bi->negative) + return 0; + if (ai->length < bi->length) { + const heim_integer *si = bi; + bi = ai; ai = si; + } + + ci.negative = 0; + ci.length = ai->length + 1; + ci.data = malloc(ci.length); + if (ci.data == NULL) + return 0; + + ap = &((const unsigned char *)ai->data)[ai->length - 1]; + bp = &((const unsigned char *)bi->data)[bi->length - 1]; + cp = &((unsigned char *)ci.data)[ci.length - 1]; + + for (len = bi->length; len > 0; len--) { + carry = *ap + *bp + carry; + *cp = carry & 0xff; + carry = (carry & ~0xff) ? 1 : 0; + ap--; bp--; cp--; + } + for (len = ai->length - bi->length; len > 0; len--) { + carry = *ap + carry; + *cp = carry & 0xff; + carry = (carry & ~0xff) ? 1 : 0; + ap--; cp--; + } + if (!carry) + memmove(cp, cp + 1, --ci.length); + else + *cp = carry; + + BN_clear(res); + *((heim_integer *)res) = ci; + + return 1; +} + + +/* + * Callback when doing slow generation of numbers, like primes. + */ + +void +BN_GENCB_set(BN_GENCB *gencb, int (*cb_2)(int, int, BN_GENCB *), void *ctx) +{ + gencb->ver = 2; + gencb->cb.cb_2 = cb_2; + gencb->arg = ctx; +} + +int +BN_GENCB_call(BN_GENCB *cb, int a, int b) +{ + if (cb == NULL || cb->cb.cb_2 == NULL) + return 1; + return cb->cb.cb_2(a, b, cb); +} diff --git a/source4/heimdal/lib/des/dh-imath.c b/source4/heimdal/lib/des/dh-imath.c new file mode 100644 index 0000000000..ebf02c72be --- /dev/null +++ b/source4/heimdal/lib/des/dh-imath.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <dh.h> + +#include <roken.h> + +#include "imath/imath.h" + +RCSID("$Id: dh-imath.c,v 1.6 2006/10/20 06:56:57 lha Exp $"); + +static void +BN2mpz(mpz_t *s, const BIGNUM *bn) +{ + size_t len; + void *p; + + len = BN_num_bytes(bn); + p = malloc(len); + BN_bn2bin(bn, p); + mp_int_read_unsigned(s, p, len); + free(p); +} + + +static BIGNUM * +mpz2BN(mpz_t *s) +{ + size_t size; + BIGNUM *bn; + void *p; + + size = mp_int_unsigned_len(s); + p = malloc(size); + if (p == NULL && size != 0) + return NULL; + mp_int_to_unsigned(s, p, size); + + bn = BN_bin2bn(p, size, NULL); + free(p); + return bn; +} + +/* + * + */ + +#define DH_NUM_TRIES 10 + +static int +dh_generate_key(DH *dh) +{ + mpz_t pub, priv_key, g, p; + int have_private_key = (dh->priv_key != NULL); + int codes, times = 0; + mp_result res; + + if (dh->p == NULL || dh->g == NULL) + return 0; + + while (times++ < DH_NUM_TRIES) { + if (!have_private_key) { + size_t bits = BN_num_bits(dh->p); + + if (dh->priv_key) + BN_free(dh->priv_key); + + dh->priv_key = BN_new(); + if (dh->priv_key == NULL) + return 0; + if (!BN_rand(dh->priv_key, bits - 1, 0, 0)) { + BN_clear_free(dh->priv_key); + dh->priv_key = NULL; + return 0; + } + } + if (dh->pub_key) + BN_free(dh->pub_key); + + mp_int_init(&pub); + mp_int_init(&priv_key); + mp_int_init(&g); + mp_int_init(&p); + + BN2mpz(&priv_key, dh->priv_key); + BN2mpz(&g, dh->g); + BN2mpz(&p, dh->p); + + res = mp_int_exptmod(&g, &priv_key, &p, &pub); + + mp_int_clear(&priv_key); + mp_int_clear(&g); + mp_int_clear(&p); + if (res != MP_OK) + continue; + + dh->pub_key = mpz2BN(&pub); + mp_int_clear(&pub); + if (dh->pub_key == NULL) + return 0; + + if (DH_check_pubkey(dh, dh->pub_key, &codes) && codes == 0) + break; + if (have_private_key) + return 0; + } + + if (times >= DH_NUM_TRIES) { + if (!have_private_key && dh->priv_key) { + BN_free(dh->priv_key); + dh->priv_key = NULL; + } + if (dh->pub_key) { + BN_free(dh->pub_key); + dh->pub_key = NULL; + } + return 0; + } + + return 1; +} + +static int +dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh) +{ + mpz_t s, priv_key, p, peer_pub; + size_t size = 0; + mp_result res; + + if (dh->pub_key == NULL || dh->g == NULL || dh->priv_key == NULL) + return -1; + + mp_int_init(&p); + BN2mpz(&p, dh->p); + + mp_int_init(&peer_pub); + BN2mpz(&peer_pub, pub); + + /* check if peers pubkey is reasonable */ + if (MP_SIGN(&peer_pub) == MP_NEG + || mp_int_compare(&peer_pub, &p) >= 0 + || mp_int_compare_value(&peer_pub, 1) <= 0) + { + mp_int_clear(&p); + mp_int_clear(&peer_pub); + return -1; + } + + mp_int_init(&priv_key); + BN2mpz(&priv_key, dh->priv_key); + + mp_int_init(&s); + + mp_int_exptmod(&peer_pub, &priv_key, &p, &s); + + mp_int_clear(&p); + mp_int_clear(&peer_pub); + mp_int_clear(&priv_key); + + size = mp_int_unsigned_len(&s); + res = mp_int_to_unsigned(&s, shared, size); + mp_int_clear(&s); + + return (res == MP_OK) ? size : -1; +} + +static int +dh_generate_params(DH *dh, int a, int b, BN_GENCB *callback) +{ + /* groups should already be known, we don't care about this */ + return 0; +} + +static int +dh_init(DH *dh) +{ + return 1; +} + +static int +dh_finish(DH *dh) +{ + return 1; +} + + +/* + * + */ + +const DH_METHOD hc_dh_imath_method = { + "hcrypto imath DH", + dh_generate_key, + dh_compute_key, + NULL, + dh_init, + dh_finish, + 0, + NULL, + dh_generate_params +}; + +const DH_METHOD * +DH_imath_method(void) +{ + return &hc_dh_imath_method; +} diff --git a/source4/heimdal/lib/des/dh.c b/source4/heimdal/lib/des/dh.c new file mode 100644 index 0000000000..66d611f6d4 --- /dev/null +++ b/source4/heimdal/lib/des/dh.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$Id: dh.c,v 1.10 2006/10/19 17:31:51 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <dh.h> + +#include <roken.h> + +/* + * + */ + +DH * +DH_new(void) +{ + return DH_new_method(NULL); +} + +DH * +DH_new_method(ENGINE *engine) +{ + DH *dh; + + dh = calloc(1, sizeof(*dh)); + if (dh == NULL) + return NULL; + + dh->references = 1; + + if (engine) { + ENGINE_up_ref(engine); + dh->engine = engine; + } else { + dh->engine = ENGINE_get_default_DH(); + } + + if (dh->engine) { + dh->meth = ENGINE_get_DH(dh->engine); + if (dh->meth == NULL) { + ENGINE_finish(engine); + free(dh); + return 0; + } + } + + if (dh->meth == NULL) + dh->meth = DH_get_default_method(); + + (*dh->meth->init)(dh); + + return dh; +} + +void +DH_free(DH *dh) +{ + if (dh->references <= 0) + abort(); + + if (--dh->references > 0) + return; + + (*dh->meth->finish)(dh); + + if (dh->engine) + ENGINE_finish(dh->engine); + +#define free_if(f) if (f) { BN_free(f); } + free_if(dh->p); + free_if(dh->g); + free_if(dh->pub_key); + free_if(dh->priv_key); + free_if(dh->q); + free_if(dh->j); + free_if(dh->counter); +#undef free_if + + memset(dh, 0, sizeof(*dh)); + free(dh); +} + +int +DH_up_ref(DH *dh) +{ + return ++dh->references; +} + +int +DH_size(const DH *dh) +{ + return BN_num_bytes(dh->p); +} + +int +DH_set_ex_data(DH *dh, int idx, void *data) +{ + dh->ex_data.sk = data; + return 1; +} + +void * +DH_get_ex_data(DH *dh, int idx) +{ + return dh->ex_data.sk; +} + +int +DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb) +{ + if (dh->meth->generate_params) + return dh->meth->generate_params(dh, prime_len, generator, cb); + return 0; +} + +/* + * Check that + * + * pub_key > 1 and pub_key < p - 1 + * + * to avoid small subgroups attack. + */ + +int +DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes) +{ + BIGNUM *bn = NULL, *sum = NULL; + int ret = 0; + + *codes = 0; + + bn = BN_new(); + if (bn == NULL) + goto out; + + if (!BN_set_word(bn, 1)) + goto out; + + if (BN_cmp(bn, pub_key) >= 0) + *codes |= DH_CHECK_PUBKEY_TOO_SMALL; + + sum = BN_new(); + if (sum == NULL) + goto out; + + BN_uadd(sum, pub_key, bn); + + if (BN_cmp(sum, dh->p) >= 0) + *codes |= DH_CHECK_PUBKEY_TOO_LARGE; + + ret = 1; +out: + if (bn) + BN_free(bn); + if (sum) + BN_free(sum); + + return ret; +} + +int +DH_generate_key(DH *dh) +{ + return dh->meth->generate_key(dh); +} + +int +DH_compute_key(unsigned char *shared_key, + const BIGNUM *peer_pub_key, DH *dh) +{ + int codes; + + if (!DH_check_pubkey(dh, peer_pub_key, &codes) || codes != 0) + return -1; + + return dh->meth->compute_key(shared_key, peer_pub_key, dh); +} + +int +DH_set_method(DH *dh, const DH_METHOD *method) +{ + (*dh->meth->finish)(dh); + if (dh->engine) { + ENGINE_finish(dh->engine); + dh->engine = NULL; + } + dh->meth = method; + (*dh->meth->init)(dh); + return 1; +} + +/* + * + */ + +static int +dh_null_generate_key(DH *dh) +{ + return 0; +} + +static int +dh_null_compute_key(unsigned char *shared,const BIGNUM *pub, DH *dh) +{ + return 0; +} + +static int +dh_null_init(DH *dh) +{ + return 1; +} + +static int +dh_null_finish(DH *dh) +{ + return 1; +} + +static int +dh_null_generate_params(DH *dh, int prime_num, int len, BN_GENCB *cb) +{ + return 0; +} + +static const DH_METHOD dh_null_method = { + "hcrypto null DH", + dh_null_generate_key, + dh_null_compute_key, + NULL, + dh_null_init, + dh_null_finish, + 0, + NULL, + dh_null_generate_params +}; + +extern const DH_METHOD hc_dh_imath_method; +static const DH_METHOD *dh_default_method = &hc_dh_imath_method; + +const DH_METHOD * +DH_null_method(void) +{ + return &dh_null_method; +} + +void +DH_set_default_method(const DH_METHOD *meth) +{ + dh_default_method = meth; +} + +const DH_METHOD * +DH_get_default_method(void) +{ + return dh_default_method; +} + diff --git a/source4/heimdal/lib/des/dsa.c b/source4/heimdal/lib/des/dsa.c new file mode 100644 index 0000000000..411597b1c6 --- /dev/null +++ b/source4/heimdal/lib/des/dsa.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$Id: dsa.c,v 1.2 2006/05/07 11:31:58 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <dsa.h> + +#include <roken.h> + +/* + * + */ + +DSA * +DSA_new(void) +{ + DSA *dsa = calloc(1, sizeof(*dsa)); + dsa->meth = rk_UNCONST(DSA_get_default_method()); + dsa->references = 1; + return dsa; +} + +void +DSA_free(DSA *dsa) +{ + if (dsa->references <= 0) + abort(); + + if (--dsa->references > 0) + return; + + (*dsa->meth->finish)(dsa); + +#define free_if(f) if (f) { BN_free(f); } + free_if(dsa->p); + free_if(dsa->q); + free_if(dsa->g); + free_if(dsa->pub_key); + free_if(dsa->priv_key); + free_if(dsa->kinv); + free_if(dsa->r); +#undef free_if + + memset(dsa, 0, sizeof(*dsa)); + free(dsa); + +} + +int +DSA_up_ref(DSA *dsa) +{ + return ++dsa->references; +} + +/* + * + */ + +static const DSA_METHOD dsa_null_method = { + "hcrypto null DSA" +}; + +const DSA_METHOD * +DSA_null_method(void) +{ + return &dsa_null_method; +} + + +const DSA_METHOD *dsa_default_mech = &dsa_null_method; + +void +DSA_set_default_method(const DSA_METHOD *mech) +{ + dsa_default_mech = mech; +} + +const DSA_METHOD * +DSA_get_default_method(void) +{ + return dsa_default_mech; +} + +int +DSA_verify(int type, const unsigned char * digest, int digest_len, + const unsigned char *sig, int sig_len, DSA *dsa) +{ + return -1; +} diff --git a/source4/heimdal/lib/des/engine.c b/source4/heimdal/lib/des/engine.c new file mode 100644 index 0000000000..b72339c362 --- /dev/null +++ b/source4/heimdal/lib/des/engine.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$Id: engine.c,v 1.11 2006/10/19 14:23:00 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <engine.h> + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif +#endif + +struct hc_engine { + int references; + char *name; + char *id; + void (*destroy)(ENGINE *); + const RSA_METHOD *rsa; + const DH_METHOD *dh; + const RAND_METHOD *rand; +}; + +int +ENGINE_finish(ENGINE *engine) +{ + if (engine->references-- <= 0) + abort(); + if (engine->references > 0) + return 1; + + if (engine->name) + free(engine->name); + if (engine->id) + free(engine->id); + if(engine->destroy) + (*engine->destroy)(engine); + + memset(engine, 0, sizeof(engine)); + engine->references = -1; + + + free(engine); + return 1; +} + +int +ENGINE_up_ref(ENGINE *engine) +{ + if (engine->references < 0) + abort(); + engine->references++; + return 1; +} + +int +ENGINE_set_id(ENGINE *engine, const char *id) +{ + engine->id = strdup(id); + return (engine->id == NULL) ? 0 : 1; +} + +int +ENGINE_set_name(ENGINE *engine, const char *name) +{ + engine->name = strdup(name); + return (engine->name == NULL) ? 0 : 1; +} + +int +ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method) +{ + engine->rsa = method; + return 1; +} + +int +ENGINE_set_DH(ENGINE *engine, const DH_METHOD *method) +{ + engine->dh = method; + return 1; +} + +int +ENGINE_set_destroy_function(ENGINE *e, void (*destroy)(ENGINE *)) +{ + e->destroy = destroy; + return 1; +} + +const char * +ENGINE_get_id(const ENGINE *engine) +{ + return engine->id; +} + +const char * +ENGINE_get_name(const ENGINE *engine) +{ + return engine->name; +} + +const RSA_METHOD * +ENGINE_get_RSA(const ENGINE *engine) +{ + return engine->rsa; +} + +const DH_METHOD * +ENGINE_get_DH(const ENGINE *engine) +{ + return engine->dh; +} + +const RAND_METHOD * +ENGINE_get_RAND(const ENGINE *engine) +{ + return engine->rand; +} + +/* + * + */ + +#define SG_default_engine(type) \ +static ENGINE *type##_engine; \ +int \ +ENGINE_set_default_##type(ENGINE *engine) \ +{ \ + if (type##_engine) \ + ENGINE_finish(type##_engine); \ + type##_engine = engine; \ + if (type##_engine) \ + ENGINE_up_ref(type##_engine); \ + return 1; \ +} \ +ENGINE * \ +ENGINE_get_default_##type(void) \ +{ \ + if (type##_engine) \ + ENGINE_up_ref(type##_engine); \ + return type##_engine; \ +} + +SG_default_engine(RSA) +SG_default_engine(DH) + +#undef SG_default_engine + +/* + * + */ + +static ENGINE **engines; +static unsigned int num_engines; + +static int +add_engine(ENGINE *engine) +{ + ENGINE **d, *dup; + + dup = ENGINE_by_id(engine->id); + if (dup) { + ENGINE_finish(dup); + return 0; + } + + d = realloc(engines, (num_engines + 1) * sizeof(*engines)); + if (d == NULL) + return 1; + engines = d; + engines[num_engines++] = engine; + + return 1; +} + +void +ENGINE_load_builtin_engines(void) +{ + ENGINE *engine; + int ret; + + engine = calloc(1, sizeof(*engine)); + if (engine == NULL) + return; + + ENGINE_set_id(engine, "builtin"); + ENGINE_set_name(engine, + "Heimdal crypto builtin engine version " PACKAGE_VERSION); + ENGINE_set_RSA(engine, RSA_imath_method()); + ENGINE_set_DH(engine, DH_imath_method()); + + ret = add_engine(engine); + if (ret != 1) + ENGINE_finish(engine); +} + +ENGINE * +ENGINE_by_dso(const char *path, const char *id) +{ +#ifdef HAVE_DLOPEN + ENGINE *engine; + void *handle; + int ret; + + engine = calloc(1, sizeof(*engine)); + if (engine == NULL) + return NULL; + + handle = dlopen(path, RTLD_NOW); + if (handle == NULL) { + /* printf("error: %s\n", dlerror()); */ + free(engine); + return NULL; + } + + { + unsigned long version; + openssl_v_check v_check; + + v_check = (openssl_v_check)dlsym(handle, "v_check"); + if (v_check == NULL) { + dlclose(handle); + free(engine); + return NULL; + } + + version = (*v_check)(OPENSSL_DYNAMIC_VERSION); + if (version == 0) { + dlclose(handle); + free(engine); + return NULL; + } + } + + { + openssl_bind_engine bind_engine; + + bind_engine = (openssl_bind_engine)dlsym(handle, "bind_engine"); + if (bind_engine == NULL) { + dlclose(handle); + free(engine); + return NULL; + } + + ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */ + if (ret != 1) { + dlclose(handle); + free(engine); + return NULL; + } + } + + ENGINE_up_ref(engine); + + ret = add_engine(engine); + if (ret != 1) { + dlclose(handle); + ENGINE_finish(engine); + return NULL; + } + + return engine; +#else + return NULL; +#endif +} + +ENGINE * +ENGINE_by_id(const char *id) +{ + int i; + + for (i = 0; i < num_engines; i++) { + if (strcmp(id, engines[i]->id) == 0) { + ENGINE_up_ref(engines[i]); + return engines[i]; + } + } + return NULL; +} + +void +ENGINE_add_conf_module(void) +{ + ENGINE *engine; + + /* + * XXX Parse configuration file instead + */ + + engine = ENGINE_by_dso("/usr/heimdal/lib/hc-modules/hc-gmp.so", NULL); + if (engine == NULL) + return; + { + const RSA_METHOD *method = ENGINE_get_RSA(engine); + if (method) + RSA_set_default_method(method); + } + { + const DH_METHOD *method = ENGINE_get_DH(engine); + if (method) + DH_set_default_method(method); + } + +} diff --git a/source4/heimdal/lib/des/imath/LICENSE b/source4/heimdal/lib/des/imath/LICENSE new file mode 100644 index 0000000000..cecfb11404 --- /dev/null +++ b/source4/heimdal/lib/des/imath/LICENSE @@ -0,0 +1,21 @@ +IMath is Copyright 2002-2006 Michael J. Fromberger +You may use it subject to the following Licensing Terms: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/source4/heimdal/lib/des/imath/imath.c b/source4/heimdal/lib/des/imath/imath.c new file mode 100755 index 0000000000..0a124fa13f --- /dev/null +++ b/source4/heimdal/lib/des/imath/imath.c @@ -0,0 +1,3246 @@ +/* + Name: imath.c + Purpose: Arbitrary precision integer arithmetic routines. + Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/> + Info: $Id: imath.c,v 1.6 2007/01/08 10:17:31 lha Exp $ + + Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include "imath.h" + +#if DEBUG +#include <stdio.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include <assert.h> + +/* {{{ Constants */ + +const mp_result MP_OK = 0; /* no error, all is well */ +const mp_result MP_FALSE = 0; /* boolean false */ +const mp_result MP_TRUE = -1; /* boolean true */ +const mp_result MP_MEMORY = -2; /* out of memory */ +const mp_result MP_RANGE = -3; /* argument out of range */ +const mp_result MP_UNDEF = -4; /* result undefined */ +const mp_result MP_TRUNC = -5; /* output truncated */ +const mp_result MP_BADARG = -6; /* invalid null argument */ + +const mp_sign MP_NEG = 1; /* value is strictly negative */ +const mp_sign MP_ZPOS = 0; /* value is non-negative */ + +static const char *s_unknown_err = "unknown result code"; +static const char *s_error_msg[] = { + "error code 0", + "boolean true", + "out of memory", + "argument out of range", + "result undefined", + "output truncated", + "invalid null argument", + NULL +}; + +/* }}} */ + +/* Argument checking macros + Use CHECK() where a return value is required; NRCHECK() elsewhere */ +#define CHECK(TEST) assert(TEST) +#define NRCHECK(TEST) assert(TEST) + +/* {{{ Logarithm table for computing output sizes */ + +/* The ith entry of this table gives the value of log_i(2). + + An integer value n requires ceil(log_i(n)) digits to be represented + in base i. Since it is easy to compute lg(n), by counting bits, we + can compute log_i(n) = lg(n) * log_i(2). + + The use of this table eliminates a dependency upon linkage against + the standard math libraries. + */ +static const double s_log2[] = { + 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ + 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ + 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ + 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ + 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ + 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ + 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ + 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ + 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ + 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ + 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ + 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ + 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ + 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ + 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ + 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ + 0.166666667 +}; + +/* }}} */ +/* {{{ Various macros */ + +/* Return the number of digits needed to represent a static value */ +#define MP_VALUE_DIGITS(V) \ +((sizeof(V)+(sizeof(mp_digit)-1))/sizeof(mp_digit)) + +/* Round precision P to nearest word boundary */ +#define ROUND_PREC(P) ((mp_size)(2*(((P)+1)/2))) + +/* Set array P of S digits to zero */ +#define ZERO(P, S) \ +do{mp_size i__=(S)*sizeof(mp_digit);mp_digit *p__=(P);memset(p__,0,i__);}while(0) + +/* Copy S digits from array P to array Q */ +#define COPY(P, Q, S) \ +do{mp_size i__=(S)*sizeof(mp_digit);mp_digit *p__=(P),*q__=(Q);\ +memcpy(q__,p__,i__);}while(0) + +/* Reverse N elements of type T in array A */ +#define REV(T, A, N) \ +do{T *u_=(A),*v_=u_+(N)-1;while(u_<v_){T xch=*u_;*u_++=*v_;*v_--=xch;}}while(0) + +#if TRACEABLE_CLAMP +#define CLAMP(Z) s_clamp(Z) +#else +#define CLAMP(Z) \ +do{mp_int z_=(Z);mp_size uz_=MP_USED(z_);mp_digit *dz_=MP_DIGITS(z_)+uz_-1;\ +while(uz_ > 1 && (*dz_-- == 0)) --uz_;MP_USED(z_)=uz_;}while(0) +#endif + +#define MIN(A, B) ((B)<(A)?(B):(A)) +#define MAX(A, B) ((B)>(A)?(B):(A)) +#define SWAP(T, A, B) do{T t_=(A);A=(B);B=t_;}while(0) + +#define TEMP(K) (temp + (K)) +#define SETUP(E, C) \ +do{if((res = (E)) != MP_OK) goto CLEANUP; ++(C);}while(0) + +#define CMPZ(Z) \ +(((Z)->used==1&&(Z)->digits[0]==0)?0:((Z)->sign==MP_NEG)?-1:1) + +#define UMUL(X, Y, Z) \ +do{mp_size ua_=MP_USED(X),ub_=MP_USED(Y);mp_size o_=ua_+ub_;\ +ZERO(MP_DIGITS(Z),o_);\ +(void) s_kmul(MP_DIGITS(X),MP_DIGITS(Y),MP_DIGITS(Z),ua_,ub_);\ +MP_USED(Z)=o_;CLAMP(Z);}while(0) + +#define USQR(X, Z) \ +do{mp_size ua_=MP_USED(X),o_=ua_+ua_;ZERO(MP_DIGITS(Z),o_);\ +(void) s_ksqr(MP_DIGITS(X),MP_DIGITS(Z),ua_);MP_USED(Z)=o_;CLAMP(Z);}while(0) + +#define UPPER_HALF(W) ((mp_word)((W) >> MP_DIGIT_BIT)) +#define LOWER_HALF(W) ((mp_digit)(W)) +#define HIGH_BIT_SET(W) ((W) >> (MP_WORD_BIT - 1)) +#define ADD_WILL_OVERFLOW(W, V) ((MP_WORD_MAX - (V)) < (W)) + +/* }}} */ +/* {{{ Default configuration settings */ + +/* Default number of digits allocated to a new mp_int */ +#if IMATH_TEST +mp_size default_precision = MP_DEFAULT_PREC; +#else +static const mp_size default_precision = MP_DEFAULT_PREC; +#endif + +/* Minimum number of digits to invoke recursive multiply */ +#if IMATH_TEST +mp_size multiply_threshold = MP_MULT_THRESH; +#else +static const mp_size multiply_threshold = MP_MULT_THRESH; +#endif + +/* }}} */ + +/* Allocate a buffer of (at least) num digits, or return + NULL if that couldn't be done. */ +static mp_digit *s_alloc(mp_size num); +#if TRACEABLE_FREE +static void s_free(void *ptr); +#else +#define s_free(P) free(P) +#endif + +/* Insure that z has at least min digits allocated, resizing if + necessary. Returns true if successful, false if out of memory. */ +int s_pad(mp_int z, mp_size min); + +/* Normalize by removing leading zeroes (except when z = 0) */ +#if TRACEABLE_CLAMP +static void s_clamp(mp_int z); +#endif + +/* Fill in a "fake" mp_int on the stack with a given value */ +static void s_fake(mp_int z, int value, mp_digit vbuf[]); + +/* Compare two runs of digits of given length, returns <0, 0, >0 */ +static int s_cdig(mp_digit *da, mp_digit *db, mp_size len); + +/* Pack the unsigned digits of v into array t */ +static int s_vpack(int v, mp_digit t[]); + +/* Compare magnitudes of a and b, returns <0, 0, >0 */ +static int s_ucmp(mp_int a, mp_int b); + +/* Compare magnitudes of a and v, returns <0, 0, >0 */ +static int s_vcmp(mp_int a, int v); + +/* Unsigned magnitude addition; assumes dc is big enough. + Carry out is returned (no memory allocated). */ +static mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned magnitude subtraction. Assumes dc is big enough. */ +static void s_usub(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned recursive multiplication. Assumes dc is big enough. */ +static int s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned magnitude multiplication. Assumes dc is big enough. */ +static void s_umul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b); + +/* Unsigned recursive squaring. Assumes dc is big enough. */ +static int s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a); + +/* Unsigned magnitude squaring. Assumes dc is big enough. */ +static void s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a); + +/* Single digit addition. Assumes a is big enough. */ +static void s_dadd(mp_int a, mp_digit b); + +/* Single digit multiplication. Assumes a is big enough. */ +static void s_dmul(mp_int a, mp_digit b); + +/* Single digit multiplication on buffers; assumes dc is big enough. */ +static void s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc, + mp_size size_a); + +/* Single digit division. Replaces a with the quotient, + returns the remainder. */ +static mp_digit s_ddiv(mp_int a, mp_digit b); + +/* Quick division by a power of 2, replaces z (no allocation) */ +static void s_qdiv(mp_int z, mp_size p2); + +/* Quick remainder by a power of 2, replaces z (no allocation) */ +static void s_qmod(mp_int z, mp_size p2); + +/* Quick multiplication by a power of 2, replaces z. + Allocates if necessary; returns false in case this fails. */ +static int s_qmul(mp_int z, mp_size p2); + +/* Quick subtraction from a power of 2, replaces z. + Allocates if necessary; returns false in case this fails. */ +static int s_qsub(mp_int z, mp_size p2); + +/* Return maximum k such that 2^k divides z. */ +static int s_dp2k(mp_int z); + +/* Return k >= 0 such that z = 2^k, or -1 if there is no such k. */ +static int s_isp2(mp_int z); + +/* Set z to 2^k. May allocate; returns false in case this fails. */ +static int s_2expt(mp_int z, int k); + +/* Normalize a and b for division, returns normalization constant */ +static int s_norm(mp_int a, mp_int b); + +/* Compute constant mu for Barrett reduction, given modulus m, result + replaces z, m is untouched. */ +static mp_result s_brmu(mp_int z, mp_int m); + +/* Reduce a modulo m, using Barrett's algorithm. */ +static int s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2); + +/* Modular exponentiation, using Barrett reduction */ +mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c); + +/* Unsigned magnitude division. Assumes |a| > |b|. Allocates + temporaries; overwrites a with quotient, b with remainder. */ +static mp_result s_udiv(mp_int a, mp_int b); + +/* Compute the number of digits in radix r required to represent the + given value. Does not account for sign flags, terminators, etc. */ +static int s_outlen(mp_int z, mp_size r); + +/* Guess how many digits of precision will be needed to represent a + radix r value of the specified number of digits. Returns a value + guaranteed to be no smaller than the actual number required. */ +static mp_size s_inlen(int len, mp_size r); + +/* Convert a character to a digit value in radix r, or + -1 if out of range */ +static int s_ch2val(char c, int r); + +/* Convert a digit value to a character */ +static char s_val2ch(int v, int caps); + +/* Take 2's complement of a buffer in place */ +static void s_2comp(unsigned char *buf, int len); + +/* Convert a value to binary, ignoring sign. On input, *limpos is the + bound on how many bytes should be written to buf; on output, *limpos + is set to the number of bytes actually written. */ +static mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad); + +#if DEBUG +/* Dump a representation of the mp_int to standard output */ +void s_print(char *tag, mp_int z); +void s_print_buf(char *tag, mp_digit *buf, mp_size num); +#endif + +/* {{{ mp_int_init(z) */ + +mp_result mp_int_init(mp_int z) +{ + if(z == NULL) + return MP_BADARG; + + z->single = 0; + z->digits = &(z->single); + z->alloc = 1; + z->used = 1; + z->sign = MP_ZPOS; + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_alloc() */ + +mp_int mp_int_alloc(void) +{ + mp_int out = malloc(sizeof(mpz_t)); + + if(out != NULL) + mp_int_init(out); + + return out; +} + +/* }}} */ + +/* {{{ mp_int_init_size(z, prec) */ + +mp_result mp_int_init_size(mp_int z, mp_size prec) +{ + CHECK(z != NULL); + + if(prec == 0) + prec = default_precision; + else if(prec == 1) + return mp_int_init(z); + else + prec = (mp_size) ROUND_PREC(prec); + + if((MP_DIGITS(z) = s_alloc(prec)) == NULL) + return MP_MEMORY; + + z->digits[0] = 0; + MP_USED(z) = 1; + MP_ALLOC(z) = prec; + MP_SIGN(z) = MP_ZPOS; + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_init_copy(z, old) */ + +mp_result mp_int_init_copy(mp_int z, mp_int old) +{ + mp_result res; + mp_size uold; + + CHECK(z != NULL && old != NULL); + + uold = MP_USED(old); + if(uold == 1) { + mp_int_init(z); + } + else { + mp_size target = MAX(uold, default_precision); + + if((res = mp_int_init_size(z, target)) != MP_OK) + return res; + } + + MP_USED(z) = uold; + MP_SIGN(z) = MP_SIGN(old); + COPY(MP_DIGITS(old), MP_DIGITS(z), uold); + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_init_value(z, value) */ + +mp_result mp_int_init_value(mp_int z, int value) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + return mp_int_init_copy(z, &vtmp); +} + +/* }}} */ + +/* {{{ mp_int_set_value(z, value) */ + +mp_result mp_int_set_value(mp_int z, int value) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + return mp_int_copy(&vtmp, z); +} + +/* }}} */ + +/* {{{ mp_int_clear(z) */ + +void mp_int_clear(mp_int z) +{ + if(z == NULL) + return; + + if(MP_DIGITS(z) != NULL) { + if((void *) MP_DIGITS(z) != (void *) z) + s_free(MP_DIGITS(z)); + + MP_DIGITS(z) = NULL; + } +} + +/* }}} */ + +/* {{{ mp_int_free(z) */ + +void mp_int_free(mp_int z) +{ + NRCHECK(z != NULL); + + mp_int_clear(z); + free(z); +} + +/* }}} */ + +/* {{{ mp_int_copy(a, c) */ + +mp_result mp_int_copy(mp_int a, mp_int c) +{ + CHECK(a != NULL && c != NULL); + + if(a != c) { + mp_size ua = MP_USED(a); + mp_digit *da, *dc; + + if(!s_pad(c, ua)) + return MP_MEMORY; + + da = MP_DIGITS(a); dc = MP_DIGITS(c); + COPY(da, dc, ua); + + MP_USED(c) = ua; + MP_SIGN(c) = MP_SIGN(a); + } + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_swap(a, c) */ + +void mp_int_swap(mp_int a, mp_int c) +{ + if(a != c) { + mpz_t tmp = *a; + + *a = *c; + *c = tmp; + } +} + +/* }}} */ + +/* {{{ mp_int_zero(z) */ + +void mp_int_zero(mp_int z) +{ + NRCHECK(z != NULL); + + z->digits[0] = 0; + MP_USED(z) = 1; + MP_SIGN(z) = MP_ZPOS; +} + +/* }}} */ + +/* {{{ mp_int_abs(a, c) */ + +mp_result mp_int_abs(mp_int a, mp_int c) +{ + mp_result res; + + CHECK(a != NULL && c != NULL); + + if((res = mp_int_copy(a, c)) != MP_OK) + return res; + + MP_SIGN(c) = MP_ZPOS; + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_neg(a, c) */ + +mp_result mp_int_neg(mp_int a, mp_int c) +{ + mp_result res; + + CHECK(a != NULL && c != NULL); + + if((res = mp_int_copy(a, c)) != MP_OK) + return res; + + if(CMPZ(c) != 0) + MP_SIGN(c) = 1 - MP_SIGN(a); + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_add(a, b, c) */ + +mp_result mp_int_add(mp_int a, mp_int b, mp_int c) +{ + mp_size ua, ub, uc, max; + + CHECK(a != NULL && b != NULL && c != NULL); + + ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c); + max = MAX(ua, ub); + + if(MP_SIGN(a) == MP_SIGN(b)) { + /* Same sign -- add magnitudes, preserve sign of addends */ + mp_digit carry; + + if(!s_pad(c, max)) + return MP_MEMORY; + + carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub); + uc = max; + + if(carry) { + if(!s_pad(c, max + 1)) + return MP_MEMORY; + + c->digits[max] = carry; + ++uc; + } + + MP_USED(c) = uc; + MP_SIGN(c) = MP_SIGN(a); + + } + else { + /* Different signs -- subtract magnitudes, preserve sign of greater */ + mp_int x, y; + int cmp = s_ucmp(a, b); /* magnitude comparision, sign ignored */ + + /* Set x to max(a, b), y to min(a, b) to simplify later code */ + if(cmp >= 0) { + x = a; y = b; + } + else { + x = b; y = a; + } + + if(!s_pad(c, MP_USED(x))) + return MP_MEMORY; + + /* Subtract smaller from larger */ + s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y)); + MP_USED(c) = MP_USED(x); + CLAMP(c); + + /* Give result the sign of the larger */ + MP_SIGN(c) = MP_SIGN(x); + } + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_add_value(a, value, c) */ + +mp_result mp_int_add_value(mp_int a, int value, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_add(a, &vtmp, c); +} + +/* }}} */ + +/* {{{ mp_int_sub(a, b, c) */ + +mp_result mp_int_sub(mp_int a, mp_int b, mp_int c) +{ + mp_size ua, ub, uc, max; + + CHECK(a != NULL && b != NULL && c != NULL); + + ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c); + max = MAX(ua, ub); + + if(MP_SIGN(a) != MP_SIGN(b)) { + /* Different signs -- add magnitudes and keep sign of a */ + mp_digit carry; + + if(!s_pad(c, max)) + return MP_MEMORY; + + carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub); + uc = max; + + if(carry) { + if(!s_pad(c, max + 1)) + return MP_MEMORY; + + c->digits[max] = carry; + ++uc; + } + + MP_USED(c) = uc; + MP_SIGN(c) = MP_SIGN(a); + + } + else { + /* Same signs -- subtract magnitudes */ + mp_int x, y; + mp_sign osign; + int cmp = s_ucmp(a, b); + + if(!s_pad(c, max)) + return MP_MEMORY; + + if(cmp >= 0) { + x = a; y = b; osign = MP_ZPOS; + } + else { + x = b; y = a; osign = MP_NEG; + } + + if(MP_SIGN(a) == MP_NEG && cmp != 0) + osign = 1 - osign; + + s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y)); + MP_USED(c) = MP_USED(x); + CLAMP(c); + + MP_SIGN(c) = osign; + } + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_sub_value(a, value, c) */ + +mp_result mp_int_sub_value(mp_int a, int value, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_sub(a, &vtmp, c); +} + +/* }}} */ + +/* {{{ mp_int_mul(a, b, c) */ + +mp_result mp_int_mul(mp_int a, mp_int b, mp_int c) +{ + mp_digit *out; + mp_size osize, ua, ub, p = 0; + mp_sign osign; + + CHECK(a != NULL && b != NULL && c != NULL); + + /* If either input is zero, we can shortcut multiplication */ + if(mp_int_compare_zero(a) == 0 || mp_int_compare_zero(b) == 0) { + mp_int_zero(c); + return MP_OK; + } + + /* Output is positive if inputs have same sign, otherwise negative */ + osign = (MP_SIGN(a) == MP_SIGN(b)) ? MP_ZPOS : MP_NEG; + + /* If the output is not equal to any of the inputs, we'll write the + results there directly; otherwise, allocate a temporary space. */ + ua = MP_USED(a); ub = MP_USED(b); + osize = ua + ub; + + if(c == a || c == b) { + p = ROUND_PREC(osize); + p = MAX(p, default_precision); + + if((out = s_alloc(p)) == NULL) + return MP_MEMORY; + } + else { + if(!s_pad(c, osize)) + return MP_MEMORY; + + out = MP_DIGITS(c); + } + ZERO(out, osize); + + if(!s_kmul(MP_DIGITS(a), MP_DIGITS(b), out, ua, ub)) + return MP_MEMORY; + + /* If we allocated a new buffer, get rid of whatever memory c was + already using, and fix up its fields to reflect that. + */ + if(out != MP_DIGITS(c)) { + if((void *) MP_DIGITS(c) != (void *) c) + s_free(MP_DIGITS(c)); + MP_DIGITS(c) = out; + MP_ALLOC(c) = p; + } + + MP_USED(c) = osize; /* might not be true, but we'll fix it ... */ + CLAMP(c); /* ... right here */ + MP_SIGN(c) = osign; + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_mul_value(a, value, c) */ + +mp_result mp_int_mul_value(mp_int a, int value, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_mul(a, &vtmp, c); +} + +/* }}} */ + +/* {{{ mp_int_mul_pow2(a, p2, c) */ + +mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c) +{ + mp_result res; + CHECK(a != NULL && c != NULL && p2 >= 0); + + if((res = mp_int_copy(a, c)) != MP_OK) + return res; + + if(s_qmul(c, (mp_size) p2)) + return MP_OK; + else + return MP_MEMORY; +} + +/* }}} */ + +/* {{{ mp_int_sqr(a, c) */ + +mp_result mp_int_sqr(mp_int a, mp_int c) +{ + mp_digit *out; + mp_size osize, p = 0; + + CHECK(a != NULL && c != NULL); + + /* Get a temporary buffer big enough to hold the result */ + osize = (mp_size) 2 * MP_USED(a); + if(a == c) { + p = ROUND_PREC(osize); + p = MAX(p, default_precision); + + if((out = s_alloc(p)) == NULL) + return MP_MEMORY; + } + else { + if(!s_pad(c, osize)) + return MP_MEMORY; + + out = MP_DIGITS(c); + } + ZERO(out, osize); + + s_ksqr(MP_DIGITS(a), out, MP_USED(a)); + + /* Get rid of whatever memory c was already using, and fix up its + fields to reflect the new digit array it's using + */ + if(out != MP_DIGITS(c)) { + if((void *) MP_DIGITS(c) != (void *) c) + s_free(MP_DIGITS(c)); + MP_DIGITS(c) = out; + MP_ALLOC(c) = p; + } + + MP_USED(c) = osize; /* might not be true, but we'll fix it ... */ + CLAMP(c); /* ... right here */ + MP_SIGN(c) = MP_ZPOS; + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_div(a, b, q, r) */ + +mp_result mp_int_div(mp_int a, mp_int b, mp_int q, mp_int r) +{ + int cmp, last = 0, lg; + mp_result res = MP_OK; + mpz_t temp[2]; + mp_int qout, rout; + mp_sign sa = MP_SIGN(a), sb = MP_SIGN(b); + + CHECK(a != NULL && b != NULL && q != r); + + if(CMPZ(b) == 0) + return MP_UNDEF; + else if((cmp = s_ucmp(a, b)) < 0) { + /* If |a| < |b|, no division is required: + q = 0, r = a + */ + if(r && (res = mp_int_copy(a, r)) != MP_OK) + return res; + + if(q) + mp_int_zero(q); + + return MP_OK; + } + else if(cmp == 0) { + /* If |a| = |b|, no division is required: + q = 1 or -1, r = 0 + */ + if(r) + mp_int_zero(r); + + if(q) { + mp_int_zero(q); + q->digits[0] = 1; + + if(sa != sb) + MP_SIGN(q) = MP_NEG; + } + + return MP_OK; + } + + /* When |a| > |b|, real division is required. We need someplace to + store quotient and remainder, but q and r are allowed to be NULL + or to overlap with the inputs. + */ + if((lg = s_isp2(b)) < 0) { + if(q && b != q && (res = mp_int_copy(a, q)) == MP_OK) { + qout = q; + } + else { + qout = TEMP(last); + SETUP(mp_int_init_copy(TEMP(last), a), last); + } + + if(r && a != r && (res = mp_int_copy(b, r)) == MP_OK) { + rout = r; + } + else { + rout = TEMP(last); + SETUP(mp_int_init_copy(TEMP(last), b), last); + } + + if((res = s_udiv(qout, rout)) != MP_OK) goto CLEANUP; + } + else { + if(q && (res = mp_int_copy(a, q)) != MP_OK) goto CLEANUP; + if(r && (res = mp_int_copy(a, r)) != MP_OK) goto CLEANUP; + + if(q) s_qdiv(q, (mp_size) lg); qout = q; + if(r) s_qmod(r, (mp_size) lg); rout = r; + } + + /* Recompute signs for output */ + if(rout) { + MP_SIGN(rout) = sa; + if(CMPZ(rout) == 0) + MP_SIGN(rout) = MP_ZPOS; + } + if(qout) { + MP_SIGN(qout) = (sa == sb) ? MP_ZPOS : MP_NEG; + if(CMPZ(qout) == 0) + MP_SIGN(qout) = MP_ZPOS; + } + + if(q && (res = mp_int_copy(qout, q)) != MP_OK) goto CLEANUP; + if(r && (res = mp_int_copy(rout, r)) != MP_OK) goto CLEANUP; + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_mod(a, m, c) */ + +mp_result mp_int_mod(mp_int a, mp_int m, mp_int c) +{ + mp_result res; + mpz_t tmp; + mp_int out; + + if(m == c) { + mp_int_init(&tmp); + out = &tmp; + } + else { + out = c; + } + + if((res = mp_int_div(a, m, NULL, out)) != MP_OK) + goto CLEANUP; + + if(CMPZ(out) < 0) + res = mp_int_add(out, m, c); + else + res = mp_int_copy(out, c); + + CLEANUP: + if(out != c) + mp_int_clear(&tmp); + + return res; +} + +/* }}} */ + + +/* {{{ mp_int_div_value(a, value, q, r) */ + +mp_result mp_int_div_value(mp_int a, int value, mp_int q, int *r) +{ + mpz_t vtmp, rtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + mp_result res; + + mp_int_init(&rtmp); + s_fake(&vtmp, value, vbuf); + + if((res = mp_int_div(a, &vtmp, q, &rtmp)) != MP_OK) + goto CLEANUP; + + if(r) + (void) mp_int_to_int(&rtmp, r); /* can't fail */ + + CLEANUP: + mp_int_clear(&rtmp); + return res; +} + +/* }}} */ + +/* {{{ mp_int_div_pow2(a, p2, q, r) */ + +mp_result mp_int_div_pow2(mp_int a, int p2, mp_int q, mp_int r) +{ + mp_result res = MP_OK; + + CHECK(a != NULL && p2 >= 0 && q != r); + + if(q != NULL && (res = mp_int_copy(a, q)) == MP_OK) + s_qdiv(q, (mp_size) p2); + + if(res == MP_OK && r != NULL && (res = mp_int_copy(a, r)) == MP_OK) + s_qmod(r, (mp_size) p2); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_expt(a, b, c) */ + +mp_result mp_int_expt(mp_int a, int b, mp_int c) +{ + mpz_t t; + mp_result res; + unsigned int v = abs(b); + + CHECK(b >= 0 && c != NULL); + + if((res = mp_int_init_copy(&t, a)) != MP_OK) + return res; + + (void) mp_int_set_value(c, 1); + while(v != 0) { + if(v & 1) { + if((res = mp_int_mul(c, &t, c)) != MP_OK) + goto CLEANUP; + } + + v >>= 1; + if(v == 0) break; + + if((res = mp_int_sqr(&t, &t)) != MP_OK) + goto CLEANUP; + } + + CLEANUP: + mp_int_clear(&t); + return res; +} + +/* }}} */ + +/* {{{ mp_int_expt_value(a, b, c) */ + +mp_result mp_int_expt_value(int a, int b, mp_int c) +{ + mpz_t t; + mp_result res; + unsigned int v = abs(b); + + CHECK(b >= 0 && c != NULL); + + if((res = mp_int_init_value(&t, a)) != MP_OK) + return res; + + (void) mp_int_set_value(c, 1); + while(v != 0) { + if(v & 1) { + if((res = mp_int_mul(c, &t, c)) != MP_OK) + goto CLEANUP; + } + + v >>= 1; + if(v == 0) break; + + if((res = mp_int_sqr(&t, &t)) != MP_OK) + goto CLEANUP; + } + + CLEANUP: + mp_int_clear(&t); + return res; +} + +/* }}} */ + +/* {{{ mp_int_compare(a, b) */ + +int mp_int_compare(mp_int a, mp_int b) +{ + mp_sign sa; + + CHECK(a != NULL && b != NULL); + + sa = MP_SIGN(a); + if(sa == MP_SIGN(b)) { + int cmp = s_ucmp(a, b); + + /* If they're both zero or positive, the normal comparison + applies; if both negative, the sense is reversed. */ + if(sa == MP_ZPOS) + return cmp; + else + return -cmp; + + } + else { + if(sa == MP_ZPOS) + return 1; + else + return -1; + } +} + +/* }}} */ + +/* {{{ mp_int_compare_unsigned(a, b) */ + +int mp_int_compare_unsigned(mp_int a, mp_int b) +{ + NRCHECK(a != NULL && b != NULL); + + return s_ucmp(a, b); +} + +/* }}} */ + +/* {{{ mp_int_compare_zero(z) */ + +int mp_int_compare_zero(mp_int z) +{ + NRCHECK(z != NULL); + + if(MP_USED(z) == 1 && z->digits[0] == 0) + return 0; + else if(MP_SIGN(z) == MP_ZPOS) + return 1; + else + return -1; +} + +/* }}} */ + +/* {{{ mp_int_compare_value(z, value) */ + +int mp_int_compare_value(mp_int z, int value) +{ + mp_sign vsign = (value < 0) ? MP_NEG : MP_ZPOS; + int cmp; + + CHECK(z != NULL); + + if(vsign == MP_SIGN(z)) { + cmp = s_vcmp(z, value); + + if(vsign == MP_ZPOS) + return cmp; + else + return -cmp; + } + else { + if(value < 0) + return 1; + else + return -1; + } +} + +/* }}} */ + +/* {{{ mp_int_exptmod(a, b, m, c) */ + +mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, mp_int c) +{ + mp_result res; + mp_size um; + mpz_t temp[3]; + mp_int s; + int last = 0; + + CHECK(a != NULL && b != NULL && c != NULL && m != NULL); + + /* Zero moduli and negative exponents are not considered. */ + if(CMPZ(m) == 0) + return MP_UNDEF; + if(CMPZ(b) < 0) + return MP_RANGE; + + um = MP_USED(m); + SETUP(mp_int_init_size(TEMP(0), 2 * um), last); + SETUP(mp_int_init_size(TEMP(1), 2 * um), last); + + if(c == b || c == m) { + SETUP(mp_int_init_size(TEMP(2), 2 * um), last); + s = TEMP(2); + } + else { + s = c; + } + + if((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP; + + if((res = s_brmu(TEMP(1), m)) != MP_OK) goto CLEANUP; + + if((res = s_embar(TEMP(0), b, m, TEMP(1), s)) != MP_OK) + goto CLEANUP; + + res = mp_int_copy(s, c); + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_exptmod_evalue(a, value, m, c) */ + +mp_result mp_int_exptmod_evalue(mp_int a, int value, mp_int m, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_exptmod(a, &vtmp, m, c); +} + +/* }}} */ + +/* {{{ mp_int_exptmod_bvalue(v, b, m, c) */ + +mp_result mp_int_exptmod_bvalue(int value, mp_int b, + mp_int m, mp_int c) +{ + mpz_t vtmp; + mp_digit vbuf[MP_VALUE_DIGITS(value)]; + + s_fake(&vtmp, value, vbuf); + + return mp_int_exptmod(&vtmp, b, m, c); +} + +/* }}} */ + +/* {{{ mp_int_exptmod_known(a, b, m, mu, c) */ + +mp_result mp_int_exptmod_known(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c) +{ + mp_result res; + mp_size um; + mpz_t temp[2]; + mp_int s; + int last = 0; + + CHECK(a && b && m && c); + + /* Zero moduli and negative exponents are not considered. */ + if(CMPZ(m) == 0) + return MP_UNDEF; + if(CMPZ(b) < 0) + return MP_RANGE; + + um = MP_USED(m); + SETUP(mp_int_init_size(TEMP(0), 2 * um), last); + + if(c == b || c == m) { + SETUP(mp_int_init_size(TEMP(1), 2 * um), last); + s = TEMP(1); + } + else { + s = c; + } + + if((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP; + + if((res = s_embar(TEMP(0), b, m, mu, s)) != MP_OK) + goto CLEANUP; + + res = mp_int_copy(s, c); + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_redux_const(m, c) */ + +mp_result mp_int_redux_const(mp_int m, mp_int c) +{ + CHECK(m != NULL && c != NULL && m != c); + + return s_brmu(c, m); +} + +/* }}} */ + +/* {{{ mp_int_invmod(a, m, c) */ + +mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c) +{ + mp_result res; + mp_sign sa; + int last = 0; + mpz_t temp[2]; + + CHECK(a != NULL && m != NULL && c != NULL); + + if(CMPZ(a) == 0 || CMPZ(m) <= 0) + return MP_RANGE; + + sa = MP_SIGN(a); /* need this for the result later */ + + for(last = 0; last < 2; ++last) + mp_int_init(TEMP(last)); + + if((res = mp_int_egcd(a, m, TEMP(0), TEMP(1), NULL)) != MP_OK) + goto CLEANUP; + + if(mp_int_compare_value(TEMP(0), 1) != 0) { + res = MP_UNDEF; + goto CLEANUP; + } + + /* It is first necessary to constrain the value to the proper range */ + if((res = mp_int_mod(TEMP(1), m, TEMP(1))) != MP_OK) + goto CLEANUP; + + /* Now, if 'a' was originally negative, the value we have is + actually the magnitude of the negative representative; to get the + positive value we have to subtract from the modulus. Otherwise, + the value is okay as it stands. + */ + if(sa == MP_NEG) + res = mp_int_sub(m, TEMP(1), c); + else + res = mp_int_copy(TEMP(1), c); + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_gcd(a, b, c) */ + +/* Binary GCD algorithm due to Josef Stein, 1961 */ +mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c) +{ + int ca, cb, k = 0; + mpz_t u, v, t; + mp_result res; + + CHECK(a != NULL && b != NULL && c != NULL); + + ca = CMPZ(a); + cb = CMPZ(b); + if(ca == 0 && cb == 0) + return MP_UNDEF; + else if(ca == 0) + return mp_int_abs(b, c); + else if(cb == 0) + return mp_int_abs(a, c); + + mp_int_init(&t); + if((res = mp_int_init_copy(&u, a)) != MP_OK) + goto U; + if((res = mp_int_init_copy(&v, b)) != MP_OK) + goto V; + + MP_SIGN(&u) = MP_ZPOS; MP_SIGN(&v) = MP_ZPOS; + + { /* Divide out common factors of 2 from u and v */ + int div2_u = s_dp2k(&u), div2_v = s_dp2k(&v); + + k = MIN(div2_u, div2_v); + s_qdiv(&u, (mp_size) k); + s_qdiv(&v, (mp_size) k); + } + + if(mp_int_is_odd(&u)) { + if((res = mp_int_neg(&v, &t)) != MP_OK) + goto CLEANUP; + } + else { + if((res = mp_int_copy(&u, &t)) != MP_OK) + goto CLEANUP; + } + + for(;;) { + s_qdiv(&t, s_dp2k(&t)); + + if(CMPZ(&t) > 0) { + if((res = mp_int_copy(&t, &u)) != MP_OK) + goto CLEANUP; + } + else { + if((res = mp_int_neg(&t, &v)) != MP_OK) + goto CLEANUP; + } + + if((res = mp_int_sub(&u, &v, &t)) != MP_OK) + goto CLEANUP; + + if(CMPZ(&t) == 0) + break; + } + + if((res = mp_int_abs(&u, c)) != MP_OK) + goto CLEANUP; + if(!s_qmul(c, (mp_size) k)) + res = MP_MEMORY; + + CLEANUP: + mp_int_clear(&v); + V: mp_int_clear(&u); + U: mp_int_clear(&t); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_egcd(a, b, c, x, y) */ + +/* This is the binary GCD algorithm again, but this time we keep track + of the elementary matrix operations as we go, so we can get values + x and y satisfying c = ax + by. + */ +mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, + mp_int x, mp_int y) +{ + int k, last = 0, ca, cb; + mpz_t temp[8]; + mp_result res; + + CHECK(a != NULL && b != NULL && c != NULL && + (x != NULL || y != NULL)); + + ca = CMPZ(a); + cb = CMPZ(b); + if(ca == 0 && cb == 0) + return MP_UNDEF; + else if(ca == 0) { + if((res = mp_int_abs(b, c)) != MP_OK) return res; + mp_int_zero(x); (void) mp_int_set_value(y, 1); return MP_OK; + } + else if(cb == 0) { + if((res = mp_int_abs(a, c)) != MP_OK) return res; + (void) mp_int_set_value(x, 1); mp_int_zero(y); return MP_OK; + } + + /* Initialize temporaries: + A:0, B:1, C:2, D:3, u:4, v:5, ou:6, ov:7 */ + for(last = 0; last < 4; ++last) + mp_int_init(TEMP(last)); + TEMP(0)->digits[0] = 1; + TEMP(3)->digits[0] = 1; + + SETUP(mp_int_init_copy(TEMP(4), a), last); + SETUP(mp_int_init_copy(TEMP(5), b), last); + + /* We will work with absolute values here */ + MP_SIGN(TEMP(4)) = MP_ZPOS; + MP_SIGN(TEMP(5)) = MP_ZPOS; + + { /* Divide out common factors of 2 from u and v */ + int div2_u = s_dp2k(TEMP(4)), div2_v = s_dp2k(TEMP(5)); + + k = MIN(div2_u, div2_v); + s_qdiv(TEMP(4), k); + s_qdiv(TEMP(5), k); + } + + SETUP(mp_int_init_copy(TEMP(6), TEMP(4)), last); + SETUP(mp_int_init_copy(TEMP(7), TEMP(5)), last); + + for(;;) { + while(mp_int_is_even(TEMP(4))) { + s_qdiv(TEMP(4), 1); + + if(mp_int_is_odd(TEMP(0)) || mp_int_is_odd(TEMP(1))) { + if((res = mp_int_add(TEMP(0), TEMP(7), TEMP(0))) != MP_OK) + goto CLEANUP; + if((res = mp_int_sub(TEMP(1), TEMP(6), TEMP(1))) != MP_OK) + goto CLEANUP; + } + + s_qdiv(TEMP(0), 1); + s_qdiv(TEMP(1), 1); + } + + while(mp_int_is_even(TEMP(5))) { + s_qdiv(TEMP(5), 1); + + if(mp_int_is_odd(TEMP(2)) || mp_int_is_odd(TEMP(3))) { + if((res = mp_int_add(TEMP(2), TEMP(7), TEMP(2))) != MP_OK) + goto CLEANUP; + if((res = mp_int_sub(TEMP(3), TEMP(6), TEMP(3))) != MP_OK) + goto CLEANUP; + } + + s_qdiv(TEMP(2), 1); + s_qdiv(TEMP(3), 1); + } + + if(mp_int_compare(TEMP(4), TEMP(5)) >= 0) { + if((res = mp_int_sub(TEMP(4), TEMP(5), TEMP(4))) != MP_OK) goto CLEANUP; + if((res = mp_int_sub(TEMP(0), TEMP(2), TEMP(0))) != MP_OK) goto CLEANUP; + if((res = mp_int_sub(TEMP(1), TEMP(3), TEMP(1))) != MP_OK) goto CLEANUP; + } + else { + if((res = mp_int_sub(TEMP(5), TEMP(4), TEMP(5))) != MP_OK) goto CLEANUP; + if((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK) goto CLEANUP; + if((res = mp_int_sub(TEMP(3), TEMP(1), TEMP(3))) != MP_OK) goto CLEANUP; + } + + if(CMPZ(TEMP(4)) == 0) { + if(x && (res = mp_int_copy(TEMP(2), x)) != MP_OK) goto CLEANUP; + if(y && (res = mp_int_copy(TEMP(3), y)) != MP_OK) goto CLEANUP; + if(c) { + if(!s_qmul(TEMP(5), k)) { + res = MP_MEMORY; + goto CLEANUP; + } + + res = mp_int_copy(TEMP(5), c); + } + + break; + } + } + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_divisible_value(a, v) */ + +int mp_int_divisible_value(mp_int a, int v) +{ + int rem = 0; + + if(mp_int_div_value(a, v, NULL, &rem) != MP_OK) + return 0; + + return rem == 0; +} + +/* }}} */ + +/* {{{ mp_int_is_pow2(z) */ + +int mp_int_is_pow2(mp_int z) +{ + CHECK(z != NULL); + + return s_isp2(z); +} + +/* }}} */ + +/* {{{ mp_int_sqrt(a, c) */ + +mp_result mp_int_sqrt(mp_int a, mp_int c) +{ + mp_result res = MP_OK; + mpz_t temp[2]; + int last = 0; + + CHECK(a != NULL && c != NULL); + + /* The square root of a negative value does not exist in the integers. */ + if(MP_SIGN(a) == MP_NEG) + return MP_UNDEF; + + SETUP(mp_int_init_copy(TEMP(last), a), last); + SETUP(mp_int_init(TEMP(last)), last); + + for(;;) { + if((res = mp_int_sqr(TEMP(0), TEMP(1))) != MP_OK) + goto CLEANUP; + + if(mp_int_compare_unsigned(a, TEMP(1)) == 0) break; + + if((res = mp_int_copy(a, TEMP(1))) != MP_OK) + goto CLEANUP; + if((res = mp_int_div(TEMP(1), TEMP(0), TEMP(1), NULL)) != MP_OK) + goto CLEANUP; + if((res = mp_int_add(TEMP(0), TEMP(1), TEMP(1))) != MP_OK) + goto CLEANUP; + if((res = mp_int_div_pow2(TEMP(1), 1, TEMP(1), NULL)) != MP_OK) + goto CLEANUP; + + if(mp_int_compare_unsigned(TEMP(0), TEMP(1)) == 0) break; + if((res = mp_int_sub_value(TEMP(0), 1, TEMP(0))) != MP_OK) goto CLEANUP; + if(mp_int_compare_unsigned(TEMP(0), TEMP(1)) == 0) break; + + if((res = mp_int_copy(TEMP(1), TEMP(0))) != MP_OK) goto CLEANUP; + } + + res = mp_int_copy(TEMP(0), c); + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_to_int(z, out) */ + +mp_result mp_int_to_int(mp_int z, int *out) +{ + unsigned int uv = 0; + mp_size uz; + mp_digit *dz; + mp_sign sz; + + CHECK(z != NULL); + + /* Make sure the value is representable as an int */ + sz = MP_SIGN(z); + if((sz == MP_ZPOS && mp_int_compare_value(z, INT_MAX) > 0) || + mp_int_compare_value(z, INT_MIN) < 0) + return MP_RANGE; + + uz = MP_USED(z); + dz = MP_DIGITS(z) + uz - 1; + + while(uz > 0) { + uv <<= MP_DIGIT_BIT/2; + uv = (uv << (MP_DIGIT_BIT/2)) | *dz--; + --uz; + } + + if(out) + *out = (sz == MP_NEG) ? -(int)uv : (int)uv; + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_to_string(z, radix, str, limit) */ + +mp_result mp_int_to_string(mp_int z, mp_size radix, + char *str, int limit) +{ + mp_result res; + int cmp = 0; + + CHECK(z != NULL && str != NULL && limit >= 2); + + if(radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) + return MP_RANGE; + + if(CMPZ(z) == 0) { + *str++ = s_val2ch(0, 1); + } + else { + mpz_t tmp; + char *h, *t; + + if((res = mp_int_init_copy(&tmp, z)) != MP_OK) + return res; + + if(MP_SIGN(z) == MP_NEG) { + *str++ = '-'; + --limit; + } + h = str; + + /* Generate digits in reverse order until finished or limit reached */ + for(/* */; limit > 0; --limit) { + mp_digit d; + + if((cmp = CMPZ(&tmp)) == 0) + break; + + d = s_ddiv(&tmp, (mp_digit)radix); + *str++ = s_val2ch(d, 1); + } + t = str - 1; + + /* Put digits back in correct output order */ + while(h < t) { + char tc = *h; + *h++ = *t; + *t-- = tc; + } + + mp_int_clear(&tmp); + } + + *str = '\0'; + if(cmp == 0) + return MP_OK; + else + return MP_TRUNC; +} + +/* }}} */ + +/* {{{ mp_int_string_len(z, radix) */ + +mp_result mp_int_string_len(mp_int z, mp_size radix) +{ + int len; + + CHECK(z != NULL); + + if(radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) + return MP_RANGE; + + len = s_outlen(z, radix) + 1; /* for terminator */ + + /* Allow for sign marker on negatives */ + if(MP_SIGN(z) == MP_NEG) + len += 1; + + return len; +} + +/* }}} */ + +/* {{{ mp_int_read_string(z, radix, *str) */ + +/* Read zero-terminated string into z */ +mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str) +{ + return mp_int_read_cstring(z, radix, str, NULL); + +} + +/* }}} */ + +/* {{{ mp_int_read_cstring(z, radix, *str, **end) */ + +mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, char **end) +{ + int ch; + + CHECK(z != NULL && str != NULL); + + if(radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) + return MP_RANGE; + + /* Skip leading whitespace */ + while(isspace((int)*str)) + ++str; + + /* Handle leading sign tag (+/-, positive default) */ + switch(*str) { + case '-': + MP_SIGN(z) = MP_NEG; + ++str; + break; + case '+': + ++str; /* fallthrough */ + default: + MP_SIGN(z) = MP_ZPOS; + break; + } + + /* Skip leading zeroes */ + while((ch = s_ch2val(*str, radix)) == 0) + ++str; + + /* Make sure there is enough space for the value */ + if(!s_pad(z, s_inlen(strlen(str), radix))) + return MP_MEMORY; + + MP_USED(z) = 1; z->digits[0] = 0; + + while(*str != '\0' && ((ch = s_ch2val(*str, radix)) >= 0)) { + s_dmul(z, (mp_digit)radix); + s_dadd(z, (mp_digit)ch); + ++str; + } + + CLAMP(z); + + /* Override sign for zero, even if negative specified. */ + if(CMPZ(z) == 0) + MP_SIGN(z) = MP_ZPOS; + + if(end != NULL) + *end = (char *)str; + + /* Return a truncation error if the string has unprocessed + characters remaining, so the caller can tell if the whole string + was done */ + if(*str != '\0') + return MP_TRUNC; + else + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_count_bits(z) */ + +mp_result mp_int_count_bits(mp_int z) +{ + mp_size nbits = 0, uz; + mp_digit d; + + CHECK(z != NULL); + + uz = MP_USED(z); + if(uz == 1 && z->digits[0] == 0) + return 1; + + --uz; + nbits = uz * MP_DIGIT_BIT; + d = z->digits[uz]; + + while(d != 0) { + d >>= 1; + ++nbits; + } + + return nbits; +} + +/* }}} */ + +/* {{{ mp_int_to_binary(z, buf, limit) */ + +mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit) +{ + static const int PAD_FOR_2C = 1; + + mp_result res; + int limpos = limit; + + CHECK(z != NULL && buf != NULL); + + res = s_tobin(z, buf, &limpos, PAD_FOR_2C); + + if(MP_SIGN(z) == MP_NEG) + s_2comp(buf, limpos); + + return res; +} + +/* }}} */ + +/* {{{ mp_int_read_binary(z, buf, len) */ + +mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len) +{ + mp_size need, i; + unsigned char *tmp; + mp_digit *dz; + + CHECK(z != NULL && buf != NULL && len > 0); + + /* Figure out how many digits are needed to represent this value */ + need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT; + if(!s_pad(z, need)) + return MP_MEMORY; + + mp_int_zero(z); + + /* If the high-order bit is set, take the 2's complement before + reading the value (it will be restored afterward) */ + if(buf[0] >> (CHAR_BIT - 1)) { + MP_SIGN(z) = MP_NEG; + s_2comp(buf, len); + } + + dz = MP_DIGITS(z); + for(tmp = buf, i = len; i > 0; --i, ++tmp) { + s_qmul(z, (mp_size) CHAR_BIT); + *dz |= *tmp; + } + + /* Restore 2's complement if we took it before */ + if(MP_SIGN(z) == MP_NEG) + s_2comp(buf, len); + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_binary_len(z) */ + +mp_result mp_int_binary_len(mp_int z) +{ + mp_result res = mp_int_count_bits(z); + int bytes = mp_int_unsigned_len(z); + + if(res <= 0) + return res; + + bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT; + + /* If the highest-order bit falls exactly on a byte boundary, we + need to pad with an extra byte so that the sign will be read + correctly when reading it back in. */ + if(bytes * CHAR_BIT == res) + ++bytes; + + return bytes; +} + +/* }}} */ + +/* {{{ mp_int_to_unsigned(z, buf, limit) */ + +mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit) +{ + static const int NO_PADDING = 0; + + CHECK(z != NULL && buf != NULL); + + return s_tobin(z, buf, &limit, NO_PADDING); +} + +/* }}} */ + +/* {{{ mp_int_read_unsigned(z, buf, len) */ + +mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len) +{ + mp_size need, i; + unsigned char *tmp; + mp_digit *dz; + + CHECK(z != NULL && buf != NULL && len > 0); + + /* Figure out how many digits are needed to represent this value */ + need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT; + if(!s_pad(z, need)) + return MP_MEMORY; + + mp_int_zero(z); + + dz = MP_DIGITS(z); + for(tmp = buf, i = len; i > 0; --i, ++tmp) { + (void) s_qmul(z, CHAR_BIT); + *dz |= *tmp; + } + + return MP_OK; +} + +/* }}} */ + +/* {{{ mp_int_unsigned_len(z) */ + +mp_result mp_int_unsigned_len(mp_int z) +{ + mp_result res = mp_int_count_bits(z); + int bytes; + + if(res <= 0) + return res; + + bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT; + + return bytes; +} + +/* }}} */ + +/* {{{ mp_error_string(res) */ + +const char *mp_error_string(mp_result res) +{ + int ix; + if(res > 0) + return s_unknown_err; + + res = -res; + for(ix = 0; ix < res && s_error_msg[ix] != NULL; ++ix) + ; + + if(s_error_msg[ix] != NULL) + return s_error_msg[ix]; + else + return s_unknown_err; +} + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* Private functions for internal use. These make assumptions. */ + +/* {{{ s_alloc(num) */ + +static mp_digit *s_alloc(mp_size num) +{ + mp_digit *out = malloc(num * sizeof(mp_digit)); + + assert(out != NULL); /* for debugging */ + + return out; +} + +/* }}} */ + +/* {{{ s_realloc(old, num) */ + +static mp_digit *s_realloc(mp_digit *old, mp_size num) +{ + mp_digit *new = realloc(old, num * sizeof(mp_digit)); + + assert(new != NULL); /* for debugging */ + + return new; +} + +/* }}} */ + +/* {{{ s_free(ptr) */ + +#if TRACEABLE_FREE +static void s_free(void *ptr) +{ + free(ptr); +} +#endif + +/* }}} */ + +/* {{{ s_pad(z, min) */ + +int s_pad(mp_int z, mp_size min) +{ + if(MP_ALLOC(z) < min) { + mp_size nsize = ROUND_PREC(min); + mp_digit *tmp; + + if((void *)z->digits == (void *)z) { + if((tmp = s_alloc(nsize)) == NULL) + return 0; + + COPY(MP_DIGITS(z), tmp, MP_USED(z)); + } + else if((tmp = s_realloc(MP_DIGITS(z), nsize)) == NULL) + return 0; + + MP_DIGITS(z) = tmp; + MP_ALLOC(z) = nsize; + } + + return 1; +} + +/* }}} */ + +/* {{{ s_clamp(z) */ + +#if TRACEABLE_CLAMP +static void s_clamp(mp_int z) +{ + mp_size uz = MP_USED(z); + mp_digit *zd = MP_DIGITS(z) + uz - 1; + + while(uz > 1 && (*zd-- == 0)) + --uz; + + MP_USED(z) = uz; +} +#endif + +/* }}} */ + +/* {{{ s_fake(z, value, vbuf) */ + +static void s_fake(mp_int z, int value, mp_digit vbuf[]) +{ + mp_size uv = (mp_size) s_vpack(value, vbuf); + + z->used = uv; + z->alloc = MP_VALUE_DIGITS(value); + z->sign = (value < 0) ? MP_NEG : MP_ZPOS; + z->digits = vbuf; +} + +/* }}} */ + +/* {{{ s_cdig(da, db, len) */ + +static int s_cdig(mp_digit *da, mp_digit *db, mp_size len) +{ + mp_digit *dat = da + len - 1, *dbt = db + len - 1; + + for(/* */; len != 0; --len, --dat, --dbt) { + if(*dat > *dbt) + return 1; + else if(*dat < *dbt) + return -1; + } + + return 0; +} + +/* }}} */ + +/* {{{ s_vpack(v, t[]) */ + +static int s_vpack(int v, mp_digit t[]) +{ + unsigned int uv = (unsigned int)((v < 0) ? -v : v); + int ndig = 0; + + if(uv == 0) + t[ndig++] = 0; + else { + while(uv != 0) { + t[ndig++] = (mp_digit) uv; + uv >>= MP_DIGIT_BIT/2; + uv >>= MP_DIGIT_BIT/2; + } + } + + return ndig; +} + +/* }}} */ + +/* {{{ s_ucmp(a, b) */ + +static int s_ucmp(mp_int a, mp_int b) +{ + mp_size ua = MP_USED(a), ub = MP_USED(b); + + if(ua > ub) + return 1; + else if(ub > ua) + return -1; + else + return s_cdig(MP_DIGITS(a), MP_DIGITS(b), ua); +} + +/* }}} */ + +/* {{{ s_vcmp(a, v) */ + +static int s_vcmp(mp_int a, int v) +{ + mp_digit vdig[MP_VALUE_DIGITS(v)]; + int ndig = 0; + mp_size ua = MP_USED(a); + + ndig = s_vpack(v, vdig); + + if(ua > ndig) + return 1; + else if(ua < ndig) + return -1; + else + return s_cdig(MP_DIGITS(a), vdig, ndig); +} + +/* }}} */ + +/* {{{ s_uadd(da, db, dc, size_a, size_b) */ + +static mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size pos; + mp_word w = 0; + + /* Insure that da is the longer of the two to simplify later code */ + if(size_b > size_a) { + SWAP(mp_digit *, da, db); + SWAP(mp_size, size_a, size_b); + } + + /* Add corresponding digits until the shorter number runs out */ + for(pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) { + w = w + (mp_word) *da + (mp_word) *db; + *dc = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + /* Propagate carries as far as necessary */ + for(/* */; pos < size_a; ++pos, ++da, ++dc) { + w = w + *da; + + *dc = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + /* Return carry out */ + return (mp_digit)w; +} + +/* }}} */ + +/* {{{ s_usub(da, db, dc, size_a, size_b) */ + +static void s_usub(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size pos; + mp_word w = 0; + + /* We assume that |a| >= |b| so this should definitely hold */ + assert(size_a >= size_b); + + /* Subtract corresponding digits and propagate borrow */ + for(pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) { + w = ((mp_word)MP_DIGIT_MAX + 1 + /* MP_RADIX */ + (mp_word)*da) - w - (mp_word)*db; + + *dc = LOWER_HALF(w); + w = (UPPER_HALF(w) == 0); + } + + /* Finish the subtraction for remaining upper digits of da */ + for(/* */; pos < size_a; ++pos, ++da, ++dc) { + w = ((mp_word)MP_DIGIT_MAX + 1 + /* MP_RADIX */ + (mp_word)*da) - w; + + *dc = LOWER_HALF(w); + w = (UPPER_HALF(w) == 0); + } + + /* If there is a borrow out at the end, it violates the precondition */ + assert(w == 0); +} + +/* }}} */ + +/* {{{ s_kmul(da, db, dc, size_a, size_b) */ + +static int s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size bot_size; + + /* Make sure b is the smaller of the two input values */ + if(size_b > size_a) { + SWAP(mp_digit *, da, db); + SWAP(mp_size, size_a, size_b); + } + + /* Insure that the bottom is the larger half in an odd-length split; + the code below relies on this being true. + */ + bot_size = (size_a + 1) / 2; + + /* If the values are big enough to bother with recursion, use the + Karatsuba algorithm to compute the product; otherwise use the + normal multiplication algorithm + */ + if(multiply_threshold && + size_a >= multiply_threshold && + size_b > bot_size) { + + mp_digit *t1, *t2, *t3, carry; + + mp_digit *a_top = da + bot_size; + mp_digit *b_top = db + bot_size; + + mp_size at_size = size_a - bot_size; + mp_size bt_size = size_b - bot_size; + mp_size buf_size = 2 * bot_size; + + /* Do a single allocation for all three temporary buffers needed; + each buffer must be big enough to hold the product of two + bottom halves, and one buffer needs space for the completed + product; twice the space is plenty. + */ + if((t1 = s_alloc(4 * buf_size)) == NULL) return 0; + t2 = t1 + buf_size; + t3 = t2 + buf_size; + ZERO(t1, 4 * buf_size); + + /* t1 and t2 are initially used as temporaries to compute the inner product + (a1 + a0)(b1 + b0) = a1b1 + a1b0 + a0b1 + a0b0 + */ + carry = s_uadd(da, a_top, t1, bot_size, at_size); /* t1 = a1 + a0 */ + t1[bot_size] = carry; + + carry = s_uadd(db, b_top, t2, bot_size, bt_size); /* t2 = b1 + b0 */ + t2[bot_size] = carry; + + (void) s_kmul(t1, t2, t3, bot_size + 1, bot_size + 1); /* t3 = t1 * t2 */ + + /* Now we'll get t1 = a0b0 and t2 = a1b1, and subtract them out so that + we're left with only the pieces we want: t3 = a1b0 + a0b1 + */ + ZERO(t1, bot_size + 1); + ZERO(t2, bot_size + 1); + (void) s_kmul(da, db, t1, bot_size, bot_size); /* t1 = a0 * b0 */ + (void) s_kmul(a_top, b_top, t2, at_size, bt_size); /* t2 = a1 * b1 */ + + /* Subtract out t1 and t2 to get the inner product */ + s_usub(t3, t1, t3, buf_size + 2, buf_size); + s_usub(t3, t2, t3, buf_size + 2, buf_size); + + /* Assemble the output value */ + COPY(t1, dc, buf_size); + (void) s_uadd(t3, dc + bot_size, dc + bot_size, + buf_size + 1, buf_size + 1); + + (void) s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size, + buf_size, buf_size); + + s_free(t1); /* note t2 and t3 are just internal pointers to t1 */ + } + else { + s_umul(da, db, dc, size_a, size_b); + } + + return 1; +} + +/* }}} */ + +/* {{{ s_umul(da, db, dc, size_a, size_b) */ + +static void s_umul(mp_digit *da, mp_digit *db, mp_digit *dc, + mp_size size_a, mp_size size_b) +{ + mp_size a, b; + mp_word w; + + for(a = 0; a < size_a; ++a, ++dc, ++da) { + mp_digit *dct = dc; + mp_digit *dbt = db; + + if(*da == 0) + continue; + + w = 0; + for(b = 0; b < size_b; ++b, ++dbt, ++dct) { + w = (mp_word)*da * (mp_word)*dbt + w + (mp_word)*dct; + + *dct = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + *dct = (mp_digit)w; + } +} + +/* }}} */ + +/* {{{ s_ksqr(da, dc, size_a) */ + +static int s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a) +{ + if(multiply_threshold && size_a > multiply_threshold) { + mp_size bot_size = (size_a + 1) / 2; + mp_digit *a_top = da + bot_size; + mp_digit *t1, *t2, *t3; + mp_size at_size = size_a - bot_size; + mp_size buf_size = 2 * bot_size; + + if((t1 = s_alloc(4 * buf_size)) == NULL) return 0; + t2 = t1 + buf_size; + t3 = t2 + buf_size; + ZERO(t1, 4 * buf_size); + + (void) s_ksqr(da, t1, bot_size); /* t1 = a0 ^ 2 */ + (void) s_ksqr(a_top, t2, at_size); /* t2 = a1 ^ 2 */ + + (void) s_kmul(da, a_top, t3, bot_size, at_size); /* t3 = a0 * a1 */ + + /* Quick multiply t3 by 2, shifting left (can't overflow) */ + { + int i, top = bot_size + at_size; + mp_word w, save = 0; + + for(i = 0; i < top; ++i) { + w = t3[i]; + w = (w << 1) | save; + t3[i] = LOWER_HALF(w); + save = UPPER_HALF(w); + } + t3[i] = LOWER_HALF(save); + } + + /* Assemble the output value */ + COPY(t1, dc, 2 * bot_size); + (void) s_uadd(t3, dc + bot_size, dc + bot_size, + buf_size + 1, buf_size + 1); + + (void) s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size, + buf_size, buf_size); + + free(t1); /* note that t2 and t2 are internal pointers only */ + + } + else { + s_usqr(da, dc, size_a); + } + + return 1; +} + +/* }}} */ + +/* {{{ s_usqr(da, dc, size_a) */ + +static void s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a) +{ + mp_size i, j; + mp_word w; + + for(i = 0; i < size_a; ++i, dc += 2, ++da) { + mp_digit *dct = dc, *dat = da; + + if(*da == 0) + continue; + + /* Take care of the first digit, no rollover */ + w = (mp_word)*dat * (mp_word)*dat + (mp_word)*dct; + *dct = LOWER_HALF(w); + w = UPPER_HALF(w); + ++dat; ++dct; + + for(j = i + 1; j < size_a; ++j, ++dat, ++dct) { + mp_word t = (mp_word)*da * (mp_word)*dat; + mp_word u = w + (mp_word)*dct, ov = 0; + + /* Check if doubling t will overflow a word */ + if(HIGH_BIT_SET(t)) + ov = 1; + + w = t + t; + + /* Check if adding u to w will overflow a word */ + if(ADD_WILL_OVERFLOW(w, u)) + ov = 1; + + w += u; + + *dct = LOWER_HALF(w); + w = UPPER_HALF(w); + if(ov) { + w += MP_DIGIT_MAX; /* MP_RADIX */ + ++w; + } + } + + w = w + *dct; + *dct = (mp_digit)w; + while((w = UPPER_HALF(w)) != 0) { + ++dct; w = w + *dct; + *dct = LOWER_HALF(w); + } + + assert(w == 0); + } +} + +/* }}} */ + +/* {{{ s_dadd(a, b) */ + +static void s_dadd(mp_int a, mp_digit b) +{ + mp_word w = 0; + mp_digit *da = MP_DIGITS(a); + mp_size ua = MP_USED(a); + + w = (mp_word)*da + b; + *da++ = LOWER_HALF(w); + w = UPPER_HALF(w); + + for(ua -= 1; ua > 0; --ua, ++da) { + w = (mp_word)*da + w; + + *da = LOWER_HALF(w); + w = UPPER_HALF(w); + } + + if(w) { + *da = (mp_digit)w; + MP_USED(a) += 1; + } +} + +/* }}} */ + +/* {{{ s_dmul(a, b) */ + +static void s_dmul(mp_int a, mp_digit b) +{ + mp_word w = 0; + mp_digit *da = MP_DIGITS(a); + mp_size ua = MP_USED(a); + + while(ua > 0) { + w = (mp_word)*da * b + w; + *da++ = LOWER_HALF(w); + w = UPPER_HALF(w); + --ua; + } + + if(w) { + *da = (mp_digit)w; + MP_USED(a) += 1; + } +} + +/* }}} */ + +/* {{{ s_dbmul(da, b, dc, size_a) */ + +static void s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc, mp_size size_a) +{ + mp_word w = 0; + + while(size_a > 0) { + w = (mp_word)*da++ * (mp_word)b + w; + + *dc++ = LOWER_HALF(w); + w = UPPER_HALF(w); + --size_a; + } + + if(w) + *dc = LOWER_HALF(w); +} + +/* }}} */ + +/* {{{ s_ddiv(da, d, dc, size_a) */ + +static mp_digit s_ddiv(mp_int a, mp_digit b) +{ + mp_word w = 0, qdigit; + mp_size ua = MP_USED(a); + mp_digit *da = MP_DIGITS(a) + ua - 1; + + for(/* */; ua > 0; --ua, --da) { + w = (w << MP_DIGIT_BIT) | *da; + + if(w >= b) { + qdigit = w / b; + w = w % b; + } + else { + qdigit = 0; + } + + *da = (mp_digit)qdigit; + } + + CLAMP(a); + return (mp_digit)w; +} + +/* }}} */ + +/* {{{ s_qdiv(z, p2) */ + +static void s_qdiv(mp_int z, mp_size p2) +{ + mp_size ndig = p2 / MP_DIGIT_BIT, nbits = p2 % MP_DIGIT_BIT; + mp_size uz = MP_USED(z); + + if(ndig) { + mp_size mark; + mp_digit *to, *from; + + if(ndig >= uz) { + mp_int_zero(z); + return; + } + + to = MP_DIGITS(z); from = to + ndig; + + for(mark = ndig; mark < uz; ++mark) + *to++ = *from++; + + MP_USED(z) = uz - ndig; + } + + if(nbits) { + mp_digit d = 0, *dz, save; + mp_size up = MP_DIGIT_BIT - nbits; + + uz = MP_USED(z); + dz = MP_DIGITS(z) + uz - 1; + + for(/* */; uz > 0; --uz, --dz) { + save = *dz; + + *dz = (*dz >> nbits) | (d << up); + d = save; + } + + CLAMP(z); + } + + if(MP_USED(z) == 1 && z->digits[0] == 0) + MP_SIGN(z) = MP_ZPOS; +} + +/* }}} */ + +/* {{{ s_qmod(z, p2) */ + +static void s_qmod(mp_int z, mp_size p2) +{ + mp_size start = p2 / MP_DIGIT_BIT + 1, rest = p2 % MP_DIGIT_BIT; + mp_size uz = MP_USED(z); + mp_digit mask = (1 << rest) - 1; + + if(start <= uz) { + MP_USED(z) = start; + z->digits[start - 1] &= mask; + CLAMP(z); + } +} + +/* }}} */ + +/* {{{ s_qmul(z, p2) */ + +static int s_qmul(mp_int z, mp_size p2) +{ + mp_size uz, need, rest, extra, i; + mp_digit *from, *to, d; + + if(p2 == 0) + return 1; + + uz = MP_USED(z); + need = p2 / MP_DIGIT_BIT; rest = p2 % MP_DIGIT_BIT; + + /* Figure out if we need an extra digit at the top end; this occurs + if the topmost `rest' bits of the high-order digit of z are not + zero, meaning they will be shifted off the end if not preserved */ + extra = 0; + if(rest != 0) { + mp_digit *dz = MP_DIGITS(z) + uz - 1; + + if((*dz >> (MP_DIGIT_BIT - rest)) != 0) + extra = 1; + } + + if(!s_pad(z, uz + need + extra)) + return 0; + + /* If we need to shift by whole digits, do that in one pass, then + to back and shift by partial digits. + */ + if(need > 0) { + from = MP_DIGITS(z) + uz - 1; + to = from + need; + + for(i = 0; i < uz; ++i) + *to-- = *from--; + + ZERO(MP_DIGITS(z), need); + uz += need; + } + + if(rest) { + d = 0; + for(i = need, from = MP_DIGITS(z) + need; i < uz; ++i, ++from) { + mp_digit save = *from; + + *from = (*from << rest) | (d >> (MP_DIGIT_BIT - rest)); + d = save; + } + + d >>= (MP_DIGIT_BIT - rest); + if(d != 0) { + *from = d; + uz += extra; + } + } + + MP_USED(z) = uz; + CLAMP(z); + + return 1; +} + +/* }}} */ + +/* {{{ s_qsub(z, p2) */ + +/* Subtract |z| from 2^p2, assuming 2^p2 > |z|, and set z to be positive */ +static int s_qsub(mp_int z, mp_size p2) +{ + mp_digit hi = (1 << (p2 % MP_DIGIT_BIT)), *zp; + mp_size tdig = (p2 / MP_DIGIT_BIT), pos; + mp_word w = 0; + + if(!s_pad(z, tdig + 1)) + return 0; + + for(pos = 0, zp = MP_DIGITS(z); pos < tdig; ++pos, ++zp) { + w = ((mp_word) MP_DIGIT_MAX + 1) - w - (mp_word)*zp; + + *zp = LOWER_HALF(w); + w = UPPER_HALF(w) ? 0 : 1; + } + + w = ((mp_word) MP_DIGIT_MAX + 1 + hi) - w - (mp_word)*zp; + *zp = LOWER_HALF(w); + + assert(UPPER_HALF(w) != 0); /* no borrow out should be possible */ + + MP_SIGN(z) = MP_ZPOS; + CLAMP(z); + + return 1; +} + +/* }}} */ + +/* {{{ s_dp2k(z) */ + +static int s_dp2k(mp_int z) +{ + int k = 0; + mp_digit *dp = MP_DIGITS(z), d; + + if(MP_USED(z) == 1 && *dp == 0) + return 1; + + while(*dp == 0) { + k += MP_DIGIT_BIT; + ++dp; + } + + d = *dp; + while((d & 1) == 0) { + d >>= 1; + ++k; + } + + return k; +} + +/* }}} */ + +/* {{{ s_isp2(z) */ + +static int s_isp2(mp_int z) +{ + mp_size uz = MP_USED(z), k = 0; + mp_digit *dz = MP_DIGITS(z), d; + + while(uz > 1) { + if(*dz++ != 0) + return -1; + k += MP_DIGIT_BIT; + --uz; + } + + d = *dz; + while(d > 1) { + if(d & 1) + return -1; + ++k; d >>= 1; + } + + return (int) k; +} + +/* }}} */ + +/* {{{ s_2expt(z, k) */ + +static int s_2expt(mp_int z, int k) +{ + mp_size ndig, rest; + mp_digit *dz; + + ndig = (k + MP_DIGIT_BIT) / MP_DIGIT_BIT; + rest = k % MP_DIGIT_BIT; + + if(!s_pad(z, ndig)) + return 0; + + dz = MP_DIGITS(z); + ZERO(dz, ndig); + *(dz + ndig - 1) = (1 << rest); + MP_USED(z) = ndig; + + return 1; +} + +/* }}} */ + +/* {{{ s_norm(a, b) */ + +static int s_norm(mp_int a, mp_int b) +{ + mp_digit d = b->digits[MP_USED(b) - 1]; + int k = 0; + + while(d < (mp_digit) (1 << (MP_DIGIT_BIT - 1))) { /* d < (MP_RADIX / 2) */ + d <<= 1; + ++k; + } + + /* These multiplications can't fail */ + if(k != 0) { + (void) s_qmul(a, (mp_size) k); + (void) s_qmul(b, (mp_size) k); + } + + return k; +} + +/* }}} */ + +/* {{{ s_brmu(z, m) */ + +static mp_result s_brmu(mp_int z, mp_int m) +{ + mp_size um = MP_USED(m) * 2; + + if(!s_pad(z, um)) + return MP_MEMORY; + + s_2expt(z, MP_DIGIT_BIT * um); + return mp_int_div(z, m, z, NULL); +} + +/* }}} */ + +/* {{{ s_reduce(x, m, mu, q1, q2) */ + +static int s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2) +{ + mp_size um = MP_USED(m), umb_p1, umb_m1; + + umb_p1 = (um + 1) * MP_DIGIT_BIT; + umb_m1 = (um - 1) * MP_DIGIT_BIT; + + if(mp_int_copy(x, q1) != MP_OK) + return 0; + + /* Compute q2 = floor((floor(x / b^(k-1)) * mu) / b^(k+1)) */ + s_qdiv(q1, umb_m1); + UMUL(q1, mu, q2); + s_qdiv(q2, umb_p1); + + /* Set x = x mod b^(k+1) */ + s_qmod(x, umb_p1); + + /* Now, q is a guess for the quotient a / m. + Compute x - q * m mod b^(k+1), replacing x. This may be off + by a factor of 2m, but no more than that. + */ + UMUL(q2, m, q1); + s_qmod(q1, umb_p1); + (void) mp_int_sub(x, q1, x); /* can't fail */ + + /* The result may be < 0; if it is, add b^(k+1) to pin it in the + proper range. */ + if((CMPZ(x) < 0) && !s_qsub(x, umb_p1)) + return 0; + + /* If x > m, we need to back it off until it is in range. + This will be required at most twice. */ + if(mp_int_compare(x, m) >= 0) + (void) mp_int_sub(x, m, x); + if(mp_int_compare(x, m) >= 0) + (void) mp_int_sub(x, m, x); + + /* At this point, x has been properly reduced. */ + return 1; +} + +/* }}} */ + +/* {{{ s_embar(a, b, m, mu, c) */ + +/* Perform modular exponentiation using Barrett's method, where mu is + the reduction constant for m. Assumes a < m, b > 0. */ +mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c) +{ + mp_digit *db, *dbt, umu, d; + mpz_t temp[3]; + mp_result res; + int last = 0; + + umu = MP_USED(mu); db = MP_DIGITS(b); dbt = db + MP_USED(b) - 1; + + while(last < 3) + SETUP(mp_int_init_size(TEMP(last), 4 * umu), last); + + (void) mp_int_set_value(c, 1); + + /* Take care of low-order digits */ + while(db < dbt) { + int i; + + for(d = *db, i = MP_DIGIT_BIT; i > 0; --i, d >>= 1) { + if(d & 1) { + /* The use of a second temporary avoids allocation */ + UMUL(c, a, TEMP(0)); + if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + mp_int_copy(TEMP(0), c); + } + + + USQR(a, TEMP(0)); + assert(MP_SIGN(TEMP(0)) == MP_ZPOS); + if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + assert(MP_SIGN(TEMP(0)) == MP_ZPOS); + mp_int_copy(TEMP(0), a); + + + } + + ++db; + } + + /* Take care of highest-order digit */ + d = *dbt; + for(;;) { + if(d & 1) { + UMUL(c, a, TEMP(0)); + if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + mp_int_copy(TEMP(0), c); + } + + d >>= 1; + if(!d) break; + + USQR(a, TEMP(0)); + if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) { + res = MP_MEMORY; goto CLEANUP; + } + (void) mp_int_copy(TEMP(0), a); + } + + CLEANUP: + while(--last >= 0) + mp_int_clear(TEMP(last)); + + return res; +} + +/* }}} */ + +/* {{{ s_udiv(a, b) */ + +/* Precondition: a >= b and b > 0 + Postcondition: a' = a / b, b' = a % b + */ +static mp_result s_udiv(mp_int a, mp_int b) +{ + mpz_t q, r, t; + mp_size ua, ub, qpos = 0; + mp_digit *da, btop; + mp_result res = MP_OK; + int k, skip = 0; + + /* Force signs to positive */ + MP_SIGN(a) = MP_ZPOS; + MP_SIGN(b) = MP_ZPOS; + + /* Normalize, per Knuth */ + k = s_norm(a, b); + + ua = MP_USED(a); ub = MP_USED(b); btop = b->digits[ub - 1]; + if((res = mp_int_init_size(&q, ua)) != MP_OK) return res; + if((res = mp_int_init_size(&t, ua + 1)) != MP_OK) goto CLEANUP; + + da = MP_DIGITS(a); + r.digits = da + ua - 1; /* The contents of r are shared with a */ + r.used = 1; + r.sign = MP_ZPOS; + r.alloc = MP_ALLOC(a); + ZERO(t.digits, t.alloc); + + /* Solve for quotient digits, store in q.digits in reverse order */ + while(r.digits >= da) { + if (qpos > q.alloc) { + char buf[1024]; + printf("qpos = %d q.alloc = %d da = %d ua = %d\n", + (int)qpos, (int)q.alloc, (int)da, (int)ua); + mp_int_to_string(a, 10, buf, sizeof(buf)); + printf("a = %s\n", buf); + mp_int_to_string(b, 10, buf, sizeof(buf)); + printf("b = %s\n", buf); + assert(qpos <= q.alloc); + } + + if(s_ucmp(b, &r) > 0) { + r.digits -= 1; + r.used += 1; + + if(++skip > 1) + q.digits[qpos++] = 0; + + CLAMP(&r); + } + else { + mp_word pfx = r.digits[r.used - 1]; + mp_word qdigit; + + if(r.used > 1 && (pfx < btop || r.digits[r.used - 2] == 0)) { + pfx <<= MP_DIGIT_BIT / 2; + pfx <<= MP_DIGIT_BIT / 2; + pfx |= r.digits[r.used - 2]; + } + + qdigit = pfx / btop; + if(qdigit > MP_DIGIT_MAX) + qdigit = 1; + + s_dbmul(MP_DIGITS(b), (mp_digit) qdigit, t.digits, ub); + t.used = ub + 1; CLAMP(&t); + while(s_ucmp(&t, &r) > 0) { + --qdigit; + (void) mp_int_sub(&t, b, &t); /* cannot fail */ + } + + s_usub(r.digits, t.digits, r.digits, r.used, t.used); + CLAMP(&r); + + q.digits[qpos++] = (mp_digit) qdigit; + ZERO(t.digits, t.used); + skip = 0; + } + } + + /* Put quotient digits in the correct order, and discard extra zeroes */ + q.used = qpos; + REV(mp_digit, q.digits, qpos); + CLAMP(&q); + + /* Denormalize the remainder */ + CLAMP(a); + if(k != 0) + s_qdiv(a, k); + + mp_int_copy(a, b); /* ok: 0 <= r < b */ + mp_int_copy(&q, a); /* ok: q <= a */ + + mp_int_clear(&t); + CLEANUP: + mp_int_clear(&q); + return res; +} + +/* }}} */ + +/* {{{ s_outlen(z, r) */ + +/* Precondition: 2 <= r < 64 */ +static int s_outlen(mp_int z, mp_size r) +{ + mp_result bits; + double raw; + + bits = mp_int_count_bits(z); + raw = (double)bits * s_log2[r]; + + return (int)(raw + 0.999999); +} + +/* }}} */ + +/* {{{ s_inlen(len, r) */ + +static mp_size s_inlen(int len, mp_size r) +{ + double raw = (double)len / s_log2[r]; + mp_size bits = (mp_size)(raw + 0.5); + + return (mp_size)((bits + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT); +} + +/* }}} */ + +/* {{{ s_ch2val(c, r) */ + +static int s_ch2val(char c, int r) +{ + int out; + + if(isdigit((unsigned char) c)) + out = c - '0'; + else if(r > 10 && isalpha((unsigned char) c)) + out = toupper(c) - 'A' + 10; + else + return -1; + + return (out >= r) ? -1 : out; +} + +/* }}} */ + +/* {{{ s_val2ch(v, caps) */ + +static char s_val2ch(int v, int caps) +{ + assert(v >= 0); + + if(v < 10) + return v + '0'; + else { + char out = (v - 10) + 'a'; + + if(caps) + return toupper(out); + else + return out; + } +} + +/* }}} */ + +/* {{{ s_2comp(buf, len) */ + +static void s_2comp(unsigned char *buf, int len) +{ + int i; + unsigned short s = 1; + + for(i = len - 1; i >= 0; --i) { + unsigned char c = ~buf[i]; + + s = c + s; + c = s & UCHAR_MAX; + s >>= CHAR_BIT; + + buf[i] = c; + } + + /* last carry out is ignored */ +} + +/* }}} */ + +/* {{{ s_tobin(z, buf, *limpos) */ + +static mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad) +{ + mp_size uz; + mp_digit *dz; + int pos = 0, limit = *limpos; + + uz = MP_USED(z); dz = MP_DIGITS(z); + while(uz > 0 && pos < limit) { + mp_digit d = *dz++; + int i; + + for(i = sizeof(mp_digit); i > 0 && pos < limit; --i) { + buf[pos++] = (unsigned char)d; + d >>= CHAR_BIT; + + /* Don't write leading zeroes */ + if(d == 0 && uz == 1) + i = 0; /* exit loop without signaling truncation */ + } + + /* Detect truncation (loop exited with pos >= limit) */ + if(i > 0) break; + + --uz; + } + + if(pad != 0 && (buf[pos - 1] >> (CHAR_BIT - 1))) { + if(pos < limit) + buf[pos++] = 0; + else + uz = 1; + } + + /* Digits are in reverse order, fix that */ + REV(unsigned char, buf, pos); + + /* Return the number of bytes actually written */ + *limpos = pos; + + return (uz == 0) ? MP_OK : MP_TRUNC; +} + +/* }}} */ + +/* {{{ s_print(tag, z) */ + +#if DEBUG +void s_print(char *tag, mp_int z) +{ + int i; + + fprintf(stderr, "%s: %c ", tag, + (MP_SIGN(z) == MP_NEG) ? '-' : '+'); + + for(i = MP_USED(z) - 1; i >= 0; --i) + fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), z->digits[i]); + + fputc('\n', stderr); + +} + +void s_print_buf(char *tag, mp_digit *buf, mp_size num) +{ + int i; + + fprintf(stderr, "%s: ", tag); + + for(i = num - 1; i >= 0; --i) + fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), buf[i]); + + fputc('\n', stderr); +} +#endif + +/* }}} */ + +/* HERE THERE BE DRAGONS */ diff --git a/source4/heimdal/lib/des/imath/imath.h b/source4/heimdal/lib/des/imath/imath.h new file mode 100755 index 0000000000..93cc35654d --- /dev/null +++ b/source4/heimdal/lib/des/imath/imath.h @@ -0,0 +1,220 @@ +/* + Name: imath.h + Purpose: Arbitrary precision integer arithmetic routines. + Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/> + Info: $Id: imath.h,v 1.3 2006/10/21 16:32:15 lha Exp $ + + Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef IMATH_H_ +#define IMATH_H_ + +#include <limits.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char mp_sign; +typedef unsigned int mp_size; +typedef int mp_result; +#ifdef USE_LONG_LONG +typedef unsigned int mp_digit; +typedef unsigned long long mp_word; +#else +typedef unsigned short mp_digit; +typedef unsigned int mp_word; +#endif + +typedef struct mpz { + mp_digit single; + mp_digit *digits; + mp_size alloc; + mp_size used; + mp_sign sign; +} mpz_t, *mp_int; + +#define MP_DIGITS(Z) ((Z)->digits) +#define MP_ALLOC(Z) ((Z)->alloc) +#define MP_USED(Z) ((Z)->used) +#define MP_SIGN(Z) ((Z)->sign) + +extern const mp_result MP_OK; +extern const mp_result MP_FALSE; +extern const mp_result MP_TRUE; +extern const mp_result MP_MEMORY; +extern const mp_result MP_RANGE; +extern const mp_result MP_UNDEF; +extern const mp_result MP_TRUNC; +extern const mp_result MP_BADARG; + +#define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT) +#define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT) + +#ifdef USE_LONG_LONG +# ifndef ULONG_LONG_MAX +# ifdef ULLONG_MAX +# define ULONG_LONG_MAX ULLONG_MAX +# else +# error "Maximum value of unsigned long long not defined!" +# endif +# endif +# define MP_DIGIT_MAX (ULONG_MAX * 1ULL) +# define MP_WORD_MAX ULONG_LONG_MAX +#else +# define MP_DIGIT_MAX (USHRT_MAX * 1UL) +# define MP_WORD_MAX (UINT_MAX * 1UL) +#endif + +#define MP_MIN_RADIX 2 +#define MP_MAX_RADIX 36 + +/* Values with fewer than this many significant digits use the + standard multiplication algorithm; otherwise, a recursive algorithm + is used. Choose a value to suit your platform. + */ +#define MP_MULT_THRESH 32 + +#define MP_DEFAULT_PREC 8 /* default memory allocation, in digits */ + +extern const mp_sign MP_NEG; +extern const mp_sign MP_ZPOS; + +#define mp_int_is_odd(Z) ((Z)->digits[0] & 1) +#define mp_int_is_even(Z) !((Z)->digits[0] & 1) + +mp_result mp_int_init(mp_int z); +mp_int mp_int_alloc(void); +mp_result mp_int_init_size(mp_int z, mp_size prec); +mp_result mp_int_init_copy(mp_int z, mp_int old); +mp_result mp_int_init_value(mp_int z, int value); +mp_result mp_int_set_value(mp_int z, int value); +void mp_int_clear(mp_int z); +void mp_int_free(mp_int z); + +mp_result mp_int_copy(mp_int a, mp_int c); /* c = a */ +void mp_int_swap(mp_int a, mp_int c); /* swap a, c */ +void mp_int_zero(mp_int z); /* z = 0 */ +mp_result mp_int_abs(mp_int a, mp_int c); /* c = |a| */ +mp_result mp_int_neg(mp_int a, mp_int c); /* c = -a */ +mp_result mp_int_add(mp_int a, mp_int b, mp_int c); /* c = a + b */ +mp_result mp_int_add_value(mp_int a, int value, mp_int c); +mp_result mp_int_sub(mp_int a, mp_int b, mp_int c); /* c = a - b */ +mp_result mp_int_sub_value(mp_int a, int value, mp_int c); +mp_result mp_int_mul(mp_int a, mp_int b, mp_int c); /* c = a * b */ +mp_result mp_int_mul_value(mp_int a, int value, mp_int c); +mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c); +mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */ +mp_result mp_int_div(mp_int a, mp_int b, /* q = a / b */ + mp_int q, mp_int r); /* r = a % b */ +mp_result mp_int_div_value(mp_int a, int value, /* q = a / value */ + mp_int q, int *r); /* r = a % value */ +mp_result mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */ + mp_int q, mp_int r); /* r = q % 2^p2 */ +mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); /* c = a % m */ +#define mp_int_mod_value(A, V, R) mp_int_div_value((A), (V), 0, (R)) +mp_result mp_int_expt(mp_int a, int b, mp_int c); /* c = a^b */ +mp_result mp_int_expt_value(int a, int b, mp_int c); /* c = a^b */ + +int mp_int_compare(mp_int a, mp_int b); /* a <=> b */ +int mp_int_compare_unsigned(mp_int a, mp_int b); /* |a| <=> |b| */ +int mp_int_compare_zero(mp_int z); /* a <=> 0 */ +int mp_int_compare_value(mp_int z, int value); /* a <=> v */ + +/* Returns true if v|a, false otherwise (including errors) */ +int mp_int_divisible_value(mp_int a, int v); + +/* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */ +int mp_int_is_pow2(mp_int z); + +mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, + mp_int c); /* c = a^b (mod m) */ +mp_result mp_int_exptmod_evalue(mp_int a, int value, + mp_int m, mp_int c); /* c = a^v (mod m) */ +mp_result mp_int_exptmod_bvalue(int value, mp_int b, + mp_int m, mp_int c); /* c = v^b (mod m) */ +mp_result mp_int_exptmod_known(mp_int a, mp_int b, + mp_int m, mp_int mu, + mp_int c); /* c = a^b (mod m) */ +mp_result mp_int_redux_const(mp_int m, mp_int c); + +mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); /* c = 1/a (mod m) */ + +mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c); /* c = gcd(a, b) */ + +mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */ + mp_int x, mp_int y); /* c = ax + by */ + +mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */ + +/* Convert to an int, if representable (returns MP_RANGE if not). */ +mp_result mp_int_to_int(mp_int z, int *out); + +/* Convert to nul-terminated string with the specified radix, writing at + most limit characters including the nul terminator */ +mp_result mp_int_to_string(mp_int z, mp_size radix, + char *str, int limit); + +/* Return the number of characters required to represent + z in the given radix. May over-estimate. */ +mp_result mp_int_string_len(mp_int z, mp_size radix); + +/* Read zero-terminated string into z */ +mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str); +mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, + char **end); + +/* Return the number of significant bits in z */ +mp_result mp_int_count_bits(mp_int z); + +/* Convert z to two's complement binary, writing at most limit bytes */ +mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit); + +/* Read a two's complement binary value into z from the given buffer */ +mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len); + +/* Return the number of bytes required to represent z in binary. */ +mp_result mp_int_binary_len(mp_int z); + +/* Convert z to unsigned binary, writing at most limit bytes */ +mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit); + +/* Read an unsigned binary value into z from the given buffer */ +mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len); + +/* Return the number of bytes required to represent z as unsigned output */ +mp_result mp_int_unsigned_len(mp_int z); + +/* Return a statically allocated string describing error code res */ +const char *mp_error_string(mp_result res); + +#if DEBUG +void s_print(char *tag, mp_int z); +void s_print_buf(char *tag, mp_digit *buf, mp_size num); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* end IMATH_H_ */ diff --git a/source4/heimdal/lib/des/imath/iprime.c b/source4/heimdal/lib/des/imath/iprime.c new file mode 100755 index 0000000000..582ade0f54 --- /dev/null +++ b/source4/heimdal/lib/des/imath/iprime.c @@ -0,0 +1,186 @@ +/* + Name: iprime.c + Purpose: Pseudoprimality testing routines + Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/> + Info: $Id: iprime.c,v 1.5 2007/01/05 21:01:48 lha Exp $ + + Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#include "iprime.h" +#include <stdlib.h> + +static const int s_ptab[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, + 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, + 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, + 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, + 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, + 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, + 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, + 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, + 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, + 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, + 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, + 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, + 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, + 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, + 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, + 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, + 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, + 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, + 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, + 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, + 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, + 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, + 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, + 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, + 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, + 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, + 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, + 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, + 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, + 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, + 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, + 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, + 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, + 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, + 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, + 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, + 4957, 4967, 4969, 4973, 4987, 4993, 4999 +}; +static const int s_ptab_size = sizeof(s_ptab)/sizeof(s_ptab[0]); + + +/* {{{ mp_int_is_prime(z) */ + +/* Test whether z is likely to be prime: + MP_TRUE means it is probably prime + MP_FALSE means it is definitely composite + */ +mp_result mp_int_is_prime(mp_int z) +{ + int i, rem; + mp_result res; + + /* First check for divisibility by small primes; this eliminates a + large number of composite candidates quickly + */ + for(i = 0; i < s_ptab_size; ++i) { + if((res = mp_int_div_value(z, s_ptab[i], NULL, &rem)) != MP_OK) + return res; + + if(rem == 0) + return MP_FALSE; + } + + /* Now try Fermat's test for several prime witnesses (since we now + know from the above that z is not a multiple of any of them) + */ + { + mpz_t tmp; + + if((res = mp_int_init(&tmp)) != MP_OK) return res; + + for(i = 0; i < 10 && i < s_ptab_size; ++i) { + if((res = mp_int_exptmod_bvalue(s_ptab[i], z, z, &tmp)) != MP_OK) + return res; + + if(mp_int_compare_value(&tmp, s_ptab[i]) != 0) { + mp_int_clear(&tmp); + return MP_FALSE; + } + } + + mp_int_clear(&tmp); + } + + return MP_TRUE; +} + +/* }}} */ + +/* {{{ mp_int_find_prime(z) */ + +/* Find the first apparent prime in ascending order from z */ +mp_result mp_int_find_prime(mp_int z) +{ + mp_result res; + + if(mp_int_is_even(z) && ((res = mp_int_add_value(z, 1, z)) != MP_OK)) + return res; + + while((res = mp_int_is_prime(z)) == MP_FALSE) { + if((res = mp_int_add_value(z, 2, z)) != MP_OK) + break; + + } + + return res; +} + +/* }}} */ + +/* Here there be dragons */ diff --git a/source4/heimdal/lib/des/imath/iprime.h b/source4/heimdal/lib/des/imath/iprime.h new file mode 100755 index 0000000000..cd54a73127 --- /dev/null +++ b/source4/heimdal/lib/des/imath/iprime.h @@ -0,0 +1,51 @@ +/* + Name: iprime.h + Purpose: Pseudoprimality testing routines + Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/> + Info: $Id: iprime.h,v 1.3 2006/10/21 16:32:30 lha Exp $ + + Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#ifndef IPRIME_H_ +#define IPRIME_H_ + +#include "imath.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Test whether z is likely to be prime + MP_YES means it is probably prime + MP_NO means it is definitely composite + */ +mp_result mp_int_is_prime(mp_int z); + +/* Find the first apparent prime in ascending order from z */ +mp_result mp_int_find_prime(mp_int z); + +#ifdef __cplusplus +} +#endif +#endif /* IPRIME_H_ */ diff --git a/source4/heimdal/lib/des/pkcs12.c b/source4/heimdal/lib/des/pkcs12.c new file mode 100644 index 0000000000..cc92285754 --- /dev/null +++ b/source4/heimdal/lib/des/pkcs12.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$Id: pkcs12.c,v 1.1 2006/01/13 08:26:49 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include <pkcs12.h> +#include <bn.h> + +#include <roken.h> + +int +PKCS12_key_gen(const void *key, size_t keylen, + const void *salt, size_t saltlen, + int id, int iteration, size_t outkeysize, + void *out, const EVP_MD *md) +{ + unsigned char *v, *I, hash[EVP_MAX_MD_SIZE]; + unsigned int size, size_I = 0; + unsigned char idc = id; + EVP_MD_CTX ctx; + unsigned char *outp = out; + int i, vlen; + + EVP_MD_CTX_init(&ctx); + + vlen = EVP_MD_block_size(md); + v = malloc(vlen + 1); + if (v == NULL) + return 0; + + I = calloc(1, vlen * 2); + if (I == NULL) { + free(v); + return 0; + } + + if (salt && saltlen > 0) { + for (i = 0; i < vlen; i++) + I[i] = ((unsigned char*)salt)[i % saltlen]; + size_I += vlen; + } + if (key && keylen > 0) { + for (i = 0; i < vlen / 2; i++) { + I[(i * 2) + size_I] = 0; + I[(i * 2) + size_I + 1] = ((unsigned char*)key)[i % (keylen + 1)]; + } + size_I += vlen; + } + + while (1) { + BIGNUM *bnB, *bnOne; + + if (!EVP_DigestInit_ex(&ctx, md, NULL)) + return 0; + for (i = 0; i < vlen; i++) + EVP_DigestUpdate(&ctx, &idc, 1); + EVP_DigestUpdate(&ctx, I, size_I); + EVP_DigestFinal_ex(&ctx, hash, &size); + + for (i = 1; i < iteration; i++) + EVP_Digest(hash, size, hash, &size, md, NULL); + + memcpy(outp, hash, min(outkeysize, size)); + if (outkeysize < size) + break; + outkeysize -= size; + outp += size; + + for (i = 0; i < vlen; i++) + v[i] = hash[i % size]; + + bnB = BN_bin2bn(v, vlen, NULL); + bnOne = BN_new(); + BN_set_word(bnOne, 1); + + BN_uadd(bnB, bnB, bnOne); + + for (i = 0; i < vlen * 2; i += vlen) { + BIGNUM *bnI; + int j; + + bnI = BN_bin2bn(I + i, vlen, NULL); + + BN_uadd(bnI, bnI, bnB); + + j = BN_num_bytes(bnI); + if (j > vlen) { + assert(j == vlen + 1); + BN_bn2bin(bnI, v); + memcpy(I + i, v + 1, vlen); + } else { + memset(I + i, 0, vlen - j); + BN_bn2bin(bnI, I + i + vlen - j); + } + BN_free(bnI); + } + BN_free(bnB); + BN_free(bnOne); + size_I = vlen * 2; + } + + EVP_MD_CTX_cleanup(&ctx); + free(I); + free(v); + + return 1; +} diff --git a/source4/heimdal/lib/des/resource.h b/source4/heimdal/lib/des/resource.h new file mode 100644 index 0000000000..02c6a7c6d9 --- /dev/null +++ b/source4/heimdal/lib/des/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by passwd_dialog.rc +// +#define IDD_PASSWD_DIALOG 101 +#define IDC_EDIT1 1000 +#define IDC_PASSWD_EDIT 1001 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1002 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/source4/heimdal/lib/des/rsa-imath.c b/source4/heimdal/lib/des/rsa-imath.c new file mode 100644 index 0000000000..298affadfe --- /dev/null +++ b/source4/heimdal/lib/des/rsa-imath.c @@ -0,0 +1,661 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$Id: rsa-imath.c,v 1.23 2007/01/06 13:45:25 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <krb5-types.h> +#include <assert.h> + +#include <rsa.h> + +#include <roken.h> + +#include "imath/imath.h" +#include "imath/iprime.h" + +static void +BN2mpz(mpz_t *s, const BIGNUM *bn) +{ + size_t len; + void *p; + + mp_int_init(s); + + len = BN_num_bytes(bn); + p = malloc(len); + BN_bn2bin(bn, p); + mp_int_read_unsigned(s, p, len); + free(p); +} + +static BIGNUM * +mpz2BN(mpz_t *s) +{ + size_t size; + BIGNUM *bn; + void *p; + + size = mp_int_unsigned_len(s); + p = malloc(size); + if (p == NULL && size != 0) + return NULL; + mp_int_to_unsigned(s, p, size); + + bn = BN_bin2bn(p, size, NULL); + free(p); + return bn; +} + +static int random_num(mp_int, size_t); + +static void +setup_blind(mp_int n, mp_int b, mp_int bi) +{ + mp_int_init(b); + mp_int_init(bi); + random_num(b, mp_int_count_bits(n)); + mp_int_mod(b, n, b); + mp_int_invmod(b, n, bi); +} + +static void +blind(mp_int in, mp_int b, mp_int e, mp_int n) +{ + mpz_t t1; + mp_int_init(&t1); + /* in' = (in * b^e) mod n */ + mp_int_exptmod(b, e, n, &t1); + mp_int_mul(&t1, in, in); + mp_int_mod(in, n, in); + mp_int_clear(&t1); +} + +static void +unblind(mp_int out, mp_int bi, mp_int n) +{ + /* out' = (out * 1/b) mod n */ + mp_int_mul(out, bi, out); + mp_int_mod(out, n, out); +} + +static mp_result +rsa_private_calculate(mp_int in, mp_int p, mp_int q, + mp_int dmp1, mp_int dmq1, mp_int iqmp, + mp_int out) +{ + mpz_t vp, vq, u; + mp_int_init(&vp); mp_int_init(&vq); mp_int_init(&u); + + /* vq = c ^ (d mod (q - 1)) mod q */ + /* vp = c ^ (d mod (p - 1)) mod p */ + mp_int_mod(in, p, &u); + mp_int_exptmod(&u, dmp1, p, &vp); + mp_int_mod(in, q, &u); + mp_int_exptmod(&u, dmq1, q, &vq); + + /* C2 = 1/q mod p (iqmp) */ + /* u = (vp - vq)C2 mod p. */ + mp_int_sub(&vp, &vq, &u); + if (mp_int_compare_zero(&u) < 0) + mp_int_add(&u, p, &u); + mp_int_mul(&u, iqmp, &u); + mp_int_mod(&u, p, &u); + + /* c ^ d mod n = vq + u q */ + mp_int_mul(&u, q, &u); + mp_int_add(&u, &vq, out); + + mp_int_clear(&vp); + mp_int_clear(&vq); + mp_int_clear(&u); + + return MP_OK; +} + +/* + * + */ + +static int +imath_rsa_public_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + mp_result res; + size_t size, padlen; + mpz_t enc, dec, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + p = p0 = malloc(size - 1); + if (p0 == NULL) { + mp_int_clear(&e); + mp_int_clear(&n); + return -3; + } + + padlen = size - flen - 3; + assert(padlen >= 8); + + *p++ = 2; + if (RAND_bytes(p, padlen) != 1) { + mp_int_clear(&e); + mp_int_clear(&n); + free(p0); + return -4; + } + while(padlen) { + if (*p == 0) + *p = 1; + padlen--; + p++; + } + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size - 1); + + mp_int_init(&enc); + mp_int_init(&dec); + mp_int_read_unsigned(&dec, p0, size - 1); + free(p0); + + res = mp_int_exptmod(&dec, &e, &n, &enc); + + mp_int_clear(&dec); + mp_int_clear(&e); + mp_int_clear(&n); + { + size_t ssize; + ssize = mp_int_unsigned_len(&enc); + assert(size >= ssize); + mp_int_to_unsigned(&enc, to, ssize); + size = ssize; + } + mp_int_clear(&enc); + + return size; +} + +static int +imath_rsa_public_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p; + mp_result res; + size_t size; + mpz_t s, us, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + if (flen > RSA_size(rsa)) + return -2; + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + +#if 0 + /* Check that the exponent is larger then 3 */ + if (mp_int_compare_value(&e, 3) <= 0) { + mp_int_clear(&n); + mp_int_clear(&e); + return -3; + } +#endif + + mp_int_init(&s); + mp_int_init(&us); + mp_int_read_unsigned(&s, rk_UNCONST(from), flen); + + if (mp_int_compare(&s, &n) >= 0) { + mp_int_clear(&n); + mp_int_clear(&e); + return -4; + } + + res = mp_int_exptmod(&s, &e, &n, &us); + + mp_int_clear(&s); + mp_int_clear(&n); + mp_int_clear(&e); + + if (res != MP_OK) + return -5; + p = to; + + + size = mp_int_unsigned_len(&us); + assert(size <= RSA_size(rsa)); + mp_int_to_unsigned(&us, p, size); + + mp_int_clear(&us); + + /* head zero was skipped by mp_int_to_unsigned */ + if (*p == 0) + return -6; + if (*p != 1) + return -7; + size--; p++; + while (size && *p == 0xff) { + size--; p++; + } + if (size == 0 || *p != 0) + return -8; + size--; p++; + + memmove(to, p, size); + + return size; +} + +static int +imath_rsa_private_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + mp_result res; + size_t size; + mpz_t in, out, n, e, b, bi; + int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + p0 = p = malloc(size); + *p++ = 0; + *p++ = 1; + memset(p, 0xff, size - flen - 3); + p += size - flen - 3; + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size); + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + mp_int_init(&in); + mp_int_init(&out); + mp_int_read_unsigned(&in, p0, size); + free(p0); + + if(mp_int_compare_zero(&in) < 0 || + mp_int_compare(&in, &n) >= 0) { + size = 0; + goto out; + } + + if (blinding) { + setup_blind(&n, &b, &bi); + blind(&in, &b, &e, &n); + } + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + mpz_t p, q, dmp1, dmq1, iqmp; + + BN2mpz(&p, rsa->p); + BN2mpz(&q, rsa->q); + BN2mpz(&dmp1, rsa->dmp1); + BN2mpz(&dmq1, rsa->dmq1); + BN2mpz(&iqmp, rsa->iqmp); + + res = rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); + + mp_int_clear(&p); + mp_int_clear(&q); + mp_int_clear(&dmp1); + mp_int_clear(&dmq1); + mp_int_clear(&iqmp); + } else { + mpz_t d; + + BN2mpz(&d, rsa->d); + res = mp_int_exptmod(&in, &d, &n, &out); + mp_int_clear(&d); + if (res != MP_OK) { + size = 0; + goto out; + } + } + + if (blinding) { + unblind(&out, &bi, &n); + mp_int_clear(&b); + mp_int_clear(&bi); + } + + { + size_t ssize; + ssize = mp_int_unsigned_len(&out); + assert(size >= ssize); + mp_int_to_unsigned(&out, to, size); + size = ssize; + } + +out: + mp_int_clear(&e); + mp_int_clear(&n); + mp_int_clear(&in); + mp_int_clear(&out); + + return size; +} + +static int +imath_rsa_private_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *ptr; + mp_result res; + size_t size; + mpz_t in, out, n, e, b, bi; + int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + if (flen > size) + return -2; + + mp_int_init(&in); + mp_int_init(&out); + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + res = mp_int_read_unsigned(&in, rk_UNCONST(from), flen); + if (res != MP_OK) { + size = -1; + goto out; + } + + if(mp_int_compare_zero(&in) < 0 || + mp_int_compare(&in, &n) >= 0) { + size = 0; + goto out; + } + + if (blinding) { + setup_blind(&n, &b, &bi); + blind(&in, &b, &e, &n); + } + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + mpz_t p, q, dmp1, dmq1, iqmp; + + BN2mpz(&p, rsa->p); + BN2mpz(&q, rsa->q); + BN2mpz(&dmp1, rsa->dmp1); + BN2mpz(&dmq1, rsa->dmq1); + BN2mpz(&iqmp, rsa->iqmp); + + res = rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); + + mp_int_clear(&p); + mp_int_clear(&q); + mp_int_clear(&dmp1); + mp_int_clear(&dmq1); + mp_int_clear(&iqmp); + } else { + mpz_t d; + + if(mp_int_compare_zero(&in) < 0 || + mp_int_compare(&in, &n) >= 0) + return MP_RANGE; + + BN2mpz(&d, rsa->d); + res = mp_int_exptmod(&in, &d, &n, &out); + mp_int_clear(&d); + if (res != MP_OK) { + size = 0; + goto out; + } + } + + if (blinding) { + unblind(&out, &bi, &n); + mp_int_clear(&b); + mp_int_clear(&bi); + } + + ptr = to; + { + size_t ssize; + ssize = mp_int_unsigned_len(&out); + assert(size >= ssize); + mp_int_to_unsigned(&out, ptr, ssize); + size = ssize; + } + + /* head zero was skipped by mp_int_to_unsigned */ + if (*ptr != 2) + return -3; + size--; ptr++; + while (size && *ptr != 0) { + size--; ptr++; + } + if (size == 0) + return -4; + size--; ptr++; + + memmove(to, ptr, size); + +out: + mp_int_clear(&e); + mp_int_clear(&n); + mp_int_clear(&in); + mp_int_clear(&out); + + return size; +} + +static int +random_num(mp_int num, size_t len) +{ + unsigned char *p; + mp_result res; + + len = (len + 7) / 8; + p = malloc(len); + if (p == NULL) + return 1; + if (RAND_bytes(p, len) != 1) { + free(p); + return 1; + } + res = mp_int_read_unsigned(num, p, len); + free(p); + if (res != MP_OK) + return 1; + return 0; +} + +#define CHECK(f, v) if ((f) != (v)) { goto out; } + +static int +imath_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) +{ + mpz_t el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; + int counter, ret; + + if (bits < 789) + return -1; + + ret = -1; + + mp_int_init(&el); + mp_int_init(&p); + mp_int_init(&q); + mp_int_init(&n); + mp_int_init(&d); + mp_int_init(&dmp1); + mp_int_init(&dmq1); + mp_int_init(&iqmp); + mp_int_init(&t1); + mp_int_init(&t2); + mp_int_init(&t3); + + BN2mpz(&el, e); + + /* generate p and q so that p != q and bits(pq) ~ bits */ + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + CHECK(random_num(&p, bits / 2 + 1), 0); + CHECK(mp_int_find_prime(&p), MP_TRUE); + + CHECK(mp_int_sub_value(&p, 1, &t1), MP_OK); + CHECK(mp_int_gcd(&t1, &el, &t2), MP_OK); + } while(mp_int_compare_value(&t2, 1) != 0); + + BN_GENCB_call(cb, 3, 0); + + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + CHECK(random_num(&q, bits / 2 + 1), 0); + CHECK(mp_int_find_prime(&q), MP_TRUE); + + if (mp_int_compare(&p, &q) == 0) /* don't let p and q be the same */ + continue; + + CHECK(mp_int_sub_value(&q, 1, &t1), MP_OK); + CHECK(mp_int_gcd(&t1, &el, &t2), MP_OK); + } while(mp_int_compare_value(&t2, 1) != 0); + + /* make p > q */ + if (mp_int_compare(&p, &q) < 0) + mp_int_swap(&p, &q); + + BN_GENCB_call(cb, 3, 1); + + /* calculate n, n = p * q */ + CHECK(mp_int_mul(&p, &q, &n), MP_OK); + + /* calculate d, d = 1/e mod (p - 1)(q - 1) */ + CHECK(mp_int_sub_value(&p, 1, &t1), MP_OK); + CHECK(mp_int_sub_value(&q, 1, &t2), MP_OK); + CHECK(mp_int_mul(&t1, &t2, &t3), MP_OK); + CHECK(mp_int_invmod(&el, &t3, &d), MP_OK); + + /* calculate dmp1 dmp1 = d mod (p-1) */ + CHECK(mp_int_mod(&d, &t1, &dmp1), MP_OK); + /* calculate dmq1 dmq1 = d mod (q-1) */ + CHECK(mp_int_mod(&d, &t2, &dmq1), MP_OK); + /* calculate iqmp iqmp = 1/q mod p */ + CHECK(mp_int_invmod(&q, &p, &iqmp), MP_OK); + + /* fill in RSA key */ + + rsa->e = mpz2BN(&el); + rsa->p = mpz2BN(&p); + rsa->q = mpz2BN(&q); + rsa->n = mpz2BN(&n); + rsa->d = mpz2BN(&d); + rsa->dmp1 = mpz2BN(&dmp1); + rsa->dmq1 = mpz2BN(&dmq1); + rsa->iqmp = mpz2BN(&iqmp); + + ret = 1; +out: + mp_int_clear(&el); + mp_int_clear(&p); + mp_int_clear(&q); + mp_int_clear(&n); + mp_int_clear(&d); + mp_int_clear(&dmp1); + mp_int_clear(&dmq1); + mp_int_clear(&iqmp); + mp_int_clear(&t1); + mp_int_clear(&t2); + mp_int_clear(&t3); + + return ret; +} + +static int +imath_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +imath_rsa_finish(RSA *rsa) +{ + return 1; +} + +const RSA_METHOD hc_rsa_imath_method = { + "hcrypto imath RSA", + imath_rsa_public_encrypt, + imath_rsa_public_decrypt, + imath_rsa_private_encrypt, + imath_rsa_private_decrypt, + NULL, + NULL, + imath_rsa_init, + imath_rsa_finish, + 0, + NULL, + NULL, + NULL, + imath_rsa_generate_key +}; + +const RSA_METHOD * +RSA_imath_method(void) +{ + return &hc_rsa_imath_method; +} diff --git a/source4/heimdal/lib/des/rsa.c b/source4/heimdal/lib/des/rsa.c new file mode 100644 index 0000000000..241afb2e46 --- /dev/null +++ b/source4/heimdal/lib/des/rsa.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$Id: rsa.c,v 1.19 2007/01/09 10:04:20 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <krb5-types.h> +#include <rfc2459_asn1.h> + +#include <rsa.h> + +#include <roken.h> + +RSA * +RSA_new(void) +{ + return RSA_new_method(NULL); +} + +RSA * +RSA_new_method(ENGINE *engine) +{ + RSA *rsa; + + rsa = calloc(1, sizeof(*rsa)); + if (rsa == NULL) + return NULL; + + rsa->references = 1; + + if (engine) { + ENGINE_up_ref(engine); + rsa->engine = engine; + } else { + rsa->engine = ENGINE_get_default_RSA(); + } + + if (rsa->engine) { + rsa->meth = ENGINE_get_RSA(rsa->engine); + if (rsa->meth == NULL) { + ENGINE_finish(engine); + free(rsa); + return 0; + } + } + + if (rsa->meth == NULL) + rsa->meth = rk_UNCONST(RSA_get_default_method()); + + (*rsa->meth->init)(rsa); + + return rsa; +} + + +void +RSA_free(RSA *rsa) +{ + if (rsa->references <= 0) + abort(); + + if (--rsa->references > 0) + return; + + (*rsa->meth->finish)(rsa); + + if (rsa->engine) + ENGINE_finish(rsa->engine); + +#define free_if(f) if (f) { BN_free(f); } + free_if(rsa->n); + free_if(rsa->e); + free_if(rsa->d); + free_if(rsa->p); + free_if(rsa->q); + free_if(rsa->dmp1); + free_if(rsa->dmq1); +#undef free_if + + memset(rsa, 0, sizeof(*rsa)); + free(rsa); +} + +int +RSA_up_ref(RSA *rsa) +{ + return ++rsa->references; +} + +const RSA_METHOD * +RSA_get_method(const RSA *rsa) +{ + return rsa->meth; +} + +int +RSA_set_method(RSA *rsa, const RSA_METHOD *method) +{ + (*rsa->meth->finish)(rsa); + + if (rsa->engine) { + ENGINE_finish(rsa->engine); + rsa->engine = NULL; + } + + rsa->meth = method; + (*rsa->meth->init)(rsa); + return 1; +} + +int +RSA_set_app_data(RSA *rsa, void *arg) +{ + rsa->ex_data.sk = arg; + return 1; +} + +void * +RSA_get_app_data(RSA *rsa) +{ + return rsa->ex_data.sk; +} + +int +RSA_check_key(const RSA *key) +{ + static const unsigned char inbuf[] = "hello, world!"; + RSA *rsa = rk_UNCONST(key); + void *buffer; + int ret; + + /* + * XXX I have no clue how to implement this w/o a bignum library. + * Well, when we have a RSA key pair, we can try to encrypt/sign + * and then decrypt/verify. + */ + + if ((rsa->d == NULL || rsa->n == NULL) && + (rsa->p == NULL || rsa->q || rsa->dmp1 == NULL || rsa->dmq1 == NULL || rsa->iqmp == NULL)) + return 0; + + buffer = malloc(RSA_size(rsa)); + if (buffer == NULL) + return 0; + + ret = RSA_private_encrypt(sizeof(inbuf), inbuf, buffer, + rsa, RSA_PKCS1_PADDING); + if (ret == -1) { + free(buffer); + return 0; + } + + ret = RSA_public_decrypt(ret, buffer, buffer, + rsa, RSA_PKCS1_PADDING); + if (ret == -1) { + free(buffer); + return 0; + } + + if (ret == sizeof(inbuf) && memcmp(buffer, inbuf, sizeof(inbuf)) == 0) { + free(buffer); + return 1; + } + free(buffer); + return 0; +} + +int +RSA_size(const RSA *rsa) +{ + return BN_num_bytes(rsa->n); +} + +#define RSAFUNC(name, body) \ +int \ +name(int flen,const unsigned char* f, unsigned char* t, RSA* r, int p){\ + return body; \ +} + +RSAFUNC(RSA_public_encrypt, (r)->meth->rsa_pub_enc(flen, f, t, r, p)) +RSAFUNC(RSA_public_decrypt, (r)->meth->rsa_pub_dec(flen, f, t, r, p)) +RSAFUNC(RSA_private_encrypt, (r)->meth->rsa_priv_enc(flen, f, t, r, p)) +RSAFUNC(RSA_private_decrypt, (r)->meth->rsa_priv_dec(flen, f, t, r, p)) + +/* XXX */ +int +RSA_sign(int type, const unsigned char *from, unsigned int flen, + unsigned char *to, unsigned int *tlen, RSA *rsa) +{ + return -1; +} + +int +RSA_verify(int type, const unsigned char *from, unsigned int flen, + unsigned char *to, unsigned int tlen, RSA *rsa) +{ + return -1; +} + +/* + * A NULL RSA_METHOD that returns failure for all operations. This is + * used as the default RSA method is we don't have any native + * support. + */ + +static RSAFUNC(null_rsa_public_encrypt, -1) +static RSAFUNC(null_rsa_public_decrypt, -1) +static RSAFUNC(null_rsa_private_encrypt, -1) +static RSAFUNC(null_rsa_private_decrypt, -1) + +/* + * + */ + +int +RSA_generate_key_ex(RSA *r, int bits, BIGNUM *e, BN_GENCB *cb) +{ + if (r->meth->rsa_keygen) + return (*r->meth->rsa_keygen)(r, bits, e, cb); + return 0; +} + + +/* + * + */ + +static int +null_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +null_rsa_finish(RSA *rsa) +{ + return 1; +} + +static const RSA_METHOD rsa_null_method = { + "hcrypto null RSA", + null_rsa_public_encrypt, + null_rsa_public_decrypt, + null_rsa_private_encrypt, + null_rsa_private_decrypt, + NULL, + NULL, + null_rsa_init, + null_rsa_finish, + 0, + NULL, + NULL, + NULL +}; + +const RSA_METHOD * +RSA_null_method(void) +{ + return &rsa_null_method; +} + +extern const RSA_METHOD hc_rsa_imath_method; +static const RSA_METHOD *default_rsa_method = &hc_rsa_imath_method; + +const RSA_METHOD * +RSA_get_default_method(void) +{ + return default_rsa_method; +} + +void +RSA_set_default_method(const RSA_METHOD *meth) +{ + default_rsa_method = meth; +} + +/* + * + */ + +static BIGNUM * +heim_int2BN(const heim_integer *i) +{ + BIGNUM *bn; + + bn = BN_bin2bn(i->data, i->length, NULL); + if (bn) + BN_set_negative(bn, i->negative); + return bn; +} + +static int +bn2heim_int(BIGNUM *bn, heim_integer *integer) +{ + integer->length = BN_num_bytes(bn); + integer->data = malloc(integer->length); + if (integer->data == NULL) { + integer->length = 0; + return ENOMEM; + } + BN_bn2bin(bn, integer->data); + integer->negative = BN_is_negative(bn); + return 0; +} + + +RSA * +d2i_RSAPrivateKey(RSA *rsa, const unsigned char **pp, size_t len) +{ + RSAPrivateKey data; + RSA *k = rsa; + size_t size; + int ret; + + ret = decode_RSAPrivateKey(*pp, len, &data, &size); + if (ret) + return NULL; + + *pp += size; + + if (k == NULL) { + k = RSA_new(); + if (k == NULL) { + free_RSAPrivateKey(&data); + return NULL; + } + } + + k->n = heim_int2BN(&data.modulus); + k->e = heim_int2BN(&data.publicExponent); + k->d = heim_int2BN(&data.privateExponent); + k->p = heim_int2BN(&data.prime1); + k->q = heim_int2BN(&data.prime2); + k->dmp1 = heim_int2BN(&data.exponent1); + k->dmq1 = heim_int2BN(&data.exponent2); + k->iqmp = heim_int2BN(&data.coefficient); + free_RSAPrivateKey(&data); + + if (k->n == NULL || k->e == NULL || k->d == NULL || k->p == NULL || + k->q == NULL || k->dmp1 == NULL || k->dmq1 == NULL || k->iqmp == NULL) + { + RSA_free(k); + return NULL; + } + + return k; +} + +int +i2d_RSAPrivateKey(RSA *rsa, unsigned char **pp) +{ + RSAPrivateKey data; + size_t size; + int ret; + + if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL || rsa->p == NULL || + rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 == NULL || + rsa->iqmp == NULL) + return -1; + + memset(&data, 0, sizeof(data)); + + ret = bn2heim_int(rsa->n, &data.modulus); + ret |= bn2heim_int(rsa->e, &data.publicExponent); + ret |= bn2heim_int(rsa->d, &data.privateExponent); + ret |= bn2heim_int(rsa->p, &data.prime1); + ret |= bn2heim_int(rsa->q, &data.prime2); + ret |= bn2heim_int(rsa->dmp1, &data.exponent1); + ret |= bn2heim_int(rsa->dmq1, &data.exponent2); + ret |= bn2heim_int(rsa->iqmp, &data.coefficient); + if (ret) { + free_RSAPrivateKey(&data); + return -1; + } + + if (pp == NULL) { + size = length_RSAPrivateKey(&data); + free_RSAPrivateKey(&data); + } else { + void *p; + size_t len; + + ASN1_MALLOC_ENCODE(RSAPrivateKey, p, len, &data, &size, ret); + free_RSAPrivateKey(&data); + if (ret) + return -1; + if (len != size) + abort(); + + memcpy(*pp, p, size); + free(p); + + *pp += size; + + } + return size; +} + +int +i2d_RSAPublicKey(RSA *rsa, unsigned char **pp) +{ + RSAPublicKey data; + size_t size; + int ret; + + memset(&data, 0, sizeof(data)); + + if (bn2heim_int(rsa->n, &data.modulus) || + bn2heim_int(rsa->e, &data.publicExponent)) + { + free_RSAPublicKey(&data); + return -1; + } + + if (pp == NULL) { + size = length_RSAPublicKey(&data); + free_RSAPublicKey(&data); + } else { + void *p; + size_t len; + + ASN1_MALLOC_ENCODE(RSAPublicKey, p, len, &data, &size, ret); + free_RSAPublicKey(&data); + if (ret) + return -1; + if (len != size) + abort(); + + memcpy(*pp, p, size); + free(p); + + *pp += size; + } + + return size; +} diff --git a/source4/heimdal/lib/des/rsa.h b/source4/heimdal/lib/des/rsa.h index 137dd9894b..0aceb9f9da 100644 --- a/source4/heimdal/lib/des/rsa.h +++ b/source4/heimdal/lib/des/rsa.h @@ -32,7 +32,7 @@ */ /* - * $Id: rsa.h,v 1.5 2006/05/07 11:34:02 lha Exp $ + * $Id: rsa.h,v 1.9 2007/01/05 20:26:23 lha Exp $ */ #ifndef _HEIM_RSA_H @@ -59,7 +59,9 @@ #define RSA_private_decrypt hc_RSA_private_decrypt #define RSA_sign hc_RSA_sign #define RSA_verify hc_RSA_verify +#define RSA_generate_key_ex hc_RSA_generate_key_ex #define d2i_RSAPrivateKey hc_d2i_RSAPrivateKey +#define i2d_RSAPrivateKey hc_i2d_RSAPrivateKey #define i2d_RSAPublicKey hc_i2d_RSAPublicKey /* @@ -119,9 +121,10 @@ struct RSA { void *mt_blinding; }; -#define RSA_FLAG_SIGN_VER 0x40 +#define RSA_FLAG_NO_BLINDING 0x0080 #define RSA_PKCS1_PADDING 1 +#define RSA_PKCS1_OAEP_PADDING 4 #define RSA_PKCS1_PADDING_SIZE 11 /* @@ -162,7 +165,11 @@ int RSA_sign(int, const unsigned char *, unsigned int, int RSA_verify(int, const unsigned char *, unsigned int, unsigned char *, unsigned int, RSA *); +int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *); + RSA * d2i_RSAPrivateKey(RSA *, const unsigned char **, size_t); +int i2d_RSAPrivateKey(RSA *, unsigned char **); + int i2d_RSAPublicKey(RSA *, unsigned char **); #endif /* _HEIM_RSA_H */ diff --git a/source4/heimdal/lib/gssapi/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi/gssapi.h index f89e5dfbee..8077aeb223 100644 --- a/source4/heimdal/lib/gssapi/gssapi/gssapi.h +++ b/source4/heimdal/lib/gssapi/gssapi/gssapi.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: gssapi.h,v 1.6 2006/11/10 00:39:50 lha Exp $ */ +/* $Id: gssapi.h,v 1.7 2006/12/15 20:02:54 lha Exp $ */ #ifndef GSSAPI_GSSAPI_H_ #define GSSAPI_GSSAPI_H_ @@ -300,6 +300,12 @@ extern gss_OID GSS_C_NT_EXPORT_NAME; extern gss_OID GSS_SASL_DIGEST_MD5_MECHANISM; +/* + * NTLM mechanism + */ + +extern gss_OID GSS_NTLM_MECHANISM; + /* Major status codes */ #define GSS_S_COMPLETE 0 diff --git a/source4/heimdal/lib/gssapi/gssapi_mech.h b/source4/heimdal/lib/gssapi/gssapi_mech.h index a05919b510..2bb5ecedf5 100644 --- a/source4/heimdal/lib/gssapi/gssapi_mech.h +++ b/source4/heimdal/lib/gssapi/gssapi_mech.h @@ -344,5 +344,6 @@ __gss_get_mechanism(gss_OID /* oid */); gssapi_mech_interface __gss_spnego_initialize(void); gssapi_mech_interface __gss_krb5_initialize(void); +gssapi_mech_interface __gss_ntlm_initialize(void); #endif /* GSSAPI_MECH_H */ diff --git a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c index 6ac80461c3..434fbee352 100644 --- a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: accept_sec_context.c,v 1.65 2006/11/07 14:52:05 lha Exp $"); +RCSID("$Id: accept_sec_context.c,v 1.66 2006/11/13 18:00:54 lha Exp $"); HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; krb5_keytab _gsskrb5_keytab; @@ -41,20 +41,21 @@ krb5_keytab _gsskrb5_keytab; OM_uint32 _gsskrb5_register_acceptor_identity (const char *identity) { + krb5_context context; krb5_error_code ret; - ret = _gsskrb5_init(); + ret = _gsskrb5_init(&context); if(ret) return GSS_S_FAILURE; HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); if(_gsskrb5_keytab != NULL) { - krb5_kt_close(_gsskrb5_context, _gsskrb5_keytab); + krb5_kt_close(context, _gsskrb5_keytab); _gsskrb5_keytab = NULL; } if (identity == NULL) { - ret = krb5_kt_default(_gsskrb5_context, &_gsskrb5_keytab); + ret = krb5_kt_default(context, &_gsskrb5_keytab); } else { char *p; @@ -63,7 +64,7 @@ _gsskrb5_register_acceptor_identity (const char *identity) HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); return GSS_S_FAILURE; } - ret = krb5_kt_resolve(_gsskrb5_context, p, &_gsskrb5_keytab); + ret = krb5_kt_resolve(context, p, &_gsskrb5_keytab); free(p); } HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); @@ -120,6 +121,7 @@ static OM_uint32 gsskrb5_accept_delegated_token (OM_uint32 * minor_status, gsskrb5_ctx ctx, + krb5_context context, gss_cred_id_t * delegated_cred_handle ) { @@ -131,33 +133,31 @@ gsskrb5_accept_delegated_token /* XXX Create a new delegated_cred_handle? */ if (delegated_cred_handle == NULL) { - kret = krb5_cc_default (_gsskrb5_context, &ccache); + kret = krb5_cc_default (context, &ccache); } else { *delegated_cred_handle = NULL; - kret = krb5_cc_gen_new (_gsskrb5_context, &krb5_mcc_ops, &ccache); + kret = krb5_cc_gen_new (context, &krb5_mcc_ops, &ccache); } if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; goto out; } - kret = krb5_cc_initialize(_gsskrb5_context, ccache, ctx->source); + kret = krb5_cc_initialize(context, ccache, ctx->source); if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; goto out; } - krb5_auth_con_removeflags(_gsskrb5_context, + krb5_auth_con_removeflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_TIME, &ac_flags); - kret = krb5_rd_cred2(_gsskrb5_context, + kret = krb5_rd_cred2(context, ctx->auth_context, ccache, &ctx->fwd_data); - if (kret) - _gsskrb5_set_error_string(); - krb5_auth_con_setflags(_gsskrb5_context, + krb5_auth_con_setflags(context, ctx->auth_context, ac_flags); if (kret) { @@ -181,16 +181,16 @@ gsskrb5_accept_delegated_token handle = (gsskrb5_cred) *delegated_cred_handle; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; - krb5_cc_close(_gsskrb5_context, ccache); + krb5_cc_close(context, ccache); ccache = NULL; } out: if (ccache) { if (delegated_cred_handle == NULL) - krb5_cc_close(_gsskrb5_context, ccache); + krb5_cc_close(context, ccache); else - krb5_cc_destroy(_gsskrb5_context, ccache); + krb5_cc_destroy(context, ccache); } return ret; } @@ -198,13 +198,14 @@ out: static OM_uint32 gsskrb5_acceptor_ready(OM_uint32 * minor_status, gsskrb5_ctx ctx, + krb5_context context, gss_cred_id_t *delegated_cred_handle) { OM_uint32 ret; int32_t seq_number; int is_cfx = 0; - krb5_auth_getremoteseqnumber (_gsskrb5_context, + krb5_auth_getremoteseqnumber (context, ctx->auth_context, &seq_number); @@ -222,7 +223,7 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status, * isn't a mutual authentication context */ if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) { - krb5_auth_con_setlocalseqnumber(_gsskrb5_context, + krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, seq_number); } @@ -233,6 +234,7 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status, if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) { ret = gsskrb5_accept_delegated_token(minor_status, ctx, + context, delegated_cred_handle); if (ret) return ret; @@ -250,6 +252,7 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status, static OM_uint32 gsskrb5_acceptor_start(OM_uint32 * minor_status, gsskrb5_ctx ctx, + krb5_context context, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, @@ -301,49 +304,46 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, krb5_rd_req_in_ctx in = NULL; krb5_rd_req_out_ctx out = NULL; - kret = krb5_rd_req_in_ctx_alloc(_gsskrb5_context, &in); + kret = krb5_rd_req_in_ctx_alloc(context, &in); if (kret == 0) - kret = krb5_rd_req_in_set_keytab(_gsskrb5_context, in, keytab); + kret = krb5_rd_req_in_set_keytab(context, in, keytab); if (kret) { if (in) - krb5_rd_req_in_ctx_free(_gsskrb5_context, in); + krb5_rd_req_in_ctx_free(context, in); ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } - kret = krb5_rd_req_ctx(_gsskrb5_context, + kret = krb5_rd_req_ctx(context, &ctx->auth_context, &indata, (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred->principal, in, &out); - krb5_rd_req_in_ctx_free(_gsskrb5_context, in); + krb5_rd_req_in_ctx_free(context, in); if (kret) { ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } /* * We need to remember some data on the context_handle. */ - kret = krb5_rd_req_out_get_ap_req_options(_gsskrb5_context, out, + kret = krb5_rd_req_out_get_ap_req_options(context, out, &ap_options); if (kret == 0) - kret = krb5_rd_req_out_get_ticket(_gsskrb5_context, out, + kret = krb5_rd_req_out_get_ticket(context, out, &ctx->ticket); if (kret == 0) - kret = krb5_rd_req_out_get_keyblock(_gsskrb5_context, out, + kret = krb5_rd_req_out_get_keyblock(context, out, &ctx->service_keyblock); ctx->lifetime = ctx->ticket->ticket.endtime; - krb5_rd_req_out_ctx_free(_gsskrb5_context, out); + krb5_rd_req_out_ctx_free(context, out); if (kret) { ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } } @@ -353,22 +353,20 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, * We need to copy the principal names to the context and the * calling layer. */ - kret = krb5_copy_principal(_gsskrb5_context, + kret = krb5_copy_principal(context, ctx->ticket->client, &ctx->source); if (kret) { ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); } - kret = krb5_copy_principal(_gsskrb5_context, + kret = krb5_copy_principal(context, ctx->ticket->server, &ctx->target); if (kret) { ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } @@ -376,18 +374,17 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, * We need to setup some compat stuff, this assumes that * context_handle->target is already set. */ - ret = _gss_DES3_get_mic_compat(minor_status, ctx); + ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); if (ret) return ret; if (src_name != NULL) { - kret = krb5_copy_principal (_gsskrb5_context, + kret = krb5_copy_principal (context, ctx->ticket->client, (gsskrb5_name*)src_name); if (kret) { ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } } @@ -398,13 +395,12 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, { krb5_authenticator authenticator; - kret = krb5_auth_con_getauthenticator(_gsskrb5_context, + kret = krb5_auth_con_getauthenticator(context, ctx->auth_context, &authenticator); if(kret) { ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } @@ -415,22 +411,21 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, &ctx->flags, &ctx->fwd_data); - krb5_free_authenticator(_gsskrb5_context, &authenticator); + krb5_free_authenticator(context, &authenticator); if (ret) { return ret; } } else { krb5_crypto crypto; - kret = krb5_crypto_init(_gsskrb5_context, + kret = krb5_crypto_init(context, ctx->auth_context->keyblock, 0, &crypto); if(kret) { - krb5_free_authenticator(_gsskrb5_context, &authenticator); + krb5_free_authenticator(context, &authenticator); ret = GSS_S_FAILURE; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } @@ -439,16 +434,15 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, * GSSAPI checksum here */ - kret = krb5_verify_checksum(_gsskrb5_context, + kret = krb5_verify_checksum(context, crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, authenticator->cksum); - krb5_free_authenticator(_gsskrb5_context, &authenticator); - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_free_authenticator(context, &authenticator); + krb5_crypto_destroy(context, crypto); if(kret) { ret = GSS_S_BAD_SIG; *minor_status = kret; - _gsskrb5_set_error_string (); return ret; } @@ -467,23 +461,22 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, if (is_cfx != 0 || (ap_options & AP_OPTS_USE_SUBKEY)) { - kret = krb5_auth_con_addflags(_gsskrb5_context, + kret = krb5_auth_con_addflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_USE_SUBKEY, NULL); ctx->more_flags |= ACCEPTOR_SUBKEY; } - kret = krb5_mk_rep(_gsskrb5_context, + kret = krb5_mk_rep(context, ctx->auth_context, &outbuf); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } - if (ctx->flags & GSS_C_DCE_STYLE) { + if (IS_DCE_STYLE(ctx)) { output_token->length = outbuf.length; output_token->value = outbuf.data; } else { @@ -510,6 +503,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, if (time_rec) { ret = _gsskrb5_lifetime_left(minor_status, + context, ctx->lifetime, time_rec); if (ret) { @@ -521,7 +515,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from * the client. */ - if (ctx->flags & GSS_C_DCE_STYLE) { + if (IS_DCE_STYLE(ctx)) { /* * Return flags to caller, but we haven't processed * delgations yet @@ -533,7 +527,8 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, return GSS_S_CONTINUE_NEEDED; } - ret = gsskrb5_acceptor_ready(minor_status, ctx, delegated_cred_handle); + ret = gsskrb5_acceptor_ready(minor_status, ctx, context, + delegated_cred_handle); if (ret_flags) *ret_flags = ctx->flags; @@ -544,6 +539,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, static OM_uint32 acceptor_wait_for_dcestyle(OM_uint32 * minor_status, gsskrb5_ctx ctx, + krb5_context context, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, @@ -572,29 +568,26 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, * the remote seq_number to the old value */ { - kret = krb5_auth_con_getlocalseqnumber(_gsskrb5_context, + kret = krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &l_seq_number); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } - kret = krb5_auth_getremoteseqnumber(_gsskrb5_context, + kret = krb5_auth_getremoteseqnumber(context, ctx->auth_context, &r_seq_number); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } - kret = krb5_auth_con_setremoteseqnumber(_gsskrb5_context, + kret = krb5_auth_con_setremoteseqnumber(context, ctx->auth_context, l_seq_number); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } @@ -609,19 +602,18 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, krb5_ap_rep_enc_part *repl; int32_t auth_flags; - krb5_auth_con_removeflags(_gsskrb5_context, + krb5_auth_con_removeflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_TIME, &auth_flags); - kret = krb5_rd_rep(_gsskrb5_context, ctx->auth_context, &inbuf, &repl); + kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } - krb5_free_ap_rep_enc_part(_gsskrb5_context, repl); - krb5_auth_con_setflags(_gsskrb5_context, ctx->auth_context, auth_flags); + krb5_free_ap_rep_enc_part(context, repl); + krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); } /* We need to check the liftime */ @@ -629,6 +621,7 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, OM_uint32 lifetime_rec; ret = _gsskrb5_lifetime_left(minor_status, + context, ctx->lifetime, &lifetime_rec); if (ret) { @@ -645,12 +638,11 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, if (ret_flags) *ret_flags = ctx->flags; if (src_name) { - kret = krb5_copy_principal(_gsskrb5_context, + kret = krb5_copy_principal(context, ctx->source, (gsskrb5_name*)src_name); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } } @@ -664,20 +656,19 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, { int32_t tmp_r_seq_number, tmp_l_seq_number; - kret = krb5_auth_getremoteseqnumber(_gsskrb5_context, + kret = krb5_auth_getremoteseqnumber(context, ctx->auth_context, &tmp_r_seq_number); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } - kret = krb5_auth_con_getlocalseqnumber(_gsskrb5_context, + kret = krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &tmp_l_seq_number); if (kret) { - _gsskrb5_set_error_string (); + *minor_status = kret; return GSS_S_FAILURE; } @@ -695,17 +686,17 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, * the old one for the GSS_wrap() calls */ { - kret = krb5_auth_con_setremoteseqnumber(_gsskrb5_context, + kret = krb5_auth_con_setremoteseqnumber(context, ctx->auth_context, r_seq_number); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } } - return gsskrb5_acceptor_ready(minor_status, ctx, delegated_cred_handle); + return gsskrb5_acceptor_ready(minor_status, ctx, context, + delegated_cred_handle); } @@ -722,10 +713,11 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status, OM_uint32 * time_rec, gss_cred_id_t * delegated_cred_handle) { + krb5_context context; OM_uint32 ret; gsskrb5_ctx ctx; - GSSAPI_KRB5_INIT(); + GSSAPI_KRB5_INIT(&context); output_token->length = 0; output_token->value = NULL; @@ -738,6 +730,7 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status, if (*context_handle == GSS_C_NO_CONTEXT) { ret = _gsskrb5_create_ctx(minor_status, context_handle, + context, input_chan_bindings, ACCEPTOR_START); if (ret) @@ -758,6 +751,7 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status, case ACCEPTOR_START: ret = gsskrb5_acceptor_start(minor_status, ctx, + context, acceptor_cred_handle, input_token_buffer, input_chan_bindings, @@ -771,6 +765,7 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status, case ACCEPTOR_WAIT_FOR_DCESTYLE: ret = acceptor_wait_for_dcestyle(minor_status, ctx, + context, acceptor_cred_handle, input_token_buffer, input_chan_bindings, diff --git a/source4/heimdal/lib/gssapi/krb5/acquire_cred.c b/source4/heimdal/lib/gssapi/krb5/acquire_cred.c index df6e137402..e811a99a8b 100644 --- a/source4/heimdal/lib/gssapi/krb5/acquire_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/acquire_cred.c @@ -33,13 +33,14 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: acquire_cred.c,v 1.31 2006/10/07 22:13:55 lha Exp $"); +RCSID("$Id: acquire_cred.c,v 1.33 2006/11/20 18:09:30 lha Exp $"); OM_uint32 __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, - krb5_ccache id, - krb5_principal principal, - OM_uint32 *lifetime) + krb5_context context, + krb5_ccache id, + krb5_principal principal, + OM_uint32 *lifetime) { krb5_creds in_cred, *out_cred; krb5_const_realm realm; @@ -48,32 +49,30 @@ __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, memset(&in_cred, 0, sizeof(in_cred)); in_cred.client = principal; - realm = krb5_principal_get_realm(_gsskrb5_context, principal); + realm = krb5_principal_get_realm(context, principal); if (realm == NULL) { _gsskrb5_clear_status (); *minor_status = KRB5_PRINC_NOMATCH; /* XXX */ return GSS_S_FAILURE; } - kret = krb5_make_principal(_gsskrb5_context, &in_cred.server, + kret = krb5_make_principal(context, &in_cred.server, realm, KRB5_TGS_NAME, realm, NULL); if (kret) { - _gsskrb5_set_error_string(); *minor_status = kret; return GSS_S_FAILURE; } - kret = krb5_get_credentials(_gsskrb5_context, 0, + kret = krb5_get_credentials(context, 0, id, &in_cred, &out_cred); - krb5_free_principal(_gsskrb5_context, in_cred.server); + krb5_free_principal(context, in_cred.server); if (kret) { - _gsskrb5_set_error_string(); *minor_status = kret; return GSS_S_FAILURE; } *lifetime = out_cred->times.endtime; - krb5_free_creds(_gsskrb5_context, out_cred); + krb5_free_creds(context, out_cred); return GSS_S_COMPLETE; } @@ -82,7 +81,7 @@ __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, static krb5_error_code -get_keytab(krb5_keytab *keytab) +get_keytab(krb5_context context, krb5_keytab *keytab) { char kt_name[256]; krb5_error_code kret; @@ -90,13 +89,13 @@ get_keytab(krb5_keytab *keytab) HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); if (_gsskrb5_keytab != NULL) { - kret = krb5_kt_get_name(_gsskrb5_context, + kret = krb5_kt_get_name(context, _gsskrb5_keytab, kt_name, sizeof(kt_name)); if (kret == 0) - kret = krb5_kt_resolve(_gsskrb5_context, kt_name, keytab); + kret = krb5_kt_resolve(context, kt_name, keytab); } else - kret = krb5_kt_default(_gsskrb5_context, keytab); + kret = krb5_kt_default(context, keytab); HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); @@ -105,6 +104,7 @@ get_keytab(krb5_keytab *keytab) static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, + krb5_context context, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, @@ -132,33 +132,33 @@ static OM_uint32 acquire_initiator_cred * caches, otherwise, fall back to default cache. Ignore * errors. */ if (handle->principal) - kret = krb5_cc_cache_match (_gsskrb5_context, + kret = krb5_cc_cache_match (context, handle->principal, NULL, &ccache); if (ccache == NULL) { - kret = krb5_cc_default(_gsskrb5_context, &ccache); + kret = krb5_cc_default(context, &ccache); if (kret) goto end; } - kret = krb5_cc_get_principal(_gsskrb5_context, ccache, + kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ - krb5_cc_destroy(_gsskrb5_context, ccache); + krb5_cc_destroy(context, ccache); ccache = NULL; kret = 0; } else if (handle->principal == NULL) { - kret = krb5_copy_principal(_gsskrb5_context, def_princ, + kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && - krb5_principal_compare(_gsskrb5_context, handle->principal, + krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { /* Before failing, lets check the keytab */ - krb5_free_principal(_gsskrb5_context, def_princ); + krb5_free_principal(context, def_princ); def_princ = NULL; } if (def_princ == NULL) { @@ -166,30 +166,30 @@ static OM_uint32 acquire_initiator_cred * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { - kret = krb5_get_default_principal(_gsskrb5_context, + kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } - kret = get_keytab(&keytab); + kret = get_keytab(context, &keytab); if (kret) goto end; - kret = krb5_get_init_creds_opt_alloc(_gsskrb5_context, &opt); + kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; - kret = krb5_get_init_creds_keytab(_gsskrb5_context, &cred, + kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); - krb5_get_init_creds_opt_free(opt); + krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; - kret = krb5_cc_gen_new(_gsskrb5_context, &krb5_mcc_ops, + kret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache); if (kret) goto end; - kret = krb5_cc_initialize(_gsskrb5_context, ccache, cred.client); + kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) goto end; - kret = krb5_cc_store_cred(_gsskrb5_context, ccache, &cred); + kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) goto end; handle->lifetime = cred.times.endtime; @@ -197,9 +197,10 @@ static OM_uint32 acquire_initiator_cred } else { ret = __gsskrb5_ccache_lifetime(minor_status, - ccache, - handle->principal, - &handle->lifetime); + context, + ccache, + handle->principal, + &handle->lifetime); if (ret != GSS_S_COMPLETE) goto end; kret = 0; @@ -210,17 +211,16 @@ static OM_uint32 acquire_initiator_cred end: if (cred.client != NULL) - krb5_free_cred_contents(_gsskrb5_context, &cred); + krb5_free_cred_contents(context, &cred); if (def_princ != NULL) - krb5_free_principal(_gsskrb5_context, def_princ); + krb5_free_principal(context, def_princ); if (keytab != NULL) - krb5_kt_close(_gsskrb5_context, keytab); + krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE) { if (ccache != NULL) - krb5_cc_close(_gsskrb5_context, ccache); + krb5_cc_close(context, ccache); if (kret != 0) { *minor_status = kret; - _gsskrb5_set_error_string (); } } return (ret); @@ -228,6 +228,7 @@ end: static OM_uint32 acquire_acceptor_cred (OM_uint32 * minor_status, + krb5_context context, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, @@ -242,7 +243,7 @@ static OM_uint32 acquire_acceptor_cred kret = 0; ret = GSS_S_FAILURE; - kret = get_keytab(&handle->keytab); + kret = get_keytab(context, &handle->keytab); if (kret) goto end; @@ -250,21 +251,20 @@ static OM_uint32 acquire_acceptor_cred if (handle->principal) { krb5_keytab_entry entry; - kret = krb5_kt_get_entry(_gsskrb5_context, handle->keytab, + kret = krb5_kt_get_entry(context, handle->keytab, handle->principal, 0, 0, &entry); if (kret) goto end; - krb5_kt_free_entry(_gsskrb5_context, &entry); + krb5_kt_free_entry(context, &entry); } ret = GSS_S_COMPLETE; end: if (ret != GSS_S_COMPLETE) { if (handle->keytab != NULL) - krb5_kt_close(_gsskrb5_context, handle->keytab); + krb5_kt_close(context, handle->keytab); if (kret != 0) { *minor_status = kret; - _gsskrb5_set_error_string (); } } return (ret); @@ -281,6 +281,7 @@ OM_uint32 _gsskrb5_acquire_cred OM_uint32 * time_rec ) { + krb5_context context; gsskrb5_cred handle; OM_uint32 ret; @@ -289,7 +290,7 @@ OM_uint32 _gsskrb5_acquire_cred return GSS_S_FAILURE; } - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT(&context); *output_cred_handle = NULL; if (time_rec) @@ -320,31 +321,33 @@ OM_uint32 _gsskrb5_acquire_cred if (desired_name != GSS_C_NO_NAME) { krb5_principal name = (krb5_principal)desired_name; - ret = krb5_copy_principal(_gsskrb5_context, name, &handle->principal); + ret = krb5_copy_principal(context, name, &handle->principal); if (ret) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); - _gsskrb5_set_error_string(); *minor_status = ret; free(handle); return GSS_S_FAILURE; } } if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { - ret = acquire_initiator_cred(minor_status, desired_name, time_req, - desired_mechs, cred_usage, handle, actual_mechs, time_rec); + ret = acquire_initiator_cred(minor_status, context, + desired_name, time_req, + desired_mechs, cred_usage, handle, + actual_mechs, time_rec); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); - krb5_free_principal(_gsskrb5_context, handle->principal); + krb5_free_principal(context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { - ret = acquire_acceptor_cred(minor_status, desired_name, time_req, + ret = acquire_acceptor_cred(minor_status, context, + desired_name, time_req, desired_mechs, cred_usage, handle, actual_mechs, time_rec); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); - krb5_free_principal(_gsskrb5_context, handle->principal); + krb5_free_principal(context, handle->principal); free(handle); return (ret); } @@ -360,15 +363,16 @@ OM_uint32 _gsskrb5_acquire_cred if (handle->mechanisms != NULL) _gsskrb5_release_oid_set(NULL, &handle->mechanisms); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); - krb5_free_principal(_gsskrb5_context, handle->principal); + krb5_free_principal(context, handle->principal); free(handle); return (ret); } *minor_status = 0; if (time_rec) { ret = _gsskrb5_lifetime_left(minor_status, - handle->lifetime, - time_rec); + context, + handle->lifetime, + time_rec); if (ret) return ret; diff --git a/source4/heimdal/lib/gssapi/krb5/add_cred.c b/source4/heimdal/lib/gssapi/krb5/add_cred.c index 4892e84798..3b0272af80 100644 --- a/source4/heimdal/lib/gssapi/krb5/add_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/add_cred.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: add_cred.c,v 1.9 2006/10/07 22:13:58 lha Exp $"); +RCSID("$Id: add_cred.c,v 1.10 2006/11/13 18:01:01 lha Exp $"); OM_uint32 _gsskrb5_add_cred ( OM_uint32 *minor_status, @@ -48,6 +48,7 @@ OM_uint32 _gsskrb5_add_cred ( OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec) { + krb5_context context; OM_uint32 ret, lifetime; gsskrb5_cred cred, handle; krb5_const_principal dname; @@ -56,6 +57,8 @@ OM_uint32 _gsskrb5_add_cred ( cred = (gsskrb5_cred)input_cred_handle; dname = (krb5_const_principal)desired_name; + GSSAPI_KRB5_INIT (&context); + if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { *minor_status = 0; return GSS_S_BAD_MECH; @@ -83,7 +86,7 @@ OM_uint32 _gsskrb5_add_cred ( /* check that we have the same name */ if (dname != NULL && - krb5_principal_compare(_gsskrb5_context, dname, + krb5_principal_compare(context, dname, cred->principal) != FALSE) { if (output_cred_handle) HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); @@ -112,7 +115,7 @@ OM_uint32 _gsskrb5_add_cred ( ret = GSS_S_FAILURE; - kret = krb5_copy_principal(_gsskrb5_context, cred->principal, + kret = krb5_copy_principal(context, cred->principal, &handle->principal); if (kret) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); @@ -127,7 +130,7 @@ OM_uint32 _gsskrb5_add_cred ( ret = GSS_S_FAILURE; - kret = krb5_kt_get_type(_gsskrb5_context, cred->keytab, + kret = krb5_kt_get_type(context, cred->keytab, name, KRB5_KT_PREFIX_MAX_LEN); if (kret) { *minor_status = kret; @@ -136,7 +139,7 @@ OM_uint32 _gsskrb5_add_cred ( len = strlen(name); name[len++] = ':'; - kret = krb5_kt_get_name(_gsskrb5_context, cred->keytab, + kret = krb5_kt_get_name(context, cred->keytab, name + len, sizeof(name) - len); if (kret) { @@ -144,7 +147,7 @@ OM_uint32 _gsskrb5_add_cred ( goto failure; } - kret = krb5_kt_resolve(_gsskrb5_context, name, + kret = krb5_kt_resolve(context, name, &handle->keytab); if (kret){ *minor_status = kret; @@ -158,21 +161,21 @@ OM_uint32 _gsskrb5_add_cred ( ret = GSS_S_FAILURE; - type = krb5_cc_get_type(_gsskrb5_context, cred->ccache); + type = krb5_cc_get_type(context, cred->ccache); if (type == NULL){ *minor_status = ENOMEM; goto failure; } if (strcmp(type, "MEMORY") == 0) { - ret = krb5_cc_gen_new(_gsskrb5_context, &krb5_mcc_ops, + ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &handle->ccache); if (ret) { *minor_status = ret; goto failure; } - ret = krb5_cc_copy_cache(_gsskrb5_context, cred->ccache, + ret = krb5_cc_copy_cache(context, cred->ccache, handle->ccache); if (ret) { *minor_status = ret; @@ -180,7 +183,7 @@ OM_uint32 _gsskrb5_add_cred ( } } else { - name = krb5_cc_get_name(_gsskrb5_context, cred->ccache); + name = krb5_cc_get_name(context, cred->ccache); if (name == NULL) { *minor_status = ENOMEM; goto failure; @@ -192,7 +195,7 @@ OM_uint32 _gsskrb5_add_cred ( goto failure; } - kret = krb5_cc_resolve(_gsskrb5_context, type_name, + kret = krb5_cc_resolve(context, type_name, &handle->ccache); free(type_name); if (kret) { @@ -234,11 +237,11 @@ OM_uint32 _gsskrb5_add_cred ( if (handle) { if (handle->principal) - krb5_free_principal(_gsskrb5_context, handle->principal); + krb5_free_principal(context, handle->principal); if (handle->keytab) - krb5_kt_close(_gsskrb5_context, handle->keytab); + krb5_kt_close(context, handle->keytab); if (handle->ccache) - krb5_cc_destroy(_gsskrb5_context, handle->ccache); + krb5_cc_destroy(context, handle->ccache); if (handle->mechanisms) _gsskrb5_release_oid_set(NULL, &handle->mechanisms); free(handle); diff --git a/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c b/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c index 9aec53faaa..18a90fe9a7 100644 --- a/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c +++ b/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c @@ -36,7 +36,8 @@ #include <roken.h> krb5_error_code -_gsskrb5i_address_to_krb5addr(OM_uint32 gss_addr_type, +_gsskrb5i_address_to_krb5addr(krb5_context context, + OM_uint32 gss_addr_type, gss_buffer_desc *gss_addr, int16_t port, krb5_address *address) @@ -61,7 +62,7 @@ _gsskrb5i_address_to_krb5addr(OM_uint32 gss_addr_type, return GSS_S_FAILURE; } - problem = krb5_h_addr2sockaddr (_gsskrb5_context, + problem = krb5_h_addr2sockaddr (context, addr_type, gss_addr->value, &sa, @@ -70,7 +71,7 @@ _gsskrb5i_address_to_krb5addr(OM_uint32 gss_addr_type, if (problem) return GSS_S_FAILURE; - problem = krb5_sockaddr2address (_gsskrb5_context, &sa, address); + problem = krb5_sockaddr2address (context, &sa, address); return problem; } diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c index 2c43ed8b32..d1bdbb641f 100644 --- a/source4/heimdal/lib/gssapi/krb5/arcfour.c +++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: arcfour.c,v 1.30 2006/11/07 19:05:16 lha Exp $"); +RCSID("$Id: arcfour.c,v 1.31 2006/11/13 18:01:08 lha Exp $"); /* * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt @@ -114,7 +114,8 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, static krb5_error_code -arcfour_mic_cksum(krb5_keyblock *key, unsigned usage, +arcfour_mic_cksum(krb5_context context, + krb5_keyblock *key, unsigned usage, u_char *sgn_cksum, size_t sgn_cksum_sz, const u_char *v1, size_t l1, const void *v2, size_t l2, @@ -138,13 +139,13 @@ arcfour_mic_cksum(krb5_keyblock *key, unsigned usage, memcpy(ptr + l1, v2, l2); memcpy(ptr + l1 + l2, v3, l3); - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { free(ptr); return ret; } - ret = krb5_create_checksum(_gsskrb5_context, + ret = krb5_create_checksum(context, crypto, usage, 0, @@ -155,7 +156,7 @@ arcfour_mic_cksum(krb5_keyblock *key, unsigned usage, memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); free_Checksum(&CKSUM); } - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return ret; } @@ -164,6 +165,7 @@ arcfour_mic_cksum(krb5_keyblock *key, unsigned usage, OM_uint32 _gssapi_get_mic_arcfour(OM_uint32 * minor_status, const gsskrb5_ctx context_handle, + krb5_context context, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token, @@ -200,7 +202,8 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status, p = NULL; - ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN, + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SIGN, p0 + 16, 8, /* SGN_CKSUM */ p0, 8, /* TOK_ID, SGN_ALG, Filer */ message_buffer->value, message_buffer->length, @@ -211,7 +214,7 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status, return GSS_S_FAILURE; } - ret = arcfour_mic_key(_gsskrb5_context, key, + ret = arcfour_mic_key(context, key, p0 + 16, 8, /* SGN_CKSUM */ k6_data, sizeof(k6_data)); if (ret) { @@ -221,13 +224,13 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status, } HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - krb5_auth_con_getlocalseqnumber (_gsskrb5_context, + krb5_auth_con_getlocalseqnumber (context, context_handle->auth_context, &seq_number); p = p0 + 8; /* SND_SEQ */ _gsskrb5_encode_be_om_uint32(seq_number, p); - krb5_auth_con_setlocalseqnumber (_gsskrb5_context, + krb5_auth_con_setlocalseqnumber (context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); @@ -248,6 +251,7 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status, OM_uint32 _gssapi_verify_mic_arcfour(OM_uint32 * minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, gss_qop_t * qop_state, @@ -279,7 +283,8 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status, return GSS_S_BAD_MIC; p += 4; - ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN, + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SIGN, cksum_data, sizeof(cksum_data), p - 8, 8, message_buffer->value, message_buffer->length, @@ -289,7 +294,7 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status, return GSS_S_FAILURE; } - ret = arcfour_mic_key(_gsskrb5_context, key, + ret = arcfour_mic_key(context, key, cksum_data, sizeof(cksum_data), k6_data, sizeof(k6_data)); if (ret) { @@ -339,6 +344,7 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status, OM_uint32 _gssapi_wrap_arcfour(OM_uint32 * minor_status, const gsskrb5_ctx context_handle, + krb5_context context, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, @@ -396,13 +402,13 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status, p = NULL; HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - krb5_auth_con_getlocalseqnumber (_gsskrb5_context, + krb5_auth_con_getlocalseqnumber (context, context_handle->auth_context, &seq_number); _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8); - krb5_auth_con_setlocalseqnumber (_gsskrb5_context, + krb5_auth_con_setlocalseqnumber (context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); @@ -420,7 +426,8 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status, if (!IS_DCE_STYLE(context_handle)) p[input_message_buffer->length] = 1; /* padding */ - ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL, + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SEAL, p0 + 16, 8, /* SGN_CKSUM */ p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ p0 + 24, 8, /* Confounder */ @@ -442,7 +449,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status, for (i = 0; i < 16; i++) Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; } - ret = arcfour_mic_key(_gsskrb5_context, &Klocal, + ret = arcfour_mic_key(context, &Klocal, p0 + 8, 4, /* SND_SEQ */ k6_data, sizeof(k6_data)); memset(Klocaldata, 0, sizeof(Klocaldata)); @@ -463,7 +470,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status, } memset(k6_data, 0, sizeof(k6_data)); - ret = arcfour_mic_key(_gsskrb5_context, key, + ret = arcfour_mic_key(context, key, p0 + 16, 8, /* SGN_CKSUM */ k6_data, sizeof(k6_data)); if (ret) { @@ -490,6 +497,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status, OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, @@ -562,7 +570,7 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, return GSS_S_BAD_MIC; p = NULL; - ret = arcfour_mic_key(_gsskrb5_context, key, + ret = arcfour_mic_key(context, key, p0 + 16, 8, /* SGN_CKSUM */ k6_data, sizeof(k6_data)); if (ret) { @@ -601,7 +609,7 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, for (i = 0; i < 16; i++) Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; } - ret = arcfour_mic_key(_gsskrb5_context, &Klocal, + ret = arcfour_mic_key(context, &Klocal, SND_SEQ, 4, k6_data, sizeof(k6_data)); memset(Klocaldata, 0, sizeof(Klocaldata)); @@ -643,7 +651,8 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, output_message_buffer->length -= padlen; } - ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL, + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SEAL, cksum_data, sizeof(cksum_data), p0, 8, Confounder, sizeof(Confounder), @@ -721,6 +730,7 @@ max_wrap_length_arcfour(const gsskrb5_ctx ctx, OM_uint32 _gssapi_wrap_size_arcfour(OM_uint32 *minor_status, const gsskrb5_ctx ctx, + krb5_context context, int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size, @@ -730,9 +740,8 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status, krb5_error_code ret; krb5_crypto crypto; - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; return GSS_S_FAILURE; } @@ -740,13 +749,12 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status, ret = max_wrap_length_arcfour(ctx, crypto, req_output_size, max_input_size); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_COMPLETE; } diff --git a/source4/heimdal/lib/gssapi/krb5/cfx.c b/source4/heimdal/lib/gssapi/krb5/cfx.c index cb3f9ee5d3..e75fe5da9d 100755 --- a/source4/heimdal/lib/gssapi/krb5/cfx.c +++ b/source4/heimdal/lib/gssapi/krb5/cfx.c @@ -32,7 +32,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: cfx.c,v 1.24 2006/10/24 21:13:22 lha Exp $"); +RCSID("$Id: cfx.c,v 1.25 2006/11/13 18:01:14 lha Exp $"); /* * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt @@ -43,7 +43,8 @@ RCSID("$Id: cfx.c,v 1.24 2006/10/24 21:13:22 lha Exp $"); #define CFXAcceptorSubkey (1 << 2) krb5_error_code -_gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto, +_gsskrb5cfx_wrap_length_cfx(krb5_context context, + krb5_crypto crypto, int conf_req_flag, size_t input_length, size_t *output_length, @@ -57,11 +58,11 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto, *output_length = sizeof(gss_cfx_wrap_token_desc); *padlength = 0; - ret = krb5_crypto_get_checksum_type(_gsskrb5_context, crypto, &type); + ret = krb5_crypto_get_checksum_type(context, crypto, &type); if (ret) return ret; - ret = krb5_checksumsize(_gsskrb5_context, type, cksumsize); + ret = krb5_checksumsize(context, type, cksumsize); if (ret) return ret; @@ -71,7 +72,7 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto, /* Header is concatenated with data before encryption */ input_length += sizeof(gss_cfx_wrap_token_desc); - ret = krb5_crypto_getpadsize(_gsskrb5_context, crypto, &padsize); + ret = krb5_crypto_getpadsize(context, crypto, &padsize); if (ret) { return ret; } @@ -83,7 +84,7 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto, input_length += *padlength; } - *output_length += krb5_get_wrapped_length(_gsskrb5_context, + *output_length += krb5_get_wrapped_length(context, crypto, input_length); } else { /* Checksum is concatenated with data */ @@ -96,7 +97,8 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto, } krb5_error_code -_gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto, +_gsskrb5cfx_max_wrap_length_cfx(krb5_context context, + krb5_crypto crypto, int conf_req_flag, size_t input_length, OM_uint32 *output_length) @@ -116,7 +118,7 @@ _gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto, wrapped_size = input_length + 1; do { wrapped_size--; - sz = krb5_get_wrapped_length(_gsskrb5_context, + sz = krb5_get_wrapped_length(context, crypto, wrapped_size); } while (wrapped_size && sz > input_length); if (wrapped_size == 0) { @@ -136,11 +138,11 @@ _gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto, krb5_cksumtype type; size_t cksumsize; - ret = krb5_crypto_get_checksum_type(_gsskrb5_context, crypto, &type); + ret = krb5_crypto_get_checksum_type(context, crypto, &type); if (ret) return ret; - ret = krb5_checksumsize(_gsskrb5_context, type, &cksumsize); + ret = krb5_checksumsize(context, type, &cksumsize); if (ret) return ret; @@ -157,6 +159,7 @@ _gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto, OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size, @@ -166,23 +169,21 @@ OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, krb5_error_code ret; krb5_crypto crypto; - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; return GSS_S_FAILURE; } - ret = _gsskrb5cfx_max_wrap_length_cfx(crypto, conf_req_flag, + ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag, req_output_size, max_input_size); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_COMPLETE; } @@ -233,6 +234,7 @@ rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, @@ -250,20 +252,19 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, int32_t seq_number; u_char *p; - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; return GSS_S_FAILURE; } - ret = _gsskrb5cfx_wrap_length_cfx(crypto, conf_req_flag, + ret = _gsskrb5cfx_wrap_length_cfx(context, + crypto, conf_req_flag, input_message_buffer->length, &wrapped_len, &cksumsize, &padlength); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -274,7 +275,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, output_message_buffer->value = malloc(output_message_buffer->length); if (output_message_buffer->value == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -324,12 +325,12 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, token->RRC[1] = 0; HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - krb5_auth_con_getlocalseqnumber(_gsskrb5_context, + krb5_auth_con_getlocalseqnumber(context, context_handle->auth_context, &seq_number); _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); - krb5_auth_con_setlocalseqnumber(_gsskrb5_context, + krb5_auth_con_setlocalseqnumber(context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); @@ -364,15 +365,14 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, memcpy(p + input_message_buffer->length + padlength, token, sizeof(*token)); - ret = krb5_encrypt(_gsskrb5_context, crypto, + ret = krb5_encrypt(context, crypto, usage, p, input_message_buffer->length + padlength + sizeof(*token), &cipher); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_FAILURE; } @@ -382,9 +382,8 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_FAILURE; } @@ -397,22 +396,21 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, buf = malloc(input_message_buffer->length + sizeof(*token)); if (buf == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_FAILURE; } memcpy(buf, input_message_buffer->value, input_message_buffer->length); memcpy(buf + input_message_buffer->length, token, sizeof(*token)); - ret = krb5_create_checksum(_gsskrb5_context, crypto, + ret = krb5_create_checksum(context, crypto, usage, 0, buf, input_message_buffer->length + sizeof(*token), &cksum); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); free(buf); return GSS_S_FAILURE; @@ -434,9 +432,8 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, ret = rrc_rotate(p, input_message_buffer->length + cksum.checksum.length, rrc, FALSE); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); free_Checksum(&cksum); return GSS_S_FAILURE; @@ -444,7 +441,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, free_Checksum(&cksum); } - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); if (conf_state != NULL) { *conf_state = conf_req_flag; @@ -456,6 +453,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, @@ -539,9 +537,8 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, /* * Decrypt and/or verify checksum */ - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; return GSS_S_FAILURE; } @@ -559,23 +556,22 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, /* Rotate by RRC; bogus to do this in-place XXX */ *minor_status = rrc_rotate(p, len, rrc, TRUE); if (*minor_status != 0) { - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } if (token_flags & CFXSealed) { - ret = krb5_decrypt(_gsskrb5_context, crypto, usage, + ret = krb5_decrypt(context, crypto, usage, p, len, &data); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_BAD_MIC; } /* Check that there is room for the pad and token header */ if (data.length < ec + sizeof(*token)) { - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); krb5_data_free(&data); return GSS_S_DEFECTIVE_TOKEN; } @@ -588,7 +584,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, /* Check the integrity of the header */ if (memcmp(p, token, sizeof(*token)) != 0) { - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); krb5_data_free(&data); return GSS_S_BAD_MIC; } @@ -599,12 +595,11 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, Checksum cksum; /* Determine checksum type */ - ret = krb5_crypto_get_checksum_type(_gsskrb5_context, + ret = krb5_crypto_get_checksum_type(context, crypto, &cksum.cksumtype); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -613,7 +608,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, /* Check we have at least as much data as the checksum */ if (len < cksum.checksum.length) { *minor_status = ERANGE; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_BAD_MIC; } @@ -625,7 +620,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, output_message_buffer->value = malloc(len + sizeof(*token)); if (output_message_buffer->value == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -642,21 +637,20 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, token->RRC[0] = 0; token->RRC[1] = 0; - ret = krb5_verify_checksum(_gsskrb5_context, crypto, + ret = krb5_verify_checksum(context, crypto, usage, output_message_buffer->value, len + sizeof(*token), &cksum); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_BAD_MIC; } } - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); if (qop_state != NULL) { *qop_state = GSS_C_QOP_DEFAULT; @@ -668,6 +662,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token, @@ -682,9 +677,8 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, size_t len; int32_t seq_number; - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; return GSS_S_FAILURE; } @@ -693,7 +687,7 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, buf = malloc(len); if (buf == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -710,12 +704,12 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, memset(token->Filler, 0xFF, 5); HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - krb5_auth_con_getlocalseqnumber(_gsskrb5_context, + krb5_auth_con_getlocalseqnumber(context, context_handle->auth_context, &seq_number); _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); - krb5_auth_con_setlocalseqnumber(_gsskrb5_context, + krb5_auth_con_setlocalseqnumber(context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); @@ -726,16 +720,15 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; } - ret = krb5_create_checksum(_gsskrb5_context, crypto, + ret = krb5_create_checksum(context, crypto, usage, 0, buf, len, &cksum); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); free(buf); return GSS_S_FAILURE; } - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); /* Determine MIC length */ message_token->length = sizeof(*token) + cksum.checksum.length; @@ -761,6 +754,7 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, gss_qop_t *qop_state, @@ -830,19 +824,17 @@ OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, /* * Verify checksum */ - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; return GSS_S_FAILURE; } - ret = krb5_crypto_get_checksum_type(_gsskrb5_context, crypto, + ret = krb5_crypto_get_checksum_type(context, crypto, &cksum.cksumtype); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -858,20 +850,19 @@ OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, buf = malloc(message_buffer->length + sizeof(*token)); if (buf == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } memcpy(buf, message_buffer->value, message_buffer->length); memcpy(buf + message_buffer->length, token, sizeof(*token)); - ret = krb5_verify_checksum(_gsskrb5_context, crypto, + ret = krb5_verify_checksum(context, crypto, usage, buf, sizeof(*token) + message_buffer->length, &cksum); - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); if (ret != 0) { - _gsskrb5_set_error_string(); *minor_status = ret; free(buf); return GSS_S_BAD_MIC; diff --git a/source4/heimdal/lib/gssapi/krb5/cfx.h b/source4/heimdal/lib/gssapi/krb5/cfx.h index 1120544fbe..ce021aa099 100755 --- a/source4/heimdal/lib/gssapi/krb5/cfx.h +++ b/source4/heimdal/lib/gssapi/krb5/cfx.h @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -/* $Id: cfx.h,v 1.7 2006/07/19 14:16:33 lha Exp $ */ +/* $Id: cfx.h,v 1.8 2006/11/13 18:01:17 lha Exp $ */ #ifndef GSSAPI_CFX_H_ #define GSSAPI_CFX_H_ 1 @@ -62,19 +62,4 @@ typedef struct gss_cfx_delete_token_desc_struct { u_char SND_SEQ[8]; } gss_cfx_delete_token_desc, *gss_cfx_delete_token; -krb5_error_code -_gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto, - int conf_req_flag, - size_t input_length, - size_t *output_length, - size_t *cksumsize, - uint16_t *padlength); - -krb5_error_code -_gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto, - int conf_req_flag, - size_t input_length, - OM_uint32 *output_length); - - #endif /* GSSAPI_CFX_H_ */ diff --git a/source4/heimdal/lib/gssapi/krb5/compare_name.c b/source4/heimdal/lib/gssapi/krb5/compare_name.c index 3e0f7edfee..6b537468df 100644 --- a/source4/heimdal/lib/gssapi/krb5/compare_name.c +++ b/source4/heimdal/lib/gssapi/krb5/compare_name.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: compare_name.c,v 1.7 2006/10/07 22:14:15 lha Exp $"); +RCSID("$Id: compare_name.c,v 1.8 2006/11/13 18:01:20 lha Exp $"); OM_uint32 _gsskrb5_compare_name (OM_uint32 * minor_status, @@ -44,10 +44,11 @@ OM_uint32 _gsskrb5_compare_name { krb5_const_principal princ1 = (krb5_const_principal)name1; krb5_const_principal princ2 = (krb5_const_principal)name2; + krb5_context context; - GSSAPI_KRB5_INIT(); + GSSAPI_KRB5_INIT(&context); - *name_equal = krb5_principal_compare (_gsskrb5_context, + *name_equal = krb5_principal_compare (context, princ1, princ2); *minor_status = 0; return GSS_S_COMPLETE; diff --git a/source4/heimdal/lib/gssapi/krb5/compat.c b/source4/heimdal/lib/gssapi/krb5/compat.c index 0ea2fce0e8..3e64df03db 100644 --- a/source4/heimdal/lib/gssapi/krb5/compat.c +++ b/source4/heimdal/lib/gssapi/krb5/compat.c @@ -33,11 +33,12 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: compat.c,v 1.13 2006/10/07 22:14:17 lha Exp $"); +RCSID("$Id: compat.c,v 1.14 2006/11/13 18:01:23 lha Exp $"); static krb5_error_code -check_compat(OM_uint32 *minor_status, krb5_const_principal name, +check_compat(OM_uint32 *minor_status, + krb5_context context, krb5_const_principal name, const char *option, krb5_boolean *compat, krb5_boolean match_val) { @@ -46,27 +47,27 @@ check_compat(OM_uint32 *minor_status, krb5_const_principal name, krb5_principal match; - p = krb5_config_get_strings(_gsskrb5_context, NULL, "gssapi", + p = krb5_config_get_strings(context, NULL, "gssapi", option, NULL); if(p == NULL) return 0; match = NULL; for(q = p; *q; q++) { - ret = krb5_parse_name(_gsskrb5_context, *q, &match); + ret = krb5_parse_name(context, *q, &match); if (ret) break; - if (krb5_principal_match(_gsskrb5_context, name, match)) { + if (krb5_principal_match(context, name, match)) { *compat = match_val; break; } - krb5_free_principal(_gsskrb5_context, match); + krb5_free_principal(context, match); match = NULL; } if (match) - krb5_free_principal(_gsskrb5_context, match); + krb5_free_principal(context, match); krb5_config_free_strings(p); if (ret) { @@ -83,17 +84,19 @@ check_compat(OM_uint32 *minor_status, krb5_const_principal name, */ OM_uint32 -_gss_DES3_get_mic_compat(OM_uint32 *minor_status, gsskrb5_ctx ctx) +_gss_DES3_get_mic_compat(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context) { krb5_boolean use_compat = FALSE; OM_uint32 ret; if ((ctx->more_flags & COMPAT_OLD_DES3_SELECTED) == 0) { - ret = check_compat(minor_status, ctx->target, + ret = check_compat(minor_status, context, ctx->target, "broken_des3_mic", &use_compat, TRUE); if (ret) return ret; - ret = check_compat(minor_status, ctx->target, + ret = check_compat(minor_status, context, ctx->target, "correct_des3_mic", &use_compat, FALSE); if (ret) return ret; diff --git a/source4/heimdal/lib/gssapi/krb5/context_time.c b/source4/heimdal/lib/gssapi/krb5/context_time.c index 4e9d9f5d1d..9012dd0b7f 100644 --- a/source4/heimdal/lib/gssapi/krb5/context_time.c +++ b/source4/heimdal/lib/gssapi/krb5/context_time.c @@ -33,12 +33,13 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: context_time.c,v 1.13 2006/10/07 22:14:19 lha Exp $"); +RCSID("$Id: context_time.c,v 1.14 2006/11/13 18:01:26 lha Exp $"); OM_uint32 _gsskrb5_lifetime_left(OM_uint32 *minor_status, - OM_uint32 lifetime, - OM_uint32 *lifetime_rec) + krb5_context context, + OM_uint32 lifetime, + OM_uint32 *lifetime_rec) { krb5_timestamp timeret; krb5_error_code kret; @@ -48,10 +49,9 @@ _gsskrb5_lifetime_left(OM_uint32 *minor_status, return GSS_S_COMPLETE; } - kret = krb5_timeofday(_gsskrb5_context, &timeret); + kret = krb5_timeofday(context, &timeret); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } @@ -70,17 +70,19 @@ OM_uint32 _gsskrb5_context_time OM_uint32 * time_rec ) { + krb5_context context; OM_uint32 lifetime; OM_uint32 major_status; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); lifetime = ctx->lifetime; HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); - major_status = _gsskrb5_lifetime_left(minor_status, lifetime, time_rec); + major_status = _gsskrb5_lifetime_left(minor_status, context, + lifetime, time_rec); if (major_status != GSS_S_COMPLETE) return major_status; diff --git a/source4/heimdal/lib/gssapi/krb5/copy_ccache.c b/source4/heimdal/lib/gssapi/krb5/copy_ccache.c index 91d21a1aec..4387a4e6ef 100644 --- a/source4/heimdal/lib/gssapi/krb5/copy_ccache.c +++ b/source4/heimdal/lib/gssapi/krb5/copy_ccache.c @@ -33,11 +33,12 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: copy_ccache.c,v 1.16 2006/11/08 02:42:50 lha Exp $"); +RCSID("$Id: copy_ccache.c,v 1.17 2006/11/13 18:01:29 lha Exp $"); #if 0 OM_uint32 gss_krb5_copy_ccache(OM_uint32 *minor_status, + krb5_context context, gss_cred_id_t cred, krb5_ccache out) { @@ -51,11 +52,10 @@ gss_krb5_copy_ccache(OM_uint32 *minor_status, return GSS_S_FAILURE; } - kret = krb5_cc_copy_cache(_gsskrb5_context, cred->ccache, out); + kret = krb5_cc_copy_cache(context, cred->ccache, out); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } *minor_status = 0; @@ -71,13 +71,14 @@ _gsskrb5_import_cred(OM_uint32 *minor_status, krb5_keytab keytab, gss_cred_id_t *cred) { + krb5_context context; krb5_error_code kret; gsskrb5_cred handle; OM_uint32 ret; *cred = NULL; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); handle = calloc(1, sizeof(*handle)); if (handle == NULL) { @@ -94,11 +95,10 @@ _gsskrb5_import_cred(OM_uint32 *minor_status, handle->usage |= GSS_C_INITIATE; - kret = krb5_cc_get_principal(_gsskrb5_context, id, + kret = krb5_cc_get_principal(context, id, &handle->principal); if (kret) { free(handle); - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } @@ -106,11 +106,11 @@ _gsskrb5_import_cred(OM_uint32 *minor_status, if (keytab_principal) { krb5_boolean match; - match = krb5_principal_compare(_gsskrb5_context, + match = krb5_principal_compare(context, handle->principal, keytab_principal); if (match == FALSE) { - krb5_free_principal(_gsskrb5_context, handle->principal); + krb5_free_principal(context, handle->principal); free(handle); _gsskrb5_clear_status (); *minor_status = EINVAL; @@ -119,21 +119,22 @@ _gsskrb5_import_cred(OM_uint32 *minor_status, } ret = __gsskrb5_ccache_lifetime(minor_status, - id, - handle->principal, - &handle->lifetime); + context, + id, + handle->principal, + &handle->lifetime); if (ret != GSS_S_COMPLETE) { - krb5_free_principal(_gsskrb5_context, handle->principal); + krb5_free_principal(context, handle->principal); free(handle); return ret; } - kret = krb5_cc_get_full_name(_gsskrb5_context, id, &str); + kret = krb5_cc_get_full_name(context, id, &str); if (kret) goto out; - kret = krb5_cc_resolve(_gsskrb5_context, str, &handle->ccache); + kret = krb5_cc_resolve(context, str, &handle->ccache); free(str); if (kret) goto out; @@ -146,18 +147,18 @@ _gsskrb5_import_cred(OM_uint32 *minor_status, handle->usage |= GSS_C_ACCEPT; if (keytab_principal && handle->principal == NULL) { - kret = krb5_copy_principal(_gsskrb5_context, + kret = krb5_copy_principal(context, keytab_principal, &handle->principal); if (kret) goto out; } - kret = krb5_kt_get_full_name(_gsskrb5_context, keytab, &str); + kret = krb5_kt_get_full_name(context, keytab, &str); if (kret) goto out; - kret = krb5_kt_resolve(_gsskrb5_context, str, &handle->keytab); + kret = krb5_kt_resolve(context, str, &handle->keytab); free(str); if (kret) goto out; @@ -180,9 +181,8 @@ _gsskrb5_import_cred(OM_uint32 *minor_status, return GSS_S_COMPLETE; out: - _gsskrb5_set_error_string (); if (handle->principal) - krb5_free_principal(_gsskrb5_context, handle->principal); + krb5_free_principal(context, handle->principal); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = kret; diff --git a/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c b/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c index e890d7d2c2..c7f2ee262d 100644 --- a/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c @@ -33,16 +33,17 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: delete_sec_context.c,v 1.19 2006/10/07 22:14:28 lha Exp $"); +RCSID("$Id: delete_sec_context.c,v 1.20 2006/11/13 18:01:32 lha Exp $"); OM_uint32 _gsskrb5_delete_sec_context(OM_uint32 * minor_status, gss_ctx_id_t * context_handle, gss_buffer_t output_token) { + krb5_context context; gsskrb5_ctx ctx; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); *minor_status = 0; @@ -59,17 +60,17 @@ _gsskrb5_delete_sec_context(OM_uint32 * minor_status, HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - krb5_auth_con_free (_gsskrb5_context, ctx->auth_context); + krb5_auth_con_free (context, ctx->auth_context); if(ctx->source) - krb5_free_principal (_gsskrb5_context, ctx->source); + krb5_free_principal (context, ctx->source); if(ctx->target) - krb5_free_principal (_gsskrb5_context, ctx->target); + krb5_free_principal (context, ctx->target); if (ctx->ticket) - krb5_free_ticket (_gsskrb5_context, ctx->ticket); + krb5_free_ticket (context, ctx->ticket); if(ctx->order) _gssapi_msg_order_destroy(&ctx->order); if (ctx->service_keyblock) - krb5_free_keyblock (_gsskrb5_context, ctx->service_keyblock); + krb5_free_keyblock (context, ctx->service_keyblock); krb5_data_free(&ctx->fwd_data); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); diff --git a/source4/heimdal/lib/gssapi/krb5/display_name.c b/source4/heimdal/lib/gssapi/krb5/display_name.c index 8fce7d8572..4956c2d77f 100644 --- a/source4/heimdal/lib/gssapi/krb5/display_name.c +++ b/source4/heimdal/lib/gssapi/krb5/display_name.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: display_name.c,v 1.12 2006/10/07 22:14:31 lha Exp $"); +RCSID("$Id: display_name.c,v 1.13 2006/11/13 18:01:36 lha Exp $"); OM_uint32 _gsskrb5_display_name (OM_uint32 * minor_status, @@ -42,16 +42,17 @@ OM_uint32 _gsskrb5_display_name gss_OID * output_name_type ) { + krb5_context context; krb5_const_principal name = (krb5_const_principal)input_name; krb5_error_code kret; char *buf; size_t len; - GSSAPI_KRB5_INIT (); - kret = krb5_unparse_name (_gsskrb5_context, name, &buf); + GSSAPI_KRB5_INIT (&context); + + kret = krb5_unparse_name (context, name, &buf); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } len = strlen (buf); diff --git a/source4/heimdal/lib/gssapi/krb5/display_status.c b/source4/heimdal/lib/gssapi/krb5/display_status.c index 11926ca557..b0155a7fdf 100644 --- a/source4/heimdal/lib/gssapi/krb5/display_status.c +++ b/source4/heimdal/lib/gssapi/krb5/display_status.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan + * Copyright (c) 1998 - 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: display_status.c,v 1.16 2006/10/07 22:14:33 lha Exp $"); +RCSID("$Id: display_status.c,v 1.17 2006/11/13 18:01:38 lha Exp $"); static const char * calling_error(OM_uint32 v) @@ -114,117 +114,87 @@ supplementary_error(OM_uint32 v) void _gsskrb5_clear_status (void) { - struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(1); - if (ctx == NULL) + krb5_context context; + + if (_gsskrb5_init (&context) != 0) return; - HEIMDAL_MUTEX_lock(&ctx->mutex); - if (ctx->error_string) - free(ctx->error_string); - ctx->error_string = NULL; - HEIMDAL_MUTEX_unlock(&ctx->mutex); + krb5_clear_error_string(context); } void _gsskrb5_set_status (const char *fmt, ...) { - struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(1); + krb5_context context; va_list args; + char *str; - if (ctx == NULL) + if (_gsskrb5_init (&context) != 0) return; - HEIMDAL_MUTEX_lock(&ctx->mutex); + va_start(args, fmt); - if (ctx->error_string) - free(ctx->error_string); - /* ignore failures, will use status code instead */ - vasprintf(&ctx->error_string, fmt, args); + vasprintf(&str, fmt, args); va_end(args); - HEIMDAL_MUTEX_unlock(&ctx->mutex); -} - -void -_gsskrb5_set_error_string (void) -{ - char *e; - - e = krb5_get_error_string(_gsskrb5_context); - if (e) { - _gsskrb5_set_status("%s", e); - krb5_free_error_string(_gsskrb5_context, e); - } else - _gsskrb5_clear_status(); -} - -char * -_gsskrb5_get_error_string (void) -{ - struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(0); - char *ret; - - if (ctx == NULL) - return NULL; - HEIMDAL_MUTEX_lock(&ctx->mutex); - ret = ctx->error_string; - ctx->error_string = NULL; - HEIMDAL_MUTEX_unlock(&ctx->mutex); - return ret; + if (str) { + krb5_set_error_string(context, str); + free(str); + } } OM_uint32 _gsskrb5_display_status - (OM_uint32 *minor_status, - OM_uint32 status_value, - int status_type, - const gss_OID mech_type, - OM_uint32 *message_context, - gss_buffer_t status_string) +(OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) { - char *buf; - - GSSAPI_KRB5_INIT (); - - status_string->length = 0; - status_string->value = NULL; - - if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 && - gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) { - *minor_status = 0; - return GSS_C_GSS_CODE; - } - - if (status_type == GSS_C_GSS_CODE) { - if (GSS_SUPPLEMENTARY_INFO(status_value)) - asprintf(&buf, "%s", - supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value))); - else - asprintf (&buf, "%s %s", - calling_error(GSS_CALLING_ERROR(status_value)), - routine_error(GSS_ROUTINE_ERROR(status_value))); - } else if (status_type == GSS_C_MECH_CODE) { - buf = _gsskrb5_get_error_string (); - if (buf == NULL) { - const char *tmp = krb5_get_err_text (_gsskrb5_context, - status_value); - if (tmp == NULL) - asprintf(&buf, "unknown mech error-code %u", - (unsigned)status_value); - else - buf = strdup(tmp); - } - } else { - *minor_status = EINVAL; - return GSS_S_BAD_STATUS; - } - - if (buf == NULL) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - - *message_context = 0; - *minor_status = 0; - - status_string->length = strlen(buf); - status_string->value = buf; + krb5_context context; + char *buf; + + GSSAPI_KRB5_INIT (&context); + + status_string->length = 0; + status_string->value = NULL; + + if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 && + gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) { + *minor_status = 0; + return GSS_C_GSS_CODE; + } + + if (status_type == GSS_C_GSS_CODE) { + if (GSS_SUPPLEMENTARY_INFO(status_value)) + asprintf(&buf, "%s", + supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value))); + else + asprintf (&buf, "%s %s", + calling_error(GSS_CALLING_ERROR(status_value)), + routine_error(GSS_ROUTINE_ERROR(status_value))); + } else if (status_type == GSS_C_MECH_CODE) { + buf = krb5_get_error_string(context); + if (buf == NULL) { + const char *tmp = krb5_get_err_text (context, status_value); + if (tmp == NULL) + asprintf(&buf, "unknown mech error-code %u", + (unsigned)status_value); + else + buf = strdup(tmp); + } + } else { + *minor_status = EINVAL; + return GSS_S_BAD_STATUS; + } + + if (buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *message_context = 0; + *minor_status = 0; + + status_string->length = strlen(buf); + status_string->value = buf; - return GSS_S_COMPLETE; + return GSS_S_COMPLETE; } diff --git a/source4/heimdal/lib/gssapi/krb5/duplicate_name.c b/source4/heimdal/lib/gssapi/krb5/duplicate_name.c index 475ae61efc..8375257180 100644 --- a/source4/heimdal/lib/gssapi/krb5/duplicate_name.c +++ b/source4/heimdal/lib/gssapi/krb5/duplicate_name.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: duplicate_name.c,v 1.10 2006/10/07 22:14:35 lha Exp $"); +RCSID("$Id: duplicate_name.c,v 1.11 2006/11/13 18:01:42 lha Exp $"); OM_uint32 _gsskrb5_duplicate_name ( OM_uint32 * minor_status, @@ -41,16 +41,16 @@ OM_uint32 _gsskrb5_duplicate_name ( gss_name_t * dest_name ) { + krb5_context context; krb5_const_principal src = (krb5_const_principal)src_name; krb5_principal *dest = (krb5_principal *)dest_name; krb5_error_code kret; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); - kret = krb5_copy_principal (_gsskrb5_context, src, dest); + kret = krb5_copy_principal (context, src, dest); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } else { *minor_status = 0; diff --git a/source4/heimdal/lib/gssapi/krb5/export_name.c b/source4/heimdal/lib/gssapi/krb5/export_name.c index d00c458898..646fdafb7c 100644 --- a/source4/heimdal/lib/gssapi/krb5/export_name.c +++ b/source4/heimdal/lib/gssapi/krb5/export_name.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: export_name.c,v 1.8 2006/10/07 22:14:40 lha Exp $"); +RCSID("$Id: export_name.c,v 1.9 2006/11/13 18:01:50 lha Exp $"); OM_uint32 _gsskrb5_export_name (OM_uint32 * minor_status, @@ -41,16 +41,17 @@ OM_uint32 _gsskrb5_export_name gss_buffer_t exported_name ) { + krb5_context context; krb5_const_principal princ = (krb5_const_principal)input_name; krb5_error_code kret; char *buf, *name; size_t len; - GSSAPI_KRB5_INIT (); - kret = krb5_unparse_name (_gsskrb5_context, princ, &name); + GSSAPI_KRB5_INIT (&context); + + kret = krb5_unparse_name (context, princ, &name); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } len = strlen (name); diff --git a/source4/heimdal/lib/gssapi/krb5/export_sec_context.c b/source4/heimdal/lib/gssapi/krb5/export_sec_context.c index aff03a0b67..ffa671a4a1 100644 --- a/source4/heimdal/lib/gssapi/krb5/export_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/export_sec_context.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: export_sec_context.c,v 1.11 2006/10/07 22:14:42 lha Exp $"); +RCSID("$Id: export_sec_context.c,v 1.12 2006/11/13 18:01:55 lha Exp $"); OM_uint32 _gsskrb5_export_sec_context ( @@ -42,6 +42,7 @@ _gsskrb5_export_sec_context ( gss_buffer_t interprocess_token ) { + krb5_context context; const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle; krb5_storage *sp; krb5_auth_context ac; @@ -52,7 +53,7 @@ _gsskrb5_export_sec_context ( OM_uint32 minor; krb5_error_code kret; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); diff --git a/source4/heimdal/lib/gssapi/krb5/external.c b/source4/heimdal/lib/gssapi/krb5/external.c index 0681bd4038..bf7f64cf20 100644 --- a/source4/heimdal/lib/gssapi/krb5/external.c +++ b/source4/heimdal/lib/gssapi/krb5/external.c @@ -34,7 +34,7 @@ #include "krb5/gsskrb5_locl.h" #include <gssapi_mech.h> -RCSID("$Id: external.c,v 1.22 2006/11/08 23:00:20 lha Exp $"); +RCSID("$Id: external.c,v 1.23 2006/11/13 18:01:57 lha Exp $"); /* * The implementation must reserve static storage for a @@ -369,7 +369,7 @@ gss_OID GSS_SASL_DIGEST_MD5_MECHANISM = &gss_sasl_digest_md5_mechanism_desc; * Context for krb5 calls. */ -krb5_context _gsskrb5_context; +krb5_context context; /* * diff --git a/source4/heimdal/lib/gssapi/krb5/get_mic.c b/source4/heimdal/lib/gssapi/krb5/get_mic.c index 5a078d634d..790c9b6166 100644 --- a/source4/heimdal/lib/gssapi/krb5/get_mic.c +++ b/source4/heimdal/lib/gssapi/krb5/get_mic.c @@ -33,12 +33,13 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: get_mic.c,v 1.34 2006/10/18 15:59:23 lha Exp $"); +RCSID("$Id: get_mic.c,v 1.35 2006/11/13 18:02:00 lha Exp $"); static OM_uint32 mic_des (OM_uint32 * minor_status, const gsskrb5_ctx ctx, + krb5_context context, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token, @@ -94,9 +95,9 @@ mic_des HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); /* sequence number */ - krb5_auth_con_getlocalseqnumber (_gsskrb5_context, - ctx->auth_context, - &seq_number); + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); p -= 16; /* SND_SEQ */ p[0] = (seq_number >> 0) & 0xFF; @@ -111,7 +112,7 @@ mic_des DES_cbc_encrypt ((void *)p, (void *)p, 8, &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT); - krb5_auth_con_setlocalseqnumber (_gsskrb5_context, + krb5_auth_con_setlocalseqnumber (context, ctx->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -127,6 +128,7 @@ static OM_uint32 mic_des3 (OM_uint32 * minor_status, const gsskrb5_ctx ctx, + krb5_context context, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token, @@ -180,18 +182,17 @@ mic_des3 memcpy (tmp, p - 8, 8); memcpy (tmp + 8, message_buffer->value, message_buffer->length); - kret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + kret = krb5_crypto_init(context, key, 0, &crypto); if (kret) { free (message_token->value); message_token->value = NULL; message_token->length = 0; free (tmp); - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } - kret = krb5_create_checksum (_gsskrb5_context, + kret = krb5_create_checksum (context, crypto, KRB5_KU_USAGE_SIGN, 0, @@ -199,12 +200,11 @@ mic_des3 message_buffer->length + 8, &cksum); free (tmp); - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); if (kret) { free (message_token->value); message_token->value = NULL; message_token->length = 0; - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } @@ -213,7 +213,7 @@ mic_des3 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); /* sequence number */ - krb5_auth_con_getlocalseqnumber (_gsskrb5_context, + krb5_auth_con_getlocalseqnumber (context, ctx->auth_context, &seq_number); @@ -225,13 +225,12 @@ mic_des3 (ctx->more_flags & LOCAL) ? 0 : 0xFF, 4); - kret = krb5_crypto_init(_gsskrb5_context, key, + kret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (kret) { free (message_token->value); message_token->value = NULL; message_token->length = 0; - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } @@ -241,16 +240,15 @@ mic_des3 else memcpy(ivec, p + 8, 8); - kret = krb5_encrypt_ivec (_gsskrb5_context, + kret = krb5_encrypt_ivec (context, crypto, KRB5_KU_USAGE_SEQ, seq, 8, &encdata, ivec); - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); if (kret) { free (message_token->value); message_token->value = NULL; message_token->length = 0; - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } @@ -260,7 +258,7 @@ mic_des3 memcpy (p, encdata.data, encdata.length); krb5_data_free (&encdata); - krb5_auth_con_setlocalseqnumber (_gsskrb5_context, + krb5_auth_con_setlocalseqnumber (context, ctx->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -278,40 +276,42 @@ OM_uint32 _gsskrb5_get_mic gss_buffer_t message_token ) { + krb5_context context; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; krb5_keyblock *key; OM_uint32 ret; krb5_keytype keytype; + GSSAPI_KRB5_INIT (&context); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - ret = _gsskrb5i_get_token_key(ctx, &key); + ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype); + krb5_enctype_to_keytype (context, key->keytype, &keytype); switch (keytype) { case KEYTYPE_DES : - ret = mic_des (minor_status, ctx, qop_req, + ret = mic_des (minor_status, ctx, context, qop_req, message_buffer, message_token, key); break; case KEYTYPE_DES3 : - ret = mic_des3 (minor_status, ctx, qop_req, + ret = mic_des3 (minor_status, ctx, context, qop_req, message_buffer, message_token, key); break; case KEYTYPE_ARCFOUR: case KEYTYPE_ARCFOUR_56: - ret = _gssapi_get_mic_arcfour (minor_status, ctx, qop_req, + ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req, message_buffer, message_token, key); break; default : - ret = _gssapi_mic_cfx (minor_status, ctx, qop_req, + ret = _gssapi_mic_cfx (minor_status, ctx, context, qop_req, message_buffer, message_token, key); break; } - krb5_free_keyblock (_gsskrb5_context, key); + krb5_free_keyblock (context, key); return ret; } diff --git a/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h b/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h index 426c0ab200..15bd5c77da 100644 --- a/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h +++ b/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h @@ -10,6 +10,7 @@ __gss_krb5_initialize (void); OM_uint32 __gsskrb5_ccache_lifetime ( OM_uint32 */*minor_status*/, + krb5_context /*context*/, krb5_ccache /*id*/, krb5_principal /*principal*/, OM_uint32 */*lifetime*/); @@ -17,7 +18,8 @@ __gsskrb5_ccache_lifetime ( OM_uint32 _gss_DES3_get_mic_compat ( OM_uint32 */*minor_status*/, - gsskrb5_ctx /*ctx*/); + gsskrb5_ctx /*ctx*/, + krb5_context /*context*/); OM_uint32 _gssapi_decapsulate ( @@ -44,6 +46,7 @@ OM_uint32 _gssapi_get_mic_arcfour ( OM_uint32 * /*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, gss_qop_t /*qop_req*/, const gss_buffer_t /*message_buffer*/, gss_buffer_t /*message_token*/, @@ -59,6 +62,7 @@ OM_uint32 _gssapi_mic_cfx ( OM_uint32 */*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, gss_qop_t /*qop_req*/, const gss_buffer_t /*message_buffer*/, gss_buffer_t /*message_token*/, @@ -99,6 +103,7 @@ OM_uint32 _gssapi_unwrap_arcfour ( OM_uint32 */*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, const gss_buffer_t /*input_message_buffer*/, gss_buffer_t /*output_message_buffer*/, int */*conf_state*/, @@ -109,6 +114,7 @@ OM_uint32 _gssapi_unwrap_cfx ( OM_uint32 */*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, const gss_buffer_t /*input_message_buffer*/, gss_buffer_t /*output_message_buffer*/, int */*conf_state*/, @@ -125,6 +131,7 @@ OM_uint32 _gssapi_verify_mic_arcfour ( OM_uint32 * /*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, const gss_buffer_t /*message_buffer*/, const gss_buffer_t /*token_buffer*/, gss_qop_t * /*qop_state*/, @@ -135,6 +142,7 @@ OM_uint32 _gssapi_verify_mic_cfx ( OM_uint32 */*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, const gss_buffer_t /*message_buffer*/, const gss_buffer_t /*token_buffer*/, gss_qop_t */*qop_state*/, @@ -150,6 +158,7 @@ OM_uint32 _gssapi_wrap_arcfour ( OM_uint32 * /*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, int /*conf_req_flag*/, gss_qop_t /*qop_req*/, const gss_buffer_t /*input_message_buffer*/, @@ -161,6 +170,7 @@ OM_uint32 _gssapi_wrap_cfx ( OM_uint32 */*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, int /*conf_req_flag*/, gss_qop_t /*qop_req*/, const gss_buffer_t /*input_message_buffer*/, @@ -172,6 +182,7 @@ OM_uint32 _gssapi_wrap_size_arcfour ( OM_uint32 */*minor_status*/, const gsskrb5_ctx /*ctx*/, + krb5_context /*context*/, int /*conf_req_flag*/, gss_qop_t /*qop_req*/, OM_uint32 /*req_output_size*/, @@ -182,6 +193,7 @@ OM_uint32 _gssapi_wrap_size_cfx ( OM_uint32 */*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, int /*conf_req_flag*/, gss_qop_t /*qop_req*/, OM_uint32 /*req_output_size*/, @@ -268,6 +280,7 @@ OM_uint32 _gsskrb5_create_ctx ( OM_uint32 * /*minor_status*/, gss_ctx_id_t * /*context_handle*/, + krb5_context /*context*/, const gss_channel_bindings_t /*input_chan_bindings*/, enum gss_ctx_id_t_state /*state*/); @@ -359,9 +372,6 @@ _gsskrb5_export_sec_context ( gss_ctx_id_t * /*context_handle*/, gss_buffer_t interprocess_token ); -char * -_gsskrb5_get_error_string (void); - ssize_t _gsskrb5_get_mech ( const u_char */*ptr*/, @@ -376,9 +386,6 @@ _gsskrb5_get_mic ( const gss_buffer_t /*message_buffer*/, gss_buffer_t message_token ); -struct gssapi_thr_context * -_gsskrb5_get_thread_context (int /*createp*/); - OM_uint32 _gsskrb5_get_tkt_flags ( OM_uint32 */*minor_status*/, @@ -412,7 +419,7 @@ _gsskrb5_indicate_mechs ( gss_OID_set * mech_set ); krb5_error_code -_gsskrb5_init (void); +_gsskrb5_init (krb5_context */*context*/); OM_uint32 _gsskrb5_init_sec_context ( @@ -496,6 +503,7 @@ _gsskrb5_krb5_ccache_name ( OM_uint32 _gsskrb5_lifetime_left ( OM_uint32 */*minor_status*/, + krb5_context /*context*/, OM_uint32 /*lifetime*/, OM_uint32 */*lifetime_rec*/); @@ -552,9 +560,6 @@ _gsskrb5_set_cred_option ( const gss_OID /*desired_object*/, const gss_buffer_t /*value*/); -void -_gsskrb5_set_error_string (void); - OM_uint32 _gsskrb5_set_sec_context_option ( OM_uint32 */*minor_status*/, @@ -635,6 +640,7 @@ OM_uint32 _gsskrb5_verify_mic_internal ( OM_uint32 * /*minor_status*/, const gsskrb5_ctx /*context_handle*/, + krb5_context /*context*/, const gss_buffer_t /*message_buffer*/, const gss_buffer_t /*token_buffer*/, gss_qop_t * /*qop_state*/, @@ -661,6 +667,7 @@ _gsskrb5_wrap_size_limit ( krb5_error_code _gsskrb5cfx_max_wrap_length_cfx ( + krb5_context /*context*/, krb5_crypto /*crypto*/, int /*conf_req_flag*/, size_t /*input_length*/, @@ -668,6 +675,7 @@ _gsskrb5cfx_max_wrap_length_cfx ( krb5_error_code _gsskrb5cfx_wrap_length_cfx ( + krb5_context /*context*/, krb5_crypto /*crypto*/, int /*conf_req_flag*/, size_t /*input_length*/, @@ -677,6 +685,7 @@ _gsskrb5cfx_wrap_length_cfx ( krb5_error_code _gsskrb5i_address_to_krb5addr ( + krb5_context /*context*/, OM_uint32 /*gss_addr_type*/, gss_buffer_desc */*gss_addr*/, int16_t /*port*/, @@ -685,16 +694,19 @@ _gsskrb5i_address_to_krb5addr ( krb5_error_code _gsskrb5i_get_acceptor_subkey ( const gsskrb5_ctx /*ctx*/, + krb5_context /*context*/, krb5_keyblock **/*key*/); krb5_error_code _gsskrb5i_get_initiator_subkey ( const gsskrb5_ctx /*ctx*/, + krb5_context /*context*/, krb5_keyblock **/*key*/); OM_uint32 _gsskrb5i_get_token_key ( const gsskrb5_ctx /*ctx*/, + krb5_context /*context*/, krb5_keyblock **/*key*/); void diff --git a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h index 39c800bf31..1983a9b8e4 100644 --- a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h +++ b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: gsskrb5_locl.h,v 1.8 2006/11/10 00:36:40 lha Exp $ */ +/* $Id: gsskrb5_locl.h,v 1.9 2006/11/13 18:02:03 lha Exp $ */ #ifndef GSSKRB5_LOCL_H #define GSSKRB5_LOCL_H @@ -100,8 +100,6 @@ typedef struct Principal *gsskrb5_name; * */ -extern krb5_context _gsskrb5_context; - extern krb5_keytab _gsskrb5_keytab; extern HEIMDAL_MUTEX gssapi_keytab_mutex; @@ -116,9 +114,9 @@ struct gssapi_thr_context { #include <krb5/gsskrb5-private.h> -#define GSSAPI_KRB5_INIT() do { \ +#define GSSAPI_KRB5_INIT(ctx) do { \ krb5_error_code kret_gss_init; \ - if((kret_gss_init = _gsskrb5_init ()) != 0) { \ + if((kret_gss_init = _gsskrb5_init (ctx)) != 0) { \ *minor_status = kret_gss_init; \ return GSS_S_FAILURE; \ } \ diff --git a/source4/heimdal/lib/gssapi/krb5/import_name.c b/source4/heimdal/lib/gssapi/krb5/import_name.c index dc24ed5cf2..15311b4614 100644 --- a/source4/heimdal/lib/gssapi/krb5/import_name.c +++ b/source4/heimdal/lib/gssapi/krb5/import_name.c @@ -33,23 +33,23 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: import_name.c,v 1.17 2006/10/07 22:14:51 lha Exp $"); +RCSID("$Id: import_name.c,v 1.18 2006/11/13 18:02:06 lha Exp $"); static OM_uint32 parse_krb5_name (OM_uint32 *minor_status, + krb5_context context, const char *name, gss_name_t *output_name) { krb5_principal princ; krb5_error_code kerr; - kerr = krb5_parse_name (_gsskrb5_context, name, &princ); + kerr = krb5_parse_name (context, name, &princ); if (kerr == 0) { *output_name = (gss_name_t)princ; return GSS_S_COMPLETE; } - _gsskrb5_set_error_string (); *minor_status = kerr; if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) @@ -60,6 +60,7 @@ parse_krb5_name (OM_uint32 *minor_status, static OM_uint32 import_krb5_name (OM_uint32 *minor_status, + krb5_context context, const gss_buffer_t input_name_buffer, gss_name_t *output_name) { @@ -76,7 +77,7 @@ import_krb5_name (OM_uint32 *minor_status, input_name_buffer->length); tmp[input_name_buffer->length] = '\0'; - ret = parse_krb5_name(minor_status, tmp, output_name); + ret = parse_krb5_name(minor_status, context, tmp, output_name); free(tmp); return ret; @@ -84,6 +85,7 @@ import_krb5_name (OM_uint32 *minor_status, static OM_uint32 import_hostbased_name (OM_uint32 *minor_status, + krb5_context context, const gss_buffer_t input_name_buffer, gss_name_t *output_name) { @@ -117,7 +119,7 @@ import_hostbased_name (OM_uint32 *minor_status, host = local_hostname; } - kerr = krb5_sname_to_principal (_gsskrb5_context, + kerr = krb5_sname_to_principal (context, host, tmp, KRB5_NT_SRV_HST, @@ -128,8 +130,6 @@ import_hostbased_name (OM_uint32 *minor_status, *output_name = (gss_name_t)princ; return GSS_S_COMPLETE; } - _gsskrb5_set_error_string (); - *minor_status = kerr; if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) return GSS_S_BAD_NAME; @@ -139,6 +139,7 @@ import_hostbased_name (OM_uint32 *minor_status, static OM_uint32 import_export_name (OM_uint32 *minor_status, + krb5_context context, const gss_buffer_t input_name_buffer, gss_name_t *output_name) { @@ -178,7 +179,7 @@ import_export_name (OM_uint32 *minor_status, memcpy(name, p, length); name[length] = '\0'; - ret = parse_krb5_name(minor_status, name, output_name); + ret = parse_krb5_name(minor_status, context, name, output_name); free(name); return ret; @@ -191,14 +192,17 @@ OM_uint32 _gsskrb5_import_name gss_name_t * output_name ) { - GSSAPI_KRB5_INIT (); + krb5_context context; *minor_status = 0; *output_name = GSS_C_NO_NAME; + GSSAPI_KRB5_INIT (&context); + if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE) || gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE_X)) return import_hostbased_name (minor_status, + context, input_name_buffer, output_name); else if (gss_oid_equal(input_name_type, GSS_C_NO_OID) @@ -206,10 +210,12 @@ OM_uint32 _gsskrb5_import_name || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) /* default printable syntax */ return import_krb5_name (minor_status, + context, input_name_buffer, output_name); else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) { return import_export_name(minor_status, + context, input_name_buffer, output_name); } else { diff --git a/source4/heimdal/lib/gssapi/krb5/import_sec_context.c b/source4/heimdal/lib/gssapi/krb5/import_sec_context.c index 8131e2621d..bbdc1d36d0 100644 --- a/source4/heimdal/lib/gssapi/krb5/import_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/import_sec_context.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: import_sec_context.c,v 1.17 2006/10/07 22:14:53 lha Exp $"); +RCSID("$Id: import_sec_context.c,v 1.18 2006/11/13 18:02:09 lha Exp $"); OM_uint32 _gsskrb5_import_sec_context ( @@ -43,6 +43,7 @@ _gsskrb5_import_sec_context ( ) { OM_uint32 ret = GSS_S_FAILURE; + krb5_context context; krb5_error_code kret; krb5_storage *sp; krb5_auth_context ac; @@ -56,7 +57,7 @@ _gsskrb5_import_sec_context ( gsskrb5_ctx ctx; gss_name_t name; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); *context_handle = GSS_C_NO_CONTEXT; @@ -77,10 +78,9 @@ _gsskrb5_import_sec_context ( } HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); - kret = krb5_auth_con_init (_gsskrb5_context, + kret = krb5_auth_con_init (context, &ctx->auth_context); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; @@ -108,11 +108,11 @@ _gsskrb5_import_sec_context ( goto failure; } - krb5_auth_con_setaddrs (_gsskrb5_context, ac, localp, remotep); + krb5_auth_con_setaddrs (context, ac, localp, remotep); if (localp) - krb5_free_address (_gsskrb5_context, localp); + krb5_free_address (context, localp); if (remotep) - krb5_free_address (_gsskrb5_context, remotep); + krb5_free_address (context, remotep); localp = remotep = NULL; if (krb5_ret_int16 (sp, &ac->local_port) != 0) @@ -123,20 +123,20 @@ _gsskrb5_import_sec_context ( if (flags & SC_KEYBLOCK) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; - krb5_auth_con_setkey (_gsskrb5_context, ac, &keyblock); - krb5_free_keyblock_contents (_gsskrb5_context, &keyblock); + krb5_auth_con_setkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_LOCAL_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; - krb5_auth_con_setlocalsubkey (_gsskrb5_context, ac, &keyblock); - krb5_free_keyblock_contents (_gsskrb5_context, &keyblock); + krb5_auth_con_setlocalsubkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_REMOTE_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; - krb5_auth_con_setremotesubkey (_gsskrb5_context, ac, &keyblock); - krb5_free_keyblock_contents (_gsskrb5_context, &keyblock); + krb5_auth_con_setremotesubkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); } if (krb5_ret_uint32 (sp, &ac->local_seqnumber)) goto failure; @@ -209,16 +209,16 @@ _gsskrb5_import_sec_context ( return GSS_S_COMPLETE; failure: - krb5_auth_con_free (_gsskrb5_context, + krb5_auth_con_free (context, ctx->auth_context); if (ctx->source != NULL) - krb5_free_principal(_gsskrb5_context, ctx->source); + krb5_free_principal(context, ctx->source); if (ctx->target != NULL) - krb5_free_principal(_gsskrb5_context, ctx->target); + krb5_free_principal(context, ctx->target); if (localp) - krb5_free_address (_gsskrb5_context, localp); + krb5_free_address (context, localp); if (remotep) - krb5_free_address (_gsskrb5_context, remotep); + krb5_free_address (context, remotep); if(ctx->order) _gssapi_msg_order_destroy(&ctx->order); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); diff --git a/source4/heimdal/lib/gssapi/krb5/init.c b/source4/heimdal/lib/gssapi/krb5/init.c index cbef8740b7..3eece8e086 100644 --- a/source4/heimdal/lib/gssapi/krb5/init.c +++ b/source4/heimdal/lib/gssapi/krb5/init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2001, 2003, 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,79 +33,51 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: init.c,v 1.9 2006/10/07 22:14:58 lha Exp $"); +RCSID("$Id: init.c,v 1.10 2006/11/13 18:02:12 lha Exp $"); -static HEIMDAL_MUTEX _gsskrb5_context_mutex = HEIMDAL_MUTEX_INITIALIZER; +static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER; static int created_key; -static HEIMDAL_thread_key gssapi_context_key; +static HEIMDAL_thread_key context_key; static void -gssapi_destroy_thread_context(void *ptr) +destroy_context(void *ptr) { - struct gssapi_thr_context *ctx = ptr; + krb5_context context = ptr; - if (ctx == NULL) + if (context == NULL) return; - if (ctx->error_string) - free(ctx->error_string); - HEIMDAL_MUTEX_destroy(&ctx->mutex); - free(ctx); -} - - -struct gssapi_thr_context * -_gsskrb5_get_thread_context(int createp) -{ - struct gssapi_thr_context *ctx; - int ret; - - HEIMDAL_MUTEX_lock(&_gsskrb5_context_mutex); - - if (!created_key) - abort(); - ctx = HEIMDAL_getspecific(gssapi_context_key); - if (ctx == NULL) { - if (!createp) - goto fail; - ctx = malloc(sizeof(*ctx)); - if (ctx == NULL) - goto fail; - ctx->error_string = NULL; - HEIMDAL_MUTEX_init(&ctx->mutex); - HEIMDAL_setspecific(gssapi_context_key, ctx, ret); - if (ret) - goto fail; - } - HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex); - return ctx; - fail: - HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex); - if (ctx) - free(ctx); - return NULL; + krb5_free_context(context); } krb5_error_code -_gsskrb5_init (void) +_gsskrb5_init (krb5_context *context) { krb5_error_code ret = 0; - HEIMDAL_MUTEX_lock(&_gsskrb5_context_mutex); + HEIMDAL_MUTEX_lock(&context_mutex); - if(_gsskrb5_context == NULL) - ret = krb5_init_context (&_gsskrb5_context); - if (ret == 0 && !created_key) { - HEIMDAL_key_create(&gssapi_context_key, - gssapi_destroy_thread_context, - ret); + if (!created_key) { + HEIMDAL_key_create(&context_key, destroy_context, ret); if (ret) { - krb5_free_context(_gsskrb5_context); - _gsskrb5_context = NULL; - } else - created_key = 1; + HEIMDAL_MUTEX_unlock(&context_mutex); + return ret; + } + created_key = 1; } + HEIMDAL_MUTEX_unlock(&context_mutex); - HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex); + *context = HEIMDAL_getspecific(context_key); + if (*context == NULL) { + + ret = krb5_init_context(context); + if (ret == 0) { + HEIMDAL_setspecific(context_key, *context, ret); + if (ret) { + krb5_free_context(*context); + *context = NULL; + } + } + } return ret; } diff --git a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c index 27d859ddd8..d5f183b0ba 100644 --- a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: init_sec_context.c,v 1.73 2006/11/07 17:40:01 lha Exp $"); +RCSID("$Id: init_sec_context.c,v 1.75 2006/12/13 10:33:20 lha Exp $"); /* * copy the addresses from `input_chan_bindings' (if any) to @@ -41,7 +41,8 @@ RCSID("$Id: init_sec_context.c,v 1.73 2006/11/07 17:40:01 lha Exp $"); */ static OM_uint32 -set_addresses (krb5_auth_context ac, +set_addresses (krb5_context context, + krb5_auth_context ac, const gss_channel_bindings_t input_chan_bindings) { /* Port numbers are expected to be in application_data.value, @@ -64,29 +65,31 @@ set_addresses (krb5_auth_context ac, ac->remote_port = *((int16_t *) input_chan_bindings->application_data.value + 1); - kret = _gsskrb5i_address_to_krb5addr(input_chan_bindings->acceptor_addrtype, + kret = _gsskrb5i_address_to_krb5addr(context, + input_chan_bindings->acceptor_addrtype, &input_chan_bindings->acceptor_address, ac->remote_port, &acceptor_addr); if (kret) return kret; - kret = _gsskrb5i_address_to_krb5addr(input_chan_bindings->initiator_addrtype, + kret = _gsskrb5i_address_to_krb5addr(context, + input_chan_bindings->initiator_addrtype, &input_chan_bindings->initiator_address, ac->local_port, &initiator_addr); if (kret) { - krb5_free_address (_gsskrb5_context, &acceptor_addr); + krb5_free_address (context, &acceptor_addr); return kret; } - kret = krb5_auth_con_setaddrs(_gsskrb5_context, + kret = krb5_auth_con_setaddrs(context, ac, &initiator_addr, /* local address */ &acceptor_addr); /* remote address */ - krb5_free_address (_gsskrb5_context, &initiator_addr); - krb5_free_address (_gsskrb5_context, &acceptor_addr); + krb5_free_address (context, &initiator_addr); + krb5_free_address (context, &acceptor_addr); #if 0 free(input_chan_bindings->application_data.value); @@ -101,6 +104,7 @@ OM_uint32 _gsskrb5_create_ctx( OM_uint32 * minor_status, gss_ctx_id_t * context_handle, + krb5_context context, const gss_channel_bindings_t input_chan_bindings, enum gss_ctx_id_t_state state) { @@ -127,23 +131,22 @@ _gsskrb5_create_ctx( ctx->order = NULL; HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); - kret = krb5_auth_con_init (_gsskrb5_context, &ctx->auth_context); + kret = krb5_auth_con_init (context, &ctx->auth_context); if (kret) { *minor_status = kret; - _gsskrb5_set_error_string (); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); return GSS_S_FAILURE; } - kret = set_addresses(ctx->auth_context, input_chan_bindings); + kret = set_addresses(context, ctx->auth_context, input_chan_bindings); if (kret) { *minor_status = kret; HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); - krb5_auth_con_free(_gsskrb5_context, ctx->auth_context); + krb5_auth_con_free(context, ctx->auth_context); return GSS_S_BAD_BINDINGS; } @@ -152,7 +155,7 @@ _gsskrb5_create_ctx( * We need a sequence number */ - krb5_auth_con_addflags(_gsskrb5_context, + krb5_auth_con_addflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE | KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, @@ -167,6 +170,7 @@ _gsskrb5_create_ctx( static OM_uint32 gsskrb5_get_creds( OM_uint32 * minor_status, + krb5_context context, krb5_ccache ccache, gsskrb5_ctx ctx, krb5_const_principal target_name, @@ -188,7 +192,7 @@ gsskrb5_get_creds( if (time_req && time_req != GSS_C_INDEFINITE) { krb5_timestamp ts; - krb5_timeofday (_gsskrb5_context, &ts); + krb5_timeofday (context, &ts); this_cred.times.endtime = ts + time_req; } else { this_cred.times.endtime = 0; @@ -196,20 +200,20 @@ gsskrb5_get_creds( this_cred.session.keytype = KEYTYPE_NULL; - kret = krb5_get_credentials(_gsskrb5_context, + kret = krb5_get_credentials(context, 0, ccache, &this_cred, cred); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } ctx->lifetime = (*cred)->times.endtime; - ret = _gsskrb5_lifetime_left(minor_status, ctx->lifetime, &lifetime_rec); + ret = _gsskrb5_lifetime_left(minor_status, context, + ctx->lifetime, &lifetime_rec); if (ret) return ret; if (lifetime_rec == 0) { @@ -225,14 +229,15 @@ gsskrb5_get_creds( static OM_uint32 gsskrb5_initiator_ready( OM_uint32 * minor_status, - gsskrb5_ctx ctx) + gsskrb5_ctx ctx, + krb5_context context) { OM_uint32 ret; int32_t seq_number; int is_cfx = 0; OM_uint32 flags = ctx->flags; - krb5_auth_getremoteseqnumber (_gsskrb5_context, + krb5_auth_getremoteseqnumber (context, ctx->auth_context, &seq_number); @@ -255,7 +260,8 @@ gsskrb5_initiator_ready( */ static void -do_delegation (krb5_auth_context ac, +do_delegation (krb5_context context, + krb5_auth_context ac, krb5_ccache ccache, krb5_creds *cred, krb5_const_principal name, @@ -269,11 +275,11 @@ do_delegation (krb5_auth_context ac, memset (&creds, 0, sizeof(creds)); krb5_data_zero (fwd_data); - kret = krb5_cc_get_principal(_gsskrb5_context, ccache, &creds.client); + kret = krb5_cc_get_principal(context, ccache, &creds.client); if (kret) goto out; - kret = krb5_build_principal(_gsskrb5_context, + kret = krb5_build_principal(context, &creds.server, strlen(creds.client->realm), creds.client->realm, @@ -293,7 +299,7 @@ do_delegation (krb5_auth_context ac, name->name.name_string.len < 2) goto out; - kret = krb5_get_forwarded_creds(_gsskrb5_context, + kret = krb5_get_forwarded_creds(context, ac, ccache, KDCOptions2int(fwd_flags), @@ -308,9 +314,9 @@ do_delegation (krb5_auth_context ac, *flags |= GSS_C_DELEG_FLAG; if (creds.client) - krb5_free_principal(_gsskrb5_context, creds.client); + krb5_free_principal(context, creds.client); if (creds.server) - krb5_free_principal(_gsskrb5_context, creds.server); + krb5_free_principal(context, creds.server); } /* @@ -322,6 +328,7 @@ init_auth (OM_uint32 * minor_status, gsskrb5_cred initiator_cred_handle, gsskrb5_ctx ctx, + krb5_context context, krb5_const_principal name, const gss_OID mech_type, OM_uint32 req_flags, @@ -356,9 +363,8 @@ init_auth *actual_mech_type = GSS_KRB5_MECHANISM; if (initiator_cred_handle == NULL) { - kret = krb5_cc_default (_gsskrb5_context, &ccache); + kret = krb5_cc_default (context, &ccache); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; @@ -366,28 +372,27 @@ init_auth } else ccache = initiator_cred_handle->ccache; - kret = krb5_cc_get_principal (_gsskrb5_context, ccache, &ctx->source); + kret = krb5_cc_get_principal (context, ccache, &ctx->source); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } - kret = krb5_copy_principal (_gsskrb5_context, name, &ctx->target); + kret = krb5_copy_principal (context, name, &ctx->target); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } - ret = _gss_DES3_get_mic_compat(minor_status, ctx); + ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); if (ret) goto failure; ret = gsskrb5_get_creds(minor_status, + context, ccache, ctx, ctx->target, @@ -400,8 +405,9 @@ init_auth ctx->lifetime = cred->times.endtime; ret = _gsskrb5_lifetime_left(minor_status, - ctx->lifetime, - &lifetime_rec); + context, + ctx->lifetime, + &lifetime_rec); if (ret) { goto failure; } @@ -412,15 +418,14 @@ init_auth goto failure; } - krb5_auth_con_setkey(_gsskrb5_context, + krb5_auth_con_setkey(context, ctx->auth_context, &cred->session); - kret = krb5_auth_con_generatelocalsubkey(_gsskrb5_context, + kret = krb5_auth_con_generatelocalsubkey(context, ctx->auth_context, &cred->session); if(kret) { - _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; @@ -436,7 +441,7 @@ init_auth if (!cred->flags.b.ok_as_delegate) { krb5_boolean delegate; - krb5_appdefault_boolean(_gsskrb5_context, + krb5_appdefault_boolean(context, "gssapi", name->realm, "ok-as-delegate", FALSE, &delegate); if (delegate) @@ -446,7 +451,8 @@ init_auth flags = 0; ap_options = 0; if (req_flags & GSS_C_DELEG_FLAG) - do_delegation (ctx->auth_context, + do_delegation (context, + ctx->auth_context, ccache, cred, name, &fwd_data, &flags); if (req_flags & GSS_C_MUTUAL_FLAG) { @@ -471,9 +477,9 @@ init_auth flags |= GSS_C_EXTENDED_ERROR_FLAG; if (req_flags & GSS_C_CONF_FLAG) - flags |= GSS_C_CONF_FLAG; + flags |= GSS_C_CONF_FLAG; if (req_flags & GSS_C_INTEG_FLAG) - flags |= GSS_C_INTEG_FLAG; + flags |= GSS_C_INTEG_FLAG; flags |= GSS_C_TRANS_FLAG; @@ -493,7 +499,7 @@ init_auth enctype = ctx->auth_context->keyblock->keytype; - kret = krb5_build_authenticator (_gsskrb5_context, + kret = krb5_build_authenticator (context, ctx->auth_context, enctype, cred, @@ -503,13 +509,12 @@ init_auth KRB5_KU_AP_REQ_AUTH); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } - kret = krb5_build_ap_req (_gsskrb5_context, + kret = krb5_build_ap_req (context, enctype, cred, ap_options, @@ -517,7 +522,6 @@ init_auth &outbuf); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; @@ -529,22 +533,22 @@ init_auth goto failure; krb5_data_free (&outbuf); - krb5_free_creds(_gsskrb5_context, cred); + krb5_free_creds(context, cred); free_Checksum(&cksum); if (initiator_cred_handle == NULL) - krb5_cc_close(_gsskrb5_context, ccache); + krb5_cc_close(context, ccache); if (flags & GSS_C_MUTUAL_FLAG) { ctx->state = INITIATOR_WAIT_FOR_MUTAL; return GSS_S_CONTINUE_NEEDED; } - return gsskrb5_initiator_ready(minor_status, ctx); + return gsskrb5_initiator_ready(minor_status, ctx, context); failure: if(cred) - krb5_free_creds(_gsskrb5_context, cred); + krb5_free_creds(context, cred); if (ccache && initiator_cred_handle == NULL) - krb5_cc_close(_gsskrb5_context, ccache); + krb5_cc_close(context, ccache); return ret; @@ -554,6 +558,7 @@ static OM_uint32 repl_mutual (OM_uint32 * minor_status, gsskrb5_ctx ctx, + krb5_context context, const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, @@ -593,28 +598,27 @@ repl_mutual } } - kret = krb5_rd_rep (_gsskrb5_context, + kret = krb5_rd_rep (context, ctx->auth_context, &indata, &repl); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } - krb5_free_ap_rep_enc_part (_gsskrb5_context, + krb5_free_ap_rep_enc_part (context, repl); _gsskrb5i_is_cfx(ctx, &is_cfx); if (is_cfx) { krb5_keyblock *key = NULL; - kret = krb5_auth_con_getremotesubkey(_gsskrb5_context, + kret = krb5_auth_con_getremotesubkey(context, ctx->auth_context, &key); if (kret == 0 && key != NULL) { ctx->more_flags |= ACCEPTOR_SUBKEY; - krb5_free_keyblock (_gsskrb5_context, key); + krb5_free_keyblock (context, key); } } @@ -622,6 +626,7 @@ repl_mutual *minor_status = 0; if (time_rec) { ret = _gsskrb5_lifetime_left(minor_status, + context, ctx->lifetime, time_rec); } else { @@ -635,16 +640,15 @@ repl_mutual krb5_data outbuf; /* Do don't do sequence number for the mk-rep */ - krb5_auth_con_removeflags(_gsskrb5_context, + krb5_auth_con_removeflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE, &con_flags); - kret = krb5_mk_rep(_gsskrb5_context, + kret = krb5_mk_rep(context, ctx->auth_context, &outbuf); if (kret) { - _gsskrb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } @@ -652,13 +656,13 @@ repl_mutual output_token->length = outbuf.length; output_token->value = outbuf.data; - krb5_auth_con_removeflags(_gsskrb5_context, + krb5_auth_con_removeflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE, NULL); } - return gsskrb5_initiator_ready(minor_status, ctx); + return gsskrb5_initiator_ready(minor_status, ctx, context); } /* @@ -681,12 +685,13 @@ OM_uint32 _gsskrb5_init_sec_context OM_uint32 * time_rec ) { + krb5_context context; gsskrb5_cred cred = (gsskrb5_cred)initiator_cred_handle; krb5_const_principal name = (krb5_const_principal)target_name; gsskrb5_ctx ctx; OM_uint32 ret; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); output_token->length = 0; output_token->value = NULL; @@ -722,6 +727,7 @@ OM_uint32 _gsskrb5_init_sec_context ret = _gsskrb5_create_ctx(minor_status, context_handle, + context, input_chan_bindings, INITIATOR_START); if (ret) @@ -742,6 +748,7 @@ OM_uint32 _gsskrb5_init_sec_context ret = init_auth(minor_status, cred, ctx, + context, name, mech_type, req_flags, @@ -756,6 +763,7 @@ OM_uint32 _gsskrb5_init_sec_context case INITIATOR_WAIT_FOR_MUTAL: ret = repl_mutual(minor_status, ctx, + context, mech_type, req_flags, time_req, diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_context.c b/source4/heimdal/lib/gssapi/krb5/inquire_context.c index ef43e6852c..bdaa01b108 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_context.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_context.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: inquire_context.c,v 1.10 2006/10/07 22:15:03 lha Exp $"); +RCSID("$Id: inquire_context.c,v 1.11 2006/11/13 18:02:18 lha Exp $"); OM_uint32 _gsskrb5_inquire_context ( OM_uint32 * minor_status, @@ -47,6 +47,7 @@ OM_uint32 _gsskrb5_inquire_context ( int * open_context ) { + krb5_context context; OM_uint32 ret; gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle; gss_name_t name; @@ -56,6 +57,8 @@ OM_uint32 _gsskrb5_inquire_context ( if (targ_name) *targ_name = GSS_C_NO_NAME; + GSSAPI_KRB5_INIT (&context); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); if (src_name) { @@ -74,6 +77,7 @@ OM_uint32 _gsskrb5_inquire_context ( if (lifetime_rec) { ret = _gsskrb5_lifetime_left(minor_status, + context, ctx->lifetime, lifetime_rec); if (ret) diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_cred.c b/source4/heimdal/lib/gssapi/krb5/inquire_cred.c index 0593729365..74018559a0 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_cred.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: inquire_cred.c,v 1.12 2006/10/07 22:15:06 lha Exp $"); +RCSID("$Id: inquire_cred.c,v 1.13 2006/11/13 18:02:21 lha Exp $"); OM_uint32 _gsskrb5_inquire_cred (OM_uint32 * minor_status, @@ -44,6 +44,7 @@ OM_uint32 _gsskrb5_inquire_cred gss_OID_set * mechanisms ) { + krb5_context context; gss_cred_id_t aqcred_init = GSS_C_NO_CREDENTIAL; gss_cred_id_t aqcred_accept = GSS_C_NO_CREDENTIAL; gsskrb5_cred acred = NULL, icred = NULL; @@ -56,6 +57,8 @@ OM_uint32 _gsskrb5_inquire_cred if (mechanisms) *mechanisms = GSS_C_NO_OID_SET; + GSSAPI_KRB5_INIT (&context); + if (cred_handle == GSS_C_NO_CREDENTIAL) { ret = _gsskrb5_acquire_cred(minor_status, GSS_C_NO_NAME, @@ -105,7 +108,7 @@ OM_uint32 _gsskrb5_inquire_cred goto out; } else if (acred && acred->usage == GSS_C_ACCEPT) { krb5_principal princ; - *minor_status = krb5_sname_to_principal(_gsskrb5_context, NULL, + *minor_status = krb5_sname_to_principal(context, NULL, NULL, KRB5_NT_SRV_HST, &princ); if (*minor_status) { @@ -115,7 +118,7 @@ OM_uint32 _gsskrb5_inquire_cred *output_name = (gss_name_t)princ; } else { krb5_principal princ; - *minor_status = krb5_get_default_principal(_gsskrb5_context, + *minor_status = krb5_get_default_principal(context, &princ); if (*minor_status) { ret = GSS_S_FAILURE; @@ -131,6 +134,7 @@ OM_uint32 _gsskrb5_inquire_cred if (icred) ilife = icred->lifetime; ret = _gsskrb5_lifetime_left(minor_status, + context, min(alife,ilife), lifetime); if (ret) diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c index 26927c740c..1a36896019 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c @@ -32,7 +32,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: inquire_cred_by_oid.c,v 1.4 2006/10/07 22:15:10 lha Exp $"); +RCSID("$Id: inquire_cred_by_oid.c,v 1.5 2006/11/13 18:02:24 lha Exp $"); OM_uint32 _gsskrb5_inquire_cred_by_oid (OM_uint32 * minor_status, @@ -40,11 +40,14 @@ OM_uint32 _gsskrb5_inquire_cred_by_oid const gss_OID desired_object, gss_buffer_set_t *data_set) { + krb5_context context; gsskrb5_cred cred = (gsskrb5_cred)cred_handle; krb5_error_code ret; gss_buffer_desc buffer; char *str; + GSSAPI_KRB5_INIT (&context); + if (gss_oid_equal(desired_object, GSS_KRB5_COPY_CCACHE_X) == 0) { *minor_status = EINVAL; return GSS_S_FAILURE; @@ -58,11 +61,10 @@ OM_uint32 _gsskrb5_inquire_cred_by_oid return GSS_S_FAILURE; } - ret = krb5_cc_get_full_name(_gsskrb5_context, cred->ccache, &str); + ret = krb5_cc_get_full_name(context, cred->ccache, &str); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); if (ret) { *minor_status = ret; - _gsskrb5_set_error_string (); return GSS_S_FAILURE; } diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c b/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c index ee4210d74a..97e86a95c7 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c @@ -32,7 +32,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: inquire_sec_context_by_oid.c,v 1.11 2006/11/07 14:34:35 lha Exp $"); +RCSID("$Id: inquire_sec_context_by_oid.c,v 1.12 2006/11/13 18:02:27 lha Exp $"); static int oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix) @@ -106,6 +106,7 @@ enum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY }; static OM_uint32 inquire_sec_context_get_subkey (OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, enum keytype keytype, gss_buffer_set_t *data_set) { @@ -127,19 +128,13 @@ static OM_uint32 inquire_sec_context_get_subkey HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); switch(keytype) { case ACCEPTOR_KEY: - ret = _gsskrb5i_get_acceptor_subkey(context_handle, &key); - if (ret) - _gsskrb5_set_error_string (); + ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key); break; case INITIATOR_KEY: - ret = _gsskrb5i_get_initiator_subkey(context_handle, &key); - if (ret) - _gsskrb5_set_error_string (); + ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key); break; case TOKEN_KEY: - ret = _gsskrb5i_get_token_key(context_handle, &key); - if (ret) - _gsskrb5_set_error_string (); + ret = _gsskrb5i_get_token_key(context_handle, context, &key); break; default: _gsskrb5_set_status("%d is not a valid subkey type", keytype); @@ -156,17 +151,13 @@ static OM_uint32 inquire_sec_context_get_subkey } ret = krb5_store_keyblock(sp, *key); - krb5_free_keyblock (_gsskrb5_context, key); - if (ret) { - _gsskrb5_set_error_string (); + krb5_free_keyblock (context, key); + if (ret) goto out; - } ret = krb5_storage_to_data(sp, &data); - if (ret) { - _gsskrb5_set_error_string (); + if (ret) goto out; - } { gss_buffer_desc value; @@ -193,6 +184,7 @@ out: static OM_uint32 inquire_sec_context_authz_data (OM_uint32 *minor_status, const gsskrb5_ctx context_handle, + krb5_context context, unsigned ad_type, gss_buffer_set_t *data_set) { @@ -211,13 +203,12 @@ static OM_uint32 inquire_sec_context_authz_data return GSS_S_NO_CONTEXT; } - ret = krb5_ticket_get_authorization_data_type(_gsskrb5_context, + ret = krb5_ticket_get_authorization_data_type(context, context_handle->ticket, ad_type, &data); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } @@ -276,6 +267,7 @@ static OM_uint32 inquire_sec_context_has_updated_spnego static OM_uint32 export_lucid_sec_context_v1(OM_uint32 *minor_status, gsskrb5_ctx context_handle, + krb5_context context, gss_buffer_set_t *data_set) { krb5_storage *sp = NULL; @@ -288,8 +280,6 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status, *minor_status = 0; - GSSAPI_KRB5_INIT (); - HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); _gsskrb5i_is_cfx(context_handle, &is_cfx); @@ -307,12 +297,12 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status, if (ret) goto out; ret = krb5_store_int32(sp, context_handle->lifetime); if (ret) goto out; - krb5_auth_con_getlocalseqnumber (_gsskrb5_context, + krb5_auth_con_getlocalseqnumber (context, context_handle->auth_context, &number); ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ ret = krb5_store_uint32(sp, (uint32_t)number); - krb5_auth_getremoteseqnumber (_gsskrb5_context, + krb5_auth_getremoteseqnumber (context, context_handle->auth_context, &number); ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ @@ -320,7 +310,7 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status, ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0); if (ret) goto out; - ret = _gsskrb5i_get_token_key(context_handle, &key); + ret = _gsskrb5i_get_token_key(context_handle, context, &key); if (ret) goto out; if (is_cfx == 0) { @@ -387,7 +377,7 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status, out: if (key) - krb5_free_keyblock (_gsskrb5_context, key); + krb5_free_keyblock (context, key); if (sp) krb5_storage_free(sp); if (ret) { @@ -485,7 +475,6 @@ out: if (sp) krb5_storage_free(sp); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; maj_stat = GSS_S_FAILURE; } @@ -501,6 +490,7 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid const gss_OID desired_object, gss_buffer_set_t *data_set) { + krb5_context context; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; unsigned suffix; @@ -509,6 +499,8 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid return GSS_S_NO_CONTEXT; } + GSSAPI_KRB5_INIT (&context); + if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) { return inquire_sec_context_tkt_flags(minor_status, ctx, @@ -520,16 +512,19 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) { return inquire_sec_context_get_subkey(minor_status, ctx, + context, TOKEN_KEY, data_set); } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) { return inquire_sec_context_get_subkey(minor_status, ctx, + context, INITIATOR_KEY, data_set); } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) { return inquire_sec_context_get_subkey(minor_status, ctx, + context, ACCEPTOR_KEY, data_set); } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) { @@ -539,6 +534,7 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid &suffix)) { return inquire_sec_context_authz_data(minor_status, ctx, + context, suffix, data_set); } else if (oid_prefix_equal(desired_object, @@ -547,6 +543,7 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid if (suffix == 1) return export_lucid_sec_context_v1(minor_status, ctx, + context, data_set); *minor_status = 0; return GSS_S_FAILURE; diff --git a/source4/heimdal/lib/gssapi/krb5/process_context_token.c b/source4/heimdal/lib/gssapi/krb5/process_context_token.c index 99568c9dd0..411d689635 100644 --- a/source4/heimdal/lib/gssapi/krb5/process_context_token.c +++ b/source4/heimdal/lib/gssapi/krb5/process_context_token.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: process_context_token.c,v 1.4 2006/10/07 22:15:19 lha Exp $"); +RCSID("$Id: process_context_token.c,v 1.5 2006/11/13 18:02:30 lha Exp $"); OM_uint32 _gsskrb5_process_context_token ( OM_uint32 *minor_status, @@ -41,6 +41,7 @@ OM_uint32 _gsskrb5_process_context_token ( const gss_buffer_t token_buffer ) { + krb5_context context; OM_uint32 ret = GSS_S_FAILURE; gss_buffer_desc empty_buffer; gss_qop_t qop_state; @@ -48,10 +49,13 @@ OM_uint32 _gsskrb5_process_context_token ( empty_buffer.length = 0; empty_buffer.value = NULL; + GSSAPI_KRB5_INIT (&context); + qop_state = GSS_C_QOP_DEFAULT; ret = _gsskrb5_verify_mic_internal(minor_status, (gsskrb5_ctx)context_handle, + context, token_buffer, &empty_buffer, GSS_C_QOP_DEFAULT, "\x01\x02"); diff --git a/source4/heimdal/lib/gssapi/krb5/release_cred.c b/source4/heimdal/lib/gssapi/krb5/release_cred.c index 662461ccfd..f6d98b29c6 100644 --- a/source4/heimdal/lib/gssapi/krb5/release_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/release_cred.c @@ -33,13 +33,14 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: release_cred.c,v 1.13 2006/10/07 22:15:24 lha Exp $"); +RCSID("$Id: release_cred.c,v 1.14 2006/11/13 18:02:34 lha Exp $"); OM_uint32 _gsskrb5_release_cred (OM_uint32 * minor_status, gss_cred_id_t * cred_handle ) { + krb5_context context; gsskrb5_cred cred; *minor_status = 0; @@ -50,21 +51,21 @@ OM_uint32 _gsskrb5_release_cred cred = (gsskrb5_cred)*cred_handle; *cred_handle = GSS_C_NO_CREDENTIAL; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); if (cred->principal != NULL) - krb5_free_principal(_gsskrb5_context, cred->principal); + krb5_free_principal(context, cred->principal); if (cred->keytab != NULL) - krb5_kt_close(_gsskrb5_context, cred->keytab); + krb5_kt_close(context, cred->keytab); if (cred->ccache != NULL) { const krb5_cc_ops *ops; - ops = krb5_cc_get_ops(_gsskrb5_context, cred->ccache); + ops = krb5_cc_get_ops(context, cred->ccache); if (cred->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) - krb5_cc_destroy(_gsskrb5_context, cred->ccache); + krb5_cc_destroy(context, cred->ccache); else - krb5_cc_close(_gsskrb5_context, cred->ccache); + krb5_cc_close(context, cred->ccache); } _gsskrb5_release_oid_set(NULL, &cred->mechanisms); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); diff --git a/source4/heimdal/lib/gssapi/krb5/release_name.c b/source4/heimdal/lib/gssapi/krb5/release_name.c index a92ad939a5..cc9c0934f7 100644 --- a/source4/heimdal/lib/gssapi/krb5/release_name.c +++ b/source4/heimdal/lib/gssapi/krb5/release_name.c @@ -33,23 +33,24 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: release_name.c,v 1.10 2006/10/07 22:15:26 lha Exp $"); +RCSID("$Id: release_name.c,v 1.11 2006/11/13 18:02:37 lha Exp $"); OM_uint32 _gsskrb5_release_name (OM_uint32 * minor_status, gss_name_t * input_name ) { + krb5_context context; krb5_principal name = (krb5_principal)*input_name; - GSSAPI_KRB5_INIT (); - if (minor_status) *minor_status = 0; + GSSAPI_KRB5_INIT (&context); + *input_name = GSS_C_NO_NAME; - krb5_free_principal(_gsskrb5_context, name); + krb5_free_principal(context, name); return GSS_S_COMPLETE; } diff --git a/source4/heimdal/lib/gssapi/krb5/set_cred_option.c b/source4/heimdal/lib/gssapi/krb5/set_cred_option.c index 5807ef0166..849760ee4a 100644 --- a/source4/heimdal/lib/gssapi/krb5/set_cred_option.c +++ b/source4/heimdal/lib/gssapi/krb5/set_cred_option.c @@ -32,7 +32,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: set_cred_option.c,v 1.4 2006/10/24 20:14:13 lha Exp $"); +RCSID("$Id: set_cred_option.c,v 1.5 2006/11/13 18:02:39 lha Exp $"); static gss_OID_desc gss_krb5_import_cred_x_oid_desc = {9, (void *)"\x2b\x06\x01\x04\x01\xa9\x4a\x13\x04"}; /* XXX */ @@ -41,6 +41,7 @@ gss_OID GSS_KRB5_IMPORT_CRED_X = &gss_krb5_import_cred_x_oid_desc; static OM_uint32 import_cred(OM_uint32 *minor_status, + krb5_context context, gss_cred_id_t *cred_handle, const gss_buffer_t value) { @@ -71,7 +72,7 @@ import_cred(OM_uint32 *minor_status, goto out; } if (str[0]) { - ret = krb5_cc_resolve(_gsskrb5_context, str, &id); + ret = krb5_cc_resolve(context, str, &id); if (ret) { *minor_status = ret; major_stat = GSS_S_FAILURE; @@ -84,7 +85,7 @@ import_cred(OM_uint32 *minor_status, /* keytab principal name */ ret = krb5_ret_string(sp, &str); if (ret == 0 && str[0]) - ret = krb5_parse_name(_gsskrb5_context, str, &keytab_principal); + ret = krb5_parse_name(context, str, &keytab_principal); if (ret) { *minor_status = ret; major_stat = GSS_S_FAILURE; @@ -101,7 +102,7 @@ import_cred(OM_uint32 *minor_status, goto out; } if (str[0]) { - ret = krb5_kt_resolve(_gsskrb5_context, str, &keytab); + ret = krb5_kt_resolve(context, str, &keytab); if (ret) { *minor_status = ret; major_stat = GSS_S_FAILURE; @@ -115,11 +116,11 @@ import_cred(OM_uint32 *minor_status, keytab, cred_handle); out: if (id) - krb5_cc_close(_gsskrb5_context, id); + krb5_cc_close(context, id); if (keytab_principal) - krb5_free_principal(_gsskrb5_context, keytab_principal); + krb5_free_principal(context, keytab_principal); if (keytab) - krb5_kt_close(_gsskrb5_context, keytab); + krb5_kt_close(context, keytab); if (str) free(str); if (sp) @@ -136,7 +137,9 @@ _gsskrb5_set_cred_option const gss_OID desired_object, const gss_buffer_t value) { - GSSAPI_KRB5_INIT (); + krb5_context context; + + GSSAPI_KRB5_INIT (&context); if (value == GSS_C_NO_BUFFER) { *minor_status = EINVAL; @@ -144,7 +147,7 @@ _gsskrb5_set_cred_option } if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_CRED_X)) { - return import_cred(minor_status, cred_handle, value); + return import_cred(minor_status, context, cred_handle, value); } *minor_status = EINVAL; diff --git a/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c b/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c index dc1495efc1..4a5f60ce94 100644 --- a/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c +++ b/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c @@ -36,7 +36,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: set_sec_context_option.c,v 1.8 2006/11/08 23:06:42 lha Exp $"); +RCSID("$Id: set_sec_context_option.c,v 1.10 2006/12/14 11:02:16 lha Exp $"); static OM_uint32 get_bool(OM_uint32 *minor_status, @@ -58,9 +58,10 @@ _gsskrb5_set_sec_context_option const gss_OID desired_object, const gss_buffer_t value) { + krb5_context context; OM_uint32 maj_stat; - GSSAPI_KRB5_INIT (); + GSSAPI_KRB5_INIT (&context); if (value == GSS_C_NO_BUFFER) { *minor_status = EINVAL; @@ -96,7 +97,7 @@ _gsskrb5_set_sec_context_option if (maj_stat != GSS_S_COMPLETE) return maj_stat; - krb5_set_dns_canonicalize_hostname(_gsskrb5_context, flag); + krb5_set_dns_canonicalize_hostname(context, flag); return GSS_S_COMPLETE; } else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) { @@ -128,14 +129,14 @@ _gsskrb5_set_sec_context_option return GSS_S_CALL_INACCESSIBLE_READ; } str = malloc(value->length + 1); - if (str) { + if (str == NULL) { *minor_status = 0; return GSS_S_UNAVAILABLE; } memcpy(str, value->value, value->length); str[value->length] = '\0'; - krb5_set_default_realm(_gsskrb5_context, str); + krb5_set_default_realm(context, str); free(str); *minor_status = 0; @@ -144,7 +145,7 @@ _gsskrb5_set_sec_context_option } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) { if (value == NULL || value->length == 0) { - krb5_set_send_to_kdc_func(_gsskrb5_context, NULL, NULL); + krb5_set_send_to_kdc_func(context, NULL, NULL); } else { struct gsskrb5_send_to_kdc c; @@ -153,7 +154,7 @@ _gsskrb5_set_sec_context_option return GSS_S_FAILURE; } memcpy(&c, value->value, sizeof(c)); - krb5_set_send_to_kdc_func(_gsskrb5_context, + krb5_set_send_to_kdc_func(context, (krb5_send_to_kdc_func)c.func, c.ptr); } diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c index 758390080c..3dd7618561 100644 --- a/source4/heimdal/lib/gssapi/krb5/unwrap.c +++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: unwrap.c,v 1.38 2006/10/18 15:59:28 lha Exp $"); +RCSID("$Id: unwrap.c,v 1.39 2006/11/13 18:02:51 lha Exp $"); static OM_uint32 unwrap_des @@ -175,6 +175,7 @@ static OM_uint32 unwrap_des3 (OM_uint32 * minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, @@ -226,18 +227,16 @@ unwrap_des3 /* decrypt data */ krb5_data tmp; - ret = krb5_crypto_init(_gsskrb5_context, key, + ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } - ret = krb5_decrypt(_gsskrb5_context, crypto, KRB5_KU_USAGE_SEAL, + ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL, p, input_message_buffer->length - len, &tmp); - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } @@ -259,10 +258,9 @@ unwrap_des3 p -= 28; - ret = krb5_crypto_init(_gsskrb5_context, key, + ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_FAILURE; @@ -271,15 +269,14 @@ unwrap_des3 DES_cblock ivec; memcpy(&ivec, p + 8, 8); - ret = krb5_decrypt_ivec (_gsskrb5_context, + ret = krb5_decrypt_ivec (context, crypto, KRB5_KU_USAGE_SEQ, p, 8, &seq_data, &ivec); } - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_FAILURE; @@ -325,21 +322,19 @@ unwrap_des3 csum.checksum.length = 20; csum.checksum.data = cksum; - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } - ret = krb5_verify_checksum (_gsskrb5_context, crypto, + ret = krb5_verify_checksum (context, crypto, KRB5_KU_USAGE_SIGN, p + 20, input_message_buffer->length - len + 8, &csum); - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } @@ -367,6 +362,7 @@ OM_uint32 _gsskrb5_unwrap ) { krb5_keyblock *key; + krb5_context context; OM_uint32 ret; krb5_keytype keytype; gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; @@ -374,17 +370,18 @@ OM_uint32 _gsskrb5_unwrap output_message_buffer->value = NULL; output_message_buffer->length = 0; + GSSAPI_KRB5_INIT (&context); + if (qop_state != NULL) *qop_state = GSS_C_QOP_DEFAULT; HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - ret = _gsskrb5i_get_token_key(ctx, &key); + ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype); + krb5_enctype_to_keytype (context, key->keytype, &keytype); *minor_status = 0; @@ -395,22 +392,22 @@ OM_uint32 _gsskrb5_unwrap conf_state, qop_state, key); break; case KEYTYPE_DES3 : - ret = unwrap_des3 (minor_status, ctx, + ret = unwrap_des3 (minor_status, ctx, context, input_message_buffer, output_message_buffer, conf_state, qop_state, key); break; case KEYTYPE_ARCFOUR: case KEYTYPE_ARCFOUR_56: - ret = _gssapi_unwrap_arcfour (minor_status, ctx, + ret = _gssapi_unwrap_arcfour (minor_status, ctx, context, input_message_buffer, output_message_buffer, conf_state, qop_state, key); break; default : - ret = _gssapi_unwrap_cfx (minor_status, ctx, + ret = _gssapi_unwrap_cfx (minor_status, ctx, context, input_message_buffer, output_message_buffer, conf_state, qop_state, key); break; } - krb5_free_keyblock (_gsskrb5_context, key); + krb5_free_keyblock (context, key); return ret; } diff --git a/source4/heimdal/lib/gssapi/krb5/verify_mic.c b/source4/heimdal/lib/gssapi/krb5/verify_mic.c index 920937cafc..29b3a7f4bb 100644 --- a/source4/heimdal/lib/gssapi/krb5/verify_mic.c +++ b/source4/heimdal/lib/gssapi/krb5/verify_mic.c @@ -33,12 +33,13 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: verify_mic.c,v 1.36 2006/10/18 15:59:30 lha Exp $"); +RCSID("$Id: verify_mic.c,v 1.37 2006/11/13 18:02:54 lha Exp $"); static OM_uint32 verify_mic_des (OM_uint32 * minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, gss_qop_t * qop_state, @@ -131,6 +132,7 @@ static OM_uint32 verify_mic_des3 (OM_uint32 * minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, gss_qop_t * qop_state, @@ -164,10 +166,9 @@ verify_mic_des3 return GSS_S_BAD_MIC; p += 4; - ret = krb5_crypto_init(_gsskrb5_context, key, + ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (ret){ - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } @@ -180,14 +181,13 @@ retry: else memcpy(ivec, p + 8, 8); - ret = krb5_decrypt_ivec (_gsskrb5_context, + ret = krb5_decrypt_ivec (context, crypto, KRB5_KU_USAGE_SEQ, p, 8, &seq_data, ivec); if (ret) { if (docompat++) { - _gsskrb5_set_error_string (); - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); *minor_status = ret; return GSS_S_FAILURE; } else @@ -197,7 +197,7 @@ retry: if (seq_data.length != 8) { krb5_data_free (&seq_data); if (docompat++) { - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); return GSS_S_BAD_MIC; } else goto retry; @@ -215,7 +215,7 @@ retry: krb5_data_free (&seq_data); if (cmp != 0) { - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); *minor_status = 0; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_BAD_MIC; @@ -223,7 +223,7 @@ retry: ret = _gssapi_msg_order_check(context_handle->order, seq_number); if (ret) { - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); *minor_status = 0; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return ret; @@ -233,7 +233,7 @@ retry: tmp = malloc (message_buffer->length + 8); if (tmp == NULL) { - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); *minor_status = ENOMEM; return GSS_S_FAILURE; @@ -246,21 +246,20 @@ retry: csum.checksum.length = 20; csum.checksum.data = p + 8; - ret = krb5_verify_checksum (_gsskrb5_context, crypto, + ret = krb5_verify_checksum (context, crypto, KRB5_KU_USAGE_SIGN, tmp, message_buffer->length + 8, &csum); free (tmp); if (ret) { - _gsskrb5_set_error_string (); - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); *minor_status = ret; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_BAD_MIC; } HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); return GSS_S_COMPLETE; } @@ -268,6 +267,7 @@ OM_uint32 _gsskrb5_verify_mic_internal (OM_uint32 * minor_status, const gsskrb5_ctx context_handle, + krb5_context context, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, gss_qop_t * qop_state, @@ -279,39 +279,40 @@ _gsskrb5_verify_mic_internal krb5_keytype keytype; HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - ret = _gsskrb5i_get_token_key(context_handle, &key); + ret = _gsskrb5i_get_token_key(context_handle, context, &key); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } *minor_status = 0; - krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype); + krb5_enctype_to_keytype (context, key->keytype, &keytype); switch (keytype) { case KEYTYPE_DES : - ret = verify_mic_des (minor_status, context_handle, + ret = verify_mic_des (minor_status, context_handle, context, message_buffer, token_buffer, qop_state, key, type); break; case KEYTYPE_DES3 : - ret = verify_mic_des3 (minor_status, context_handle, + ret = verify_mic_des3 (minor_status, context_handle, context, message_buffer, token_buffer, qop_state, key, type); break; case KEYTYPE_ARCFOUR : case KEYTYPE_ARCFOUR_56 : ret = _gssapi_verify_mic_arcfour (minor_status, context_handle, + context, message_buffer, token_buffer, qop_state, key, type); break; default : ret = _gssapi_verify_mic_cfx (minor_status, context_handle, + context, message_buffer, token_buffer, qop_state, key); break; } - krb5_free_keyblock (_gsskrb5_context, key); + krb5_free_keyblock (context, key); return ret; } @@ -325,13 +326,17 @@ _gsskrb5_verify_mic gss_qop_t * qop_state ) { + krb5_context context; OM_uint32 ret; + GSSAPI_KRB5_INIT (&context); + if (qop_state != NULL) *qop_state = GSS_C_QOP_DEFAULT; ret = _gsskrb5_verify_mic_internal(minor_status, - (gsskrb5_ctx)context_handle, + (gsskrb5_ctx)context_handle, + context, message_buffer, token_buffer, qop_state, "\x01\x01"); diff --git a/source4/heimdal/lib/gssapi/krb5/wrap.c b/source4/heimdal/lib/gssapi/krb5/wrap.c index ebbc975b8a..79cfb48ed2 100644 --- a/source4/heimdal/lib/gssapi/krb5/wrap.c +++ b/source4/heimdal/lib/gssapi/krb5/wrap.c @@ -33,74 +33,80 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: wrap.c,v 1.37 2006/10/18 15:59:33 lha Exp $"); +RCSID("$Id: wrap.c,v 1.39 2006/11/14 09:49:56 lha Exp $"); /* * Return initiator subkey, or if that doesn't exists, the subkey. */ krb5_error_code -_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx, krb5_keyblock **key) +_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) { krb5_error_code ret; *key = NULL; if (ctx->more_flags & LOCAL) { - ret = krb5_auth_con_getlocalsubkey(_gsskrb5_context, + ret = krb5_auth_con_getlocalsubkey(context, ctx->auth_context, key); } else { - ret = krb5_auth_con_getremotesubkey(_gsskrb5_context, + ret = krb5_auth_con_getremotesubkey(context, ctx->auth_context, key); } - if (*key == NULL) - ret = krb5_auth_con_getkey(_gsskrb5_context, + if (ret == 0 && *key == NULL) + ret = krb5_auth_con_getkey(context, ctx->auth_context, key); - if (*key == NULL) { - _gsskrb5_set_status("No initiator subkey available"); + if (ret == 0 && *key == NULL) { + krb5_set_error_string(context, "No initiator subkey available"); return GSS_KRB5_S_KG_NO_SUBKEY; } return ret; } krb5_error_code -_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx, krb5_keyblock **key) +_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) { krb5_error_code ret; *key = NULL; if (ctx->more_flags & LOCAL) { - ret = krb5_auth_con_getremotesubkey(_gsskrb5_context, + ret = krb5_auth_con_getremotesubkey(context, ctx->auth_context, key); } else { - ret = krb5_auth_con_getlocalsubkey(_gsskrb5_context, + ret = krb5_auth_con_getlocalsubkey(context, ctx->auth_context, key); } - if (*key == NULL) { - _gsskrb5_set_status("No acceptor subkey available"); + if (ret == 0 && *key == NULL) { + krb5_set_error_string(context, "No acceptor subkey available"); return GSS_KRB5_S_KG_NO_SUBKEY; } return ret; } OM_uint32 -_gsskrb5i_get_token_key(const gsskrb5_ctx ctx, krb5_keyblock **key) +_gsskrb5i_get_token_key(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) { - _gsskrb5i_get_acceptor_subkey(ctx, key); + _gsskrb5i_get_acceptor_subkey(ctx, context, key); if(*key == NULL) { /* * Only use the initiator subkey or ticket session key if an * acceptor subkey was not required. */ if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0) - _gsskrb5i_get_initiator_subkey(ctx, key); + _gsskrb5i_get_initiator_subkey(ctx, context, key); } if (*key == NULL) { - _gsskrb5_set_status("No token key available"); + krb5_set_error_string(context, "No token key available"); return GSS_KRB5_S_KG_NO_SUBKEY; } return 0; @@ -140,20 +146,22 @@ _gsskrb5_wrap_size_limit ( OM_uint32 * max_input_size ) { + krb5_context context; krb5_keyblock *key; OM_uint32 ret; krb5_keytype keytype; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + GSSAPI_KRB5_INIT (&context); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - ret = _gsskrb5i_get_token_key(ctx, &key); + ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype); + krb5_enctype_to_keytype (context, key->keytype, &keytype); switch (keytype) { case KEYTYPE_DES : @@ -161,7 +169,7 @@ _gsskrb5_wrap_size_limit ( break; case KEYTYPE_ARCFOUR: case KEYTYPE_ARCFOUR_56: - ret = _gssapi_wrap_size_arcfour(minor_status, ctx, + ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context, conf_req_flag, qop_req, req_output_size, max_input_size, key); break; @@ -169,12 +177,12 @@ _gsskrb5_wrap_size_limit ( ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); break; default : - ret = _gssapi_wrap_size_cfx(minor_status, ctx, + ret = _gssapi_wrap_size_cfx(minor_status, ctx, context, conf_req_flag, qop_req, req_output_size, max_input_size, key); break; } - krb5_free_keyblock (_gsskrb5_context, key); + krb5_free_keyblock (context, key); *minor_status = 0; return ret; } @@ -183,6 +191,7 @@ static OM_uint32 wrap_des (OM_uint32 * minor_status, const gsskrb5_ctx ctx, + krb5_context context, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, @@ -257,9 +266,9 @@ wrap_des /* sequence number */ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - krb5_auth_con_getlocalseqnumber (_gsskrb5_context, - ctx->auth_context, - &seq_number); + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); p -= 16; p[0] = (seq_number >> 0) & 0xFF; @@ -274,7 +283,7 @@ wrap_des DES_cbc_encrypt ((void *)p, (void *)p, 8, &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT); - krb5_auth_con_setlocalseqnumber (_gsskrb5_context, + krb5_auth_con_setlocalseqnumber (context, ctx->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -309,6 +318,7 @@ static OM_uint32 wrap_des3 (OM_uint32 * minor_status, const gsskrb5_ctx ctx, + krb5_context context, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, @@ -365,9 +375,8 @@ wrap_des3 input_message_buffer->length); memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength); - ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { - _gsskrb5_set_error_string (); free (output_message_buffer->value); output_message_buffer->length = 0; output_message_buffer->value = NULL; @@ -375,16 +384,15 @@ wrap_des3 return GSS_S_FAILURE; } - ret = krb5_create_checksum (_gsskrb5_context, + ret = krb5_create_checksum (context, crypto, KRB5_KU_USAGE_SIGN, 0, p + 20, datalen + 8, &cksum); - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); if (ret) { - _gsskrb5_set_error_string (); free (output_message_buffer->value); output_message_buffer->length = 0; output_message_buffer->value = NULL; @@ -400,7 +408,7 @@ wrap_des3 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); /* sequence number */ - krb5_auth_con_getlocalseqnumber (_gsskrb5_context, + krb5_auth_con_getlocalseqnumber (context, ctx->auth_context, &seq_number); @@ -413,7 +421,7 @@ wrap_des3 4); - ret = krb5_crypto_init(_gsskrb5_context, key, ETYPE_DES3_CBC_NONE, + ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (ret) { free (output_message_buffer->value); @@ -427,15 +435,14 @@ wrap_des3 DES_cblock ivec; memcpy (&ivec, p + 8, 8); - ret = krb5_encrypt_ivec (_gsskrb5_context, + ret = krb5_encrypt_ivec (context, crypto, KRB5_KU_USAGE_SEQ, seq, 8, &encdata, &ivec); } - krb5_crypto_destroy (_gsskrb5_context, crypto); + krb5_crypto_destroy (context, crypto); if (ret) { - _gsskrb5_set_error_string (); free (output_message_buffer->value); output_message_buffer->length = 0; output_message_buffer->value = NULL; @@ -448,7 +455,7 @@ wrap_des3 memcpy (p, encdata.data, encdata.length); krb5_data_free (&encdata); - krb5_auth_con_setlocalseqnumber (_gsskrb5_context, + krb5_auth_con_setlocalseqnumber (context, ctx->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -459,21 +466,19 @@ wrap_des3 if(conf_req_flag) { krb5_data tmp; - ret = krb5_crypto_init(_gsskrb5_context, key, + ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (ret) { - _gsskrb5_set_error_string (); free (output_message_buffer->value); output_message_buffer->length = 0; output_message_buffer->value = NULL; *minor_status = ret; return GSS_S_FAILURE; } - ret = krb5_encrypt(_gsskrb5_context, crypto, KRB5_KU_USAGE_SEAL, + ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL, p, datalen, &tmp); - krb5_crypto_destroy(_gsskrb5_context, crypto); + krb5_crypto_destroy(context, crypto); if (ret) { - _gsskrb5_set_error_string (); free (output_message_buffer->value); output_message_buffer->length = 0; output_message_buffer->value = NULL; @@ -501,44 +506,46 @@ OM_uint32 _gsskrb5_wrap gss_buffer_t output_message_buffer ) { + krb5_context context; krb5_keyblock *key; OM_uint32 ret; krb5_keytype keytype; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + GSSAPI_KRB5_INIT (&context); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - ret = _gsskrb5i_get_token_key(ctx, &key); + ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); if (ret) { - _gsskrb5_set_error_string (); *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype); + krb5_enctype_to_keytype (context, key->keytype, &keytype); switch (keytype) { case KEYTYPE_DES : - ret = wrap_des (minor_status, ctx, conf_req_flag, + ret = wrap_des (minor_status, ctx, context, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer, key); break; case KEYTYPE_DES3 : - ret = wrap_des3 (minor_status, ctx, conf_req_flag, + ret = wrap_des3 (minor_status, ctx, context, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer, key); break; case KEYTYPE_ARCFOUR: case KEYTYPE_ARCFOUR_56: - ret = _gssapi_wrap_arcfour (minor_status, ctx, conf_req_flag, + ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer, key); break; default : - ret = _gssapi_wrap_cfx (minor_status, ctx, conf_req_flag, + ret = _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer, key); break; } - krb5_free_keyblock (_gsskrb5_context, key); + krb5_free_keyblock (context, key); return ret; } diff --git a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c index 73207806a0..7df8a3483e 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c +++ b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_accept_sec_context.c,v 1.7 2006/11/10 03:30:12 lha Exp $"); +RCSID("$Id: gss_accept_sec_context.c,v 1.9 2006/12/15 20:12:20 lha Exp $"); static OM_uint32 parse_header(const gss_buffer_t input_token, gss_OID mech_oid) @@ -91,6 +91,8 @@ parse_header(const gss_buffer_t input_token, gss_OID mech_oid) static gss_OID_desc krb5_mechanism = {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")}; +static gss_OID_desc ntlm_mechanism = + {10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")}; static gss_OID_desc spnego_mechanism = {6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02")}; @@ -112,7 +114,14 @@ choose_mech(const gss_buffer_t input, gss_OID mech_oid) * Lets guess what mech is really is, callback function to mech ?? */ - if (input->length != 0 && ((const char *)input->value)[0] == 0x6E) { + if (input->length > 8 && + memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0) + { + *mech_oid = ntlm_mechanism; + return GSS_S_COMPLETE; + } else if (input->length != 0 && + ((const char *)input->value)[0] == 0x6E) + { /* Could be a raw AP-REQ (check for APPLICATION tag) */ *mech_oid = krb5_mechanism; return GSS_S_COMPLETE; diff --git a/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c b/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c index ccaf91ba9d..0d50bbd92b 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c +++ b/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c @@ -27,7 +27,23 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_init_sec_context.c,v 1.3 2006/07/06 22:30:09 lha Exp $"); +RCSID("$Id: gss_init_sec_context.c,v 1.4 2006/11/14 12:33:11 lha Exp $"); + +static gss_cred_id_t +_gss_mech_cred_find(gss_cred_id_t cred_handle, gss_OID mech_type) +{ + struct _gss_cred *cred = (struct _gss_cred *)cred_handle; + struct _gss_mechanism_cred *mc; + + if (cred == NULL) + return GSS_C_NO_CREDENTIAL; + + SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { + if (gss_oid_equal(mech_type, mc->gmc_mech_oid)) + return mc->gmc_cred; + } + return GSS_C_NO_CREDENTIAL; +} OM_uint32 gss_init_sec_context(OM_uint32 * minor_status, @@ -49,8 +65,6 @@ gss_init_sec_context(OM_uint32 * minor_status, struct _gss_name *name = (struct _gss_name *) target_name; struct _gss_mechanism_name *mn; struct _gss_context *ctx = (struct _gss_context *) *context_handle; - struct _gss_cred *cred = (struct _gss_cred *) initiator_cred_handle; - struct _gss_mechanism_cred *mc; gss_cred_id_t cred_handle; int allocated_ctx; gss_OID mech_type = input_mech_type; @@ -97,15 +111,7 @@ gss_init_sec_context(OM_uint32 * minor_status, /* * If we have a cred, find the cred for this mechanism. */ - cred_handle = GSS_C_NO_CREDENTIAL; - if (cred) { - SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { - if (gss_oid_equal(mech_type, mc->gmc_mech_oid)) { - cred_handle = mc->gmc_cred; - break; - } - } - } + cred_handle = _gss_mech_cred_find(initiator_cred_handle, mech_type); major_status = m->gm_init_sec_context(minor_status, cred_handle, diff --git a/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c b/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c index 3d01ba69d4..b8fdefdca1 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c +++ b/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c @@ -28,7 +28,7 @@ #include "mech_locl.h" #include <heim_threads.h> -RCSID("$Id: gss_mech_switch.c,v 1.7 2006/10/09 11:13:30 lha Exp $"); +RCSID("$Id: gss_mech_switch.c,v 1.8 2006/12/15 20:05:43 lha Exp $"); #ifndef _PATH_GSS_MECH #define _PATH_GSS_MECH "/etc/gss/mech" @@ -169,6 +169,8 @@ add_builtin(gssapi_mech_interface mech) { struct _gss_mech_switch *m; OM_uint32 minor_status; + if (!mech) + return 0; m = malloc(sizeof(*m)); if (m == NULL) @@ -214,6 +216,7 @@ _gss_load_mech(void) add_builtin(__gss_krb5_initialize()); add_builtin(__gss_spnego_initialize()); + add_builtin(__gss_ntlm_initialize()); fp = fopen(_PATH_GSS_MECH, "r"); if (!fp) { diff --git a/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c b/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c index f8e013da18..f813d72ac8 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c +++ b/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c @@ -31,7 +31,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_set_cred_option.c,v 1.7 2006/07/01 08:50:49 lha Exp $"); +RCSID("$Id: gss_set_cred_option.c,v 1.8 2006/11/13 08:59:43 lha Exp $"); OM_uint32 gss_set_cred_option (OM_uint32 *minor_status, @@ -102,7 +102,7 @@ gss_set_cred_option (OM_uint32 *minor_status, major_status = m->gm_set_cred_option(minor_status, &mc->gmc_cred, object, value); - if (major_status == GSS_S_BAD_MECH) + if (major_status == GSS_S_COMPLETE) one_ok = 1; } } diff --git a/source4/heimdal/lib/gssapi/mech/gss_utils.c b/source4/heimdal/lib/gssapi/mech/gss_utils.c index 33ee033209..d674fb163b 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_utils.c +++ b/source4/heimdal/lib/gssapi/mech/gss_utils.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_utils.c,v 1.2 2006/06/28 09:00:25 lha Exp $"); +RCSID("$Id: gss_utils.c,v 1.3 2006/12/18 13:01:25 lha Exp $"); OM_uint32 _gss_copy_oid(OM_uint32 *minor_status, @@ -46,6 +46,17 @@ _gss_copy_oid(OM_uint32 *minor_status, return (GSS_S_COMPLETE); } +OM_uint32 +_gss_free_oid(OM_uint32 *minor_status, gss_OID oid) +{ + *minor_status = 0; + if (oid->elements) { + free(oid->elements); + oid->elements = NULL; + oid->length = 0; + } + return (GSS_S_COMPLETE); +} OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status, diff --git a/source4/heimdal/lib/gssapi/mech/utils.h b/source4/heimdal/lib/gssapi/mech/utils.h index 75a507298c..42e92c3f42 100644 --- a/source4/heimdal/lib/gssapi/mech/utils.h +++ b/source4/heimdal/lib/gssapi/mech/utils.h @@ -24,9 +24,10 @@ * SUCH DAMAGE. * * $FreeBSD: src/lib/libgssapi/utils.h,v 1.1 2005/12/29 14:40:20 dfr Exp $ - * $Id: utils.h,v 1.3 2006/07/20 01:48:25 lha Exp $ + * $Id: utils.h,v 1.4 2006/12/18 13:01:40 lha Exp $ */ +OM_uint32 _gss_free_oid(OM_uint32 *, gss_OID); OM_uint32 _gss_copy_oid(OM_uint32 *, const gss_OID, gss_OID); OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status, const gss_buffer_t from_buf, gss_buffer_t to_buf); diff --git a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c index 8a885a3e2f..2c86b3f794 100644 --- a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c +++ b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * Portions Copyright (c) 2004 PADL Software Pty Ltd. * @@ -33,203 +33,85 @@ #include "spnego/spnego_locl.h" -RCSID("$Id: accept_sec_context.c,v 1.6 2006/10/07 22:26:57 lha Exp $"); - -OM_uint32 -_gss_spnego_encode_response(OM_uint32 *minor_status, - const NegTokenResp *resp, - gss_buffer_t data, - u_char **ret_buf) -{ - OM_uint32 ret; - u_char *buf; - size_t buf_size, buf_len; - - buf_size = 1024; - buf = malloc(buf_size); - if (buf == NULL) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - - do { - ret = encode_NegTokenResp(buf + buf_size - 1, - buf_size, - resp, &buf_len); - if (ret == 0) { - size_t tmp; - - ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, - buf_size - buf_len, - buf_len, - ASN1_C_CONTEXT, - CONS, - 1, - &tmp); - if (ret == 0) - buf_len += tmp; - } - if (ret) { - if (ret == ASN1_OVERFLOW) { - u_char *tmp; - - buf_size *= 2; - tmp = realloc (buf, buf_size); - if (tmp == NULL) { - *minor_status = ENOMEM; - free(buf); - return GSS_S_FAILURE; - } - buf = tmp; - } else { - *minor_status = ret; - free(buf); - return GSS_S_FAILURE; - } - } - } while (ret == ASN1_OVERFLOW); - - data->value = buf + buf_size - buf_len; - data->length = buf_len; - *ret_buf = buf; - - return GSS_S_COMPLETE; -} +RCSID("$Id: accept_sec_context.c,v 1.16 2006/12/19 12:10:35 lha Exp $"); static OM_uint32 send_reject (OM_uint32 *minor_status, gss_buffer_t output_token) { - NegTokenResp resp; - gss_buffer_desc data; - u_char *buf; - OM_uint32 ret; + NegotiationToken nt; + size_t size; + + nt.element = choice_NegotiationToken_negTokenResp; - ALLOC(resp.negResult, 1); - if (resp.negResult == NULL) { + ALLOC(nt.u.negTokenResp.negResult, 1); + if (nt.u.negTokenResp.negResult == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } - *(resp.negResult) = reject; - resp.supportedMech = NULL; - resp.responseToken = NULL; - resp.mechListMIC = NULL; + *(nt.u.negTokenResp.negResult) = reject; + nt.u.negTokenResp.supportedMech = NULL; + nt.u.negTokenResp.responseToken = NULL; + nt.u.negTokenResp.mechListMIC = NULL; - ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf); - free_NegTokenResp(&resp); - if (ret != GSS_S_COMPLETE) - return ret; + ASN1_MALLOC_ENCODE(NegotiationToken, + output_token->value, output_token->length, &nt, + &size, *minor_status); + free_NegotiationToken(&nt); + if (*minor_status != 0) + return GSS_S_FAILURE; - output_token->value = malloc(data.length); - if (output_token->value == NULL) { - *minor_status = ENOMEM; - ret = GSS_S_FAILURE; - } else { - output_token->length = data.length; - memcpy(output_token->value, data.value, output_token->length); - } - free(buf); - if (ret != GSS_S_COMPLETE) - return ret; return GSS_S_BAD_MECH; } -OM_uint32 -_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status, - int includeMSCompatOID, - const gssspnego_cred cred_handle, - MechTypeList *mechtypelist, - gss_OID *preferred_mech) +static OM_uint32 +acceptor_approved(gss_name_t target_name, gss_OID mech) { - OM_uint32 ret; - gss_OID_set supported_mechs = GSS_C_NO_OID_SET; - int i, count; - - if (cred_handle != NULL) { - ret = gss_inquire_cred(minor_status, - cred_handle->negotiated_cred_id, - NULL, - NULL, - NULL, - &supported_mechs); - } else { - ret = gss_indicate_mechs(minor_status, &supported_mechs); - } + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + gss_OID_set oidset; + OM_uint32 junk, ret; - if (ret != GSS_S_COMPLETE) { - return ret; - } + if (target_name == GSS_C_NO_NAME) + return GSS_S_COMPLETE; - if (supported_mechs->count == 0) { - *minor_status = ENOENT; - gss_release_oid_set(minor_status, &supported_mechs); - return GSS_S_FAILURE; - } - - count = supported_mechs->count; - if (includeMSCompatOID) - count++; - - mechtypelist->len = 0; - mechtypelist->val = calloc(count, sizeof(MechType)); - if (mechtypelist->val == NULL) { - *minor_status = ENOMEM; - gss_release_oid_set(minor_status, &supported_mechs); - return GSS_S_FAILURE; - } - - for (i = 0; i < supported_mechs->count; i++) { - ret = _gss_spnego_add_mech_type(&supported_mechs->elements[i], - includeMSCompatOID, - mechtypelist); - if (ret != 0) { - *minor_status = ENOMEM; - ret = GSS_S_FAILURE; - break; - } - } - - if (ret == GSS_S_COMPLETE && preferred_mech != NULL) { - ret = gss_duplicate_oid(minor_status, - &supported_mechs->elements[0], - preferred_mech); - } - - if (ret != GSS_S_COMPLETE) { - free_MechTypeList(mechtypelist); - mechtypelist->len = 0; - mechtypelist->val = NULL; - } - gss_release_oid_set(minor_status, &supported_mechs); - - return ret; + gss_create_empty_oid_set(&junk, &oidset); + gss_add_oid_set_member(&junk, mech, &oidset); + + ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset, + GSS_C_ACCEPT, &cred, NULL, NULL); + gss_release_oid_set(&junk, &oidset); + if (ret != GSS_S_COMPLETE) + return ret; + gss_release_cred(&junk, &cred); + + return GSS_S_COMPLETE; } static OM_uint32 send_supported_mechs (OM_uint32 *minor_status, gss_buffer_t output_token) { - NegTokenInit ni; + NegotiationTokenWin nt; char hostname[MAXHOSTNAMELEN], *p; gss_buffer_desc name_buf; gss_OID name_type; gss_name_t target_princ; gss_name_t canon_princ; - OM_uint32 ret, minor; - u_char *buf; - size_t buf_size, buf_len; + OM_uint32 minor; + size_t buf_len; gss_buffer_desc data; + OM_uint32 ret; - memset(&ni, 0, sizeof(ni)); + memset(&nt, 0, sizeof(nt)); - ni.reqFlags = NULL; - ni.mechToken = NULL; - ni.negHints = NULL; - ni.mechListMIC = NULL; + nt.element = choice_NegotiationTokenWin_negTokenInit; + nt.u.negTokenInit.reqFlags = NULL; + nt.u.negTokenInit.mechToken = NULL; + nt.u.negTokenInit.negHints = NULL; - ret = _gss_spnego_indicate_mechtypelist(minor_status, 1, - NULL, - &ni.mechTypes, NULL); + ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME, + acceptor_approved, 1, NULL, + &nt.u.negTokenInit.mechTypes, NULL); if (ret != GSS_S_COMPLETE) { return ret; } @@ -237,7 +119,7 @@ send_supported_mechs (OM_uint32 *minor_status, memset(&target_princ, 0, sizeof(target_princ)); if (gethostname(hostname, sizeof(hostname) - 1) != 0) { *minor_status = errno; - free_NegTokenInit(&ni); + free_NegotiationTokenWin(&nt); return GSS_S_FAILURE; } @@ -255,6 +137,7 @@ send_supported_mechs (OM_uint32 *minor_status, GSS_C_NO_OID, &target_princ); if (ret != GSS_S_COMPLETE) { + free_NegotiationTokenWin(&nt); return ret; } @@ -267,6 +150,7 @@ send_supported_mechs (OM_uint32 *minor_status, GSS_C_NO_OID, &canon_princ); if (ret != GSS_S_COMPLETE) { + free_NegotiationTokenWin(&nt); gss_release_name(&minor, &target_princ); return ret; } @@ -274,6 +158,7 @@ send_supported_mechs (OM_uint32 *minor_status, ret = gss_display_name(minor_status, canon_princ, &name_buf, &name_type); if (ret != GSS_S_COMPLETE) { + free_NegotiationTokenWin(&nt); gss_release_name(&minor, &canon_princ); gss_release_name(&minor, &target_princ); return ret; @@ -282,81 +167,38 @@ send_supported_mechs (OM_uint32 *minor_status, gss_release_name(&minor, &canon_princ); gss_release_name(&minor, &target_princ); - ALLOC(ni.negHints, 1); - if (ni.negHints == NULL) { + ALLOC(nt.u.negTokenInit.negHints, 1); + if (nt.u.negTokenInit.negHints == NULL) { *minor_status = ENOMEM; gss_release_buffer(&minor, &name_buf); - free_NegTokenInit(&ni); + free_NegotiationTokenWin(&nt); return GSS_S_FAILURE; } - ALLOC(ni.negHints->hintName, 1); - if (ni.negHints->hintName == NULL) { + ALLOC(nt.u.negTokenInit.negHints->hintName, 1); + if (nt.u.negTokenInit.negHints->hintName == NULL) { *minor_status = ENOMEM; gss_release_buffer(&minor, &name_buf); - free_NegTokenInit(&ni); + free_NegotiationTokenWin(&nt); return GSS_S_FAILURE; } - *(ni.negHints->hintName) = name_buf.value; + *(nt.u.negTokenInit.negHints->hintName) = name_buf.value; name_buf.value = NULL; - ni.negHints->hintAddress = NULL; + nt.u.negTokenInit.negHints->hintAddress = NULL; - buf_size = 1024; - buf = malloc(buf_size); - if (buf == NULL) { - free_NegTokenInit(&ni); - *minor_status = ENOMEM; - return GSS_S_FAILURE; + ASN1_MALLOC_ENCODE(NegotiationTokenWin, + data.value, data.length, &nt, &buf_len, ret); + free_NegotiationTokenWin(&nt); + if (ret) { + return ret; } + if (data.length != buf_len) + abort(); - do { - ret = encode_NegTokenInit(buf + buf_size - 1, - buf_size, - &ni, &buf_len); - if (ret == 0) { - size_t tmp; - - ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, - buf_size - buf_len, - buf_len, - ASN1_C_CONTEXT, - CONS, - 0, - &tmp); - if (ret == 0) - buf_len += tmp; - } - if (ret) { - if (ret == ASN1_OVERFLOW) { - u_char *tmp; - - buf_size *= 2; - tmp = realloc (buf, buf_size); - if (tmp == NULL) { - *minor_status = ENOMEM; - free(buf); - free_NegTokenInit(&ni); - return GSS_S_FAILURE; - } - buf = tmp; - } else { - *minor_status = ret; - free(buf); - free_NegTokenInit(&ni); - return GSS_S_FAILURE; - } - } - } while (ret == ASN1_OVERFLOW); + ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token); - data.value = buf + buf_size - buf_len; - data.length = buf_len; - - ret = gss_encapsulate_token(&data, - GSS_SPNEGO_MECHANISM, - output_token); - free (buf); - free_NegTokenInit (&ni); + free (data.value); if (ret != GSS_S_COMPLETE) return ret; @@ -374,16 +216,17 @@ send_accept (OM_uint32 *minor_status, gss_buffer_t mech_buf, gss_buffer_t output_token) { - NegTokenResp resp; - gss_buffer_desc data; - u_char *buf; + NegotiationToken nt; OM_uint32 ret; gss_buffer_desc mech_mic_buf; + size_t size; - memset(&resp, 0, sizeof(resp)); + memset(&nt, 0, sizeof(nt)); - ALLOC(resp.negResult, 1); - if (resp.negResult == NULL) { + nt.element = choice_NegotiationToken_negTokenResp; + + ALLOC(nt.u.negTokenResp.negResult, 1); + if (nt.u.negTokenResp.negResult == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } @@ -392,79 +235,85 @@ send_accept (OM_uint32 *minor_status, if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0 && mech_buf != GSS_C_NO_BUFFER) - *(resp.negResult) = accept_incomplete; + *(nt.u.negTokenResp.negResult) = accept_incomplete; else - *(resp.negResult) = accept_completed; + *(nt.u.negTokenResp.negResult) = accept_completed; } else { if (initial_response && context_handle->require_mic) - *(resp.negResult) = request_mic; + *(nt.u.negTokenResp.negResult) = request_mic; else - *(resp.negResult) = accept_incomplete; + *(nt.u.negTokenResp.negResult) = accept_incomplete; } if (initial_response) { - ALLOC(resp.supportedMech, 1); - if (resp.supportedMech == NULL) { - free_NegTokenResp(&resp); + ALLOC(nt.u.negTokenResp.supportedMech, 1); + if (nt.u.negTokenResp.supportedMech == NULL) { + free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } ret = der_get_oid(context_handle->preferred_mech_type->elements, context_handle->preferred_mech_type->length, - resp.supportedMech, + nt.u.negTokenResp.supportedMech, NULL); if (ret) { - free_NegTokenResp(&resp); + free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } } else { - resp.supportedMech = NULL; + nt.u.negTokenResp.supportedMech = NULL; } if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) { - ALLOC(resp.responseToken, 1); - if (resp.responseToken == NULL) { - free_NegTokenResp(&resp); + ALLOC(nt.u.negTokenResp.responseToken, 1); + if (nt.u.negTokenResp.responseToken == NULL) { + free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } - resp.responseToken->length = mech_token->length; - resp.responseToken->data = mech_token->value; + nt.u.negTokenResp.responseToken->length = mech_token->length; + nt.u.negTokenResp.responseToken->data = mech_token->value; mech_token->length = 0; mech_token->value = NULL; } else { - resp.responseToken = NULL; + nt.u.negTokenResp.responseToken = NULL; } if (mech_buf != GSS_C_NO_BUFFER) { - ALLOC(resp.mechListMIC, 1); - if (resp.mechListMIC == NULL) { - free_NegTokenResp(&resp); - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - ret = gss_get_mic(minor_status, context_handle->negotiated_ctx_id, 0, mech_buf, &mech_mic_buf); - if (ret != GSS_S_COMPLETE) { - free_NegTokenResp(&resp); + if (ret == GSS_S_COMPLETE) { + ALLOC(nt.u.negTokenResp.mechListMIC, 1); + if (nt.u.negTokenResp.mechListMIC == NULL) { + gss_release_buffer(minor_status, &mech_mic_buf); + free_NegotiationToken(&nt); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length; + nt.u.negTokenResp.mechListMIC->data = mech_mic_buf.value; + } else if (ret == GSS_S_UNAVAILABLE) { + nt.u.negTokenResp.mechListMIC = NULL; + } else { + free_NegotiationToken(&nt); return ret; } - resp.mechListMIC->length = mech_mic_buf.length; - resp.mechListMIC->data = mech_mic_buf.value; } else - resp.mechListMIC = NULL; + nt.u.negTokenResp.mechListMIC = NULL; - ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf); - if (ret != GSS_S_COMPLETE) { - free_NegTokenResp(&resp); - return ret; + ASN1_MALLOC_ENCODE(NegotiationToken, + output_token->value, output_token->length, + &nt, &size, ret); + if (ret) { + free_NegotiationToken(&nt); + *minor_status = ret; + return GSS_S_FAILURE; } /* @@ -472,23 +321,12 @@ send_accept (OM_uint32 *minor_status, * it is a SubsequentContextToken (note though RFC 1964 * specifies encapsulation for all _Kerberos_ tokens). */ - output_token->value = malloc(data.length); - if (output_token->value == NULL) { - *minor_status = ENOMEM; - ret = GSS_S_FAILURE; - } else { - output_token->length = data.length; - memcpy(output_token->value, data.value, output_token->length); - } - free(buf); - if (ret != GSS_S_COMPLETE) { - free_NegTokenResp(&resp); - return ret; - } - ret = (*(resp.negResult) == accept_completed) ? GSS_S_COMPLETE : - GSS_S_CONTINUE_NEEDED; - free_NegTokenResp(&resp); + if (*(nt.u.negTokenResp.negResult) == accept_completed) + ret = GSS_S_COMPLETE; + else + ret = GSS_S_CONTINUE_NEEDED; + free_NegotiationToken(&nt); return ret; } @@ -530,8 +368,164 @@ verify_mechlist_mic return ret; } -OM_uint32 -_gss_spnego_accept_sec_context +static OM_uint32 +select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p, + gss_OID *mech_p) +{ + char mechbuf[64]; + size_t mech_len; + gss_OID_desc oid; + OM_uint32 ret, junk; + + ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1, + sizeof(mechbuf), + mechType, + &mech_len); + if (ret) { + return GSS_S_DEFECTIVE_TOKEN; + } + + oid.length = mech_len; + oid.elements = mechbuf + sizeof(mechbuf) - mech_len; + + if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) { + return GSS_S_BAD_MECH; + } + + *minor_status = 0; + + /* Translate broken MS Kebreros OID */ + if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc)) { + gssapi_mech_interface mech; + + mech = __gss_get_mechanism(&_gss_spnego_krb5_mechanism_oid_desc); + if (mech == NULL) + return GSS_S_BAD_MECH; + + ret = gss_duplicate_oid(minor_status, + &_gss_spnego_mskrb_mechanism_oid_desc, + mech_p); + } else { + gssapi_mech_interface mech; + + mech = __gss_get_mechanism(&oid); + if (mech == NULL) + return GSS_S_BAD_MECH; + + ret = gss_duplicate_oid(minor_status, + &mech->gm_mech_oid, + mech_p); + } + + if (verify_p) { + gss_name_t name = GSS_C_NO_NAME; + gss_buffer_desc namebuf; + char *str = NULL, *host, hostname[MAXHOSTNAMELEN]; + + host = getenv("GSSAPI_SPNEGO_NAME"); + if (host == NULL || issuid()) { + if (gethostname(hostname, sizeof(hostname)) != 0) { + *minor_status = errno; + return GSS_S_FAILURE; + } + asprintf(&str, "host@%s", hostname); + host = str; + } + + namebuf.length = strlen(host); + namebuf.value = host; + + ret = gss_import_name(minor_status, &namebuf, + GSS_C_NT_HOSTBASED_SERVICE, &name); + if (str) + free(str); + if (ret != GSS_S_COMPLETE) + return ret; + + ret = acceptor_approved(name, *mech_p); + gss_release_name(&junk, &name); + } + + return ret; +} + + +static OM_uint32 +acceptor_complete(OM_uint32 * minor_status, + gssspnego_ctx ctx, + int *get_mic, + gss_buffer_t mech_buf, + gss_buffer_t mech_input_token, + gss_buffer_t mech_output_token, + heim_octet_string *mic, + gss_buffer_t output_token) +{ + OM_uint32 ret; + int require_mic, verify_mic; + gss_buffer_desc buf; + + buf.length = 0; + buf.value = NULL; + + ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic); + if (ret) + return ret; + + ctx->require_mic = require_mic; + + if (mic != NULL) + require_mic = 1; + + if (ctx->open && require_mic) { + if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */ + verify_mic = 1; + *get_mic = 0; + } else if (mech_output_token != GSS_C_NO_BUFFER && + mech_output_token->length == 0) { /* Odd */ + *get_mic = verify_mic = 1; + } else { /* Even/One */ + verify_mic = 0; + *get_mic = 1; + } + + if (verify_mic || get_mic) { + int eret; + size_t buf_len; + + ASN1_MALLOC_ENCODE(MechTypeList, + mech_buf->value, mech_buf->length, + &ctx->initiator_mech_types, &buf_len, eret); + if (eret) { + *minor_status = eret; + return GSS_S_FAILURE; + } + if (buf.length != buf_len) + abort(); + } + + if (verify_mic) { + ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic); + if (ret) { + if (get_mic) + send_reject (minor_status, output_token); + if (buf.value) + free(buf.value); + return ret; + } + ctx->verified_mic = 1; + } + if (buf.value) + free(buf.value); + + } else + *get_mic = verify_mic = 0; + + return GSS_S_COMPLETE; +} + + +static OM_uint32 +acceptor_start (OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_cred_id_t acceptor_cred_handle, @@ -547,40 +541,21 @@ _gss_spnego_accept_sec_context { OM_uint32 ret, ret2, minor; NegTokenInit ni; - NegTokenResp na; - size_t ni_len, na_len; + size_t ni_len; int i; gss_buffer_desc data; size_t len, taglen; - int initialToken; - unsigned int negResult = accept_incomplete; gss_buffer_t mech_input_token = GSS_C_NO_BUFFER; - gss_buffer_t mech_output_token = GSS_C_NO_BUFFER; + gss_buffer_desc mech_output_token; gss_buffer_desc mech_buf; gss_OID preferred_mech_type = GSS_C_NO_OID; gssspnego_ctx ctx; gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle; + int get_mic = 0; + int first_ok = 0; - *minor_status = 0; - - output_token->length = 0; - output_token->value = NULL; - - if (src_name != NULL) - *src_name = GSS_C_NO_NAME; - - if (mech_type != NULL) - *mech_type = GSS_C_NO_OID; - - if (ret_flags != NULL) - *ret_flags = 0; - - if (time_rec != NULL) - *time_rec = 0; - - if (delegated_cred_handle != NULL) - *delegated_cred_handle = GSS_C_NO_CREDENTIAL; - + mech_output_token.value = NULL; + mech_output_token.length = 0; mech_buf.value = NULL; if (*context_handle == GSS_C_NO_CONTEXT) { @@ -590,8 +565,7 @@ _gss_spnego_accept_sec_context return ret; if (input_token_buffer->length == 0) { - return send_supported_mechs (minor_status, - output_token); + return send_supported_mechs (minor_status, output_token); } } @@ -604,16 +578,12 @@ _gss_spnego_accept_sec_context ret = gss_decapsulate_token (input_token_buffer, GSS_SPNEGO_MECHANISM, &data); - initialToken = (ret == GSS_S_COMPLETE); - - if (!initialToken) { - data.value = input_token_buffer->value; - data.length = input_token_buffer->length; - } + if (ret) + return ret; ret = der_match_tag_and_length(data.value, data.length, ASN1_C_CONTEXT, CONS, - initialToken ? 0 : 1, + 0, &len, &taglen); if (ret) { *minor_status = ret; @@ -625,70 +595,263 @@ _gss_spnego_accept_sec_context return GSS_S_FAILURE; } - if (initialToken) { - ret = decode_NegTokenInit((const unsigned char *)data.value + taglen, + ret = decode_NegTokenInit((const unsigned char *)data.value + taglen, len, &ni, &ni_len); - } else { - ret = decode_NegTokenResp((const unsigned char *)data.value + taglen, - len, &na, &na_len); - } if (ret) { *minor_status = ret; return GSS_S_DEFECTIVE_TOKEN; } - if (!initialToken && na.negResult != NULL) { - negResult = *(na.negResult); + if (ni.mechTypes.len < 1) { + free_NegTokenInit(&ni); + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; } - if (negResult == reject || negResult == request_mic) { - /* request_mic should only be sent by acceptor */ - free_NegTokenResp(&na); - return GSS_S_DEFECTIVE_TOKEN; + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + ret = copy_MechTypeList(&ni.mechTypes, &ctx->initiator_mech_types); + if (ret) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + free_NegTokenInit(&ni); + *minor_status = ret; + return GSS_S_FAILURE; } - if (initialToken) { - for (i = 0; i < ni.mechTypes.len; ++i) { - /* Call glue layer to find first mech we support */ - ret = _gss_spnego_select_mech(minor_status, &ni.mechTypes.val[i], - &preferred_mech_type); + /* + * First we try the opportunistic token if we have support for it, + * don't try to verify we have credential for the token, + * gss_accept_sec_context will (hopefully) tell us that. + * If that failes, + */ + + ret = select_mech(minor_status, + &ni.mechTypes.val[0], + 0, + &preferred_mech_type); + + if (ret == 0 && ni.mechToken != NULL) { + gss_cred_id_t mech_delegated_cred = GSS_C_NO_CREDENTIAL; + gss_cred_id_t mech_cred; + gss_buffer_desc ibuf; + + ibuf.length = ni.mechToken->length; + ibuf.value = ni.mechToken->data; + mech_input_token = &ibuf; + + if (acceptor_cred != NULL) + mech_cred = acceptor_cred->negotiated_cred_id; + else + mech_cred = GSS_C_NO_CREDENTIAL; + + if (ctx->mech_src_name != GSS_C_NO_NAME) + gss_release_name(&minor, &ctx->mech_src_name); + + if (ctx->delegated_cred_id != GSS_C_NO_CREDENTIAL) + _gss_spnego_release_cred(&minor, &ctx->delegated_cred_id); + + ret = gss_accept_sec_context(&minor, + &ctx->negotiated_ctx_id, + mech_cred, + mech_input_token, + input_chan_bindings, + &ctx->mech_src_name, + &ctx->negotiated_mech_type, + &mech_output_token, + &ctx->mech_flags, + &ctx->mech_time_rec, + &mech_delegated_cred); + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { + if (delegated_cred_handle) + ret = _gss_spnego_alloc_cred(minor_status, + mech_delegated_cred, + delegated_cred_handle); + else + gss_release_cred(&ret2, &mech_delegated_cred); + + ctx->preferred_mech_type = preferred_mech_type; + ctx->negotiated_mech_type = preferred_mech_type; + if (ret == GSS_S_COMPLETE) + ctx->open = 1; + + ret = acceptor_complete(minor_status, + ctx, + &get_mic, + &mech_buf, + mech_input_token, + &mech_output_token, + ni.mechListMIC, + output_token); + if (ret != GSS_S_COMPLETE) + goto out; + + first_ok = 1; + } + } + + /* + * If opportunistic token failed, lets try the other mechs. + */ + + if (!first_ok) { + + /* Call glue layer to find first mech we support */ + for (i = 1; i < ni.mechTypes.len; ++i) { + ret = select_mech(minor_status, + &ni.mechTypes.val[i], + 1, + &preferred_mech_type); if (ret == 0) break; } if (preferred_mech_type == GSS_C_NO_OID) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); free_NegTokenInit(&ni); return GSS_S_BAD_MECH; } + + ctx->preferred_mech_type = preferred_mech_type; + ctx->negotiated_mech_type = preferred_mech_type; } - HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + /* + * The initial token always have a response + */ - if (initialToken) { - ctx->preferred_mech_type = preferred_mech_type; - ctx->initiator_mech_types.len = ni.mechTypes.len; - ctx->initiator_mech_types.val = ni.mechTypes.val; - ni.mechTypes.len = 0; - ni.mechTypes.val = NULL; + ret = send_accept (minor_status, + ctx, + &mech_output_token, + 1, + get_mic ? &mech_buf : NULL, + output_token); + if (ret) + goto out; + +out: + if (mech_output_token.value != NULL) + gss_release_buffer(&minor, &mech_output_token); + if (mech_buf.value != NULL) { + free(mech_buf.value); + mech_buf.value = NULL; + } + free_NegTokenInit(&ni); + + if (ret == GSS_S_COMPLETE) { + if (src_name != NULL && ctx->mech_src_name != NULL) { + spnego_name name; + + name = calloc(1, sizeof(*name)); + if (name) { + name->mech = ctx->mech_src_name; + ctx->mech_src_name = NULL; + *src_name = (gss_name_t)name; + } else + *src_name = GSS_C_NO_NAME; + } + if (delegated_cred_handle != NULL) { + *delegated_cred_handle = ctx->delegated_cred_id; + ctx->delegated_cred_id = GSS_C_NO_CREDENTIAL; + } + } + + if (mech_type != NULL) + *mech_type = ctx->negotiated_mech_type; + if (ret_flags != NULL) + *ret_flags = ctx->mech_flags; + if (time_rec != NULL) + *time_rec = ctx->mech_time_rec; + + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; } + _gss_spnego_internal_delete_sec_context(&minor, context_handle, + GSS_C_NO_BUFFER); + + return ret; +} + + +static OM_uint32 +acceptor_continue + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t *delegated_cred_handle + ) +{ + OM_uint32 ret, ret2, minor; + NegTokenResp na; + size_t na_len; + gss_buffer_desc data; + size_t len, taglen; + unsigned int negResult = accept_incomplete; + gss_buffer_t mech_input_token = GSS_C_NO_BUFFER; + gss_buffer_t mech_output_token = GSS_C_NO_BUFFER; + gss_buffer_desc mech_buf; + gssspnego_ctx ctx; + gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle; + + mech_buf.value = NULL; + + ctx = (gssspnego_ctx)*context_handle; + + /* + * The GSS-API encapsulation is only present on the initial + * context token (negTokenInit). + */ + + data.value = input_token_buffer->value; + data.length = input_token_buffer->length; + + ret = der_match_tag_and_length(data.value, data.length, + ASN1_C_CONTEXT, CONS, + 1, + &len, &taglen); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (len > data.length - taglen) { + *minor_status = ASN1_OVERRUN; + return GSS_S_FAILURE; + } + + ret = decode_NegTokenResp((const unsigned char *)data.value + taglen, + len, &na, &na_len); + if (ret) { + *minor_status = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (na.negResult != NULL) { + negResult = *(na.negResult); + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + { gss_buffer_desc ibuf, obuf; - int require_mic, verify_mic, get_mic; + int require_mic, get_mic; int require_response; heim_octet_string *mic; - if (initialToken) { - if (ni.mechToken != NULL) { - ibuf.length = ni.mechToken->length; - ibuf.value = ni.mechToken->data; - mech_input_token = &ibuf; - } + if (na.responseToken != NULL) { + ibuf.length = na.responseToken->length; + ibuf.value = na.responseToken->data; + mech_input_token = &ibuf; } else { - if (na.responseToken != NULL) { - ibuf.length = na.responseToken->length; - ibuf.value = na.responseToken->data; - mech_input_token = &ibuf; - } + ibuf.value = NULL; + ibuf.length = 0; } if (mech_input_token != GSS_C_NO_BUFFER) { @@ -737,10 +900,7 @@ _gss_spnego_accept_sec_context mech_output_token = &obuf; } if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) { - if (initialToken) - free_NegTokenInit(&ni); - else - free_NegTokenResp(&na); + free_NegTokenResp(&na); send_reject (minor_status, output_token); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return ret; @@ -758,50 +918,19 @@ _gss_spnego_accept_sec_context ctx->require_mic = require_mic; - mic = initialToken ? ni.mechListMIC : na.mechListMIC; + mic = na.mechListMIC; if (mic != NULL) require_mic = 1; - if (ctx->open && require_mic) { - if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */ - verify_mic = 1; - get_mic = 0; - } else if (mech_output_token != GSS_C_NO_BUFFER && - mech_output_token->length == 0) { /* Odd */ - get_mic = verify_mic = 1; - } else { /* Even/One */ - verify_mic = 0; - get_mic = 1; - } - - if (verify_mic || get_mic) { - int eret; - size_t buf_len; - - ASN1_MALLOC_ENCODE(MechTypeList, - mech_buf.value, mech_buf.length, - &ctx->initiator_mech_types, &buf_len, eret); - if (eret) { - ret2 = GSS_S_FAILURE; - *minor_status = eret; - goto out; - } - if (mech_buf.length != buf_len) - abort(); - } - - if (verify_mic) { - ret2 = verify_mechlist_mic(minor_status, ctx, &mech_buf, mic); - if (ret2) { - if (get_mic) - send_reject (minor_status, output_token); - goto out; - } - - ctx->verified_mic = 1; - } - } else - verify_mic = get_mic = 0; + if (ret == GSS_S_COMPLETE) + ret = acceptor_complete(minor_status, + ctx, + &get_mic, + &mech_buf, + mech_input_token, + mech_output_token, + na.mechListMIC, + output_token); if (ctx->mech_flags & GSS_C_DCE_STYLE) require_response = (negResult != accept_completed); @@ -814,12 +943,13 @@ _gss_spnego_accept_sec_context */ if ((mech_output_token != GSS_C_NO_BUFFER && mech_output_token->length != 0) + || (ctx->open && negResult == accept_incomplete) || require_response || get_mic) { ret2 = send_accept (minor_status, ctx, mech_output_token, - initialToken, + 0, get_mic ? &mech_buf : NULL, output_token); if (ret2) @@ -833,10 +963,7 @@ _gss_spnego_accept_sec_context gss_release_buffer(&minor, mech_output_token); if (mech_buf.value != NULL) free(mech_buf.value); - if (initialToken) - free_NegTokenInit(&ni); - else - free_NegTokenResp(&na); + free_NegTokenResp(&na); } if (ret == GSS_S_COMPLETE) { @@ -871,3 +998,48 @@ _gss_spnego_accept_sec_context return ret; } +OM_uint32 +_gss_spnego_accept_sec_context + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t *delegated_cred_handle + ) +{ + _gss_accept_sec_context_t *func; + + *minor_status = 0; + + output_token->length = 0; + output_token->value = NULL; + + if (src_name != NULL) + *src_name = GSS_C_NO_NAME; + if (mech_type != NULL) + *mech_type = GSS_C_NO_OID; + if (ret_flags != NULL) + *ret_flags = 0; + if (time_rec != NULL) + *time_rec = 0; + if (delegated_cred_handle != NULL) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + + + if (*context_handle == GSS_C_NO_CONTEXT) + func = acceptor_start; + else + func = acceptor_continue; + + + return (*func)(minor_status, context_handle, acceptor_cred_handle, + input_token_buffer, input_chan_bindings, + src_name, mech_type, output_token, ret_flags, + time_rec, delegated_cred_handle); +} diff --git a/source4/heimdal/lib/gssapi/spnego/compat.c b/source4/heimdal/lib/gssapi/spnego/compat.c index aeae088258..786eac1340 100644 --- a/source4/heimdal/lib/gssapi/spnego/compat.c +++ b/source4/heimdal/lib/gssapi/spnego/compat.c @@ -32,7 +32,7 @@ #include "spnego/spnego_locl.h" -RCSID("$Id: compat.c,v 1.6 2006/10/07 22:26:59 lha Exp $"); +RCSID("$Id: compat.c,v 1.9 2006/12/18 17:52:26 lha Exp $"); /* * Apparently Microsoft got the OID wrong, and used @@ -42,10 +42,10 @@ RCSID("$Id: compat.c,v 1.6 2006/10/07 22:26:59 lha Exp $"); * prefer to deal with this here rather than inside the * Kerberos mechanism. */ -static gss_OID_desc gss_mskrb_mechanism_oid_desc = +gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc = {9, (void *)"\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"}; -static gss_OID_desc gss_krb5_mechanism_oid_desc = +gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; /* @@ -191,8 +191,8 @@ _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status, if (*require_mic) { if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) { *require_mic = 0; - } else if (gss_oid_equal(ctx->negotiated_mech_type, &gss_krb5_mechanism_oid_desc) && - gss_oid_equal(ctx->preferred_mech_type, &gss_mskrb_mechanism_oid_desc)) { + } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) && + gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) { *require_mic = 0; } } @@ -200,86 +200,122 @@ _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status, return GSS_S_COMPLETE; } -int _gss_spnego_add_mech_type(gss_OID mech_type, - int includeMSCompatOID, - MechTypeList *mechtypelist) +static int +add_mech_type(gss_OID mech_type, + int includeMSCompatOID, + MechTypeList *mechtypelist) { + MechType mech; int ret; if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM)) return 0; if (includeMSCompatOID && - gss_oid_equal(mech_type, &gss_krb5_mechanism_oid_desc)) { - ret = der_get_oid(gss_mskrb_mechanism_oid_desc.elements, - gss_mskrb_mechanism_oid_desc.length, - &mechtypelist->val[mechtypelist->len], + gss_oid_equal(mech_type, &_gss_spnego_krb5_mechanism_oid_desc)) { + ret = der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc.elements, + _gss_spnego_mskrb_mechanism_oid_desc.length, + &mech, NULL); if (ret) return ret; - mechtypelist->len++; + ret = add_MechTypeList(mechtypelist, &mech); + free_MechType(&mech); + if (ret) + return ret; } - ret = der_get_oid(mech_type->elements, - mech_type->length, - &mechtypelist->val[mechtypelist->len], - NULL); + ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL); if (ret) return ret; - mechtypelist->len++; - - return 0; + ret = add_MechTypeList(mechtypelist, &mech); + free_MechType(&mech); + return ret; } + OM_uint32 -_gss_spnego_select_mech(OM_uint32 *minor_status, - MechType *mechType, - gss_OID *mech_p) +_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status, + gss_name_t target_name, + OM_uint32 (*func)(gss_name_t, gss_OID), + int includeMSCompatOID, + const gssspnego_cred cred_handle, + MechTypeList *mechtypelist, + gss_OID *preferred_mech) { - char mechbuf[64]; - size_t mech_len; - gss_OID_desc oid; + gss_OID_set supported_mechs = GSS_C_NO_OID_SET; + gss_OID first_mech = GSS_C_NO_OID; OM_uint32 ret; - - ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1, - sizeof(mechbuf), - mechType, - &mech_len); - if (ret) { - return GSS_S_DEFECTIVE_TOKEN; + int i; + + mechtypelist->len = 0; + mechtypelist->val = NULL; + + if (cred_handle != NULL) { + ret = gss_inquire_cred(minor_status, + cred_handle->negotiated_cred_id, + NULL, + NULL, + NULL, + &supported_mechs); + } else { + ret = gss_indicate_mechs(minor_status, &supported_mechs); } - oid.length = mech_len; - oid.elements = mechbuf + sizeof(mechbuf) - mech_len; - - if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) { - return GSS_S_BAD_MECH; + if (ret != GSS_S_COMPLETE) { + return ret; } - *minor_status = 0; - - /* Translate broken MS Kebreros OID */ - if (gss_oid_equal(&oid, &gss_mskrb_mechanism_oid_desc)) { - gssapi_mech_interface mech; - - mech = __gss_get_mechanism(&gss_krb5_mechanism_oid_desc); - if (mech == NULL) - return GSS_S_BAD_MECH; + if (supported_mechs->count == 0) { + *minor_status = ENOENT; + gss_release_oid_set(minor_status, &supported_mechs); + return GSS_S_FAILURE; + } - ret = gss_duplicate_oid(minor_status, - &gss_mskrb_mechanism_oid_desc, - mech_p); - } else { - gssapi_mech_interface mech; + ret = (*func)(target_name, GSS_KRB5_MECHANISM); + if (ret == GSS_S_COMPLETE) { + ret = add_mech_type(GSS_KRB5_MECHANISM, + includeMSCompatOID, + mechtypelist); + if (!GSS_ERROR(ret)) + first_mech = GSS_KRB5_MECHANISM; + } + ret = GSS_S_COMPLETE; + + for (i = 0; i < supported_mechs->count; i++) { + OM_uint32 subret; + if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM)) + continue; + if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM)) + continue; + + subret = (*func)(target_name, &supported_mechs->elements[i]); + if (subret != GSS_S_COMPLETE) + continue; + + ret = add_mech_type(&supported_mechs->elements[i], + includeMSCompatOID, + mechtypelist); + if (ret != 0) { + *minor_status = ret; + ret = GSS_S_FAILURE; + break; + } + if (first_mech == GSS_C_NO_OID) + first_mech = &supported_mechs->elements[i]; + } - mech = __gss_get_mechanism(&oid); - if (mech == NULL) - return GSS_S_BAD_MECH; + if (mechtypelist->len == 0) { + gss_release_oid_set(minor_status, &supported_mechs); + *minor_status = 0; + return GSS_S_BAD_MECH; + } - ret = gss_duplicate_oid(minor_status, - &mech->gm_mech_oid, - mech_p); + if (preferred_mech != NULL) { + ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech); + if (ret != GSS_S_COMPLETE) + free_MechTypeList(mechtypelist); } + gss_release_oid_set(minor_status, &supported_mechs); return ret; } - diff --git a/source4/heimdal/lib/gssapi/spnego/context_stubs.c b/source4/heimdal/lib/gssapi/spnego/context_stubs.c index 902ddbbdf9..57bc45a492 100644 --- a/source4/heimdal/lib/gssapi/spnego/context_stubs.c +++ b/source4/heimdal/lib/gssapi/spnego/context_stubs.c @@ -32,7 +32,7 @@ #include "spnego/spnego_locl.h" -RCSID("$Id: context_stubs.c,v 1.8 2006/10/07 22:27:01 lha Exp $"); +RCSID("$Id: context_stubs.c,v 1.9 2006/12/18 12:59:44 lha Exp $"); static OM_uint32 spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs) @@ -282,7 +282,21 @@ OM_uint32 _gss_spnego_compare_name int * name_equal ) { - return gss_compare_name(minor_status, name1, name2, name_equal); + spnego_name n1 = (spnego_name)name1; + spnego_name n2 = (spnego_name)name2; + + *name_equal = 0; + + if (!gss_oid_equal(&n1->type, &n2->type)) + return GSS_S_COMPLETE; + if (n1->value.length != n2->value.length) + return GSS_S_COMPLETE; + if (memcmp(n1->value.value, n2->value.value, n2->value.length) != 0) + return GSS_S_COMPLETE; + + *name_equal = 1; + + return GSS_S_COMPLETE; } OM_uint32 _gss_spnego_display_name @@ -292,19 +306,51 @@ OM_uint32 _gss_spnego_display_name gss_OID * output_name_type ) { - return gss_display_name(minor_status, input_name, + spnego_name name = (spnego_name)input_name; + + *minor_status = 0; + + if (name->mech == GSS_C_NO_NAME) + return GSS_S_FAILURE; + + return gss_display_name(minor_status, name->mech, output_name_buffer, output_name_type); } OM_uint32 _gss_spnego_import_name (OM_uint32 * minor_status, - const gss_buffer_t input_name_buffer, - const gss_OID input_name_type, + const gss_buffer_t name_buffer, + const gss_OID name_type, gss_name_t * output_name ) { - return gss_import_name(minor_status, input_name_buffer, - input_name_type, output_name); + spnego_name name; + OM_uint32 maj_stat; + + *minor_status = 0; + + name = calloc(1, sizeof(*name)); + if (name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + maj_stat = _gss_copy_oid(minor_status, name_type, &name->type); + if (maj_stat) { + free(name); + return GSS_S_FAILURE; + } + + maj_stat = _gss_copy_buffer(minor_status, name_buffer, &name->value); + if (maj_stat) { + gss_name_t rname = (gss_name_t)name; + _gss_spnego_release_name(minor_status, &rname); + return GSS_S_FAILURE; + } + name->mech = GSS_C_NO_NAME; + *output_name = (gss_name_t)name; + + return GSS_S_COMPLETE; } OM_uint32 _gss_spnego_export_name @@ -313,8 +359,17 @@ OM_uint32 _gss_spnego_export_name gss_buffer_t exported_name ) { - return gss_export_name(minor_status, input_name, - exported_name); + spnego_name name; + *minor_status = 0; + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + name = (spnego_name)input_name; + if (name->mech == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + return gss_export_name(minor_status, name->mech, exported_name); } OM_uint32 _gss_spnego_release_name @@ -322,7 +377,20 @@ OM_uint32 _gss_spnego_release_name gss_name_t * input_name ) { - return gss_release_name(minor_status, input_name); + *minor_status = 0; + + if (*input_name != GSS_C_NO_NAME) { + OM_uint32 junk; + spnego_name name = (spnego_name)*input_name; + _gss_free_oid(&junk, &name->type); + gss_release_buffer(&junk, &name->value); + if (name->mech != GSS_C_NO_NAME) + gss_release_name(&junk, &name->mech); + free(name); + + *input_name = GSS_C_NO_NAME; + } + return GSS_S_COMPLETE; } OM_uint32 _gss_spnego_inquire_context ( diff --git a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c index 5a652fdb2e..a221281a70 100644 --- a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c +++ b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c @@ -33,7 +33,39 @@ #include "spnego/spnego_locl.h" -RCSID("$Id: init_sec_context.c,v 1.6 2006/10/14 10:09:15 lha Exp $"); +RCSID("$Id: init_sec_context.c,v 1.11 2006/12/18 15:42:03 lha Exp $"); + +/* + * Is target_name an sane target for `mech´. + */ + +static OM_uint32 +initiator_approved(gss_name_t target_name, gss_OID mech) +{ + OM_uint32 min_stat, maj_stat; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc out; + + maj_stat = gss_init_sec_context(&min_stat, + GSS_C_NO_CREDENTIAL, + &ctx, + target_name, + mech, + 0, + GSS_C_INDEFINITE, + GSS_C_NO_CHANNEL_BINDINGS, + GSS_C_NO_BUFFER, + NULL, + &out, + NULL, + NULL); + if (GSS_ERROR(maj_stat)) + return GSS_S_BAD_MECH; + gss_release_buffer(&min_stat, &out); + gss_delete_sec_context(&min_stat, &ctx, NULL); + + return GSS_S_COMPLETE; +} /* * Send a reply. Note that we only need to send a reply if we @@ -50,11 +82,10 @@ spnego_reply_internal(OM_uint32 *minor_status, gss_buffer_t mech_token, gss_buffer_t output_token) { - NegTokenResp resp; + NegotiationToken nt; gss_buffer_desc mic_buf; OM_uint32 ret; - gss_buffer_desc data; - u_char *buf; + size_t size; if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) { output_token->length = 0; @@ -63,85 +94,83 @@ spnego_reply_internal(OM_uint32 *minor_status, return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE; } - memset(&resp, 0, sizeof(resp)); + memset(&nt, 0, sizeof(nt)); - ALLOC(resp.negResult, 1); - if (resp.negResult == NULL) { + nt.element = choice_NegotiationToken_negTokenResp; + + ALLOC(nt.u.negTokenResp.negResult, 1); + if (nt.u.negTokenResp.negResult == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } - resp.supportedMech = NULL; + nt.u.negTokenResp.supportedMech = NULL; output_token->length = 0; output_token->value = NULL; if (mech_token->length == 0) { - resp.responseToken = NULL; - *(resp.negResult) = accept_completed; + nt.u.negTokenResp.responseToken = NULL; + *(nt.u.negTokenResp.negResult) = accept_completed; } else { - ALLOC(resp.responseToken, 1); - if (resp.responseToken == NULL) { - free_NegTokenResp(&resp); + ALLOC(nt.u.negTokenResp.responseToken, 1); + if (nt.u.negTokenResp.responseToken == NULL) { + free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } - resp.responseToken->length = mech_token->length; - resp.responseToken->data = mech_token->value; + nt.u.negTokenResp.responseToken->length = mech_token->length; + nt.u.negTokenResp.responseToken->data = mech_token->value; mech_token->length = 0; mech_token->value = NULL; - *(resp.negResult) = accept_incomplete; + *(nt.u.negTokenResp.negResult) = accept_incomplete; } if (mech_buf != GSS_C_NO_BUFFER) { - ALLOC(resp.mechListMIC, 1); - if (resp.mechListMIC == NULL) { - free_NegTokenResp(&resp); - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } ret = gss_get_mic(minor_status, context_handle->negotiated_ctx_id, 0, mech_buf, &mic_buf); - if (ret) { - free_NegTokenResp(&resp); + if (ret == GSS_S_COMPLETE) { + ALLOC(nt.u.negTokenResp.mechListMIC, 1); + if (nt.u.negTokenResp.mechListMIC == NULL) { + gss_release_buffer(minor_status, &mic_buf); + free_NegotiationToken(&nt); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + nt.u.negTokenResp.mechListMIC->length = mic_buf.length; + nt.u.negTokenResp.mechListMIC->data = mic_buf.value; + } else if (ret == GSS_S_UNAVAILABLE) { + nt.u.negTokenResp.mechListMIC = NULL; + } if (ret) { + free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } - - resp.mechListMIC->length = mic_buf.length; - resp.mechListMIC->data = mic_buf.value; } else { - resp.mechListMIC = NULL; + nt.u.negTokenResp.mechListMIC = NULL; } - ret = _gss_spnego_encode_response (minor_status, &resp, - &data, &buf); + ASN1_MALLOC_ENCODE(NegotiationToken, + output_token->value, output_token->length, + &nt, &size, ret); if (ret) { - free_NegTokenResp(&resp); - return ret; - } - - output_token->value = malloc(data.length); - if (output_token->value == NULL) { - *minor_status = ENOMEM; - ret = GSS_S_FAILURE; - } else { - output_token->length = data.length; - memcpy(output_token->value, data.value, output_token->length); + free_NegotiationToken(&nt); + *minor_status = ret; + return GSS_S_FAILURE; } - free(buf); - if (*(resp.negResult) == accept_completed) + if (*(nt.u.negTokenResp.negResult) == accept_completed) ret = GSS_S_COMPLETE; else ret = GSS_S_CONTINUE_NEEDED; - free_NegTokenResp(&resp); + free_NegotiationToken(&nt); return ret; } @@ -172,12 +201,16 @@ spnego_initial size_t ni_len; gss_ctx_id_t context; gssspnego_ctx ctx; + spnego_name name = (spnego_name)target_name; + + *minor_status = 0; memset (&ni, 0, sizeof(ni)); *context_handle = GSS_C_NO_CONTEXT; - *minor_status = 0; + if (target_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; sub = _gss_spnego_alloc_sec_context(&minor, &context); if (GSS_ERROR(sub)) { @@ -190,7 +223,17 @@ spnego_initial ctx->local = 1; - sub = _gss_spnego_indicate_mechtypelist(&minor, 0, + sub = gss_import_name(&minor, &name->value, &name->type, &ctx->target_name); + if (GSS_ERROR(sub)) { + *minor_status = minor; + _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); + return sub; + } + + sub = _gss_spnego_indicate_mechtypelist(&minor, + ctx->target_name, + initiator_approved, + 0, cred, &ni.mechTypes, &ctx->preferred_mech_type); @@ -212,8 +255,8 @@ spnego_initial (cred != NULL) ? cred->negotiated_cred_id : GSS_C_NO_CREDENTIAL, &ctx->negotiated_ctx_id, - target_name, - GSS_C_NO_OID, + ctx->target_name, + ctx->preferred_mech_type, req_flags, time_req, input_chan_bindings, @@ -228,6 +271,8 @@ spnego_initial _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); return sub; } + if (sub == GSS_S_COMPLETE) + ctx->maybe_open = 1; if (mech_token.length != 0) { ALLOC(ni.mechToken, 1); @@ -345,8 +390,6 @@ spnego_reply { OM_uint32 ret, minor; NegTokenResp resp; - u_char oidbuf[17]; - size_t oidlen; size_t len, taglen; gss_OID_desc mech; int require_mic; @@ -385,34 +428,73 @@ spnego_reply if (resp.negResult == NULL || *(resp.negResult) == reject - || resp.supportedMech == NULL) { + /* || resp.supportedMech == NULL */ + ) + { free_NegTokenResp(&resp); return GSS_S_BAD_MECH; } - ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1, - sizeof(oidbuf), - resp.supportedMech, - &oidlen); - if (ret || (oidlen == GSS_SPNEGO_MECHANISM->length && - memcmp(oidbuf + sizeof(oidbuf) - oidlen, - GSS_SPNEGO_MECHANISM->elements, - oidlen) == 0)) { + /* + * Pick up the mechanism that the acceptor selected, only allow it + * to be sent in packet. + */ + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + if (resp.supportedMech) { + + if (ctx->oidlen) { + free_NegTokenResp(&resp); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_BAD_MECH; + } + ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1, + sizeof(ctx->oidbuf), + resp.supportedMech, + &ctx->oidlen); /* Avoid recursively embedded SPNEGO */ + if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length && + memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen, + GSS_SPNEGO_MECHANISM->elements, + ctx->oidlen) == 0)) + { + free_NegTokenResp(&resp); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_BAD_MECH; + } + + /* check if the acceptor took our optimistic token */ + if (ctx->oidlen != ctx->preferred_mech_type->length || + memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen, + ctx->preferred_mech_type->elements, + ctx->oidlen) != 0) + { + gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id, + GSS_C_NO_BUFFER); + ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; + } + } else if (ctx->oidlen == 0) { free_NegTokenResp(&resp); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return GSS_S_BAD_MECH; } - HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - - if (resp.responseToken != NULL) { + if (resp.responseToken != NULL || + ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { gss_buffer_desc mech_input_token; - mech_input_token.length = resp.responseToken->length; - mech_input_token.value = resp.responseToken->data; + if (resp.responseToken) { + mech_input_token.length = resp.responseToken->length; + mech_input_token.value = resp.responseToken->data; + } else { + mech_input_token.length = 0; + mech_input_token.value = NULL; + } - mech.length = oidlen; - mech.elements = oidbuf + sizeof(oidbuf) - oidlen; + + mech.length = ctx->oidlen; + mech.elements = ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen; /* Fall through as if the negotiated mechanism was requested explicitly */ @@ -420,7 +502,7 @@ spnego_reply (cred != NULL) ? cred->negotiated_cred_id : GSS_C_NO_CREDENTIAL, &ctx->negotiated_ctx_id, - target_name, + ctx->target_name, &mech, req_flags, time_req, @@ -439,6 +521,9 @@ spnego_reply if (ret == GSS_S_COMPLETE) { ctx->open = 1; } + } else if (*(resp.negResult) == accept_completed) { + if (ctx->maybe_open) + ctx->open = 1; } if (*(resp.negResult) == request_mic) { diff --git a/source4/heimdal/lib/gssapi/spnego/spnego-private.h b/source4/heimdal/lib/gssapi/spnego/spnego-private.h index df50f65580..d80db0018a 100644 --- a/source4/heimdal/lib/gssapi/spnego/spnego-private.h +++ b/source4/heimdal/lib/gssapi/spnego/spnego-private.h @@ -46,12 +46,6 @@ _gss_spnego_add_cred ( OM_uint32 * /*initiator_time_rec*/, OM_uint32 * acceptor_time_rec ); -int -_gss_spnego_add_mech_type ( - gss_OID /*mech_type*/, - int /*includeMSCompatOID*/, - MechTypeList */*mechtypelist*/); - OM_uint32 _gss_spnego_alloc_cred ( OM_uint32 */*minor_status*/, @@ -112,13 +106,6 @@ _gss_spnego_duplicate_name ( gss_name_t * dest_name ); OM_uint32 -_gss_spnego_encode_response ( - OM_uint32 */*minor_status*/, - const NegTokenResp */*resp*/, - gss_buffer_t /*data*/, - u_char **/*ret_buf*/); - -OM_uint32 _gss_spnego_export_name ( OM_uint32 * /*minor_status*/, const gss_name_t /*input_name*/, @@ -141,8 +128,8 @@ _gss_spnego_get_mic ( OM_uint32 _gss_spnego_import_name ( OM_uint32 * /*minor_status*/, - const gss_buffer_t /*input_name_buffer*/, - const gss_OID /*input_name_type*/, + const gss_buffer_t /*name_buffer*/, + const gss_OID /*name_type*/, gss_name_t * output_name ); OM_uint32 @@ -154,6 +141,8 @@ _gss_spnego_import_sec_context ( OM_uint32 _gss_spnego_indicate_mechtypelist ( OM_uint32 */*minor_status*/, + gss_name_t /*target_name*/, + OM_uint32 (*/*func*/)(gss_name_t, gss_OID), int /*includeMSCompatOID*/, const gssspnego_cred /*cred_handle*/, MechTypeList */*mechtypelist*/, @@ -271,12 +260,6 @@ _gss_spnego_seal ( gss_buffer_t output_message_buffer ); OM_uint32 -_gss_spnego_select_mech ( - OM_uint32 */*minor_status*/, - MechType */*mechType*/, - gss_OID */*mech_p*/); - -OM_uint32 _gss_spnego_set_sec_context_option ( OM_uint32 * /*minor_status*/, gss_ctx_id_t * /*context_handle*/, diff --git a/source4/heimdal/lib/gssapi/spnego/spnego.asn1 b/source4/heimdal/lib/gssapi/spnego/spnego.asn1 index 187ce0a0a6..76fafa356c 100644 --- a/source4/heimdal/lib/gssapi/spnego/spnego.asn1 +++ b/source4/heimdal/lib/gssapi/spnego/spnego.asn1 @@ -1,4 +1,4 @@ --- $Id: spnego.asn1,v 1.1.1.1 2006/06/28 08:34:45 lha Exp $ +-- $Id: spnego.asn1,v 1.3 2006/12/18 18:28:49 lha Exp $ SPNEGO DEFINITIONS ::= BEGIN @@ -22,14 +22,21 @@ NegHints ::= SEQUENCE { hintAddress [1] OCTET STRING OPTIONAL } +NegTokenInitWin ::= SEQUENCE { + mechTypes [0] MechTypeList, + reqFlags [1] ContextFlags OPTIONAL, + mechToken [2] OCTET STRING OPTIONAL, + negHints [3] NegHints OPTIONAL + } + NegTokenInit ::= SEQUENCE { mechTypes [0] MechTypeList, reqFlags [1] ContextFlags OPTIONAL, mechToken [2] OCTET STRING OPTIONAL, - negHints [3] NegHints OPTIONAL, - mechListMIC [4] OCTET STRING OPTIONAL + mechListMIC [3] OCTET STRING OPTIONAL } + -- NB: negResult is not OPTIONAL in the new SPNEGO spec but -- Windows clients do not always send it NegTokenResp ::= SEQUENCE { @@ -48,4 +55,8 @@ NegotiationToken ::= CHOICE { negTokenResp[1] NegTokenResp } +NegotiationTokenWin ::= CHOICE { + negTokenInit[0] NegTokenInitWin +} + END diff --git a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h index 255e07d056..45dff04313 100644 --- a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h +++ b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -/* $Id: spnego_locl.h,v 1.12 2006/11/07 19:53:40 lha Exp $ */ +/* $Id: spnego_locl.h,v 1.15 2006/12/18 15:42:03 lha Exp $ */ #ifndef SPNEGO_LOCL_H #define SPNEGO_LOCL_H @@ -67,6 +67,7 @@ #include <gssapi_mech.h> #include "spnego_asn1.h" +#include "mech/utils.h" #include <der.h> #include <roken.h> @@ -86,13 +87,29 @@ typedef struct { OM_uint32 mech_time_rec; gss_name_t mech_src_name; gss_cred_id_t delegated_cred_id; - int open : 1; - int local : 1; - int require_mic : 1; - int verified_mic : 1; + unsigned int open : 1; + unsigned int local : 1; + unsigned int require_mic : 1; + unsigned int verified_mic : 1; + unsigned int maybe_open : 1; HEIMDAL_MUTEX ctx_id_mutex; + + gss_name_t target_name; + + u_char oidbuf[17]; + size_t oidlen; + } *gssspnego_ctx; +typedef struct { + gss_OID_desc type; + gss_buffer_desc value; + gss_name_t mech; +} *spnego_name; + +extern gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc; +extern gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc; + #include <spnego/spnego-private.h> #endif /* SPNEGO_LOCL_H */ diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c index d1fa4ffd6a..cd4f24a732 100644 --- a/source4/heimdal/lib/hdb/hdb.c +++ b/source4/heimdal/lib/hdb/hdb.c @@ -33,7 +33,7 @@ #include "hdb_locl.h" -RCSID("$Id: hdb.c,v 1.62 2006/10/06 16:47:22 lha Exp $"); +RCSID("$Id: hdb.c,v 1.64 2006/11/28 14:24:27 lha Exp $"); #ifdef HAVE_DLFCN_H #include <dlfcn.h> diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h index 69c91d12ad..dcfceb58f0 100644 --- a/source4/heimdal/lib/hdb/hdb.h +++ b/source4/heimdal/lib/hdb/hdb.h @@ -60,24 +60,6 @@ typedef struct hdb_entry_ex { void *ctx; hdb_entry entry; void (*free_entry)(krb5_context, struct hdb_entry_ex *); - krb5_error_code (*check_client_access)(krb5_context, struct hdb_entry_ex *, - HostAddresses *); - krb5_error_code (*authz_data_as_req)(krb5_context, - struct hdb_entry_ex *, - METHOD_DATA* pa_data_seq, - time_t authtime, - const EncryptionKey *tgtkey, - const EncryptionKey *sessionkey, - AuthorizationData **out); - krb5_error_code (*authz_data_tgs_req)(krb5_context, - struct hdb_entry_ex *, - krb5_principal client, - AuthorizationData *in, - time_t authtime, - const EncryptionKey *tgtkey, - const EncryptionKey *servicekey, - const EncryptionKey *sessionkey, - AuthorizationData **out); } hdb_entry_ex; diff --git a/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x new file mode 100644 index 0000000000..e17bad6ed8 --- /dev/null +++ b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x @@ -0,0 +1,22 @@ +/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/ocsp.asn1 */ +/* Do not edit */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <errno.h> +#include <krb5-types.h> +#include <ocsp_asn1.h> +#include <asn1_err.h> +#include <der.h> +#include <parse_units.h> + +static unsigned oid_id_pkix_ocsp_variable_num[9] = {1, 3, 6, 1, 5, 5, 7, 48, 1 }; +static const heim_oid oid_id_pkix_ocsp_variable = { 9, oid_id_pkix_ocsp_variable_num }; + +const heim_oid *oid_id_pkix_ocsp(void) +{ +return &oid_id_pkix_ocsp_variable; +} + diff --git a/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x new file mode 100644 index 0000000000..6f030f1713 --- /dev/null +++ b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x @@ -0,0 +1,22 @@ +/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/ocsp.asn1 */ +/* Do not edit */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <errno.h> +#include <krb5-types.h> +#include <ocsp_asn1.h> +#include <asn1_err.h> +#include <der.h> +#include <parse_units.h> + +static unsigned oid_id_pkix_ocsp_basic_variable_num[10] = {1, 3, 6, 1, 5, 5, 7, 48, 1, 1 }; +static const heim_oid oid_id_pkix_ocsp_basic_variable = { 10, oid_id_pkix_ocsp_basic_variable_num }; + +const heim_oid *oid_id_pkix_ocsp_basic(void) +{ +return &oid_id_pkix_ocsp_basic_variable; +} + diff --git a/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x new file mode 100644 index 0000000000..36d7422a0d --- /dev/null +++ b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x @@ -0,0 +1,22 @@ +/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/ocsp.asn1 */ +/* Do not edit */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <errno.h> +#include <krb5-types.h> +#include <ocsp_asn1.h> +#include <asn1_err.h> +#include <der.h> +#include <parse_units.h> + +static unsigned oid_id_pkix_ocsp_nonce_variable_num[10] = {1, 3, 6, 1, 5, 5, 7, 48, 1, 2 }; +static const heim_oid oid_id_pkix_ocsp_nonce_variable = { 10, oid_id_pkix_ocsp_nonce_variable_num }; + +const heim_oid *oid_id_pkix_ocsp_nonce(void) +{ +return &oid_id_pkix_ocsp_nonce_variable; +} + diff --git a/source4/heimdal/lib/hx509/ca.c b/source4/heimdal/lib/hx509/ca.c new file mode 100644 index 0000000000..1a5b4947be --- /dev/null +++ b/source4/heimdal/lib/hx509/ca.c @@ -0,0 +1,893 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#include <pkinit_asn1.h> +RCSID("$Id: ca.c,v 1.12 2007/01/05 18:40:46 lha Exp $"); + +struct hx509_ca_tbs { + hx509_name subject; + SubjectPublicKeyInfo spki; + ExtKeyUsage eku; + GeneralNames san; + unsigned key_usage; + heim_integer serial; + struct { + unsigned int proxy:1; + unsigned int ca:1; + unsigned int key:1; + unsigned int serial:1; + } flags; + time_t notBefore; + time_t notAfter; + int pathLenConstraint; /* both for CA and Proxy */ +}; + +int +hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs) +{ + *tbs = calloc(1, sizeof(**tbs)); + if (*tbs == NULL) + return ENOMEM; + + (*tbs)->subject = NULL; + (*tbs)->san.len = 0; + (*tbs)->san.val = NULL; + (*tbs)->eku.len = 0; + (*tbs)->eku.val = NULL; + (*tbs)->pathLenConstraint = 0; + + return 0; +} + +void +hx509_ca_tbs_free(hx509_ca_tbs *tbs) +{ + if (tbs == NULL || *tbs == NULL) + return; + + free_SubjectPublicKeyInfo(&(*tbs)->spki); + free_GeneralNames(&(*tbs)->san); + free_ExtKeyUsage(&(*tbs)->eku); + der_free_heim_integer(&(*tbs)->serial); + + hx509_name_free(&(*tbs)->subject); + + memset(*tbs, 0, sizeof(**tbs)); + free(*tbs); + *tbs = NULL; +} + +int +hx509_ca_tbs_set_notBefore(hx509_context context, + hx509_ca_tbs tbs, + time_t t) +{ + tbs->notBefore = t; + return 0; +} + +int +hx509_ca_tbs_set_notAfter(hx509_context context, + hx509_ca_tbs tbs, + time_t t) +{ + tbs->notAfter = t; + return 0; +} + +int +hx509_ca_tbs_set_notAfter_lifetime(hx509_context context, + hx509_ca_tbs tbs, + time_t delta) +{ + return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta); +} + +int +hx509_ca_tbs_set_ca(hx509_context context, + hx509_ca_tbs tbs, + int pathLenConstraint) +{ + tbs->flags.ca = 1; + tbs->pathLenConstraint = pathLenConstraint; + return 0; +} + +int +hx509_ca_tbs_set_proxy(hx509_context context, + hx509_ca_tbs tbs, + int pathLenConstraint) +{ + tbs->flags.proxy = 1; + tbs->pathLenConstraint = pathLenConstraint; + return 0; +} + + +int +hx509_ca_tbs_set_spki(hx509_context context, + hx509_ca_tbs tbs, + const SubjectPublicKeyInfo *spki) +{ + int ret; + free_SubjectPublicKeyInfo(&tbs->spki); + ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki); + tbs->flags.key = !ret; + return ret; +} + +int +hx509_ca_tbs_set_serialnumber(hx509_context context, + hx509_ca_tbs tbs, + const heim_integer *serialNumber) +{ + int ret; + der_free_heim_integer(&tbs->serial); + ret = der_copy_heim_integer(serialNumber, &tbs->serial); + tbs->flags.serial = !ret; + return ret; +} + +int +hx509_ca_tbs_add_eku(hx509_context contex, + hx509_ca_tbs tbs, + const heim_oid *oid) +{ + void *ptr; + int ret; + + ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1)); + if (ptr == NULL) + return ENOMEM; + tbs->eku.val = ptr; + ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]); + if (ret) + return ret; + tbs->eku.len += 1; + return 0; +} + +int +hx509_ca_tbs_add_san_otherName(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *oid, + const heim_octet_string *os) +{ + GeneralName gn; + + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_otherName; + gn.u.otherName.type_id = *oid; + gn.u.otherName.value = *os; + + return add_GeneralNames(&tbs->san, &gn); +} + + +int +hx509_ca_tbs_add_san_pkinit(hx509_context context, + hx509_ca_tbs tbs, + const char *principal) +{ + heim_octet_string os; + KRB5PrincipalName p; + size_t size; + int ret; + char *s = NULL; + + memset(&p, 0, sizeof(p)); + + /* parse principal */ + { + const char *str; + char *q; + int n; + + /* count number of component */ + n = 1; + for(str = principal; *str != '\0' && *str != '@'; str++){ + if(*str=='\\'){ + if(str[1] == '\0' || str[1] == '@') { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, + "trailing \\ in principal name"); + goto out; + } + str++; + } else if(*str == '/') + n++; + } + p.principalName.name_string.val = + calloc(n, sizeof(*p.principalName.name_string.val)); + if (p.principalName.name_string.val == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc: out of memory"); + goto out; + } + p.principalName.name_string.len = n; + + p.principalName.name_type = KRB5_NT_PRINCIPAL; + q = s = strdup(principal); + if (q == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc: out of memory"); + goto out; + } + p.realm = strrchr(q, '@'); + if (p.realm == NULL) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, "Missing @ in principal"); + goto out; + }; + *p.realm++ = '\0'; + + n = 0; + while (q) { + p.principalName.name_string.val[n++] = q; + q = strchr(q, '/'); + if (q) + *q++ = '\0'; + } + } + + ASN1_MALLOC_ENCODE(KRB5PrincipalName, os.data, os.length, &p, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != os.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = hx509_ca_tbs_add_san_otherName(context, + tbs, + oid_id_pkinit_san(), + &os); + free(os.data); +out: + if (p.principalName.name_string.val) + free (p.principalName.name_string.val); + if (s) + free(s); + return ret; +} + +int +hx509_ca_tbs_add_san_hostname(hx509_context context, + hx509_ca_tbs tbs, + const char *dnsname) +{ + GeneralName gn; + + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_dNSName; + gn.u.dNSName = rk_UNCONST(dnsname); + + return add_GeneralNames(&tbs->san, &gn); +} + +int +hx509_ca_tbs_add_san_rfc822name(hx509_context context, + hx509_ca_tbs tbs, + const char *rfc822Name) +{ + GeneralName gn; + + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_rfc822Name; + gn.u.rfc822Name = rk_UNCONST(rfc822Name); + + return add_GeneralNames(&tbs->san, &gn); +} + + +int +hx509_ca_tbs_set_subject(hx509_context context, + hx509_ca_tbs tbs, + hx509_name subject) +{ + if (tbs->subject) + hx509_name_free(&tbs->subject); + return hx509_name_copy(context, subject, &tbs->subject); +} + +static int +add_extension(hx509_context context, + TBSCertificate *tbsc, + int critical_flag, + const heim_oid *oid, + const heim_octet_string *data) +{ + Extension ext; + int ret; + + memset(&ext, 0, sizeof(ext)); + + if (critical_flag) { + ext.critical = malloc(sizeof(*ext.critical)); + if (ext.critical == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + *ext.critical = TRUE; + } + + ret = der_copy_oid(oid, &ext.extnID); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = der_copy_octet_string(data, &ext.extnValue); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = add_Extensions(tbsc->extensions, &ext); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } +out: + free_Extension(&ext); + return ret; +} + +static int +build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject) +{ + char *tstr; + time_t t; + int ret; + + ret = copy_Name(issuer, subject); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy subject name"); + return ret; + } + + t = time(NULL); + asprintf(&tstr, "ts-%lu", (unsigned long)t); + if (tstr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "Failed to copy subject name"); + return ENOMEM; + } + /* prefix with CN=<ts>,...*/ + ret = _hx509_name_modify(context, subject, 1, oid_id_at_commonName(), tstr); + free(tstr); + if (ret) + free_Name(subject); + return ret; +} + +static int +ca_sign(hx509_context context, + hx509_ca_tbs tbs, + hx509_private_key signer, + const AuthorityKeyIdentifier *ai, + const Name *issuername, + hx509_cert *certificate) +{ + heim_octet_string data; + Certificate c; + TBSCertificate *tbsc; + size_t size; + int ret; + const AlgorithmIdentifier *sigalg; + time_t notBefore; + time_t notAfter; + unsigned key_usage; + + sigalg = hx509_signature_rsa_with_sha1(); + + memset(&c, 0, sizeof(c)); + + /* + * Default values are: Valid since 24h ago, valid one year into + * the future, KeyUsage digitalSignature and keyEncipherment set, + * and keyCertSign for CA certificates. + */ + notBefore = tbs->notBefore; + if (notBefore == 0) + notBefore = time(NULL) - 3600 * 24; + notAfter = tbs->notAfter; + if (notAfter == 0) + notAfter = time(NULL) + 3600 * 24 * 365; + + key_usage = tbs->key_usage; + if (key_usage == 0) { + KeyUsage ku; + memset(&ku, 0, sizeof(ku)); + ku.digitalSignature = 1; + ku.keyEncipherment = 1; + key_usage = KeyUsage2int(ku); + } + + if (tbs->flags.ca) { + KeyUsage ku; + memset(&ku, 0, sizeof(ku)); + ku.keyCertSign = 1; + key_usage |= KeyUsage2int(ku); + } + + /* + * + */ + + tbsc = &c.tbsCertificate; + + if (tbs->flags.key == 0) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, "No public key set"); + return ret; + } + if (tbs->subject == NULL && !tbs->flags.proxy) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, "No subject name set"); + return ret; + } + if (tbs->flags.ca && tbs->flags.proxy) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, "Can't be proxy and CA " + "at the same time"); + return ret; + } + if (tbs->flags.proxy) { + if (tbs->san.len > 0) { + hx509_set_error_string(context, 0, EINVAL, + "Proxy certificate is not allowed " + "to have SubjectAltNames"); + return EINVAL; + } + } + + /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */ + tbsc->version = calloc(1, sizeof(*tbsc->version)); + if (tbsc->version == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + *tbsc->version = rfc3280_version_3; + /* serialNumber CertificateSerialNumber, */ + if (tbs->flags.serial) { + ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } else { + tbsc->serialNumber.length = 20; + tbsc->serialNumber.data = malloc(tbsc->serialNumber.length); + if (tbsc->serialNumber.data == NULL){ + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + /* XXX diffrent */ + RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length); + ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f; + } + /* signature AlgorithmIdentifier, */ + ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy sigature alg"); + goto out; + } + /* issuer Name, */ + if (issuername) + ret = copy_Name(issuername, &tbsc->issuer); + else + ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy issuer name"); + goto out; + } + /* validity Validity, */ + tbsc->validity.notBefore.element = choice_Time_generalTime; + tbsc->validity.notBefore.u.generalTime = notBefore; + tbsc->validity.notAfter.element = choice_Time_generalTime; + tbsc->validity.notAfter.u.generalTime = notAfter; + /* subject Name, */ + if (tbs->flags.proxy) { + ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject); + if (ret) + goto out; + } else { + ret = hx509_name_to_Name(tbs->subject, &tbsc->subject); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy subject name"); + goto out; + } + } + /* subjectPublicKeyInfo SubjectPublicKeyInfo, */ + ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy spki"); + goto out; + } + /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */ + /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */ + /* extensions [3] EXPLICIT Extensions OPTIONAL */ + tbsc->extensions = calloc(1, sizeof(*tbsc->extensions)); + if (tbsc->extensions == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + /* add KeyUsage */ + { + KeyUsage ku; + + ku = int2KeyUsage(key_usage); + ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 1, + oid_id_x509_ce_keyUsage(), &data); + free(data.data); + if (ret) + goto out; + } + + /* add ExtendedKeyUsage */ + if (tbs->eku.len > 0) { + ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length, + &tbs->eku, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + oid_id_x509_ce_extKeyUsage(), &data); + free(data.data); + if (ret) + goto out; + } + + /* add Subject Alternative Name */ + if (tbs->san.len > 0) { + ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length, + &tbs->san, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + oid_id_x509_ce_subjectAltName(), + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add Authority Key Identifier */ + if (ai) { + ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length, + ai, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + oid_id_x509_ce_authorityKeyIdentifier(), + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add Subject Key Identifier */ + { + SubjectKeyIdentifier si; + unsigned char hash[SHA_DIGEST_LENGTH]; + + { + SHA_CTX m; + + SHA1_Init(&m); + SHA1_Update(&m, tbs->spki.subjectPublicKey.data, + tbs->spki.subjectPublicKey.length / 8); + SHA1_Final (hash, &m); + } + + si.data = hash; + si.length = sizeof(hash); + + ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length, + &si, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + oid_id_x509_ce_subjectKeyIdentifier(), + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add BasicConstraints */ + { + BasicConstraints bc; + int aCA = 1; + uint32_t path; + + memset(&bc, 0, sizeof(bc)); + + if (tbs->flags.ca) { + bc.cA = &aCA; + if (tbs->pathLenConstraint >= 0) { + path = tbs->pathLenConstraint; + bc.pathLenConstraint = &path; + } + } + + ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length, + &bc, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + oid_id_x509_ce_basicConstraints(), + &data); + free(data.data); + if (ret) + goto out; + } + + /* add Proxy */ + if (tbs->flags.proxy) { + ProxyCertInfo info; + + memset(&info, 0, sizeof(info)); + + if (tbs->pathLenConstraint >= 0) { + info.pCPathLenConstraint = + malloc(sizeof(*info.pCPathLenConstraint)); + if (info.pCPathLenConstraint == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + *info.pCPathLenConstraint = tbs->pathLenConstraint; + } + + ret = der_copy_oid(oid_id_pkix_ppl_inheritAll(), + &info.proxyPolicy.policyLanguage); + if (ret) { + free_ProxyCertInfo(&info); + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length, + &info, &size, ret); + free_ProxyCertInfo(&info); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + oid_id_pe_proxyCertInfo(), + &data); + free(data.data); + if (ret) + goto out; + } + + + ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + goto out; + } + if (data.length != size) + _hx509_abort("internal ASN.1 encoder error"); + + ret = _hx509_create_signature_bitstring(context, + signer, + sigalg, + &data, + &c.signatureAlgorithm, + &c.signatureValue); + free(data.data); + if (ret) + goto out; + + ret = hx509_cert_init(context, &c, certificate); + if (ret) + goto out; + + free_Certificate(&c); + + return 0; + +out: + free_Certificate(&c); + return ret; +} + +static int +get_AuthorityKeyIdentifier(hx509_context context, + const Certificate *certificate, + AuthorityKeyIdentifier *ai) +{ + SubjectKeyIdentifier si; + int ret; + + ret = _hx509_find_extension_subject_key_id(certificate, &si); + if (ret == 0) { + ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier)); + if (ai->keyIdentifier == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = der_copy_octet_string(&si, ai->keyIdentifier); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } else { + GeneralNames gns; + GeneralName gn; + Name name; + + memset(&gn, 0, sizeof(gn)); + memset(&gns, 0, sizeof(gns)); + memset(&name, 0, sizeof(name)); + + ai->authorityCertIssuer = + calloc(1, sizeof(*ai->authorityCertIssuer)); + if (ai->authorityCertIssuer == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ai->authorityCertSerialNumber = + calloc(1, sizeof(*ai->authorityCertSerialNumber)); + if (ai->authorityCertSerialNumber == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + /* + * XXX unbreak when asn1 compiler handle IMPLICIT + * + * This is so horrible. + */ + + ret = copy_Name(&certificate->tbsCertificate.subject, &name); + if (ai->authorityCertSerialNumber == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + gn.element = choice_GeneralName_directoryName; + gn.u.directoryName.element = + choice_GeneralName_directoryName_rdnSequence; + gn.u.directoryName.u.rdnSequence = name.u.rdnSequence; + + ret = add_GeneralNames(&gns, &gn); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + ai->authorityCertIssuer->val = gns.val; + ai->authorityCertIssuer->len = gns.len; + + ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber, + ai->authorityCertSerialNumber); + if (ai->authorityCertSerialNumber == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } +out: + if (ret) + free_AuthorityKeyIdentifier(ai); + return ret; +} + + +int +hx509_ca_sign(hx509_context context, + hx509_ca_tbs tbs, + hx509_cert signer, + hx509_cert *certificate) +{ + const Certificate *signer_cert; + AuthorityKeyIdentifier ai; + int ret; + + memset(&ai, 0, sizeof(ai)); + + signer_cert = _hx509_get_cert(signer); + + ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai); + if (ret) + goto out; + + ret = ca_sign(context, + tbs, + _hx509_cert_private_key(signer), + &ai, + &signer_cert->tbsCertificate.subject, + certificate); + +out: + free_AuthorityKeyIdentifier(&ai); + + return ret; +} + +int +hx509_ca_sign_self(hx509_context context, + hx509_ca_tbs tbs, + hx509_private_key signer, + hx509_cert *certificate) +{ + return ca_sign(context, + tbs, + signer, + NULL, + NULL, + certificate); +} diff --git a/source4/heimdal/lib/hx509/cert.c b/source4/heimdal/lib/hx509/cert.c new file mode 100644 index 0000000000..f84c61a798 --- /dev/null +++ b/source4/heimdal/lib/hx509/cert.c @@ -0,0 +1,2214 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: cert.c,v 1.82 2007/01/09 10:52:03 lha Exp $"); +#include "crypto-headers.h" + +struct hx509_verify_ctx_data { + hx509_certs trust_anchors; + int flags; +#define HX509_VERIFY_CTX_F_TIME_SET 1 +#define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2 +#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4 +#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8 + time_t time_now; + unsigned int max_depth; +#define HX509_VERIFY_MAX_DEPTH 30 + hx509_revoke_ctx revoke_ctx; +}; + +#define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280) +#define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS) + +struct _hx509_cert_attrs { + size_t len; + hx509_cert_attribute *val; +}; + +struct hx509_cert_data { + unsigned int ref; + char *friendlyname; + Certificate *data; + hx509_private_key private_key; + struct _hx509_cert_attrs attrs; + hx509_name basename; + _hx509_cert_release_func release; + void *ctx; +}; + +typedef struct hx509_name_constraints { + NameConstraints *val; + size_t len; +} hx509_name_constraints; + +#define GeneralSubtrees_SET(g,var) \ + (g)->len = (var)->len, (g)->val = (var)->val; + +/* + * + */ + +void +_hx509_abort(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + fflush(stdout); + abort(); +} + +/* + * + */ + +int +hx509_context_init(hx509_context *context) +{ + *context = calloc(1, sizeof(**context)); + if (*context == NULL) + return ENOMEM; + + _hx509_ks_mem_register(*context); + _hx509_ks_file_register(*context); + _hx509_ks_pkcs12_register(*context); + _hx509_ks_pkcs11_register(*context); + _hx509_ks_dir_register(*context); + + ENGINE_add_conf_module(); + OpenSSL_add_all_algorithms(); + + (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF; + + initialize_hx_error_table_r(&(*context)->et_list); + initialize_asn1_error_table_r(&(*context)->et_list); + + return 0; +} + +void +hx509_context_set_missing_revoke(hx509_context context, int flag) +{ + if (flag) + context->flags |= HX509_CTX_VERIFY_MISSING_OK; + else + context->flags &= ~HX509_CTX_VERIFY_MISSING_OK; +} + +void +hx509_context_free(hx509_context *context) +{ + hx509_clear_error_string(*context); + if ((*context)->ks_ops) { + free((*context)->ks_ops); + (*context)->ks_ops = NULL; + } + (*context)->ks_num_ops = 0; + free_error_table ((*context)->et_list); + free(*context); + *context = NULL; +} + + +/* + * + */ + +Certificate * +_hx509_get_cert(hx509_cert cert) +{ + return cert->data; +} + +/* + * + */ + +#if 0 +void +_hx509_print_cert_subject(hx509_cert cert) +{ + char *subject_name; + hx509_name name; + int ret; + + ret = hx509_cert_get_subject(cert, &name); + if (ret) + abort(); + + ret = hx509_name_to_string(name, &subject_name); + hx509_name_free(&name); + if (ret) + abort(); + + printf("name: %s\n", subject_name); + + free(subject_name); +} +#endif + +/* + * + */ + +int +_hx509_cert_get_version(const Certificate *t) +{ + return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1; +} + +int +hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert) +{ + int ret; + + *cert = malloc(sizeof(**cert)); + if (*cert == NULL) + return ENOMEM; + (*cert)->ref = 1; + (*cert)->friendlyname = NULL; + (*cert)->attrs.len = 0; + (*cert)->attrs.val = NULL; + (*cert)->private_key = NULL; + (*cert)->basename = NULL; + (*cert)->release = NULL; + (*cert)->ctx = NULL; + + (*cert)->data = calloc(1, sizeof(*(*cert)->data)); + if ((*cert)->data == NULL) { + free(*cert); + return ENOMEM; + } + ret = copy_Certificate(c, (*cert)->data); + if (ret) { + free((*cert)->data); + free(*cert); + } + return ret; +} + +void +_hx509_cert_set_release(hx509_cert cert, + _hx509_cert_release_func release, + void *ctx) +{ + cert->release = release; + cert->ctx = ctx; +} + + +/* Doesn't make a copy of `private_key'. */ + +int +_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key) +{ + if (cert->private_key) + _hx509_private_key_free(&cert->private_key); + cert->private_key = _hx509_private_key_ref(private_key); + return 0; +} + +void +hx509_cert_free(hx509_cert cert) +{ + int i; + + if (cert == NULL) + return; + + if (cert->ref <= 0) + _hx509_abort("refcount <= 0"); + if (--cert->ref > 0) + return; + + if (cert->release) + (cert->release)(cert, cert->ctx); + + if (cert->private_key) + _hx509_private_key_free(&cert->private_key); + + free_Certificate(cert->data); + free(cert->data); + + for (i = 0; i < cert->attrs.len; i++) { + der_free_octet_string(&cert->attrs.val[i]->data); + der_free_oid(&cert->attrs.val[i]->oid); + free(cert->attrs.val[i]); + } + free(cert->attrs.val); + free(cert->friendlyname); + if (cert->basename) + hx509_name_free(&cert->basename); + memset(cert, 0, sizeof(cert)); + free(cert); +} + +hx509_cert +hx509_cert_ref(hx509_cert cert) +{ + if (cert->ref <= 0) + _hx509_abort("refcount <= 0"); + cert->ref++; + if (cert->ref == 0) + _hx509_abort("refcount == 0"); + return cert; +} + +int +hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx) +{ + hx509_verify_ctx c; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return ENOMEM; + + c->max_depth = HX509_VERIFY_MAX_DEPTH; + + *ctx = c; + + return 0; +} + +void +hx509_verify_destroy_ctx(hx509_verify_ctx ctx) +{ + if (ctx) + memset(ctx, 0, sizeof(*ctx)); + free(ctx); +} + +void +hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set) +{ + ctx->trust_anchors = set; +} + +void +hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx) +{ + ctx->revoke_ctx = revoke_ctx; +} + +void +hx509_verify_set_time(hx509_verify_ctx ctx, time_t t) +{ + ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET; + ctx->time_now = t; +} + +void +hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean) +{ + if (boolean) + ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; + else + ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; +} + +void +hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean) +{ + if (boolean) + ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280; + else + ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280; +} + +static const Extension * +find_extension(const Certificate *cert, const heim_oid *oid, int *idx) +{ + const TBSCertificate *c = &cert->tbsCertificate; + + if (c->version == NULL || *c->version < 2 || c->extensions == NULL) + return NULL; + + for (;*idx < c->extensions->len; (*idx)++) { + if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0) + return &c->extensions->val[(*idx)++]; + } + return NULL; +} + +static int +find_extension_auth_key_id(const Certificate *subject, + AuthorityKeyIdentifier *ai) +{ + const Extension *e; + size_t size; + int i = 0; + + memset(ai, 0, sizeof(*ai)); + + e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_AuthorityKeyIdentifier(e->extnValue.data, + e->extnValue.length, + ai, &size); +} + +int +_hx509_find_extension_subject_key_id(const Certificate *issuer, + SubjectKeyIdentifier *si) +{ + const Extension *e; + size_t size; + int i = 0; + + memset(si, 0, sizeof(*si)); + + e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_SubjectKeyIdentifier(e->extnValue.data, + e->extnValue.length, + si, &size); +} + +static int +find_extension_name_constraints(const Certificate *subject, + NameConstraints *nc) +{ + const Extension *e; + size_t size; + int i = 0; + + memset(nc, 0, sizeof(*nc)); + + e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_NameConstraints(e->extnValue.data, + e->extnValue.length, + nc, &size); +} + +static int +find_extension_subject_alt_name(const Certificate *cert, int *i, + GeneralNames *sa) +{ + const Extension *e; + size_t size; + + memset(sa, 0, sizeof(*sa)); + + e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_GeneralNames(e->extnValue.data, + e->extnValue.length, + sa, &size); +} + +static int +find_extension_eku(const Certificate *cert, ExtKeyUsage *eku) +{ + const Extension *e; + size_t size; + int i = 0; + + memset(eku, 0, sizeof(*eku)); + + e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_ExtKeyUsage(e->extnValue.data, + e->extnValue.length, + eku, &size); +} + +static int +add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry) +{ + void *p; + int ret; + + p = realloc(list->val, (list->len + 1) * sizeof(list->val[0])); + if (p == NULL) + return ENOMEM; + list->val = p; + ret = der_copy_octet_string(entry, &list->val[list->len]); + if (ret) + return ret; + list->len++; + return 0; +} + +void +hx509_free_octet_string_list(hx509_octet_string_list *list) +{ + int i; + for (i = 0; i < list->len; i++) + der_free_octet_string(&list->val[i]); + free(list->val); + list->val = NULL; + list->len = 0; +} + +int +hx509_cert_find_subjectAltName_otherName(hx509_cert cert, + const heim_oid *oid, + hx509_octet_string_list *list) +{ + GeneralNames sa; + int ret, i, j; + + list->val = NULL; + list->len = 0; + + i = 0; + while (1) { + ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa); + i++; + if (ret == HX509_EXTENSION_NOT_FOUND) { + ret = 0; + break; + } else if (ret != 0) + break; + + + for (j = 0; j < sa.len; j++) { + if (sa.val[j].element == choice_GeneralName_otherName && + der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0) + { + ret = add_to_list(list, &sa.val[j].u.otherName.value); + if (ret) { + free_GeneralNames(&sa); + return ret; + } + } + } + free_GeneralNames(&sa); + } + return ret; +} + + +static int +check_key_usage(hx509_context context, const Certificate *cert, + unsigned flags, int req_present) +{ + const Extension *e; + KeyUsage ku; + size_t size; + int ret, i = 0; + unsigned ku_flags; + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i); + if (e == NULL) { + if (req_present) { + hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, + "Required extension key " + "usage missing from certifiate"); + return HX509_KU_CERT_MISSING; + } + return 0; + } + + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size); + if (ret) + return ret; + ku_flags = KeyUsage2int(ku); + if ((ku_flags & flags) != flags) { + unsigned missing = (~ku_flags) & flags; + char buf[256], *name; + + unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf)); + _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); + hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, + "Key usage %s required but missing " + "from certifiate %s", buf, name); + free(name); + return HX509_KU_CERT_MISSING; + } + return 0; +} + +int +_hx509_check_key_usage(hx509_context context, hx509_cert cert, + unsigned flags, int req_present) +{ + return check_key_usage(context, _hx509_get_cert(cert), flags, req_present); +} + +enum certtype { PROXY_CERT, EE_CERT, CA_CERT }; + +static int +check_basic_constraints(hx509_context context, const Certificate *cert, + enum certtype type, int depth) +{ + BasicConstraints bc; + const Extension *e; + size_t size; + int ret, i = 0; + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i); + if (e == NULL) { + switch(type) { + case PROXY_CERT: + case EE_CERT: + return 0; + case CA_CERT: { + char *name; + ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); + assert(ret == 0); + hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND, + "basicConstraints missing from " + "CA certifiacte %s", name); + free(name); + return HX509_EXTENSION_NOT_FOUND; + } + } + } + + ret = decode_BasicConstraints(e->extnValue.data, + e->extnValue.length, &bc, + &size); + if (ret) + return ret; + switch(type) { + case PROXY_CERT: + if (bc.cA != NULL && *bc.cA) + ret = HX509_PARENT_IS_CA; + break; + case EE_CERT: + ret = 0; + break; + case CA_CERT: + if (bc.cA == NULL || !*bc.cA) + ret = HX509_PARENT_NOT_CA; + else if (bc.pathLenConstraint) + if (depth - 1 > *bc.pathLenConstraint) + ret = HX509_CA_PATH_TOO_DEEP; + break; + } + free_BasicConstraints(&bc); + return ret; +} + +int +_hx509_cert_is_parent_cmp(const Certificate *subject, + const Certificate *issuer, + int allow_self_signed) +{ + int diff; + AuthorityKeyIdentifier ai; + SubjectKeyIdentifier si; + int ret_ai, ret_si; + + diff = _hx509_name_cmp(&issuer->tbsCertificate.subject, + &subject->tbsCertificate.issuer); + if (diff) + return diff; + + memset(&ai, 0, sizeof(ai)); + memset(&si, 0, sizeof(si)); + + /* + * Try to find AuthorityKeyIdentifier, if its not present in the + * subject certificate nor the parent. + */ + + ret_ai = find_extension_auth_key_id(subject, &ai); + if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND) + return 1; + ret_si = _hx509_find_extension_subject_key_id(issuer, &si); + if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND) + return -1; + + if (ret_si && ret_ai) + goto out; + if (ret_ai) + goto out; + if (ret_si) { + if (allow_self_signed) { + diff = 0; + goto out; + } else if (ai.keyIdentifier) { + diff = -1; + goto out; + } + } + + if (ai.keyIdentifier == NULL) { + Name name; + + if (ai.authorityCertIssuer == NULL) + return -1; + if (ai.authorityCertSerialNumber == NULL) + return -1; + + diff = der_heim_integer_cmp(ai.authorityCertSerialNumber, + &issuer->tbsCertificate.serialNumber); + if (diff) + return diff; + if (ai.authorityCertIssuer->len != 1) + return -1; + if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName) + return -1; + + name.element = + ai.authorityCertIssuer->val[0].u.directoryName.element; + name.u.rdnSequence = + ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence; + + diff = _hx509_name_cmp(&issuer->tbsCertificate.subject, + &name); + if (diff) + return diff; + diff = 0; + } else + diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si); + if (diff) + goto out; + + out: + free_AuthorityKeyIdentifier(&ai); + free_SubjectKeyIdentifier(&si); + return diff; +} + +static int +certificate_is_anchor(hx509_context context, + hx509_certs trust_anchors, + const hx509_cert cert) +{ + hx509_query q; + hx509_cert c; + int ret; + + if (trust_anchors == NULL) + return 0; + + _hx509_query_clear(&q); + + q.match = HX509_QUERY_MATCH_CERTIFICATE; + q.certificate = _hx509_get_cert(cert); + + ret = hx509_certs_find(context, trust_anchors, &q, &c); + if (ret == 0) + hx509_cert_free(c); + return ret == 0; +} + +static int +certificate_is_self_signed(const Certificate *cert) +{ + return _hx509_cert_is_parent_cmp(cert, cert, 1) == 0; +} + +/* + * The subjectName is "null" when its empty set of relative DBs. + */ + +static int +subject_null_p(const Certificate *c) +{ + return c->tbsCertificate.subject.u.rdnSequence.len == 0; +} + + +static int +find_parent(hx509_context context, + time_t time_now, + hx509_certs trust_anchors, + hx509_path *path, + hx509_certs pool, + hx509_cert current, + hx509_cert *parent) +{ + AuthorityKeyIdentifier ai; + hx509_query q; + int ret; + + *parent = NULL; + memset(&ai, 0, sizeof(ai)); + + _hx509_query_clear(&q); + + if (!subject_null_p(current->data)) { + q.match |= HX509_QUERY_FIND_ISSUER_CERT; + q.subject = _hx509_get_cert(current); + } else { + ret = find_extension_auth_key_id(current->data, &ai); + if (ret) { + hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, + "Subjectless certificate missing AuthKeyID"); + return HX509_CERTIFICATE_MALFORMED; + } + + if (ai.keyIdentifier == NULL) { + free_AuthorityKeyIdentifier(&ai); + hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, + "Subjectless certificate missing keyIdentifier " + "inside AuthKeyID"); + return HX509_CERTIFICATE_MALFORMED; + } + + q.subject_id = ai.keyIdentifier; + q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; + } + + q.path = path; + q.match |= HX509_QUERY_NO_MATCH_PATH; + + if (pool) { + q.timenow = time_now; + q.match |= HX509_QUERY_MATCH_TIME; + + ret = hx509_certs_find(context, pool, &q, parent); + if (ret == 0) { + free_AuthorityKeyIdentifier(&ai); + return 0; + } + q.match &= ~HX509_QUERY_MATCH_TIME; + } + + if (trust_anchors) { + ret = hx509_certs_find(context, trust_anchors, &q, parent); + if (ret == 0) { + free_AuthorityKeyIdentifier(&ai); + return ret; + } + } + free_AuthorityKeyIdentifier(&ai); + + { + hx509_name name; + char *str; + + ret = hx509_cert_get_subject(current, &name); + if (ret) { + hx509_clear_error_string(context); + return HX509_ISSUER_NOT_FOUND; + } + ret = hx509_name_to_string(name, &str); + hx509_name_free(&name); + if (ret) { + hx509_clear_error_string(context); + return HX509_ISSUER_NOT_FOUND; + } + + hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND, + "Failed to find issuer for " + "certificate with subject: %s", str); + free(str); + } + return HX509_ISSUER_NOT_FOUND; +} + +/* + * + */ + +static int +is_proxy_cert(hx509_context context, const Certificate *cert, ProxyCertInfo *rinfo) +{ + ProxyCertInfo info; + const Extension *e; + size_t size; + int ret, i = 0; + + if (rinfo) + memset(rinfo, 0, sizeof(*rinfo)); + + e = find_extension(cert, oid_id_pe_proxyCertInfo(), &i); + if (e == NULL) { + hx509_clear_error_string(context); + return HX509_EXTENSION_NOT_FOUND; + } + + ret = decode_ProxyCertInfo(e->extnValue.data, + e->extnValue.length, + &info, + &size); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + if (size != e->extnValue.length) { + free_ProxyCertInfo(&info); + hx509_clear_error_string(context); + return HX509_EXTRA_DATA_AFTER_STRUCTURE; + } + if (rinfo) + *rinfo = info; + + return 0; +} + +/* + * Path operations are like MEMORY based keyset, but with exposed + * internal so we can do easy searches. + */ + +int +_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert) +{ + hx509_cert *val; + val = realloc(path->val, (path->len + 1) * sizeof(path->val[0])); + if (val == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + path->val = val; + path->val[path->len] = hx509_cert_ref(cert); + path->len++; + + return 0; +} + +void +_hx509_path_free(hx509_path *path) +{ + unsigned i; + + for (i = 0; i < path->len; i++) + hx509_cert_free(path->val[i]); + free(path->val); + path->val = NULL; + path->len = 0; +} + +/* + * Find path by looking up issuer for the top certificate and continue + * until an anchor certificate is found or max limit is found. A + * certificate never included twice in the path. + * + * If the trust anchors are not given, calculate optimistic path, just + * follow the chain upward until we no longer find a parent or we hit + * the max path limit. In this case, a failure will always be returned + * depending on what error condition is hit first. + * + * The path includes a path from the top certificate to the anchor + * certificate. + * + * The caller needs to free `path´ both on successful built path and + * failure. + */ + +int +_hx509_calculate_path(hx509_context context, + int flags, + time_t time_now, + hx509_certs anchors, + unsigned int max_depth, + hx509_cert cert, + hx509_certs pool, + hx509_path *path) +{ + hx509_cert parent, current; + int ret; + + if (max_depth == 0) + max_depth = HX509_VERIFY_MAX_DEPTH; + + ret = _hx509_path_append(context, path, cert); + if (ret) + return ret; + + current = hx509_cert_ref(cert); + + while (!certificate_is_anchor(context, anchors, current)) { + + ret = find_parent(context, time_now, anchors, path, + pool, current, &parent); + hx509_cert_free(current); + if (ret) + return ret; + + ret = _hx509_path_append(context, path, parent); + if (ret) + return ret; + current = parent; + + if (path->len > max_depth) { + hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG, + "Path too long while bulding certificate chain"); + return HX509_PATH_TOO_LONG; + } + } + + if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) && + path->len > 0 && + certificate_is_anchor(context, anchors, path->val[path->len - 1])) + { + hx509_cert_free(path->val[path->len - 1]); + path->len--; + } + + hx509_cert_free(current); + return 0; +} + +static int +AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p, + const AlgorithmIdentifier *q) +{ + int diff; + diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm); + if (diff) + return diff; + if (p->parameters) { + if (q->parameters) + return heim_any_cmp(p->parameters, + q->parameters); + else + return 1; + } else { + if (q->parameters) + return -1; + else + return 0; + } +} + +int +_hx509_Certificate_cmp(const Certificate *p, const Certificate *q) +{ + int diff; + diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue); + if (diff) + return diff; + diff = AlgorithmIdentifier_cmp(&p->signatureAlgorithm, + &q->signatureAlgorithm); + if (diff) + return diff; + diff = der_heim_octet_string_cmp(&p->tbsCertificate._save, + &q->tbsCertificate._save); + return diff; +} + +int +hx509_cert_cmp(hx509_cert p, hx509_cert q) +{ + return _hx509_Certificate_cmp(p->data, q->data); +} + +int +hx509_cert_get_issuer(hx509_cert p, hx509_name *name) +{ + return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name); +} + +int +hx509_cert_get_subject(hx509_cert p, hx509_name *name) +{ + return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name); +} + +int +hx509_cert_get_base_subject(hx509_context context, hx509_cert c, + hx509_name *name) +{ + if (c->basename) + return hx509_name_copy(context, c->basename, name); + if (is_proxy_cert(context, c->data, NULL) == 0) { + int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED; + hx509_set_error_string(context, 0, ret, + "Proxy certificate have not been " + "canonicalize yet, no base name"); + return ret; + } + return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name); +} + +int +hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i) +{ + return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i); +} + +hx509_private_key +_hx509_cert_private_key(hx509_cert p) +{ + return p->private_key; +} + +int +_hx509_cert_private_key_exportable(hx509_cert p) +{ + if (p->private_key == NULL) + return 0; + return _hx509_private_key_exportable(p->private_key); +} + +int +_hx509_cert_private_decrypt(hx509_context context, + const heim_octet_string *ciphertext, + const heim_oid *encryption_oid, + hx509_cert p, + heim_octet_string *cleartext) +{ + cleartext->data = NULL; + cleartext->length = 0; + + if (p->private_key == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "Private key missing"); + return HX509_PRIVATE_KEY_MISSING; + } + + return _hx509_private_key_private_decrypt(context, + ciphertext, + encryption_oid, + p->private_key, + cleartext); +} + +int +_hx509_cert_public_encrypt(hx509_context context, + const heim_octet_string *cleartext, + const hx509_cert p, + heim_oid *encryption_oid, + heim_octet_string *ciphertext) +{ + return _hx509_public_encrypt(context, + cleartext, p->data, + encryption_oid, ciphertext); +} + +/* + * + */ + +time_t +_hx509_Time2time_t(const Time *t) +{ + switch(t->element) { + case choice_Time_utcTime: + return t->u.utcTime; + case choice_Time_generalTime: + return t->u.generalTime; + } + return 0; +} + +/* + * + */ + +static int +init_name_constraints(hx509_name_constraints *nc) +{ + memset(nc, 0, sizeof(*nc)); + return 0; +} + +static int +add_name_constraints(hx509_context context, const Certificate *c, int not_ca, + hx509_name_constraints *nc) +{ + NameConstraints tnc; + int ret; + + ret = find_extension_name_constraints(c, &tnc); + if (ret == HX509_EXTENSION_NOT_FOUND) + return 0; + else if (ret) { + hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints"); + return ret; + } else if (not_ca) { + ret = HX509_VERIFY_CONSTRAINTS; + hx509_set_error_string(context, 0, ret, "Not a CA and " + "have NameConstraints"); + } else { + NameConstraints *val; + val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1)); + if (val == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + nc->val = val; + ret = copy_NameConstraints(&tnc, &nc->val[nc->len]); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + nc->len += 1; + } +out: + free_NameConstraints(&tnc); + return ret; +} + +static int +match_RDN(const RelativeDistinguishedName *c, + const RelativeDistinguishedName *n) +{ + int i; + + if (c->len != n->len) + return HX509_NAME_CONSTRAINT_ERROR; + + for (i = 0; i < n->len; i++) { + if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + } + return 0; +} + +static int +match_X501Name(const Name *c, const Name *n) +{ + int i, ret; + + if (c->element != choice_Name_rdnSequence + || n->element != choice_Name_rdnSequence) + return 0; + if (c->u.rdnSequence.len > n->u.rdnSequence.len) + return HX509_NAME_CONSTRAINT_ERROR; + for (i = 0; i < c->u.rdnSequence.len; i++) { + ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]); + if (ret) + return ret; + } + return 0; +} + + +static int +match_general_name(const GeneralName *c, const GeneralName *n, int *match) +{ + /* + * Name constraints only apply to the same name type, see RFC3280, + * 4.2.1.11. + */ + assert(c->element == n->element); + + switch(c->element) { + case choice_GeneralName_otherName: + if (der_heim_oid_cmp(&c->u.otherName.type_id, + &n->u.otherName.type_id) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (heim_any_cmp(&c->u.otherName.value, + &n->u.otherName.value) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + *match = 1; + return 0; + case choice_GeneralName_rfc822Name: { + const char *s; + size_t len1, len2; + s = strchr(c->u.rfc822Name, '@'); + if (s) { + if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + } else { + s = strchr(n->u.rfc822Name, '@'); + if (s == NULL) + return HX509_NAME_CONSTRAINT_ERROR; + len1 = strlen(c->u.rfc822Name); + len2 = strlen(s + 1); + if (len1 > len2) + return HX509_NAME_CONSTRAINT_ERROR; + if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (len1 < len2 && s[len2 - len1] != '.') + return HX509_NAME_CONSTRAINT_ERROR; + } + *match = 1; + return 0; + } + case choice_GeneralName_dNSName: { + size_t len1, len2; + + len1 = strlen(c->u.dNSName); + len2 = strlen(n->u.dNSName); + if (len1 > len2) + return HX509_NAME_CONSTRAINT_ERROR; + if (strcasecmp(&n->u.dNSName[len2 - len1], c->u.dNSName) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + *match = 1; + return 0; + } + case choice_GeneralName_directoryName: { + Name c_name, n_name; + int ret; + + c_name._save.data = NULL; + c_name._save.length = 0; + c_name.element = c->u.directoryName.element; + c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence; + + n_name._save.data = NULL; + n_name._save.length = 0; + n_name.element = n->u.directoryName.element; + n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence; + + ret = match_X501Name(&c_name, &n_name); + if (ret == 0) + *match = 1; + return ret; + } + case choice_GeneralName_uniformResourceIdentifier: + case choice_GeneralName_iPAddress: + case choice_GeneralName_registeredID: + default: + return HX509_NAME_CONSTRAINT_ERROR; + } +} + +static int +match_alt_name(const GeneralName *n, const Certificate *c, + int *same, int *match) +{ + GeneralNames sa; + int ret, i, j; + + i = 0; + do { + ret = find_extension_subject_alt_name(c, &i, &sa); + if (ret == HX509_EXTENSION_NOT_FOUND) { + ret = 0; + break; + } else if (ret != 0) + break; + + for (j = 0; j < sa.len; j++) { + if (n->element == sa.val[j].element) { + *same = 1; + ret = match_general_name(n, &sa.val[j], match); + } + } + free_GeneralNames(&sa); + } while (1); + + return ret; +} + + +static int +match_tree(const GeneralSubtrees *t, const Certificate *c, int *match) +{ + int name, alt_name, same; + unsigned int i; + int ret = 0; + + name = alt_name = same = *match = 0; + for (i = 0; i < t->len; i++) { + if (t->val[i].minimum && t->val[i].maximum) + return HX509_RANGE; + + /* + * If the constraint apply to directoryNames, test is with + * subjectName of the certificate if the certificate have a + * non-null (empty) subjectName. + */ + + if (t->val[i].base.element == choice_GeneralName_directoryName + && !subject_null_p(c)) + { + GeneralName certname; + + + certname.element = choice_GeneralName_directoryName; + certname.u.directoryName.element = + c->tbsCertificate.subject.element; + certname.u.directoryName.u.rdnSequence = + c->tbsCertificate.subject.u.rdnSequence; + + ret = match_general_name(&t->val[i].base, &certname, &name); + } + + /* Handle subjectAltNames, this is icky since they + * restrictions only apply if the subjectAltName is of the + * same type. So if there have been a match of type, require + * altname to be set. + */ + ret = match_alt_name(&t->val[i].base, c, &same, &alt_name); + } + if (name && (!same || alt_name)) + *match = 1; + return ret; +} + +static int +check_name_constraints(hx509_context context, + const hx509_name_constraints *nc, + const Certificate *c) +{ + int match, ret; + int i; + + for (i = 0 ; i < nc->len; i++) { + GeneralSubtrees gs; + + if (nc->val[i].permittedSubtrees) { + GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees); + ret = match_tree(&gs, c, &match); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + /* allow null subjectNames, they wont matches anything */ + if (match == 0 && !subject_null_p(c)) { + hx509_clear_error_string(context); + return HX509_VERIFY_CONSTRAINTS; + } + } + if (nc->val[i].excludedSubtrees) { + GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees); + ret = match_tree(&gs, c, &match); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + if (match) { + hx509_clear_error_string(context); + return HX509_VERIFY_CONSTRAINTS; + } + } + } + return 0; +} + +static void +free_name_constraints(hx509_name_constraints *nc) +{ + int i; + + for (i = 0 ; i < nc->len; i++) + free_NameConstraints(&nc->val[i]); + free(nc->val); +} + +int +hx509_verify_path(hx509_context context, + hx509_verify_ctx ctx, + hx509_cert cert, + hx509_certs pool) +{ + hx509_name_constraints nc; + hx509_path path; +#if 0 + const AlgorithmIdentifier *alg_id; +#endif + int ret, i, proxy_cert_depth; + enum certtype type; + Name proxy_issuer; + + memset(&proxy_issuer, 0, sizeof(proxy_issuer)); + + ret = init_name_constraints(&nc); + if (ret) + return ret; + + path.val = NULL; + path.len = 0; + + if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0) + ctx->time_now = time(NULL); + + /* + * Calculate the path from the certificate user presented to the + * to an anchor. + */ + ret = _hx509_calculate_path(context, 0, ctx->time_now, + ctx->trust_anchors, ctx->max_depth, + cert, pool, &path); + if (ret) + goto out; + +#if 0 + alg_id = path.val[path->len - 1]->data->tbsCertificate.signature; +#endif + + /* + * Check CA and proxy certificate chain from the top of the + * certificate chain. Also check certificate is valid with respect + * to the current time. + * + */ + + proxy_cert_depth = 0; + + if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) + type = PROXY_CERT; + else + type = EE_CERT; + + for (i = 0; i < path.len; i++) { + Certificate *c; + time_t t; + + c = _hx509_get_cert(path.val[i]); + + /* + * Lets do some basic check on issuer like + * keyUsage.keyCertSign and basicConstraints.cA bit depending + * on what type of certificate this is. + */ + + switch (type) { + case CA_CERT: + /* XXX make constants for keyusage */ + ret = check_key_usage(context, c, 1 << 5, + REQUIRE_RFC3280(ctx) ? TRUE : FALSE); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Key usage missing from CA certificate"); + goto out; + } + break; + case PROXY_CERT: { + ProxyCertInfo info; + + if (is_proxy_cert(context, c, &info) == 0) { + int j; + + if (info.pCPathLenConstraint != NULL && + *info.pCPathLenConstraint < i) + { + free_ProxyCertInfo(&info); + ret = HX509_PATH_TOO_LONG; + hx509_set_error_string(context, 0, ret, + "Proxy certificate chain " + "longer then allowed"); + goto out; + } + /* XXX MUST check info.proxyPolicy */ + free_ProxyCertInfo(&info); + + j = 0; + if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) { + ret = HX509_PROXY_CERT_INVALID; + hx509_set_error_string(context, 0, ret, + "Proxy certificate have explicity " + "forbidden subjectAltName"); + goto out; + } + + j = 0; + if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) { + ret = HX509_PROXY_CERT_INVALID; + hx509_set_error_string(context, 0, ret, + "Proxy certificate have explicity " + "forbidden issuerAltName"); + goto out; + } + + /* + * The subject name of the proxy certificate should be + * CN=XXX,<proxy issuer>, prune of CN and check if its + * the same over the whole chain of proxy certs and + * then check with the EE cert when we get to it. + */ + + if (proxy_cert_depth) { + ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject); + if (ret) { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_set_error_string(context, 0, ret, + "Base proxy name not right"); + goto out; + } + } + + free_Name(&proxy_issuer); + + ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + j = proxy_issuer.u.rdnSequence.len; + if (proxy_issuer.u.rdnSequence.len < 2 + || proxy_issuer.u.rdnSequence.val[j - 1].len > 1 + || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type, + oid_id_at_commonName())) + { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_set_error_string(context, 0, ret, + "Proxy name too short or " + "does not have Common name " + "at the top"); + goto out; + } + + free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]); + proxy_issuer.u.rdnSequence.len -= 1; + + ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer); + if (ret != 0) { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_set_error_string(context, 0, ret, + "Proxy issuer name not as expected"); + goto out; + } + + break; + } else { + /* + * Now we are done with the proxy certificates, this + * cert was an EE cert and we we will fall though to + * EE checking below. + */ + type = EE_CERT; + /* FALLTHOUGH */ + } + } + case EE_CERT: + /* + * If there where any proxy certificates in the chain + * (proxy_cert_depth > 0), check that the proxy issuer + * matched proxy certificates "base" subject. + */ + if (proxy_cert_depth) { + + ret = _hx509_name_cmp(&proxy_issuer, + &c->tbsCertificate.subject); + if (ret) { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_clear_error_string(context); + goto out; + } + if (cert->basename) + hx509_name_free(&cert->basename); + + ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + + break; + } + + ret = check_basic_constraints(context, c, type, i - proxy_cert_depth); + if (ret) + goto out; + + /* + * Don't check the trust anchors expiration time since they + * are transported out of band, from RFC3820. + */ + if (i + 1 != path.len || CHECK_TA(ctx)) { + + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); + if (t > ctx->time_now) { + ret = HX509_CERT_USED_BEFORE_TIME; + hx509_clear_error_string(context); + goto out; + } + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); + if (t < ctx->time_now) { + ret = HX509_CERT_USED_AFTER_TIME; + hx509_clear_error_string(context); + goto out; + } + } + + if (type == EE_CERT) + type = CA_CERT; + else if (type == PROXY_CERT) + proxy_cert_depth++; + } + + /* + * Verify constraints, do this backward so path constraints are + * checked in the right order. + */ + + for (ret = 0, i = path.len - 1; i >= 0; i--) { + Certificate *c; + + c = _hx509_get_cert(path.val[i]); + +#if 0 + /* check that algorithm and parameters is the same */ + /* XXX this is wrong */ + ret = alg_cmp(&c->tbsCertificate.signature, alg_id); + if (ret) { + hx509_clear_error_string(context); + ret = HX509_PATH_ALGORITHM_CHANGED; + goto out; + } +#endif + + /* verify name constraints, not for selfsigned and anchor */ + if (!certificate_is_self_signed(c) || i == path.len - 1) { + ret = check_name_constraints(context, &nc, c); + if (ret) { + goto out; + } + } + ret = add_name_constraints(context, c, i == 0, &nc); + if (ret) + goto out; + + /* XXX verify all other silly constraints */ + + } + + /* + * Verify that no certificates has been revoked. + */ + + if (ctx->revoke_ctx) { + hx509_certs certs; + + ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0, + NULL, &certs); + if (ret) + goto out; + + for (i = 0; i < path.len; i++) { + ret = hx509_certs_add(context, certs, path.val[i]); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + } + ret = hx509_certs_merge(context, certs, pool); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + + for (i = 0; i < path.len - 1; i++) { + int parent = (i < path.len - 1) ? i + 1 : i; + + ret = hx509_revoke_verify(context, + ctx->revoke_ctx, + certs, + ctx->time_now, + path.val[i], + path.val[parent]); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + } + hx509_certs_free(&certs); + } + +#if 0 + for (i = path.len - 1; i >= 0; i--) { + _hx509_print_cert_subject(path.val[i]); + } +#endif + + /* + * Verify signatures, do this backward so public key working + * parameter is passed up from the anchor up though the chain. + */ + + for (i = path.len - 1; i >= 0; i--) { + Certificate *signer, *c; + + c = _hx509_get_cert(path.val[i]); + + /* is last in chain (trust anchor) */ + if (i == path.len - 1) { + signer = path.val[i]->data; + + /* if trust anchor is not self signed, don't check sig */ + if (!certificate_is_self_signed(signer)) + continue; + } else { + /* take next certificate in chain */ + signer = path.val[i + 1]->data; + } + + /* verify signatureValue */ + ret = _hx509_verify_signature_bitstring(context, + signer, + &c->signatureAlgorithm, + &c->tbsCertificate._save, + &c->signatureValue); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to verify signature of certificate"); + goto out; + } + } + +out: + free_Name(&proxy_issuer); + free_name_constraints(&nc); + _hx509_path_free(&path); + + return ret; +} + +int +hx509_verify_signature(hx509_context context, + const hx509_cert signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + return _hx509_verify_signature(context, signer->data, alg, data, sig); +} + +int +hx509_verify_hostname(hx509_context context, + const hx509_cert cert, + int require_match, + const char *hostname, + const struct sockaddr *sa, + /* XXX krb5_socklen_t */ int sa_size) +{ + if (sa && sa_size <= 0) + return EINVAL; + return 0; +} + +int +_hx509_set_cert_attribute(hx509_context context, + hx509_cert cert, + const heim_oid *oid, + const heim_octet_string *attr) +{ + hx509_cert_attribute a; + void *d; + + if (hx509_cert_get_attribute(cert, oid) != NULL) + return 0; + + d = realloc(cert->attrs.val, + sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1)); + if (d == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + cert->attrs.val = d; + + a = malloc(sizeof(*a)); + if (a == NULL) + return ENOMEM; + + der_copy_octet_string(attr, &a->data); + der_copy_oid(oid, &a->oid); + + cert->attrs.val[cert->attrs.len] = a; + cert->attrs.len++; + + return 0; +} + +hx509_cert_attribute +hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid) +{ + int i; + for (i = 0; i < cert->attrs.len; i++) + if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0) + return cert->attrs.val[i]; + return NULL; +} + +int +hx509_cert_set_friendly_name(hx509_cert cert, const char *name) +{ + if (cert->friendlyname) + free(cert->friendlyname); + cert->friendlyname = strdup(name); + if (cert->friendlyname == NULL) + return ENOMEM; + return 0; +} + + +const char * +hx509_cert_get_friendly_name(hx509_cert cert) +{ + hx509_cert_attribute a; + PKCS9_friendlyName n; + size_t sz; + int ret, i; + + if (cert->friendlyname) + return cert->friendlyname; + + a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName()); + if (a == NULL) { + /* XXX use subject name ? */ + return NULL; + } + + ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz); + if (ret) + return NULL; + + if (n.len != 1) { + free_PKCS9_friendlyName(&n); + return NULL; + } + + cert->friendlyname = malloc(n.val[0].length + 1); + if (cert->friendlyname == NULL) { + free_PKCS9_friendlyName(&n); + return NULL; + } + + for (i = 0; i < n.val[0].length; i++) { + if (n.val[0].data[i] <= 0xff) + cert->friendlyname[i] = n.val[0].data[i] & 0xff; + else + cert->friendlyname[i] = 'X'; + } + cert->friendlyname[i] = '\0'; + free_PKCS9_friendlyName(&n); + + return cert->friendlyname; +} + +void +_hx509_query_clear(hx509_query *q) +{ + memset(q, 0, sizeof(*q)); +} + +int +hx509_query_alloc(hx509_context context, hx509_query **q) +{ + *q = calloc(1, sizeof(**q)); + if (*q == NULL) + return ENOMEM; + return 0; +} + +void +hx509_query_match_option(hx509_query *q, hx509_query_option option) +{ + switch(option) { + case HX509_QUERY_OPTION_PRIVATE_KEY: + q->match |= HX509_QUERY_PRIVATE_KEY; + break; + case HX509_QUERY_OPTION_KU_ENCIPHERMENT: + q->match |= HX509_QUERY_KU_ENCIPHERMENT; + break; + case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE: + q->match |= HX509_QUERY_KU_DIGITALSIGNATURE; + break; + case HX509_QUERY_OPTION_KU_KEYCERTSIGN: + q->match |= HX509_QUERY_KU_KEYCERTSIGN; + break; + case HX509_QUERY_OPTION_END: + default: + break; + } +} + +int +hx509_query_match_issuer_serial(hx509_query *q, + const Name *issuer, + const heim_integer *serialNumber) +{ + int ret; + if (q->serial) { + der_free_heim_integer(q->serial); + free(q->serial); + } + q->serial = malloc(sizeof(*q->serial)); + if (q->serial == NULL) + return ENOMEM; + ret = der_copy_heim_integer(serialNumber, q->serial); + if (ret) { + free(q->serial); + q->serial = NULL; + return ret; + } + if (q->issuer_name) { + free_Name(q->issuer_name); + free(q->issuer_name); + } + q->issuer_name = malloc(sizeof(*q->issuer_name)); + if (q->issuer_name == NULL) + return ENOMEM; + ret = copy_Name(issuer, q->issuer_name); + if (ret) { + free(q->issuer_name); + q->issuer_name = NULL; + return ret; + } + q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; + return 0; +} + + +int +hx509_query_match_friendly_name(hx509_query *q, const char *name) +{ + if (q->friendlyname) + free(q->friendlyname); + q->friendlyname = strdup(name); + if (q->friendlyname == NULL) + return ENOMEM; + q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME; + return 0; +} + +int +hx509_query_match_cmp_func(hx509_query *q, + int (*func)(void *, hx509_cert), + void *ctx) +{ + if (func) + q->match |= HX509_QUERY_MATCH_FUNCTION; + else + q->match &= ~HX509_QUERY_MATCH_FUNCTION; + q->cmp_func = func; + q->cmp_func_ctx = ctx; + return 0; +} + + +void +hx509_query_free(hx509_context context, hx509_query *q) +{ + if (q->serial) { + der_free_heim_integer(q->serial); + free(q->serial); + q->serial = NULL; + } + if (q->issuer_name) { + free_Name(q->issuer_name); + free(q->issuer_name); + q->issuer_name = NULL; + } + if (q) { + free(q->friendlyname); + memset(q, 0, sizeof(*q)); + } + free(q); +} + +int +_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert) +{ + Certificate *c = _hx509_get_cert(cert); + + if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) && + _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) && + _hx509_Certificate_cmp(q->certificate, c) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER) + && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME) + && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME) + && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0) + return 0; + + if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) { + SubjectKeyIdentifier si; + int ret; + + ret = _hx509_find_extension_subject_key_id(c, &si); + if (ret == 0) { + if (der_heim_octet_string_cmp(&si, q->subject_id) != 0) + ret = 1; + free_SubjectKeyIdentifier(&si); + } + if (ret) + return 0; + } + if ((q->match & HX509_QUERY_MATCH_ISSUER_ID)) + return 0; + if ((q->match & HX509_QUERY_PRIVATE_KEY) && + _hx509_cert_private_key(cert) == NULL) + return 0; + + { + unsigned ku = 0; + if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE) + ku |= (1 << 0); + if (q->match & HX509_QUERY_KU_NONREPUDIATION) + ku |= (1 << 1); + if (q->match & HX509_QUERY_KU_ENCIPHERMENT) + ku |= (1 << 2); + if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT) + ku |= (1 << 3); + if (q->match & HX509_QUERY_KU_KEYAGREEMENT) + ku |= (1 << 4); + if (q->match & HX509_QUERY_KU_KEYCERTSIGN) + ku |= (1 << 5); + if (q->match & HX509_QUERY_KU_CRLSIGN) + ku |= (1 << 6); + if (ku && check_key_usage(context, c, ku, TRUE)) + return 0; + } + if ((q->match & HX509_QUERY_ANCHOR)) + return 0; + + if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) { + hx509_cert_attribute a; + + a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId()); + if (a == NULL) + return 0; + if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0) + return 0; + } + + if (q->match & HX509_QUERY_NO_MATCH_PATH) { + size_t i; + + for (i = 0; i < q->path->len; i++) + if (hx509_cert_cmp(q->path->val[i], cert) == 0) + return 0; + } + if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) { + const char *name = hx509_cert_get_friendly_name(cert); + if (name == NULL) + return 0; + if (strcasecmp(q->friendlyname, name) != 0) + return 0; + } + if (q->match & HX509_QUERY_MATCH_FUNCTION) { + int ret = (*q->cmp_func)(q->cmp_func_ctx, cert); + if (ret != 0) + return 0; + } + + if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) { + heim_octet_string os; + int ret; + + os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = + c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_verify_signature(context, + NULL, + hx509_signature_sha1(), + &os, + q->keyhash_sha1); + if (ret != 0) + return 0; + } + + if (q->match & HX509_QUERY_MATCH_TIME) { + time_t t; + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); + if (t > q->timenow) + return 0; + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); + if (t < q->timenow) + return 0; + } + + if (q->match & ~HX509_QUERY_MASK) + return 0; + + return 1; +} + +int +hx509_cert_check_eku(hx509_context context, hx509_cert cert, + const heim_oid *eku, int allow_any_eku) +{ + ExtKeyUsage e; + int ret, i; + + ret = find_extension_eku(_hx509_get_cert(cert), &e); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + + for (i = 0; i < e.len; i++) { + if (der_heim_oid_cmp(eku, &e.val[i]) == 0) { + free_ExtKeyUsage(&e); + return 0; + } + if (allow_any_eku) { +#if 0 + if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) { + free_ExtKeyUsage(&e); + return 0; + } +#endif + } + } + free_ExtKeyUsage(&e); + hx509_clear_error_string(context); + return HX509_CERTIFICATE_MISSING_EKU; +} + +int +_hx509_cert_get_keyusage(hx509_context context, + hx509_cert c, + KeyUsage *ku) +{ + Certificate *cert; + const Extension *e; + size_t size; + int ret, i = 0; + + memset(ku, 0, sizeof(*ku)); + + cert = _hx509_get_cert(c); + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i); + if (e == NULL) + return HX509_KU_CERT_MISSING; + + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size); + if (ret) + return ret; + return 0; +} diff --git a/source4/heimdal/lib/hx509/cms.c b/source4/heimdal/lib/hx509/cms.c new file mode 100644 index 0000000000..4ed70b8f84 --- /dev/null +++ b/source4/heimdal/lib/hx509/cms.c @@ -0,0 +1,1279 @@ +/* + * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: cms.c,v 1.48 2007/01/08 18:45:03 lha Exp $"); + +#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) +#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) + +int +hx509_cms_wrap_ContentInfo(const heim_oid *oid, + const heim_octet_string *buf, + heim_octet_string *res) +{ + ContentInfo ci; + size_t size; + int ret; + + memset(res, 0, sizeof(*res)); + memset(&ci, 0, sizeof(ci)); + + ret = der_copy_oid(oid, &ci.contentType); + if (ret) + return ret; + ALLOC(ci.content, 1); + if (ci.content == NULL) { + free_ContentInfo(&ci); + return ENOMEM; + } + ci.content->data = malloc(buf->length); + if (ci.content->data == NULL) { + free_ContentInfo(&ci); + return ENOMEM; + } + memcpy(ci.content->data, buf->data, buf->length); + ci.content->length = buf->length; + + ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret); + free_ContentInfo(&ci); + if (ret) + return ret; + if (res->length != size) + _hx509_abort("internal ASN.1 encoder error"); + + return 0; +} + +int +hx509_cms_unwrap_ContentInfo(const heim_octet_string *in, + heim_oid *oid, + heim_octet_string *out, + int *have_data) +{ + ContentInfo ci; + size_t size; + int ret; + + memset(oid, 0, sizeof(*oid)); + memset(out, 0, sizeof(*out)); + + ret = decode_ContentInfo(in->data, in->length, &ci, &size); + if (ret) + return ret; + + ret = der_copy_oid(&ci.contentType, oid); + if (ret) { + free_ContentInfo(&ci); + return ret; + } + if (ci.content) { + ret = der_copy_octet_string(ci.content, out); + if (ret) { + der_free_oid(oid); + free_ContentInfo(&ci); + return ret; + } + } else + memset(out, 0, sizeof(*out)); + + if (have_data) + *have_data = (ci.content != NULL) ? 1 : 0; + + free_ContentInfo(&ci); + + return 0; +} + +static int +fill_CMSIdentifier(const hx509_cert cert, CMSIdentifier *id) +{ + hx509_name name; + int ret; + + id->element = choice_CMSIdentifier_issuerAndSerialNumber; + ret = hx509_cert_get_issuer(cert, &name); + if (ret) + return ret; + ret = copy_Name(&name->der_name, + &id->u.issuerAndSerialNumber.issuer); + hx509_name_free(&name); + if (ret) + return ret; + + ret = hx509_cert_get_serialnumber(cert, + &id->u.issuerAndSerialNumber.serialNumber); + return ret; +} + +static int +unparse_CMSIdentifier(hx509_context context, + CMSIdentifier *id, + char **str) +{ + int ret; + + *str = NULL; + switch (id->element) { + case choice_CMSIdentifier_issuerAndSerialNumber: { + IssuerAndSerialNumber *iasn; + char *serial, *name; + + iasn = &id->u.issuerAndSerialNumber; + + ret = _hx509_Name_to_string(&iasn->issuer, &name); + if(ret) + return ret; + ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial); + if (ret) { + free(name); + return ret; + } + asprintf(str, "certificate issued by %s with serial number %s", + name, serial); + free(name); + free(serial); + break; + } + case choice_CMSIdentifier_subjectKeyIdentifier: { + KeyIdentifier *ki = &id->u.subjectKeyIdentifier; + char *keyid; + ssize_t len; + + len = hex_encode(ki->data, ki->length, &keyid); + if (len < 0) + return ENOMEM; + + asprintf(str, "certificate with id %s", keyid); + free(keyid); + break; + } + default: + asprintf(str, "certificate have unknown CMSidentifier type"); + break; + } + if (*str == NULL) + return ENOMEM; + return 0; +} + +static int +find_CMSIdentifier(hx509_context context, + CMSIdentifier *client, + hx509_certs certs, + hx509_cert *signer_cert, + int match) +{ + hx509_query q; + hx509_cert cert; + Certificate c; + int ret; + + memset(&c, 0, sizeof(c)); + _hx509_query_clear(&q); + + *signer_cert = NULL; + + switch (client->element) { + case choice_CMSIdentifier_issuerAndSerialNumber: + q.serial = &client->u.issuerAndSerialNumber.serialNumber; + q.issuer_name = &client->u.issuerAndSerialNumber.issuer; + q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; + break; + case choice_CMSIdentifier_subjectKeyIdentifier: + q.subject_id = &client->u.subjectKeyIdentifier; + q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; + break; + default: + hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE, + "unknown CMS identifier element"); + return HX509_CMS_NO_RECIPIENT_CERTIFICATE; + } + + q.match |= match; + + q.match |= HX509_QUERY_MATCH_TIME; + q.timenow = time(NULL); + + ret = hx509_certs_find(context, certs, &q, &cert); + if (ret == HX509_CERT_NOT_FOUND) { + char *str; + + ret = unparse_CMSIdentifier(context, client, &str); + if (ret == 0) { + hx509_set_error_string(context, 0, + HX509_CMS_NO_RECIPIENT_CERTIFICATE, + "Failed to find %s", str); + } else + hx509_clear_error_string(context); + return HX509_CMS_NO_RECIPIENT_CERTIFICATE; + } else if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, + HX509_CMS_NO_RECIPIENT_CERTIFICATE, + "Failed to find CMS id in cert store"); + return HX509_CMS_NO_RECIPIENT_CERTIFICATE; + } + + *signer_cert = cert; + + return 0; +} + +int +hx509_cms_unenvelope(hx509_context context, + hx509_certs certs, + int flags, + const void *data, + size_t length, + const heim_octet_string *encryptedContent, + heim_oid *contentType, + heim_octet_string *content) +{ + heim_octet_string key; + EnvelopedData ed; + hx509_cert cert; + AlgorithmIdentifier *ai; + const heim_octet_string *enccontent; + heim_octet_string *params, params_data; + heim_octet_string ivec; + size_t size; + int ret, i, matched = 0, findflags = 0; + + + memset(&key, 0, sizeof(key)); + memset(&ed, 0, sizeof(ed)); + memset(&ivec, 0, sizeof(ivec)); + memset(content, 0, sizeof(*content)); + memset(contentType, 0, sizeof(*contentType)); + + if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0) + findflags |= HX509_QUERY_KU_ENCIPHERMENT; + + ret = decode_EnvelopedData(data, length, &ed, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode EnvelopedData"); + return ret; + } + + if (ed.recipientInfos.len == 0) { + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + hx509_set_error_string(context, 0, ret, + "No recipient info in enveloped data"); + goto out; + } + + enccontent = ed.encryptedContentInfo.encryptedContent; + if (enccontent == NULL) { + if (encryptedContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "Content missing from encrypted data"); + goto out; + } + enccontent = encryptedContent; + } + + cert = NULL; + for (i = 0; i < ed.recipientInfos.len; i++) { + KeyTransRecipientInfo *ri; + char *str; + int ret2; + + ri = &ed.recipientInfos.val[i]; + + /* ret = search_keyset(ri, + * PRIVATE_KEY, + * ki->keyEncryptionAlgorithm.algorithm); + */ + + ret = find_CMSIdentifier(context, &ri->rid, certs, &cert, + HX509_QUERY_PRIVATE_KEY|findflags); + if (ret) + continue; + + matched = 1; /* found a matching certificate, let decrypt */ + + ret = _hx509_cert_private_decrypt(context, + &ri->encryptedKey, + &ri->keyEncryptionAlgorithm.algorithm, + cert, &key); + + hx509_cert_free(cert); + if (ret == 0) + break; /* succuessfully decrypted cert */ + cert = NULL; + ret2 = unparse_CMSIdentifier(context, &ri->rid, &str); + if (ret2 == 0) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to decrypt with %s", str); + free(str); + } + } + + if (!matched) { + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + hx509_set_error_string(context, 0, ret, + "No private key matched any certificate"); + goto out; + } + + if (cert == NULL) { + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "No private key decrypted the transfer key"); + goto out; + } + + ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy EnvelopedData content oid"); + goto out; + } + + ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + if (ai->parameters) { + params_data.data = ai->parameters->data; + params_data.length = ai->parameters->length; + params = ¶ms_data; + } else + params = NULL; + + { + hx509_crypto crypto; + + ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto); + if (ret) + goto out; + + if (params) { + ret = hx509_crypto_set_params(context, crypto, params, &ivec); + if (ret) { + hx509_crypto_destroy(crypto); + goto out; + } + } + + ret = hx509_crypto_set_key_data(crypto, key.data, key.length); + if (ret) { + hx509_crypto_destroy(crypto); + hx509_set_error_string(context, 0, ret, + "Failed to set key for decryption " + "of EnvelopedData"); + goto out; + } + + ret = hx509_crypto_decrypt(crypto, + enccontent->data, + enccontent->length, + ivec.length ? &ivec : NULL, + content); + hx509_crypto_destroy(crypto); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decrypt EnvelopedData"); + goto out; + } + } + +out: + + free_EnvelopedData(&ed); + der_free_octet_string(&key); + if (ivec.length) + der_free_octet_string(&ivec); + if (ret) { + der_free_oid(contentType); + der_free_octet_string(content); + } + + return ret; +} + +int +hx509_cms_envelope_1(hx509_context context, + hx509_cert cert, + const void *data, + size_t length, + const heim_oid *encryption_type, + const heim_oid *contentType, + heim_octet_string *content) +{ + KeyTransRecipientInfo *ri; + heim_octet_string ivec; + heim_octet_string key; + hx509_crypto crypto = NULL; + EnvelopedData ed; + size_t size; + int ret; + + memset(&ivec, 0, sizeof(ivec)); + memset(&key, 0, sizeof(key)); + memset(&ed, 0, sizeof(ed)); + memset(content, 0, sizeof(*content)); + + if (encryption_type == NULL) + encryption_type = oid_id_aes_256_cbc(); + + ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE); + if (ret) + goto out; + + ret = hx509_crypto_init(context, NULL, encryption_type, &crypto); + if (ret) + goto out; + + ret = hx509_crypto_set_random_key(crypto, &key); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Create random key for EnvelopedData content"); + goto out; + } + + ret = hx509_crypto_encrypt(crypto, + data, + length, + &ivec, + &ed.encryptedContentInfo.encryptedContent); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to encrypt EnvelopedData content"); + goto out; + } + + { + AlgorithmIdentifier *enc_alg; + enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + ret = der_copy_oid(encryption_type, &enc_alg->algorithm); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to set crypto oid " + "for EnvelopedData"); + goto out; + } + ALLOC(enc_alg->parameters, 1); + if (enc_alg->parameters == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, + "Failed to allocate crypto paramaters " + "for EnvelopedData"); + goto out; + } + + ret = hx509_crypto_get_params(context, + crypto, + &ivec, + enc_alg->parameters); + if (ret) { + goto out; + } + } + + ALLOC_SEQ(&ed.recipientInfos, 1); + if (ed.recipientInfos.val == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, + "Failed to allocate recipients info " + "for EnvelopedData"); + goto out; + } + + ri = &ed.recipientInfos.val[0]; + + ri->version = 0; + ret = fill_CMSIdentifier(cert, &ri->rid); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to set CMS identifier info " + "for EnvelopedData"); + goto out; + } + + ret = _hx509_cert_public_encrypt(context, + &key, cert, + &ri->keyEncryptionAlgorithm.algorithm, + &ri->encryptedKey); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to encrypt transport key for " + "EnvelopedData"); + goto out; + } + + /* + * + */ + + ed.version = 0; + ed.originatorInfo = NULL; + + ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy content oid for " + "EnvelopedData"); + goto out; + } + + ed.unprotectedAttrs = NULL; + + ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length, + &ed, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to encode EnvelopedData"); + goto out; + } + if (size != content->length) + _hx509_abort("internal ASN.1 encoder error"); + +out: + if (crypto) + hx509_crypto_destroy(crypto); + if (ret) + der_free_octet_string(content); + der_free_octet_string(&key); + der_free_octet_string(&ivec); + free_EnvelopedData(&ed); + + return ret; +} + +static int +any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs) +{ + int ret, i; + + if (sd->certificates == NULL) + return 0; + + for (i = 0; i < sd->certificates->len; i++) { + Certificate cert; + hx509_cert c; + + const void *p = sd->certificates->val[i].data; + size_t size, length = sd->certificates->val[i].length; + + ret = decode_Certificate(p, length, &cert, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode certificate %d " + "in SignedData.certificates", i); + return ret; + } + + ret = hx509_cert_init(context, &cert, &c); + free_Certificate(&cert); + if (ret) + return ret; + ret = hx509_certs_add(context, certs, c); + hx509_cert_free(c); + if (ret) + return ret; + } + + return 0; +} + +static const Attribute * +find_attribute(const CMSAttributes *attr, const heim_oid *oid) +{ + int i; + for (i = 0; i < attr->len; i++) + if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0) + return &attr->val[i]; + return NULL; +} + +int +hx509_cms_verify_signed(hx509_context context, + hx509_verify_ctx ctx, + const void *data, + size_t length, + hx509_certs store, + heim_oid *contentType, + heim_octet_string *content, + hx509_certs *signer_certs) +{ + SignerInfo *signer_info; + hx509_cert cert = NULL; + hx509_certs certs = NULL; + SignedData sd; + size_t size; + int ret, i, found_valid_sig; + + *signer_certs = NULL; + content->data = NULL; + content->length = 0; + contentType->length = 0; + contentType->components = NULL; + + memset(&sd, 0, sizeof(sd)); + + ret = decode_SignedData(data, length, &sd, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode SignedData"); + goto out; + } + + if (sd.encapContentInfo.eContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "No content data in SignedData"); + goto out; + } + + ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer", + 0, NULL, &certs); + if (ret) + goto out; + + ret = hx509_certs_init(context, "MEMORY:cms-signer-certs", + 0, NULL, signer_certs); + if (ret) + goto out; + + /* XXX Check CMS version */ + + ret = any_to_certs(context, &sd, certs); + if (ret) + goto out; + + if (store) { + ret = hx509_certs_merge(context, certs, store); + if (ret) + goto out; + } + + for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) { + heim_octet_string *signed_data; + const heim_oid *match_oid; + heim_oid decode_oid; + + signer_info = &sd.signerInfos.val[i]; + match_oid = NULL; + + if (signer_info->signature.length == 0) { + ret = HX509_CMS_MISSING_SIGNER_DATA; + hx509_set_error_string(context, 0, ret, + "SignerInfo %d in SignedData " + "missing sigature", i); + continue; + } + + ret = find_CMSIdentifier(context, &signer_info->sid, certs, &cert, + HX509_QUERY_KU_DIGITALSIGNATURE); + if (ret) + continue; + + if (signer_info->signedAttrs) { + const Attribute *attr; + + CMSAttributes sa; + heim_octet_string os; + + sa.val = signer_info->signedAttrs->val; + sa.len = signer_info->signedAttrs->len; + + /* verify that sigature exists */ + attr = find_attribute(&sa, oid_id_pkcs9_messageDigest()); + if (attr == NULL) { + ret = HX509_CRYPTO_SIGNATURE_MISSING; + hx509_set_error_string(context, 0, ret, + "SignerInfo have signed attributes " + "but messageDigest (signature) " + "is missing"); + goto next_sigature; + } + if (attr->value.len != 1) { + ret = HX509_CRYPTO_SIGNATURE_MISSING; + hx509_set_error_string(context, 0, ret, + "SignerInfo have more then one " + "messageDigest (signature)"); + goto next_sigature; + } + + ret = decode_MessageDigest(attr->value.val[0].data, + attr->value.val[0].length, + &os, + &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode " + "messageDigest (signature)"); + goto next_sigature; + } + + ret = _hx509_verify_signature(context, + NULL, + &signer_info->digestAlgorithm, + sd.encapContentInfo.eContent, + &os); + der_free_octet_string(&os); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to verify messageDigest"); + goto next_sigature; + } + + /* + * Fetch content oid inside signedAttrs or set it to + * id-pkcs7-data. + */ + attr = find_attribute(&sa, oid_id_pkcs9_contentType()); + if (attr == NULL) { + match_oid = oid_id_pkcs7_data(); + } else { + if (attr->value.len != 1) { + ret = HX509_CMS_DATA_OID_MISMATCH; + hx509_set_error_string(context, 0, ret, + "More then one oid in signedAttrs"); + goto next_sigature; + + } + ret = decode_ContentType(attr->value.val[0].data, + attr->value.val[0].length, + &decode_oid, + &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode " + "oid in signedAttrs"); + goto next_sigature; + } + match_oid = &decode_oid; + } + + ALLOC(signed_data, 1); + if (signed_data == NULL) { + if (match_oid == &decode_oid) + der_free_oid(&decode_oid); + ret = ENOMEM; + hx509_clear_error_string(context); + goto next_sigature; + } + + ASN1_MALLOC_ENCODE(CMSAttributes, + signed_data->data, + signed_data->length, + &sa, + &size, ret); + if (ret) { + if (match_oid == &decode_oid) + der_free_oid(&decode_oid); + free(signed_data); + hx509_clear_error_string(context); + goto next_sigature; + } + if (size != signed_data->length) + _hx509_abort("internal ASN.1 encoder error"); + + } else { + signed_data = sd.encapContentInfo.eContent; + match_oid = oid_id_pkcs7_data(); + } + + if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) { + ret = HX509_CMS_DATA_OID_MISMATCH; + hx509_set_error_string(context, 0, ret, + "Oid in message mismatch from the expected"); + } + if (match_oid == &decode_oid) + der_free_oid(&decode_oid); + + if (ret == 0) { + ret = hx509_verify_signature(context, + cert, + &signer_info->signatureAlgorithm, + signed_data, + &signer_info->signature); + if (ret) + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to verify sigature in " + "CMS SignedData"); + } + if (signed_data != sd.encapContentInfo.eContent) { + der_free_octet_string(signed_data); + free(signed_data); + } + if (ret) + goto next_sigature; + + ret = hx509_verify_path(context, ctx, cert, certs); + if (ret) + goto next_sigature; + + ret = hx509_certs_add(context, *signer_certs, cert); + if (ret) + goto next_sigature; + + found_valid_sig++; + + next_sigature: + if (cert) + hx509_cert_free(cert); + cert = NULL; + } + if (found_valid_sig == 0) { + if (ret == 0) { + ret = HX509_CMS_SIGNER_NOT_FOUND; + hx509_set_error_string(context, 0, ret, + "No signers where found"); + } + goto out; + } + + ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + content->data = malloc(sd.encapContentInfo.eContent->length); + if (content->data == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + content->length = sd.encapContentInfo.eContent->length; + memcpy(content->data,sd.encapContentInfo.eContent->data,content->length); + +out: + free_SignedData(&sd); + if (certs) + hx509_certs_free(&certs); + if (ret) { + if (*signer_certs) + hx509_certs_free(signer_certs); + der_free_oid(contentType); + der_free_octet_string(content); + } + + return ret; +} + +int +_hx509_set_digest_alg(DigestAlgorithmIdentifier *id, + const heim_oid *oid, + void *param, size_t length) +{ + int ret; + if (param) { + id->parameters = malloc(sizeof(*id->parameters)); + if (id->parameters == NULL) + return ENOMEM; + id->parameters->data = malloc(length); + if (id->parameters->data == NULL) { + free(id->parameters); + id->parameters = NULL; + return ENOMEM; + } + memcpy(id->parameters->data, param, length); + id->parameters->length = length; + } else + id->parameters = NULL; + ret = der_copy_oid(oid, &id->algorithm); + if (ret) { + if (id->parameters) { + free(id->parameters->data); + free(id->parameters); + id->parameters = NULL; + } + return ret; + } + return 0; +} + +static int +add_one_attribute(Attribute **attr, + unsigned int *len, + const heim_oid *oid, + heim_octet_string *data) +{ + void *d; + int ret; + + d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1)); + if (d == NULL) + return ENOMEM; + (*attr) = d; + + ret = der_copy_oid(oid, &(*attr)[*len].type); + if (ret) + return ret; + + ALLOC_SEQ(&(*attr)[*len].value, 1); + if ((*attr)[*len].value.val == NULL) { + der_free_oid(&(*attr)[*len].type); + return ENOMEM; + } + + (*attr)[*len].value.val[0].data = data->data; + (*attr)[*len].value.val[0].length = data->length; + + *len += 1; + + return 0; +} + +int +hx509_cms_create_signed_1(hx509_context context, + const heim_oid *eContentType, + const void *data, size_t length, + const AlgorithmIdentifier *digest_alg, + hx509_cert cert, + hx509_peer_info peer, + hx509_certs anchors, + hx509_certs pool, + heim_octet_string *signed_data) +{ + AlgorithmIdentifier digest; + hx509_name name; + SignerInfo *signer_info; + heim_octet_string buf; + SignedData sd; + int ret; + size_t size; + hx509_path path; + + memset(&sd, 0, sizeof(sd)); + memset(&name, 0, sizeof(name)); + memset(&path, 0, sizeof(path)); + memset(&digest, 0, sizeof(digest)); + + if (_hx509_cert_private_key(cert) == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "Private key missing for signing"); + return HX509_PRIVATE_KEY_MISSING; + } + + if (digest_alg == NULL) { + ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, + _hx509_cert_private_key(cert), peer, &digest); + } else { + ret = copy_AlgorithmIdentifier(digest_alg, &digest); + if (ret) + hx509_clear_error_string(context); + } + if (ret) + goto out; + + sd.version = CMSVersion_v3; + + der_copy_oid(eContentType, &sd.encapContentInfo.eContentType); + ALLOC(sd.encapContentInfo.eContent, 1); + if (sd.encapContentInfo.eContent == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + sd.encapContentInfo.eContent->data = malloc(length); + if (sd.encapContentInfo.eContent->data == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + memcpy(sd.encapContentInfo.eContent->data, data, length); + sd.encapContentInfo.eContent->length = length; + + ALLOC_SEQ(&sd.signerInfos, 1); + if (sd.signerInfos.val == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + signer_info = &sd.signerInfos.val[0]; + + signer_info->version = 1; + + ret = fill_CMSIdentifier(cert, &signer_info->sid); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + signer_info->signedAttrs = NULL; + signer_info->unsignedAttrs = NULL; + + ALLOC(signer_info->signedAttrs, 1); + if (signer_info->signedAttrs == NULL) { + ret = ENOMEM; + goto out; + } + + { + heim_octet_string data; + + ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + ret = _hx509_create_signature(context, + NULL, + &digest, + sd.encapContentInfo.eContent, + NULL, + &data); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + ASN1_MALLOC_ENCODE(MessageDigest, + buf.data, + buf.length, + &data, + &size, + ret); + der_free_octet_string(&data); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + if (size != buf.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = add_one_attribute(&signer_info->signedAttrs->val, + &signer_info->signedAttrs->len, + oid_id_pkcs9_messageDigest(), + &buf); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + } + + if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { + + ASN1_MALLOC_ENCODE(ContentType, + buf.data, + buf.length, + eContentType, + &size, + ret); + if (ret) + goto out; + if (size != buf.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = add_one_attribute(&signer_info->signedAttrs->val, + &signer_info->signedAttrs->len, + oid_id_pkcs9_contentType(), + &buf); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + + + { + CMSAttributes sa; + heim_octet_string os; + + sa.val = signer_info->signedAttrs->val; + sa.len = signer_info->signedAttrs->len; + + ASN1_MALLOC_ENCODE(CMSAttributes, + os.data, + os.length, + &sa, + &size, + ret); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + if (size != os.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = _hx509_create_signature(context, + _hx509_cert_private_key(cert), + hx509_signature_rsa_with_sha1(), + &os, + &signer_info->signatureAlgorithm, + &signer_info->signature); + + der_free_octet_string(&os); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + + ALLOC_SEQ(&sd.digestAlgorithms, 1); + if (sd.digestAlgorithms.val == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + /* + * Provide best effort path + */ + if (pool) { + _hx509_calculate_path(context, + HX509_CALCULATE_PATH_NO_ANCHOR, + time(NULL), + anchors, + 0, + cert, + pool, + &path); + } else + _hx509_path_append(context, &path, cert); + + + if (path.len) { + int i; + + ALLOC(sd.certificates, 1); + if (sd.certificates == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + ALLOC_SEQ(sd.certificates, path.len); + if (sd.certificates->val == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + for (i = 0; i < path.len; i++) { + ASN1_MALLOC_ENCODE(Certificate, + sd.certificates->val[i].data, + sd.certificates->val[i].length, + _hx509_get_cert(path.val[i]), + &size, ret); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + if (sd.certificates->val[i].length != size) + _hx509_abort("internal ASN.1 encoder error"); + } + } + + ASN1_MALLOC_ENCODE(SignedData, + signed_data->data, signed_data->length, + &sd, &size, ret); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + if (signed_data->length != size) + _hx509_abort("internal ASN.1 encoder error"); + +out: + free_AlgorithmIdentifier(&digest); + _hx509_path_free(&path); + free_SignedData(&sd); + + return ret; +} + +int +hx509_cms_decrypt_encrypted(hx509_context context, + hx509_lock lock, + const void *data, + size_t length, + heim_oid *contentType, + heim_octet_string *content) +{ + heim_octet_string cont; + CMSEncryptedData ed; + AlgorithmIdentifier *ai; + int ret; + + memset(content, 0, sizeof(*content)); + memset(&cont, 0, sizeof(cont)); + + ret = decode_CMSEncryptedData(data, length, &ed, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode CMSEncryptedData"); + return ret; + } + + if (ed.encryptedContentInfo.encryptedContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "No content in EncryptedData"); + goto out; + } + + ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + if (ai->parameters == NULL) { + ret = HX509_ALG_NOT_SUPP; + hx509_clear_error_string(context); + goto out; + } + + ret = _hx509_pbe_decrypt(context, + lock, + ai, + ed.encryptedContentInfo.encryptedContent, + &cont); + if (ret) + goto out; + + *content = cont; + +out: + if (ret) { + if (cont.data) + free(cont.data); + } + free_CMSEncryptedData(&ed); + return ret; +} diff --git a/source4/heimdal/lib/hx509/collector.c b/source4/heimdal/lib/hx509/collector.c new file mode 100644 index 0000000000..ec172f46f4 --- /dev/null +++ b/source4/heimdal/lib/hx509/collector.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: collector.c,v 1.16 2007/01/09 10:52:04 lha Exp $"); + +struct private_key { + AlgorithmIdentifier alg; + hx509_private_key private_key; + heim_octet_string localKeyId; +}; + +struct hx509_collector { + hx509_lock lock; + hx509_certs unenvelop_certs; + hx509_certs certs; + struct { + struct private_key **data; + size_t len; + } val; +}; + + +struct hx509_collector * +_hx509_collector_alloc(hx509_context context, hx509_lock lock) +{ + struct hx509_collector *c; + int ret; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return NULL; + c->lock = lock; + + ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert", + 0,NULL, &c->unenvelop_certs); + if (ret) { + free(c); + return NULL; + } + c->val.data = NULL; + c->val.len = 0; + ret = hx509_certs_init(context, "MEMORY:collector-tmp-store", + 0, NULL, &c->certs); + if (ret) { + hx509_certs_free(&c->unenvelop_certs); + free(c); + return NULL; + } + + return c; +} + +hx509_lock +_hx509_collector_get_lock(struct hx509_collector *c) +{ + return c->lock; +} + + +int +_hx509_collector_certs_add(hx509_context context, + struct hx509_collector *c, + hx509_cert cert) +{ + return hx509_certs_add(context, c->certs, cert); +} + +static void +free_private_key(struct private_key *key) +{ + free_AlgorithmIdentifier(&key->alg); + if (key->private_key) + _hx509_private_key_free(&key->private_key); + der_free_octet_string(&key->localKeyId); + free(key); +} + +int +_hx509_collector_private_key_add(hx509_context context, + struct hx509_collector *c, + const AlgorithmIdentifier *alg, + hx509_private_key private_key, + const heim_octet_string *key_data, + const heim_octet_string *localKeyId) +{ + struct private_key *key; + void *d; + int ret; + + key = calloc(1, sizeof(*key)); + if (key == NULL) + return ENOMEM; + + d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0])); + if (d == NULL) { + free(key); + hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); + return ENOMEM; + } + c->val.data = d; + + ret = copy_AlgorithmIdentifier(alg, &key->alg); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy " + "AlgorithmIdentifier"); + goto out; + } + if (private_key) { + key->private_key = private_key; + } else { + ret = _hx509_parse_private_key(context, &alg->algorithm, + key_data->data, key_data->length, + &key->private_key); + if (ret) + goto out; + } + if (localKeyId) { + ret = der_copy_octet_string(localKeyId, &key->localKeyId); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy localKeyId"); + goto out; + } + } else + memset(&key->localKeyId, 0, sizeof(key->localKeyId)); + + c->val.data[c->val.len] = key; + c->val.len++; + +out: + if (ret) + free_private_key(key); + + return ret; +} + +static int +match_localkeyid(hx509_context context, + struct private_key *value, + hx509_certs certs) +{ + hx509_cert cert; + hx509_query q; + int ret; + + if (value->localKeyId.length == 0) { + hx509_set_error_string(context, 0, HX509_LOCAL_ATTRIBUTE_MISSING, + "No local key attribute on private key"); + return HX509_LOCAL_ATTRIBUTE_MISSING; + } + + _hx509_query_clear(&q); + q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID; + + q.local_key_id = &value->localKeyId; + + ret = hx509_certs_find(context, certs, &q, &cert); + if (ret == 0) { + + if (value->private_key) + _hx509_cert_assign_key(cert, value->private_key); + hx509_cert_free(cert); + } + return ret; +} + +static int +match_keys(hx509_context context, struct private_key *value, hx509_certs certs) +{ + hx509_cursor cursor; + hx509_cert c; + int ret, found = HX509_CERT_NOT_FOUND; + + if (value->private_key == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "No private key to compare with"); + return HX509_PRIVATE_KEY_MISSING; + } + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + c = NULL; + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + if (_hx509_cert_private_key(c)) { + hx509_cert_free(c); + continue; + } + + ret = _hx509_match_keys(c, value->private_key); + if (ret) { + _hx509_cert_assign_key(c, value->private_key); + hx509_cert_free(c); + found = 0; + break; + } + hx509_cert_free(c); + } + + hx509_certs_end_seq(context, certs, cursor); + + if (found) + hx509_clear_error_string(context); + + return found; +} + +int +_hx509_collector_collect_certs(hx509_context context, + struct hx509_collector *c, + hx509_certs *ret_certs) +{ + hx509_certs certs; + int ret, i; + + *ret_certs = NULL; + + ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs); + if (ret) + return ret; + + ret = hx509_certs_merge(context, certs, c->certs); + if (ret) { + hx509_certs_free(&certs); + return ret; + } + + for (i = 0; i < c->val.len; i++) { + ret = match_localkeyid(context, c->val.data[i], certs); + if (ret == 0) + continue; + ret = match_keys(context, c->val.data[i], certs); + if (ret == 0) + continue; + } + + *ret_certs = certs; + + return 0; +} + +int +_hx509_collector_collect_private_keys(hx509_context context, + struct hx509_collector *c, + hx509_private_key **keys) +{ + int i, nkeys; + + *keys = NULL; + + for (i = 0, nkeys = 0; i < c->val.len; i++) + if (c->val.data[i]->private_key) + nkeys++; + + *keys = calloc(nkeys + 1, sizeof(**keys)); + if (*keys == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory"); + return ENOMEM; + } + + for (i = 0, nkeys = 0; i < c->val.len; i++) { + if (c->val.data[i]->private_key) { + (*keys)[nkeys++] = c->val.data[i]->private_key; + c->val.data[i]->private_key = NULL; + } + } + (*keys)[nkeys++] = NULL; + + return 0; +} + + +void +_hx509_collector_free(struct hx509_collector *c) +{ + int i; + + if (c->unenvelop_certs) + hx509_certs_free(&c->unenvelop_certs); + if (c->certs) + hx509_certs_free(&c->certs); + for (i = 0; i < c->val.len; i++) + free_private_key(c->val.data[i]); + if (c->val.data) + free(c->val.data); + free(c); +} diff --git a/source4/heimdal/lib/hx509/crmf.asn1 b/source4/heimdal/lib/hx509/crmf.asn1 new file mode 100644 index 0000000000..4f02b26872 --- /dev/null +++ b/source4/heimdal/lib/hx509/crmf.asn1 @@ -0,0 +1,113 @@ +-- $Id: crmf.asn1,v 1.1 2006/04/18 13:05:21 lha Exp $ +PKCS10 DEFINITIONS ::= + +BEGIN + +IMPORTS + Time, + GeneralName, + SubjectPublicKeyInfo, + RelativeDistinguishedName, + AttributeTypeAndValue, + Extension, + AlgorithmIdentifier + FROM rfc2459 + heim_any + FROM heim; + +CRMFRDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +Controls ::= SEQUENCE -- SIZE(1..MAX) -- OF AttributeTypeAndValue + +-- XXX IMPLICIT brokenness +POPOSigningKey ::= SEQUENCE { + poposkInput [0] IMPLICIT POPOSigningKeyInput OPTIONAL, + algorithmIdentifier AlgorithmIdentifier, + signature BIT STRING } + +PKMACValue ::= SEQUENCE { + algId AlgorithmIdentifier, + value BIT STRING +} + +-- XXX IMPLICIT brokenness +POPOSigningKeyInput ::= SEQUENCE { + authInfo CHOICE { + sender [0] IMPLICIT GeneralName, + publicKeyMAC PKMACValue + }, + publicKey SubjectPublicKeyInfo +} -- from CertTemplate + + +PBMParameter ::= SEQUENCE { + salt OCTET STRING, + owf AlgorithmIdentifier, + iterationCount INTEGER, + mac AlgorithmIdentifier +} + +SubsequentMessage ::= INTEGER { + encrCert (0), + challengeResp (1) +} + +-- XXX IMPLICIT brokenness +POPOPrivKey ::= CHOICE { + thisMessage [0] BIT STRING, -- Deprecated + subsequentMessage [1] IMPLICIT SubsequentMessage, + dhMAC [2] BIT STRING, -- Deprecated + agreeMAC [3] IMPLICIT PKMACValue, + encryptedKey [4] heim_any +} + +-- XXX IMPLICIT brokenness +ProofOfPossession ::= CHOICE { + raVerified [0] NULL, + signature [1] POPOSigningKey, + keyEncipherment [2] POPOPrivKey, + keyAgreement [3] POPOPrivKey +} + +CertTemplate ::= SEQUENCE { + version [0] INTEGER OPTIONAL, + serialNumber [1] INTEGER OPTIONAL, + signingAlg [2] SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters heim_any OPTIONAL + } -- AlgorithmIdentifier -- OPTIONAL, + issuer [3] IMPLICIT CHOICE { + rdnSequence CRMFRDNSequence + } -- Name -- OPTIONAL, + validity [4] SEQUENCE { + notBefore [0] Time OPTIONAL, + notAfter [1] Time OPTIONAL + } -- OptionalValidity -- OPTIONAL, + subject [5] IMPLICIT CHOICE { + rdnSequence CRMFRDNSequence + } -- Name -- OPTIONAL, + publicKey [6] IMPLICIT SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING OPTIONAL + } -- SubjectPublicKeyInfo -- OPTIONAL, + issuerUID [7] IMPLICIT BIT STRING OPTIONAL, + subjectUID [8] IMPLICIT BIT STRING OPTIONAL, + extensions [9] IMPLICIT SEQUENCE OF Extension OPTIONAL +} + +CertRequest ::= SEQUENCE { + certReqId INTEGER, + certTemplate CertTemplate, + controls Controls OPTIONAL +} + +CertReqMsg ::= SEQUENCE { + certReq CertRequest, + popo ProofOfPossession OPTIONAL, + regInfo SEQUENCE OF AttributeTypeAndValue OPTIONAL } + +CertReqMessages ::= SEQUENCE OF CertReqMsg + + +END + diff --git a/source4/heimdal/lib/hx509/crypto.c b/source4/heimdal/lib/hx509/crypto.c new file mode 100644 index 0000000000..dac0a8160b --- /dev/null +++ b/source4/heimdal/lib/hx509/crypto.c @@ -0,0 +1,2438 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: crypto.c,v 1.63 2007/01/09 10:52:05 lha Exp $"); + +struct hx509_crypto; + +struct signature_alg; + +enum crypto_op_type { + COT_SIGN +}; + + +struct hx509_private_key_ops { + const char *pemtype; + const heim_oid *(*key_oid)(void); + int (*get_spki)(hx509_context, + const hx509_private_key, + SubjectPublicKeyInfo *); + int (*export)(hx509_context context, + const hx509_private_key, + heim_octet_string *); + int (*import)(hx509_context, + const void *data, + size_t len, + hx509_private_key private_key); + int (*generate_private_key)(hx509_context context, + hx509_private_key private_key); + int (*handle_alg)(const hx509_private_key, + const AlgorithmIdentifier *, + enum crypto_op_type); + int (*sign)(hx509_context context, + const hx509_private_key, + const AlgorithmIdentifier *, + const heim_octet_string *, + AlgorithmIdentifier *, + heim_octet_string *); +#if 0 + const AlgorithmIdentifier *(*preferred_sig_alg) + (const hx509_private_key, + const hx509_peer_info); + int (*unwrap)(hx509_context context, + const hx509_private_key, + const AlgorithmIdentifier *, + const heim_octet_string *, + heim_octet_string *); +#endif +}; + +struct hx509_private_key { + unsigned int ref; + const struct signature_alg *md; + const heim_oid *signature_alg; + union { + RSA *rsa; + void *keydata; + } private_key; + /* new crypto layer */ + hx509_private_key_ops *ops; +}; + +/* + * + */ + +struct signature_alg { + char *name; + const heim_oid *(*sig_oid)(void); + const AlgorithmIdentifier *(*sig_alg)(void); + const heim_oid *(*key_oid)(void); + const heim_oid *(*digest_oid)(void); + int flags; +#define PROVIDE_CONF 1 +#define REQUIRE_SIGNER 2 + +#define SIG_DIGEST 0x100 +#define SIG_PUBLIC_SIG 0x200 +#define SIG_PUBLIC_ENC 0x400 +#define SIG_SECRET 0x800 + + int (*verify_signature)(hx509_context context, + const struct signature_alg *, + const Certificate *, + const AlgorithmIdentifier *, + const heim_octet_string *, + const heim_octet_string *); + int (*create_signature)(hx509_context, + const struct signature_alg *, + const hx509_private_key, + const AlgorithmIdentifier *, + const heim_octet_string *, + AlgorithmIdentifier *, + heim_octet_string *); + int (*private_key2SPKI)(hx509_context, + hx509_private_key, + SubjectPublicKeyInfo *); +}; + +/* + * + */ + +static BIGNUM * +heim_int2BN(const heim_integer *i) +{ + BIGNUM *bn; + + bn = BN_bin2bn(i->data, i->length, NULL); + BN_set_negative(bn, i->negative); + return bn; +} + +static int +rsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const SubjectPublicKeyInfo *spi; + DigestInfo di; + unsigned char *to; + int tosize, retsize; + int ret; + RSA *rsa; + RSAPublicKey pk; + size_t size; + + memset(&di, 0, sizeof(di)); + + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + rsa = RSA_new(); + if (rsa == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + ret = decode_RSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to decode RSAPublicKey"); + goto out; + } + + rsa->n = heim_int2BN(&pk.modulus); + rsa->e = heim_int2BN(&pk.publicExponent); + + free_RSAPublicKey(&pk); + + if (rsa->n == NULL || rsa->e == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + tosize = RSA_size(rsa); + to = malloc(tosize); + if (to == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + retsize = RSA_public_decrypt(sig->length, (unsigned char *)sig->data, + to, rsa, RSA_PKCS1_PADDING); + if (retsize <= 0) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, + "RSA public decrypt failed: %d", retsize); + free(to); + goto out; + } + if (retsize > tosize) + _hx509_abort("internal rsa decryption failure: ret > tosize"); + ret = decode_DigestInfo(to, retsize, &di, &size); + free(to); + if (ret) { + goto out; + } + + /* Check for extra data inside the sigature */ + if (size != retsize) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "size from decryption mismatch"); + goto out; + } + + if (sig_alg->digest_oid && + der_heim_oid_cmp(&di.digestAlgorithm.algorithm, + (*sig_alg->digest_oid)()) != 0) + { + ret = HX509_CRYPTO_OID_MISMATCH; + hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch"); + goto out; + } + + /* verify that the parameters are NULL or the NULL-type */ + if (di.digestAlgorithm.parameters != NULL && + (di.digestAlgorithm.parameters->length != 2 || + memcmp(di.digestAlgorithm.parameters->data, "\x05\x00", 2) != 0)) + { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "Extra parameters inside RSA signature"); + goto out; + } + + ret = _hx509_verify_signature(context, + NULL, + &di.digestAlgorithm, + data, + &di.digest); + out: + free_DigestInfo(&di); + RSA_free(rsa); + return ret; +} + +static int +rsa_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + heim_octet_string indata; + const heim_oid *sig_oid; + DigestInfo di; + size_t size; + int ret; + + if (alg) + sig_oid = &alg->algorithm; + else + sig_oid = signer->signature_alg; + + if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha256WithRSAEncryption()) == 0) { + digest_alg = hx509_signature_sha256(); + } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha1WithRSAEncryption()) == 0) { + digest_alg = hx509_signature_sha1(); + } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) { + digest_alg = hx509_signature_md5(); + } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) { + digest_alg = hx509_signature_md5(); + } else if (der_heim_oid_cmp(sig_oid, oid_id_dsa_with_sha1()) == 0) { + digest_alg = hx509_signature_sha1(); + } else + return HX509_ALG_NOT_SUPP; + + if (signatureAlgorithm) { + ret = _hx509_set_digest_alg(signatureAlgorithm, + sig_oid, "\x05\x00", 2); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + } + + memset(&di, 0, sizeof(di)); + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + &di.digestAlgorithm, + &di.digest); + if (ret) + return ret; + ASN1_MALLOC_ENCODE(DigestInfo, + indata.data, + indata.length, + &di, + &size, + ret); + free_DigestInfo(&di); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + if (indata.length != size) + _hx509_abort("internal ASN.1 encoder error"); + + sig->length = RSA_size(signer->private_key.rsa); + sig->data = malloc(sig->length); + if (sig->data == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = RSA_private_encrypt(indata.length, indata.data, + sig->data, + signer->private_key.rsa, + RSA_PKCS1_PADDING); + der_free_octet_string(&indata); + if (ret <= 0) { + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + hx509_set_error_string(context, 0, ret, + "RSA private decrypt failed: %d", ret); + return ret; + } + if (ret > sig->length) + _hx509_abort("RSA signature prelen longer the output len"); + + sig->length = ret; + + return 0; +} + +static int +rsa_private_key_import(hx509_context context, + const void *data, + size_t len, + hx509_private_key private_key) +{ + const unsigned char *p = data; + + private_key->private_key.rsa = + d2i_RSAPrivateKey(NULL, &p, len); + if (private_key->private_key.rsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse RSA key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + + return 0; +} + +static int +rsa_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + int len, ret; + + memset(spki, 0, sizeof(*spki)); + + len = i2d_RSAPublicKey(private_key->private_key.rsa, NULL); + + spki->subjectPublicKey.data = malloc(len); + if (spki->subjectPublicKey.data == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory"); + return ENOMEM; + } + spki->subjectPublicKey.length = len * 8; + + ret = _hx509_set_digest_alg(&spki->algorithm, + oid_id_pkcs1_rsaEncryption(), + "\x05\x00", 2); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc - out of memory"); + free(spki->subjectPublicKey.data); + spki->subjectPublicKey.data = NULL; + spki->subjectPublicKey.length = 0; + return ret; + } + + { + unsigned char *pp = spki->subjectPublicKey.data; + i2d_RSAPublicKey(private_key->private_key.rsa, &pp); + } + + return 0; +} + +static int +cb_func(int a, int b, BN_GENCB *c) +{ + return 1; +} + +static int +rsa_generate_private_key(hx509_context context, hx509_private_key private_key) +{ + BN_GENCB cb; + BIGNUM *e; + int ret; + + static const int default_rsa_e = 65537; + static const int default_rsa_bits = 1024; + + private_key->private_key.rsa = RSA_new(); + if (private_key->private_key.rsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to generate RSA key"); + return HX509_PARSING_KEY_FAILED; + } + + e = BN_new(); + BN_set_word(e, default_rsa_e); + + BN_GENCB_set(&cb, cb_func, NULL); + ret = RSA_generate_key_ex(private_key->private_key.rsa, + default_rsa_bits, e, &cb); + BN_free(e); + if (ret != 1) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to generate RSA key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + + return 0; +} + +static int +rsa_private_key_export(hx509_context context, + const hx509_private_key key, + heim_octet_string *data) +{ + int ret; + + data->data = NULL; + data->length = 0; + + ret = i2d_RSAPrivateKey(key->private_key.rsa, NULL); + if (ret <= 0) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, + "Private key is not exportable"); + return ret; + } + + data->data = malloc(ret); + if (data->data == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + return ret; + } + data->length = ret; + + { + unsigned char *p = data->data; + i2d_RSAPrivateKey(key->private_key.rsa, &p); + } + + return 0; +} + + +static hx509_private_key_ops rsa_private_key_ops = { + "RSA PRIVATE KEY", + oid_id_pkcs1_rsaEncryption, + rsa_private_key2SPKI, + rsa_private_key_export, + rsa_private_key_import, + rsa_generate_private_key +}; + + +/* + * + */ + +static int +dsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const SubjectPublicKeyInfo *spi; + DSAPublicKey pk; + DSAParams param; + size_t size; + DSA *dsa; + int ret; + + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + dsa = DSA_new(); + if (dsa == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = decode_DSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) + goto out; + + dsa->pub_key = heim_int2BN(&pk); + + free_DSAPublicKey(&pk); + + if (dsa->pub_key == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + if (spi->algorithm.parameters == NULL) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "DSA parameters missing"); + goto out; + } + + ret = decode_DSAParams(spi->algorithm.parameters->data, + spi->algorithm.parameters->length, + ¶m, + &size); + if (ret) { + hx509_set_error_string(context, 0, ret, "DSA parameters failed to decode"); + goto out; + } + + dsa->p = heim_int2BN(¶m.p); + dsa->q = heim_int2BN(¶m.q); + dsa->g = heim_int2BN(¶m.g); + + free_DSAParams(¶m); + + if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + ret = DSA_verify(-1, data->data, data->length, + (unsigned char*)sig->data, sig->length, + dsa); + if (ret == 1) + ret = 0; + else if (ret == 0 || ret == -1) { + ret = HX509_CRYPTO_BAD_SIGNATURE; + hx509_set_error_string(context, 0, ret, "BAD DSA sigature"); + } else { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "Invalid format of DSA sigature"); + } + + out: + DSA_free(dsa); + + return ret; +} + +#if 0 +static int +dsa_parse_private_key(hx509_context context, + const void *data, + size_t len, + hx509_private_key private_key) +{ + const unsigned char *p = data; + + private_key->private_key.dsa = + d2i_DSAPrivateKey(NULL, &p, len); + if (private_key->private_key.dsa == NULL) + return EINVAL; + private_key->signature_alg = oid_id_dsa_with_sha1(); + + return 0; +/* else */ + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "No support to parse DSA keys"); + return HX509_PARSING_KEY_FAILED; +} +#endif + + +static int +sha1_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + unsigned char digest[SHA_DIGEST_LENGTH]; + SHA_CTX m; + + if (sig->length != SHA_DIGEST_LENGTH) { + hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, + "SHA1 sigature have wrong length"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + SHA1_Init(&m); + SHA1_Update(&m, data->data, data->length); + SHA1_Final (digest, &m); + + if (memcmp(digest, sig->data, SHA_DIGEST_LENGTH) != 0) { + hx509_set_error_string(context, 0, HX509_CRYPTO_BAD_SIGNATURE, + "Bad SHA1 sigature"); + return HX509_CRYPTO_BAD_SIGNATURE; + } + + return 0; +} + +static int +sha256_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + SHA256_CTX m; + + memset(sig, 0, sizeof(*sig)); + + if (signatureAlgorithm) { + int ret; + ret = _hx509_set_digest_alg(signatureAlgorithm, + (*sig_alg->sig_oid)(), "\x05\x00", 2); + if (ret) + return ret; + } + + + sig->data = malloc(SHA256_DIGEST_LENGTH); + if (sig->data == NULL) { + sig->length = 0; + return ENOMEM; + } + sig->length = SHA256_DIGEST_LENGTH; + + SHA256_Init(&m); + SHA256_Update(&m, data->data, data->length); + SHA256_Final (sig->data, &m); + + return 0; +} + +static int +sha256_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + unsigned char digest[SHA256_DIGEST_LENGTH]; + SHA256_CTX m; + + if (sig->length != SHA256_DIGEST_LENGTH) { + hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, + "SHA256 sigature have wrong length"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + SHA256_Init(&m); + SHA256_Update(&m, data->data, data->length); + SHA256_Final (digest, &m); + + if (memcmp(digest, sig->data, SHA256_DIGEST_LENGTH) != 0) { + hx509_set_error_string(context, 0, HX509_CRYPTO_BAD_SIGNATURE, + "Bad SHA256 sigature"); + return HX509_CRYPTO_BAD_SIGNATURE; + } + + return 0; +} + +static int +sha1_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + SHA_CTX m; + + memset(sig, 0, sizeof(*sig)); + + if (signatureAlgorithm) { + int ret; + ret = _hx509_set_digest_alg(signatureAlgorithm, + (*sig_alg->sig_oid)(), "\x05\x00", 2); + if (ret) + return ret; + } + + + sig->data = malloc(SHA_DIGEST_LENGTH); + if (sig->data == NULL) { + sig->length = 0; + return ENOMEM; + } + sig->length = SHA_DIGEST_LENGTH; + + SHA1_Init(&m); + SHA1_Update(&m, data->data, data->length); + SHA1_Final (sig->data, &m); + + return 0; +} + +static int +md5_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + unsigned char digest[MD5_DIGEST_LENGTH]; + MD5_CTX m; + + if (sig->length != MD5_DIGEST_LENGTH) { + hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, + "MD5 sigature have wrong length"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + MD5_Init(&m); + MD5_Update(&m, data->data, data->length); + MD5_Final (digest, &m); + + if (memcmp(digest, sig->data, MD5_DIGEST_LENGTH) != 0) { + hx509_set_error_string(context, 0, HX509_CRYPTO_BAD_SIGNATURE, + "Bad MD5 sigature"); + return HX509_CRYPTO_BAD_SIGNATURE; + } + + return 0; +} + +static int +md2_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + unsigned char digest[MD2_DIGEST_LENGTH]; + MD2_CTX m; + + if (sig->length != MD2_DIGEST_LENGTH) { + hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, + "MD2 sigature have wrong length"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + MD2_Init(&m); + MD2_Update(&m, data->data, data->length); + MD2_Final (digest, &m); + + if (memcmp(digest, sig->data, MD2_DIGEST_LENGTH) != 0) { + hx509_set_error_string(context, 0, HX509_CRYPTO_BAD_SIGNATURE, + "Bad MD2 sigature"); + return HX509_CRYPTO_BAD_SIGNATURE; + } + + return 0; +} + +static struct signature_alg pkcs1_rsa_sha1_alg = { + "rsa", + oid_id_pkcs1_rsaEncryption, + hx509_signature_rsa_with_sha1, + oid_id_pkcs1_rsaEncryption, + NULL, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + rsa_verify_signature, + rsa_create_signature, + rsa_private_key2SPKI +}; + +static struct signature_alg rsa_with_sha256_alg = { + "rsa-with-sha256", + oid_id_pkcs1_sha256WithRSAEncryption, + hx509_signature_rsa_with_sha256, + oid_id_pkcs1_rsaEncryption, + oid_id_sha256, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + rsa_verify_signature, + rsa_create_signature, + rsa_private_key2SPKI +}; + +static struct signature_alg rsa_with_sha1_alg = { + "rsa-with-sha1", + oid_id_pkcs1_sha1WithRSAEncryption, + hx509_signature_rsa_with_sha1, + oid_id_pkcs1_rsaEncryption, + oid_id_secsig_sha_1, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + rsa_verify_signature, + rsa_create_signature, + rsa_private_key2SPKI +}; + +static struct signature_alg rsa_with_md5_alg = { + "rsa-with-md5", + oid_id_pkcs1_md5WithRSAEncryption, + hx509_signature_rsa_with_md5, + oid_id_pkcs1_rsaEncryption, + oid_id_rsa_digest_md5, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + rsa_verify_signature, + rsa_create_signature, + rsa_private_key2SPKI +}; + +static struct signature_alg rsa_with_md2_alg = { + "rsa-with-md2", + oid_id_pkcs1_md2WithRSAEncryption, + hx509_signature_rsa_with_md2, + oid_id_pkcs1_rsaEncryption, + oid_id_rsa_digest_md2, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + rsa_verify_signature, + rsa_create_signature, + rsa_private_key2SPKI +}; + +static struct signature_alg dsa_sha1_alg = { + "dsa-with-sha1", + oid_id_dsa_with_sha1, + NULL, + oid_id_dsa, + oid_id_secsig_sha_1, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + dsa_verify_signature, + /* create_signature */ NULL, +}; + +static struct signature_alg sha256_alg = { + "sha-256", + oid_id_sha256, + hx509_signature_sha256, + NULL, + NULL, + SIG_DIGEST, + sha256_verify_signature, + sha256_create_signature +}; + +static struct signature_alg sha1_alg = { + "sha1", + oid_id_secsig_sha_1, + hx509_signature_sha1, + NULL, + NULL, + SIG_DIGEST, + sha1_verify_signature, + sha1_create_signature +}; + +static struct signature_alg md5_alg = { + "rsa-md5", + oid_id_rsa_digest_md5, + hx509_signature_md5, + NULL, + NULL, + SIG_DIGEST, + md5_verify_signature +}; + +static struct signature_alg md2_alg = { + "rsa-md2", + oid_id_rsa_digest_md2, + hx509_signature_md2, + NULL, + NULL, + SIG_DIGEST, + md2_verify_signature +}; + +/* + * Order matter in this structure, "best" first for each "key + * compatible" type (type is RSA, DSA, none, etc) + */ + +static struct signature_alg *sig_algs[] = { + &rsa_with_sha256_alg, + &rsa_with_sha1_alg, + &pkcs1_rsa_sha1_alg, + &rsa_with_md5_alg, + &rsa_with_md2_alg, + &dsa_sha1_alg, + &sha256_alg, + &sha1_alg, + &md5_alg, + &md2_alg, + NULL +}; + +static const struct signature_alg * +find_sig_alg(const heim_oid *oid) +{ + int i; + for (i = 0; sig_algs[i]; i++) + if (der_heim_oid_cmp((*sig_algs[i]->sig_oid)(), oid) == 0) + return sig_algs[i]; + return NULL; +} + +/* + * + */ + +static struct hx509_private_key_ops *private_algs[] = { + &rsa_private_key_ops, + NULL +}; + +static hx509_private_key_ops * +find_private_alg(const heim_oid *oid) +{ + int i; + for (i = 0; private_algs[i]; i++) { + if (private_algs[i]->key_oid == NULL) + continue; + if (der_heim_oid_cmp((*private_algs[i]->key_oid)(), oid) == 0) + return private_algs[i]; + } + return NULL; +} + + +int +_hx509_verify_signature(hx509_context context, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const struct signature_alg *md; + + md = find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + if (signer && (md->flags & PROVIDE_CONF) == 0) { + hx509_clear_error_string(context); + return HX509_CRYPTO_SIG_NO_CONF; + } + if (signer == NULL && (md->flags & REQUIRE_SIGNER)) { + hx509_clear_error_string(context); + return HX509_CRYPTO_SIGNATURE_WITHOUT_SIGNER; + } + if (md->key_oid && signer) { + const SubjectPublicKeyInfo *spi; + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + if (der_heim_oid_cmp(&spi->algorithm.algorithm, (*md->key_oid)()) != 0) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_DONT_MATCH_KEY_ALG; + } + } + return (*md->verify_signature)(context, md, signer, alg, data, sig); +} + +int +_hx509_verify_signature_bitstring(hx509_context context, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_bit_string *sig) +{ + heim_octet_string os; + + if (sig->length & 7) { + hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, + "signature not multiple of 8 bits"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + os.data = sig->data; + os.length = sig->length / 8; + + return _hx509_verify_signature(context, signer, alg, data, &os); +} + +int +_hx509_create_signature(hx509_context context, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const struct signature_alg *md; + + if (signer && signer->ops && signer->ops->handle_alg && + (*signer->ops->handle_alg)(signer, alg, COT_SIGN)) + { + return (*signer->ops->sign)(context, signer, alg, data, + signatureAlgorithm, sig); + } + + md = find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED, + "algorithm no supported"); + return HX509_SIG_ALG_NO_SUPPORTED; + } + + if (signer && (md->flags & PROVIDE_CONF) == 0) { + hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED, + "algorithm provides no conf"); + return HX509_CRYPTO_SIG_NO_CONF; + } + + return (*md->create_signature)(context, md, signer, alg, data, + signatureAlgorithm, sig); +} + +int +_hx509_create_signature_bitstring(hx509_context context, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_bit_string *sig) +{ + heim_octet_string os; + int ret; + + ret = _hx509_create_signature(context, signer, alg, + data, signatureAlgorithm, &os); + if (ret) + return ret; + sig->data = os.data; + sig->length = os.length * 8; + return 0; +} + +int +_hx509_public_encrypt(hx509_context context, + const heim_octet_string *cleartext, + const Certificate *cert, + heim_oid *encryption_oid, + heim_octet_string *ciphertext) +{ + const SubjectPublicKeyInfo *spi; + unsigned char *to; + int tosize; + int ret; + RSA *rsa; + RSAPublicKey pk; + size_t size; + + ciphertext->data = NULL; + ciphertext->length = 0; + + spi = &cert->tbsCertificate.subjectPublicKeyInfo; + + rsa = RSA_new(); + if (rsa == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = decode_RSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) { + RSA_free(rsa); + hx509_set_error_string(context, 0, ret, "RSAPublicKey decode failure"); + return ret; + } + rsa->n = heim_int2BN(&pk.modulus); + rsa->e = heim_int2BN(&pk.publicExponent); + + free_RSAPublicKey(&pk); + + if (rsa->n == NULL || rsa->e == NULL) { + RSA_free(rsa); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + tosize = RSA_size(rsa); + to = malloc(tosize); + if (to == NULL) { + RSA_free(rsa); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = RSA_public_encrypt(cleartext->length, + (unsigned char *)cleartext->data, + to, rsa, RSA_PKCS1_PADDING); + RSA_free(rsa); + if (ret <= 0) { + free(to); + hx509_set_error_string(context, 0, HX509_CRYPTO_RSA_PUBLIC_ENCRYPT, + "RSA public encrypt failed with %d", ret); + return HX509_CRYPTO_RSA_PUBLIC_ENCRYPT; + } + if (ret > tosize) + _hx509_abort("internal rsa decryption failure: ret > tosize"); + + ciphertext->length = ret; + ciphertext->data = to; + + ret = der_copy_oid(oid_id_pkcs1_rsaEncryption(), encryption_oid); + if (ret) { + der_free_octet_string(ciphertext); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + return 0; +} + +int +_hx509_private_key_private_decrypt(hx509_context context, + const heim_octet_string *ciphertext, + const heim_oid *encryption_oid, + hx509_private_key p, + heim_octet_string *cleartext) +{ + int ret; + + cleartext->data = NULL; + cleartext->length = 0; + + if (p->private_key.rsa == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "Private RSA key missing"); + return HX509_PRIVATE_KEY_MISSING; + } + + cleartext->length = RSA_size(p->private_key.rsa); + cleartext->data = malloc(cleartext->length); + if (cleartext->data == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + ret = RSA_private_decrypt(ciphertext->length, ciphertext->data, + cleartext->data, + p->private_key.rsa, + RSA_PKCS1_PADDING); + if (ret <= 0) { + der_free_octet_string(cleartext); + hx509_set_error_string(context, 0, HX509_CRYPTO_RSA_PRIVATE_DECRYPT, + "Failed to decrypt using private key: %d", ret); + return HX509_CRYPTO_RSA_PRIVATE_DECRYPT; + } + if (cleartext->length < ret) + _hx509_abort("internal rsa decryption failure: ret > tosize"); + + cleartext->length = ret; + + return 0; +} + + +int +_hx509_parse_private_key(hx509_context context, + const heim_oid *key_oid, + const void *data, + size_t len, + hx509_private_key *private_key) +{ + struct hx509_private_key_ops *ops; + int ret; + + *private_key = NULL; + + ops = find_private_alg(key_oid); + if (ops == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + + ret = _hx509_private_key_init(private_key, ops, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + + ret = (*ops->import)(context, data, len, *private_key); + if (ret) + _hx509_private_key_free(private_key); + + return ret; +} + +/* + * + */ + +int +_hx509_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + const struct hx509_private_key_ops *ops = private_key->ops; + if (ops == NULL || ops->get_spki == NULL) { + hx509_set_error_string(context, 0, HX509_UNIMPLEMENTED_OPERATION, + "Private key have no key2SPKI function"); + return HX509_UNIMPLEMENTED_OPERATION; + } + return (*ops->get_spki)(context, private_key, spki); +} + +int +_hx509_generate_private_key(hx509_context context, + const heim_oid *key_oid, + hx509_private_key *private_key) +{ + struct hx509_private_key_ops *ops; + int ret; + + *private_key = NULL; + + ops = find_private_alg(key_oid); + if (ops == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + + ret = _hx509_private_key_init(private_key, ops, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + + ret = (*ops->generate_private_key)(context, *private_key); + if (ret) + _hx509_private_key_free(private_key); + + return ret; +} + + +/* + * + */ + +static const heim_octet_string null_entry_oid = { 2, "\x05\x00" }; + +static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 3 }; +const AlgorithmIdentifier _hx509_signature_sha512_data = { + { 8, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2 }; +const AlgorithmIdentifier _hx509_signature_sha384_data = { + { 8, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_sha256_data = { + { 8, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; +const AlgorithmIdentifier _hx509_signature_sha1_data = { + { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; +const AlgorithmIdentifier _hx509_signature_md5_data = { + { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 }; +const AlgorithmIdentifier _hx509_signature_md2_data = { + { 6, rk_UNCONST(md2_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = { + { 7, rk_UNCONST(rsa_with_sha512_oid) }, NULL +}; + +static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = { + { 7, rk_UNCONST(rsa_with_sha384_oid) }, NULL +}; + +static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = { + { 7, rk_UNCONST(rsa_with_sha256_oid) }, NULL +}; + +static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = { + { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL +}; + +static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = { + { 7, rk_UNCONST(rsa_with_md5_oid) }, NULL +}; + +static const unsigned rsa_with_md2_oid[] ={ 1, 2, 840, 113549, 1, 1, 2 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_md2_data = { + { 7, rk_UNCONST(rsa_with_md2_oid) }, NULL +}; + +static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 }; +const AlgorithmIdentifier _hx509_signature_rsa_data = { + { 7, rk_UNCONST(rsa_oid) }, NULL +}; + + +const AlgorithmIdentifier * +hx509_signature_sha512(void) +{ return &_hx509_signature_sha512_data; } + +const AlgorithmIdentifier * +hx509_signature_sha384(void) +{ return &_hx509_signature_sha384_data; } + +const AlgorithmIdentifier * +hx509_signature_sha256(void) +{ return &_hx509_signature_sha256_data; } + +const AlgorithmIdentifier * +hx509_signature_sha1(void) +{ return &_hx509_signature_sha1_data; } + +const AlgorithmIdentifier * +hx509_signature_md5(void) +{ return &_hx509_signature_md5_data; } + +const AlgorithmIdentifier * +hx509_signature_md2(void) +{ return &_hx509_signature_md2_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha512(void) +{ return &_hx509_signature_rsa_with_sha512_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha384(void) +{ return &_hx509_signature_rsa_with_sha384_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha256(void) +{ return &_hx509_signature_rsa_with_sha256_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha1(void) +{ return &_hx509_signature_rsa_with_sha1_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_md5(void) +{ return &_hx509_signature_rsa_with_md5_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_md2(void) +{ return &_hx509_signature_rsa_with_md2_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa(void) +{ return &_hx509_signature_rsa_data; } + +int +_hx509_private_key_init(hx509_private_key *key, + hx509_private_key_ops *ops, + void *keydata) +{ + *key = calloc(1, sizeof(**key)); + if (*key == NULL) + return ENOMEM; + (*key)->ref = 1; + (*key)->ops = ops; + (*key)->private_key.keydata = keydata; + return 0; +} + +hx509_private_key +_hx509_private_key_ref(hx509_private_key key) +{ + if (key->ref <= 0) + _hx509_abort("refcount <= 0"); + key->ref++; + if (key->ref == 0) + _hx509_abort("refcount == 0"); + return key; +} + +const char * +_hx509_private_pem_name(hx509_private_key key) +{ + return key->ops->pemtype; +} + +int +_hx509_private_key_free(hx509_private_key *key) +{ + if (key == NULL || *key == NULL) + return 0; + + if ((*key)->ref <= 0) + _hx509_abort("refcount <= 0"); + if (--(*key)->ref > 0) + return 0; + + if ((*key)->private_key.rsa) + RSA_free((*key)->private_key.rsa); + (*key)->private_key.rsa = NULL; + free(*key); + *key = NULL; + return 0; +} + +void +_hx509_private_key_assign_rsa(hx509_private_key key, void *ptr) +{ + if (key->private_key.rsa) + RSA_free(key->private_key.rsa); + key->private_key.rsa = ptr; + key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + key->md = &pkcs1_rsa_sha1_alg; +} + +int +_hx509_private_key_oid(hx509_context context, + const hx509_private_key key, + heim_oid *data) +{ + int ret; + ret = der_copy_oid((*key->ops->key_oid)(), data); + if (ret) + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + return ret; +} + +int +_hx509_private_key_exportable(hx509_private_key key) +{ + if (key->ops->export == NULL) + return 0; + return 1; +} + +int +_hx509_private_key_export(hx509_context context, + const hx509_private_key key, + heim_octet_string *data) +{ + if (key->ops->export == NULL) { + hx509_clear_error_string(context); + return HX509_UNIMPLEMENTED_OPERATION; + } + return (*key->ops->export)(context, key, data); +} + +/* + * + */ + +struct hx509cipher { + const char *name; + const heim_oid *(*oid_func)(void); + const EVP_CIPHER *(*evp_func)(void); + int (*get_params)(hx509_context, const hx509_crypto, + const heim_octet_string *, heim_octet_string *); + int (*set_params)(hx509_context, const heim_octet_string *, + hx509_crypto, heim_octet_string *); +}; + +struct hx509_crypto_data { + char *name; + const struct hx509cipher *cipher; + const EVP_CIPHER *c; + heim_octet_string key; + heim_oid oid; + void *param; +}; + +/* + * + */ + +static const heim_oid * +oid_private_rc2_40(void) +{ + static unsigned oid_data[] = { 127, 1 }; + static const heim_oid oid = { 2, oid_data }; + + return &oid; +} + + +/* + * + */ + +static int +CMSCBCParam_get(hx509_context context, const hx509_crypto crypto, + const heim_octet_string *ivec, heim_octet_string *param) +{ + size_t size; + int ret; + + assert(crypto->param == NULL); + if (ivec == NULL) + return 0; + + ASN1_MALLOC_ENCODE(CMSCBCParameter, param->data, param->length, + ivec, &size, ret); + if (ret == 0 && size != param->length) + _hx509_abort("Internal asn1 encoder failure"); + if (ret) + hx509_clear_error_string(context); + return ret; +} + +static int +CMSCBCParam_set(hx509_context context, const heim_octet_string *param, + hx509_crypto crypto, heim_octet_string *ivec) +{ + int ret; + if (ivec == NULL) + return 0; + + ret = decode_CMSCBCParameter(param->data, param->length, ivec, NULL); + if (ret) + hx509_clear_error_string(context); + + return ret; +} + +struct _RC2_params { + int maximum_effective_key; +}; + +static int +CMSRC2CBCParam_get(hx509_context context, const hx509_crypto crypto, + const heim_octet_string *ivec, heim_octet_string *param) +{ + CMSRC2CBCParameter rc2params; + const struct _RC2_params *p = crypto->param; + int maximum_effective_key = 128; + size_t size; + int ret; + + memset(&rc2params, 0, sizeof(rc2params)); + + if (p) + maximum_effective_key = p->maximum_effective_key; + + switch(maximum_effective_key) { + case 40: + rc2params.rc2ParameterVersion = 160; + break; + case 64: + rc2params.rc2ParameterVersion = 120; + break; + case 128: + rc2params.rc2ParameterVersion = 58; + break; + } + rc2params.iv = *ivec; + + ASN1_MALLOC_ENCODE(CMSRC2CBCParameter, param->data, param->length, + &rc2params, &size, ret); + if (ret == 0 && size != param->length) + _hx509_abort("Internal asn1 encoder failure"); + + return ret; +} + +static int +CMSRC2CBCParam_set(hx509_context context, const heim_octet_string *param, + hx509_crypto crypto, heim_octet_string *ivec) +{ + CMSRC2CBCParameter rc2param; + struct _RC2_params *p; + size_t size; + int ret; + + ret = decode_CMSRC2CBCParameter(param->data, param->length, + &rc2param, &size); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + free_CMSRC2CBCParameter(&rc2param); + hx509_clear_error_string(context); + return ENOMEM; + } + switch(rc2param.rc2ParameterVersion) { + case 160: + crypto->c = EVP_rc2_40_cbc(); + p->maximum_effective_key = 40; + break; + case 120: + crypto->c = EVP_rc2_64_cbc(); + p->maximum_effective_key = 64; + break; + case 58: + crypto->c = EVP_rc2_cbc(); + p->maximum_effective_key = 128; + break; + default: + free_CMSRC2CBCParameter(&rc2param); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + if (ivec) + ret = der_copy_octet_string(&rc2param.iv, ivec); + free_CMSRC2CBCParameter(&rc2param); + if (ret) + hx509_clear_error_string(context); + else + crypto->param = p; + + return ret; +} + +/* + * + */ + +static const struct hx509cipher ciphers[] = { + { + "rc2-cbc", + oid_id_pkcs3_rc2_cbc, + EVP_rc2_cbc, + CMSRC2CBCParam_get, + CMSRC2CBCParam_set + }, + { + "rc2-cbc", + oid_id_rsadsi_rc2_cbc, + EVP_rc2_cbc, + CMSRC2CBCParam_get, + CMSRC2CBCParam_set + }, + { + "rc2-40-cbc", + oid_private_rc2_40, + EVP_rc2_40_cbc, + CMSRC2CBCParam_get, + CMSRC2CBCParam_set + }, + { + "des-ede3-cbc", + oid_id_pkcs3_des_ede3_cbc, + EVP_des_ede3_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "des-ede3-cbc", + oid_id_rsadsi_des_ede3_cbc, + EVP_des_ede3_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "aes-128-cbc", + oid_id_aes_128_cbc, + EVP_aes_128_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "aes-192-cbc", + oid_id_aes_192_cbc, + EVP_aes_192_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "aes-256-cbc", + oid_id_aes_256_cbc, + EVP_aes_256_cbc, + CMSCBCParam_get, + CMSCBCParam_set + } +}; + +static const struct hx509cipher * +find_cipher_by_oid(const heim_oid *oid) +{ + int i; + + for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) + if (der_heim_oid_cmp(oid, (*ciphers[i].oid_func)()) == 0) + return &ciphers[i]; + + return NULL; +} + +static const struct hx509cipher * +find_cipher_by_name(const char *name) +{ + int i; + + for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) + if (strcasecmp(name, ciphers[i].name) == 0) + return &ciphers[i]; + + return NULL; +} + + +const heim_oid * +hx509_crypto_enctype_by_name(const char *name) +{ + const struct hx509cipher *cipher; + + cipher = find_cipher_by_name(name); + if (cipher == NULL) + return NULL; + return (*cipher->oid_func)(); +} + +int +hx509_crypto_init(hx509_context context, + const char *provider, + const heim_oid *enctype, + hx509_crypto *crypto) +{ + const struct hx509cipher *cipher; + + *crypto = NULL; + + cipher = find_cipher_by_oid(enctype); + if (cipher == NULL) { + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "Algorithm not supported"); + return HX509_ALG_NOT_SUPP; + } + + *crypto = calloc(1, sizeof(**crypto)); + if (*crypto == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + (*crypto)->cipher = cipher; + (*crypto)->c = (*cipher->evp_func)(); + + if (der_copy_oid(enctype, &(*crypto)->oid)) { + hx509_crypto_destroy(*crypto); + *crypto = NULL; + hx509_clear_error_string(context); + return ENOMEM; + } + + return 0; +} + +const char * +hx509_crypto_provider(hx509_crypto crypto) +{ + return "unknown"; +} + +void +hx509_crypto_destroy(hx509_crypto crypto) +{ + if (crypto->name) + free(crypto->name); + if (crypto->key.data) + free(crypto->key.data); + if (crypto->param) + free(crypto->param); + der_free_oid(&crypto->oid); + memset(crypto, 0, sizeof(*crypto)); + free(crypto); +} + +int +hx509_crypto_set_key_name(hx509_crypto crypto, const char *name) +{ + return 0; +} + +int +hx509_crypto_set_key_data(hx509_crypto crypto, const void *data, size_t length) +{ + if (EVP_CIPHER_key_length(crypto->c) > length) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (crypto->key.data) { + free(crypto->key.data); + crypto->key.data = NULL; + crypto->key.length = 0; + } + crypto->key.data = malloc(length); + if (crypto->key.data == NULL) + return ENOMEM; + memcpy(crypto->key.data, data, length); + crypto->key.length = length; + + return 0; +} + +int +hx509_crypto_set_random_key(hx509_crypto crypto, heim_octet_string *key) +{ + if (crypto->key.data) { + free(crypto->key.data); + crypto->key.length = 0; + } + + crypto->key.length = EVP_CIPHER_key_length(crypto->c); + crypto->key.data = malloc(crypto->key.length); + if (crypto->key.data == NULL) { + crypto->key.length = 0; + return ENOMEM; + } + if (RAND_bytes(crypto->key.data, crypto->key.length) <= 0) { + free(crypto->key.data); + crypto->key.data = NULL; + crypto->key.length = 0; + return HX509_CRYPTO_INTERNAL_ERROR; + } + if (key) + return der_copy_octet_string(&crypto->key, key); + else + return 0; +} + +int +hx509_crypto_set_params(hx509_context context, + hx509_crypto crypto, + const heim_octet_string *param, + heim_octet_string *ivec) +{ + return (*crypto->cipher->set_params)(context, param, crypto, ivec); +} + +int +hx509_crypto_get_params(hx509_context context, + hx509_crypto crypto, + const heim_octet_string *ivec, + heim_octet_string *param) +{ + return (*crypto->cipher->get_params)(context, crypto, ivec, param); +} + +int +hx509_crypto_encrypt(hx509_crypto crypto, + const void *data, + const size_t length, + heim_octet_string *ivec, + heim_octet_string **ciphertext) +{ + EVP_CIPHER_CTX evp; + size_t padsize; + int ret; + + *ciphertext = NULL; + + EVP_CIPHER_CTX_init(&evp); + + ivec->length = EVP_CIPHER_iv_length(crypto->c); + ivec->data = malloc(ivec->length); + if (ivec->data == NULL) { + ret = ENOMEM; + goto out; + } + + if (RAND_bytes(ivec->data, ivec->length) <= 0) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + ret = EVP_CipherInit_ex(&evp, crypto->c, NULL, + crypto->key.data, ivec->data, 1); + if (ret != 1) { + EVP_CIPHER_CTX_cleanup(&evp); + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + *ciphertext = calloc(1, sizeof(**ciphertext)); + if (*ciphertext == NULL) { + ret = ENOMEM; + goto out; + } + + if (EVP_CIPHER_block_size(crypto->c) == 1) { + padsize = 0; + } else { + int bsize = EVP_CIPHER_block_size(crypto->c); + padsize = bsize - (length % bsize); + } + (*ciphertext)->length = length + padsize; + (*ciphertext)->data = malloc(length + padsize); + if ((*ciphertext)->data == NULL) { + ret = ENOMEM; + goto out; + } + + memcpy((*ciphertext)->data, data, length); + if (padsize) { + int i; + unsigned char *p = (*ciphertext)->data; + p += length; + for (i = 0; i < padsize; i++) + *p++ = padsize; + } + + ret = EVP_Cipher(&evp, (*ciphertext)->data, + (*ciphertext)->data, + length + padsize); + if (ret != 1) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + ret = 0; + + out: + if (ret) { + if (ivec->data) { + free(ivec->data); + memset(ivec, 0, sizeof(*ivec)); + } + if (*ciphertext) { + if ((*ciphertext)->data) { + free((*ciphertext)->data); + } + free(*ciphertext); + *ciphertext = NULL; + } + } + EVP_CIPHER_CTX_cleanup(&evp); + + return ret; +} + +int +hx509_crypto_decrypt(hx509_crypto crypto, + const void *data, + const size_t length, + heim_octet_string *ivec, + heim_octet_string *clear) +{ + EVP_CIPHER_CTX evp; + void *idata = NULL; + int ret; + + clear->data = NULL; + clear->length = 0; + + if (ivec && EVP_CIPHER_iv_length(crypto->c) < ivec->length) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (crypto->key.data == NULL) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (ivec) + idata = ivec->data; + + EVP_CIPHER_CTX_init(&evp); + + ret = EVP_CipherInit_ex(&evp, crypto->c, NULL, + crypto->key.data, idata, 0); + if (ret != 1) { + EVP_CIPHER_CTX_cleanup(&evp); + return HX509_CRYPTO_INTERNAL_ERROR; + } + + clear->length = length; + clear->data = malloc(length); + if (clear->data == NULL) { + EVP_CIPHER_CTX_cleanup(&evp); + clear->length = 0; + return ENOMEM; + } + + if (EVP_Cipher(&evp, clear->data, data, length) != 1) { + return HX509_CRYPTO_INTERNAL_ERROR; + } + EVP_CIPHER_CTX_cleanup(&evp); + + if (EVP_CIPHER_block_size(crypto->c) > 1) { + int padsize; + unsigned char *p; + int j, bsize = EVP_CIPHER_block_size(crypto->c); + + if (clear->length < bsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + + p = clear->data; + p += clear->length - 1; + padsize = *p; + if (padsize > bsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + clear->length -= padsize; + for (j = 0; j < padsize; j++) { + if (*p-- != padsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + } + } + + return 0; + + out: + if (clear->data) + free(clear->data); + clear->data = NULL; + clear->length = 0; + return ret; +} + +typedef int (*PBE_string2key_func)(hx509_context, + const char *, + const heim_octet_string *, + hx509_crypto *, heim_octet_string *, + heim_octet_string *, + const heim_oid *, const EVP_MD *); + +static int +PBE_string2key(hx509_context context, + const char *password, + const heim_octet_string *parameters, + hx509_crypto *crypto, + heim_octet_string *key, heim_octet_string *iv, + const heim_oid *enc_oid, + const EVP_MD *md) +{ + PKCS12_PBEParams p12params; + int passwordlen = strlen(password); + hx509_crypto c; + int iter, saltlen, ret; + unsigned char *salt; + + if (parameters == NULL) + return HX509_ALG_NOT_SUPP; + + ret = decode_PKCS12_PBEParams(parameters->data, + parameters->length, + &p12params, NULL); + if (ret) + goto out; + + if (p12params.iterations) + iter = *p12params.iterations; + else + iter = 1; + salt = p12params.salt.data; + saltlen = p12params.salt.length; + + /* XXX It needs to be here, but why ? */ + if (passwordlen == 0) + password = NULL; + + if (!PKCS12_key_gen (password, passwordlen, salt, saltlen, + PKCS12_KEY_ID, iter, key->length, key->data, md)) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + if (!PKCS12_key_gen (password, passwordlen, salt, saltlen, + PKCS12_IV_ID, iter, iv->length, iv->data, md)) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + ret = hx509_crypto_init(context, NULL, enc_oid, &c); + if (ret) + goto out; + + ret = hx509_crypto_set_key_data(c, key->data, key->length); + if (ret) { + hx509_crypto_destroy(c); + goto out; + } + + *crypto = c; +out: + free_PKCS12_PBEParams(&p12params); + return ret; +} + +static const heim_oid * +find_string2key(const heim_oid *oid, + const EVP_CIPHER **c, + const EVP_MD **md, + PBE_string2key_func *s2k) +{ + if (der_heim_oid_cmp(oid, oid_id_pbewithSHAAnd40BitRC2_CBC()) == 0) { + *c = EVP_rc2_40_cbc(); + *md = EVP_sha1(); + *s2k = PBE_string2key; + return oid_private_rc2_40(); + } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC2_CBC()) == 0) { + *c = EVP_rc2_cbc(); + *md = EVP_sha1(); + *s2k = PBE_string2key; + return oid_id_pkcs3_rc2_cbc(); +#if 0 + } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd40BitRC4()) == 0) { + *c = EVP_rc4_40(); + *md = EVP_sha1(); + *s2k = PBE_string2key; + return NULL; + } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC4()) == 0) { + *c = EVP_rc4(); + *md = EVP_sha1(); + *s2k = PBE_string2key; + return oid_id_pkcs3_rc4(); +#endif + } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC()) == 0) { + *c = EVP_des_ede3_cbc(); + *md = EVP_sha1(); + *s2k = PBE_string2key; + return oid_id_pkcs3_des_ede3_cbc(); + } + + return NULL; +} + + +int +_hx509_pbe_decrypt(hx509_context context, + hx509_lock lock, + const AlgorithmIdentifier *ai, + const heim_octet_string *econtent, + heim_octet_string *content) +{ + const struct _hx509_password *pw; + heim_octet_string key, iv; + const heim_oid *enc_oid; + const EVP_CIPHER *c; + const EVP_MD *md; + PBE_string2key_func s2k; + int i, ret = 0; + + memset(&key, 0, sizeof(key)); + memset(&iv, 0, sizeof(iv)); + + memset(content, 0, sizeof(*content)); + + enc_oid = find_string2key(&ai->algorithm, &c, &md, &s2k); + if (enc_oid == NULL) { + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "String to key algorithm not supported"); + ret = HX509_ALG_NOT_SUPP; + goto out; + } + + key.length = EVP_CIPHER_key_length(c); + key.data = malloc(key.length); + if (key.data == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + iv.length = EVP_CIPHER_iv_length(c); + iv.data = malloc(iv.length); + if (iv.data == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + pw = _hx509_lock_get_passwords(lock); + + ret = HX509_CRYPTO_INTERNAL_ERROR; + for (i = 0; i < pw->len + 1; i++) { + hx509_crypto crypto; + const char *password; + + if (i < pw->len) + password = pw->val[i]; + else + password = ""; + + ret = (*s2k)(context, password, ai->parameters, &crypto, + &key, &iv, enc_oid, md); + if (ret) + goto out; + + ret = hx509_crypto_decrypt(crypto, + econtent->data, + econtent->length, + &iv, + content); + hx509_crypto_destroy(crypto); + if (ret == 0) + goto out; + + } +out: + if (key.data) + der_free_octet_string(&key); + if (iv.data) + der_free_octet_string(&iv); + return ret; +} + +/* + * + */ + + +int +_hx509_match_keys(hx509_cert c, hx509_private_key private_key) +{ + const Certificate *cert; + const SubjectPublicKeyInfo *spi; + RSAPublicKey pk; + RSA *rsa; + size_t size; + int ret; + + if (private_key->private_key.rsa == NULL) + return 0; + + rsa = private_key->private_key.rsa; + if (rsa->d == NULL || rsa->p == NULL || rsa->q == NULL) + return 0; + + cert = _hx509_get_cert(c); + spi = &cert->tbsCertificate.subjectPublicKeyInfo; + + rsa = RSA_new(); + if (rsa == NULL) + return 0; + + ret = decode_RSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) { + RSA_free(rsa); + return 0; + } + rsa->n = heim_int2BN(&pk.modulus); + rsa->e = heim_int2BN(&pk.publicExponent); + + free_RSAPublicKey(&pk); + + rsa->d = BN_dup(private_key->private_key.rsa->d); + rsa->p = BN_dup(private_key->private_key.rsa->p); + rsa->q = BN_dup(private_key->private_key.rsa->q); + rsa->dmp1 = BN_dup(private_key->private_key.rsa->dmp1); + rsa->dmq1 = BN_dup(private_key->private_key.rsa->dmq1); + rsa->iqmp = BN_dup(private_key->private_key.rsa->iqmp); + + if (rsa->n == NULL || rsa->e == NULL || + rsa->d == NULL || rsa->p == NULL|| rsa->q == NULL || + rsa->dmp1 == NULL || rsa->dmq1 == NULL) { + RSA_free(rsa); + return 0; + } + + ret = RSA_check_key(rsa); + RSA_free(rsa); + + return ret == 1; +} + +static const heim_oid * +find_keytype(const hx509_private_key key) +{ + const struct signature_alg *md; + + if (key == NULL) + return NULL; + + md = find_sig_alg(key->signature_alg); + if (md == NULL) + return NULL; + return (*md->key_oid)(); +} + + +int +hx509_crypto_select(const hx509_context context, + int type, + const hx509_private_key source, + hx509_peer_info peer, + AlgorithmIdentifier *selected) +{ + const heim_oid *keytype = NULL; + const AlgorithmIdentifier *def; + size_t i, j; + int ret, bits; + + memset(selected, 0, sizeof(*selected)); + + if (type == HX509_SELECT_DIGEST) { + bits = SIG_DIGEST; + def = hx509_signature_sha1(); + } else if (type == HX509_SELECT_PUBLIC_SIG) { + bits = SIG_PUBLIC_SIG; + /* XXX depend on `source´ and `peer´ */ + def = hx509_signature_rsa_with_sha1(); + } else { + hx509_set_error_string(context, 0, EINVAL, + "Unknown type %d of selection", type); + return EINVAL; + } + + keytype = find_keytype(source); + + if (peer) { + for (i = 0; i < peer->len; i++) { + for (j = 0; sig_algs[j]; j++) { + if ((sig_algs[j]->flags & bits) != bits) + continue; + if (der_heim_oid_cmp((*sig_algs[j]->sig_oid)(), + &peer->val[i].algorithm) != 0) + continue; + if (keytype && sig_algs[j]->key_oid && + der_heim_oid_cmp(keytype, (*sig_algs[j]->key_oid)())) + continue; + + /* found one, use that */ + ret = copy_AlgorithmIdentifier(&peer->val[i], selected); + if (ret) + hx509_clear_error_string(context); + return ret; + } + } + } + + /* use default */ + ret = copy_AlgorithmIdentifier(def, selected); + if (ret) + hx509_clear_error_string(context); + return ret; +} + +int +hx509_crypto_available(hx509_context context, + int type, + hx509_cert source, + AlgorithmIdentifier **val, + unsigned int *plen) +{ + const heim_oid *keytype = NULL; + unsigned int len, i; + void *ptr; + int bits, ret; + + *val = NULL; + + if (type == HX509_SELECT_ALL) { + bits = SIG_DIGEST | SIG_PUBLIC_SIG; + } else if (type == HX509_SELECT_DIGEST) { + bits = SIG_DIGEST; + } else if (type == HX509_SELECT_PUBLIC_SIG) { + bits = SIG_PUBLIC_SIG; + } else { + hx509_set_error_string(context, 0, EINVAL, + "Unknown type %d of available", type); + return EINVAL; + } + + if (source) + keytype = find_keytype(_hx509_cert_private_key(source)); + + len = 0; + for (i = 0; sig_algs[i]; i++) { + if ((sig_algs[i]->flags & bits) == 0) + continue; + if (sig_algs[i]->sig_alg == NULL) + continue; + if (keytype && sig_algs[i]->key_oid && + der_heim_oid_cmp((*sig_algs[i]->key_oid)(), keytype)) + continue; + + /* found one, add that to the list */ + ptr = realloc(*val, sizeof(**val) * (len + 1)); + if (ptr == NULL) + goto out; + *val = ptr; + + ret = copy_AlgorithmIdentifier((*sig_algs[i]->sig_alg)(), &(*val)[len]); + if (ret) + goto out; + len++; + } + + *plen = len; + return 0; + +out: + for (i = 0; i < len; i++) + free_AlgorithmIdentifier(&(*val)[i]); + free(*val); + *val = NULL; + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; +} + +void +hx509_crypto_free_algs(AlgorithmIdentifier *val, + unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + free_AlgorithmIdentifier(&val[i]); + free(val); +} diff --git a/source4/heimdal/lib/hx509/error.c b/source4/heimdal/lib/hx509/error.c new file mode 100644 index 0000000000..770b71981a --- /dev/null +++ b/source4/heimdal/lib/hx509/error.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: error.c,v 1.4 2006/11/16 15:08:09 lha Exp $"); + +struct hx509_error_data { + hx509_error next; + int code; + char *msg; +}; + +static void +free_error_string(hx509_error msg) +{ + while(msg) { + hx509_error m2 = msg->next; + free(msg->msg); + free(msg); + msg = m2; + } +} + +void +hx509_clear_error_string(hx509_context context) +{ + free_error_string(context->error); + context->error = NULL; +} + +void +hx509_set_error_stringv(hx509_context context, int flags, int code, + const char *fmt, va_list ap) +{ + hx509_error msg; + + msg = calloc(1, sizeof(*msg)); + if (msg == NULL) { + hx509_clear_error_string(context); + return; + } + + if (vasprintf(&msg->msg, fmt, ap) == -1) { + hx509_clear_error_string(context); + free(msg); + return; + } + msg->code = code; + + if (flags & HX509_ERROR_APPEND) { + msg->next = context->error; + context->error = msg; + } else { + free_error_string(context->error); + context->error = msg; + } +} + +void +hx509_set_error_string(hx509_context context, int flags, int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + hx509_set_error_stringv(context, flags, code, fmt, ap); + va_end(ap); +} + +char * +hx509_get_error_string(hx509_context context, int error_code) +{ + struct rk_strpool *p = NULL; + hx509_error msg; + + if (context->error == NULL) { + const char *cstr; + char *str; + + cstr = com_right(context->et_list, error_code); + if (cstr) + return strdup(cstr); + cstr = strerror(error_code); + if (cstr) + return strdup(cstr); + if (asprintf(&str, "<unknown error: %d>", error_code) == -1) + return NULL; + return str; + } + + for (msg = context->error; msg; msg = msg->next) + p = rk_strpoolprintf(p, "%s%s", msg->msg, + msg->next != NULL ? "; " : ""); + + return rk_strpoolcollect(p); +} + +void +hx509_err(hx509_context context, int exit_code, int error_code, char *fmt, ...) +{ + va_list ap; + char *msg, *str; + + va_start(ap, fmt); + vasprintf(&str, fmt, ap); + va_end(ap); + msg = hx509_get_error_string(context, error_code); + if (msg == NULL) + msg = "no error"; + + errx(exit_code, "%s: %s", str, msg); +} diff --git a/source4/heimdal/lib/hx509/file.c b/source4/heimdal/lib/hx509/file.c new file mode 100644 index 0000000000..39497fc3a9 --- /dev/null +++ b/source4/heimdal/lib/hx509/file.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$ID$"); + +int +_hx509_map_file(const char *fn, void **data, size_t *length, struct stat *rsb) +{ + struct stat sb; + size_t len; + ssize_t l; + int ret; + void *d; + int fd; + + *data = NULL; + *length = 0; + + fd = open(fn, O_RDONLY); + if (fd < 0) + return errno; + + if (fstat(fd, &sb) < 0) { + ret = errno; + close(fd); + return ret; + } + + len = sb.st_size; + + d = malloc(len); + if (d == NULL) { + close(fd); + return ENOMEM; + } + + l = read(fd, d, len); + close(fd); + if (l < 0 || l != len) { + free(d); + return EINVAL; + } + + if (rsb) + *rsb = sb; + *data = d; + *length = len; + return 0; +} + +void +_hx509_unmap_file(void *data, size_t len) +{ + free(data); +} + +int +_hx509_write_file(const char *fn, const void *data, size_t length) +{ + ssize_t sz; + const unsigned char *p = data; + int fd; + + fd = open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); + if (fd < 0) + return errno; + + do { + sz = write(fd, p, length); + if (sz < 0) { + int saved_errno = errno; + close(fd); + return saved_errno; + } + if (sz == 0) + break; + length -= sz; + } while (length > 0); + + if (close(fd) == -1) + return errno; + + return 0; +} diff --git a/source4/heimdal/lib/hx509/hx509-protos.h b/source4/heimdal/lib/hx509/hx509-protos.h new file mode 100644 index 0000000000..4fcab70ff8 --- /dev/null +++ b/source4/heimdal/lib/hx509/hx509-protos.h @@ -0,0 +1,824 @@ +/* This is a generated file */ +#ifndef __hx509_protos_h__ +#define __hx509_protos_h__ + +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +void +hx509_bitstring_print ( + const heim_bit_string */*b*/, + hx509_vprint_func /*func*/, + void */*ctx*/); + +int +hx509_ca_sign ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + hx509_cert /*signer*/, + hx509_cert */*certificate*/); + +int +hx509_ca_sign_self ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + hx509_private_key /*signer*/, + hx509_cert */*certificate*/); + +int +hx509_ca_tbs_add_eku ( + hx509_context /*contex*/, + hx509_ca_tbs /*tbs*/, + const heim_oid */*oid*/); + +int +hx509_ca_tbs_add_san_hostname ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const char */*dnsname*/); + +int +hx509_ca_tbs_add_san_otherName ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const heim_oid */*oid*/, + const heim_octet_string */*os*/); + +int +hx509_ca_tbs_add_san_pkinit ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const char */*principal*/); + +int +hx509_ca_tbs_add_san_rfc822name ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const char */*rfc822Name*/); + +void +hx509_ca_tbs_free (hx509_ca_tbs */*tbs*/); + +int +hx509_ca_tbs_init ( + hx509_context /*context*/, + hx509_ca_tbs */*tbs*/); + +int +hx509_ca_tbs_set_ca ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + int /*pathLenConstraint*/); + +int +hx509_ca_tbs_set_notAfter ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + time_t /*t*/); + +int +hx509_ca_tbs_set_notAfter_lifetime ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + time_t /*delta*/); + +int +hx509_ca_tbs_set_notBefore ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + time_t /*t*/); + +int +hx509_ca_tbs_set_proxy ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + int /*pathLenConstraint*/); + +int +hx509_ca_tbs_set_serialnumber ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const heim_integer */*serialNumber*/); + +int +hx509_ca_tbs_set_spki ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const SubjectPublicKeyInfo */*spki*/); + +int +hx509_ca_tbs_set_subject ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + hx509_name /*subject*/); + +int +hx509_cert_check_eku ( + hx509_context /*context*/, + hx509_cert /*cert*/, + const heim_oid */*eku*/, + int /*allow_any_eku*/); + +int +hx509_cert_cmp ( + hx509_cert /*p*/, + hx509_cert /*q*/); + +int +hx509_cert_find_subjectAltName_otherName ( + hx509_cert /*cert*/, + const heim_oid */*oid*/, + hx509_octet_string_list */*list*/); + +void +hx509_cert_free (hx509_cert /*cert*/); + +hx509_cert_attribute +hx509_cert_get_attribute ( + hx509_cert /*cert*/, + const heim_oid */*oid*/); + +int +hx509_cert_get_base_subject ( + hx509_context /*context*/, + hx509_cert /*c*/, + hx509_name */*name*/); + +const char * +hx509_cert_get_friendly_name (hx509_cert /*cert*/); + +int +hx509_cert_get_issuer ( + hx509_cert /*p*/, + hx509_name */*name*/); + +int +hx509_cert_get_serialnumber ( + hx509_cert /*p*/, + heim_integer */*i*/); + +int +hx509_cert_get_subject ( + hx509_cert /*p*/, + hx509_name */*name*/); + +int +hx509_cert_init ( + hx509_context /*context*/, + const Certificate */*c*/, + hx509_cert */*cert*/); + +int +hx509_cert_keyusage_print ( + hx509_context /*context*/, + hx509_cert /*c*/, + char **/*s*/); + +hx509_cert +hx509_cert_ref (hx509_cert /*cert*/); + +int +hx509_cert_set_friendly_name ( + hx509_cert /*cert*/, + const char */*name*/); + +int +hx509_certs_add ( + hx509_context /*context*/, + hx509_certs /*certs*/, + hx509_cert /*cert*/); + +int +hx509_certs_append ( + hx509_context /*context*/, + hx509_certs /*to*/, + hx509_lock /*lock*/, + const char */*name*/); + +int +hx509_certs_end_seq ( + hx509_context /*context*/, + hx509_certs /*certs*/, + hx509_cursor /*cursor*/); + +int +hx509_certs_find ( + hx509_context /*context*/, + hx509_certs /*certs*/, + const hx509_query */*q*/, + hx509_cert */*r*/); + +void +hx509_certs_free (hx509_certs */*certs*/); + +int +hx509_certs_info ( + hx509_context /*context*/, + hx509_certs /*certs*/, + int (*/*func*/)(void *, char *), + void */*ctx*/); + +int +hx509_certs_init ( + hx509_context /*context*/, + const char */*name*/, + int /*flags*/, + hx509_lock /*lock*/, + hx509_certs */*certs*/); + +int +hx509_certs_iter ( + hx509_context /*context*/, + hx509_certs /*certs*/, + int (*/*fn*/)(hx509_context, void *, hx509_cert), + void */*ctx*/); + +int +hx509_certs_merge ( + hx509_context /*context*/, + hx509_certs /*to*/, + hx509_certs /*from*/); + +int +hx509_certs_next_cert ( + hx509_context /*context*/, + hx509_certs /*certs*/, + hx509_cursor /*cursor*/, + hx509_cert */*cert*/); + +int +hx509_certs_start_seq ( + hx509_context /*context*/, + hx509_certs /*certs*/, + hx509_cursor */*cursor*/); + +int +hx509_certs_store ( + hx509_context /*context*/, + hx509_certs /*certs*/, + int /*flags*/, + hx509_lock /*lock*/); + +int +hx509_ci_print_names ( + hx509_context /*context*/, + void */*ctx*/, + hx509_cert /*c*/); + +void +hx509_clear_error_string (hx509_context /*context*/); + +int +hx509_cms_create_signed_1 ( + hx509_context /*context*/, + const heim_oid */*eContentType*/, + const void */*data*/, + size_t /*length*/, + const AlgorithmIdentifier */*digest_alg*/, + hx509_cert /*cert*/, + hx509_peer_info /*peer*/, + hx509_certs /*anchors*/, + hx509_certs /*pool*/, + heim_octet_string */*signed_data*/); + +int +hx509_cms_decrypt_encrypted ( + hx509_context /*context*/, + hx509_lock /*lock*/, + const void */*data*/, + size_t /*length*/, + heim_oid */*contentType*/, + heim_octet_string */*content*/); + +int +hx509_cms_envelope_1 ( + hx509_context /*context*/, + hx509_cert /*cert*/, + const void */*data*/, + size_t /*length*/, + const heim_oid */*encryption_type*/, + const heim_oid */*contentType*/, + heim_octet_string */*content*/); + +int +hx509_cms_unenvelope ( + hx509_context /*context*/, + hx509_certs /*certs*/, + int /*flags*/, + const void */*data*/, + size_t /*length*/, + const heim_octet_string */*encryptedContent*/, + heim_oid */*contentType*/, + heim_octet_string */*content*/); + +int +hx509_cms_unwrap_ContentInfo ( + const heim_octet_string */*in*/, + heim_oid */*oid*/, + heim_octet_string */*out*/, + int */*have_data*/); + +int +hx509_cms_verify_signed ( + hx509_context /*context*/, + hx509_verify_ctx /*ctx*/, + const void */*data*/, + size_t /*length*/, + hx509_certs /*store*/, + heim_oid */*contentType*/, + heim_octet_string */*content*/, + hx509_certs */*signer_certs*/); + +int +hx509_cms_wrap_ContentInfo ( + const heim_oid */*oid*/, + const heim_octet_string */*buf*/, + heim_octet_string */*res*/); + +void +hx509_context_free (hx509_context */*context*/); + +int +hx509_context_init (hx509_context */*context*/); + +void +hx509_context_set_missing_revoke ( + hx509_context /*context*/, + int /*flag*/); + +int +hx509_crypto_available ( + hx509_context /*context*/, + int /*type*/, + hx509_cert /*source*/, + AlgorithmIdentifier **/*val*/, + unsigned int */*plen*/); + +int +hx509_crypto_decrypt ( + hx509_crypto /*crypto*/, + const void */*data*/, + const size_t /*length*/, + heim_octet_string */*ivec*/, + heim_octet_string */*clear*/); + +void +hx509_crypto_destroy (hx509_crypto /*crypto*/); + +int +hx509_crypto_encrypt ( + hx509_crypto /*crypto*/, + const void */*data*/, + const size_t /*length*/, + heim_octet_string */*ivec*/, + heim_octet_string **/*ciphertext*/); + +const heim_oid * +hx509_crypto_enctype_by_name (const char */*name*/); + +void +hx509_crypto_free_algs ( + AlgorithmIdentifier */*val*/, + unsigned int /*len*/); + +int +hx509_crypto_get_params ( + hx509_context /*context*/, + hx509_crypto /*crypto*/, + const heim_octet_string */*ivec*/, + heim_octet_string */*param*/); + +int +hx509_crypto_init ( + hx509_context /*context*/, + const char */*provider*/, + const heim_oid */*enctype*/, + hx509_crypto */*crypto*/); + +const char * +hx509_crypto_provider (hx509_crypto /*crypto*/); + +int +hx509_crypto_select ( + const hx509_context /*context*/, + int /*type*/, + const hx509_private_key /*source*/, + hx509_peer_info /*peer*/, + AlgorithmIdentifier */*selected*/); + +int +hx509_crypto_set_key_data ( + hx509_crypto /*crypto*/, + const void */*data*/, + size_t /*length*/); + +int +hx509_crypto_set_key_name ( + hx509_crypto /*crypto*/, + const char */*name*/); + +int +hx509_crypto_set_params ( + hx509_context /*context*/, + hx509_crypto /*crypto*/, + const heim_octet_string */*param*/, + heim_octet_string */*ivec*/); + +int +hx509_crypto_set_random_key ( + hx509_crypto /*crypto*/, + heim_octet_string */*key*/); + +void +hx509_err ( + hx509_context /*context*/, + int /*exit_code*/, + int /*error_code*/, + char */*fmt*/, + ...); + +void +hx509_free_octet_string_list (hx509_octet_string_list */*list*/); + +char * +hx509_get_error_string ( + hx509_context /*context*/, + int /*error_code*/); + +int +hx509_get_one_cert ( + hx509_context /*context*/, + hx509_certs /*certs*/, + hx509_cert */*c*/); + +int +hx509_lock_add_cert ( + hx509_context /*context*/, + hx509_lock /*lock*/, + hx509_cert /*cert*/); + +int +hx509_lock_add_certs ( + hx509_context /*context*/, + hx509_lock /*lock*/, + hx509_certs /*certs*/); + +int +hx509_lock_add_password ( + hx509_lock /*lock*/, + const char */*password*/); + +int +hx509_lock_command_string ( + hx509_lock /*lock*/, + const char */*string*/); + +void +hx509_lock_free (hx509_lock /*lock*/); + +int +hx509_lock_init ( + hx509_context /*context*/, + hx509_lock */*lock*/); + +int +hx509_lock_prompt ( + hx509_lock /*lock*/, + hx509_prompt */*prompt*/); + +void +hx509_lock_reset_certs ( + hx509_context /*context*/, + hx509_lock /*lock*/); + +void +hx509_lock_reset_passwords (hx509_lock /*lock*/); + +void +hx509_lock_reset_promper (hx509_lock /*lock*/); + +int +hx509_lock_set_prompter ( + hx509_lock /*lock*/, + hx509_prompter_fct /*prompt*/, + void */*data*/); + +int +hx509_name_copy ( + hx509_context /*context*/, + const hx509_name /*from*/, + hx509_name */*to*/); + +void +hx509_name_free (hx509_name */*name*/); + +int +hx509_name_is_null_p (const hx509_name /*name*/); + +int +hx509_name_to_Name ( + const hx509_name /*from*/, + Name */*to*/); + +int +hx509_name_to_der_name ( + const hx509_name /*name*/, + void **/*data*/, + size_t */*length*/); + +int +hx509_name_to_string ( + const hx509_name /*name*/, + char **/*str*/); + +int +hx509_ocsp_request ( + hx509_context /*context*/, + hx509_certs /*reqcerts*/, + hx509_certs /*pool*/, + hx509_cert /*signer*/, + const AlgorithmIdentifier */*digest*/, + heim_octet_string */*request*/, + heim_octet_string */*nonce*/); + +int +hx509_ocsp_verify ( + hx509_context /*context*/, + time_t /*now*/, + hx509_cert /*cert*/, + int /*flags*/, + const void */*data*/, + size_t /*length*/, + time_t */*expiration*/); + +void +hx509_oid_print ( + const heim_oid */*oid*/, + hx509_vprint_func /*func*/, + void */*ctx*/); + +int +hx509_oid_sprint ( + const heim_oid */*oid*/, + char **/*str*/); + +int +hx509_parse_name ( + hx509_context /*context*/, + const char */*str*/, + hx509_name */*name*/); + +int +hx509_peer_info_alloc ( + hx509_context /*context*/, + hx509_peer_info */*peer*/); + +int +hx509_peer_info_free (hx509_peer_info /*peer*/); + +int +hx509_peer_info_set_cert ( + hx509_peer_info /*peer*/, + hx509_cert /*cert*/); + +int +hx509_peer_info_set_cms_algs ( + hx509_context /*context*/, + hx509_peer_info /*peer*/, + const AlgorithmIdentifier */*val*/, + size_t /*len*/); + +void +hx509_print_func ( + hx509_vprint_func /*func*/, + void */*ctx*/, + const char */*fmt*/, + ...); + +void +hx509_print_stdout ( + void */*ctx*/, + const char */*fmt*/, + va_list /*va*/); + +int +hx509_prompt_hidden (hx509_prompt_type /*type*/); + +int +hx509_query_alloc ( + hx509_context /*context*/, + hx509_query **/*q*/); + +void +hx509_query_free ( + hx509_context /*context*/, + hx509_query */*q*/); + +int +hx509_query_match_cmp_func ( + hx509_query */*q*/, + int (*/*func*/)(void *, hx509_cert), + void */*ctx*/); + +int +hx509_query_match_friendly_name ( + hx509_query */*q*/, + const char */*name*/); + +int +hx509_query_match_issuer_serial ( + hx509_query */*q*/, + const Name */*issuer*/, + const heim_integer */*serialNumber*/); + +void +hx509_query_match_option ( + hx509_query */*q*/, + hx509_query_option /*option*/); + +int +hx509_revoke_add_crl ( + hx509_context /*context*/, + hx509_revoke_ctx /*ctx*/, + const char */*path*/); + +int +hx509_revoke_add_ocsp ( + hx509_context /*context*/, + hx509_revoke_ctx /*ctx*/, + const char */*path*/); + +void +hx509_revoke_free (hx509_revoke_ctx */*ctx*/); + +int +hx509_revoke_init ( + hx509_context /*context*/, + hx509_revoke_ctx */*ctx*/); + +int +hx509_revoke_ocsp_print ( + hx509_context /*context*/, + const char */*path*/, + FILE */*out*/); + +int +hx509_revoke_verify ( + hx509_context /*context*/, + hx509_revoke_ctx /*ctx*/, + hx509_certs /*certs*/, + time_t /*now*/, + hx509_cert /*cert*/, + hx509_cert /*parent_cert*/); + +void +hx509_set_error_string ( + hx509_context /*context*/, + int /*flags*/, + int /*code*/, + const char */*fmt*/, + ...); + +void +hx509_set_error_stringv ( + hx509_context /*context*/, + int /*flags*/, + int /*code*/, + const char */*fmt*/, + va_list /*ap*/); + +const AlgorithmIdentifier * +hx509_signature_md2 (void); + +const AlgorithmIdentifier * +hx509_signature_md5 (void); + +const AlgorithmIdentifier * +hx509_signature_rsa (void); + +const AlgorithmIdentifier * +hx509_signature_rsa_with_md2 (void); + +const AlgorithmIdentifier * +hx509_signature_rsa_with_md5 (void); + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha1 (void); + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha256 (void); + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha384 (void); + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha512 (void); + +const AlgorithmIdentifier * +hx509_signature_sha1 (void); + +const AlgorithmIdentifier * +hx509_signature_sha256 (void); + +const AlgorithmIdentifier * +hx509_signature_sha384 (void); + +const AlgorithmIdentifier * +hx509_signature_sha512 (void); + +int +hx509_unparse_der_name ( + const void */*data*/, + size_t /*length*/, + char **/*str*/); + +int +hx509_validate_cert ( + hx509_context /*context*/, + hx509_validate_ctx /*ctx*/, + hx509_cert /*cert*/); + +void +hx509_validate_ctx_add_flags ( + hx509_validate_ctx /*ctx*/, + int /*flags*/); + +void +hx509_validate_ctx_free (hx509_validate_ctx /*ctx*/); + +int +hx509_validate_ctx_init ( + hx509_context /*context*/, + hx509_validate_ctx */*ctx*/); + +void +hx509_validate_ctx_set_print ( + hx509_validate_ctx /*ctx*/, + hx509_vprint_func /*func*/, + void */*c*/); + +void +hx509_verify_attach_anchors ( + hx509_verify_ctx /*ctx*/, + hx509_certs /*set*/); + +void +hx509_verify_attach_revoke ( + hx509_verify_ctx /*ctx*/, + hx509_revoke_ctx /*revoke_ctx*/); + +void +hx509_verify_destroy_ctx (hx509_verify_ctx /*ctx*/); + +int +hx509_verify_hostname ( + hx509_context /*context*/, + const hx509_cert /*cert*/, + int /*require_match*/, + const char */*hostname*/, + const struct sockaddr */*sa*/, + int /*sa_size*/); + +int +hx509_verify_init_ctx ( + hx509_context /*context*/, + hx509_verify_ctx */*ctx*/); + +int +hx509_verify_path ( + hx509_context /*context*/, + hx509_verify_ctx /*ctx*/, + hx509_cert /*cert*/, + hx509_certs /*pool*/); + +void +hx509_verify_set_proxy_certificate ( + hx509_verify_ctx /*ctx*/, + int /*boolean*/); + +void +hx509_verify_set_strict_rfc3280_verification ( + hx509_verify_ctx /*ctx*/, + int /*boolean*/); + +void +hx509_verify_set_time ( + hx509_verify_ctx /*ctx*/, + time_t /*t*/); + +int +hx509_verify_signature ( + hx509_context /*context*/, + const hx509_cert /*signer*/, + const AlgorithmIdentifier */*alg*/, + const heim_octet_string */*data*/, + const heim_octet_string */*sig*/); + +#ifdef __cplusplus +} +#endif + +#endif /* __hx509_protos_h__ */ diff --git a/source4/heimdal/lib/hx509/hx509.h b/source4/heimdal/lib/hx509/hx509.h new file mode 100644 index 0000000000..70f29ea92d --- /dev/null +++ b/source4/heimdal/lib/hx509/hx509.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: hx509.h,v 1.16 2007/01/09 10:52:05 lha Exp $ */ + +typedef struct hx509_cert_attribute_data *hx509_cert_attribute; +typedef struct hx509_cert_data *hx509_cert; +typedef struct hx509_certs_data *hx509_certs; +typedef struct hx509_context_data *hx509_context; +typedef struct hx509_crypto_data *hx509_crypto; +typedef struct hx509_lock_data *hx509_lock; +typedef struct hx509_name_data *hx509_name; +typedef struct hx509_private_key *hx509_private_key; +typedef struct hx509_validate_ctx_data *hx509_validate_ctx; +typedef struct hx509_verify_ctx_data *hx509_verify_ctx; +typedef struct hx509_revoke_ctx_data *hx509_revoke_ctx; +typedef struct hx509_query_data hx509_query; +typedef void * hx509_cursor; +typedef struct hx509_request_data *hx509_request; +typedef struct hx509_error_data *hx509_error; +typedef struct hx509_peer_info *hx509_peer_info; +typedef struct hx509_ca_tbs *hx509_ca_tbs; + +typedef void (*hx509_vprint_func)(void *, const char *, va_list); + +enum { + HX509_VALIDATE_F_VALIDATE = 1, + HX509_VALIDATE_F_VERBOSE = 2 +}; + +struct hx509_cert_attribute_data { + heim_oid oid; + heim_octet_string data; +}; + +typedef enum { + HX509_PROMPT_TYPE_PASSWORD = 0x1, /* password, hidden */ + HX509_PROMPT_TYPE_QUESTION = 0x2, /* question, not hidden */ + HX509_PROMPT_TYPE_INFO = 0x4 /* infomation, reply doesn't matter */ +} hx509_prompt_type; + +typedef struct hx509_prompt { + const char *prompt; + hx509_prompt_type type; + heim_octet_string reply; +} hx509_prompt; + +typedef int (*hx509_prompter_fct)(void *, const hx509_prompt *); + +typedef struct hx509_octet_string_list { + size_t len; + heim_octet_string *val; +} hx509_octet_string_list; + +/* + * Options passed to hx509_query_match_option. + */ +typedef enum { + HX509_QUERY_OPTION_PRIVATE_KEY = 1, + HX509_QUERY_OPTION_KU_ENCIPHERMENT = 2, + HX509_QUERY_OPTION_KU_DIGITALSIGNATURE = 3, + HX509_QUERY_OPTION_KU_KEYCERTSIGN = 4, + HX509_QUERY_OPTION_END = 0xffff +} hx509_query_option; + +/* flags to hx509_certs_init */ +#define HX509_CERTS_CREATE 0x01 + +/* flags to hx509_set_error_string */ +#define HX509_ERROR_APPEND 0x01 + +/* flags to hx509_cms_unenvelope */ +#define HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT 0x01 + +/* selectors passed to hx509_crypto_select and hx509_crypto_available */ +#define HX509_SELECT_ALL 0 +#define HX509_SELECT_DIGEST 1 +#define HX509_SELECT_PUBLIC_SIG 2 +#define HX509_SELECT_PUBLIC_ENC 3 + +#include <hx509-protos.h> diff --git a/source4/heimdal/lib/hx509/hx509_err.c b/source4/heimdal/lib/hx509/hx509_err.c new file mode 100644 index 0000000000..339759d6b7 --- /dev/null +++ b/source4/heimdal/lib/hx509/hx509_err.c @@ -0,0 +1,157 @@ +/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/hx509_err.et */ +/* $Id: hx509_err.et,v 1.19 2006/12/30 23:05:39 lha Exp $ */ + +#include <stddef.h> +#include <com_err.h> +#include "hx509_err.h" + +static const char *hx_error_strings[] = { + /* 000 */ "ASN.1 failed call to system time library", + /* 001 */ "Extension not found", + /* 002 */ "Certification path not found", + /* 003 */ "Parent certificate is not a CA", + /* 004 */ "CA path too deep", + /* 005 */ "Signature algorithm not supported", + /* 006 */ "Signature algorithm doesn't match certificate key", + /* 007 */ "Certificate used before it became valid", + /* 008 */ "Certificate used after it became invalid", + /* 009 */ "Private key required for the operation is missing", + /* 010 */ "Algorithm not supported", + /* 011 */ "Issuer couldn't be found", + /* 012 */ "Error verifing constraints", + /* 013 */ "Number too large", + /* 014 */ "Error while verifing name constraints", + /* 015 */ "Path is too long, failed to find valid anchor", + /* 016 */ "Required keyusage for this certificate is missing", + /* 017 */ "Certificate not found", + /* 018 */ "Unknown lock command", + /* 019 */ "Parent certificate is a CA", + /* 020 */ "Extra data was found after the structure", + /* 021 */ "Proxy certificate is invalid", + /* 022 */ "Proxy certificate name is wrong", + /* 023 */ "Name is malformated", + /* 024 */ "Certificate is malformated", + /* 025 */ "Certificate is missing a required EKU", + /* 026 */ "Proxy certificate not canonicalize", + /* 027 */ "Reserved hx error (27)", + /* 028 */ "Reserved hx error (28)", + /* 029 */ "Reserved hx error (29)", + /* 030 */ "Reserved hx error (30)", + /* 031 */ "Reserved hx error (31)", + /* 032 */ "Failed to create signature", + /* 033 */ "Missing signer data", + /* 034 */ "Couldn't find signers certificate", + /* 035 */ "No data to perform the operation on", + /* 036 */ "Data in the message is invalid", + /* 037 */ "Padding in the message invalid", + /* 038 */ "Couldn't find recipient certificate", + /* 039 */ "Mismatch bewteen signed type and unsigned type", + /* 040 */ "Reserved hx error (40)", + /* 041 */ "Reserved hx error (41)", + /* 042 */ "Reserved hx error (42)", + /* 043 */ "Reserved hx error (43)", + /* 044 */ "Reserved hx error (44)", + /* 045 */ "Reserved hx error (45)", + /* 046 */ "Reserved hx error (46)", + /* 047 */ "Reserved hx error (47)", + /* 048 */ "Reserved hx error (48)", + /* 049 */ "Reserved hx error (49)", + /* 050 */ "Reserved hx error (50)", + /* 051 */ "Reserved hx error (51)", + /* 052 */ "Reserved hx error (52)", + /* 053 */ "Reserved hx error (53)", + /* 054 */ "Reserved hx error (54)", + /* 055 */ "Reserved hx error (55)", + /* 056 */ "Reserved hx error (56)", + /* 057 */ "Reserved hx error (57)", + /* 058 */ "Reserved hx error (58)", + /* 059 */ "Reserved hx error (59)", + /* 060 */ "Reserved hx error (60)", + /* 061 */ "Reserved hx error (61)", + /* 062 */ "Reserved hx error (62)", + /* 063 */ "Reserved hx error (63)", + /* 064 */ "Internal error in the crypto engine", + /* 065 */ "External error in the crypto engine", + /* 066 */ "Signature missing for data", + /* 067 */ "Signature is not valid", + /* 068 */ "Sigature doesn't provide confidentiality", + /* 069 */ "Invalid format on signature", + /* 070 */ "Mismatch bewteen oids", + /* 071 */ "No prompter function defined", + /* 072 */ "Signature require signer, but non available", + /* 073 */ "RSA public encyption failed", + /* 074 */ "RSA public encyption failed", + /* 075 */ "RSA private decryption failed", + /* 076 */ "RSA private decryption failed", + /* 077 */ "Reserved hx error (77)", + /* 078 */ "Reserved hx error (78)", + /* 079 */ "Reserved hx error (79)", + /* 080 */ "Reserved hx error (80)", + /* 081 */ "Reserved hx error (81)", + /* 082 */ "Reserved hx error (82)", + /* 083 */ "Reserved hx error (83)", + /* 084 */ "Reserved hx error (84)", + /* 085 */ "Reserved hx error (85)", + /* 086 */ "Reserved hx error (86)", + /* 087 */ "Reserved hx error (87)", + /* 088 */ "Reserved hx error (88)", + /* 089 */ "Reserved hx error (89)", + /* 090 */ "Reserved hx error (90)", + /* 091 */ "Reserved hx error (91)", + /* 092 */ "Reserved hx error (92)", + /* 093 */ "Reserved hx error (93)", + /* 094 */ "Reserved hx error (94)", + /* 095 */ "Reserved hx error (95)", + /* 096 */ "CRL used before it became valid", + /* 097 */ "CRL used after it became invalid", + /* 098 */ "CRL have invalid format", + /* 099 */ "Certificate is included in CRL", + /* 100 */ "No revoke status found for certificates", + /* 101 */ "Unknown extension", + /* 102 */ "Got wrong CRL/OCSP data from server", + /* 103 */ "Doesn't have same parent as other certificaes", + /* 104 */ "Reserved hx error (104)", + /* 105 */ "Reserved hx error (105)", + /* 106 */ "Reserved hx error (106)", + /* 107 */ "Reserved hx error (107)", + /* 108 */ "No local key attribute", + /* 109 */ "Failed to parse key", + /* 110 */ "Unsupported operation", + /* 111 */ "Unimplemented operation", + /* 112 */ "Failed to parse name", + /* 113 */ "Reserved hx error (113)", + /* 114 */ "Reserved hx error (114)", + /* 115 */ "Reserved hx error (115)", + /* 116 */ "Reserved hx error (116)", + /* 117 */ "Reserved hx error (117)", + /* 118 */ "Reserved hx error (118)", + /* 119 */ "Reserved hx error (119)", + /* 120 */ "Reserved hx error (120)", + /* 121 */ "Reserved hx error (121)", + /* 122 */ "Reserved hx error (122)", + /* 123 */ "Reserved hx error (123)", + /* 124 */ "Reserved hx error (124)", + /* 125 */ "Reserved hx error (125)", + /* 126 */ "Reserved hx error (126)", + /* 127 */ "Reserved hx error (127)", + /* 128 */ "No smartcard reader/device found", + /* 129 */ "No smartcard in reader", + /* 130 */ "No supported mech(s)", + /* 131 */ "Token or slot failed in inconsistent way", + /* 132 */ "Failed to open session to slot", + /* 133 */ "Failed to login to slot", + /* 134 */ "Failed to load PKCS module", + NULL +}; + +#define num_errors 135 + +void initialize_hx_error_table_r(struct et_list **list) +{ + initialize_error_table_r(list, hx_error_strings, num_errors, ERROR_TABLE_BASE_hx); +} + +void initialize_hx_error_table(void) +{ + init_error_table(hx_error_strings, ERROR_TABLE_BASE_hx, num_errors); +} diff --git a/source4/heimdal/lib/hx509/hx509_err.et b/source4/heimdal/lib/hx509/hx509_err.et new file mode 100644 index 0000000000..54ec177e47 --- /dev/null +++ b/source4/heimdal/lib/hx509/hx509_err.et @@ -0,0 +1,100 @@ +# +# Error messages for the hx509 library +# +# This might look like a com_err file, but is not +# +id "$Id: hx509_err.et,v 1.19 2006/12/30 23:05:39 lha Exp $" + +error_table hx +prefix HX509 + +# path validateion and construction related errors +error_code BAD_TIMEFORMAT, "ASN.1 failed call to system time library" +error_code EXTENSION_NOT_FOUND, "Extension not found" +error_code NO_PATH, "Certification path not found" +error_code PARENT_NOT_CA, "Parent certificate is not a CA" +error_code CA_PATH_TOO_DEEP, "CA path too deep" +error_code SIG_ALG_NO_SUPPORTED, "Signature algorithm not supported" +error_code SIG_ALG_DONT_MATCH_KEY_ALG, "Signature algorithm doesn't match certificate key" +error_code CERT_USED_BEFORE_TIME, "Certificate used before it became valid" +error_code CERT_USED_AFTER_TIME, "Certificate used after it became invalid" +error_code PRIVATE_KEY_MISSING, "Private key required for the operation is missing" +error_code ALG_NOT_SUPP, "Algorithm not supported" +error_code ISSUER_NOT_FOUND, "Issuer couldn't be found" +error_code VERIFY_CONSTRAINTS, "Error verifing constraints" +error_code RANGE, "Number too large" +error_code NAME_CONSTRAINT_ERROR, "Error while verifing name constraints" +error_code PATH_TOO_LONG, "Path is too long, failed to find valid anchor" +error_code KU_CERT_MISSING, "Required keyusage for this certificate is missing" +error_code CERT_NOT_FOUND, "Certificate not found" +error_code UNKNOWN_LOCK_COMMAND, "Unknown lock command" +error_code PARENT_IS_CA, "Parent certificate is a CA" +error_code EXTRA_DATA_AFTER_STRUCTURE, "Extra data was found after the structure" +error_code PROXY_CERT_INVALID, "Proxy certificate is invalid" +error_code PROXY_CERT_NAME_WRONG, "Proxy certificate name is wrong" +error_code NAME_MALFORMED, "Name is malformated" +error_code CERTIFICATE_MALFORMED, "Certificate is malformated" +error_code CERTIFICATE_MISSING_EKU, "Certificate is missing a required EKU" +error_code PROXY_CERTIFICATE_NOT_CANONICALIZED, "Proxy certificate not canonicalize" + +# cms related errors +index 32 +prefix HX509_CMS +error_code FAILED_CREATE_SIGATURE, "Failed to create signature" +error_code MISSING_SIGNER_DATA, "Missing signer data" +error_code SIGNER_NOT_FOUND, "Couldn't find signers certificate" +error_code NO_DATA_AVAILABLE, "No data to perform the operation on" +error_code INVALID_DATA, "Data in the message is invalid" +error_code PADDING_ERROR, "Padding in the message invalid" +error_code NO_RECIPIENT_CERTIFICATE, "Couldn't find recipient certificate" +error_code DATA_OID_MISMATCH, "Mismatch bewteen signed type and unsigned type" + +# crypto related errors +index 64 +prefix HX509_CRYPTO +error_code INTERNAL_ERROR, "Internal error in the crypto engine" +error_code EXTERNAL_ERROR, "External error in the crypto engine" +error_code SIGNATURE_MISSING, "Signature missing for data" +error_code BAD_SIGNATURE, "Signature is not valid" +error_code SIG_NO_CONF, "Sigature doesn't provide confidentiality" +error_code SIG_INVALID_FORMAT, "Invalid format on signature" +error_code OID_MISMATCH, "Mismatch bewteen oids" +error_code NO_PROMPTER, "No prompter function defined" +error_code SIGNATURE_WITHOUT_SIGNER, "Signature require signer, but non available" +error_code RSA_PUBLIC_ENCRYPT, "RSA public encyption failed" +error_code RSA_PRIVATE_ENCRYPT, "RSA public encyption failed" +error_code RSA_PUBLIC_DECRYPT, "RSA private decryption failed" +error_code RSA_PRIVATE_DECRYPT, "RSA private decryption failed" + +# revoke related errors +index 96 +prefix HX509 +error_code CRL_USED_BEFORE_TIME, "CRL used before it became valid" +error_code CRL_USED_AFTER_TIME, "CRL used after it became invalid" +error_code CRL_INVALID_FORMAT, "CRL have invalid format" +error_code CRL_CERT_REVOKED, "Certificate is included in CRL" +error_code REVOKE_STATUS_MISSING, "No revoke status found for certificates" +error_code CRL_UNKNOWN_EXTENSION, "Unknown extension" +error_code REVOKE_WRONG_DATA, "Got wrong CRL/OCSP data from server" +error_code REVOKE_NOT_SAME_PARENT, "Doesn't have same parent as other certificaes" + +# misc error +index 108 +error_code LOCAL_ATTRIBUTE_MISSING, "No local key attribute" +error_code PARSING_KEY_FAILED, "Failed to parse key" +error_code UNSUPPORTED_OPERATION, "Unsupported operation" +error_code UNIMPLEMENTED_OPERATION, "Unimplemented operation" +error_code PARSING_NAME_FAILED, "Failed to parse name" + +# keystore related error +index 128 +prefix HX509_PKCS11 +error_code NO_SLOT, "No smartcard reader/device found" +error_code NO_TOKEN, "No smartcard in reader" +error_code NO_MECH, "No supported mech(s)" +error_code TOKEN_CONFUSED, "Token or slot failed in inconsistent way" +error_code OPEN_SESSION, "Failed to open session to slot" +error_code LOGIN, "Failed to login to slot" +error_code LOAD, "Failed to load PKCS module" + +end diff --git a/source4/heimdal/lib/hx509/hx_locl.h b/source4/heimdal/lib/hx509/hx_locl.h new file mode 100644 index 0000000000..78d158f8b1 --- /dev/null +++ b/source4/heimdal/lib/hx509/hx_locl.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: hx_locl.h,v 1.30 2007/01/09 10:52:06 lha Exp $ */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <strings.h> +#include <assert.h> +#include <stdarg.h> +#include <err.h> +#include <getarg.h> +#include <base64.h> +#include <hex.h> +#include <roken.h> +#include <com_err.h> +#include <parse_units.h> +#include <parse_bytes.h> + +#include <krb5-types.h> + +#include <rfc2459_asn1.h> +#include <cms_asn1.h> +#include <pkcs8_asn1.h> +#include <pkcs9_asn1.h> +#include <pkcs12_asn1.h> +#include <ocsp_asn1.h> +#include <pkcs10_asn1.h> +#include <asn1_err.h> +#include <pkinit_asn1.h> + +#include <der.h> + +#include "crypto-headers.h" + +struct hx509_keyset_ops; +struct hx509_collector; +typedef struct hx509_path hx509_path; + +#include <hx509.h> + +typedef void (*_hx509_cert_release_func)(struct hx509_cert_data *, void *); + +typedef struct hx509_private_key_ops hx509_private_key_ops; + +#include <hx509-private.h> +#include <hx509_err.h> + +struct hx509_peer_info { + hx509_cert cert; + AlgorithmIdentifier *val; + size_t len; +}; + +#define HX509_CERTS_FIND_SERIALNUMBER 1 +#define HX509_CERTS_FIND_ISSUER 2 +#define HX509_CERTS_FIND_SUBJECT 4 +#define HX509_CERTS_FIND_ISSUER_KEY_ID 8 +#define HX509_CERTS_FIND_SUBJECT_KEY_ID 16 + +struct hx509_name_data { + Name der_name; +}; + +struct hx509_path { + size_t len; + hx509_cert *val; +}; + +struct hx509_query_data { + int match; +#define HX509_QUERY_FIND_ISSUER_CERT 0x000001 +#define HX509_QUERY_MATCH_SERIALNUMBER 0x000002 +#define HX509_QUERY_MATCH_ISSUER_NAME 0x000004 +#define HX509_QUERY_MATCH_SUBJECT_NAME 0x000008 +#define HX509_QUERY_MATCH_SUBJECT_KEY_ID 0x000010 +#define HX509_QUERY_MATCH_ISSUER_ID 0x000020 +#define HX509_QUERY_PRIVATE_KEY 0x000040 +#define HX509_QUERY_KU_ENCIPHERMENT 0x000080 +#define HX509_QUERY_KU_DIGITALSIGNATURE 0x000100 +#define HX509_QUERY_KU_KEYCERTSIGN 0x000200 +#define HX509_QUERY_KU_CRLSIGN 0x000400 +#define HX509_QUERY_KU_NONREPUDIATION 0x000800 +#define HX509_QUERY_KU_KEYAGREEMENT 0x001000 +#define HX509_QUERY_KU_DATAENCIPHERMENT 0x002000 +#define HX509_QUERY_ANCHOR 0x004000 +#define HX509_QUERY_MATCH_CERTIFICATE 0x008000 +#define HX509_QUERY_MATCH_LOCAL_KEY_ID 0x010000 +#define HX509_QUERY_NO_MATCH_PATH 0x020000 +#define HX509_QUERY_MATCH_FRIENDLY_NAME 0x040000 +#define HX509_QUERY_MATCH_FUNCTION 0x080000 +#define HX509_QUERY_MATCH_KEY_HASH_SHA1 0x100000 +#define HX509_QUERY_MATCH_TIME 0x200000 +#define HX509_QUERY_MASK 0x3fffff + Certificate *subject; + Certificate *certificate; + heim_integer *serial; + heim_octet_string *subject_id; + heim_octet_string *local_key_id; + Name *issuer_name; + Name *subject_name; + hx509_path *path; + char *friendlyname; + int (*cmp_func)(void *, hx509_cert); + void *cmp_func_ctx; + heim_octet_string *keyhash_sha1; + time_t timenow; +}; + +struct hx509_keyset_ops { + char *name; + int flags; + int (*init)(hx509_context, hx509_certs, void **, + int, const char *, hx509_lock); + int (*store)(hx509_context, hx509_certs, void *, int, hx509_lock); + int (*free)(hx509_certs, void *); + int (*add)(hx509_context, hx509_certs, void *, hx509_cert); + int (*query)(hx509_context, hx509_certs, void *, + const hx509_query *, hx509_cert *); + int (*iter_start)(hx509_context, hx509_certs, void *, void **); + int (*iter)(hx509_context, hx509_certs, void *, void *, hx509_cert *); + int (*iter_end)(hx509_context, hx509_certs, void *, void *); + int (*printinfo)(hx509_context, hx509_certs, + void *, int (*)(void *, char *), void *); + int (*getkeys)(hx509_context, hx509_certs, void *, hx509_private_key **); + int (*addkey)(hx509_context, hx509_certs, void *, hx509_private_key); +}; + +struct _hx509_password { + size_t len; + char **val; +}; + +extern hx509_lock _hx509_empty_lock; + +struct hx509_context_data { + struct hx509_keyset_ops **ks_ops; + int ks_num_ops; + int flags; +#define HX509_CTX_VERIFY_MISSING_OK 1 + int ocsp_time_diff; +#define HX509_DEFAULT_OCSP_TIME_DIFF (5*60) + hx509_error error; + struct et_list *et_list; +}; + +/* _hx509_calculate_path flag field */ +#define HX509_CALCULATE_PATH_NO_ANCHOR 1 diff --git a/source4/heimdal/lib/hx509/keyset.c b/source4/heimdal/lib/hx509/keyset.c new file mode 100644 index 0000000000..c3d5ee210c --- /dev/null +++ b/source4/heimdal/lib/hx509/keyset.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: keyset.c,v 1.18 2007/01/09 10:52:07 lha Exp $"); + +struct hx509_certs_data { + struct hx509_keyset_ops *ops; + void *ops_data; +}; + +static struct hx509_keyset_ops * +_hx509_ks_type(hx509_context context, const char *type) +{ + int i; + + for (i = 0; i < context->ks_num_ops; i++) + if (strcasecmp(type, context->ks_ops[i]->name) == 0) + return context->ks_ops[i]; + + return NULL; +} + +void +_hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops) +{ + struct hx509_keyset_ops **val; + + if (_hx509_ks_type(context, ops->name)) + return; + + val = realloc(context->ks_ops, + (context->ks_num_ops + 1) * sizeof(context->ks_ops[0])); + if (val == NULL) + return; + val[context->ks_num_ops] = ops; + context->ks_ops = val; + context->ks_num_ops++; +} + +int +hx509_certs_init(hx509_context context, + const char *name, int flags, + hx509_lock lock, hx509_certs *certs) +{ + struct hx509_keyset_ops *ops; + const char *residue; + hx509_certs c; + char *type; + int ret; + + *certs = NULL; + + residue = strchr(name, ':'); + if (residue) { + type = malloc(residue - name + 1); + if (type) + strlcpy(type, name, residue - name + 1); + residue++; + if (residue[0] == '\0') + residue = NULL; + } else { + type = strdup("MEMORY"); + residue = name; + } + if (type == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ops = _hx509_ks_type(context, type); + free(type); + if (ops == NULL) { + hx509_set_error_string(context, 0, ENOENT, + "Keyset type %s is not supported", type); + return ENOENT; + } + c = calloc(1, sizeof(*c)); + if (c == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + c->ops = ops; + + ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock); + if (ret) { + free(c); + return ret; + } + + *certs = c; + return 0; +} + +int +hx509_certs_store(hx509_context context, + hx509_certs certs, + int flags, + hx509_lock lock) +{ + if (certs->ops->store == NULL) { + hx509_set_error_string(context, 0, EINVAL, + "keystore if type %s doesn't support " + "store operation", + certs->ops->name); + return EINVAL; + } + + return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock); +} + + +void +hx509_certs_free(hx509_certs *certs) +{ + if (*certs) { + (*(*certs)->ops->free)(*certs, (*certs)->ops_data); + free(*certs); + *certs = NULL; + } +} + +int +hx509_certs_start_seq(hx509_context context, + hx509_certs certs, + hx509_cursor *cursor) +{ + int ret; + + if (certs->ops->iter_start == NULL) { + hx509_set_error_string(context, 0, ENOENT, + "Keyset type %s doesn't support iteration", + certs->ops->name); + return ENOENT; + } + + ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor); + if (ret) + return ret; + + return 0; +} + +int +hx509_certs_next_cert(hx509_context context, + hx509_certs certs, + hx509_cursor cursor, + hx509_cert *cert) +{ + *cert = NULL; + return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert); +} + +int +hx509_certs_end_seq(hx509_context context, + hx509_certs certs, + hx509_cursor cursor) +{ + (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor); + return 0; +} + + +int +hx509_certs_iter(hx509_context context, + hx509_certs certs, + int (*fn)(hx509_context, void *, hx509_cert), + void *ctx) +{ + hx509_cursor cursor; + hx509_cert c; + int ret; + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) { + ret = 0; + break; + } + ret = (*fn)(context, ctx, c); + hx509_cert_free(c); + if (ret) + break; + } + + hx509_certs_end_seq(context, certs, cursor); + + return ret; +} + +int +hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c) +{ + Certificate *cert; + hx509_name n; + char *s, *i; + + cert = _hx509_get_cert(c); + + _hx509_name_from_Name(&cert->tbsCertificate.subject, &n); + hx509_name_to_string(n, &s); + hx509_name_free(&n); + _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n); + hx509_name_to_string(n, &i); + hx509_name_free(&n); + fprintf(ctx, "subject: %s\nissuer: %s\n", s, i); + free(s); + free(i); + return 0; +} + +/* + * The receiving keyset `certs´ will either increase reference counter + * of the `cert´ or make a deep copy, either way, the caller needs to + * free the `cert´ itself. + */ + +int +hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert) +{ + if (certs->ops->add == NULL) { + hx509_set_error_string(context, 0, ENOENT, + "Keyset type %s doesn't support add operation", + certs->ops->name); + return ENOENT; + } + + return (*certs->ops->add)(context, certs, certs->ops_data, cert); +} + +int +hx509_certs_find(hx509_context context, + hx509_certs certs, + const hx509_query *q, + hx509_cert *r) +{ + hx509_cursor cursor; + hx509_cert c; + int ret; + + *r = NULL; + + if (certs->ops->query) + return (*certs->ops->query)(context, certs, certs->ops_data, q, r); + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + c = NULL; + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + if (_hx509_query_match_cert(context, q, c)) { + *r = c; + break; + } + hx509_cert_free(c); + } + + hx509_certs_end_seq(context, certs, cursor); + if (ret) + return ret; + if (c == NULL) { + hx509_clear_error_string(context); + return HX509_CERT_NOT_FOUND; + } + + return 0; +} + +static int +certs_merge_func(hx509_context context, void *ctx, hx509_cert c) +{ + return hx509_certs_add(context, (hx509_certs)ctx, c); +} + +int +hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from) +{ + return hx509_certs_iter(context, from, certs_merge_func, to); +} + +int +hx509_certs_append(hx509_context context, + hx509_certs to, + hx509_lock lock, + const char *name) +{ + hx509_certs s; + int ret; + + ret = hx509_certs_init(context, name, 0, lock, &s); + if (ret) + return ret; + ret = hx509_certs_merge(context, to, s); + hx509_certs_free(&s); + return ret; +} + +int +hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c) +{ + hx509_cursor cursor; + int ret; + + *c = NULL; + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + ret = hx509_certs_next_cert(context, certs, cursor, c); + if (ret) + return ret; + + hx509_certs_end_seq(context, certs, cursor); + return 0; +} + +static int +certs_info_stdio(void *ctx, char *str) +{ + FILE *f = ctx; + fprintf(f, "%s\n", str); + return 0; +} + +int +hx509_certs_info(hx509_context context, + hx509_certs certs, + int (*func)(void *, char *), + void *ctx) +{ + if (func == NULL) { + func = certs_info_stdio; + if (ctx == NULL) + ctx = stdout; + } + if (certs->ops->printinfo == NULL) { + (*func)(ctx, "No info function for certs"); + return 0; + } + return (*certs->ops->printinfo)(context, certs, certs->ops_data, + func, ctx); +} + +void +_hx509_pi_printf(int (*func)(void *, char *), void *ctx, + char *fmt, ...) +{ + va_list ap; + char *str; + + va_start(ap, fmt); + vasprintf(&str, fmt, ap); + va_end(ap); + if (str == NULL) + return; + (*func)(ctx, str); + free(str); +} + +int +_hx509_certs_keys_get(hx509_context context, + hx509_certs certs, + hx509_private_key **keys) +{ + if (certs->ops->getkeys == NULL) { + *keys = NULL; + return 0; + } + return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys); +} + +int +_hx509_certs_keys_add(hx509_context context, + hx509_certs certs, + hx509_private_key key) +{ + if (certs->ops->addkey == NULL) { + hx509_set_error_string(context, 0, EINVAL, + "keystore if type %s doesn't support " + "key add operation", + certs->ops->name); + return EINVAL; + } + return (*certs->ops->addkey)(context, certs, certs->ops_data, key); +} + + +void +_hx509_certs_keys_free(hx509_context context, + hx509_private_key *keys) +{ + int i; + for (i = 0; keys[i]; i++) + _hx509_private_key_free(&keys[i]); + free(keys); +} diff --git a/source4/heimdal/lib/hx509/ks_dir.c b/source4/heimdal/lib/hx509/ks_dir.c new file mode 100644 index 0000000000..01dcf5795b --- /dev/null +++ b/source4/heimdal/lib/hx509/ks_dir.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: ks_dir.c,v 1.7 2007/01/09 10:52:08 lha Exp $"); +#include <dirent.h> + +/* + * The DIR keyset module is strange compared to the other modules + * since it does lazy evaluation and really doesn't keep any local + * state except for the directory iteration and cert iteration of + * files. DIR ignores most errors so that the consumer doesn't get + * failes for stray files in directories. + */ + +struct dircursor { + DIR *dir; + hx509_certs certs; + void *iter; +}; + +/* + * + */ + +static int +dir_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + *data = NULL; + + { + struct stat sb; + int ret; + + ret = stat(residue, &sb); + if (ret == -1) { + hx509_set_error_string(context, 0, ENOENT, + "No such file %s", residue); + return ENOENT; + } + + if ((sb.st_mode & S_IFDIR) == 0) { + hx509_set_error_string(context, 0, ENOTDIR, + "%s is not a directory", residue); + return ENOTDIR; + } + } + + *data = strdup(residue); + if (*data == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + return 0; +} + +static int +dir_free(hx509_certs certs, void *data) +{ + free(data); + return 0; +} + + + +static int +dir_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct dircursor *d; + + *cursor = NULL; + + d = calloc(1, sizeof(*d)); + if (d == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + d->dir = opendir(data); + if (d->dir == NULL) { + hx509_clear_error_string(context); + free(d); + return errno; + } + d->certs = NULL; + d->iter = NULL; + + *cursor = d; + return 0; +} + +static int +dir_iter(hx509_context context, + hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + struct dircursor *d = iter; + int ret = 0; + + *cert = NULL; + + do { + struct dirent *dir; + char *fn; + + if (d->certs) { + ret = hx509_certs_next_cert(context, d->certs, d->iter, cert); + if (ret) { + hx509_certs_end_seq(context, d->certs, d->iter); + d->iter = NULL; + hx509_certs_free(&d->certs); + return ret; + } + if (*cert) { + ret = 0; + break; + } + hx509_certs_end_seq(context, d->certs, d->iter); + d->iter = NULL; + hx509_certs_free(&d->certs); + } + + dir = readdir(d->dir); + if (dir == NULL) { + ret = 0; + break; + } + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) + continue; + + if (asprintf(&fn, "FILE:%s/%s", (char *)data, dir->d_name) == -1) + return ENOMEM; + + ret = hx509_certs_init(context, fn, 0, NULL, &d->certs); + if (ret == 0) { + + ret = hx509_certs_start_seq(context, d->certs, &d->iter); + if (ret) + hx509_certs_free(&d->certs); + } + /* ignore errors */ + if (ret) { + d->certs = NULL; + ret = 0; + } + + free(fn); + } while(ret == 0); + + return ret; +} + + +static int +dir_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct dircursor *d = cursor; + + if (d->certs) { + hx509_certs_end_seq(context, d->certs, d->iter); + d->iter = NULL; + hx509_certs_free(&d->certs); + } + closedir(d->dir); + free(d); + return 0; +} + + +static struct hx509_keyset_ops keyset_dir = { + "DIR", + 0, + dir_init, + NULL, + dir_free, + NULL, + NULL, + dir_iter_start, + dir_iter, + dir_iter_end +}; + +void +_hx509_ks_dir_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_dir); +} diff --git a/source4/heimdal/lib/hx509/ks_file.c b/source4/heimdal/lib/hx509/ks_file.c new file mode 100644 index 0000000000..db0f475129 --- /dev/null +++ b/source4/heimdal/lib/hx509/ks_file.c @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: ks_file.c,v 1.31 2007/01/09 10:52:08 lha Exp $"); + +struct ks_file { + hx509_certs certs; + char *fn; +}; + +struct header { + char *header; + char *value; + struct header *next; +}; + +static int +add_headers(struct header **headers, const char *header, const char *value) +{ + struct header *h; + h = calloc(1, sizeof(*h)); + if (h == NULL) + return ENOMEM; + h->header = strdup(header); + if (h->header == NULL) { + free(h); + return ENOMEM; + } + h->value = strdup(value); + if (h->value == NULL) { + free(h->header); + free(h); + return ENOMEM; + } + + h->next = *headers; + *headers = h; + + return 0; +} + +static void +free_headers(struct header *headers) +{ + struct header *h; + while (headers) { + h = headers; + headers = headers->next; + free(h->header); + free(h->value); + free(h); + } +} + +static const char * +find_header(const struct header *headers, const char *header) +{ + while(headers) { + if (strcmp(header, headers->header) == 0) + return headers->value; + headers = headers->next; + } + return NULL; +} + +/* + * + */ + +static int +parse_certificate(hx509_context context, const char *fn, + struct hx509_collector *c, + const struct header *headers, + const void *data, size_t len) +{ + hx509_cert cert; + Certificate t; + size_t size; + int ret; + + ret = decode_Certificate(data, len, &t, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to parse certificate in %s", + fn); + return ret; + } + + ret = hx509_cert_init(context, &t, &cert); + free_Certificate(&t); + if (ret) + return ret; + + ret = _hx509_collector_certs_add(context, c, cert); + hx509_cert_free(cert); + return ret; +} + +static int +try_decrypt(hx509_context context, + struct hx509_collector *collector, + const AlgorithmIdentifier *alg, + const EVP_CIPHER *c, + const void *ivdata, + const void *password, + size_t passwordlen, + const void *cipher, + size_t len) +{ + heim_octet_string clear; + size_t keylen; + void *key; + int ret; + + keylen = EVP_CIPHER_key_length(c); + + key = malloc(keylen); + if (key == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ret = EVP_BytesToKey(c, EVP_md5(), ivdata, + password, passwordlen, + 1, key, NULL); + if (ret <= 0) { + hx509_set_error_string(context, 0, HX509_CRYPTO_INTERNAL_ERROR, + "Failed to do string2key for private key"); + return HX509_CRYPTO_INTERNAL_ERROR; + } + + clear.data = malloc(len); + if (clear.data == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "Out of memory to decrypt for private key"); + ret = ENOMEM; + goto out; + } + clear.length = len; + + { + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_CipherInit_ex(&ctx, c, NULL, key, ivdata, 0); + EVP_Cipher(&ctx, clear.data, cipher, len); + EVP_CIPHER_CTX_cleanup(&ctx); + } + + ret = _hx509_collector_private_key_add(context, + collector, + alg, + NULL, + &clear, + NULL); + + memset(clear.data, 0, clear.length); + free(clear.data); +out: + memset(key, 0, keylen); + free(key); + return ret; +} + +static int +parse_rsa_private_key(hx509_context context, const char *fn, + struct hx509_collector *c, + const struct header *headers, + const void *data, size_t len) +{ + int ret = 0; + const char *enc; + + enc = find_header(headers, "Proc-Type"); + if (enc) { + const char *dek; + char *type, *iv; + ssize_t ssize, size; + void *ivdata; + const EVP_CIPHER *cipher; + const struct _hx509_password *pw; + hx509_lock lock; + int i, decrypted = 0; + + lock = _hx509_collector_get_lock(c); + if (lock == NULL) { + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "Failed to get password for " + "password protected file %s", fn); + return HX509_ALG_NOT_SUPP; + } + + if (strcmp(enc, "4,ENCRYPTED") != 0) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "RSA key encrypted in unknown method %s " + "in file", + enc, fn); + hx509_clear_error_string(context); + return HX509_PARSING_KEY_FAILED; + } + + dek = find_header(headers, "DEK-Info"); + if (dek == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Encrypted RSA missing DEK-Info"); + return HX509_PARSING_KEY_FAILED; + } + + type = strdup(dek); + if (type == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + iv = strchr(type, ','); + if (iv) + *iv++ = '\0'; + + size = strlen(iv); + ivdata = malloc(size); + if (ivdata == NULL) { + hx509_clear_error_string(context); + free(type); + return ENOMEM; + } + + cipher = EVP_get_cipherbyname(type); + if (cipher == NULL) { + free(ivdata); + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "RSA key encrypted with " + "unsupported cipher: %s", + type); + free(type); + return HX509_ALG_NOT_SUPP; + } + +#define PKCS5_SALT_LEN 8 + + ssize = hex_decode(iv, ivdata, size); + free(type); + type = NULL; + iv = NULL; + + if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) { + free(ivdata); + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Salt have wrong length in RSA key file"); + return HX509_PARSING_KEY_FAILED; + } + + pw = _hx509_lock_get_passwords(lock); + if (pw != NULL) { + const void *password; + size_t passwordlen; + + for (i = 0; i < pw->len; i++) { + password = pw->val[i]; + passwordlen = strlen(password); + + ret = try_decrypt(context, c, hx509_signature_rsa(), + cipher, ivdata, password, passwordlen, + data, len); + if (ret == 0) { + decrypted = 1; + break; + } + } + } + if (!decrypted) { + hx509_prompt prompt; + char password[128]; + + memset(&prompt, 0, sizeof(prompt)); + + prompt.prompt = "Password for keyfile: "; + prompt.type = HX509_PROMPT_TYPE_PASSWORD; + prompt.reply.data = password; + prompt.reply.length = sizeof(password); + + ret = hx509_lock_prompt(lock, &prompt); + if (ret == 0) + ret = try_decrypt(context, c, hx509_signature_rsa(), + cipher, ivdata, password, strlen(password), + data, len); + /* XXX add password to lock password collection ? */ + memset(password, 0, sizeof(password)); + } + free(ivdata); + + } else { + heim_octet_string keydata; + + keydata.data = rk_UNCONST(data); + keydata.length = len; + + ret = _hx509_collector_private_key_add(context, + c, + hx509_signature_rsa(), + NULL, + &keydata, + NULL); + } + + return ret; +} + + +struct pem_formats { + const char *name; + int (*func)(hx509_context, const char *, struct hx509_collector *, + const struct header *, const void *, size_t); +} formats[] = { + { "CERTIFICATE", parse_certificate }, + { "RSA PRIVATE KEY", parse_rsa_private_key } +}; + + +static int +parse_pem_file(hx509_context context, + const char *fn, + struct hx509_collector *c, + int *found_data) +{ + struct header *headers = NULL; + char *type = NULL; + void *data = NULL; + size_t len = 0; + char buf[1024]; + int ret; + FILE *f; + + + enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; + + where = BEFORE; + *found_data = 0; + + if ((f = fopen(fn, "r")) == NULL) { + hx509_set_error_string(context, 0, ENOENT, + "Failed to open PEM file \"%s\": %s", + fn, strerror(errno)); + return ENOENT; + } + ret = 0; + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p; + int i; + + i = strcspn(buf, "\n"); + if (buf[i] == '\n') { + buf[i] = '\0'; + if (i > 0) + i--; + } + if (buf[i] == '\r') { + buf[i] = '\0'; + if (i > 0) + i--; + } + + switch (where) { + case BEFORE: + if (strncmp("-----BEGIN ", buf, 11) == 0) { + type = strdup(buf + 11); + if (type == NULL) + break; + p = strchr(type, '-'); + if (p) + *p = '\0'; + *found_data = 1; + where = SEARCHHEADER; + } + break; + case SEARCHHEADER: + p = strchr(buf, ':'); + if (p == NULL) { + where = INDATA; + goto indata; + } + /* FALLTHOUGH */ + case INHEADER: + if (buf[0] == '\0') { + where = INDATA; + break; + } + p = strchr(buf, ':'); + if (p) { + *p++ = '\0'; + while (isspace((int)*p)) + p++; + add_headers(&headers, buf, p); + } + break; + case INDATA: + indata: + + if (strncmp("-----END ", buf, 9) == 0) { + where = DONE; + break; + } + + p = emalloc(i); + i = base64_decode(buf, p); + if (i < 0) { + free(p); + goto out; + } + + data = erealloc(data, len + i); + memcpy(((char *)data) + len, p, i); + free(p); + len += i; + break; + case DONE: + abort(); + } + + if (where == DONE) { + int j; + + for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) { + const char *q = formats[j].name; + if (strcasecmp(type, q) == 0) { + ret = (*formats[j].func)(context, fn, c, + headers, data, len); + break; + } + } + if (j == sizeof(formats)/sizeof(formats[0])) { + ret = HX509_UNSUPPORTED_OPERATION; + hx509_set_error_string(context, 0, ret, + "Found no matching PEM format for %s", + type); + } + out: + free(data); + data = NULL; + len = 0; + free(type); + type = NULL; + where = BEFORE; + free_headers(headers); + headers = NULL; + if (ret) + break; + } + } + + fclose(f); + + if (where != BEFORE) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "File ends before end of PEM end tag"); + ret = HX509_PARSING_KEY_FAILED; + } + if (data) + free(data); + if (type) + free(type); + if (headers) + free_headers(headers); + + return ret; +} + +/* + * + */ + +static int +file_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + char *p, *pnext; + struct ks_file *f = NULL; + struct hx509_collector *c = NULL; + hx509_private_key *keys = NULL; + int ret; + + *data = NULL; + + if (lock == NULL) + lock = _hx509_empty_lock; + + f = calloc(1, sizeof(*f)); + if (f == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + f->fn = strdup(residue); + if (f->fn == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + /* + * XXX this is broken, the function should parse the file before + * overwriting it + */ + + if (flags & HX509_CERTS_CREATE) { + ret = hx509_certs_init(context, "MEMORY:ks-file-create", + 0, lock, &f->certs); + if (ret) + goto out; + *data = f; + return 0; + } + + c = _hx509_collector_alloc(context, lock); + if (c == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + for (p = f->fn; p != NULL; p = pnext) { + int found_data; + + pnext = strchr(p, ','); + if (pnext) + *pnext++ = '\0'; + + ret = parse_pem_file(context, p, c, &found_data); + if (ret) + goto out; + + if (!found_data) { + size_t length; + void *ptr; + int i; + + ret = _hx509_map_file(p, &ptr, &length, NULL); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { + ret = (*formats[i].func)(context, p, c, NULL, ptr, length); + if (ret == 0) + break; + } + _hx509_unmap_file(ptr, length); + if (ret) + goto out; + } + } + + ret = _hx509_collector_collect_certs(context, c, &f->certs); + if (ret) + goto out; + + ret = _hx509_collector_collect_private_keys(context, c, &keys); + if (ret == 0) { + int i; + + for (i = 0; keys[i]; i++) + _hx509_certs_keys_add(context, f->certs, keys[i]); + _hx509_certs_keys_free(context, keys); + } + +out: + if (ret == 0) + *data = f; + else { + if (f->fn) + free(f->fn); + free(f); + } + if (c) + _hx509_collector_free(c); + return ret; +} + +static int +file_free(hx509_certs certs, void *data) +{ + struct ks_file *f = data; + hx509_certs_free(&f->certs); + free(f->fn); + free(f); + return 0; +} + +static void +pem_header(FILE *f, const char *type, const char *str) +{ + fprintf(f, "-----%s %s-----\n", type, str); +} + +static int +dump_pem_file(hx509_context context, const char *header, + FILE *f, const void *data, size_t size) +{ + const char *p = data; + size_t length; + char *line; + +#define ENCODE_LINE_LENGTH 54 + + pem_header(f, "BEGIN", header); + + while (size > 0) { + ssize_t l; + + length = size; + if (length > ENCODE_LINE_LENGTH) + length = ENCODE_LINE_LENGTH; + + l = base64_encode(p, length, &line); + if (l < 0) { + hx509_set_error_string(context, 0, ENOMEM, + "malloc - out of memory"); + return ENOMEM; + } + size -= length; + fprintf(f, "%s\n", line); + p += length; + free(line); + } + + pem_header(f, "END", header); + + return 0; +} + +static int +store_private_key(hx509_context context, FILE *f, hx509_private_key key) +{ + heim_octet_string data; + int ret; + + ret = _hx509_private_key_export(context, key, &data); + if (ret == 0) + dump_pem_file(context, _hx509_private_pem_name(key), f, + data.data, data.length); + free(data.data); + return ret; +} + +static int +store_func(hx509_context context, void *ctx, hx509_cert c) +{ + FILE *f = (FILE *)ctx; + size_t size; + heim_octet_string data; + int ret; + + ASN1_MALLOC_ENCODE(Certificate, data.data, data.length, + _hx509_get_cert(c), &size, ret); + if (ret) + return ret; + if (data.length != size) + _hx509_abort("internal ASN.1 encoder error"); + + dump_pem_file(context, "CERTIFICATE", f, data.data, data.length); + free(data.data); + + if (_hx509_cert_private_key_exportable(c)) + store_private_key(context, f, _hx509_cert_private_key(c)); + + return 0; +} + +static int +file_store(hx509_context context, + hx509_certs certs, void *data, int flags, hx509_lock lock) +{ + struct ks_file *f = data; + FILE *fh; + int ret; + + fh = fopen(f->fn, "w"); + if (fh == NULL) { + hx509_set_error_string(context, 0, ENOENT, + "Failed to open file %s for writing"); + return ENOENT; + } + + ret = hx509_certs_iter(context, f->certs, store_func, fh); + fclose(fh); + return ret; +} + +static int +file_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c) +{ + struct ks_file *f = data; + return hx509_certs_add(context, f->certs, c); +} + +static int +file_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct ks_file *f = data; + return hx509_certs_start_seq(context, f->certs, cursor); +} + +static int +file_iter(hx509_context context, + hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + struct ks_file *f = data; + return hx509_certs_next_cert(context, f->certs, iter, cert); +} + +static int +file_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct ks_file *f = data; + return hx509_certs_end_seq(context, f->certs, cursor); +} + +static int +file_getkeys(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key **keys) +{ + struct ks_file *f = data; + return _hx509_certs_keys_get(context, f->certs, keys); +} + +static int +file_addkey(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key key) +{ + struct ks_file *f = data; + return _hx509_certs_keys_add(context, f->certs, key); +} + +static struct hx509_keyset_ops keyset_file = { + "FILE", + 0, + file_init, + file_store, + file_free, + file_add, + NULL, + file_iter_start, + file_iter, + file_iter_end, + NULL, + file_getkeys, + file_addkey +}; + +void +_hx509_ks_file_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_file); +} diff --git a/source4/heimdal/lib/hx509/ks_mem.c b/source4/heimdal/lib/hx509/ks_mem.c new file mode 100644 index 0000000000..dd7b7166bc --- /dev/null +++ b/source4/heimdal/lib/hx509/ks_mem.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("Id$"); + +/* + * Should use two hash/tree certificates intead of a array. Criteria + * should be subject and subjectKeyIdentifier since those two are + * commonly seached on in CMS and path building. + */ + +struct mem_data { + char *name; + struct { + unsigned long len; + hx509_cert *val; + } certs; + hx509_private_key *keys; +}; + +static int +mem_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + struct mem_data *mem; + mem = calloc(1, sizeof(*mem)); + if (mem == NULL) + return ENOMEM; + if (residue == NULL || residue[0] == '\0') + residue = "anonymous"; + mem->name = strdup(residue); + if (mem->name == NULL) { + free(mem); + return ENOMEM; + } + *data = mem; + return 0; +} + +static int +mem_free(hx509_certs certs, void *data) +{ + struct mem_data *mem = data; + unsigned long i; + + for (i = 0; i < mem->certs.len; i++) + hx509_cert_free(mem->certs.val[i]); + free(mem->certs.val); + for (i = 0; mem->keys && mem->keys[i]; i++) + _hx509_private_key_free(&mem->keys[i]); + free(mem->name); + free(mem); + + return 0; +} + +static int +mem_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c) +{ + struct mem_data *mem = data; + hx509_cert *val; + + val = realloc(mem->certs.val, + (mem->certs.len + 1) * sizeof(mem->certs.val[0])); + if (val == NULL) + return ENOMEM; + + mem->certs.val = val; + mem->certs.val[mem->certs.len] = hx509_cert_ref(c); + mem->certs.len++; + + return 0; +} + +static int +mem_iter_start(hx509_context context, + hx509_certs certs, + void *data, + void **cursor) +{ + unsigned long *iter = malloc(sizeof(*iter)); + + if (iter == NULL) + return ENOMEM; + + *iter = 0; + *cursor = iter; + + return 0; +} + +static int +mem_iter(hx509_context contexst, + hx509_certs certs, + void *data, + void *cursor, + hx509_cert *cert) +{ + unsigned long *iter = cursor; + struct mem_data *mem = data; + + if (*iter >= mem->certs.len) { + *cert = NULL; + return 0; + } + + *cert = hx509_cert_ref(mem->certs.val[*iter]); + (*iter)++; + return 0; +} + +static int +mem_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + free(cursor); + return 0; +} + +static int +mem_getkeys(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key **keys) +{ + struct mem_data *mem = data; + int i; + + for (i = 0; mem->keys && mem->keys[i]; i++) + ; + *keys = calloc(i, sizeof(**keys)); + for (i = 0; mem->keys && mem->keys[i]; i++) { + (*keys)[i] = _hx509_private_key_ref(mem->keys[i]); + if ((*keys)[i] == NULL) { + while (--i >= 0) + _hx509_private_key_free(&(*keys)[i]); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + } + (*keys)[i] = NULL; + return 0; +} + +static int +mem_addkey(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key key) +{ + struct mem_data *mem = data; + void *ptr; + int i; + + for (i = 0; mem->keys && mem->keys[i]; i++) + ; + ptr = realloc(mem->keys, (i + 2) * sizeof(*mem->keys)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + mem->keys = ptr; + mem->keys[i++] = _hx509_private_key_ref(key); + mem->keys[i++] = NULL; + return 0; +} + + +static struct hx509_keyset_ops keyset_mem = { + "MEMORY", + 0, + mem_init, + NULL, + mem_free, + mem_add, + NULL, + mem_iter_start, + mem_iter, + mem_iter_end, + NULL, + mem_getkeys, + mem_addkey +}; + +void +_hx509_ks_mem_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_mem); +} diff --git a/source4/heimdal/lib/hx509/ks_null.c b/source4/heimdal/lib/hx509/ks_null.c new file mode 100644 index 0000000000..1e6c2ea3fb --- /dev/null +++ b/source4/heimdal/lib/hx509/ks_null.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: ks_null.c,v 1.5 2007/01/09 10:52:10 lha Exp $"); + + +static int +null_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + *data = NULL; + return 0; +} + +static int +null_free(hx509_certs certs, void *data) +{ + assert(data == NULL); + return 0; +} + +static int +null_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + *cursor = NULL; + return 0; +} + +static int +null_iter(hx509_context context, + hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + *cert = NULL; + return ENOENT; +} + +static int +null_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + assert(cursor == NULL); + return 0; +} + + +struct hx509_keyset_ops keyset_null = { + "NULL", + 0, + null_init, + NULL, + null_free, + NULL, + NULL, + null_iter_start, + null_iter, + null_iter_end +}; diff --git a/source4/heimdal/lib/hx509/ks_p11.c b/source4/heimdal/lib/hx509/ks_p11.c new file mode 100644 index 0000000000..b103264b7a --- /dev/null +++ b/source4/heimdal/lib/hx509/ks_p11.c @@ -0,0 +1,1183 @@ +/* + * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: ks_p11.c,v 1.45 2007/01/09 19:43:35 lha Exp $"); +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#ifdef HAVE_DLOPEN + +#include "pkcs11.h" + +struct p11_slot { + int flags; +#define P11_SESSION 1 +#define P11_SESSION_IN_USE 2 +#define P11_LOGIN_REQ 4 +#define P11_LOGIN_DONE 8 +#define P11_TOKEN_PRESENT 16 + CK_SESSION_HANDLE session; + CK_SLOT_ID id; + CK_BBOOL token; + char *name; + hx509_certs certs; + char *pin; + struct { + CK_MECHANISM_TYPE_PTR list; + CK_ULONG num; + CK_MECHANISM_INFO_PTR *infos; + } mechs; +}; + +struct p11_module { + void *dl_handle; + CK_FUNCTION_LIST_PTR funcs; + CK_ULONG num_slots; + unsigned int refcount; + struct p11_slot *slot; +}; + +#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args + +static int p11_get_session(hx509_context, + struct p11_module *, + struct p11_slot *, + hx509_lock, + CK_SESSION_HANDLE *); +static int p11_put_session(struct p11_module *, + struct p11_slot *, + CK_SESSION_HANDLE); +static void p11_release_module(struct p11_module *); + +static int p11_list_keys(hx509_context, + struct p11_module *, + struct p11_slot *, + CK_SESSION_HANDLE, + hx509_lock, + hx509_certs *); + +/* + * + */ + +struct p11_rsa { + struct p11_module *p; + struct p11_slot *slot; + CK_OBJECT_HANDLE private_key; + CK_OBJECT_HANDLE public_key; +}; + +static int +p11_rsa_public_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + +static int +p11_rsa_public_decrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + + +static int +p11_rsa_private_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + struct p11_rsa *p11rsa = RSA_get_app_data(rsa); + CK_OBJECT_HANDLE key = p11rsa->private_key; + CK_SESSION_HANDLE session; + CK_MECHANISM mechanism; + CK_ULONG ck_sigsize; + int ret; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_RSA_PKCS; + + ck_sigsize = RSA_size(rsa); + + ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); + if (ret) + return -1; + + ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key)); + if (ret != CKR_OK) { + p11_put_session(p11rsa->p, p11rsa->slot, session); + return -1; + } + + ret = P11FUNC(p11rsa->p, Sign, + (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); + p11_put_session(p11rsa->p, p11rsa->slot, session); + if (ret != CKR_OK) + return -1; + + return ck_sigsize; +} + +static int +p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, + RSA * rsa, int padding) +{ + struct p11_rsa *p11rsa = RSA_get_app_data(rsa); + CK_OBJECT_HANDLE key = p11rsa->private_key; + CK_SESSION_HANDLE session; + CK_MECHANISM mechanism; + CK_ULONG ck_sigsize; + int ret; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_RSA_PKCS; + + ck_sigsize = RSA_size(rsa); + + ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); + if (ret) + return -1; + + ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key)); + if (ret != CKR_OK) { + p11_put_session(p11rsa->p, p11rsa->slot, session); + return -1; + } + + ret = P11FUNC(p11rsa->p, Decrypt, + (session, (CK_BYTE *)from, flen, to, &ck_sigsize)); + p11_put_session(p11rsa->p, p11rsa->slot, session); + if (ret != CKR_OK) + return -1; + + return ck_sigsize; +} + +static int +p11_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +p11_rsa_finish(RSA *rsa) +{ + struct p11_rsa *p11rsa = RSA_get_app_data(rsa); + p11_release_module(p11rsa->p); + free(p11rsa); + return 1; +} + +static const RSA_METHOD rsa_pkcs1_method = { + "hx509 PKCS11 PKCS#1 RSA", + p11_rsa_public_encrypt, + p11_rsa_public_decrypt, + p11_rsa_private_encrypt, + p11_rsa_private_decrypt, + NULL, + NULL, + p11_rsa_init, + p11_rsa_finish, + 0, + NULL, + NULL, + NULL +}; + +/* + * + */ + +static int +p11_mech_info(hx509_context context, + struct p11_module *p, + struct p11_slot *slot, + int num) +{ + CK_ULONG i; + int ret; + + ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "Failed to get mech list count for slot %d", + num); + return HX509_PKCS11_NO_MECH; + } + if (i == 0) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "no mech supported for slot %d", num); + return HX509_PKCS11_NO_MECH; + } + slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0])); + if (slot->mechs.list == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + slot->mechs.num = i; + ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "Failed to get mech list for slot %d", + num); + return HX509_PKCS11_NO_MECH; + } + assert(i == slot->mechs.num); + + slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos)); + if (slot->mechs.list == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + + for (i = 0; i < slot->mechs.num; i++) { + slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0]))); + if (slot->mechs.infos[i] == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i], + slot->mechs.infos[i])); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "Failed to get mech info for slot %d", + num); + return HX509_PKCS11_NO_MECH; + } + } + + return 0; +} + +static int +p11_init_slot(hx509_context context, + struct p11_module *p, + hx509_lock lock, + CK_SLOT_ID id, + int num, + struct p11_slot *slot) +{ + CK_SESSION_HANDLE session; + CK_SLOT_INFO slot_info; + CK_TOKEN_INFO token_info; + int ret, i; + + slot->certs = NULL; + slot->id = id; + + ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, + "Failed to init PKCS11 slot %d", + num); + return HX509_PKCS11_TOKEN_CONFUSED; + } + + for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) { + char c = slot_info.slotDescription[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0') + continue; + i++; + break; + } + + asprintf(&slot->name, "%.*s", + i, slot_info.slotDescription); + + if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) + return 0; + + ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN, + "Failed to init PKCS11 slot %d " + "with error 0x08x", + num, ret); + return HX509_PKCS11_NO_TOKEN; + } + slot->flags |= P11_TOKEN_PRESENT; + + if (token_info.flags & CKF_LOGIN_REQUIRED) + slot->flags |= P11_LOGIN_REQ; + + ret = p11_get_session(context, p, slot, lock, &session); + if (ret) + return ret; + + ret = p11_mech_info(context, p, slot, num); + if (ret) + goto out; + + ret = p11_list_keys(context, p, slot, session, lock, &slot->certs); + out: + p11_put_session(p, slot, session); + + return ret; +} + +static int +p11_get_session(hx509_context context, + struct p11_module *p, + struct p11_slot *slot, + hx509_lock lock, + CK_SESSION_HANDLE *psession) +{ + CK_RV ret; + + if (slot->flags & P11_SESSION_IN_USE) + _hx509_abort("slot already in session"); + + if (slot->flags & P11_SESSION) { + slot->flags |= P11_SESSION_IN_USE; + *psession = slot->session; + return 0; + } + + ret = P11FUNC(p, OpenSession, (slot->id, + CKF_SERIAL_SESSION, + NULL, + NULL, + &slot->session)); + if (ret != CKR_OK) { + if (context) + hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION, + "Failed to OpenSession for slot id %d " + "with error: 0x%08x", + (int)slot->id, ret); + return HX509_PKCS11_OPEN_SESSION; + } + + slot->flags |= P11_SESSION; + + /* + * If we have have to login, and haven't tried before and have a + * prompter or known to work pin code. + * + * This code is very conversative and only uses the prompter in + * the hx509_lock, the reason is that its bad to try many + * passwords on a pkcs11 token, it might lock up and have to be + * unlocked by a administrator. + * + * XXX try harder to not use pin several times on the same card. + */ + + if ( (slot->flags & P11_LOGIN_REQ) + && (slot->flags & P11_LOGIN_DONE) == 0 + && (lock || slot->pin)) + { + hx509_prompt prompt; + char pin[20]; + char *str; + + slot->flags |= P11_LOGIN_DONE; + + if (slot->pin == NULL) { + + memset(&prompt, 0, sizeof(prompt)); + + asprintf(&str, "PIN code for %s: ", slot->name); + prompt.prompt = str; + prompt.type = HX509_PROMPT_TYPE_PASSWORD; + prompt.reply.data = pin; + prompt.reply.length = sizeof(pin); + + ret = hx509_lock_prompt(lock, &prompt); + if (ret) { + free(str); + if (context) + hx509_set_error_string(context, 0, ret, + "Failed to get pin code for slot " + "id %d with error: %d", + (int)slot->id, ret); + return ret; + } + free(str); + } else { + strlcpy(pin, slot->pin, sizeof(pin)); + } + + ret = P11FUNC(p, Login, (slot->session, CKU_USER, + (unsigned char*)pin, strlen(pin))); + if (ret != CKR_OK) { + if (context) + hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN, + "Failed to login on slot id %d " + "with error: 0x%08x", + (int)slot->id, ret); + p11_put_session(p, slot, slot->session); + return HX509_PKCS11_LOGIN; + } + if (slot->pin == NULL) { + slot->pin = strdup(pin); + if (slot->pin == NULL) { + if (context) + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + p11_put_session(p, slot, slot->session); + return ENOMEM; + } + } + } else + slot->flags |= P11_LOGIN_DONE; + + slot->flags |= P11_SESSION_IN_USE; + + *psession = slot->session; + + return 0; +} + +static int +p11_put_session(struct p11_module *p, + struct p11_slot *slot, + CK_SESSION_HANDLE session) +{ + if ((slot->flags & P11_SESSION_IN_USE) == 0) + _hx509_abort("slot not in session"); + slot->flags &= ~P11_SESSION_IN_USE; + + return 0; +} + +static int +iterate_entries(hx509_context context, + struct p11_module *p, struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_ATTRIBUTE *search_data, int num_search_data, + CK_ATTRIBUTE *query, int num_query, + int (*func)(hx509_context, + struct p11_module *, struct p11_slot *, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + void *, CK_ATTRIBUTE *, int), void *ptr) +{ + CK_OBJECT_HANDLE object; + CK_ULONG object_count; + int ret, i; + + ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data)); + if (ret != CKR_OK) { + return -1; + } + while (1) { + ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count)); + if (ret != CKR_OK) { + return -1; + } + if (object_count == 0) + break; + + for (i = 0; i < num_query; i++) + query[i].pValue = NULL; + + ret = P11FUNC(p, GetAttributeValue, + (session, object, query, num_query)); + if (ret != CKR_OK) { + return -1; + } + for (i = 0; i < num_query; i++) { + query[i].pValue = malloc(query[i].ulValueLen); + if (query[i].pValue == NULL) { + ret = ENOMEM; + goto out; + } + } + ret = P11FUNC(p, GetAttributeValue, + (session, object, query, num_query)); + if (ret != CKR_OK) { + ret = -1; + goto out; + } + + ret = (*func)(context, p, slot, session, object, ptr, query, num_query); + if (ret) + goto out; + + for (i = 0; i < num_query; i++) { + if (query[i].pValue) + free(query[i].pValue); + query[i].pValue = NULL; + } + } + out: + + for (i = 0; i < num_query; i++) { + if (query[i].pValue) + free(query[i].pValue); + query[i].pValue = NULL; + } + + ret = P11FUNC(p, FindObjectsFinal, (session)); + if (ret != CKR_OK) { + return -2; + } + + + return 0; +} + +static BIGNUM * +getattr_bn(struct p11_module *p, + struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + unsigned int type) +{ + CK_ATTRIBUTE query; + BIGNUM *bn; + int ret; + + query.type = type; + query.pValue = NULL; + query.ulValueLen = 0; + + ret = P11FUNC(p, GetAttributeValue, + (session, object, &query, 1)); + if (ret != CKR_OK) + return NULL; + + query.pValue = malloc(query.ulValueLen); + + ret = P11FUNC(p, GetAttributeValue, + (session, object, &query, 1)); + if (ret != CKR_OK) { + free(query.pValue); + return NULL; + } + bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL); + free(query.pValue); + + return bn; +} + +static int +collect_private_key(hx509_context context, + struct p11_module *p, struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + void *ptr, CK_ATTRIBUTE *query, int num_query) +{ + struct hx509_collector *collector = ptr; + hx509_private_key key; + heim_octet_string localKeyId; + int ret; + RSA *rsa; + struct p11_rsa *p11rsa; + + localKeyId.data = query[0].pValue; + localKeyId.length = query[0].ulValueLen; + + ret = _hx509_private_key_init(&key, NULL, NULL); + if (ret) + return ret; + + rsa = RSA_new(); + if (rsa == NULL) + _hx509_abort("out of memory"); + + /* + * The exponent and modulus should always be present according to + * the pkcs11 specification, but some smartcards leaves it out, + * let ignore any failure to fetch it. + */ + rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS); + rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT); + + p11rsa = calloc(1, sizeof(*p11rsa)); + if (p11rsa == NULL) + _hx509_abort("out of memory"); + + p11rsa->p = p; + p11rsa->slot = slot; + p11rsa->private_key = object; + + p->refcount++; + if (p->refcount == 0) + _hx509_abort("pkcs11 refcount to high"); + + RSA_set_method(rsa, &rsa_pkcs1_method); + ret = RSA_set_app_data(rsa, p11rsa); + if (ret != 1) + _hx509_abort("RSA_set_app_data"); + + _hx509_private_key_assign_rsa(key, rsa); + + ret = _hx509_collector_private_key_add(context, + collector, + hx509_signature_rsa(), + key, + NULL, + &localKeyId); + + if (ret) { + _hx509_private_key_free(&key); + return ret; + } + return 0; +} + +static void +p11_cert_release(hx509_cert cert, void *ctx) +{ + struct p11_module *p = ctx; + p11_release_module(p); +} + + +static int +collect_cert(hx509_context context, + struct p11_module *p, struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + void *ptr, CK_ATTRIBUTE *query, int num_query) +{ + struct hx509_collector *collector = ptr; + hx509_cert cert; + Certificate t; + int ret; + + if ((CK_LONG)query[0].ulValueLen == -1 || + (CK_LONG)query[1].ulValueLen == -1) + { + return 0; + } + + + ret = decode_Certificate(query[1].pValue, query[1].ulValueLen, + &t, NULL); + if (ret) { + hx509_clear_error_string(context); + return 0; + } + + ret = hx509_cert_init(context, &t, &cert); + free_Certificate(&t); + if (ret) + return ret; + + p->refcount++; + if (p->refcount == 0) + _hx509_abort("pkcs11 refcount to high"); + + _hx509_cert_set_release(cert, p11_cert_release, p); + + { + heim_octet_string data; + + data.data = query[0].pValue; + data.length = query[0].ulValueLen; + + _hx509_set_cert_attribute(context, + cert, + oid_id_pkcs_9_at_localKeyId(), + &data); + } + + if ((CK_LONG)query[2].ulValueLen != -1) { + char *str; + + asprintf(&str, "%.*s", + (int)query[2].ulValueLen, (char *)query[2].pValue); + if (str) { + hx509_cert_set_friendly_name(cert, str); + free(str); + } + } + + ret = _hx509_collector_certs_add(context, collector, cert); + hx509_cert_free(cert); + + return ret; +} + + +static int +p11_list_keys(hx509_context context, + struct p11_module *p, + struct p11_slot *slot, + CK_SESSION_HANDLE session, + hx509_lock lock, + hx509_certs *certs) +{ + struct hx509_collector *collector; + CK_OBJECT_CLASS key_class; + CK_ATTRIBUTE search_data[] = { + {CKA_CLASS, NULL, 0}, + }; + CK_ATTRIBUTE query_data[3] = { + {CKA_ID, NULL, 0}, + {CKA_VALUE, NULL, 0}, + {CKA_LABEL, NULL, 0} + }; + int ret; + + search_data[0].pValue = &key_class; + search_data[0].ulValueLen = sizeof(key_class); + + if (lock == NULL) + lock = _hx509_empty_lock; + + collector = _hx509_collector_alloc(context, lock); + if (collector == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + key_class = CKO_PRIVATE_KEY; + ret = iterate_entries(context, p, slot, session, + search_data, 1, + query_data, 1, + collect_private_key, collector); + if (ret) + goto out; + + key_class = CKO_CERTIFICATE; + ret = iterate_entries(context, p, slot, session, + search_data, 1, + query_data, 3, + collect_cert, collector); + if (ret) + goto out; + + ret = _hx509_collector_collect_certs(context, collector, &slot->certs); + +out: + _hx509_collector_free(collector); + + return ret; +} + + +static int +p11_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + CK_C_GetFunctionList getFuncs; + struct p11_module *p; + char *list, *str; + int ret; + + *data = NULL; + + list = strdup(residue); + if (list == NULL) + return ENOMEM; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + free(list); + return ENOMEM; + } + + p->refcount = 1; + + str = strchr(list, ','); + if (str) + *str++ = '\0'; + while (str) { + char *strnext; + strnext = strchr(str, ','); + if (strnext) + *strnext++ = '\0'; +#if 0 + if (strncasecmp(str, "slot=", 5) == 0) + p->selected_slot = atoi(str + 5); +#endif + str = strnext; + } + + p->dl_handle = dlopen(list, RTLD_NOW); + free(list); + if (p->dl_handle == NULL) { + ret = HX509_PKCS11_LOAD; + hx509_set_error_string(context, 0, ret, + "Failed to open %s: %s", list, dlerror()); + goto out; + } + + getFuncs = dlsym(p->dl_handle, "C_GetFunctionList"); + if (getFuncs == NULL) { + ret = HX509_PKCS11_LOAD; + hx509_set_error_string(context, 0, ret, + "C_GetFunctionList missing in %s: %s", + list, dlerror()); + goto out; + } + + ret = (*getFuncs)(&p->funcs); + if (ret) { + ret = HX509_PKCS11_LOAD; + hx509_set_error_string(context, 0, ret, + "C_GetFunctionList failed in %s", list); + goto out; + } + + ret = P11FUNC(p, Initialize, (NULL_PTR)); + if (ret != CKR_OK) { + ret = HX509_PKCS11_TOKEN_CONFUSED; + hx509_set_error_string(context, 0, ret, + "Failed initialize the PKCS11 module"); + goto out; + } + + ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots)); + if (ret) { + ret = HX509_PKCS11_TOKEN_CONFUSED; + hx509_set_error_string(context, 0, ret, + "Failed to get number of PKCS11 slots"); + goto out; + } + + if (p->num_slots == 0) { + ret = HX509_PKCS11_NO_SLOT; + hx509_set_error_string(context, 0, ret, + "Selected PKCS11 module have no slots"); + goto out; + } + + + { + CK_SLOT_ID_PTR slot_ids; + int i, num_tokens = 0; + + slot_ids = malloc(p->num_slots * sizeof(*slot_ids)); + if (slot_ids == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots)); + if (ret) { + free(slot_ids); + hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, + "Failed getting slot-list from " + "PKCS11 module"); + ret = HX509_PKCS11_TOKEN_CONFUSED; + goto out; + } + + p->slot = calloc(p->num_slots, sizeof(p->slot[0])); + if (p->slot == NULL) { + free(slot_ids); + hx509_set_error_string(context, 0, ENOMEM, + "Failed to get memory for slot-list"); + ret = ENOMEM; + goto out; + } + + for (i = 0; i < p->num_slots; i++) { + ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]); + if (ret) + break; + if (p->slot[i].flags & P11_TOKEN_PRESENT) + num_tokens++; + } + free(slot_ids); + if (ret) + goto out; + if (num_tokens == 0) { + ret = HX509_PKCS11_NO_TOKEN; + goto out; + } + } + + *data = p; + + return 0; + out: + p11_release_module(p); + return ret; +} + +static void +p11_release_module(struct p11_module *p) +{ + int i; + + if (p->refcount == 0) + _hx509_abort("pkcs11 refcount to low"); + if (--p->refcount > 0) + return; + + for (i = 0; i < p->num_slots; i++) { + if (p->slot[i].flags & P11_SESSION_IN_USE) + _hx509_abort("pkcs11 module release while session in use"); + if (p->slot[i].flags & P11_SESSION) { + int ret; + + ret = P11FUNC(p, CloseSession, (p->slot[i].session)); + if (ret != CKR_OK) + ; + } + + if (p->slot[i].name) + free(p->slot[i].name); + if (p->slot[i].pin) { + memset(p->slot[i].pin, 0, strlen(p->slot[i].pin)); + free(p->slot[i].pin); + } + if (p->slot[i].mechs.num) { + free(p->slot[i].mechs.list); + + if (p->slot[i].mechs.infos) { + int j; + + for (j = 0 ; j < p->slot[i].mechs.num ; j++) + free(p->slot[i].mechs.infos[j]); + free(p->slot[i].mechs.infos); + } + } + } + free(p->slot); + + if (p->funcs) + P11FUNC(p, Finalize, (NULL)); + + if (p->dl_handle) + dlclose(p->dl_handle); + + memset(p, 0, sizeof(*p)); + free(p); +} + +static int +p11_free(hx509_certs certs, void *data) +{ + struct p11_module *p = data; + int i; + + for (i = 0; i < p->num_slots; i++) { + if (p->slot[i].certs) + hx509_certs_free(&p->slot[i].certs); + } + p11_release_module(p); + return 0; +} + +struct p11_cursor { + hx509_certs certs; + void *cursor; +}; + +static int +p11_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct p11_module *p = data; + struct p11_cursor *c; + int ret, i; + + c = malloc(sizeof(*c)); + if (c == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs); + if (ret) { + free(c); + return ret; + } + + for (i = 0 ; i < p->num_slots; i++) { + if (p->slot[i].certs == NULL) + continue; + ret = hx509_certs_merge(context, c->certs, p->slot[i].certs); + if (ret) { + hx509_certs_free(&c->certs); + free(c); + return ret; + } + } + + ret = hx509_certs_start_seq(context, c->certs, &c->cursor); + if (ret) { + hx509_certs_free(&c->certs); + free(c); + return 0; + } + *cursor = c; + + return 0; +} + +static int +p11_iter(hx509_context context, + hx509_certs certs, void *data, void *cursor, hx509_cert *cert) +{ + struct p11_cursor *c = cursor; + return hx509_certs_next_cert(context, c->certs, c->cursor, cert); +} + +static int +p11_iter_end(hx509_context context, + hx509_certs certs, void *data, void *cursor) +{ + struct p11_cursor *c = cursor; + int ret; + ret = hx509_certs_end_seq(context, c->certs, c->cursor); + hx509_certs_free(&c->certs); + free(c); + return ret; +} + +#define MECHFLAG(x) { "unknown-flag-" #x, x } +static struct units mechflags[] = { + MECHFLAG(0x80000000), + MECHFLAG(0x40000000), + MECHFLAG(0x20000000), + MECHFLAG(0x10000000), + MECHFLAG(0x08000000), + MECHFLAG(0x04000000), + {"ec-compress", 0x2000000 }, + {"ec-uncompress", 0x1000000 }, + {"ec-namedcurve", 0x0800000 }, + {"ec-ecparameters", 0x0400000 }, + {"ec-f-2m", 0x0200000 }, + {"ec-f-p", 0x0100000 }, + {"derive", 0x0080000 }, + {"unwrap", 0x0040000 }, + {"wrap", 0x0020000 }, + {"genereate-key-pair", 0x0010000 }, + {"generate", 0x0008000 }, + {"verify-recover", 0x0004000 }, + {"verify", 0x0002000 }, + {"sign-recover", 0x0001000 }, + {"sign", 0x0000800 }, + {"digest", 0x0000400 }, + {"decrypt", 0x0000200 }, + {"encrypt", 0x0000100 }, + MECHFLAG(0x00080), + MECHFLAG(0x00040), + MECHFLAG(0x00020), + MECHFLAG(0x00010), + MECHFLAG(0x00008), + MECHFLAG(0x00004), + MECHFLAG(0x00002), + {"hw", 0x0000001 }, + { NULL, 0x0000000 } +}; +#undef MECHFLAG + +static int +p11_printinfo(hx509_context context, + hx509_certs certs, + void *data, + int (*func)(void *, char *), + void *ctx) +{ + struct p11_module *p = data; + int i, j; + + _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s", + p->num_slots, p->num_slots > 1 ? "s" : ""); + + for (i = 0; i < p->num_slots; i++) { + struct p11_slot *s = &p->slot[i]; + + _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x", + i, (int)s->id, s->name, s->flags); + + _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu", + (unsigned long)s->mechs.num); + for (j = 0; j < s->mechs.num; j++) { + const char *mechname = "unknown"; + char flags[256], unknownname[40]; +#define MECHNAME(s,n) case s: mechname = n; break + switch(s->mechs.list[j]) { + MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen"); + MECHNAME(CKM_RSA_PKCS, "rsa-pkcs"); + MECHNAME(CKM_RSA_X_509, "rsa-x-509"); + MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs"); + MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs"); + default: + snprintf(unknownname, sizeof(unknownname), + "unknown-mech-%lu", + (unsigned long)s->mechs.list[j]); + mechname = unknownname; + break; + } +#undef MECHNAME + unparse_flags(s->mechs.infos[j]->flags, mechflags, + flags, sizeof(flags)); + + _hx509_pi_printf(func, ctx, " %s: %s", mechname, flags); + } + } + + return 0; +} + +static struct hx509_keyset_ops keyset_pkcs11 = { + "PKCS11", + 0, + p11_init, + NULL, + p11_free, + NULL, + NULL, + p11_iter_start, + p11_iter, + p11_iter_end, + p11_printinfo +}; + +#endif /* HAVE_DLOPEN */ + +void +_hx509_ks_pkcs11_register(hx509_context context) +{ +#ifdef HAVE_DLOPEN + _hx509_ks_register(context, &keyset_pkcs11); +#endif +} diff --git a/source4/heimdal/lib/hx509/ks_p12.c b/source4/heimdal/lib/hx509/ks_p12.c new file mode 100644 index 0000000000..69dba802e5 --- /dev/null +++ b/source4/heimdal/lib/hx509/ks_p12.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: ks_p12.c,v 1.18 2007/01/09 10:52:11 lha Exp $"); + +struct ks_pkcs12 { + hx509_certs certs; + char *fn; +}; + +typedef int (*collector_func)(hx509_context, + struct hx509_collector *, + const void *, size_t, + const PKCS12_Attributes *); + +struct type { + const heim_oid * (*oid)(void); + collector_func func; +}; + +static void +parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *, + const void *, size_t, const PKCS12_Attributes *); + + +static const PKCS12_Attribute * +find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid) +{ + int i; + if (attrs == NULL) + return NULL; + for (i = 0; i < attrs->len; i++) + if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0) + return &attrs->val[i]; + return NULL; +} + +static int +keyBag_parser(hx509_context context, + struct hx509_collector *c, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + const PKCS12_Attribute *attr; + PKCS8PrivateKeyInfo ki; + const heim_octet_string *os = NULL; + int ret; + + attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId()); + if (attr) + os = &attr->attrValues; + + ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL); + if (ret) + return ret; + + _hx509_collector_private_key_add(context, + c, + &ki.privateKeyAlgorithm, + NULL, + &ki.privateKey, + &attr->attrValues); + free_PKCS8PrivateKeyInfo(&ki); + return 0; +} + +static int +ShroudedKeyBag_parser(hx509_context context, + struct hx509_collector *c, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + PKCS8EncryptedPrivateKeyInfo pk; + heim_octet_string content; + int ret; + + memset(&pk, 0, sizeof(pk)); + + ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL); + if (ret) + return ret; + + ret = _hx509_pbe_decrypt(context, + _hx509_collector_get_lock(c), + &pk.encryptionAlgorithm, + &pk.encryptedData, + &content); + free_PKCS8EncryptedPrivateKeyInfo(&pk); + if (ret) + return ret; + + ret = keyBag_parser(context, c, content.data, content.length, attrs); + der_free_octet_string(&content); + return ret; +} + +static int +certBag_parser(hx509_context context, + struct hx509_collector *c, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string os; + Certificate t; + hx509_cert cert; + PKCS12_CertBag cb; + int ret; + + ret = decode_PKCS12_CertBag(data, length, &cb, NULL); + if (ret) + return ret; + + if (der_heim_oid_cmp(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType)) { + free_PKCS12_CertBag(&cb); + return 0; + } + + ret = decode_PKCS12_OctetString(cb.certValue.data, + cb.certValue.length, + &os, + NULL); + free_PKCS12_CertBag(&cb); + if (ret) + return ret; + + ret = decode_Certificate(os.data, os.length, &t, NULL); + der_free_octet_string(&os); + if (ret) + return ret; + + ret = hx509_cert_init(context, &t, &cert); + free_Certificate(&t); + if (ret) + return ret; + + ret = _hx509_collector_certs_add(context, c, cert); + if (ret) { + hx509_cert_free(cert); + return ret; + } + + { + const PKCS12_Attribute *attr; + const heim_oid * (*oids[])(void) = { + oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName + }; + int i; + + for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { + const heim_oid *oid = (*(oids[i]))(); + attr = find_attribute(attrs, oid); + if (attr) + _hx509_set_cert_attribute(context, cert, oid, + &attr->attrValues); + } + } + + hx509_cert_free(cert); + + return 0; +} + +static int +parse_safe_content(hx509_context context, + struct hx509_collector *c, + const unsigned char *p, size_t len) +{ + PKCS12_SafeContents sc; + int ret, i; + + memset(&sc, 0, sizeof(sc)); + + ret = decode_PKCS12_SafeContents(p, len, &sc, NULL); + if (ret) + return ret; + + for (i = 0; i < sc.len ; i++) + parse_pkcs12_type(context, + c, + &sc.val[i].bagId, + sc.val[i].bagValue.data, + sc.val[i].bagValue.length, + sc.val[i].bagAttributes); + + free_PKCS12_SafeContents(&sc); + return 0; +} + +static int +safeContent_parser(hx509_context context, + struct hx509_collector *c, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string os; + int ret; + + ret = decode_PKCS12_OctetString(data, length, &os, NULL); + if (ret) + return ret; + ret = parse_safe_content(context, c, os.data, os.length); + der_free_octet_string(&os); + return ret; +} + +static int +encryptedData_parser(hx509_context context, + struct hx509_collector *c, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string content; + heim_oid contentType; + int ret; + + memset(&contentType, 0, sizeof(contentType)); + + ret = hx509_cms_decrypt_encrypted(context, + _hx509_collector_get_lock(c), + data, length, + &contentType, + &content); + if (ret) + return ret; + + if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) + ret = parse_safe_content(context, c, content.data, content.length); + + der_free_octet_string(&content); + der_free_oid(&contentType); + return ret; +} + +static int +envelopedData_parser(hx509_context context, + struct hx509_collector *c, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string content; + heim_oid contentType; + hx509_lock lock; + int ret; + + memset(&contentType, 0, sizeof(contentType)); + + lock = _hx509_collector_get_lock(c); + + ret = hx509_cms_unenvelope(context, + _hx509_lock_unlock_certs(lock), + 0, + data, length, + NULL, + &contentType, + &content); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "PKCS12 failed to unenvelope"); + return ret; + } + + if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) + ret = parse_safe_content(context, c, content.data, content.length); + + der_free_octet_string(&content); + der_free_oid(&contentType); + + return ret; +} + + +struct type bagtypes[] = { + { oid_id_pkcs12_keyBag, keyBag_parser }, + { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, + { oid_id_pkcs12_certBag, certBag_parser }, + { oid_id_pkcs7_data, safeContent_parser }, + { oid_id_pkcs7_encryptedData, encryptedData_parser }, + { oid_id_pkcs7_envelopedData, envelopedData_parser } +}; + +static void +parse_pkcs12_type(hx509_context context, + struct hx509_collector *c, + const heim_oid *oid, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + int i; + + for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++) + if (der_heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0) + (*bagtypes[i].func)(context, c, data, length, attrs); +} + +static int +p12_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + struct ks_pkcs12 *p12; + size_t len; + void *buf; + PKCS12_PFX pfx; + PKCS12_AuthenticatedSafe as; + int ret, i; + struct hx509_collector *c; + + *data = NULL; + + if (lock == NULL) + lock = _hx509_empty_lock; + + c = _hx509_collector_alloc(context, lock); + if (c == NULL) + return ENOMEM; + + p12 = calloc(1, sizeof(*p12)); + if (p12 == NULL) { + ret = ENOMEM; + goto out; + } + + p12->fn = strdup(residue); + if (p12->fn == NULL) { + ret = ENOMEM; + goto out; + } + + if (flags & HX509_CERTS_CREATE) { + ret = hx509_certs_init(context, "MEMORY:ks-file-create", + 0, lock, &p12->certs); + if (ret) + goto out; + *data = p12; + return 0; + } + + ret = _hx509_map_file(residue, &buf, &len, NULL); + if (ret) + goto out; + + ret = decode_PKCS12_PFX(buf, len, &pfx, NULL); + _hx509_unmap_file(buf, len); + if (ret) + goto out; + + if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) { + free_PKCS12_PFX(&pfx); + ret = EINVAL; + hx509_set_error_string(context, 0, ret, + "PKCS PFX isn't a pkcs7-data container"); + goto out; + } + + if (pfx.authSafe.content == NULL) { + free_PKCS12_PFX(&pfx); + ret = EINVAL; + hx509_set_error_string(context, 0, ret, + "PKCS PFX missing data"); + goto out; + } + + { + heim_octet_string asdata; + + ret = decode_PKCS12_OctetString(pfx.authSafe.content->data, + pfx.authSafe.content->length, + &asdata, + NULL); + free_PKCS12_PFX(&pfx); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + ret = decode_PKCS12_AuthenticatedSafe(asdata.data, + asdata.length, + &as, + NULL); + der_free_octet_string(&asdata); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + + for (i = 0; i < as.len; i++) + parse_pkcs12_type(context, + c, + &as.val[i].contentType, + as.val[i].content->data, + as.val[i].content->length, + NULL); + + free_PKCS12_AuthenticatedSafe(&as); + + ret = _hx509_collector_collect_certs(context, c, &p12->certs); + if (ret == 0) + *data = p12; + +out: + _hx509_collector_free(c); + + if (ret) { + if (p12->certs) + hx509_certs_free(&p12->certs); + free(p12); + } + + return ret; +} + +static int +addBag(hx509_context context, + PKCS12_AuthenticatedSafe *as, + const heim_oid *oid, + void *data, + size_t length) +{ + void *ptr; + int ret; + + ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory"); + return ENOMEM; + } + as->val = ptr; + + ret = der_copy_oid(oid, &as->val[as->len].contentType); + + as->val[as->len].content = calloc(1, sizeof(*as->val[0].content)); + if (as->val[as->len].content == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory"); + return ENOMEM; + } + + as->val[as->len].content->data = data; + as->val[as->len].content->length = length; + + as->len++; + + return 0; +} + +static int +store_func(hx509_context context, void *ctx, hx509_cert c) +{ + PKCS12_AuthenticatedSafe *as = ctx; + PKCS12_OctetString os; + PKCS12_CertBag cb; + size_t size; + int ret; + + memset(&os, 0, sizeof(os)); + memset(&cb, 0, sizeof(cb)); + + os.data = NULL; + os.length = 0; + + ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, + _hx509_get_cert(c), &size, ret); + if (ret) + goto out; + ASN1_MALLOC_ENCODE(PKCS12_OctetString, + cb.certValue.data,cb.certValue.length, + &os, &size, ret); + free(os.data); + if (ret) + goto out; + ret = der_copy_oid(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType); + if (ret) { + free_PKCS12_CertBag(&cb); + goto out; + } + ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length, + &cb, &size, ret); + free(cb.certValue.data); + if (ret) + goto out; + + ret = addBag(context, as, oid_id_pkcs12_certBag(), os.data, os.length); + + if (_hx509_cert_private_key_exportable(c)) { + hx509_private_key key = _hx509_cert_private_key(c); + PKCS8PrivateKeyInfo pki; + + memset(&pki, 0, sizeof(pki)); + + ret = der_parse_hex_heim_integer("00", &pki.version); + if (ret) + return ret; + ret = _hx509_private_key_oid(context, key, + &pki.privateKeyAlgorithm.algorithm); + if (ret) { + free_PKCS8PrivateKeyInfo(&pki); + return ret; + } + ret = _hx509_private_key_export(context, + _hx509_cert_private_key(c), + &pki.privateKey); + if (ret) { + free_PKCS8PrivateKeyInfo(&pki); + return ret; + } + /* set attribute, oid_id_pkcs_9_at_localKeyId() */ + + ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length, + &pki, &size, ret); + free_PKCS8PrivateKeyInfo(&pki); + if (ret) + return ret; + + ret = addBag(context, as, oid_id_pkcs12_keyBag(), os.data, os.length); + if (ret) + return ret; + } + +out: + return ret; +} + +static int +p12_store(hx509_context context, + hx509_certs certs, void *data, int flags, hx509_lock lock) +{ + struct ks_pkcs12 *p12 = data; + PKCS12_PFX pfx; + PKCS12_AuthenticatedSafe as; + PKCS12_OctetString asdata; + size_t size; + int ret; + + memset(&as, 0, sizeof(as)); + memset(&pfx, 0, sizeof(pfx)); + + ret = hx509_certs_iter(context, p12->certs, store_func, &as); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length, + &as, &size, ret); + free_PKCS12_AuthenticatedSafe(&as); + if (ret) + return ret; + + ret = der_parse_hex_heim_integer("03", &pfx.version); + if (ret) { + free(asdata.data); + goto out; + } + + pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content)); + + ASN1_MALLOC_ENCODE(PKCS12_OctetString, + pfx.authSafe.content->data, + pfx.authSafe.content->length, + &asdata, &size, ret); + free(asdata.data); + if (ret) + goto out; + + ret = der_copy_oid(oid_id_pkcs7_data(), &pfx.authSafe.contentType); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length, + &pfx, &size, ret); + if (ret) + goto out; + +#if 0 + const struct _hx509_password *pw; + + pw = _hx509_lock_get_passwords(lock); + if (pw != NULL) { + pfx.macData = calloc(1, sizeof(*pfx.macData)); + if (pfx.macData == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + return ret; + } + if (pfx.macData == NULL) { + free(asdata.data); + goto out; + } + } + ret = calculate_hash(&aspath, pw, pfx.macData); +#endif + + rk_dumpdata(p12->fn, asdata.data, asdata.length); + free(asdata.data); + +out: + free_PKCS12_AuthenticatedSafe(&as); + free_PKCS12_PFX(&pfx); + + return ret; +} + + +static int +p12_free(hx509_certs certs, void *data) +{ + struct ks_pkcs12 *p12 = data; + hx509_certs_free(&p12->certs); + free(p12->fn); + free(p12); + return 0; +} + +static int +p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_add(context, p12->certs, c); +} + +static int +p12_iter_start(hx509_context context, + hx509_certs certs, + void *data, + void **cursor) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_start_seq(context, p12->certs, cursor); +} + +static int +p12_iter(hx509_context context, + hx509_certs certs, + void *data, + void *cursor, + hx509_cert *cert) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_next_cert(context, p12->certs, cursor, cert); +} + +static int +p12_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_end_seq(context, p12->certs, cursor); +} + +static struct hx509_keyset_ops keyset_pkcs12 = { + "PKCS12", + 0, + p12_init, + p12_store, + p12_free, + p12_add, + NULL, + p12_iter_start, + p12_iter, + p12_iter_end +}; + +void +_hx509_ks_pkcs12_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_pkcs12); +} diff --git a/source4/heimdal/lib/hx509/lock.c b/source4/heimdal/lib/hx509/lock.c new file mode 100644 index 0000000000..95fc0aa26d --- /dev/null +++ b/source4/heimdal/lib/hx509/lock.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: lock.c,v 1.13 2006/10/14 09:41:05 lha Exp $"); + +struct hx509_lock_data { + struct _hx509_password password; + hx509_certs certs; + hx509_prompter_fct prompt; + void *prompt_data; +}; + +static struct hx509_lock_data empty_lock_data = { + { 0, NULL } +}; + +hx509_lock _hx509_empty_lock = &empty_lock_data; + +/* + * + */ + +int +hx509_lock_init(hx509_context context, hx509_lock *lock) +{ + hx509_lock l; + int ret; + + *lock = NULL; + + l = calloc(1, sizeof(*l)); + if (l == NULL) + return ENOMEM; + + ret = hx509_certs_init(context, + "MEMORY:locks-internal", + 0, + NULL, + &l->certs); + if (ret) { + free(l); + return ret; + } + + *lock = l; + + return 0; +} + +int +hx509_lock_add_password(hx509_lock lock, const char *password) +{ + void *d; + char *s; + + s = strdup(password); + if (s == NULL) + return ENOMEM; + + d = realloc(lock->password.val, + (lock->password.len + 1) * sizeof(lock->password.val[0])); + if (d == NULL) { + free(s); + return ENOMEM; + } + lock->password.val = d; + lock->password.val[lock->password.len] = s; + lock->password.len++; + + return 0; +} + +const struct _hx509_password * +_hx509_lock_get_passwords(hx509_lock lock) +{ + return &lock->password; +} + +hx509_certs +_hx509_lock_unlock_certs(hx509_lock lock) +{ + return lock->certs; +} + +void +hx509_lock_reset_passwords(hx509_lock lock) +{ + int i; + for (i = 0; i < lock->password.len; i++) + free(lock->password.val[i]); + free(lock->password.val); + lock->password.val = NULL; + lock->password.len = 0; +} + +int +hx509_lock_add_cert(hx509_context context, hx509_lock lock, hx509_cert cert) +{ + return hx509_certs_add(context, lock->certs, cert); +} + +int +hx509_lock_add_certs(hx509_context context, hx509_lock lock, hx509_certs certs) +{ + return hx509_certs_merge(context, lock->certs, certs); +} + +void +hx509_lock_reset_certs(hx509_context context, hx509_lock lock) +{ + hx509_certs certs = lock->certs; + int ret; + + ret = hx509_certs_init(context, + "MEMORY:locks-internal", + 0, + NULL, + &lock->certs); + if (ret == 0) + hx509_certs_free(&certs); + else + lock->certs = certs; +} + +int +_hx509_lock_find_cert(hx509_lock lock, const hx509_query *q, hx509_cert *c) +{ + *c = NULL; + return 0; +} + +int +hx509_lock_set_prompter(hx509_lock lock, hx509_prompter_fct prompt, void *data) +{ + lock->prompt = prompt; + lock->prompt_data = data; + return 0; +} + +void +hx509_lock_reset_promper(hx509_lock lock) +{ + lock->prompt = NULL; + lock->prompt_data = NULL; +} + +static int +default_prompter(void *data, const hx509_prompt *prompter) +{ + if (hx509_prompt_hidden(prompter->type)) { + if(UI_UTIL_read_pw_string(prompter->reply.data, + prompter->reply.length, + prompter->prompt, + 0)) + return 1; + } else { + char *s = prompter->reply.data; + + fputs (prompter->prompt, stdout); + fflush (stdout); + if(fgets(prompter->reply.data, + prompter->reply.length, + stdin) == NULL) + return 1; + s[strcspn(s, "\n")] = '\0'; + } + return 0; +} + +int +hx509_lock_prompt(hx509_lock lock, hx509_prompt *prompt) +{ + if (lock->prompt == NULL) + return HX509_CRYPTO_NO_PROMPTER; + return (*lock->prompt)(lock->prompt_data, prompt); +} + +void +hx509_lock_free(hx509_lock lock) +{ + hx509_certs_free(&lock->certs); + hx509_lock_reset_passwords(lock); + memset(lock, 0, sizeof(*lock)); + free(lock); +} + +int +hx509_prompt_hidden(hx509_prompt_type type) +{ + /* default to hidden if unknown */ + + switch (type) { + case HX509_PROMPT_TYPE_QUESTION: + case HX509_PROMPT_TYPE_INFO: + return 0; + default: + return 1; + } +} + +int +hx509_lock_command_string(hx509_lock lock, const char *string) +{ + if (strncasecmp(string, "PASS:", 5) == 0) { + hx509_lock_add_password(lock, string + 5); + } else if (strcasecmp(string, "PROMPT") == 0) { + hx509_lock_set_prompter(lock, default_prompter, NULL); + } else + return HX509_UNKNOWN_LOCK_COMMAND; + return 0; +} diff --git a/source4/heimdal/lib/hx509/name.c b/source4/heimdal/lib/hx509/name.c new file mode 100644 index 0000000000..92e9e6f974 --- /dev/null +++ b/source4/heimdal/lib/hx509/name.c @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: name.c,v 1.33 2006/12/30 23:04:11 lha Exp $"); + +/* + * name parsing from rfc2253 + * fix so parsing rfc1779 works too + * rfc3280 + */ + +static const struct { + char *n; + const heim_oid *(*o)(void); +} no[] = { + { "C", oid_id_at_countryName }, + { "CN", oid_id_at_commonName }, + { "DC", oid_id_domainComponent }, + { "L", oid_id_at_localityName }, + { "O", oid_id_at_organizationName }, + { "OU", oid_id_at_organizationalUnitName }, + { "S", oid_id_at_stateOrProvinceName }, + { "UID", oid_id_Userid }, + { "emailAddress", oid_id_pkcs9_emailAddress }, + { "serialNumber", oid_id_at_serialNumber } +}; + +static char * +quote_string(const char *f, size_t len, size_t *rlen) +{ + size_t i, j, tolen; + const char *from = f; + char *to; + + tolen = len * 3 + 1; + to = malloc(tolen); + if (to == NULL) + return NULL; + + for (i = 0, j = 0; i < len; i++) { + if (from[i] == ' ' && i + 1 < len) + to[j++] = from[i]; + else if (from[i] == ',' || from[i] == '=' || from[i] == '+' || + from[i] == '<' || from[i] == '>' || from[i] == '#' || + from[i] == ';' || from[i] == ' ') + { + to[j++] = '\\'; + to[j++] = from[i]; + } else if (((unsigned char)from[i]) >= 32 && ((unsigned char)from[i]) <= 127) { + to[j++] = from[i]; + } else { + int l = snprintf(&to[j], tolen - j - 1, + "#%02x", (unsigned int)from[i]); + j += l; + } + } + to[j] = '\0'; + *rlen = j; + return to; +} + + +static int +append_string(char **str, size_t *total_len, char *ss, size_t len, int quote) +{ + char *s, *qs; + + if (quote) + qs = quote_string(ss, len, &len); + else + qs = ss; + + s = realloc(*str, len + *total_len + 1); + if (s == NULL) + _hx509_abort("allocation failure"); /* XXX */ + memcpy(s + *total_len, qs, len); + if (qs != ss) + free(qs); + s[*total_len + len] = '\0'; + *str = s; + *total_len += len; + return 0; +} + +static char * +oidtostring(const heim_oid *type) +{ + char *s; + size_t i; + + for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { + if (der_heim_oid_cmp((*no[i].o)(), type) == 0) + return strdup(no[i].n); + } + if (der_print_heim_oid(type, '.', &s) != 0) + return NULL; + return s; +} + +static int +stringtooid(const char *name, size_t len, heim_oid *oid) +{ + int i, ret; + char *s; + + memset(oid, 0, sizeof(*oid)); + + for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { + if (strncasecmp(no[i].n, name, len) == 0) + return der_copy_oid((*no[i].o)(), oid); + } + s = malloc(len + 1); + if (s == NULL) + return ENOMEM; + memcpy(s, name, len); + s[len] = '\0'; + ret = der_parse_heim_oid(s, ".", oid); + free(s); + return ret; +} + +int +hx509_name_to_string(const hx509_name name, char **str) +{ + return _hx509_Name_to_string(&name->der_name, str); +} + +int +_hx509_Name_to_string(const Name *n, char **str) +{ + size_t total_len = 0; + int i, j; + + *str = strdup(""); + if (*str == NULL) + return ENOMEM; + + for (i = n->u.rdnSequence.len - 1 ; i >= 0 ; i--) { + int len; + + for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { + DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; + char *oidname; + char *ss; + + oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type); + + switch(ds->element) { + case choice_DirectoryString_ia5String: + ss = ds->u.ia5String; + break; + case choice_DirectoryString_printableString: + ss = ds->u.ia5String; + break; + case choice_DirectoryString_utf8String: + ss = ds->u.ia5String; + break; + case choice_DirectoryString_bmpString: { + uint16_t *bmp = ds->u.bmpString.data; + size_t bmplen = ds->u.bmpString.length; + size_t k; + + ss = malloc(bmplen + 1); + if (ss == NULL) + _hx509_abort("allocation failure"); /* XXX */ + for (k = 0; k < bmplen; k++) + ss[k] = bmp[k] & 0xff; /* XXX */ + ss[k] = '\0'; + break; + } + case choice_DirectoryString_teletexString: + ss = "teletex-string"; /* XXX */ + break; + case choice_DirectoryString_universalString: + ss = "universalString"; /* XXX */ + break; + default: + _hx509_abort("unknown directory type: %d", ds->element); + exit(1); + } + append_string(str, &total_len, oidname, strlen(oidname), 0); + free(oidname); + append_string(str, &total_len, "=", 1, 0); + len = strlen(ss); + append_string(str, &total_len, ss, len, 1); + if (ds->element == choice_DirectoryString_bmpString) + free(ss); + if (j + 1 < n->u.rdnSequence.val[i].len) + append_string(str, &total_len, "+", 1, 0); + } + + if (i > 0) + append_string(str, &total_len, ",", 1, 0); + } + return 0; +} + +/* + * XXX this function is broken, it needs to compare code points, not + * bytes. + */ + +int +_hx509_name_ds_cmp(const DirectoryString *ds1, const DirectoryString *ds2) +{ + int c; + + c = ds1->element - ds2->element; + if (c) + return c; + + switch(ds1->element) { + case choice_DirectoryString_ia5String: + c = strcmp(ds1->u.ia5String, ds2->u.ia5String); + break; + case choice_DirectoryString_teletexString: + c = der_heim_octet_string_cmp(&ds1->u.teletexString, + &ds2->u.teletexString); + break; + case choice_DirectoryString_printableString: + c = strcasecmp(ds1->u.printableString, ds2->u.printableString); + break; + case choice_DirectoryString_utf8String: + c = strcmp(ds1->u.utf8String, ds2->u.utf8String); + break; + case choice_DirectoryString_universalString: + c = der_heim_universal_string_cmp(&ds1->u.universalString, + &ds2->u.universalString); + break; + case choice_DirectoryString_bmpString: + c = der_heim_bmp_string_cmp(&ds1->u.bmpString, + &ds2->u.bmpString); + break; + default: + c = 1; + break; + } + return c; +} + +int +_hx509_name_cmp(const Name *n1, const Name *n2) +{ + int i, j, c; + + c = n1->u.rdnSequence.len - n2->u.rdnSequence.len; + if (c) + return c; + + for (i = 0 ; i < n1->u.rdnSequence.len; i++) { + c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len; + if (c) + return c; + + for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) { + c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type, + &n1->u.rdnSequence.val[i].val[j].type); + if (c) + return c; + + c = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value, + &n2->u.rdnSequence.val[i].val[j].value); + if (c) + return c; + } + } + return 0; +} + +int +_hx509_name_from_Name(const Name *n, hx509_name *name) +{ + int ret; + *name = calloc(1, sizeof(**name)); + if (*name == NULL) + return ENOMEM; + ret = copy_Name(n, &(*name)->der_name); + if (ret) { + free(*name); + *name = NULL; + } + return ret; +} + +static int +hx509_der_parse_name(const void *data, size_t length, hx509_name *name) +{ + int ret; + Name n; + + *name = NULL; + ret = decode_Name(data, length, &n, NULL); + if (ret) + return ret; + return _hx509_name_from_Name(&n, name); +} + +int +_hx509_name_modify(hx509_context context, + Name *name, + int append, + const heim_oid *oid, + const char *str) +{ + RelativeDistinguishedName *rdn; + int ret; + void *ptr; + + ptr = realloc(name->u.rdnSequence.val, + sizeof(name->u.rdnSequence.val[0]) * + (name->u.rdnSequence.len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); + return ENOMEM; + } + name->u.rdnSequence.val = ptr; + + if (append) { + rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len]; + } else { + memmove(&name->u.rdnSequence.val[1], + &name->u.rdnSequence.val[0], + name->u.rdnSequence.len * + sizeof(name->u.rdnSequence.val[0])); + + rdn = &name->u.rdnSequence.val[0]; + } + rdn->val = malloc(sizeof(rdn->val[0])); + if (rdn->val == NULL) + return ENOMEM; + rdn->len = 1; + ret = der_copy_oid(oid, &rdn->val[0].type); + if (ret) + return ret; + rdn->val[0].value.element = choice_DirectoryString_utf8String; + rdn->val[0].value.u.utf8String = strdup(str); + if (rdn->val[0].value.u.utf8String == NULL) + return ENOMEM; + name->u.rdnSequence.len += 1; + + return 0; +} + +int +hx509_parse_name(hx509_context context, const char *str, hx509_name *name) +{ + const char *p, *q; + size_t len; + hx509_name n; + int ret; + + *name = NULL; + + n = calloc(1, sizeof(*n)); + if (n == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + n->der_name.element = choice_Name_rdnSequence; + + p = str; + + while (p != NULL && *p != '\0') { + heim_oid oid; + int last; + + q = strchr(p, ','); + if (q) { + len = (q - p); + last = 1; + } else { + len = strlen(p); + last = 0; + } + + q = strchr(p, '='); + if (q == NULL) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, "missing = in %s", p); + goto out; + } + if (q == p) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, + "missing name before = in %s", p); + goto out; + } + + if ((q - p) > len) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, " = after , in %s", p); + goto out; + } + + ret = stringtooid(p, q - p, &oid); + if (ret) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, + "unknown type: %.*s", (int)(q - p), p); + goto out; + } + + { + size_t pstr_len = len - (q - p) - 1; + const char *pstr = p + (q - p) + 1; + char *r; + + r = malloc(pstr_len + 1); + if (r == NULL) { + der_free_oid(&oid); + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + memcpy(r, pstr, pstr_len); + r[pstr_len] = '\0'; + + ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r); + free(r); + der_free_oid(&oid); + if(ret) + goto out; + } + p += len + last; + } + + *name = n; + + return 0; +out: + hx509_name_free(&n); + return HX509_NAME_MALFORMED; +} + +int +hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to) +{ + int ret; + + *to = calloc(1, sizeof(**to)); + if (*to == NULL) + return ENOMEM; + ret = copy_Name(&from->der_name, &(*to)->der_name); + if (ret) { + free(*to); + *to = NULL; + return ENOMEM; + } + return 0; +} + +int +hx509_name_to_Name(const hx509_name from, Name *to) +{ + return copy_Name(&from->der_name, to); +} + + +void +hx509_name_free(hx509_name *name) +{ + free_Name(&(*name)->der_name); + memset(*name, 0, sizeof(**name)); + free(*name); + *name = NULL; +} + +int +hx509_unparse_der_name(const void *data, size_t length, char **str) +{ + hx509_name name; + int ret; + + ret = hx509_der_parse_name(data, length, &name); + if (ret) + return ret; + + ret = hx509_name_to_string(name, str); + hx509_name_free(&name); + return ret; +} + +int +hx509_name_to_der_name(const hx509_name name, void **data, size_t *length) +{ + size_t size; + int ret; + + ASN1_MALLOC_ENCODE(Name, *data, *length, &name->der_name, &size, ret); + if (ret) + return ret; + if (*length != size) + _hx509_abort("internal ASN.1 encoder error"); + + return 0; +} + + +int +_hx509_unparse_Name(const Name *aname, char **str) +{ + hx509_name name; + int ret; + + ret = _hx509_name_from_Name(aname, &name); + if (ret) + return ret; + + ret = hx509_name_to_string(name, str); + hx509_name_free(&name); + return ret; +} + +int +hx509_name_is_null_p(const hx509_name name) +{ + return name->der_name.u.rdnSequence.len == 0; +} diff --git a/source4/heimdal/lib/hx509/ocsp.asn1 b/source4/heimdal/lib/hx509/ocsp.asn1 new file mode 100644 index 0000000000..62a2750b96 --- /dev/null +++ b/source4/heimdal/lib/hx509/ocsp.asn1 @@ -0,0 +1,113 @@ +-- From rfc2560 +-- $Id: ocsp.asn1,v 1.4 2006/12/30 12:38:44 lha Exp $ +OCSP DEFINITIONS EXPLICIT TAGS::= + +BEGIN + +IMPORTS + Certificate, AlgorithmIdentifier, CRLReason, + Name, GeneralName, CertificateSerialNumber, Extensions + FROM rfc2459; + +OCSPVersion ::= INTEGER { ocsp-v1(0) } + +OCSPCertStatus ::= CHOICE { + good [0] IMPLICIT NULL, + revoked [1] IMPLICIT -- OCSPRevokedInfo -- SEQUENCE { + revocationTime GeneralizedTime, + revocationReason[0] EXPLICIT CRLReason OPTIONAL + }, + unknown [2] IMPLICIT NULL } + +OCSPCertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, -- Hash of Issuer's DN + issuerKeyHash OCTET STRING, -- Hash of Issuers public key + serialNumber CertificateSerialNumber } + +OCSPSingleResponse ::= SEQUENCE { + certID OCSPCertID, + certStatus OCSPCertStatus, + thisUpdate GeneralizedTime, + nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + singleExtensions [1] EXPLICIT Extensions OPTIONAL } + +OCSPInnerRequest ::= SEQUENCE { + reqCert OCSPCertID, + singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + +OCSPTBSRequest ::= SEQUENCE { + version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL, + requestorName [1] EXPLICIT GeneralName OPTIONAL, + requestList SEQUENCE OF OCSPInnerRequest, + requestExtensions [2] EXPLICIT Extensions OPTIONAL } + +OCSPSignature ::= SEQUENCE { + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +OCSPRequest ::= SEQUENCE { + tbsRequest OCSPTBSRequest, + optionalSignature [0] EXPLICIT OCSPSignature OPTIONAL } + +OCSPResponseBytes ::= SEQUENCE { + responseType OBJECT IDENTIFIER, + response OCTET STRING } + +OCSPResponseStatus ::= ENUMERATED { + successful (0), --Response has valid confirmations + malformedRequest (1), --Illegal confirmation request + internalError (2), --Internal error in issuer + tryLater (3), --Try again later + --(4) is not used + sigRequired (5), --Must sign the request + unauthorized (6) --Request unauthorized +} + +OCSPResponse ::= SEQUENCE { + responseStatus OCSPResponseStatus, + responseBytes [0] EXPLICIT OCSPResponseBytes OPTIONAL } + +OCSPKeyHash ::= OCTET STRING --SHA-1 hash of responder's public key + --(excluding the tag and length fields) + +OCSPResponderID ::= CHOICE { + byName [1] Name, + byKey [2] OCSPKeyHash } + +OCSPResponseData ::= SEQUENCE { + version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL, + responderID OCSPResponderID, + producedAt GeneralizedTime, + responses SEQUENCE OF OCSPSingleResponse, + responseExtensions [1] EXPLICIT Extensions OPTIONAL } + +OCSPBasicOCSPResponse ::= SEQUENCE { + tbsResponseData OCSPResponseData, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +-- ArchiveCutoff ::= GeneralizedTime + +-- AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER + +-- Object Identifiers + +id-pkix-ocsp OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) pkix-ad(48) 1 +} + +id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } +id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 } +-- id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 } +-- id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 } +-- id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 } +-- id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 } +-- id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 } + + +END + diff --git a/source4/heimdal/lib/hx509/peer.c b/source4/heimdal/lib/hx509/peer.c new file mode 100644 index 0000000000..f82f2877f6 --- /dev/null +++ b/source4/heimdal/lib/hx509/peer.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: peer.c,v 1.1 2006/11/26 15:49:01 lha Exp $"); + +int +hx509_peer_info_alloc(hx509_context context, hx509_peer_info *peer) +{ + *peer = calloc(1, sizeof(**peer)); + if (*peer == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + return 0; +} + + +static void +free_cms_alg(hx509_peer_info peer) +{ + if (peer->val) { + size_t i; + for (i = 0; i < peer->len; i++) + free_AlgorithmIdentifier(&peer->val[i]); + free(peer->val); + peer->val = NULL; + peer->len = 0; + } +} + +int +hx509_peer_info_free(hx509_peer_info peer) +{ + if (peer->cert) + hx509_cert_free(peer->cert); + free_cms_alg(peer); + memset(peer, 0, sizeof(*peer)); + return 0; +} + +int +hx509_peer_info_set_cert(hx509_peer_info peer, + hx509_cert cert) +{ + if (peer->cert) + hx509_cert_free(peer->cert); + peer->cert = hx509_cert_ref(cert); + return 0; +} + +int +hx509_peer_info_set_cms_algs(hx509_context context, + hx509_peer_info peer, + const AlgorithmIdentifier *val, + size_t len) +{ + size_t i; + + free_cms_alg(peer); + + peer->val = calloc(len, sizeof(*peer->val)); + if (peer->val == NULL) { + peer->len = 0; + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + peer->len = len; + for (i = 0; i < len; i++) { + int ret; + ret = copy_AlgorithmIdentifier(&val[i], &peer->val[i]); + if (ret) { + hx509_clear_error_string(context); + free_cms_alg(peer); + return ret; + } + } + return 0; +} + +#if 0 + +/* + * S/MIME + */ + +int +hx509_peer_info_parse_smime(hx509_peer_info peer, + const heim_octet_string *data) +{ + return 0; +} + +int +hx509_peer_info_unparse_smime(hx509_peer_info peer, + heim_octet_string *data) +{ + return 0; +} + +/* + * For storing hx509_peer_info to be able to cache them. + */ + +int +hx509_peer_info_parse(hx509_peer_info peer, + const heim_octet_string *data) +{ + return 0; +} + +int +hx509_peer_info_unparse(hx509_peer_info peer, + heim_octet_string *data) +{ + return 0; +} +#endif diff --git a/source4/heimdal/lib/hx509/pkcs10.asn1 b/source4/heimdal/lib/hx509/pkcs10.asn1 new file mode 100644 index 0000000000..c33fd36cb2 --- /dev/null +++ b/source4/heimdal/lib/hx509/pkcs10.asn1 @@ -0,0 +1,25 @@ +-- $Id: pkcs10.asn1,v 1.1 2006/04/01 09:46:57 lha Exp $ +PKCS10 DEFINITIONS ::= + +BEGIN + +IMPORTS + Name, SubjectPublicKeyInfo, Attribute, AlgorithmIdentifier + FROM rfc2459; + + +CertificationRequestInfo ::= SEQUENCE { + version INTEGER { pkcs10-v1(0) }, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] IMPLICIT SET OF Attribute OPTIONAL +} + +CertificationRequest ::= SEQUENCE { + certificationRequestInfo CertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +END + diff --git a/source4/heimdal/lib/hx509/print.c b/source4/heimdal/lib/hx509/print.c new file mode 100644 index 0000000000..802ac12b4e --- /dev/null +++ b/source4/heimdal/lib/hx509/print.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: print.c,v 1.15 2006/12/07 20:37:57 lha Exp $"); + + +struct hx509_validate_ctx_data { + int flags; + hx509_vprint_func vprint_func; + void *ctx; +}; + +/* + * + */ + +static int +Time2string(const Time *T, char **str) +{ + time_t t; + char *s; + struct tm *tm; + + *str = NULL; + t = _hx509_Time2time_t(T); + tm = gmtime (&t); + s = malloc(30); + if (s == NULL) + return ENOMEM; + strftime(s, 30, "%Y-%m-%d %H:%M:%S", tm); + *str = s; + return 0; +} + +void +hx509_print_stdout(void *ctx, const char *fmt, va_list va) +{ + FILE *f = ctx; + vfprintf(f, fmt, va); +} + +void +hx509_print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + (*func)(ctx, fmt, va); + va_end(va); +} + +int +hx509_oid_sprint(const heim_oid *oid, char **str) +{ + return der_print_heim_oid(oid, '.', str); +} + +void +hx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx) +{ + char *str; + hx509_oid_sprint(oid, &str); + hx509_print_func(func, ctx, "%s", str); + free(str); +} + +void +hx509_bitstring_print(const heim_bit_string *b, + hx509_vprint_func func, void *ctx) +{ + int i; + hx509_print_func(func, ctx, "\tlength: %d\n\t", b->length); + for (i = 0; i < (b->length + 7) / 8; i++) + hx509_print_func(func, ctx, "%02x%s%s", + ((unsigned char *)b->data)[i], + i < (b->length - 7) / 8 + && (i == 0 || (i % 16) != 15) ? ":" : "", + i != 0 && (i % 16) == 15 ? + (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):""); +} + +int +hx509_cert_keyusage_print(hx509_context context, hx509_cert c, char **s) +{ + KeyUsage ku; + char buf[256]; + int ret; + + *s = NULL; + + ret = _hx509_cert_get_keyusage(context, c, &ku); + if (ret) + return ret; + unparse_flags(KeyUsage2int(ku), asn1_KeyUsage_units(), buf, sizeof(buf)); + *s = strdup(buf); + if (*s == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + return 0; +} + +/* + * + */ + +static void +validate_vprint(void *c, const char *fmt, va_list va) +{ + hx509_validate_ctx ctx = c; + if (ctx->vprint_func == NULL) + return; + (ctx->vprint_func)(ctx->ctx, fmt, va); +} + +static void +validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...) +{ + va_list va; + if ((ctx->flags & flags) == 0) + return; + va_start(va, fmt); + validate_vprint(ctx, fmt, va); + va_end(va); +} + +enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C }; + +static int +check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e) +{ + switch(cf) { + case D_C: + break; + case S_C: + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical not set on SHOULD\n"); + break; + case S_N_C: + if (e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical set on SHOULD NOT\n"); + break; + case M_C: + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical not set on MUST\n"); + break; + case M_N_C: + if (e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical set on MUST NOT\n"); + break; + default: + _hx509_abort("internal check_Null state error"); + } + return 0; +} + +static int +check_subjectKeyIdentifier(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *e) +{ + check_Null(ctx, cf, e); + return 0; +} + +static int +check_pkinit_san(hx509_validate_ctx ctx, heim_any *a) +{ + KRB5PrincipalName kn; + unsigned i; + size_t size; + int ret; + + ret = decode_KRB5PrincipalName(a->data, a->length, + &kn, &size); + if (ret) { + printf("Decoding kerberos name in SAN failed: %d", ret); + return 1; + } + + if (size != a->length) { + printf("Decoding kerberos name have extra bits on the end"); + return 1; + } + + /* print kerberos principal, add code to quote / within components */ + for (i = 0; i < kn.principalName.name_string.len; i++) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", + kn.principalName.name_string.val[i]); + if (i + 1 < kn.principalName.name_string.len) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "/"); + } + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "@"); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", kn.realm); + + free_KRB5PrincipalName(&kn); + return 0; +} + +static int +check_dnssrv_san(hx509_validate_ctx ctx, heim_any *a) +{ + return 0; +} + +struct { + const char *name; + const heim_oid *(*oid)(void); + int (*func)(hx509_validate_ctx, heim_any *); +} check_altname[] = { + { "pk-init", oid_id_pkinit_san, check_pkinit_san }, + { "dns-srv", oid_id_pkix_on_dnsSRV, check_dnssrv_san } +}; + +static int +check_altName(hx509_validate_ctx ctx, + const char *name, + enum critical_flag cf, + const Extension *e) +{ + GeneralNames gn; + size_t size; + int ret, i; + + check_Null(ctx, cf, e); + + if (e->extnValue.length == 0) { + printf("%sAltName empty, not allowed", name); + return 1; + } + ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length, + &gn, &size); + if (ret) { + printf("\tret = %d while decoding %s GeneralNames\n", ret, name); + return 1; + } + if (gn.len == 0) { + printf("%sAltName generalName empty, not allowed", name); + return 1; + } + + for (i = 0; i < gn.len; i++) { + switch (gn.val[i].element) { + case choice_GeneralName_otherName: { + unsigned j; + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%sAltName otherName ", name); + + for (j = 0; j < sizeof(check_altname)/sizeof(check_altname[0]); j++) { + if (der_heim_oid_cmp((*check_altname[j].oid)(), + &gn.val[i].u.otherName.type_id) != 0) + continue; + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ", + check_altname[j].name); + (*check_altname[j].func)(ctx, &gn.val[i].u.otherName.value); + break; + } + if (j == sizeof(check_altname)/sizeof(check_altname[0])) { + hx509_oid_print(&gn.val[i].u.otherName.type_id, + validate_vprint, ctx); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown"); + } + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n"); + break; + } + case choice_GeneralName_rfc822Name: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "rfc822Name: %s\n", + gn.val[i].u.rfc822Name); + break; + case choice_GeneralName_dNSName: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "dNSName: %s\n", + gn.val[i].u.dNSName); + break; + case choice_GeneralName_directoryName: { + Name dir; + char *s; + dir.element = gn.val[i].u.directoryName.element; + dir.u.rdnSequence = gn.val[i].u.directoryName.u.rdnSequence; + ret = _hx509_unparse_Name(&dir, &s); + if (ret) { + printf("unable to parse %sAltName directoryName\n", name); + return 1; + } + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "directoryName: %s\n", s); + free(s); + break; + } + case choice_GeneralName_uniformResourceIdentifier: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "uri: %s\n", + gn.val[i].u.uniformResourceIdentifier); + break; + case choice_GeneralName_iPAddress: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "ip address\n"); + break; + case choice_GeneralName_registeredID: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "registered id: "); + hx509_oid_print(&gn.val[i].u.registeredID, + validate_vprint, ctx); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n"); + break; + } + } + + free_GeneralNames(&gn); + + return 0; +} + +static int +check_subjectAltName(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *e) +{ + return check_altName(ctx, "subject", cf, e); +} + +static int +check_issuerAltName(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *e) +{ + return check_altName(ctx, "issuer", cf, e); +} + + +static int +check_basicConstraints(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *e) +{ + BasicConstraints b; + size_t size; + int ret; + + check_Null(ctx, cf, e); + + ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length, + &b, &size); + if (ret) { + printf("\tret = %d while decoding BasicConstraints\n", ret); + return 0; + } + if (size != e->extnValue.length) + printf("\tlength of der data isn't same as extension\n"); + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT "); + if (b.pathLenConstraint) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tpathLenConstraint: %d\n", *b.pathLenConstraint); + + return 0; +} + +struct { + const char *name; + const heim_oid *(*oid)(void); + int (*func)(hx509_validate_ctx ctx, + enum critical_flag cf, + const Extension *); + enum critical_flag cf; +} check_extension[] = { +#define ext(name, checkname) #name, &oid_id_x509_ce_##name, check_##checkname + { ext(subjectDirectoryAttributes, Null), M_N_C }, + { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C }, + { ext(keyUsage, Null), S_C }, + { ext(subjectAltName, subjectAltName), M_N_C }, + { ext(issuerAltName, issuerAltName), S_N_C }, + { ext(basicConstraints, basicConstraints), M_C }, + { ext(cRLNumber, Null), M_N_C }, + { ext(cRLReason, Null), M_N_C }, + { ext(holdInstructionCode, Null), M_N_C }, + { ext(invalidityDate, Null), M_N_C }, + { ext(deltaCRLIndicator, Null), M_C }, + { ext(issuingDistributionPoint, Null), M_C }, + { ext(certificateIssuer, Null), M_C }, + { ext(nameConstraints, Null), M_C }, + { ext(cRLDistributionPoints, Null), S_N_C }, + { ext(certificatePolicies, Null) }, + { ext(policyMappings, Null), M_N_C }, + { ext(authorityKeyIdentifier, Null), M_N_C }, + { ext(policyConstraints, Null), D_C }, + { ext(extKeyUsage, Null), D_C }, + { ext(freshestCRL, Null), M_N_C }, + { ext(inhibitAnyPolicy, Null), M_C }, + { NULL } +}; + +int +hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx) +{ + *ctx = malloc(sizeof(**ctx)); + if (*ctx == NULL) + return ENOMEM; + memset(*ctx, 0, sizeof(**ctx)); + return 0; +} + +void +hx509_validate_ctx_set_print(hx509_validate_ctx ctx, + hx509_vprint_func func, + void *c) +{ + ctx->vprint_func = func; + ctx->ctx = c; +} + +void +hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags) +{ + ctx->flags |= flags; +} + +void +hx509_validate_ctx_free(hx509_validate_ctx ctx) +{ + free(ctx); +} + +int +hx509_validate_cert(hx509_context context, + hx509_validate_ctx ctx, + hx509_cert cert) +{ + Certificate *c = _hx509_get_cert(cert); + TBSCertificate *t = &c->tbsCertificate; + hx509_name name; + char *str; + + if (_hx509_cert_get_version(c) != 3) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Not version 3 certificate\n"); + + if (t->version && *t->version < 2 && t->extensions) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Not version 3 certificate with extensions\n"); + + _hx509_name_from_Name(&t->subject, &name); + hx509_name_to_string(name, &str); + hx509_name_free(&name); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "subject name: %s\n", str); + free(str); + + _hx509_name_from_Name(&t->issuer, &name); + hx509_name_to_string(name, &str); + hx509_name_free(&name); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "issuer name: %s\n", str); + free(str); + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Validity:\n"); + + Time2string(&t->validity.notBefore, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str); + free(str); + Time2string(&t->validity.notAfter, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str); + free(str); + + if (t->extensions) { + int i, j; + + if (t->extensions->len == 0) { + validate_print(ctx, + HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, + "The empty extensions list is not " + "allowed by PKIX\n"); + } + + for (i = 0; i < t->extensions->len; i++) { + + for (j = 0; check_extension[j].name; j++) + if (der_heim_oid_cmp((*check_extension[j].oid)(), + &t->extensions->val[i].extnID) == 0) + break; + if (check_extension[j].name == NULL) { + int flags = HX509_VALIDATE_F_VERBOSE; + if (t->extensions->val[i].critical) + flags |= HX509_VALIDATE_F_VALIDATE; + validate_print(ctx, flags, "don't know what "); + if (t->extensions->val[i].critical) + validate_print(ctx, flags, "and is CRITICAL "); + if (ctx->flags & flags) + hx509_oid_print(&t->extensions->val[i].extnID, + validate_vprint, ctx); + validate_print(ctx, flags, " is\n"); + continue; + } + validate_print(ctx, + HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, + "checking extention: %s\n", + check_extension[j].name); + (*check_extension[j].func)(ctx, + check_extension[j].cf, + &t->extensions->val[i]); + } + } else + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n"); + + return 0; +} diff --git a/source4/heimdal/lib/hx509/req.c b/source4/heimdal/lib/hx509/req.c new file mode 100644 index 0000000000..ca7baa514b --- /dev/null +++ b/source4/heimdal/lib/hx509/req.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#include <pkcs10_asn1.h> +RCSID("$Id: req.c,v 1.7 2007/01/04 20:20:11 lha Exp $"); + +struct hx509_request_data { + hx509_name name; + SubjectPublicKeyInfo key; + ExtKeyUsage eku; + GeneralNames san; +}; + +/* + * + */ + +int +_hx509_request_init(hx509_context context, hx509_request *req) +{ + *req = calloc(1, sizeof(**req)); + if (*req == NULL) + return ENOMEM; + + return 0; +} + +void +_hx509_request_free(hx509_request *req) +{ + if ((*req)->name) + hx509_name_free(&(*req)->name); + free_SubjectPublicKeyInfo(&(*req)->key); + free_ExtKeyUsage(&(*req)->eku); + free_GeneralNames(&(*req)->san); + memset(*req, 0, sizeof(**req)); + free(*req); + *req = NULL; +} + +int +_hx509_request_set_name(hx509_context context, + hx509_request req, + hx509_name name) +{ + if (req->name) + hx509_name_free(&req->name); + if (name) { + int ret = hx509_name_copy(context, name, &req->name); + if (ret) + return ret; + } + return 0; +} + +int +_hx509_request_set_SubjectPublicKeyInfo(hx509_context context, + hx509_request req, + const SubjectPublicKeyInfo *key) +{ + free_SubjectPublicKeyInfo(&req->key); + return copy_SubjectPublicKeyInfo(key, &req->key); +} + +int +_hx509_request_add_eku(hx509_context context, + hx509_request req, + const heim_oid *oid) +{ + void *val; + int ret; + + val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1)); + if (val == NULL) + return ENOMEM; + req->eku.val = val; + + ret = der_copy_oid(oid, &req->eku.val[req->eku.len]); + if (ret) + return ret; + + req->eku.len += 1; + + return 0; +} + +int +_hx509_request_add_dns_name(hx509_context context, + hx509_request req, + const char *hostname) +{ + GeneralName name; + + memset(&name, 0, sizeof(name)); + name.element = choice_GeneralName_dNSName; + name.u.dNSName = rk_UNCONST(hostname); + + return add_GeneralNames(&req->san, &name); +} + +int +_hx509_request_add_email(hx509_context context, + hx509_request req, + const char *email) +{ + GeneralName name; + + memset(&name, 0, sizeof(name)); + name.element = choice_GeneralName_rfc822Name; + name.u.dNSName = rk_UNCONST(email); + + return add_GeneralNames(&req->san, &name); +} + + + +int +_hx509_request_to_pkcs10(hx509_context context, + const hx509_request req, + const hx509_private_key signer, + heim_octet_string *request) +{ + CertificationRequest r; + heim_octet_string data, os; + int ret; + size_t size; + + if (req->name == NULL) { + hx509_set_error_string(context, 0, EINVAL, + "PKCS10 needs to have a subject"); + return EINVAL; + } + + memset(&r, 0, sizeof(r)); + memset(request, 0, sizeof(*request)); + + r.certificationRequestInfo.version = pkcs10_v1; + + ret = copy_Name(&req->name->der_name, + &r.certificationRequestInfo.subject); + if (ret) + goto out; + ret = copy_SubjectPublicKeyInfo(&req->key, + &r.certificationRequestInfo.subjectPKInfo); + if (ret) + goto out; + r.certificationRequestInfo.attributes = + calloc(1, sizeof(*r.certificationRequestInfo.attributes)); + if (r.certificationRequestInfo.attributes == NULL) { + ret = ENOMEM; + goto out; + } + + ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length, + &r.certificationRequestInfo, &size, ret); + if (ret) + goto out; + if (data.length != size) + abort(); + + ret = _hx509_create_signature(context, + signer, + hx509_signature_rsa_with_sha1(), + &data, + &r.signatureAlgorithm, + &os); + free(data.data); + if (ret) + goto out; + r.signature.data = os.data; + r.signature.length = os.length * 8; + + ASN1_MALLOC_ENCODE(CertificationRequest, data.data, data.length, + &r, &size, ret); + if (ret) + goto out; + if (data.length != size) + abort(); + + *request = data; + +out: + free_CertificationRequest(&r); + + return ret; +} diff --git a/source4/heimdal/lib/hx509/revoke.c b/source4/heimdal/lib/hx509/revoke.c new file mode 100644 index 0000000000..8067b29c10 --- /dev/null +++ b/source4/heimdal/lib/hx509/revoke.c @@ -0,0 +1,1020 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: revoke.c,v 1.32 2006/12/30 17:09:06 lha Exp $"); + +struct revoke_crl { + char *path; + time_t last_modfied; + CRLCertificateList crl; + int verified; +}; + +struct revoke_ocsp { + char *path; + time_t last_modfied; + OCSPBasicOCSPResponse ocsp; + hx509_certs certs; + hx509_cert signer; +}; + + +struct hx509_revoke_ctx_data { + struct { + struct revoke_crl *val; + size_t len; + } crls; + struct { + struct revoke_ocsp *val; + size_t len; + } ocsps; +}; + +int +hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx) +{ + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) + return ENOMEM; + + (*ctx)->crls.len = 0; + (*ctx)->crls.val = NULL; + (*ctx)->ocsps.len = 0; + (*ctx)->ocsps.val = NULL; + + return 0; +} + +static void +free_ocsp(struct revoke_ocsp *ocsp) +{ + free(ocsp->path); + free_OCSPBasicOCSPResponse(&ocsp->ocsp); + hx509_certs_free(&ocsp->certs); + hx509_cert_free(ocsp->signer); +} + +void +hx509_revoke_free(hx509_revoke_ctx *ctx) +{ + size_t i ; + + if (ctx == NULL || *ctx == NULL) + return; + + for (i = 0; i < (*ctx)->crls.len; i++) { + free((*ctx)->crls.val[i].path); + free_CRLCertificateList(&(*ctx)->crls.val[i].crl); + } + + for (i = 0; i < (*ctx)->ocsps.len; i++) + free_ocsp(&(*ctx)->ocsps.val[i]); + free((*ctx)->ocsps.val); + + free((*ctx)->crls.val); + + memset(*ctx, 0, sizeof(**ctx)); + free(*ctx); + *ctx = NULL; +} + +static int +verify_ocsp(hx509_context context, + struct revoke_ocsp *ocsp, + time_t time_now, + hx509_certs certs, + hx509_cert parent) +{ + hx509_cert signer = NULL; + hx509_query q; + int ret; + + _hx509_query_clear(&q); + + /* + * Need to match on issuer too in case there are two CA that have + * issued the same name to a certificate. One example of this is + * the www.openvalidation.org test's ocsp validator. + */ + + q.match = HX509_QUERY_MATCH_ISSUER_NAME; + q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer; + + switch(ocsp->ocsp.tbsResponseData.responderID.element) { + case choice_OCSPResponderID_byName: + q.match |= HX509_QUERY_MATCH_SUBJECT_NAME; + q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName; + break; + case choice_OCSPResponderID_byKey: + q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1; + q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey; + break; + } + + ret = hx509_certs_find(context, certs, &q, &signer); + if (ret && ocsp->certs) + ret = hx509_certs_find(context, ocsp->certs, &q, &signer); + if (ret) + goto out; + + /* + * If signer certificate isn't the CA certificate, lets check the + * its the CA that signed the signer certificate and the OCSP EKU + * is set. + */ + if (hx509_cert_cmp(signer, parent) != 0) { + Certificate *p = _hx509_get_cert(parent); + Certificate *s = _hx509_get_cert(signer); + + ret = _hx509_cert_is_parent_cmp(s, p, 0); + if (ret != 0) { + ret = HX509_PARENT_NOT_CA; + hx509_set_error_string(context, 0, ret, "Revoke OSCP signer is " + "doesn't have CA as signer certificate"); + goto out; + } + + ret = _hx509_verify_signature_bitstring(context, + p, + &s->signatureAlgorithm, + &s->tbsCertificate._save, + &s->signatureValue); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "OSCP signer signature invalid"); + goto out; + } + + ret = hx509_cert_check_eku(context, signer, + oid_id_pkix_kp_OCSPSigning(), 0); + if (ret) + goto out; + } + + ret = _hx509_verify_signature_bitstring(context, + _hx509_get_cert(signer), + &ocsp->ocsp.signatureAlgorithm, + &ocsp->ocsp.tbsResponseData._save, + &ocsp->ocsp.signature); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "OSCP signature invalid"); + goto out; + } + + ocsp->signer = signer; + signer = NULL; +out: + if (signer) + hx509_cert_free(signer); + + return ret; +} + +/* + * + */ + +static int +parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic) +{ + OCSPResponse resp; + size_t size; + int ret; + + memset(basic, 0, sizeof(*basic)); + + ret = decode_OCSPResponse(data, length, &resp, &size); + if (ret) + return ret; + if (length != size) { + free_OCSPResponse(&resp); + return ASN1_EXTRA_DATA; + } + + switch (resp.responseStatus) { + case successful: + break; + default: + free_OCSPResponse(&resp); + return HX509_REVOKE_WRONG_DATA; + } + + if (resp.responseBytes == NULL) { + free_OCSPResponse(&resp); + return EINVAL; + } + + ret = der_heim_oid_cmp(&resp.responseBytes->responseType, + oid_id_pkix_ocsp_basic()); + if (ret != 0) { + free_OCSPResponse(&resp); + return HX509_REVOKE_WRONG_DATA; + } + + ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data, + resp.responseBytes->response.length, + basic, + &size); + if (ret) { + free_OCSPResponse(&resp); + return ret; + } + if (size != resp.responseBytes->response.length) { + free_OCSPResponse(&resp); + free_OCSPBasicOCSPResponse(basic); + return ASN1_EXTRA_DATA; + } + free_OCSPResponse(&resp); + + return 0; +} + +/* + * + */ + +static int +load_ocsp(hx509_context context, struct revoke_ocsp *ocsp) +{ + OCSPBasicOCSPResponse basic; + hx509_certs certs = NULL; + size_t length; + struct stat sb; + void *data; + int ret; + + ret = _hx509_map_file(ocsp->path, &data, &length, &sb); + if (ret) + return ret; + + ret = parse_ocsp_basic(data, length, &basic); + _hx509_unmap_file(data, length); + if (ret) + return ret; + + if (basic.certs) { + int i; + + ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, + NULL, &certs); + if (ret) { + free_OCSPBasicOCSPResponse(&basic); + return ret; + } + + for (i = 0; i < basic.certs->len; i++) { + hx509_cert c; + + ret = hx509_cert_init(context, &basic.certs->val[i], &c); + if (ret) + continue; + + ret = hx509_certs_add(context, certs, c); + hx509_cert_free(c); + if (ret) + continue; + } + } + + ocsp->last_modfied = sb.st_mtime; + + free_OCSPBasicOCSPResponse(&ocsp->ocsp); + hx509_certs_free(&ocsp->certs); + hx509_cert_free(ocsp->signer); + + ocsp->ocsp = basic; + ocsp->certs = certs; + ocsp->signer = NULL; + + return 0; +} + +int +hx509_revoke_add_ocsp(hx509_context context, + hx509_revoke_ctx ctx, + const char *path) +{ + void *data; + int ret; + size_t i; + + if (strncmp(path, "FILE:", 5) != 0) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "unsupport type in %s", path); + return HX509_UNSUPPORTED_OPERATION; + } + + path += 5; + + for (i = 0; i < ctx->ocsps.len; i++) { + if (strcmp(ctx->ocsps.val[0].path, path) == 0) + return 0; + } + + data = realloc(ctx->ocsps.val, + (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0])); + if (data == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ctx->ocsps.val = data; + + memset(&ctx->ocsps.val[ctx->ocsps.len], 0, + sizeof(ctx->ocsps.val[0])); + + ctx->ocsps.val[ctx->ocsps.len].path = strdup(path); + if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]); + if (ret) { + free(ctx->ocsps.val[ctx->ocsps.len].path); + return ret; + } + ctx->ocsps.len++; + + return ret; +} + +/* + * + */ + +static int +verify_crl(hx509_context context, + CRLCertificateList *crl, + time_t time_now, + hx509_certs certs, + hx509_cert parent) +{ + hx509_cert signer; + hx509_query q; + time_t t; + int ret; + + t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate); + if (t > time_now) + return HX509_CRL_USED_BEFORE_TIME; + + if (crl->tbsCertList.nextUpdate == NULL) + return HX509_CRL_INVALID_FORMAT; + + t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate); + if (t < time_now) + return HX509_CRL_USED_AFTER_TIME; + + _hx509_query_clear(&q); + + q.match = HX509_QUERY_MATCH_SUBJECT_NAME; + q.subject_name = &crl->tbsCertList.issuer; + + ret = hx509_certs_find(context, certs, &q, &signer); + if (ret) + return ret; + + /* verify is parent or CRLsigner */ + if (hx509_cert_cmp(signer, parent) != 0) { + Certificate *p = _hx509_get_cert(parent); + Certificate *s = _hx509_get_cert(signer); + + ret = _hx509_cert_is_parent_cmp(s, p, 0); + if (ret != 0) { + ret = HX509_PARENT_NOT_CA; + hx509_set_error_string(context, 0, ret, "Revoke CRL signer is " + "doesn't have CA as signer certificate"); + goto out; + } + + ret = _hx509_verify_signature_bitstring(context, + p, + &s->signatureAlgorithm, + &s->tbsCertificate._save, + &s->signatureValue); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "CRL signer signature invalid"); + goto out; + } + + ret = _hx509_check_key_usage(context, signer, 1 << 6, TRUE); /* crl */ + if (ret != 0) + goto out; + } + + ret = _hx509_verify_signature_bitstring(context, + _hx509_get_cert(signer), + &crl->signatureAlgorithm, + &crl->tbsCertList._save, + &crl->signatureValue); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "CRL signature invalid"); + goto out; + } + +out: + hx509_cert_free(signer); + + return ret; +} + +static int +load_crl(const char *path, time_t *t, CRLCertificateList *crl) +{ + size_t length, size; + struct stat sb; + void *data; + int ret; + + memset(crl, 0, sizeof(*crl)); + + ret = _hx509_map_file(path, &data, &length, &sb); + if (ret) + return ret; + + *t = sb.st_mtime; + + ret = decode_CRLCertificateList(data, length, crl, &size); + _hx509_unmap_file(data, length); + if (ret) + return ret; + + /* check signature is aligned */ + if (crl->signatureValue.length & 7) { + free_CRLCertificateList(crl); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + return 0; +} + +int +hx509_revoke_add_crl(hx509_context context, + hx509_revoke_ctx ctx, + const char *path) +{ + void *data; + size_t i; + int ret; + + if (strncmp(path, "FILE:", 5) != 0) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "unsupport type in %s", path); + return HX509_UNSUPPORTED_OPERATION; + } + + + path += 5; + + for (i = 0; i < ctx->crls.len; i++) { + if (strcmp(ctx->crls.val[0].path, path) == 0) + return 0; + } + + data = realloc(ctx->crls.val, + (ctx->crls.len + 1) * sizeof(ctx->crls.val[0])); + if (data == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + ctx->crls.val = data; + + memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0])); + + ctx->crls.val[ctx->crls.len].path = strdup(path); + if (ctx->crls.val[ctx->crls.len].path == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ret = load_crl(path, + &ctx->crls.val[ctx->crls.len].last_modfied, + &ctx->crls.val[ctx->crls.len].crl); + if (ret) { + free(ctx->crls.val[ctx->crls.len].path); + return ret; + } + + ctx->crls.len++; + + return ret; +} + + +int +hx509_revoke_verify(hx509_context context, + hx509_revoke_ctx ctx, + hx509_certs certs, + time_t now, + hx509_cert cert, + hx509_cert parent_cert) +{ + const Certificate *c = _hx509_get_cert(cert); + const Certificate *p = _hx509_get_cert(parent_cert); + unsigned long i, j, k; + int ret; + + for (i = 0; i < ctx->ocsps.len; i++) { + struct revoke_ocsp *ocsp = &ctx->ocsps.val[i]; + struct stat sb; + + /* check this ocsp apply to this cert */ + + /* check if there is a newer version of the file */ + ret = stat(ocsp->path, &sb); + if (ret == 0 && ocsp->last_modfied != sb.st_mtime) { + ret = load_ocsp(context, ocsp); + if (ret) + continue; + } + + /* verify signature in ocsp if not already done */ + if (ocsp->signer == NULL) { + ret = verify_ocsp(context, ocsp, now, certs, parent_cert); + if (ret) + continue; + } + + for (i = 0; i < ocsp->ocsp.tbsResponseData.responses.len; i++) { + heim_octet_string os; + + ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[i].certID.serialNumber, + &c->tbsCertificate.serialNumber); + if (ret != 0) + continue; + + /* verify issuer hashes hash */ + ret = _hx509_verify_signature(context, + NULL, + &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, + &c->tbsCertificate.issuer._save, + &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash); + if (ret != 0) + continue; + + os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_verify_signature(context, + NULL, + &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, + &os, + &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerKeyHash); + if (ret != 0) + continue; + + switch (ocsp->ocsp.tbsResponseData.responses.val[i].certStatus.element) { + case choice_OCSPCertStatus_good: + break; + case choice_OCSPCertStatus_revoked: + case choice_OCSPCertStatus_unknown: + continue; + } + + /* don't allow the update to be in the future */ + if (ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate > + now + context->ocsp_time_diff) + continue; + + /* don't allow the next updte to be in the past */ + if (ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate) { + if (*ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate < now) + continue; + } else + /* Should force a refetch, but can we ? */; + + return 0; + } + } + + for (i = 0; i < ctx->crls.len; i++) { + struct revoke_crl *crl = &ctx->crls.val[i]; + struct stat sb; + + /* check if cert.issuer == crls.val[i].crl.issuer */ + ret = _hx509_name_cmp(&c->tbsCertificate.issuer, + &crl->crl.tbsCertList.issuer); + if (ret) + continue; + + ret = stat(crl->path, &sb); + if (ret == 0 && crl->last_modfied != sb.st_mtime) { + CRLCertificateList cl; + + ret = load_crl(crl->path, &crl->last_modfied, &cl); + if (ret == 0) { + free_CRLCertificateList(&crl->crl); + crl->crl = cl; + crl->verified = 0; + } + } + + /* verify signature in crl if not already done */ + if (crl->verified == 0) { + ret = verify_crl(context, &crl->crl, now, certs, parent_cert); + if (ret) + return ret; + crl->verified = 1; + } + + if (crl->crl.tbsCertList.crlExtensions) + for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) + if (crl->crl.tbsCertList.crlExtensions->val[j].critical) + return HX509_CRL_UNKNOWN_EXTENSION; + + if (crl->crl.tbsCertList.revokedCertificates == NULL) + return 0; + + /* check if cert is in crl */ + for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) { + time_t t; + + ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate, + &c->tbsCertificate.serialNumber); + if (ret != 0) + continue; + + t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate); + if (t > now) + continue; + + if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions) + for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++) + if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical) + return HX509_CRL_UNKNOWN_EXTENSION; + + return HX509_CRL_CERT_REVOKED; + } + + return 0; + } + + + if (context->flags & HX509_CTX_VERIFY_MISSING_OK) + return 0; + return HX509_REVOKE_STATUS_MISSING; +} + +struct ocsp_add_ctx { + OCSPTBSRequest *req; + hx509_certs certs; + const AlgorithmIdentifier *digest; + hx509_cert parent; +}; + +static int +add_to_req(hx509_context context, void *ptr, hx509_cert cert) +{ + struct ocsp_add_ctx *ctx = ptr; + OCSPInnerRequest *one; + hx509_cert parent = NULL; + Certificate *p, *c = _hx509_get_cert(cert); + heim_octet_string os; + int ret; + hx509_query q; + void *d; + + d = realloc(ctx->req->requestList.val, + sizeof(ctx->req->requestList.val[0]) * + (ctx->req->requestList.len + 1)); + if (d == NULL) + return ENOMEM; + ctx->req->requestList.val = d; + + one = &ctx->req->requestList.val[ctx->req->requestList.len]; + memset(one, 0, sizeof(*one)); + + _hx509_query_clear(&q); + + q.match |= HX509_QUERY_FIND_ISSUER_CERT; + q.subject = c; + + ret = hx509_certs_find(context, ctx->certs, &q, &parent); + if (ret) + goto out; + + if (ctx->parent) { + if (hx509_cert_cmp(ctx->parent, parent) != 0) { + ret = HX509_REVOKE_NOT_SAME_PARENT; + hx509_set_error_string(context, 0, ret, + "Not same parent certifate as " + "last certificate in request"); + goto out; + } + } else + ctx->parent = hx509_cert_ref(parent); + + p = _hx509_get_cert(parent); + + ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); + if (ret) + goto out; + + ret = _hx509_create_signature(context, + NULL, + &one->reqCert.hashAlgorithm, + &c->tbsCertificate.issuer._save, + NULL, + &one->reqCert.issuerNameHash); + if (ret) + goto out; + + os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = + p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_create_signature(context, + NULL, + &one->reqCert.hashAlgorithm, + &os, + NULL, + &one->reqCert.issuerKeyHash); + if (ret) + goto out; + + ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, + &one->reqCert.serialNumber); + if (ret) + goto out; + + ctx->req->requestList.len++; +out: + hx509_cert_free(parent); + if (ret) { + free_OCSPInnerRequest(one); + memset(one, 0, sizeof(*one)); + } + + return ret; +} + + +int +hx509_ocsp_request(hx509_context context, + hx509_certs reqcerts, + hx509_certs pool, + hx509_cert signer, + const AlgorithmIdentifier *digest, + heim_octet_string *request, + heim_octet_string *nonce) +{ + OCSPRequest req; + size_t size; + int ret; + struct ocsp_add_ctx ctx; + Extensions *es; + + memset(&req, 0, sizeof(req)); + + if (digest == NULL) + digest = hx509_signature_sha1(); + + ctx.req = &req.tbsRequest; + ctx.certs = pool; + ctx.digest = digest; + ctx.parent = NULL; + + ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx); + hx509_cert_free(ctx.parent); + if (ret) { + free_OCSPRequest(&req); + return ret; + } + + if (nonce) { + + req.tbsRequest.requestExtensions = + calloc(1, sizeof(*req.tbsRequest.requestExtensions)); + if (req.tbsRequest.requestExtensions == NULL) { + free_OCSPRequest(&req); + return ENOMEM; + } + + es = req.tbsRequest.requestExtensions; + + es->len = 1; + es->val = calloc(es->len, sizeof(es->val[0])); + + ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID); + if (ret) + abort(); + + es->val[0].extnValue.data = malloc(10); + if (es->val[0].extnValue.data == NULL) { + free_OCSPRequest(&req); + return ENOMEM; + } + es->val[0].extnValue.length = 10; + + ret = RAND_bytes(es->val[0].extnValue.data, + es->val[0].extnValue.length); + if (ret != 1) { + free_OCSPRequest(&req); + return HX509_CRYPTO_INTERNAL_ERROR; + } + } + + ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length, + &req, &size, ret); + free_OCSPRequest(&req); + if (ret) + return ret; + if (size != request->length) + _hx509_abort("internal ASN.1 encoder error"); + + + return 0; +} + +static char * +printable_time(time_t t) +{ + static char s[128]; + strlcpy(s, ctime(&t)+ 4, sizeof(s)); + s[20] = 0; + return s; +} + +int +hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) +{ + struct revoke_ocsp ocsp; + int ret, i; + + if (out == NULL) + out = stdout; + + memset(&ocsp, 0, sizeof(ocsp)); + + ocsp.path = strdup(path); + if (ocsp.path == NULL) + return ENOMEM; + + ret = load_ocsp(context, &ocsp); + if (ret) { + free_ocsp(&ocsp); + return ret; + } + + fprintf(out, "signer: "); + + switch(ocsp.ocsp.tbsResponseData.responderID.element) { + case choice_OCSPResponderID_byName: { + hx509_name n; + char *s; + _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n); + hx509_name_to_string(n, &s); + hx509_name_free(&n); + fprintf(out, " byName: %s\n", s); + free(s); + break; + } + case choice_OCSPResponderID_byKey: { + char *s; + hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data, + ocsp.ocsp.tbsResponseData.responderID.u.byKey.length, + &s); + fprintf(out, " byKey: %s\n", s); + free(s); + break; + } + default: + _hx509_abort("choice_OCSPResponderID unknown"); + break; + } + + fprintf(out, "producedAt: %s\n", + printable_time(ocsp.ocsp.tbsResponseData.producedAt)); + + fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); + + for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { + char *status; + switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { + case choice_OCSPCertStatus_good: + status = "good"; + break; + case choice_OCSPCertStatus_revoked: + status = "revoked"; + break; + case choice_OCSPCertStatus_unknown: + status = "unknown"; + break; + default: + status = "element unknown"; + } + + fprintf(out, "\t%d. status: %s\n", i, status); + + fprintf(out, "\tthisUpdate: %s\n", + printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); + if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate) + fprintf(out, "\tproducedAt: %s\n", + printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); + + } + + fprintf(out, "appended certs:\n"); + if (ocsp.certs) + ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out); + + free_ocsp(&ocsp); + return ret; +} + +int +hx509_ocsp_verify(hx509_context context, + time_t now, + hx509_cert cert, + int flags, + const void *data, size_t length, + time_t *expiration) +{ + const Certificate *c = _hx509_get_cert(cert); + OCSPBasicOCSPResponse basic; + int ret, i; + + *expiration = 0; + + ret = parse_ocsp_basic(data, length, &basic); + if (ret) + return ret; + + + for (i = 0; i < basic.tbsResponseData.responses.len; i++) { + + ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber, + &c->tbsCertificate.serialNumber); + if (ret != 0) + continue; + + /* verify issuer hashes hash */ + ret = _hx509_verify_signature(context, + NULL, + &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm, + &c->tbsCertificate.issuer._save, + &basic.tbsResponseData.responses.val[i].certID.issuerNameHash); + if (ret != 0) + continue; + + switch (basic.tbsResponseData.responses.val[i].certStatus.element) { + case choice_OCSPCertStatus_good: + break; + case choice_OCSPCertStatus_revoked: + case choice_OCSPCertStatus_unknown: + continue; + } + + /* don't allow the update to be in the future */ + if (basic.tbsResponseData.responses.val[i].thisUpdate > + now + context->ocsp_time_diff) + continue; + + /* don't allow the next updte to be in the past */ + if (basic.tbsResponseData.responses.val[i].nextUpdate) { + if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) + continue; + } else + continue; + + *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; + + return 0; + } + free_OCSPBasicOCSPResponse(&basic); + + return 0; +} diff --git a/source4/heimdal/lib/hx509/test_name.c b/source4/heimdal/lib/hx509/test_name.c new file mode 100644 index 0000000000..9017e54ab1 --- /dev/null +++ b/source4/heimdal/lib/hx509/test_name.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: test_name.c,v 1.6 2006/12/30 23:04:54 lha Exp $"); + +static int +test_name(hx509_context context, const char *name) +{ + hx509_name n; + char *s; + int ret; + + ret = hx509_parse_name(context, name, &n); + if (ret) + return 1; + + ret = hx509_name_to_string(n, &s); + if (ret) + return 1; + + if (strcmp(s, name) != 0) + return 1; + + hx509_name_free(&n); + free(s); + + return 0; +} + +static int +test_name_fail(hx509_context context, const char *name) +{ + hx509_name n; + + if (hx509_parse_name(context, name, &n) == HX509_NAME_MALFORMED) + return 0; + hx509_name_free(&n); + return 1; +} + +int +main(int argc, char **argv) +{ + hx509_context context; + int ret = 0; + + ret = hx509_context_init(&context); + if (ret) + errx(1, "hx509_context_init failed with %d", ret); + + ret += test_name(context, "CN=foo,C=SE"); + ret += test_name(context, "CN=foo,CN=kaka,CN=FOO,DC=ad1,C=SE"); + ret += test_name(context, "1.2.3.4=foo,C=SE"); + ret += test_name_fail(context, "="); + ret += test_name_fail(context, "CN=foo,=foo"); + ret += test_name_fail(context, "CN=foo,really-unknown-type=foo"); + + hx509_context_free(&context); + + return ret; +} diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c index 004926bc89..d20c24699b 100644 --- a/source4/heimdal/lib/krb5/acache.c +++ b/source4/heimdal/lib/krb5/acache.c @@ -37,7 +37,7 @@ #include <dlfcn.h> #endif -RCSID("$Id: acache.c,v 1.16 2006/10/19 11:41:38 lha Exp $"); +RCSID("$Id: acache.c,v 1.17 2007/01/08 15:31:01 lha Exp $"); /* XXX should we fetch these for each open ? */ static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER; @@ -106,7 +106,12 @@ init_ccapi(krb5_context context) } #ifdef HAVE_DLOPEN - cc_handle = dlopen(lib, 0); + +#ifndef RTLD_LAZY +#define RTLD_LAZY 0 +#endif + + cc_handle = dlopen(lib, RTLD_LAZY); if (cc_handle == NULL) { HEIMDAL_MUTEX_unlock(&acc_mutex); krb5_set_error_string(context, "Failed to load %s", lib); diff --git a/source4/heimdal/lib/krb5/config_file.c b/source4/heimdal/lib/krb5/config_file.c index 66051303ed..bbd9cf4c78 100644 --- a/source4/heimdal/lib/krb5/config_file.c +++ b/source4/heimdal/lib/krb5/config_file.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: config_file.c,v 1.54 2006/04/02 00:59:19 lha Exp $"); +RCSID("$Id: config_file.c,v 1.55 2006/12/04 23:35:54 lha Exp $"); #ifndef HAVE_NETINFO @@ -158,8 +158,7 @@ parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent, char *p; ++*lineno; - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; + buf[strcspn(buf, "\r\n")] = '\0'; p = buf; while(isspace((unsigned char)*p)) ++p; @@ -255,8 +254,7 @@ krb5_config_parse_debug (struct fileptr *f, char *p; ++*lineno; - if(buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; + buf[strcspn(buf, "\r\n")] = '\0'; p = buf; while(isspace((unsigned char)*p)) ++p; diff --git a/source4/heimdal/lib/krb5/context.c b/source4/heimdal/lib/krb5/context.c index f3b0fad347..d0317da375 100644 --- a/source4/heimdal/lib/krb5/context.c +++ b/source4/heimdal/lib/krb5/context.c @@ -34,7 +34,7 @@ #include "krb5_locl.h" #include <com_err.h> -RCSID("$Id: context.c,v 1.111 2006/11/08 02:55:46 lha Exp $"); +RCSID("$Id: context.c,v 1.112 2006/11/24 14:24:33 lha Exp $"); #define INIT_FIELD(C, T, E, D, F) \ (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \ @@ -180,7 +180,7 @@ init_context_from_config_file(krb5_context context) /* prefer dns_lookup_kdc over srv_lookup. */ INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup"); INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc"); - INIT_FIELD(context, int, large_msg_size, 6000, "large_message_size"); + INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size"); INIT_FIELD(context, bool, dns_canonicalize_hostname, TRUE, "dns_canonicalize_hostname"); context->default_cc_name = NULL; return 0; diff --git a/source4/heimdal/lib/krb5/crypto.c b/source4/heimdal/lib/krb5/crypto.c index 9f6ef6b82b..6d4a81baa8 100644 --- a/source4/heimdal/lib/krb5/crypto.c +++ b/source4/heimdal/lib/krb5/crypto.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: crypto.c,v 1.145 2006/10/22 07:32:40 lha Exp $"); +RCSID("$Id: crypto.c,v 1.146 2006/11/17 21:58:47 lha Exp $"); #undef CRYPTO_DEBUG #ifdef CRYPTO_DEBUG @@ -1076,6 +1076,21 @@ krb5_enctype_keysize(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION +krb5_enctype_keybits(krb5_context context, + krb5_enctype type, + size_t *keybits) +{ + struct encryption_type *et = _find_enctype(type); + if(et == NULL) { + krb5_set_error_string(context, "encryption type %d not supported", + type); + return KRB5_PROG_ETYPE_NOSUPP; + } + *keybits = et->keytype->bits; + return 0; +} + +krb5_error_code KRB5_LIB_FUNCTION krb5_generate_random_keyblock(krb5_context context, krb5_enctype type, krb5_keyblock *key) diff --git a/source4/heimdal/lib/krb5/fcache.c b/source4/heimdal/lib/krb5/fcache.c index 79b809d2a2..7441509e38 100644 --- a/source4/heimdal/lib/krb5/fcache.c +++ b/source4/heimdal/lib/krb5/fcache.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: fcache.c,v 1.52 2006/04/02 01:04:37 lha Exp $"); +RCSID("$Id: fcache.c,v 1.54 2006/12/15 21:35:52 lha Exp $"); typedef struct krb5_fcache{ char *filename; @@ -699,6 +699,62 @@ fcc_get_version(krb5_context context, return FCACHE(id)->version; } +struct fcache_iter { + int first; +}; + +static krb5_error_code +fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct fcache_iter *iter; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + iter->first = 1; + *cursor = iter; + return 0; +} + +static krb5_error_code +fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct fcache_iter *iter = cursor; + krb5_error_code ret; + const char *fn; + char *expandedfn = NULL; + + if (!iter->first) { + krb5_clear_error_string(context); + return KRB5_CC_END; + } + iter->first = 0; + + fn = krb5_cc_default_name(context); + if (strncasecmp(fn, "FILE:", 5) != 0) { + ret = _krb5_expand_default_cc_name(context, + KRB5_DEFAULT_CCNAME_FILE, + &expandedfn); + if (ret) + return ret; + } + ret = krb5_cc_resolve(context, fn, id); + if (expandedfn) + free(expandedfn); + + return ret; +} + +static krb5_error_code +fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct fcache_iter *iter = cursor; + free(iter); + return 0; +} + const krb5_cc_ops krb5_fcc_ops = { "FILE", fcc_get_name, @@ -715,5 +771,8 @@ const krb5_cc_ops krb5_fcc_ops = { fcc_end_get, fcc_remove_cred, fcc_set_flags, - fcc_get_version + fcc_get_version, + fcc_get_cache_first, + fcc_get_cache_next, + fcc_end_cache_get }; diff --git a/source4/heimdal/lib/krb5/get_cred.c b/source4/heimdal/lib/krb5/get_cred.c index b404c30f6e..663b5e7f1b 100644 --- a/source4/heimdal/lib/krb5/get_cred.c +++ b/source4/heimdal/lib/krb5/get_cred.c @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: get_cred.c,v 1.112 2006/06/06 21:22:54 lha Exp $"); +RCSID("$Id: get_cred.c,v 1.113 2006/11/21 05:14:01 lha Exp $"); /* * Take the `body' and encode it into `padata' using the credentials @@ -458,7 +458,7 @@ get_cred_kdc_usage(krb5_context context, ret = krb5_create_checksum(context, crypto, - KRB5_KU_TGS_IMPERSONATE, + KRB5_KU_OTHER_CKSUM, 0, data.data, data.length, diff --git a/source4/heimdal/lib/krb5/init_creds.c b/source4/heimdal/lib/krb5/init_creds.c index 6dacb316d8..a331524a7e 100644 --- a/source4/heimdal/lib/krb5/init_creds.c +++ b/source4/heimdal/lib/krb5/init_creds.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: init_creds.c,v 1.28 2006/09/04 14:28:54 lha Exp $"); +RCSID("$Id: init_creds.c,v 1.30 2006/11/23 16:27:36 lha Exp $"); void KRB5_LIB_FUNCTION krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) @@ -130,9 +130,10 @@ _krb5_get_init_creds_opt_set_krb5_error(krb5_context context, void KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opt) +krb5_get_init_creds_opt_free(krb5_context context, + krb5_get_init_creds_opt *opt) { - if (opt->opt_private == NULL) + if (opt == NULL || opt->opt_private == NULL) return; if (opt->opt_private->refcount < 1) /* abort ? */ return; diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c index d43ae0ae6f..f6f6eac7d5 100644 --- a/source4/heimdal/lib/krb5/init_creds_pw.c +++ b/source4/heimdal/lib/krb5/init_creds_pw.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: init_creds_pw.c,v 1.101 2006/10/02 12:00:59 lha Exp $"); +RCSID("$Id: init_creds_pw.c,v 1.105 2007/01/09 10:44:59 lha Exp $"); typedef struct krb5_get_init_creds_ctx { KDCOptions flags; @@ -656,7 +656,7 @@ free_paid(krb5_context context, struct pa_info_data *ppaid) { krb5_free_salt(context, ppaid->salt); if (ppaid->s2kparams) - krb5_data_free(ppaid->s2kparams); + krb5_free_data(context, ppaid->s2kparams); } @@ -729,8 +729,8 @@ pa_etype_info2(krb5_context context, if (e.val[i].salt == NULL) krb5_free_salt(context, salt); if (ret == 0) { - free_ETYPE_INFO2(&e); - return paid; + free_ETYPE_INFO2(&e); + return paid; } } } @@ -1092,23 +1092,31 @@ process_pa_data_to_md(krb5_context context, (*out_md)->len = 0; (*out_md)->val = NULL; - if (in_md->len != 0) { - struct pa_info_data paid, *ppaid; + /* + * Make sure we don't sent both ENC-TS and PK-INIT pa data, no + * need to expose our password protecting our PKCS12 key. + */ - memset(&paid, 0, sizeof(paid)); + if (ctx->pk_init_ctx) { + + ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md); + if (ret) + return ret; + } else if (in_md->len != 0) { + struct pa_info_data paid, *ppaid; + + memset(&paid, 0, sizeof(paid)); + paid.etype = ENCTYPE_NULL; ppaid = process_pa_info(context, creds->client, a, &paid, in_md); - + pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md); if (ppaid) free_paid(context, ppaid); } pa_data_add_pac_request(context, ctx, *out_md); - ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md); - if (ret) - return ret; if ((*out_md)->len == 0) { free(*out_md); @@ -1503,7 +1511,7 @@ krb5_get_init_creds_password(krb5_context context, free (q); if (ret) { memset (buf, 0, sizeof(buf)); - krb5_get_init_creds_opt_free(options); + krb5_get_init_creds_opt_free(context, options); ret = KRB5_LIBOS_PWDINTR; krb5_clear_error_string (context); return ret; @@ -1515,7 +1523,7 @@ krb5_get_init_creds_password(krb5_context context, ret = krb5_get_init_creds_opt_set_pa_password(context, options, password, NULL); if (ret) { - krb5_get_init_creds_opt_free(options); + krb5_get_init_creds_opt_free(context, options); memset(buf, 0, sizeof(buf)); return ret; } @@ -1523,7 +1531,7 @@ krb5_get_init_creds_password(krb5_context context, ret = krb5_get_init_creds(context, creds, client, prompter, data, start_time, in_tkt_service, options); - krb5_get_init_creds_opt_free(options); + krb5_get_init_creds_opt_free(context, options); memset(buf, 0, sizeof(buf)); return ret; } diff --git a/source4/heimdal/lib/krb5/krb5-private.h b/source4/heimdal/lib/krb5/krb5-private.h index ba2f75ad22..c3e5732753 100644 --- a/source4/heimdal/lib/krb5/krb5-private.h +++ b/source4/heimdal/lib/krb5/krb5-private.h @@ -73,15 +73,6 @@ _krb5_extract_ticket ( krb5_decrypt_proc /*decrypt_proc*/, krb5_const_pointer /*decryptarg*/); -int -_krb5_find_type_in_ad ( - krb5_context /*context*/, - int /*type*/, - krb5_data */*data*/, - krb5_boolean */*found*/, - krb5_keyblock */*sessionkey*/, - const AuthorizationData */*ad*/); - void _krb5_free_krbhst_info (krb5_krbhst_info */*hi*/); @@ -299,38 +290,17 @@ _krb5_oid_to_enctype ( const heim_oid */*oid*/, krb5_enctype */*etype*/); -void -_krb5_pac_free ( - krb5_context /*context*/, - struct krb5_pac */*pac*/); - -krb5_error_code -_krb5_pac_parse ( - krb5_context /*context*/, - const void */*ptr*/, - size_t /*len*/, - struct krb5_pac **/*pac*/); - krb5_error_code _krb5_pac_sign ( krb5_context /*context*/, struct krb5_pac */*p*/, time_t /*authtime*/, krb5_principal /*principal*/, - krb5_keyblock */*server_key*/, - krb5_keyblock */*priv_key*/, + const krb5_keyblock */*server_key*/, + const krb5_keyblock */*priv_key*/, krb5_data */*data*/); krb5_error_code -_krb5_pac_verify ( - krb5_context /*context*/, - struct krb5_pac */*pac*/, - time_t /*authtime*/, - krb5_principal /*principal*/, - krb5_keyblock */*server*/, - krb5_keyblock */*privsvr*/); - -krb5_error_code _krb5_parse_moduli ( krb5_context /*context*/, const char */*file*/, diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h index 8b61e8d7d2..9dfe487b0a 100644 --- a/source4/heimdal/lib/krb5/krb5-protos.h +++ b/source4/heimdal/lib/krb5/krb5-protos.h @@ -499,10 +499,11 @@ krb5_boolean KRB5_LIB_FUNCTION krb5_c_is_keyed_cksum (krb5_cksumtype /*ctype*/); krb5_error_code KRB5_LIB_FUNCTION -krb5_c_keylength ( +krb5_c_keylengths ( krb5_context /*context*/, krb5_enctype /*enctype*/, - size_t */*len*/); + size_t */*ilen*/, + size_t */*keylen*/); krb5_error_code KRB5_LIB_FUNCTION krb5_c_make_checksum ( @@ -1520,6 +1521,12 @@ krb5_enctype_disable ( krb5_enctype /*enctype*/); krb5_error_code KRB5_LIB_FUNCTION +krb5_enctype_keybits ( + krb5_context /*context*/, + krb5_enctype /*type*/, + size_t */*keybits*/); + +krb5_error_code KRB5_LIB_FUNCTION krb5_enctype_keysize ( krb5_context /*context*/, krb5_enctype /*type*/, @@ -2021,7 +2028,9 @@ krb5_get_init_creds_opt_alloc ( krb5_get_init_creds_opt **/*opt*/); void KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_free (krb5_get_init_creds_opt */*opt*/); +krb5_get_init_creds_opt_free ( + krb5_context /*context*/, + krb5_get_init_creds_opt */*opt*/); krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_opt_get_error ( @@ -2189,6 +2198,9 @@ krb5_get_server_rcache ( krb5_boolean KRB5_LIB_FUNCTION krb5_get_use_admin_kdc (krb5_context /*context*/); +krb5_log_facility * KRB5_LIB_FUNCTION +krb5_get_warn_dest (krb5_context /*context*/); + size_t krb5_get_wrapped_length ( krb5_context /*context*/, @@ -2609,12 +2621,172 @@ krb5_net_write_block ( size_t /*len*/, time_t /*timeout*/); +krb5_error_code +krb5_ntlm_alloc ( + krb5_context /*context*/, + krb5_ntlm */*ntlm*/); + +krb5_error_code +krb5_ntlm_free ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/); + +krb5_error_code +krb5_ntlm_init_get_challange ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*challange*/); + +krb5_error_code +krb5_ntlm_init_get_flags ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + uint32_t */*flags*/); + +krb5_error_code +krb5_ntlm_init_get_opaque ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*opaque*/); + +krb5_error_code +krb5_ntlm_init_get_targetinfo ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*data*/); + +krb5_error_code +krb5_ntlm_init_get_targetname ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + char **/*name*/); + +krb5_error_code +krb5_ntlm_init_request ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_realm /*realm*/, + krb5_ccache /*ccache*/, + uint32_t /*flags*/, + const char */*hostname*/, + const char */*domainname*/); + +krb5_error_code +krb5_ntlm_rep_get_sessionkey ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*data*/); + +krb5_boolean +krb5_ntlm_rep_get_status ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/); + +krb5_error_code +krb5_ntlm_req_set_flags ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + uint32_t /*flags*/); + +krb5_error_code +krb5_ntlm_req_set_lm ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + void */*hash*/, + size_t /*len*/); + +krb5_error_code +krb5_ntlm_req_set_ntlm ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + void */*hash*/, + size_t /*len*/); + +krb5_error_code +krb5_ntlm_req_set_opaque ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*opaque*/); + +krb5_error_code +krb5_ntlm_req_set_session ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + void */*sessionkey*/, + size_t /*length*/); + +krb5_error_code +krb5_ntlm_req_set_targetname ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + const char */*targetname*/); + +krb5_error_code +krb5_ntlm_req_set_username ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + const char */*username*/); + +krb5_error_code +krb5_ntlm_request ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_realm /*realm*/, + krb5_ccache /*ccache*/); + krb5_error_code KRB5_LIB_FUNCTION krb5_openlog ( krb5_context /*context*/, const char */*program*/, krb5_log_facility **/*fac*/); +krb5_error_code +krb5_pac_add_buffer ( + krb5_context /*context*/, + struct krb5_pac */*p*/, + uint32_t /*type*/, + const krb5_data */*data*/); + +void +krb5_pac_free ( + krb5_context /*context*/, + struct krb5_pac */*pac*/); + +krb5_error_code +krb5_pac_get_buffer ( + krb5_context /*context*/, + struct krb5_pac */*p*/, + uint32_t /*type*/, + krb5_data */*data*/); + +krb5_error_code +krb5_pac_get_types ( + krb5_context /*context*/, + struct krb5_pac */*p*/, + size_t */*len*/, + uint32_t **/*types*/); + +krb5_error_code +krb5_pac_init ( + krb5_context /*context*/, + struct krb5_pac **/*pac*/); + +krb5_error_code +krb5_pac_parse ( + krb5_context /*context*/, + const void */*ptr*/, + size_t /*len*/, + struct krb5_pac **/*pac*/); + +krb5_error_code +krb5_pac_verify ( + krb5_context /*context*/, + const struct krb5_pac */*pac*/, + time_t /*authtime*/, + krb5_const_principal /*principal*/, + const krb5_keyblock */*server*/, + const krb5_keyblock */*privsvr*/); + int KRB5_LIB_FUNCTION krb5_padata_add ( krb5_context /*context*/, @@ -2904,6 +3076,12 @@ krb5_rd_req_in_set_keytab ( krb5_rd_req_in_ctx /*in*/, krb5_keytab /*keytab*/); +krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_req_in_set_pac_check ( + krb5_context /*context*/, + krb5_rd_req_in_ctx /*in*/, + krb5_boolean /*flag*/); + void KRB5_LIB_FUNCTION krb5_rd_req_out_ctx_free ( krb5_context /*context*/, @@ -3515,6 +3693,11 @@ krb5_ticket_get_client ( const krb5_ticket */*ticket*/, krb5_principal */*client*/); +time_t KRB5_LIB_FUNCTION +krb5_ticket_get_endtime ( + krb5_context /*context*/, + const krb5_ticket */*ticket*/); + krb5_error_code KRB5_LIB_FUNCTION krb5_ticket_get_server ( krb5_context /*context*/, diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h index 1b26e8b3e7..55a83fb533 100644 --- a/source4/heimdal/lib/krb5/krb5.h +++ b/source4/heimdal/lib/krb5/krb5.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: krb5.h,v 1.255 2006/11/12 08:33:07 lha Exp $ */ +/* $Id: krb5.h,v 1.259 2007/01/03 18:51:52 lha Exp $ */ #ifndef __KRB5_H__ #define __KRB5_H__ @@ -77,8 +77,10 @@ typedef struct krb5_get_creds_opt_data *krb5_get_creds_opt; struct krb5_digest; typedef struct krb5_digest *krb5_digest; +struct krb5_ntlm; +typedef struct krb5_ntlm *krb5_ntlm; -struct krb5_pac; +typedef struct krb5_pac *krb5_pac; typedef struct krb5_rd_req_in_ctx *krb5_rd_req_in_ctx; typedef struct krb5_rd_req_out_ctx *krb5_rd_req_out_ctx; @@ -216,8 +218,6 @@ typedef enum krb5_key_usage { /* Keyusage for the server referral in a TGS req */ KRB5_KU_SAM_ENC_NONCE_SAD = 27, /* Encryption of the SAM-NONCE-OR-SAD field */ - KRB5_KU_TGS_IMPERSONATE = -17, - /* Checksum type used in the impersonate field */ KRB5_KU_DIGEST_ENCRYPT = -18, /* Encryption key usage used in the digest encryption field */ KRB5_KU_DIGEST_OPAQUE = -19, @@ -716,6 +716,7 @@ typedef struct krb5_krbhst_data *krb5_krbhst_handle; #define KRB5_KRBHST_ADMIN 2 #define KRB5_KRBHST_CHANGEPW 3 #define KRB5_KRBHST_KRB524 4 +#define KRB5_KRBHST_KCA 5 typedef struct krb5_krbhst_info { enum { KRB5_KRBHST_UDP, diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h index 3fb5461b3c..35d046c8d9 100644 --- a/source4/heimdal/lib/krb5/krb5_locl.h +++ b/source4/heimdal/lib/krb5/krb5_locl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: krb5_locl.h,v 1.93 2006/10/20 18:13:31 lha Exp $ */ +/* $Id: krb5_locl.h,v 1.97 2006/12/15 16:46:51 lha Exp $ */ #ifndef __KRB5_LOCL_H__ #define __KRB5_LOCL_H__ @@ -239,20 +239,20 @@ typedef struct krb5_context_data { int large_msg_size; int dns_canonicalize_hostname; struct send_to_kdc *send_to_kdc; - void *mem_ctx; /* Some parts of Samba4 need a valid - memory context (under the event - context) to use */ } krb5_context_data; +#define KRB5_DEFAULT_CCNAME_FILE "FILE:/tmp/krb5cc_%{uid}" +#define KRB5_DEFAULT_CCNAME_API "API:" + /* * Configurable options */ #ifndef KRB5_DEFAULT_CCNAME #ifdef __APPLE__ -#define KRB5_DEFAULT_CCNAME "API:" +#define KRB5_DEFAULT_CCNAME KRB5_DEFAULT_CCNAME_API #else -#define KRB5_DEFAULT_CCNAME "FILE:/tmp/krb5cc_%{uid}" +#define KRB5_DEFAULT_CCNAME KRB5_DEFAULT_CCNAME_FILE #endif #endif diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c index f395f0d0c3..3e281e5c63 100644 --- a/source4/heimdal/lib/krb5/krbhst.c +++ b/source4/heimdal/lib/krb5/krbhst.c @@ -35,7 +35,7 @@ #include <resolve.h> #include "locate_plugin.h" -RCSID("$Id: krbhst.c,v 1.58 2006/11/12 20:05:20 lha Exp $"); +RCSID("$Id: krbhst.c,v 1.61 2006/11/30 17:23:08 lha Exp $"); static int string_to_proto(const char *string) @@ -493,7 +493,7 @@ add_locate(void *ctx, int type, struct sockaddr *addr) if (ret != 0) return 0; - memset(&hints, 0, sizeof(hints)); + make_hints(&hints, krbhst_get_default_proto(kd)); ret = getaddrinfo(host, port, &hints, &ai); if (ret) return 0; @@ -521,7 +521,7 @@ plugin_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, enum locate_service_type type) { - struct krb5_plugin *list, *e; + struct krb5_plugin *list = NULL, *e; krb5_error_code ret; ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "resolve", &list); @@ -619,6 +619,13 @@ admin_get_next(krb5_context context, { krb5_error_code ret; + if ((kd->flags & KD_PLUGIN) == 0) { + plugin_get_hosts(context, kd, locate_service_kadmin); + kd->flags |= KD_PLUGIN; + if(get_next(kd, host)) + return 0; + } + if((kd->flags & KD_CONFIG) == 0) { config_get_hosts(context, kd, "admin_server"); kd->flags |= KD_CONFIG; @@ -660,6 +667,13 @@ kpasswd_get_next(krb5_context context, { krb5_error_code ret; + if ((kd->flags & KD_PLUGIN) == 0) { + plugin_get_hosts(context, kd, locate_service_kpasswd); + kd->flags |= KD_PLUGIN; + if(get_next(kd, host)) + return 0; + } + if((kd->flags & KD_CONFIG) == 0) { config_get_hosts(context, kd, "kpasswd_server"); kd->flags |= KD_CONFIG; @@ -705,6 +719,13 @@ krb524_get_next(krb5_context context, struct krb5_krbhst_data *kd, krb5_krbhst_info **host) { + if ((kd->flags & KD_PLUGIN) == 0) { + plugin_get_hosts(context, kd, locate_service_krb524); + kd->flags |= KD_PLUGIN; + if(get_next(kd, host)) + return 0; + } + if((kd->flags & KD_CONFIG) == 0) { config_get_hosts(context, kd, "krb524_server"); if(get_next(kd, host)) diff --git a/source4/heimdal/lib/krb5/log.c b/source4/heimdal/lib/krb5/log.c index e6fcb6bbb9..9523ca848c 100644 --- a/source4/heimdal/lib/krb5/log.c +++ b/source4/heimdal/lib/krb5/log.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: log.c,v 1.39 2006/04/24 15:09:27 lha Exp $"); +RCSID("$Id: log.c,v 1.40 2006/11/21 08:08:46 lha Exp $"); struct facility { int min; diff --git a/source4/heimdal/lib/krb5/mit_glue.c b/source4/heimdal/lib/krb5/mit_glue.c index 493c4cd845..c4d3ff5390 100755 --- a/source4/heimdal/lib/krb5/mit_glue.c +++ b/source4/heimdal/lib/krb5/mit_glue.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: mit_glue.c,v 1.9 2006/11/09 21:24:16 lha Exp $"); +RCSID("$Id: mit_glue.c,v 1.12 2006/11/17 22:17:46 lha Exp $"); /* * Glue for MIT API @@ -327,9 +327,16 @@ krb5_c_make_random_key(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION -krb5_c_keylength(krb5_context context, - krb5_enctype enctype, - size_t *len) +krb5_c_keylengths(krb5_context context, + krb5_enctype enctype, + size_t *ilen, + size_t *keylen) { - return krb5_enctype_keysize(context, enctype, len); + krb5_error_code ret; + + ret = krb5_enctype_keybits(context, enctype, ilen); + if (ret) + return ret; + *ilen = (*ilen + 7) / 8; + return krb5_enctype_keysize(context, enctype, keylen); } diff --git a/source4/heimdal/lib/krb5/mk_req_ext.c b/source4/heimdal/lib/krb5/mk_req_ext.c index 18b0e3552f..8646c4ebea 100644 --- a/source4/heimdal/lib/krb5/mk_req_ext.c +++ b/source4/heimdal/lib/krb5/mk_req_ext.c @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: mk_req_ext.c,v 1.32 2006/03/19 20:33:13 lha Exp $"); +RCSID("$Id: mk_req_ext.c,v 1.33 2006/12/27 12:07:22 lha Exp $"); krb5_error_code _krb5_mk_req_internal(krb5_context context, @@ -91,7 +91,9 @@ _krb5_mk_req_internal(krb5_context context, in_data->length, &c); } else if(ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5 || - ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56) { + ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56 || + ac->keyblock->keytype == ETYPE_DES_CBC_MD4 || + ac->keyblock->keytype == ETYPE_DES_CBC_MD5) { /* this is to make MS kdc happy */ ret = krb5_create_checksum(context, NULL, diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c new file mode 100644 index 0000000000..5bc7235459 --- /dev/null +++ b/source4/heimdal/lib/krb5/pac.c @@ -0,0 +1,1034 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +RCSID("$Id: pac.c,v 1.13 2007/01/09 11:22:56 lha Exp $"); + +struct PAC_INFO_BUFFER { + uint32_t type; + uint32_t buffersize; + uint32_t offset_hi; + uint32_t offset_lo; +}; + +struct PACTYPE { + uint32_t numbuffers; + uint32_t version; + struct PAC_INFO_BUFFER buffers[1]; +}; + +struct krb5_pac { + struct PACTYPE *pac; + krb5_data data; + struct PAC_INFO_BUFFER *server_checksum; + struct PAC_INFO_BUFFER *privsvr_checksum; + struct PAC_INFO_BUFFER *logon_name; +}; + +#define PAC_ALIGNMENT 8 + +#define PACTYPE_SIZE 8 +#define PAC_INFO_BUFFER_SIZE 16 + +#define PAC_SERVER_CHECKSUM 6 +#define PAC_PRIVSVR_CHECKSUM 7 +#define PAC_LOGON_NAME 10 + +#define CHECK(r,f,l) \ + do { \ + if (((r) = f ) != 0) { \ + krb5_clear_error_string(context); \ + goto l; \ + } \ + } while(0) + +static const char zeros[PAC_ALIGNMENT] = { 0 }; + +/* + * + */ + +krb5_error_code +krb5_pac_parse(krb5_context context, const void *ptr, size_t len, + struct krb5_pac **pac) +{ + krb5_error_code ret; + struct krb5_pac *p; + krb5_storage *sp = NULL; + uint32_t i, tmp, tmp2, header_end; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + ret = ENOMEM; + krb5_set_error_string(context, "out of memory"); + goto out; + } + + sp = krb5_storage_from_readonly_mem(ptr, len); + if (sp == NULL) { + ret = ENOMEM; + krb5_set_error_string(context, "out of memory"); + goto out; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_ret_uint32(sp, &tmp), out); + CHECK(ret, krb5_ret_uint32(sp, &tmp2), out); + if (tmp < 1) { + krb5_set_error_string(context, "PAC have too few buffer"); + ret = EINVAL; /* Too few buffers */ + goto out; + } + if (tmp2 != 0) { + krb5_set_error_string(context, "PAC have wrong version"); + ret = EINVAL; /* Wrong version */ + goto out; + } + + p->pac = calloc(1, + sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (tmp - 1))); + if (p->pac == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + + p->pac->numbuffers = tmp; + p->pac->version = tmp2; + + header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers); + if (header_end > len) { + ret = EINVAL; + goto out; + } + + for (i = 0; i < p->pac->numbuffers; i++) { + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].type), out); + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize), out); + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_lo), out); + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_hi), out); + + /* consistency checks */ + if (p->pac->buffers[i].offset_lo & (PAC_ALIGNMENT - 1)) { + krb5_set_error_string(context, "PAC out of allignment"); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].offset_hi) { + krb5_set_error_string(context, "PAC high offset set"); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].offset_lo > len) { + krb5_set_error_string(context, "PAC offset off end"); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].offset_lo < header_end) { + krb5_set_error_string(context, "PAC offset inside header: %d %d", + p->pac->buffers[i].offset_lo, header_end); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){ + krb5_set_error_string(context, "PAC length off end"); + ret = EINVAL; + goto out; + } + + /* let save pointer to data we need later */ + if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) { + if (p->server_checksum) { + krb5_set_error_string(context, "PAC have two server checksums"); + ret = EINVAL; + goto out; + } + p->server_checksum = &p->pac->buffers[i]; + } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) { + if (p->privsvr_checksum) { + krb5_set_error_string(context, "PAC have two KDC checksums"); + ret = EINVAL; + goto out; + } + p->privsvr_checksum = &p->pac->buffers[i]; + } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { + if (p->logon_name) { + krb5_set_error_string(context, "PAC have two logon names"); + ret = EINVAL; + goto out; + } + p->logon_name = &p->pac->buffers[i]; + } + } + + ret = krb5_data_copy(&p->data, ptr, len); + if (ret) + goto out; + + krb5_storage_free(sp); + + *pac = p; + return 0; + +out: + if (sp) + krb5_storage_free(sp); + if (p) { + if (p->pac) + free(p->pac); + free(p); + } + *pac = NULL; + + return ret; +} + +krb5_error_code +krb5_pac_init(krb5_context context, struct krb5_pac **pac) +{ + krb5_error_code ret; + struct krb5_pac *p; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + + p->pac = calloc(1, sizeof(*p->pac)); + if (p->pac == NULL) { + free(p); + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + + ret = krb5_data_alloc(&p->data, PACTYPE_SIZE); + if (ret) { + free (p->pac); + free(p); + krb5_set_error_string(context, "out of memory"); + return ret; + } + + + *pac = p; + return 0; +} + +krb5_error_code +krb5_pac_add_buffer(krb5_context context, struct krb5_pac *p, + uint32_t type, const krb5_data *data) +{ + krb5_error_code ret; + void *ptr; + size_t len, offset, header_end; + uint32_t i; + + len = p->pac->numbuffers + 1; + if (len < p->pac->numbuffers) + return EINVAL; + + ptr = realloc(p->pac, + sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * len)); + if (ptr == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + p->pac = ptr; + + for (i = 0; i < len; i++) + p->pac->buffers[i].offset_lo += PAC_INFO_BUFFER_SIZE; + + offset = p->data.length + PAC_INFO_BUFFER_SIZE; + + p->pac->buffers[len - 1].type = type; + p->pac->buffers[len - 1].buffersize = data->length; + p->pac->buffers[len - 1].offset_lo = offset; + p->pac->buffers[len - 1].offset_hi = 0; + + len = p->data.length + data->length + PAC_INFO_BUFFER_SIZE; + if (len < p->data.length) { + krb5_set_error_string(context, "integer overrun"); + return EINVAL; + } + + /* align to PAC_ALIGNMENT */ + len = ((len + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT; + + ret = krb5_data_realloc(&p->data, len); + if (ret) { + krb5_set_error_string(context, "out of memory"); + return ret; + } + + /* make place for PAC INFO BUFFER header */ + header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers); + memmove((unsigned char *)p->data.data + header_end, + (unsigned char *)p->data.data + header_end + PAC_INFO_BUFFER_SIZE, + PAC_INFO_BUFFER_SIZE); + + /* + * + */ + + memcpy((unsigned char *)p->data.data + offset, + data->data, data->length); + memset((unsigned char *)p->data.data + offset + data->length, + 0, p->data.length - offset - data->length); + + p->pac->numbuffers += 1; + + return 0; +} + +krb5_error_code +krb5_pac_get_buffer(krb5_context context, struct krb5_pac *p, + uint32_t type, krb5_data *data) +{ + krb5_error_code ret; + uint32_t i; + + /* + * Hide the checksums from external consumers + */ + + if (type == PAC_PRIVSVR_CHECKSUM || type == PAC_SERVER_CHECKSUM) { + ret = krb5_data_alloc(data, 16); + if (ret) { + krb5_set_error_string(context, "out of memory"); + return ret; + } + memset(data->data, 0, data->length); + return 0; + } + + for (i = 0; i < p->pac->numbuffers; i++) { + size_t len = p->pac->buffers[i].buffersize; + size_t offset = p->pac->buffers[i].offset_lo; + + if (p->pac->buffers[i].type != type) + continue; + + ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len); + if (ret) { + krb5_set_error_string(context, "Out of memory"); + return ret; + } + return 0; + } + krb5_set_error_string(context, "No PAC buffer of type %lu was found", + (unsigned long)type); + return ENOENT; +} + +/* + * + */ + +krb5_error_code +krb5_pac_get_types(krb5_context context, + struct krb5_pac *p, + size_t *len, + uint32_t **types) +{ + size_t i; + + *types = calloc(p->pac->numbuffers, sizeof(*types)); + if (*types == NULL) { + *len = 0; + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + for (i = 0; i < p->pac->numbuffers; i++) + (*types)[i] = p->pac->buffers[i].type; + *len = p->pac->numbuffers; + + return 0; +} + +/* + * + */ + +void +krb5_pac_free(krb5_context context, struct krb5_pac *pac) +{ + krb5_data_free(&pac->data); + free(pac->pac); + free(pac); +} + +/* + * + */ + +static krb5_error_code +verify_checksum(krb5_context context, + const struct PAC_INFO_BUFFER *sig, + const krb5_data *data, + void *ptr, size_t len, + const krb5_keyblock *key) +{ + krb5_crypto crypto = NULL; + krb5_storage *sp = NULL; + uint32_t type; + krb5_error_code ret; + Checksum cksum; + + sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo, + sig->buffersize); + if (sp == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_ret_uint32(sp, &type), out); + cksum.cksumtype = type; + cksum.checksum.length = + sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR); + cksum.checksum.data = malloc(cksum.checksum.length); + if (cksum.checksum.data == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length); + if (ret != cksum.checksum.length) { + krb5_set_error_string(context, "PAC checksum missing checksum"); + ret = EINVAL; + goto out; + } + + if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) { + krb5_set_error_string (context, "Checksum type %d not keyed", + cksum.cksumtype); + ret = EINVAL; + goto out; + } + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + goto out; + + ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, + ptr, len, &cksum); + krb5_crypto_destroy(context, crypto); + krb5_storage_free(sp); + + return ret; + +out: + if (sp) + krb5_storage_free(sp); + if (crypto) + krb5_crypto_destroy(context, crypto); + return ret; +} + +static krb5_error_code +create_checksum(krb5_context context, + const krb5_keyblock *key, + void *data, size_t datalen, + void *sig, size_t siglen) +{ + krb5_crypto crypto = NULL; + krb5_error_code ret; + Checksum cksum; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + return ret; + + ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, + data, datalen, &cksum); + krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + if (cksum.checksum.length != siglen) { + krb5_set_error_string(context, "pac checksum wrong length"); + free_Checksum(&cksum); + return EINVAL; + } + + memcpy(sig, cksum.checksum.data, siglen); + free_Checksum(&cksum); + + return 0; +} + + +/* + * + */ + +#define NTTIME_EPOCH 0x019DB1DED53E8000LL + +static uint64_t +unix2nttime(time_t unix_time) +{ + long long wt; + wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH; + return wt; +} + +static krb5_error_code +verify_logonname(krb5_context context, + const struct PAC_INFO_BUFFER *logon_name, + const krb5_data *data, + time_t authtime, + krb5_const_principal principal) +{ + krb5_error_code ret; + krb5_principal p2; + uint32_t time1, time2; + krb5_storage *sp; + uint16_t len; + char *s; + + sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, + logon_name->buffersize); + if (sp == NULL) { + krb5_set_error_string(context, "Out of memory"); + return ENOMEM; + } + + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_ret_uint32(sp, &time1), out); + CHECK(ret, krb5_ret_uint32(sp, &time2), out); + + { + uint64_t t1, t2; + t1 = unix2nttime(authtime); + t2 = ((uint64_t)time2 << 32) | time1; + if (t1 != t2) { + krb5_storage_free(sp); + krb5_set_error_string(context, "PAC timestamp mismatch"); + return EINVAL; + } + } + CHECK(ret, krb5_ret_uint16(sp, &len), out); + if (len == 0) { + krb5_storage_free(sp); + krb5_set_error_string(context, "PAC logon name length missing"); + return EINVAL; + } + + s = malloc(len); + if (s == NULL) { + krb5_storage_free(sp); + krb5_set_error_string(context, "Out of memory"); + return ENOMEM; + } + ret = krb5_storage_read(sp, s, len); + if (ret != len) { + krb5_storage_free(sp); + krb5_set_error_string(context, "Failed to read pac logon name"); + return EINVAL; + } + krb5_storage_free(sp); +#if 1 /* cheat for now */ + { + size_t i; + + if (len & 1) { + krb5_set_error_string(context, "PAC logon name malformed"); + return EINVAL; + } + + for (i = 0; i < len / 2; i++) { + if (s[(i * 2) + 1]) { + krb5_set_error_string(context, "PAC logon name not ASCII"); + return EINVAL; + } + s[i] = s[i * 2]; + } + s[i] = '\0'; + } +#else + { + uint16_t *ucs2; + ssize_t ucs2len; + size_t u8len; + + ucs2 = malloc(sizeof(ucs2[0]) * len / 2); + if (ucs2) + abort(); + ucs2len = wind_ucs2read(s, len / 2, ucs2); + free(s); + if (len < 0) + return -1; + ret = wind_ucs2toutf8(ucs2, ucs2len, NULL, &u8len); + if (ret < 0) + abort(); + s = malloc(u8len + 1); + if (s == NULL) + abort(); + wind_ucs2toutf8(ucs2, ucs2len, s, &u8len); + free(ucs2); + } +#endif + ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); + free(s); + if (ret) + return ret; + + if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) { + krb5_set_error_string(context, "PAC logon name mismatch"); + ret = EINVAL; + } + krb5_free_principal(context, p2); + return ret; +out: + return ret; +} + +/* + * + */ + +static krb5_error_code +build_logon_name(krb5_context context, + time_t authtime, + krb5_const_principal principal, + krb5_data *logon) +{ + krb5_error_code ret; + krb5_storage *sp; + uint64_t t; + char *s, *s2; + size_t i, len; + + t = unix2nttime(authtime); + + krb5_data_zero(logon); + + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out); + CHECK(ret, krb5_store_uint32(sp, t >> 32), out); + + ret = krb5_unparse_name_flags(context, principal, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s); + if (ret) + goto out; + + len = strlen(s); + + CHECK(ret, krb5_store_uint16(sp, len * 2), out); + +#if 1 /* cheat for now */ + s2 = malloc(len * 2); + if (s2 == NULL) { + ret = ENOMEM; + free(s); + goto out; + } + for (i = 0; i < len; i++) { + s2[i * 2] = s[i]; + s2[i * 2 + 1] = 0; + } + free(s); +#else + /* write libwind code here */ +#endif + + ret = krb5_storage_write(sp, s2, len * 2); + free(s2); + if (ret != len * 2) { + ret = ENOMEM; + goto out; + } + ret = krb5_storage_to_data(sp, logon); + if (ret) + goto out; + krb5_storage_free(sp); + + return 0; +out: + krb5_storage_free(sp); + return ret; +} + + +/* + * + */ + +krb5_error_code +krb5_pac_verify(krb5_context context, + const struct krb5_pac *pac, + time_t authtime, + krb5_const_principal principal, + const krb5_keyblock *server, + const krb5_keyblock *privsvr) +{ + krb5_error_code ret; + + if (pac->server_checksum == NULL) { + krb5_set_error_string(context, "PAC missing server checksum"); + return EINVAL; + } + if (pac->privsvr_checksum == NULL) { + krb5_set_error_string(context, "PAC missing kdc checksum"); + return EINVAL; + } + if (pac->logon_name == NULL) { + krb5_set_error_string(context, "PAC missing logon name"); + return EINVAL; + } + + ret = verify_logonname(context, + pac->logon_name, + &pac->data, + authtime, + principal); + if (ret) + return ret; + + /* + * in the service case, clean out data option of the privsvr and + * server checksum before checking the checksum. + */ + { + krb5_data *copy; + + ret = krb5_copy_data(context, &pac->data, ©); + if (ret) + return ret; + + if (pac->server_checksum->buffersize < 4) + return EINVAL; + if (pac->privsvr_checksum->buffersize < 4) + return EINVAL; + + memset((char *)copy->data + pac->server_checksum->offset_lo + 4, + 0, + pac->server_checksum->buffersize - 4); + + memset((char *)copy->data + pac->privsvr_checksum->offset_lo + 4, + 0, + pac->privsvr_checksum->buffersize - 4); + + ret = verify_checksum(context, + pac->server_checksum, + &pac->data, + copy->data, + copy->length, + server); + krb5_free_data(context, copy); + if (ret) + return ret; + } + if (privsvr) { + ret = verify_checksum(context, + pac->privsvr_checksum, + &pac->data, + (char *)pac->data.data + + pac->server_checksum->offset_lo + 4, + pac->server_checksum->buffersize - 4, + privsvr); + if (ret) + return ret; + } + + return 0; +} + +/* + * + */ + +static krb5_error_code +fill_zeros(krb5_context context, krb5_storage *sp, size_t len) +{ + ssize_t sret; + size_t l; + + while (len) { + l = len; + if (l > sizeof(zeros)) + l = sizeof(zeros); + sret = krb5_storage_write(sp, zeros, l); + if (sret <= 0) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + len -= sret; + } + return 0; +} + +static krb5_error_code +pac_checksum(krb5_context context, + const krb5_keyblock *key, + uint32_t *cksumtype, + size_t *cksumsize) +{ + krb5_cksumtype cktype; + krb5_error_code ret; + krb5_crypto crypto = NULL; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + return ret; + + ret = krb5_crypto_get_checksum_type(context, crypto, &cktype); + ret = krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + if (krb5_checksum_is_keyed(context, cktype) == FALSE) { + krb5_set_error_string(context, "PAC checksum type is not keyed"); + return EINVAL; + } + + ret = krb5_checksumsize(context, cktype, cksumsize); + if (ret) + return ret; + + *cksumtype = (uint32_t)cktype; + + return 0; +} + +krb5_error_code +_krb5_pac_sign(krb5_context context, + struct krb5_pac *p, + time_t authtime, + krb5_principal principal, + const krb5_keyblock *server_key, + const krb5_keyblock *priv_key, + krb5_data *data) +{ + krb5_error_code ret; + krb5_storage *sp = NULL, *spdata = NULL; + uint32_t end; + size_t server_size, priv_size; + uint32_t server_offset = 0, priv_offset = 0; + uint32_t server_cksumtype = 0, priv_cksumtype = 0; + int i, num = 0; + krb5_data logon, d; + + krb5_data_zero(&logon); + + if (p->server_checksum == NULL) + num++; + if (p->privsvr_checksum == NULL) + num++; + if (p->logon_name == NULL) + num++; + + if (num) { + void *ptr; + + ptr = realloc(p->pac, sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (p->pac->numbuffers + num - 1))); + if (ptr == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + p->pac = ptr; + + if (p->server_checksum == NULL) { + p->server_checksum = &p->pac->buffers[p->pac->numbuffers++]; + memset(p->server_checksum, 0, sizeof(*p->server_checksum)); + p->server_checksum->type = PAC_SERVER_CHECKSUM; + } + if (p->privsvr_checksum == NULL) { + p->privsvr_checksum = &p->pac->buffers[p->pac->numbuffers++]; + memset(p->privsvr_checksum, 0, sizeof(*p->privsvr_checksum)); + p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM; + } + if (p->logon_name == NULL) { + p->logon_name = &p->pac->buffers[p->pac->numbuffers++]; + memset(p->logon_name, 0, sizeof(*p->logon_name)); + p->logon_name->type = PAC_LOGON_NAME; + } + } + + /* Calculate LOGON NAME */ + ret = build_logon_name(context, authtime, principal, &logon); + if (ret) + goto out; + + /* Set lengths for checksum */ + + ret = pac_checksum(context, server_key, &server_cksumtype, &server_size); + if (ret) + goto out; + ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size); + if (ret) + goto out; + + /* Encode PAC */ + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + spdata = krb5_storage_emem(); + if (spdata == NULL) { + krb5_storage_free(sp); + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out); + CHECK(ret, krb5_store_uint32(sp, p->pac->version), out); + + end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers); + + for (i = 0; i < p->pac->numbuffers; i++) { + uint32_t len; + size_t sret; + void *ptr = NULL; + + /* store data */ + + if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) { + len = server_size + 4; + server_offset = end + 4; + CHECK(ret, krb5_store_uint32(spdata, server_cksumtype), out); + CHECK(ret, fill_zeros(context, spdata, server_size), out); + } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) { + len = priv_size + 4; + priv_offset = end + 4; + CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out); + CHECK(ret, fill_zeros(context, spdata, priv_size), out); + } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { + len = krb5_storage_write(spdata, logon.data, logon.length); + if (logon.length != len) { + ret = EINVAL; + goto out; + } + } else { + len = p->pac->buffers[i].buffersize; + ptr = (char *)p->data.data + p->pac->buffers[i].offset_lo; + + sret = krb5_storage_write(spdata, ptr, len); + if (sret != len) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + /* XXX if not aligned, fill_zeros */ + } + + /* write header */ + CHECK(ret, krb5_store_uint32(sp, p->pac->buffers[i].type), out); + CHECK(ret, krb5_store_uint32(sp, len), out); + CHECK(ret, krb5_store_uint32(sp, end), out); + CHECK(ret, krb5_store_uint32(sp, 0), out); + + /* advance data endpointer and align */ + { + int32_t e; + + end += len; + e = ((end + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT; + if (end != e) { + CHECK(ret, fill_zeros(context, spdata, e - end), out); + } + end = e; + } + + } + + /* assert (server_offset != 0 && priv_offset != 0); */ + + /* export PAC */ + ret = krb5_storage_to_data(spdata, &d); + if (ret) { + krb5_set_error_string(context, "out of memory"); + goto out; + } + ret = krb5_storage_write(sp, d.data, d.length); + if (ret != d.length) { + krb5_data_free(&d); + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + krb5_data_free(&d); + + ret = krb5_storage_to_data(sp, &d); + if (ret) { + krb5_set_error_string(context, "out of memory"); + goto out; + } + + /* sign */ + + ret = create_checksum(context, server_key, + d.data, d.length, + (char *)d.data + server_offset, server_size); + if (ret) { + krb5_data_free(&d); + goto out; + } + + ret = create_checksum(context, priv_key, + (char *)d.data + server_offset, server_size, + (char *)d.data + priv_offset, priv_size); + if (ret) { + krb5_data_free(&d); + goto out; + } + + /* done */ + *data = d; + + krb5_data_free(&logon); + krb5_storage_free(sp); + krb5_storage_free(spdata); + + return 0; +out: + krb5_data_free(&logon); + if (sp) + krb5_storage_free(sp); + if (spdata) + krb5_storage_free(spdata); + return ret; +} diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c index f519b5ad08..4f8ed8fe07 100755 --- a/source4/heimdal/lib/krb5/pkinit.c +++ b/source4/heimdal/lib/krb5/pkinit.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: pkinit.c,v 1.110 2006/10/14 09:52:50 lha Exp $"); +RCSID("$Id: pkinit.c,v 1.120 2006/12/08 02:48:09 lha Exp $"); struct krb5_dh_moduli { char *name; @@ -81,12 +81,26 @@ struct krb5_pk_init_ctx_data { DH *dh; krb5_data *clientDHNonce; struct krb5_dh_moduli **m; + hx509_peer_info peer; + int type; int require_binding; int require_eku; int require_krbtgt_otherName; int require_hostname_match; }; +static void +_krb5_pk_copy_error(krb5_context context, + hx509_context hx509ctx, + int hxret, + const char *fmt, + ...) + __attribute__ ((format (printf, 4, 5))); + +/* + * + */ + void KRB5_LIB_FUNCTION _krb5_pk_cert_free(struct krb5_pk_cert *cert) { @@ -130,6 +144,7 @@ _krb5_pk_create_sign(krb5_context context, const heim_oid *eContentType, krb5_data *eContent, struct krb5_pk_identity *id, + hx509_peer_info peer, krb5_data *sd_data) { hx509_cert cert; @@ -137,16 +152,22 @@ _krb5_pk_create_sign(krb5_context context, int ret; ret = hx509_query_alloc(id->hx509ctx, &q); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Allocate query to find signing certificate"); return ret; + } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); ret = hx509_certs_find(id->hx509ctx, id->certs, q, &cert); hx509_query_free(id->hx509ctx, q); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Find certificate to signed CMS data"); return ret; + } ret = hx509_cms_create_signed_1(id->hx509ctx, eContentType, @@ -154,9 +175,12 @@ _krb5_pk_create_sign(krb5_context context, eContent->length, NULL, cert, + peer, NULL, - NULL, + id->certs, sd_data); + if (ret) + _krb5_pk_copy_error(context, id->hx509ctx, ret, "create CMS signedData"); hx509_cert_free(cert); return ret; @@ -402,6 +426,19 @@ build_auth_pack(krb5_context context, a->clientPublicValue->subjectPublicKey.data = dhbuf.data; } + { + a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes)); + if (a->supportedCMSTypes == NULL) + return ENOMEM; + + ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL, + &a->supportedCMSTypes->val, + &a->supportedCMSTypes->len); + if (ret) + return ret; + } + + return ret; } @@ -429,7 +466,6 @@ _krb5_pk_mk_ContentInfo(krb5_context context, static krb5_error_code pk_mk_padata(krb5_context context, - int compat, krb5_pk_init_ctx ctx, const KDC_REQ_BODY *req_body, unsigned nonce, @@ -446,7 +482,7 @@ pk_mk_padata(krb5_context context, krb5_data_zero(&sd_buf); memset(&content_info, 0, sizeof(content_info)); - if (compat == COMPAT_WIN2K) { + if (ctx->type == COMPAT_WIN2K) { AuthPack_Win2k ap; krb5_timestamp sec; int32_t usec; @@ -483,7 +519,7 @@ pk_mk_padata(krb5_context context, krb5_abortx(context, "internal ASN1 encoder error"); oid = oid_id_pkcs7_data(); - } else if (compat == COMPAT_IETF) { + } else if (ctx->type == COMPAT_IETF) { AuthPack ap; memset(&ap, 0, sizeof(ap)); @@ -510,7 +546,8 @@ pk_mk_padata(krb5_context context, ret = _krb5_pk_create_sign(context, oid, &buf, - ctx->id, + ctx->id, + ctx->peer, &sd_buf); krb5_data_free(&buf); if (ret) @@ -529,7 +566,7 @@ pk_mk_padata(krb5_context context, if (buf.length != size) krb5_abortx(context, "Internal ASN1 encoder error"); - if (compat == COMPAT_WIN2K) { + if (ctx->type == COMPAT_WIN2K) { PA_PK_AS_REQ_Win2k winreq; pa_type = KRB5_PADATA_PK_AS_REQ_WIN; @@ -542,7 +579,7 @@ pk_mk_padata(krb5_context context, &winreq, &size, ret); free_PA_PK_AS_REQ_Win2k(&winreq); - } else if (compat == COMPAT_IETF) { + } else if (ctx->type == COMPAT_IETF) { PA_PK_AS_REQ req; pa_type = KRB5_PADATA_PK_AS_REQ; @@ -583,7 +620,7 @@ pk_mk_padata(krb5_context context, if (ret) free(buf.data); - if (ret == 0 && compat == COMPAT_WIN2K) + if (ret == 0 && ctx->type == COMPAT_WIN2K) krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); out: @@ -601,13 +638,13 @@ _krb5_pk_mk_padata(krb5_context context, METHOD_DATA *md) { krb5_pk_init_ctx ctx = c; - int win2k_compat, type; + int win2k_compat; win2k_compat = krb5_config_get_bool_default(context, NULL, FALSE, "realms", req_body->realm, - "win2k_pkinit", + "pkinit_win2k", NULL); if (context->pkinit_flags & KRB5_PKINIT_WIN2K) win2k_compat = 1; @@ -618,11 +655,11 @@ _krb5_pk_mk_padata(krb5_context context, FALSE, "realms", req_body->realm, - "win2k_pkinit_require_binding", + "pkinit_win2k_require_binding", NULL); - type = COMPAT_WIN2K; + ctx->type = COMPAT_WIN2K; } else - type = COMPAT_IETF; + ctx->type = COMPAT_IETF; ctx->require_eku = krb5_config_get_bool_default(context, NULL, @@ -647,7 +684,7 @@ _krb5_pk_mk_padata(krb5_context context, "pkinit_require_hostname_match", NULL); - return pk_mk_padata(context, type, ctx, req_body, nonce, md); + return pk_mk_padata(context, ctx, req_body, nonce, md); } krb5_error_code KRB5_LIB_FUNCTION @@ -673,13 +710,8 @@ _krb5_pk_verify_sign(krb5_context context, content, &signer_certs); if (ret) { - char *s = hx509_get_error_string(id->hx509ctx, ret); - if (s) { - krb5_set_error_string(context, - "CMS verify signed failed with %s", s); - free(s); - } else - krb5_clear_error_string(context); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "CMS verify signed failed"); return ret; } @@ -692,7 +724,8 @@ _krb5_pk_verify_sign(krb5_context context, ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert); if (ret) { - krb5_clear_error_string(context); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to get on of the signer certs"); goto out; } @@ -932,8 +965,11 @@ pk_rd_pa_reply_enckey(krb5_context context, NULL, &contentType, &content); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, ctx->id->hx509ctx, ret, + "Failed to unenvelope CMS data in PK-INIT reply"); return ret; + } p = content.data; length = content.length; @@ -1212,8 +1248,13 @@ _krb5_pk_rd_pa_reply(krb5_context context, size_t size; /* Check for IETF PK-INIT first */ - if (pa->padata_type == KRB5_PADATA_PK_AS_REP) { + if (ctx->type == COMPAT_IETF) { PA_PK_AS_REP rep; + + if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { + krb5_set_error_string(context, "PKINIT: wrong padata recv"); + return EINVAL; + } memset(&rep, 0, sizeof(rep)); @@ -1269,14 +1310,19 @@ _krb5_pk_rd_pa_reply(krb5_context context, ret = EINVAL; break; } - if (ret == 0) - return ret; - } - /* Check for Windows encoding of the AS-REP pa data */ - { + } else if (ctx->type == COMPAT_WIN2K) { PA_PK_AS_REP_Win2k w2krep; + /* Check for Windows encoding of the AS-REP pa data */ + +#if 0 /* should this be ? */ + if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { + krb5_set_error_string(context, "PKINIT: wrong padata recv"); + return EINVAL; + } +#endif + memset(&w2krep, 0, sizeof(w2krep)); ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data, @@ -1317,6 +1363,9 @@ _krb5_pk_rd_pa_reply(krb5_context context, break; } + } else { + krb5_set_error_string(context, "PKINIT: unknown reply type"); + ret = EINVAL; } return ret; @@ -1428,25 +1477,34 @@ _krb5_pk_load_id(krb5_context context, } ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to init cert certs"); goto out; + } ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to init anchors"); goto out; + } ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain", 0, NULL, &id->certpool); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to init chain"); goto out; + } while (chain_list && *chain_list) { ret = hx509_certs_append(id->hx509ctx, id->certpool, NULL, *chain_list); if (ret) { - krb5_set_error_string(context, - "pkinit failed to load chain %s", - *chain_list); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to laod chain %s", + *chain_list); goto out; } chain_list++; @@ -1455,7 +1513,8 @@ _krb5_pk_load_id(krb5_context context, if (revoke_list) { ret = hx509_revoke_init(id->hx509ctx, &id->revokectx); if (ret) { - krb5_set_error_string(context, "revoke failed to init"); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed init revoke list"); goto out; } @@ -1464,9 +1523,8 @@ _krb5_pk_load_id(krb5_context context, id->revokectx, *revoke_list); if (ret) { - krb5_set_error_string(context, - "pkinit failed to load revoke %s", - *revoke_list); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed load revoke list"); goto out; } revoke_list++; @@ -1475,8 +1533,11 @@ _krb5_pk_load_id(krb5_context context, hx509_context_set_missing_revoke(id->hx509ctx, 1); ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed init verify context"); goto out; + } hx509_verify_attach_anchors(id->verify_ctx, id->anchors); hx509_verify_attach_revoke(id->verify_ctx, id->revokectx); @@ -1504,9 +1565,25 @@ select_dh_group(krb5_context context, DH *dh, unsigned long bits, { const struct krb5_dh_moduli *m; - m = moduli[1]; /* XXX */ - if (m == NULL) - m = moduli[0]; /* XXX */ + if (bits == 0) { + m = moduli[1]; /* XXX */ + if (m == NULL) + m = moduli[0]; /* XXX */ + } else { + int i; + for (i = 0; moduli[i] != NULL; i++) { + if (bits < moduli[i]->bits) + break; + } + if (moduli[i] == NULL) { + krb5_set_error_string(context, + "Did not find a DH group parameter " + "matching requirement of %lu bits", + bits); + return EINVAL; + } + m = moduli[i]; + } dh->p = integer_to_BN(context, "p", &m->p); if (dh->p == NULL) @@ -1822,25 +1899,25 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, opt->opt_private->pk_init_ctx->require_binding = 0; opt->opt_private->pk_init_ctx->require_eku = 1; opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1; - + opt->opt_private->pk_init_ctx->peer = NULL; /* XXX implement krb5_appdefault_strings */ if (pool == NULL) pool = krb5_config_get_strings(context, NULL, "appdefaults", - "pkinit-pool", + "pkinit_pool", NULL); if (pki_revoke == NULL) pki_revoke = krb5_config_get_strings(context, NULL, "appdefaults", - "pkinit-revoke", + "pkinit_revoke", NULL); if (x509_anchors == NULL) { krb5_appdefault_string(context, "kinit", krb5_principal_get_realm(context, principal), - "pkinit-anchors", NULL, &anchors); + "pkinit_anchors", NULL, &anchors); x509_anchors = anchors; } @@ -1861,12 +1938,19 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, if ((flags & 2) == 0) { const char *moduli_file; + unsigned long dh_min_bits; moduli_file = krb5_config_get_string(context, NULL, "libdefaults", "moduli", NULL); + dh_min_bits = + krb5_config_get_int_default(context, NULL, 0, + "libdefaults", + "pkinit_dh_min_bits", + NULL); + ret = _krb5_parse_moduli(context, moduli_file, &opt->opt_private->pk_init_ctx->m); if (ret) { @@ -1881,7 +1965,8 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return ENOMEM; } - ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, 0, + ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, + dh_min_bits, opt->opt_private->pk_init_ctx->m); if (ret) { _krb5_get_init_creds_opt_free_pkinit(opt); @@ -1901,3 +1986,36 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return EINVAL; #endif } + +/* + * + */ + +static void +_krb5_pk_copy_error(krb5_context context, + hx509_context hx509ctx, + int hxret, + const char *fmt, + ...) +{ + va_list va; + char *s, *f; + + va_start(va, fmt); + vasprintf(&f, fmt, va); + va_end(va); + if (f == NULL) { + krb5_clear_error_string(context); + return; + } + + s = hx509_get_error_string(hx509ctx, hxret); + if (s == NULL) { + krb5_clear_error_string(context); + free(f); + return; + } + krb5_set_error_string(context, "%s: %s", f, s); + free(s); + free(f); +} diff --git a/source4/heimdal/lib/krb5/plugin.c b/source4/heimdal/lib/krb5/plugin.c index 294807faab..ce7171dbf0 100644 --- a/source4/heimdal/lib/krb5/plugin.c +++ b/source4/heimdal/lib/krb5/plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: plugin.c,v 1.2 2006/11/12 21:39:43 lha Exp $"); +RCSID("$Id: plugin.c,v 1.4 2007/01/09 17:46:01 lha Exp $"); #ifdef HAVE_DLFCN_H #include <dlfcn.h> #endif @@ -89,7 +89,11 @@ loadlib(krb5_context context, return ENOMEM; } - (*e)->dsohandle = dlopen(lib, 0); +#ifndef RTLD_LAZY +#define RTLD_LAZY 0 +#endif + + (*e)->dsohandle = dlopen(lib, RTLD_LAZY); if ((*e)->dsohandle == NULL) { free(*e); krb5_set_error_string(context, "Failed to load %s: %s", diff --git a/source4/heimdal/lib/krb5/principal.c b/source4/heimdal/lib/krb5/principal.c index 4d13e7db11..57fcf63dcf 100644 --- a/source4/heimdal/lib/krb5/principal.c +++ b/source4/heimdal/lib/krb5/principal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -41,7 +41,7 @@ #include <fnmatch.h> #include "resolve.h" -RCSID("$Id: principal.c,v 1.99 2006/10/18 06:53:22 lha Exp $"); +RCSID("$Id: principal.c,v 1.100 2006/12/17 22:53:39 lha Exp $"); #define princ_num_comp(P) ((P)->name.name_string.len) #define princ_type(P) ((P)->name.name_type) diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c index 3352334f65..b7dea2a327 100644 --- a/source4/heimdal/lib/krb5/rd_req.c +++ b/source4/heimdal/lib/krb5/rd_req.c @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: rd_req.c,v 1.68 2006/11/07 17:11:31 lha Exp $"); +RCSID("$Id: rd_req.c,v 1.70 2007/01/04 11:27:20 lha Exp $"); static krb5_error_code decrypt_tkt_enc_part (krb5_context context, @@ -513,6 +513,7 @@ krb5_verify_ap_req2(krb5_context context, struct krb5_rd_req_in_ctx { krb5_keytab keytab; krb5_keyblock *keyblock; + krb5_boolean no_pac_check; }; struct krb5_rd_req_out_ctx { @@ -546,6 +547,16 @@ krb5_rd_req_in_set_keytab(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_req_in_set_pac_check(krb5_context context, + krb5_rd_req_in_ctx in, + krb5_boolean flag) +{ + in->no_pac_check = !flag; + return 0; +} + + +krb5_error_code KRB5_LIB_FUNCTION krb5_rd_req_in_set_keyblock(krb5_context context, krb5_rd_req_in_ctx in, krb5_keyblock *keyblock) @@ -822,6 +833,36 @@ krb5_rd_req_ctx(krb5_context context, &o->ap_req_options, &o->ticket); + if (ret) + goto out; + + /* If there is a PAC, verify its server signature */ + if (inctx->no_pac_check == FALSE) { + krb5_pac pac; + krb5_data data; + + ret = krb5_ticket_get_authorization_data_type(context, + o->ticket, + KRB5_AUTHDATA_WIN2K_PAC, + &data); + if (ret == 0) { + ret = krb5_pac_parse(context, data.data, data.length, &pac); + krb5_data_free(&data); + if (ret) + goto out; + + ret = krb5_pac_verify(context, + pac, + o->ticket->ticket.authtime, + o->ticket->client, + o->keyblock, + NULL); + krb5_pac_free(context, pac); + if (ret) + goto out; + } + ret = 0; + } out: if (ret || outctx == NULL) { krb5_rd_req_out_ctx_free(context, o); diff --git a/source4/heimdal/lib/krb5/store.c b/source4/heimdal/lib/krb5/store.c index e75f28ca5f..5422c540b9 100644 --- a/source4/heimdal/lib/krb5/store.c +++ b/source4/heimdal/lib/krb5/store.c @@ -34,7 +34,7 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id: store.c,v 1.59 2006/08/18 08:39:13 lha Exp $"); +RCSID("$Id: store.c,v 1.60 2006/12/17 22:49:37 lha Exp $"); #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V)) #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE) @@ -577,6 +577,7 @@ krb5_ret_principal(krb5_storage *sp, p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val)); if(p->name.name_string.val == NULL && ncomp != 0){ free(p->realm); + free(p); return ENOMEM; } for(i = 0; i < ncomp; i++){ diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c index fdc2a1b3a5..81372c158e 100644 --- a/source4/heimdal/lib/krb5/ticket.c +++ b/source4/heimdal/lib/krb5/ticket.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: ticket.c,v 1.15 2006/10/14 09:53:19 lha Exp $"); +RCSID("$Id: ticket.c,v 1.18 2006/12/28 20:49:18 lha Exp $"); krb5_error_code KRB5_LIB_FUNCTION krb5_free_ticket(krb5_context context, @@ -97,6 +97,13 @@ krb5_ticket_get_server(krb5_context context, return krb5_copy_principal(context, ticket->server, server); } +time_t KRB5_LIB_FUNCTION +krb5_ticket_get_endtime(krb5_context context, + const krb5_ticket *ticket) +{ + return ticket->ticket.endtime; +} + static int find_type_in_ad(krb5_context context, int type, @@ -107,10 +114,6 @@ find_type_in_ad(krb5_context context, const AuthorizationData *ad, int level) { - /* It is not an error if nothing in here, that is reported by *found */ - /* Setting a default error causes found to be set to FALSE, on - * recursion to an second embedded authz data even if the first - * element contains the required type */ krb5_error_code ret = 0; int i; @@ -148,8 +151,8 @@ find_type_in_ad(krb5_context context, "IF_RELEVANT with %d", ret); goto out; } - ret = find_type_in_ad(context, type, data, found, 0, sessionkey, - &child, level + 1); + ret = find_type_in_ad(context, type, data, found, FALSE, + sessionkey, &child, level + 1); free_AuthorizationData(&child); if (ret) goto out; @@ -232,19 +235,6 @@ out: return ret; } -int -_krb5_find_type_in_ad(krb5_context context, - int type, - krb5_data *data, - krb5_boolean *found, - krb5_keyblock *sessionkey, - const AuthorizationData *ad) -{ - krb5_data_zero(data); - return find_type_in_ad(context, type, data, found, TRUE, sessionkey, ad, 0); -} - - /* * Extract the authorization data type of `type' from the * 'ticket'. Store the field in `data'. This function is to use for @@ -259,7 +249,9 @@ krb5_ticket_get_authorization_data_type(krb5_context context, { AuthorizationData *ad; krb5_error_code ret; - krb5_boolean found = 0; + krb5_boolean found = FALSE; + + krb5_data_zero(data); ad = ticket->ticket.authorization_data; if (ticket->ticket.authorization_data == NULL) { @@ -267,8 +259,8 @@ krb5_ticket_get_authorization_data_type(krb5_context context, return ENOENT; /* XXX */ } - ret = _krb5_find_type_in_ad(context, type, data, &found, &ticket->ticket.key, - ticket->ticket.authorization_data); + ret = find_type_in_ad(context, type, data, &found, TRUE, + &ticket->ticket.key, ad, 0); if (ret) return ret; if (!found) { diff --git a/source4/heimdal/lib/krb5/warn.c b/source4/heimdal/lib/krb5/warn.c index f9825914ee..4252865301 100644 --- a/source4/heimdal/lib/krb5/warn.c +++ b/source4/heimdal/lib/krb5/warn.c @@ -34,7 +34,7 @@ #include "krb5_locl.h" #include <err.h> -RCSID("$Id: warn.c,v 1.15 2004/05/25 21:46:26 lha Exp $"); +RCSID("$Id: warn.c,v 1.16 2006/11/21 08:06:40 lha Exp $"); static krb5_error_code _warnerr(krb5_context context, int do_errtext, krb5_error_code code, int level, const char *fmt, va_list ap) @@ -203,3 +203,9 @@ krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac) context->warn_dest = fac; return 0; } + +krb5_log_facility * KRB5_LIB_FUNCTION +krb5_get_warn_dest(krb5_context context) +{ + return context->warn_dest; +} diff --git a/source4/heimdal/lib/ntlm/heimntlm-protos.h b/source4/heimdal/lib/ntlm/heimntlm-protos.h new file mode 100644 index 0000000000..e9e0837003 --- /dev/null +++ b/source4/heimdal/lib/ntlm/heimntlm-protos.h @@ -0,0 +1,120 @@ +/* This is a generated file */ +#ifndef __heimntlm_protos_h__ +#define __heimntlm_protos_h__ + +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int +heim_ntlm_build_ntlm1_master ( + void */*key*/, + size_t /*len*/, + struct ntlm_buf */*session*/, + struct ntlm_buf */*master*/); + +int +heim_ntlm_calculate_ntlm1 ( + void */*key*/, + size_t /*len*/, + unsigned char challange[8], + struct ntlm_buf */*answer*/); + +int +heim_ntlm_calculate_ntlm2 ( + const void */*key*/, + size_t /*len*/, + const char */*username*/, + const char */*target*/, + const unsigned char serverchallange[8], + const struct ntlm_buf */*infotarget*/, + unsigned char ntlmv2[16], + struct ntlm_buf */*answer*/); + +int +heim_ntlm_decode_targetinfo ( + struct ntlm_buf */*data*/, + int /*ucs2*/, + struct ntlm_targetinfo */*ti*/); + +int +heim_ntlm_decode_type1 ( + const struct ntlm_buf */*buf*/, + struct ntlm_type1 */*data*/); + +int +heim_ntlm_decode_type2 ( + const struct ntlm_buf */*buf*/, + struct ntlm_type2 */*type2*/); + +int +heim_ntlm_decode_type3 ( + const struct ntlm_buf */*buf*/, + int /*ucs2*/, + struct ntlm_type3 */*type3*/); + +int +heim_ntlm_encode_targetinfo ( + struct ntlm_targetinfo */*ti*/, + int /*ucs2*/, + struct ntlm_buf */*data*/); + +int +heim_ntlm_encode_type1 ( + const struct ntlm_type1 */*type1*/, + struct ntlm_buf */*data*/); + +int +heim_ntlm_encode_type2 ( + struct ntlm_type2 */*type2*/, + struct ntlm_buf */*data*/); + +int +heim_ntlm_encode_type3 ( + struct ntlm_type3 */*type3*/, + struct ntlm_buf */*data*/); + +void +heim_ntlm_free_targetinfo (struct ntlm_targetinfo */*ti*/); + +void +heim_ntlm_free_type1 (struct ntlm_type1 */*data*/); + +void +heim_ntlm_free_type2 (struct ntlm_type2 */*type2*/); + +void +heim_ntlm_free_type3 (struct ntlm_type3 */*data*/); + +int +heim_ntlm_nt_key ( + const char */*password*/, + struct ntlm_buf */*key*/); + +void +heim_ntlm_ntlmv2_key ( + const void */*key*/, + size_t /*len*/, + const char */*username*/, + const char */*target*/, + unsigned char ntlmv2[16]); + +int +heim_ntlm_verify_ntlm2 ( + const void */*key*/, + size_t /*len*/, + const char */*username*/, + const char */*target*/, + time_t /*now*/, + const unsigned char serverchallange[8], + const struct ntlm_buf */*answer*/, + struct ntlm_buf */*infotarget*/, + unsigned char ntlmv2[16]); + +#ifdef __cplusplus +} +#endif + +#endif /* __heimntlm_protos_h__ */ diff --git a/source4/heimdal/lib/ntlm/heimntlm.h b/source4/heimdal/lib/ntlm/heimntlm.h new file mode 100644 index 0000000000..1e38b2e400 --- /dev/null +++ b/source4/heimdal/lib/ntlm/heimntlm.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: heimntlm.h,v 1.4 2006/12/20 07:28:37 lha Exp $ */ + +#ifndef HEIM_NTLM_H +#define HEIM_NTLM_H + +struct ntlm_buf { + size_t length; + void *data; +}; + +#define NTLM_NEG_UNICODE 0x00000001 +#define NTLM_NEG_SIGN 0x00000010 +#define NTLM_NEG_SEAL 0x00000020 +#define NTLM_NEG_NTLM 0x00000200 + +#define NTLM_SUPPLIED_DOMAIN 0x00001000 +#define NTLM_SUPPLIED_WORKSTAION 0x00002000 + +#define NTLM_NEG_ALWAYS_SIGN 0x00008000 +#define NTLM_NEG_NTLM2_SESSION 0x00080000 + +#define NTLM_NEG_TARGET_DOMAIN 0x00010000 +#define NTLM_ENC_128 0x20000000 +#define NTLM_NEG_KEYEX 0x40000000 + +struct ntlm_targetinfo { + char *servername; + char *domainname; + char *dnsdomainname; + char *dnsservername; +}; + +struct ntlm_type1 { + uint32_t flags; + char *domain; + char *hostname; + uint32_t os[2]; +}; + +struct ntlm_type2 { + uint32_t flags; + char *targetname; + struct ntlm_buf targetinfo; + unsigned char challange[8]; + uint32_t context[2]; + uint32_t os[2]; +}; + +struct ntlm_type3 { + uint32_t flags; + char *username; + char *targetname; + struct ntlm_buf lm; + struct ntlm_buf ntlm; + struct ntlm_buf sessionkey; + char *ws; + uint32_t os[2]; +}; + +#include <heimntlm-protos.h> + +#endif /* NTLM_NTLM_H */ diff --git a/source4/heimdal/lib/ntlm/ntlm.c b/source4/heimdal/lib/ntlm/ntlm.c new file mode 100644 index 0000000000..430e80505e --- /dev/null +++ b/source4/heimdal/lib/ntlm/ntlm.c @@ -0,0 +1,1078 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> + +RCSID("$Id: ntlm.c,v 1.8 2006/12/26 00:25:17 lha Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> + +#include <krb5.h> +#include <roken.h> + +#include "krb5-types.h" +#include "crypto-headers.h" + +#include <heimntlm.h> + + +struct sec_buffer { + uint16_t length; + uint16_t allocated; + uint32_t offset; +}; + +static const unsigned char ntlmsigature[8] = "NTLMSSP\x00"; + +/* + * + */ + +#define CHECK(f, e) \ + do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0) + +static void +_ntlm_free_buf(struct ntlm_buf *p) +{ + if (p->data) + free(p->data); + p->data = NULL; + p->length = 0; +} + + +static int +ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf) +{ + unsigned char *p; + size_t len, i; + + len = strlen(string); + if (len / 2 > UINT_MAX) + return ERANGE; + + buf->length = len * 2; + buf->data = malloc(buf->length); + if (buf->data == NULL && len != 0) { + _ntlm_free_buf(buf); + return ENOMEM; + } + + p = buf->data; + for (i = 0; i < len; i++) { + unsigned char t = (unsigned char)string[i]; + if (t & 0x80) { + _ntlm_free_buf(buf); + return EINVAL; + } + if (up) + t = toupper(t); + p[(i * 2) + 0] = t; + p[(i * 2) + 1] = 0; + } + return 0; +} + +/* + * + */ + +static krb5_error_code +ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf) +{ + krb5_error_code ret; + CHECK(krb5_ret_uint16(sp, &buf->length), 0); + CHECK(krb5_ret_uint16(sp, &buf->allocated), 0); + CHECK(krb5_ret_uint32(sp, &buf->offset), 0); +out: + return ret; +} + +static krb5_error_code +store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf) +{ + krb5_error_code ret; + CHECK(krb5_store_uint16(sp, buf->length), 0); + CHECK(krb5_store_uint16(sp, buf->allocated), 0); + CHECK(krb5_store_uint32(sp, buf->offset), 0); +out: + return ret; +} + +/* + * Strings are either OEM or UNICODE. The later is encoded as ucs2 on + * wire, but using utf8 in memory. + */ + +static krb5_error_code +len_string(int ucs2, const char *s) +{ + size_t len = strlen(s); + if (ucs2) + len *= 2; + return len; +} + +static krb5_error_code +ret_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s) +{ + krb5_error_code ret; + + *s = malloc(desc->length + 1); + CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset); + CHECK(krb5_storage_read(sp, *s, desc->length), desc->length); + (*s)[desc->length] = '\0'; + + if (ucs2) { + size_t i; + for (i = 0; i < desc->length / 2; i++) { + (*s)[i] = (*s)[i * 2]; + if ((*s)[i * 2 + 1]) { + free(*s); + *s = NULL; + return EINVAL; + } + } + (*s)[i] = '\0'; + } + ret = 0; +out: + return ret; + + return 0; +} + +static krb5_error_code +put_string(krb5_storage *sp, int ucs2, const char *s) +{ + krb5_error_code ret; + struct ntlm_buf buf; + + if (ucs2) { + ret = ascii2ucs2le(s, 0, &buf); + if (ret) + return ret; + } else { + buf.data = rk_UNCONST(s); + buf.length = strlen(s); + } + + CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length); + if (ucs2) + _ntlm_free_buf(&buf); + ret = 0; +out: + return ret; +} + +/* + * + */ + +static krb5_error_code +ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf) +{ + krb5_error_code ret; + + buf->data = malloc(desc->length); + buf->length = desc->length; + CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset); + CHECK(krb5_storage_read(sp, buf->data, buf->length), buf->length); + ret = 0; +out: + return ret; +} + +static krb5_error_code +put_buf(krb5_storage *sp, struct ntlm_buf *buf) +{ + krb5_error_code ret; + CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length); + ret = 0; +out: + return ret; +} + +/* + * + */ + +void +heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti) +{ + free(ti->servername); + free(ti->domainname); + free(ti->dnsdomainname); + free(ti->dnsservername); + memset(ti, 0, sizeof(*ti)); +} + +static int +encode_ti_blob(krb5_storage *out, uint16_t type, int ucs2, char *s) +{ + krb5_error_code ret; + CHECK(krb5_store_uint16(out, type), 0); + CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0); + CHECK(put_string(out, ucs2, s), 0); +out: + return ret; +} + +int +heim_ntlm_encode_targetinfo(struct ntlm_targetinfo *ti, + int ucs2, + struct ntlm_buf *data) +{ + krb5_error_code ret; + krb5_storage *out; + + data->data = NULL; + data->length = 0; + + out = krb5_storage_emem(); + if (out == NULL) + return ENOMEM; + + if (ti->servername) + CHECK(encode_ti_blob(out, 1, ucs2, ti->servername), 0); + if (ti->domainname) + CHECK(encode_ti_blob(out, 2, ucs2, ti->domainname), 0); + if (ti->dnsservername) + CHECK(encode_ti_blob(out, 3, ucs2, ti->dnsservername), 0); + if (ti->dnsdomainname) + CHECK(encode_ti_blob(out, 4, ucs2, ti->dnsdomainname), 0); + + /* end tag */ + CHECK(krb5_store_int16(out, 0), 0); + CHECK(krb5_store_int16(out, 0), 0); + + { + krb5_data d; + ret = krb5_storage_to_data(out, &d); + data->data = d.data; + data->length = d.length; + } +out: + krb5_storage_free(out); + return ret; +} + +int +heim_ntlm_decode_targetinfo(struct ntlm_buf *data, int ucs2, + struct ntlm_targetinfo *ti) +{ + memset(ti, 0, sizeof(*ti)); + return 0; +} + +/* + * encoder/decoder type1 messages + */ + +void +heim_ntlm_free_type1(struct ntlm_type1 *data) +{ + free(data->domain); + free(data->hostname); + memset(data, 0, sizeof(*data)); +} + +int +heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data) +{ + krb5_error_code ret; + unsigned char sig[8]; + uint32_t type; + struct sec_buffer domain, hostname; + krb5_storage *in; + + memset(data, 0, sizeof(*data)); + + in = krb5_storage_from_readonly_mem(buf->data, buf->length); + if (in == NULL) { + ret = EINVAL; + goto out; + } + krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); + CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); + CHECK(krb5_ret_uint32(in, &type), 0); + CHECK(type, 1); + CHECK(krb5_ret_uint32(in, &data->flags), 0); + if (data->flags & NTLM_SUPPLIED_DOMAIN) + CHECK(ret_sec_buffer(in, &domain), 0); + if (data->flags & NTLM_SUPPLIED_WORKSTAION) + CHECK(ret_sec_buffer(in, &hostname), 0); +#if 0 + if (domain.offset > 32) { + CHECK(krb5_ret_uint32(in, &data->os[0]), 0); + CHECK(krb5_ret_uint32(in, &data->os[1]), 0); + } +#endif + if (data->flags & NTLM_SUPPLIED_DOMAIN) + CHECK(ret_string(in, 0, &domain, &data->domain), 0); + if (data->flags & NTLM_SUPPLIED_WORKSTAION) + CHECK(ret_string(in, 0, &hostname, &data->hostname), 0); + +out: + krb5_storage_free(in); + if (ret) + heim_ntlm_free_type1(data); + + return ret; +} + +int +heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data) +{ + krb5_error_code ret; + struct sec_buffer domain, hostname; + krb5_storage *out; + uint32_t base, flags; + + flags = type1->flags; + base = 16; + + if (type1->domain) { + base += 8; + flags |= NTLM_SUPPLIED_DOMAIN; + } + if (type1->hostname) { + base += 8; + flags |= NTLM_SUPPLIED_WORKSTAION; + } + if (type1->os[0]) + base += 8; + + if (type1->domain) { + domain.offset = base; + domain.length = len_string(0, type1->domain); + domain.allocated = domain.length; + } + if (type1->hostname) { + hostname.offset = domain.allocated + domain.offset; + hostname.length = len_string(0, type1->hostname); + hostname.allocated = hostname.length; + } + + out = krb5_storage_emem(); + if (out == NULL) + return ENOMEM; + + krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); + CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), + sizeof(ntlmsigature)); + CHECK(krb5_store_uint32(out, 1), 0); + CHECK(krb5_store_uint32(out, flags), 0); + + if (type1->domain) + CHECK(store_sec_buffer(out, &domain), 0); + if (type1->hostname) + CHECK(store_sec_buffer(out, &hostname), 0); + if (type1->os[0]) { + CHECK(krb5_store_uint32(out, type1->os[0]), 0); + CHECK(krb5_store_uint32(out, type1->os[1]), 0); + } + if (type1->domain) + CHECK(put_string(out, 0, type1->domain), 0); + if (type1->hostname) + CHECK(put_string(out, 0, type1->hostname), 0); + + { + krb5_data d; + ret = krb5_storage_to_data(out, &d); + data->data = d.data; + data->length = d.length; + } +out: + krb5_storage_free(out); + + return ret; +} + +/* + * encoder/decoder type 2 messages + */ + +void +heim_ntlm_free_type2(struct ntlm_type2 *type2) +{ + memset(type2, 0, sizeof(*type2)); +} + +int +heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2) +{ + krb5_error_code ret; + unsigned char sig[8]; + uint32_t type, ctx[2]; + struct sec_buffer targetname, targetinfo; + krb5_storage *in; + int ucs2 = 0; + + memset(type2, 0, sizeof(*type2)); + + in = krb5_storage_from_readonly_mem(buf->data, buf->length); + if (in == NULL) { + ret = EINVAL; + goto out; + } + krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); + CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); + CHECK(krb5_ret_uint32(in, &type), 0); + CHECK(type, 2); + + CHECK(ret_sec_buffer(in, &targetname), 0); + CHECK(krb5_ret_uint32(in, &type2->flags), 0); + if (type2->flags & NTLM_NEG_UNICODE) + ucs2 = 1; + CHECK(krb5_storage_read(in, type2->challange, sizeof(type2->challange)), + sizeof(type2->challange)); + CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */ + CHECK(krb5_ret_uint32(in, &ctx[1]), 0); + CHECK(ret_sec_buffer(in, &targetinfo), 0); + /* os version */ +#if 0 + CHECK(krb5_ret_uint32(in, &type2->os[0]), 0); + CHECK(krb5_ret_uint32(in, &type2->os[1]), 0); +#endif + + CHECK(ret_string(in, ucs2, &targetname, &type2->targetname), 0); + CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0); + ret = 0; + +out: + krb5_storage_free(in); + if (ret) + heim_ntlm_free_type2(type2); + + return ret; +} + +int +heim_ntlm_encode_type2(struct ntlm_type2 *type2, struct ntlm_buf *data) +{ + struct sec_buffer targetname, targetinfo; + krb5_error_code ret; + krb5_storage *out = NULL; + uint32_t base; + int ucs2 = 0; + + if (type2->os[0]) + base = 56; + else + base = 48; + + if (type2->flags & NTLM_NEG_UNICODE) + ucs2 = 1; + + targetname.offset = base; + targetname.length = len_string(ucs2, type2->targetname); + targetname.allocated = targetname.length; + + targetinfo.offset = targetname.allocated + targetname.offset; + targetinfo.length = type2->targetinfo.length; + targetinfo.allocated = type2->targetinfo.length; + + out = krb5_storage_emem(); + if (out == NULL) + return ENOMEM; + + krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); + CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), + sizeof(ntlmsigature)); + CHECK(krb5_store_uint32(out, 2), 0); + CHECK(store_sec_buffer(out, &targetname), 0); + CHECK(krb5_store_uint32(out, type2->flags), 0); + CHECK(krb5_storage_write(out, type2->challange, sizeof(type2->challange)), + sizeof(type2->challange)); + CHECK(krb5_store_uint32(out, 0), 0); /* context */ + CHECK(krb5_store_uint32(out, 0), 0); + CHECK(store_sec_buffer(out, &targetinfo), 0); + /* os version */ + if (type2->os[0]) { + CHECK(krb5_store_uint32(out, type2->os[0]), 0); + CHECK(krb5_store_uint32(out, type2->os[1]), 0); + } + CHECK(put_string(out, ucs2, type2->targetname), 0); + CHECK(krb5_storage_write(out, type2->targetinfo.data, + type2->targetinfo.length), + type2->targetinfo.length); + + { + krb5_data d; + ret = krb5_storage_to_data(out, &d); + data->data = d.data; + data->length = d.length; + } + +out: + krb5_storage_free(out); + + return ret; +} + +/* + * encoder/decoder type 2 messages + */ + +void +heim_ntlm_free_type3(struct ntlm_type3 *data) +{ + memset(data, 0, sizeof(*data)); +} + + +/* + * + */ + +int +heim_ntlm_decode_type3(const struct ntlm_buf *buf, + int ucs2, + struct ntlm_type3 *type3) +{ + krb5_error_code ret; + unsigned char sig[8]; + uint32_t type; + krb5_storage *in; + struct sec_buffer lm, ntlm, target, username, sessionkey, ws; + + memset(type3, 0, sizeof(*type3)); + memset(&sessionkey, 0, sizeof(sessionkey)); + + in = krb5_storage_from_readonly_mem(buf->data, buf->length); + if (in == NULL) { + ret = EINVAL; + goto out; + } + krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); + CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); + CHECK(krb5_ret_uint32(in, &type), 0); + CHECK(type, 3); + CHECK(ret_sec_buffer(in, &lm), 0); + CHECK(ret_sec_buffer(in, &ntlm), 0); + CHECK(ret_sec_buffer(in, &target), 0); + CHECK(ret_sec_buffer(in, &username), 0); + CHECK(ret_sec_buffer(in, &ws), 0); + if (lm.offset >= 60) { + CHECK(ret_sec_buffer(in, &sessionkey), 0); + } + if (lm.offset >= 64) { + CHECK(krb5_ret_uint32(in, &type3->flags), 0); + } + if (lm.offset >= 72) { + CHECK(krb5_ret_uint32(in, &type3->os[0]), 0); + CHECK(krb5_ret_uint32(in, &type3->os[1]), 0); + } + CHECK(ret_buf(in, &lm, &type3->lm), 0); + CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0); + CHECK(ret_string(in, ucs2, &target, &type3->targetname), 0); + CHECK(ret_string(in, ucs2, &username, &type3->username), 0); + CHECK(ret_string(in, ucs2, &username, &type3->ws), 0); + if (sessionkey.offset) + CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0); + +out: + krb5_storage_free(in); + if (ret) + heim_ntlm_free_type3(type3); + + return ret; +} + +int +heim_ntlm_encode_type3(struct ntlm_type3 *type3, struct ntlm_buf *data) +{ + struct sec_buffer lm, ntlm, target, username, sessionkey, ws; + krb5_error_code ret; + krb5_storage *out = NULL; + uint32_t base; + int ucs2 = 0; + + memset(&lm, 0, sizeof(lm)); + memset(&ntlm, 0, sizeof(ntlm)); + memset(&target, 0, sizeof(target)); + memset(&username, 0, sizeof(username)); + memset(&ws, 0, sizeof(ws)); + memset(&sessionkey, 0, sizeof(sessionkey)); + + base = 52; + if (type3->sessionkey.length) { + base += 8; /* sessionkey sec buf */ + base += 4; /* flags */ + } + if (type3->os[0]) { + base += 8; + } + + if (type3->flags & NTLM_NEG_UNICODE) + ucs2 = 1; + + lm.offset = base; + lm.length = type3->lm.length; + lm.allocated = type3->lm.length; + + ntlm.offset = lm.offset + lm.allocated; + ntlm.length = type3->ntlm.length; + ntlm.allocated = ntlm.length; + + target.offset = ntlm.offset + ntlm.allocated; + target.length = len_string(ucs2, type3->targetname); + target.allocated = target.length; + + username.offset = target.offset + target.allocated; + username.length = len_string(ucs2, type3->username); + username.allocated = username.length; + + ws.offset = username.offset + username.allocated; + ws.length = len_string(ucs2, type3->ws); + ws.allocated = ws.length; + + sessionkey.offset = ws.offset + ws.allocated; + sessionkey.length = type3->sessionkey.length; + sessionkey.allocated = type3->sessionkey.length; + + out = krb5_storage_emem(); + if (out == NULL) + return ENOMEM; + + krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE); + CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)), + sizeof(ntlmsigature)); + CHECK(krb5_store_uint32(out, 3), 0); + + CHECK(store_sec_buffer(out, &lm), 0); + CHECK(store_sec_buffer(out, &ntlm), 0); + CHECK(store_sec_buffer(out, &target), 0); + CHECK(store_sec_buffer(out, &username), 0); + CHECK(store_sec_buffer(out, &ws), 0); + /* optional */ + if (type3->sessionkey.length) { + CHECK(store_sec_buffer(out, &sessionkey), 0); + CHECK(krb5_store_uint32(out, type3->flags), 0); + } +#if 0 + CHECK(krb5_store_uint32(out, 0), 0); /* os0 */ + CHECK(krb5_store_uint32(out, 0), 0); /* os1 */ +#endif + + CHECK(put_buf(out, &type3->lm), 0); + CHECK(put_buf(out, &type3->ntlm), 0); + CHECK(put_string(out, ucs2, type3->targetname), 0); + CHECK(put_string(out, ucs2, type3->username), 0); + CHECK(put_string(out, ucs2, type3->ws), 0); + CHECK(put_buf(out, &type3->sessionkey), 0); + + { + krb5_data d; + ret = krb5_storage_to_data(out, &d); + data->data = d.data; + data->length = d.length; + } + +out: + krb5_storage_free(out); + + return ret; +} + + +/* + * + */ + +static void +splitandenc(unsigned char *hash, + unsigned char *challange, + unsigned char *answer) +{ + DES_cblock key; + DES_key_schedule sched; + + ((unsigned char*)key)[0] = hash[0]; + ((unsigned char*)key)[1] = (hash[0] << 7) | (hash[1] >> 1); + ((unsigned char*)key)[2] = (hash[1] << 6) | (hash[2] >> 2); + ((unsigned char*)key)[3] = (hash[2] << 5) | (hash[3] >> 3); + ((unsigned char*)key)[4] = (hash[3] << 4) | (hash[4] >> 4); + ((unsigned char*)key)[5] = (hash[4] << 3) | (hash[5] >> 5); + ((unsigned char*)key)[6] = (hash[5] << 2) | (hash[6] >> 6); + ((unsigned char*)key)[7] = (hash[6] << 1); + + DES_set_odd_parity(&key); + DES_set_key(&key, &sched); + DES_ecb_encrypt((DES_cblock *)challange, (DES_cblock *)answer, &sched, 1); + memset(&sched, 0, sizeof(sched)); + memset(key, 0, sizeof(key)); +} + +int +heim_ntlm_nt_key(const char *password, struct ntlm_buf *key) +{ + struct ntlm_buf buf; + MD4_CTX ctx; + int ret; + + key->data = malloc(MD5_DIGEST_LENGTH); + if (key->data == NULL) + return ENOMEM; + key->length = MD5_DIGEST_LENGTH; + + ret = ascii2ucs2le(password, 0, &buf); + if (ret) { + _ntlm_free_buf(key); + return ret; + } + MD4_Init(&ctx); + MD4_Update(&ctx, buf.data, buf.length); + MD4_Final(key->data, &ctx); + _ntlm_free_buf(&buf); + return 0; +} + +int +heim_ntlm_calculate_ntlm1(void *key, size_t len, + unsigned char challange[8], + struct ntlm_buf *answer) +{ + unsigned char res[21]; + + if (len != MD4_DIGEST_LENGTH) + return EINVAL; + + memcpy(res, key, len); + memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH); + + answer->data = malloc(24); + if (answer->data == NULL) + return ENOMEM; + answer->length = 24; + + splitandenc(&res[0], challange, ((unsigned char *)answer->data) + 0); + splitandenc(&res[7], challange, ((unsigned char *)answer->data) + 8); + splitandenc(&res[14], challange, ((unsigned char *)answer->data) + 16); + + return 0; +} + +int +heim_ntlm_build_ntlm1_master(void *key, size_t len, + struct ntlm_buf *session, + struct ntlm_buf *master) +{ + RC4_KEY rc4; + + memset(master, 0, sizeof(*master)); + memset(session, 0, sizeof(*session)); + + if (len != MD4_DIGEST_LENGTH) + return EINVAL; + + session->length = MD4_DIGEST_LENGTH; + session->data = malloc(session->length); + if (session->data == NULL) { + session->length = 0; + return EINVAL; + } + master->length = MD4_DIGEST_LENGTH; + master->data = malloc(master->length); + if (master->data == NULL) { + _ntlm_free_buf(master); + _ntlm_free_buf(session); + return EINVAL; + } + + { + unsigned char sessionkey[MD4_DIGEST_LENGTH]; + MD4_CTX ctx; + + MD4_Init(&ctx); + MD4_Update(&ctx, key, len); + MD4_Final(sessionkey, &ctx); + + RC4_set_key(&rc4, sizeof(sessionkey), sessionkey); + } + + if (RAND_bytes(session->data, session->length) != 1) { + _ntlm_free_buf(master); + _ntlm_free_buf(session); + return EINVAL; + } + + RC4(&rc4, master->length, session->data, master->data); + memset(&rc4, 0, sizeof(rc4)); + + return 0; +} + +/* + * + */ + +void +heim_ntlm_ntlmv2_key(const void *key, size_t len, + const char *username, + const char *target, + unsigned char ntlmv2[16]) +{ + unsigned int hmaclen; + HMAC_CTX c; + + HMAC_CTX_init(&c); + HMAC_Init_ex(&c, key, len, EVP_md5(), NULL); + { + struct ntlm_buf buf; + /* uppercase username and turn it inte ucs2-le */ + ascii2ucs2le(username, 1, &buf); + HMAC_Update(&c, buf.data, buf.length); + free(buf.data); + /* turn target into ucs2-le */ + ascii2ucs2le(target, 0, &buf); + HMAC_Update(&c, buf.data, buf.length); + free(buf.data); + } + HMAC_Final(&c, ntlmv2, &hmaclen); + HMAC_CTX_cleanup(&c); + +} + +/* + * + */ + +#define NTTIME_EPOCH 0x019DB1DED53E8000LL + +static uint64_t +unix2nttime(time_t unix_time) +{ + long long wt; + wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH; + return wt; +} + +static time_t +nt2unixtime(uint64_t t) +{ + t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000); + if (t > (((time_t)(~(uint64_t)0)) >> 1)) + return 0; + return (time_t)t; +} + + +int +heim_ntlm_calculate_ntlm2(const void *key, size_t len, + const char *username, + const char *target, + const unsigned char serverchallange[8], + const struct ntlm_buf *infotarget, + unsigned char ntlmv2[16], + struct ntlm_buf *answer) +{ + krb5_error_code ret; + krb5_data data; + unsigned int hmaclen; + unsigned char ntlmv2answer[16]; + krb5_storage *sp; + unsigned char clientchallange[8]; + HMAC_CTX c; + uint64_t t; + + t = unix2nttime(time(NULL)); + + if (RAND_bytes(clientchallange, sizeof(clientchallange)) != 1) + return EINVAL; + + /* calculate ntlmv2 key */ + + heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2); + + /* calculate and build ntlmv2 answer */ + + sp = krb5_storage_emem(); + if (sp == NULL) + return ENOMEM; + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(krb5_store_uint32(sp, 0x01010000), 0); + CHECK(krb5_store_uint32(sp, 0), 0); + /* timestamp le 64 bit ts */ + CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0); + CHECK(krb5_store_uint32(sp, t >> 32), 0); + CHECK(krb5_storage_write(sp, clientchallange, 8), 8); + CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length), + infotarget->length); + /* unknown */ + /* CHECK(krb5_store_uint32(sp, 0), 0); */ + + CHECK(krb5_storage_to_data(sp, &data), 0); + krb5_storage_free(sp); + sp = NULL; + + HMAC_CTX_init(&c); + HMAC_Init_ex(&c, ntlmv2, sizeof(ntlmv2), EVP_md5(), NULL); + HMAC_Update(&c, data.data, data.length); + HMAC_Update(&c, serverchallange, 8); + HMAC_Final(&c, ntlmv2answer, &hmaclen); + HMAC_CTX_cleanup(&c); + + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_data_free(&data); + return ENOMEM; + } + + CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16); + CHECK(krb5_storage_write(sp, data.data, data.length), data.length); + krb5_data_free(&data); + + CHECK(krb5_storage_to_data(sp, &data), 0); + krb5_storage_free(sp); + sp = NULL; + + answer->data = data.data; + answer->length = data.length; + + return 0; +out: + if (sp) + krb5_storage_free(sp); + return ret; +} + +static const int authtimediff = 3600 * 2; /* 2 hours */ + +int +heim_ntlm_verify_ntlm2(const void *key, size_t len, + const char *username, + const char *target, + time_t now, + const unsigned char serverchallange[8], + const struct ntlm_buf *answer, + struct ntlm_buf *infotarget, + unsigned char ntlmv2[16]) +{ + krb5_error_code ret; + unsigned int hmaclen; + unsigned char clientanswer[16]; + unsigned char serveranswer[16]; + krb5_storage *sp; + HMAC_CTX c; + uint64_t t; + time_t authtime; + uint32_t temp; + + infotarget->length = 0; + infotarget->data = NULL; + + if (answer->length < 16) + return EINVAL; + + if (now == 0) + now = time(NULL); + + /* calculate ntlmv2 key */ + + heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2); + + /* calculate and build ntlmv2 answer */ + + sp = krb5_storage_from_readonly_mem(answer->data, answer->length); + if (sp == NULL) + return ENOMEM; + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(krb5_storage_read(sp, clientanswer, 16), 16); + + CHECK(krb5_ret_uint32(sp, &temp), 0); + CHECK(temp, 0x01010000); + CHECK(krb5_ret_uint32(sp, &temp), 0); + CHECK(temp, 0); + /* timestamp le 64 bit ts */ + CHECK(krb5_ret_uint32(sp, &temp), 0); + t = temp; + CHECK(krb5_ret_uint32(sp, &temp), 0); + t |= ((uint64_t)temp)<< 32; + + authtime = nt2unixtime(t); + + if (abs((int)(authtime - now)) > authtimediff) { + ret = EINVAL; + goto out; + } + + /* client challange */ + CHECK(krb5_storage_read(sp, serveranswer, 8), 8); + + infotarget->length = answer->length - 40; + infotarget->data = malloc(infotarget->length); + if (infotarget->data == NULL) { + ret = ENOMEM; + goto out; + } + CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length), + infotarget->length); + /* XXX remove the unknown uint32_t */ + krb5_storage_free(sp); + sp = NULL; + + HMAC_CTX_init(&c); + HMAC_Init_ex(&c, ntlmv2, sizeof(ntlmv2), EVP_md5(), NULL); + HMAC_Update(&c, ((char *)answer->data) + 16, answer->length - 16); + HMAC_Update(&c, serverchallange, 8); + HMAC_Final(&c, serveranswer, &hmaclen); + HMAC_CTX_cleanup(&c); + + if (memcmp(serveranswer, clientanswer, 16) != 0) { + _ntlm_free_buf(infotarget); + return EINVAL; + } + + return 0; +out: + _ntlm_free_buf(infotarget); + if (sp) + krb5_storage_free(sp); + return ret; +} diff --git a/source4/heimdal/lib/roken/closefrom.c b/source4/heimdal/lib/roken/closefrom.c new file mode 100644 index 0000000000..6b02f1ebca --- /dev/null +++ b/source4/heimdal/lib/roken/closefrom.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$Id: closefrom.c,v 1.2 2005/04/13 08:01:38 lha Exp $"); +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <roken.h> + +int ROKEN_LIB_FUNCTION +closefrom(int fd) +{ + int num = getdtablesize(); + + if (num < 0) + num = 1024; /* XXX */ + + for (; fd <= num; fd++) + close(fd); + + return 0; +} diff --git a/source4/heimdal/lib/roken/dumpdata.c b/source4/heimdal/lib/roken/dumpdata.c new file mode 100644 index 0000000000..402b4b1cb9 --- /dev/null +++ b/source4/heimdal/lib/roken/dumpdata.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$Id: dumpdata.c,v 1.1 2005/09/22 23:51:35 lha Exp $"); +#endif + +#include <unistd.h> + +#include <roken.h> + +/* + * Write datablob to a filename, don't care about errors. + */ + +void ROKEN_LIB_FUNCTION +rk_dumpdata (const char *filename, const void *buf, size_t size) +{ + int fd; + + fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0640); + if (fd < 0) + return; + net_write(fd, buf, size); + close(fd); +} diff --git a/source4/heimdal/lib/roken/erealloc.c b/source4/heimdal/lib/roken/erealloc.c new file mode 100644 index 0000000000..497b1e7ec2 --- /dev/null +++ b/source4/heimdal/lib/roken/erealloc.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$Id: erealloc.c,v 1.6 2005/04/12 11:28:37 lha Exp $"); +#endif + +#include <stdlib.h> +#include <err.h> + +#include <roken.h> + +/* + * Like realloc but never fails. + */ + +void * ROKEN_LIB_FUNCTION +erealloc (void *ptr, size_t sz) +{ + void *tmp = realloc (ptr, sz); + + if (tmp == NULL && sz != 0) + errx (1, "realloc %lu failed", (unsigned long)sz); + return tmp; +} diff --git a/source4/heimdal/lib/roken/parse_bytes.h b/source4/heimdal/lib/roken/parse_bytes.h new file mode 100644 index 0000000000..1537d16c33 --- /dev/null +++ b/source4/heimdal/lib/roken/parse_bytes.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: parse_bytes.h,v 1.4 2005/04/13 13:19:07 lha Exp $ */ + +#ifndef __PARSE_BYTES_H__ +#define __PARSE_BYTES_H__ + +#ifndef ROKEN_LIB_FUNCTION +#ifdef _WIN32 +#define ROKEN_LIB_FUNCTION _stdcall +#else +#define ROKEN_LIB_FUNCTION +#endif +#endif + +int ROKEN_LIB_FUNCTION +parse_bytes (const char *s, const char *def_unit); + +int ROKEN_LIB_FUNCTION +unparse_bytes (int t, char *s, size_t len); + +int ROKEN_LIB_FUNCTION +unparse_bytes_short (int t, char *s, size_t len); + +#endif /* __PARSE_BYTES_H__ */ diff --git a/source4/heimdal/lib/roken/resolve.c b/source4/heimdal/lib/roken/resolve.c index 6a14547c62..0f45bc57b2 100644 --- a/source4/heimdal/lib/roken/resolve.c +++ b/source4/heimdal/lib/roken/resolve.c @@ -504,7 +504,7 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type) memset(&state, 0, sizeof(state)); if(res_ninit(&state)) return NULL; /* is this the best we can do? */ -#elif defined(HAVE__RES) && defined(HAVE_DECL__RES) +#elif defined(HAVE__RES) u_long old_options = 0; #endif @@ -520,7 +520,7 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type) if (_resolve_debug) { #ifdef HAVE_RES_NSEARCH state.options |= RES_DEBUG; -#elif defined(HAVE__RES) && defined(HAVE_DECL__RES) +#elif defined(HAVE__RES) old_options = _res.options; _res.options |= RES_DEBUG; #endif @@ -540,7 +540,7 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type) len = res_search(domain, rr_class, rr_type, reply, size); #endif if (_resolve_debug) { -#if defined(HAVE__RES) && defined(HAVE_DECL__RES) && !defined(HAVE_RES_NSEARCH) +#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH) _res.options = old_options; #endif fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", diff --git a/source4/heimdal/lib/roken/simple_exec.c b/source4/heimdal/lib/roken/simple_exec.c new file mode 100644 index 0000000000..048f2846dd --- /dev/null +++ b/source4/heimdal/lib/roken/simple_exec.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$Id: simple_exec.c,v 1.14 2005/04/13 11:39:00 lha Exp $"); +#endif + +#include <stdarg.h> +#include <stdlib.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> + +#include <roken.h> + +#define EX_NOEXEC 126 +#define EX_NOTFOUND 127 + +/* return values: + -1 on `unspecified' system errors + -2 on fork failures + -3 on waitpid errors + -4 exec timeout + 0- is return value from subprocess + 126 if the program couldn't be executed + 127 if the program couldn't be found + 128- is 128 + signal that killed subprocess + + possible values `func' can return: + ((time_t)-2) exit loop w/o killing child and return + `exec timeout'/-4 from simple_exec + ((time_t)-1) kill child with SIGTERM and wait for child to exit + 0 don't timeout again + n seconds to next timeout + */ + +static int sig_alarm; + +static RETSIGTYPE +sigtimeout(int sig) +{ + sig_alarm = 1; + SIGRETURN(0); +} + +int ROKEN_LIB_FUNCTION +wait_for_process_timed(pid_t pid, time_t (*func)(void *), + void *ptr, time_t timeout) +{ + RETSIGTYPE (*old_func)(int sig) = NULL; + unsigned int oldtime = 0; + int ret; + + sig_alarm = 0; + + if (func) { + old_func = signal(SIGALRM, sigtimeout); + oldtime = alarm(timeout); + } + + while(1) { + int status; + + while(waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) { + ret = -3; + goto out; + } + if (func == NULL) + continue; + if (sig_alarm == 0) + continue; + timeout = (*func)(ptr); + if (timeout == (time_t)-1) { + kill(pid, SIGTERM); + continue; + } else if (timeout == (time_t)-2) { + ret = -4; + goto out; + } + alarm(timeout); + } + if(WIFSTOPPED(status)) + continue; + if(WIFEXITED(status)) { + ret = WEXITSTATUS(status); + break; + } + if(WIFSIGNALED(status)) { + ret = WTERMSIG(status) + 128; + break; + } + } + out: + if (func) { + signal(SIGALRM, old_func); + alarm(oldtime); + } + return ret; +} + +int ROKEN_LIB_FUNCTION +wait_for_process(pid_t pid) +{ + return wait_for_process_timed(pid, NULL, NULL, 0); +} + +int ROKEN_LIB_FUNCTION +pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd, + const char *file, ...) +{ + int in_fd[2], out_fd[2], err_fd[2]; + pid_t pid; + va_list ap; + char **argv; + + if(stdin_fd != NULL) + pipe(in_fd); + if(stdout_fd != NULL) + pipe(out_fd); + if(stderr_fd != NULL) + pipe(err_fd); + pid = fork(); + switch(pid) { + case 0: + va_start(ap, file); + argv = vstrcollect(&ap); + va_end(ap); + if(argv == NULL) + exit(-1); + + /* close pipes we're not interested in */ + if(stdin_fd != NULL) + close(in_fd[1]); + if(stdout_fd != NULL) + close(out_fd[0]); + if(stderr_fd != NULL) + close(err_fd[0]); + + /* pipe everything caller doesn't care about to /dev/null */ + if(stdin_fd == NULL) + in_fd[0] = open(_PATH_DEVNULL, O_RDONLY); + if(stdout_fd == NULL) + out_fd[1] = open(_PATH_DEVNULL, O_WRONLY); + if(stderr_fd == NULL) + err_fd[1] = open(_PATH_DEVNULL, O_WRONLY); + + /* move to proper descriptors */ + if(in_fd[0] != STDIN_FILENO) { + dup2(in_fd[0], STDIN_FILENO); + close(in_fd[0]); + } + if(out_fd[1] != STDOUT_FILENO) { + dup2(out_fd[1], STDOUT_FILENO); + close(out_fd[1]); + } + if(err_fd[1] != STDERR_FILENO) { + dup2(err_fd[1], STDERR_FILENO); + close(err_fd[1]); + } + + closefrom(3); + + execv(file, argv); + exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); + case -1: + if(stdin_fd != NULL) { + close(in_fd[0]); + close(in_fd[1]); + } + if(stdout_fd != NULL) { + close(out_fd[0]); + close(out_fd[1]); + } + if(stderr_fd != NULL) { + close(err_fd[0]); + close(err_fd[1]); + } + return -2; + default: + if(stdin_fd != NULL) { + close(in_fd[0]); + *stdin_fd = fdopen(in_fd[1], "w"); + } + if(stdout_fd != NULL) { + close(out_fd[1]); + *stdout_fd = fdopen(out_fd[0], "r"); + } + if(stderr_fd != NULL) { + close(err_fd[1]); + *stderr_fd = fdopen(err_fd[0], "r"); + } + } + return pid; +} + +int ROKEN_LIB_FUNCTION +simple_execvp_timed(const char *file, char *const args[], + time_t (*func)(void *), void *ptr, time_t timeout) +{ + pid_t pid = fork(); + switch(pid){ + case -1: + return -2; + case 0: + execvp(file, args); + exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); + default: + return wait_for_process_timed(pid, func, ptr, timeout); + } +} + +int ROKEN_LIB_FUNCTION +simple_execvp(const char *file, char *const args[]) +{ + return simple_execvp_timed(file, args, NULL, NULL, 0); +} + +/* gee, I'd like a execvpe */ +int ROKEN_LIB_FUNCTION +simple_execve_timed(const char *file, char *const args[], char *const envp[], + time_t (*func)(void *), void *ptr, time_t timeout) +{ + pid_t pid = fork(); + switch(pid){ + case -1: + return -2; + case 0: + execve(file, args, envp); + exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); + default: + return wait_for_process_timed(pid, func, ptr, timeout); + } +} + +int ROKEN_LIB_FUNCTION +simple_execve(const char *file, char *const args[], char *const envp[]) +{ + return simple_execve_timed(file, args, envp, NULL, NULL, 0); +} + +int ROKEN_LIB_FUNCTION +simple_execlp(const char *file, ...) +{ + va_list ap; + char **argv; + int ret; + + va_start(ap, file); + argv = vstrcollect(&ap); + va_end(ap); + if(argv == NULL) + return -1; + ret = simple_execvp(file, argv); + free(argv); + return ret; +} + +int ROKEN_LIB_FUNCTION +simple_execle(const char *file, ... /* ,char *const envp[] */) +{ + va_list ap; + char **argv; + char *const* envp; + int ret; + + va_start(ap, file); + argv = vstrcollect(&ap); + envp = va_arg(ap, char **); + va_end(ap); + if(argv == NULL) + return -1; + ret = simple_execve(file, argv, envp); + free(argv); + return ret; +} + +int ROKEN_LIB_FUNCTION +simple_execl(const char *file, ...) +{ + va_list ap; + char **argv; + int ret; + + va_start(ap, file); + argv = vstrcollect(&ap); + va_end(ap); + if(argv == NULL) + return -1; + ret = simple_execve(file, argv, environ); + free(argv); + return ret; +} diff --git a/source4/heimdal/lib/roken/strcollect.c b/source4/heimdal/lib/roken/strcollect.c new file mode 100644 index 0000000000..d6f3077348 --- /dev/null +++ b/source4/heimdal/lib/roken/strcollect.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$Id: strcollect.c,v 1.2 2005/04/12 11:29:07 lha Exp $"); +#endif + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <roken.h> + +enum { initial = 10, increment = 5 }; + +static char ** +sub (char **argv, int i, int argc, va_list *ap) +{ + do { + if(i == argc) { + /* realloc argv */ + char **tmp = realloc(argv, (argc + increment) * sizeof(*argv)); + if(tmp == NULL) { + free(argv); + errno = ENOMEM; + return NULL; + } + argv = tmp; + argc += increment; + } + argv[i++] = va_arg(*ap, char*); + } while(argv[i - 1] != NULL); + return argv; +} + +/* + * return a malloced vector of pointers to the strings in `ap' + * terminated by NULL. + */ + +char ** ROKEN_LIB_FUNCTION +vstrcollect(va_list *ap) +{ + return sub (NULL, 0, 0, ap); +} + +/* + * + */ + +char ** ROKEN_LIB_FUNCTION +strcollect(char *first, ...) +{ + va_list ap; + char **ret = malloc (initial * sizeof(char *)); + + if (ret == NULL) + return ret; + + ret[0] = first; + va_start(ap, first); + ret = sub (ret, 1, initial, &ap); + va_end(ap); + return ret; +} diff --git a/source4/heimdal/lib/roken/vis.c b/source4/heimdal/lib/roken/vis.c index a4bde71e9b..3e54f6d58a 100644 --- a/source4/heimdal/lib/roken/vis.c +++ b/source4/heimdal/lib/roken/vis.c @@ -65,7 +65,7 @@ #if 1 #ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id: vis.c,v 1.9 2005/04/12 11:29:15 lha Exp $"); +RCSID("$Id: vis.c,v 1.13 2006/12/15 11:49:22 lha Exp $"); #endif #include <roken.h> #ifndef _DIAGASSERT @@ -108,6 +108,20 @@ __weak_alias(vis,_vis) #define BELL '\007' #endif +char ROKEN_LIB_FUNCTION + *rk_vis (char *, int, int, int); +char ROKEN_LIB_FUNCTION + *rk_svis (char *, int, int, int, const char *); +int ROKEN_LIB_FUNCTION + rk_strvis (char *, const char *, int); +int ROKEN_LIB_FUNCTION + rk_strsvis (char *, const char *, int, const char *); +int ROKEN_LIB_FUNCTION + rk_strvisx (char *, const char *, size_t, int); +int ROKEN_LIB_FUNCTION + rk_strsvisx (char *, const char *, size_t, int, const char *); + + #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') #define iswhite(c) (c == ' ' || c == '\t' || c == '\n') #define issafe(c) (c == '\b' || c == BELL || c == '\r') @@ -208,9 +222,9 @@ do { \ * svis - visually encode characters, also encoding the characters * pointed to by `extra' */ -#ifndef HAVE_SVIS + char * ROKEN_LIB_FUNCTION -svis(char *dst, int c, int flag, int nextc, const char *extra) +rk_svis(char *dst, int c, int flag, int nextc, const char *extra) { _DIAGASSERT(dst != NULL); _DIAGASSERT(extra != NULL); @@ -219,7 +233,6 @@ svis(char *dst, int c, int flag, int nextc, const char *extra) *dst = '\0'; return(dst); } -#endif /* @@ -237,9 +250,9 @@ svis(char *dst, int c, int flag, int nextc, const char *extra) * Strsvisx encodes exactly len bytes from src into dst. * This is useful for encoding a block of data. */ -#ifndef HAVE_STRSVIS + int ROKEN_LIB_FUNCTION -strsvis(char *dst, const char *src, int flag, const char *extra) +rk_strsvis(char *dst, const char *src, int flag, const char *extra) { char c; char *start; @@ -253,12 +266,10 @@ strsvis(char *dst, const char *src, int flag, const char *extra) *dst = '\0'; return (dst - start); } -#endif -#ifndef HAVE_STRVISX int ROKEN_LIB_FUNCTION -strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra) +rk_strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra) { char c; char *start; @@ -274,15 +285,13 @@ strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra) *dst = '\0'; return (dst - start); } -#endif /* * vis - visually encode characters */ -#ifndef HAVE_VIS char * ROKEN_LIB_FUNCTION -vis(char *dst, int c, int flag, int nextc) +rk_vis(char *dst, int c, int flag, int nextc) { char extra[MAXEXTRAS]; @@ -293,7 +302,6 @@ vis(char *dst, int c, int flag, int nextc) *dst = '\0'; return (dst); } -#endif /* @@ -306,25 +314,22 @@ vis(char *dst, int c, int flag, int nextc) * Strvisx encodes exactly len bytes from src into dst. * This is useful for encoding a block of data. */ -#ifndef HAVE_STRVIS + int ROKEN_LIB_FUNCTION -strvis(char *dst, const char *src, int flag) +rk_strvis(char *dst, const char *src, int flag) { char extra[MAXEXTRAS]; MAKEEXTRALIST(flag, extra); - return (strsvis(dst, src, flag, extra)); + return (rk_strsvis(dst, src, flag, extra)); } -#endif -#ifndef HAVE_STRVISX int ROKEN_LIB_FUNCTION -strvisx(char *dst, const char *src, size_t len, int flag) +rk_strvisx(char *dst, const char *src, size_t len, int flag) { char extra[MAXEXTRAS]; MAKEEXTRALIST(flag, extra); - return (strsvisx(dst, src, len, flag, extra)); + return (rk_strsvisx(dst, src, len, flag, extra)); } -#endif diff --git a/source4/heimdal/lib/roken/vis.hin b/source4/heimdal/lib/roken/vis.hin index 5b45c94362..b7a6f3ceff 100644 --- a/source4/heimdal/lib/roken/vis.hin +++ b/source4/heimdal/lib/roken/vis.hin @@ -1,5 +1,5 @@ /* $NetBSD: vis.h,v 1.11 1999/11/25 16:55:50 wennmach Exp $ */ -/* $Id: vis.hin,v 1.3 2005/04/12 11:29:15 lha Exp $ */ +/* $Id: vis.hin,v 1.7 2006/12/15 11:53:09 lha Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -79,20 +79,37 @@ #define UNVIS_END 1 /* no more characters */ char ROKEN_LIB_FUNCTION - *vis (char *, int, int, int); + *rk_vis (char *, int, int, int); char ROKEN_LIB_FUNCTION - *svis (char *, int, int, int, const char *); + *rk_svis (char *, int, int, int, const char *); int ROKEN_LIB_FUNCTION - strvis (char *, const char *, int); + rk_strvis (char *, const char *, int); int ROKEN_LIB_FUNCTION - strsvis (char *, const char *, int, const char *); + rk_strsvis (char *, const char *, int, const char *); int ROKEN_LIB_FUNCTION - strvisx (char *, const char *, size_t, int); + rk_strvisx (char *, const char *, size_t, int); int ROKEN_LIB_FUNCTION - strsvisx (char *, const char *, size_t, int, const char *); + rk_strsvisx (char *, const char *, size_t, int, const char *); int ROKEN_LIB_FUNCTION - strunvis (char *, const char *); + rk_strunvis (char *, const char *); int ROKEN_LIB_FUNCTION - unvis (char *, int, int *, int); + rk_unvis (char *, int, int *, int); + +#undef vis +#define vis(a,b,c,d) rk_vis(a,b,c,d) +#undef svis +#define svis(a,b,c,d,e) rk_svis(a,b,c,d,e) +#undef strvis +#define strvis(a,b,c) rk_strvis(a,b,c) +#undef strsvis +#define strsvis(a,b,c,d) rk_strsvis(a,b,c,d) +#undef strvisx +#define strvisx(a,b,c,d) rk_strvisx(a,b,c,d) +#undef strsvisx +#define strsvisx(a,b,c,d,e) rk_strsvisx(a,b,c,d,e) +#undef strunvis +#define strunvis(a,b) rk_strunvis(a,b) +#undef unvis +#define unvis(a,b,c,d) rk_unvis(a,b,c,d) #endif /* !_VIS_H_ */ diff --git a/source4/heimdal/lib/vers/print_version.c b/source4/heimdal/lib/vers/print_version.c index 92c709b494..5f5a2c4a4a 100644 --- a/source4/heimdal/lib/vers/print_version.c +++ b/source4/heimdal/lib/vers/print_version.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998 - 2004 Kungliga Tekniska Högskolan + * Copyright (c) 1998 - 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id: print_version.c,v 1.9 2005/01/01 14:27:47 lha Exp $"); +RCSID("$Id: print_version.c,v 1.10 2006/12/29 16:00:16 lha Exp $"); #endif #include "roken.h" @@ -50,6 +50,6 @@ print_version(const char *progname) if(*package_list == '\0') package_list = "no version information"; fprintf(stderr, "%s (%s)\n", progname, package_list); - fprintf(stderr, "Copyright 1999-2005 Kungliga Tekniska Högskolan\n"); + fprintf(stderr, "Copyright 1995-2007 Kungliga Tekniska Högskolan\n"); fprintf(stderr, "Send bug-reports to %s\n", PACKAGE_BUGREPORT); } |