r20640: Commit part 2/2
authorAndrew Bartlett <abartlet@samba.org>
Wed, 10 Jan 2007 01:57:32 +0000 (01:57 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:37:20 +0000 (14:37 -0500)
Update Heimdal to match current lorikeet-heimdal.  This includes
integrated PAC hooks, so Samba doesn't have to handle this any more.

This also brings in the PKINIT code, hence so many new files.

Andrew Bartlett
(This used to be commit 351f7040f7bb73b9a60b22b564686f7c2f98a729)

176 files changed:
source4/heimdal/cf/check-var.m4
source4/heimdal/kdc/digest.c
source4/heimdal/kdc/headers.h
source4/heimdal/kdc/kdc-private.h
source4/heimdal/kdc/kdc.h
source4/heimdal/kdc/kdc_locl.h
source4/heimdal/kdc/kerberos5.c
source4/heimdal/kdc/krb5tgs.c
source4/heimdal/kdc/kx509.c [new file with mode: 0644]
source4/heimdal/kdc/pkinit.c
source4/heimdal/kdc/process.c
source4/heimdal/kdc/windc.c [new file with mode: 0644]
source4/heimdal/kdc/windc_plugin.h [new file with mode: 0644]
source4/heimdal/lib/asn1/asn1-common.h
source4/heimdal/lib/asn1/der-protos.h
source4/heimdal/lib/asn1/der_copy.c
source4/heimdal/lib/asn1/der_format.c
source4/heimdal/lib/asn1/der_free.c
source4/heimdal/lib/asn1/der_get.c
source4/heimdal/lib/asn1/der_length.c
source4/heimdal/lib/asn1/der_put.c
source4/heimdal/lib/asn1/digest.asn1
source4/heimdal/lib/asn1/gen.c
source4/heimdal/lib/asn1/gen_copy.c
source4/heimdal/lib/asn1/gen_decode.c
source4/heimdal/lib/asn1/gen_encode.c
source4/heimdal/lib/asn1/gen_free.c
source4/heimdal/lib/asn1/gen_length.c
source4/heimdal/lib/asn1/k5.asn1
source4/heimdal/lib/asn1/kx509.asn1 [new file with mode: 0644]
source4/heimdal/lib/asn1/lex.l
source4/heimdal/lib/asn1/parse.c
source4/heimdal/lib/asn1/parse.y
source4/heimdal/lib/asn1/rfc2459.asn1
source4/heimdal/lib/asn1/symbol.h
source4/heimdal/lib/com_err/lex.c
source4/heimdal/lib/com_err/parse.c
source4/heimdal/lib/com_err/parse.h
source4/heimdal/lib/des/bn.c [new file with mode: 0644]
source4/heimdal/lib/des/dh-imath.c [new file with mode: 0644]
source4/heimdal/lib/des/dh.c [new file with mode: 0644]
source4/heimdal/lib/des/dsa.c [new file with mode: 0644]
source4/heimdal/lib/des/engine.c [new file with mode: 0644]
source4/heimdal/lib/des/imath/LICENSE [new file with mode: 0644]
source4/heimdal/lib/des/imath/imath.c [new file with mode: 0755]
source4/heimdal/lib/des/imath/imath.h [new file with mode: 0755]
source4/heimdal/lib/des/imath/iprime.c [new file with mode: 0755]
source4/heimdal/lib/des/imath/iprime.h [new file with mode: 0755]
source4/heimdal/lib/des/pkcs12.c [new file with mode: 0644]
source4/heimdal/lib/des/resource.h [new file with mode: 0644]
source4/heimdal/lib/des/rsa-imath.c [new file with mode: 0644]
source4/heimdal/lib/des/rsa.c [new file with mode: 0644]
source4/heimdal/lib/des/rsa.h
source4/heimdal/lib/gssapi/gssapi/gssapi.h
source4/heimdal/lib/gssapi/gssapi_mech.h
source4/heimdal/lib/gssapi/krb5/accept_sec_context.c
source4/heimdal/lib/gssapi/krb5/acquire_cred.c
source4/heimdal/lib/gssapi/krb5/add_cred.c
source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c
source4/heimdal/lib/gssapi/krb5/arcfour.c
source4/heimdal/lib/gssapi/krb5/cfx.c
source4/heimdal/lib/gssapi/krb5/cfx.h
source4/heimdal/lib/gssapi/krb5/compare_name.c
source4/heimdal/lib/gssapi/krb5/compat.c
source4/heimdal/lib/gssapi/krb5/context_time.c
source4/heimdal/lib/gssapi/krb5/copy_ccache.c
source4/heimdal/lib/gssapi/krb5/delete_sec_context.c
source4/heimdal/lib/gssapi/krb5/display_name.c
source4/heimdal/lib/gssapi/krb5/display_status.c
source4/heimdal/lib/gssapi/krb5/duplicate_name.c
source4/heimdal/lib/gssapi/krb5/export_name.c
source4/heimdal/lib/gssapi/krb5/export_sec_context.c
source4/heimdal/lib/gssapi/krb5/external.c
source4/heimdal/lib/gssapi/krb5/get_mic.c
source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h
source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h
source4/heimdal/lib/gssapi/krb5/import_name.c
source4/heimdal/lib/gssapi/krb5/import_sec_context.c
source4/heimdal/lib/gssapi/krb5/init.c
source4/heimdal/lib/gssapi/krb5/init_sec_context.c
source4/heimdal/lib/gssapi/krb5/inquire_context.c
source4/heimdal/lib/gssapi/krb5/inquire_cred.c
source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c
source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c
source4/heimdal/lib/gssapi/krb5/process_context_token.c
source4/heimdal/lib/gssapi/krb5/release_cred.c
source4/heimdal/lib/gssapi/krb5/release_name.c
source4/heimdal/lib/gssapi/krb5/set_cred_option.c
source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c
source4/heimdal/lib/gssapi/krb5/unwrap.c
source4/heimdal/lib/gssapi/krb5/verify_mic.c
source4/heimdal/lib/gssapi/krb5/wrap.c
source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c
source4/heimdal/lib/gssapi/mech/gss_mech_switch.c
source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c
source4/heimdal/lib/gssapi/mech/gss_utils.c
source4/heimdal/lib/gssapi/mech/utils.h
source4/heimdal/lib/gssapi/spnego/accept_sec_context.c
source4/heimdal/lib/gssapi/spnego/compat.c
source4/heimdal/lib/gssapi/spnego/context_stubs.c
source4/heimdal/lib/gssapi/spnego/init_sec_context.c
source4/heimdal/lib/gssapi/spnego/spnego-private.h
source4/heimdal/lib/gssapi/spnego/spnego.asn1
source4/heimdal/lib/gssapi/spnego/spnego_locl.h
source4/heimdal/lib/hdb/hdb.c
source4/heimdal/lib/hdb/hdb.h
source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x [new file with mode: 0644]
source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x [new file with mode: 0644]
source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x [new file with mode: 0644]
source4/heimdal/lib/hx509/ca.c [new file with mode: 0644]
source4/heimdal/lib/hx509/cert.c [new file with mode: 0644]
source4/heimdal/lib/hx509/cms.c [new file with mode: 0644]
source4/heimdal/lib/hx509/collector.c [new file with mode: 0644]
source4/heimdal/lib/hx509/crmf.asn1 [new file with mode: 0644]
source4/heimdal/lib/hx509/crypto.c [new file with mode: 0644]
source4/heimdal/lib/hx509/error.c [new file with mode: 0644]
source4/heimdal/lib/hx509/file.c [new file with mode: 0644]
source4/heimdal/lib/hx509/hx509-protos.h [new file with mode: 0644]
source4/heimdal/lib/hx509/hx509.h [new file with mode: 0644]
source4/heimdal/lib/hx509/hx509_err.c [new file with mode: 0644]
source4/heimdal/lib/hx509/hx509_err.et [new file with mode: 0644]
source4/heimdal/lib/hx509/hx_locl.h [new file with mode: 0644]
source4/heimdal/lib/hx509/keyset.c [new file with mode: 0644]
source4/heimdal/lib/hx509/ks_dir.c [new file with mode: 0644]
source4/heimdal/lib/hx509/ks_file.c [new file with mode: 0644]
source4/heimdal/lib/hx509/ks_mem.c [new file with mode: 0644]
source4/heimdal/lib/hx509/ks_null.c [new file with mode: 0644]
source4/heimdal/lib/hx509/ks_p11.c [new file with mode: 0644]
source4/heimdal/lib/hx509/ks_p12.c [new file with mode: 0644]
source4/heimdal/lib/hx509/lock.c [new file with mode: 0644]
source4/heimdal/lib/hx509/name.c [new file with mode: 0644]
source4/heimdal/lib/hx509/ocsp.asn1 [new file with mode: 0644]
source4/heimdal/lib/hx509/peer.c [new file with mode: 0644]
source4/heimdal/lib/hx509/pkcs10.asn1 [new file with mode: 0644]
source4/heimdal/lib/hx509/print.c [new file with mode: 0644]
source4/heimdal/lib/hx509/req.c [new file with mode: 0644]
source4/heimdal/lib/hx509/revoke.c [new file with mode: 0644]
source4/heimdal/lib/hx509/test_name.c [new file with mode: 0644]
source4/heimdal/lib/krb5/acache.c
source4/heimdal/lib/krb5/config_file.c
source4/heimdal/lib/krb5/context.c
source4/heimdal/lib/krb5/crypto.c
source4/heimdal/lib/krb5/fcache.c
source4/heimdal/lib/krb5/get_cred.c
source4/heimdal/lib/krb5/init_creds.c
source4/heimdal/lib/krb5/init_creds_pw.c
source4/heimdal/lib/krb5/krb5-private.h
source4/heimdal/lib/krb5/krb5-protos.h
source4/heimdal/lib/krb5/krb5.h
source4/heimdal/lib/krb5/krb5_locl.h
source4/heimdal/lib/krb5/krbhst.c
source4/heimdal/lib/krb5/log.c
source4/heimdal/lib/krb5/mit_glue.c
source4/heimdal/lib/krb5/mk_req_ext.c
source4/heimdal/lib/krb5/pac.c [new file with mode: 0644]
source4/heimdal/lib/krb5/pkinit.c
source4/heimdal/lib/krb5/plugin.c
source4/heimdal/lib/krb5/principal.c
source4/heimdal/lib/krb5/rd_req.c
source4/heimdal/lib/krb5/store.c
source4/heimdal/lib/krb5/ticket.c
source4/heimdal/lib/krb5/warn.c
source4/heimdal/lib/ntlm/heimntlm-protos.h [new file with mode: 0644]
source4/heimdal/lib/ntlm/heimntlm.h [new file with mode: 0644]
source4/heimdal/lib/ntlm/ntlm.c [new file with mode: 0644]
source4/heimdal/lib/roken/closefrom.c [new file with mode: 0644]
source4/heimdal/lib/roken/dumpdata.c [new file with mode: 0644]
source4/heimdal/lib/roken/erealloc.c [new file with mode: 0644]
source4/heimdal/lib/roken/parse_bytes.h [new file with mode: 0644]
source4/heimdal/lib/roken/resolve.c
source4/heimdal/lib/roken/simple_exec.c [new file with mode: 0644]
source4/heimdal/lib/roken/strcollect.c [new file with mode: 0644]
source4/heimdal/lib/roken/vis.c
source4/heimdal/lib/roken/vis.hin
source4/heimdal/lib/vers/print_version.c

index 41401f6dd93b3e34f55c352b62038c09da67d02a..b33b5c6e285c6559746384bfbb40ef6bf63a07a4 100644 (file)
@@ -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])
index a5517fb89635294f22353472315e0fdb670f7358..2c012a2ead53c1f43ef0d448a88f539f5f3db869 100644 (file)
  */
 
 #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);
index 87d713b076f0c0a18a8374a1f84bc0381659f130..56ddc8090b64b1a7b6a3e94b67158fcf017f3f89 100644 (file)
@@ -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
 #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
index 6d4fd2a29ba12151ab138c8f62a2a93b39b0abfd..d896bd10e9988be4c3800a9657aadf2d8c632943 100644 (file)
@@ -14,6 +14,13 @@ _kdc_add_KRB5SignedPath (
        KRB5SignedPathPrincipals */*principals*/,
        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*/,
@@ -89,6 +96,15 @@ _kdc_do_kaserver (
        const char */*from*/,
        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*/,
@@ -182,6 +198,20 @@ _kdc_maybe_version4 (
        unsigned char */*buf*/,
        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*/,
@@ -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__ */
index 043b6de47d2269d96cf10eacbab32904bcb77cf3..ea9eb7125e504d86b02463082f2afb5723c53429 100644 (file)
@@ -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>
index ca8672c062d5ad5e4ea420adfb90ba2b6864cca3..ed3010b673f6a13de2f8f80512246c3963eb0cc8 100644 (file)
@@ -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"
 
index dd88e2ea503e858d784e934160c24ee1f998d76a..bf727ee739535b99c2817e1ff124d451e7e0a248 100644 (file)
@@ -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))
 
@@ -634,6 +634,69 @@ get_pa_etype_info2(krb5_context context,
     return 0;
 }
 
+/*
+ *
+ */
+
+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
@@ -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;
+}
index dcf29eb6e9867f068e37b6e713ad64f09f89a649..a056839e5f3751a5a7034b429b34e89389b422cd 100644 (file)
@@ -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 (file)
index 0000000..d817338
--- /dev/null
@@ -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;
+}
index 6657ab7c4484c7fff46dee72f1b6de55da2cb0a8..418a38d0307ab2b3969332c0cdf3b5725e20e9eb 100755 (executable)
@@ -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) {
index ed5cb3d651330c046fad37e7fb1059260770f247..a64efaa05ddd216d7898fa7170ff0fa8b265dbe7 100644 (file)
@@ -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 (file)
index 0000000..41e4ad1
--- /dev/null
@@ -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 (file)
index 0000000..a3b7534
--- /dev/null
@@ -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 */
+
index ab06ae79dd630d02670386744f71d584c906fe4b..5f09cd6794650750cdc658c03c07e4de4e659365 100644 (file)
@@ -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;
index 3aee392c962a3c58a28e992c25683f4255e71f37..7bfe02ebb44987ec7ec2f14ef92007e9d24da78d 100644 (file)
@@ -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*/,
@@ -251,6 +259,13 @@ der_get_utf8string (
        heim_utf8_string */*str*/,
        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*/,
@@ -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*/,
@@ -504,6 +522,13 @@ der_put_utf8string (
        const heim_utf8_string */*str*/,
        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*/,
index 96eea9c6d7c99416346417624b6223c3d04ecdce..15e7b817a04ba4d9ef0eb47f283371548303ce41 100644 (file)
@@ -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, 
@@ -88,6 +88,13 @@ der_copy_universal_string (const heim_universal_string *from,
     return 0;
 }
 
+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)
 {
index 9655269356d6a7716aa9ff21fd2ef97d004906cd..32cf23cb39b665e98e4e7805e7b588389dcd2d0b 100644 (file)
@@ -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;
index c3a6a17fff730923cee5c3f0d4f34d196ea101b0..6827486d9f7720d44b5955d889e83760982746f7 100644 (file)
@@ -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)
@@ -79,6 +79,13 @@ der_free_universal_string (heim_universal_string *k)
     k->length = 0;
 }
 
+void
+der_free_visible_string (heim_visible_string *str)
+{
+    free(*str);
+    *str = NULL;
+}
+
 void
 der_free_octet_string (heim_octet_string *k)
 {
index 7808fa81651d7099bf6d633aeef41336d5e8b482..a1ed23f10bce13f4300ef8f237dbf8c9a0566b9e 100644 (file)
@@ -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>
 
@@ -214,6 +214,13 @@ der_get_universal_string (const unsigned char *p, size_t len,
     return 0;
 }
 
+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)
index 9b2e9f09981c981feddfd215e5017feccc3809fc..93cabe466c1e6cc05883feb050b15f6bfc0dc60e 100644 (file)
@@ -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)
@@ -166,6 +166,12 @@ der_length_universal_string (const heim_universal_string *data)
     return data->length * 4;
 }
 
+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)
 {
index b006f233ca62ab8ab9395fc74c8bf61837501782..9ed8f21906e76f1987ca8be10ebff7de850ebddd 100644 (file)
@@ -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
@@ -230,6 +230,13 @@ der_put_universal_string (unsigned char *p, size_t len,
     return 0;
 }
 
+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)
index 1f8f18b5cd946f5f4d70dfa88da4cc29dafeb5a0..92bfb232343a5162bc39a3a2f75669582ba7cd16 100644 (file)
@@ -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 {
index c3af316c888aaa4c14ba8e82316ed016f48d3c45..3bb9022be85db9338c7eab7f832394df861512b3 100644 (file)
@@ -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;
 
@@ -135,6 +135,9 @@ init_generate (const char *filename, const char *base)
             "  size_t length;\n"
             "  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"
@@ -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);
index 9455f33c6f360a7ca1c88baae9da92bef3010a97..95646d0a3c8f70e8819e63dd0107dde4557593e0 100644 (file)
@@ -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;
index 193dab40e1a4e5ced8b1ec5ef35b69a3cd79e155..19ddbb46db67f1fc46cfbd7087873c685b4d5ffc 100644 (file)
@@ -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:
index 4099fbf643331002168ff91bf36596106e729da5..bc2aff86e5dd085c4ce9da8aa43b1cdb05645d77 100644 (file)
@@ -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:
index 2b143bf81898250057f7a622c00f427a9a8ac112..26e02e39dd4937ff73880649d8f9e4f3e070eadd 100644 (file)
@@ -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;
index 0c92225b9248a17ac376ff8df2bf444f6f91db1f..7f9dc7257b98f9f2efcf3073271ef0b9e6916600 100644 (file)
@@ -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;
index 3f501f0592c2e6e63610f2d5394ec39feb505726..a86df38a999175a06c88bfdfcf37d0586ff5db10 100644 (file)
@@ -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 (file)
index 0000000..9706b06
--- /dev/null
@@ -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
index 4b2c5af0621a944ab2196af36d0e4c9ce0cbe64b..6ec7b67bb9cdd65fdd2eb2ccdd072d366ebba9a3 100644 (file)
@@ -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; }
index 29d13ed68d2341c215c9c34697e0d3cd223874bc..fc9f195e1f44751101f9ff1bfc0bd0ca85c24f94 100644 (file)
 #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"
 \f
   yyvsp -= yylen;
   yyssp -= yylen;
@@ -2502,7 +2510,7 @@ yyreturn:
 }
 
 
-#line 879 "parse.y"
+#line 884 "parse.y"
 
 
 void
index 223847828476502ead6ea7e0f66882315d189bd1..029cef9f0f420bbad8e26fe7562fac7b3c82fe54 100644 (file)
@@ -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, 
index eebbc3211b90f9469d3d7da5a8080eb351bd7b16..430674a5ee8c79644737f325e5d0297941e9f508 100644 (file)
@@ -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
index 93a6e019bd600cdf976d54bd5cf830abf8351347..436bd043a18a8c43e2e9ae6290f8e4484aa15f7b 100644 (file)
@@ -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;
index 30b44d0c192d2268279151ddc2c9ee4cf1832916..8b7113baa2f8e5d79c4d3a23458a5d7cd0cd9f00 100644 (file)
@@ -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 */
index a7160a4d42fe5a4ec6c6504866c7e973fcf2aba4..4cef0c492d74a5f67628c65e592a342e3dc72faf 100644 (file)
@@ -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
+
 \f
-/* 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 */
+
+\f
+
+#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;
+    }
+}
 \f
-#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"
 \f
   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);
 }
+
index 07e33790d321b3d90151bce5b3a16292dd02863a..2f9755e19b1fae988da2c7a958cd18918eccc5cc 100644 (file)
@@ -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 (file)
index 0000000..c4230b6
--- /dev/null
@@ -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 (file)
index 0000000..ebf02c7
--- /dev/null
@@ -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 (file)
index 0000000..66d611f
--- /dev/null
@@ -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 (file)
index 0000000..411597b
--- /dev/null
@@ -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 (file)
index 0000000..b72339c
--- /dev/null
@@ -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 (file)
index 0000000..cecfb11
--- /dev/null
@@ -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 (executable)
index 0000000..0a124fa
--- /dev/null
@@ -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 (executable)
index 0000000..93cc356
--- /dev/null
@@ -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 (executable)
index 0000000..582ade0
--- /dev/null
@@ -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 (executable)
index 0000000..cd54a73
--- /dev/null
@@ -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 (file)
index 0000000..cc92285
--- /dev/null
@@ -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 (file)
index 0000000..02c6a7c
--- /dev/null
@@ -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 (file)
index 0000000..298affa
--- /dev/null
@@ -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 (file)
index 0000000..241afb2
--- /dev/null
@@ -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;
+}
index 137dd9894b69fba7cdf840e77518536127d8b79c..0aceb9f9dad0322ee63c99864296abb036f33994 100644 (file)
@@ -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 */
index f89e5dfbeed4260cd581287ac425d1a7b3083e3b..8077aeb2239c26227e1933e2fc9c7d7d11cff63f 100644 (file)
@@ -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
index a05919b51097987a667227f8c30cf458630a6368..2bb5ecedf50687bf26f3e7b35dfa3e74813a6c8d 100644 (file)
@@ -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 */
index 6ac80461c351fec6db4a8136a8eedc7f2f291ba0..434fbee352e7a010630faadf4132c638fbb8163a 100644 (file)
@@ -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,
index df6e1374025b4a667076618e067dbc2121ed52d9..e811a99a8bea6e8020768e41c3c3619b3304ea84 100644 (file)
 
 #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;
index 4892e84798644f6567e81106201d60204d531b71..3b0272af80050628ba2063d5f019fe8bf6bf5f9d 100644 (file)
@@ -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);
index 9aec53faaae69834c0b0600d18cfe32bbb18cdad..18a90fe9a762fbac4da36005b499f8c0d7b9ba06 100644 (file)
@@ -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;  
 }
index 2c43ed8b32182a57973d1fdaa06ead78c28f5efb..d1bdbb641ff64bf8c0a1ef079b26ad4df95b5047 100644 (file)
@@ -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;
 }
index cb3f9ee5d3178654817f9cd04ef612c60f0a7172..e75fe5da9d83e69d3ea1518d691042b4c227985a 100755 (executable)
@@ -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;
index 1120544fbeb285876ae01e25478aa1a5c636f911..ce021aa09934755254517ca26bac7adb4abc0d8c 100755 (executable)
@@ -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_ */
index 3e0f7edfee37099735b2eae47ed7497e37b5c839..6b537468df5e486a919d5aa2465aab9b3c4c7be7 100644 (file)
@@ -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;
index 0ea2fce0e8374bb1f011892f233c00f47338ae8a..3e64df03dbe8d04163ce2d7bb75ca1442b3c5d6a 100644 (file)
 
 #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;
index 4e9d9f5d1d7d4c7d5c6cfa0e57896e96a3c559cb..9012dd0b7f6356f71bddedbf4832006b4476ef33 100644 (file)
 
 #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;
 
index 91d21a1aec4d92c0bd69d8b4aa9e8f3fb0bbb701..4387a4e6ef21b526e56e515098d7d0dc9099219a 100644 (file)
 
 #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;
index e890d7d2c2653bf282206f9ddffe65199bfb529f..c7f2ee262d00f3822368591f15aa97b69647dc9a 100644 (file)
 
 #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);
index 8fce7d8572446d11300073586e37e80c634e9c7c..4956c2d77f4ad8cf770a595471eba807ba5d0bea 100644 (file)
@@ -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);
index 11926ca5579f676d3e8525d8331b2157b0aa40aa..b0155a7fdfd07fca2996a11e6481d08b067c65f8 100644 (file)
@@ -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;
 }
index 475ae61efce0e79ec1d828a76266dc7e3a8e0852..8375257180dfed4c01fd7acc0ae32d724de46680 100644 (file)
@@ -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;
index d00c458898a2bc47959eac6fd2f432c2540f3bb6..646fdafb7c4a950b2cc7acfcb7713bbec15ca240 100644 (file)
@@ -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);
index aff03a0b675840920f1d23549eb4def2b8cab79c..ffa671a4a14684a209e4aa15ee56fb593928a842 100644 (file)
@@ -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);
 
index 0681bd4038684d4f0517bb772c90788e54a353ba..bf7f64cf20e605ac96fb8ff629a27e6376c2be81 100644 (file)
@@ -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;
 
 /*
  *
index 5a078d634d0808e07079479fe1312415c3cb1784..790c9b616633f4f4353169ab8d1b6ff48e955a44 100644 (file)
 
 #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;
 }
index 426c0ab200736ec8f2e2ba2ea6b15fd8fdf09694..15bd5c77daea48aa041cd304f14f0022fca1c8a7 100644 (file)
@@ -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
index 39c800bf31be2d3c7789fb20253704e9c0f04f46..1983a9b8e4dd042e25ce040a8a0270725c6d92e8 100644 (file)
@@ -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;                                   \
     }                                                          \
index dc24ed5cf2088ecd9e9f1057a58c9ca16cc0d4ce..15311b461496fc1025a50351ae66cf570d7e5272 100644 (file)
 
 #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 {
index 8131e2621d12508208752da44fd36f6bc563436f..bbdc1d36d0c12d00e8f39ff9311b64103d143dec 100644 (file)
@@ -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);
index cbef8740b7af058a11bfadb78645e4f4acbdf8e7..3eece8e08642a2cf85901a085fee8204ad60b6e1 100644 (file)
@@ -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. 
  *
 
 #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;
 }
index 27d859ddd88b4e6e16a949b0ebf51a4f1c5f36d8..d5f183b0baab1cb8bfe0bff66fdb90bc09468172 100644 (file)
@@ -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,
index ef43e6852c4c99efc610adc66c45c671bd30e898..bdaa01b108680eb9b3d66933db2073bc834912e8 100644 (file)
@@ -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)
index 0593729365712c61c1a37b1b7826b0c5fa2b3c83..74018559a0b671389d91e03dbe65118815f1dff5 100644 (file)
@@ -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)
index 26927c740ce56e188ed12599472189a9b4aa671c..1a36896019ff3727f7b14d5c5411a457091fe74f 100644 (file)
@@ -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;
     }
 
index ee4210d74a594ab2dadaf6240a4582f48ba11a83..97e86a95c7b4f95387fc80eb69a1f42a66900ff4 100644 (file)
@@ -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;
index 99568c9dd082bf610e3f106287d238d985961218..411d689635e3cb6b96b70283230c492e511ff7b7 100644 (file)
@@ -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");
 
index 662461ccfd663df41023d4cb49899353ed4d55d0..f6d98b29c6d4f6801bad781bcbe449b191f92829 100644 (file)
 
 #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);
index a92ad939a584cd6d96329d0ec0a0d299efb9236d..cc9c0934f75e1370c578d7cea2c2fef3dd205560 100644 (file)
 
 #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;
 }
index 5807ef016618bab6ac68d127d76b73c1e451e13d..849760ee4a6e5d3d158c4109736cf28be3404b91 100644 (file)
@@ -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;
index dc1495efc1be1ee9215ef3157ab29240f3f7b7fc..4a5f60ce94221c0ef58a95c3f4aa0b3462a99925 100644 (file)
@@ -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);
        }
index 758390080cd3bcd882af9cb34c16140a85747c5c..3dd7618561578951e5964549b915f085de485217 100644 (file)
@@ -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;
 }
index 920937cafcdc81425a8b4557e1bb63fb39cee1c6..29b3a7f4bb37aaf5e2f2a5073e91104b6e6c5c68 100644 (file)
 
 #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");
 
index ebbc975b8a308aa1f626583dc3ba982c4814e3bf..79cfb48ed2a8f71ab3295150662c0784adab9a5c 100644 (file)
 
 #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;
 }
index 73207806a03a48c48b6cebdb9921c0228e31618a..7df8a3483eabbfa57ee8f19490c27ae538558808 100644 (file)
@@ -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;
index ccaf91ba9de2de14396bf8dfd38a79ef75bad75c..0d50bbd92bfa612755ca056b964febf08effe4aa 100644 (file)
  */
 
 #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,
index 3d01ba69d49f2c4d120996be3df721d89f4c87a8..b8fdefdca13fdb0ec3f1566c1ae9ca35698d1170 100644 (file)
@@ -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) {
index f8e013da1808f7d8595fec18858f129c9c99bfd6..f813d72ac8bc9ac0efbf11d836e5fb19a2a9ac5c 100644 (file)
@@ -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;
                }
        }
index 33ee03320962ea2d9e43edd3a99caf966a0f6295..d674fb163b273d86c805ce54fe1e31995d80f43d 100644 (file)
@@ -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,
index 75a507298c0a8518c5cd4a0a91bcac877b37eea9..42e92c3f42bc57f5ba6a56797de0d70034de2120 100644 (file)
  * 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);
index 8a885a3e2f71d8bf8db493a5d2162b61453360c8..2c86b3f794ed19e392900c1ab09bae56e25b1b06 100644 (file)
@@ -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.
  *
 
 #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);
+}
index aeae0882580a9adff4bf2e378c9a528db83c0b63..786eac13400aa208534ab2bc71bcaad45a1b6fcd 100644 (file)
@@ -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;
 }
-
index 902ddbbdf9cd63be679f69c045ff0d426b695583..57bc45a49276c7e6efef472392adaa0d6c2fa0c7 100644 (file)
@@ -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 (
index 5a652fdb2e50ba24cb1099b121b275d3d5716671..a221281a70797d4698951243369d1956c00613b1 100644 (file)
 
 #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) {
index df50f65580dcd57e1046ac4c56ebd934ce418714..d80db0018adfc173f3a83dac91b57844f57846b9 100644 (file)
@@ -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*/,
@@ -111,13 +105,6 @@ _gss_spnego_duplicate_name (
        const gss_name_t /*src_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*/,
@@ -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*/,
@@ -270,12 +259,6 @@ _gss_spnego_seal (
        int * /*conf_state*/,
        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*/,
index 187ce0a0a6d5ec803300830801f7b48ca0678a3c..76fafa356c33d2be5ff00ddc0ada19e4de50fd66 100644 (file)
@@ -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
index 255e07d056320c9c4b7d957073679645d2cbe4fc..45dff04313baefba9afa58f163f618fc896c4049 100644 (file)
@@ -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 */
index d1fa4ffd6a6a0d54200c0c176ac70cf70a8f259b..cd4f24a7321d0b86a54737efeb716cecaf058c97 100644 (file)
@@ -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>
index 69c91d12ad3c3b78b9e4afb2f8ab059d1b3c288c..dcfceb58f07ccd73c07490137d1c41317a07ede3 100644 (file)
@@ -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 (file)
index 0000000..e17bad6
--- /dev/null
@@ -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 (file)
index 0000000..6f030f1
--- /dev/null
@@ -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 (file)
index 0000000..36d7422
--- /dev/null
@@ -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 (file)
index 0000000..1a5b494
--- /dev/null
@@ -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 (file)
index 0000000..f84c61a
--- /dev/null
@@ -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 (file)
index 0000000..4ed70b8
--- /dev/null
@@ -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 = &params_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 (file)
index 0000000..ec172f4
--- /dev/null
@@ -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 (file)
index 0000000..4f02b26
--- /dev/null
@@ -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 (file)
index 0000000..dac0a81
--- /dev/null
@@ -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,
+                          &param,
+                          &size);
+    if (ret) {
+       hx509_set_error_string(context, 0, ret, "DSA parameters failed to decode");
+       goto out;
+    }
+
+    dsa->p = heim_int2BN(&param.p);
+    dsa->q = heim_int2BN(&param.q);
+    dsa->g = heim_int2BN(&param.g);
+
+    free_DSAParams(&param);
+
+    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 (file)
index 0000000..770b719
--- /dev/null
@@ -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 (file)
index 0000000..39497fc
--- /dev/null
@@ -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 (file)
index 0000000..4fcab70
--- /dev/null
@@ -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 (file)
index 0000000..70f29ea
--- /dev/null
@@ -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 (file)
index 0000000..339759d
--- /dev/null
@@ -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 (file)
index 0000000..54ec177
--- /dev/null
@@ -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 (file)
index 0000000..78d158f
--- /dev/null
@@ -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 (file)
index 0000000..c3d5ee2
--- /dev/null
@@ -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 (file)
index 0000000..01dcf57
--- /dev/null
@@ -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 (file)
index 0000000..db0f475
--- /dev/null
@@ -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 (file)
index 0000000..dd7b716
--- /dev/null
@@ -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 (file)
index 0000000..1e6c2ea
--- /dev/null
@@ -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 (file)
index 0000000..b103264
--- /dev/null
@@ -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 (file)
index 0000000..69dba80
--- /dev/null
@@ -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 (file)
index 0000000..95fc0aa
--- /dev/null
@@ -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 (file)
index 0000000..92e9e6f
--- /dev/null
@@ -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 (file)
index 0000000..62a2750
--- /dev/null
@@ -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 (file)
index 0000000..f82f287
--- /dev/null
@@ -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 (file)
index 0000000..c33fd36
--- /dev/null
@@ -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 (file)
index 0000000..802ac12
--- /dev/null
@@ -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 (file)
index 0000000..ca7baa5
--- /dev/null
@@ -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 (file)
index 0000000..8067b29
--- /dev/null
@@ -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 (file)
index 0000000..9017e54
--- /dev/null
@@ -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;
+}
index 004926bc894ff88725c7b110cf8a39d11354722c..d20c24699be5489d371f0f30f6c8e72fd74ddc5d 100644 (file)
@@ -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);
index 66051303ed8b5d62938eba318f35e73d527e42ac..bbd9cf4c781550f5aa3e07954c3a75e6213c2841 100644 (file)
@@ -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;
index f3b0fad347a72c76fbaa582bdf24107c3c0b621e..d0317da37554433e23786be05a1619eeb9f00856 100644 (file)
@@ -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;
index 9f6ef6b82b4e72643d6bd336dec3f795410f20c6..6d4a81baa8c4332e56afdd6239d7dee6d8e4f2a7 100644 (file)
@@ -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
@@ -1075,6 +1075,21 @@ krb5_enctype_keysize(krb5_context context,
     return 0;
 }
 
+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,
index 79b809d2a29b59004c4d610f9b7a10b541e31a27..7441509e388c31965c921d6dedec1fe07c12dc80 100644 (file)
@@ -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
 };
index b404c30f6e9fa7e0663c953fdb5441d974daf6df..663b5e7f1b92f5282d9cb0b07328ab8ef0461653 100644 (file)
@@ -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, 
index 6dacb316d8c7b1ddd507c44491a47dee1ad9eff0..a331524a7edee8b281280d5c57aff15aeb10eb49 100644 (file)
@@ -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;
index d43ae0ae6ff54c0e151b56f9d5926578f1192e66..f6f6eac7d5b739fae4edea7837c4c8100c4b1d2e 100644 (file)
@@ -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;
 }
index ba2f75ad229de033ebdfe5687bee74bc481ed55d..c3e573275393dee21538211c7b4eb494c132345f 100644 (file)
@@ -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,37 +290,16 @@ _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*/,
index 8b61e8d7d250d57a37646c15279dd29fdb0b8136..9dfe487b0af955528e9fa48b1e3eb2ef513de08b 100644 (file)
@@ -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 (
@@ -1519,6 +1520,12 @@ krb5_enctype_disable (
        krb5_context /*context*/,
        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*/,
@@ -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*/,
index 1b26e8b3e77935577dd1390878e1001552e4a859..55a83fb53359c9b2645009bba7302a204848d45b 100644 (file)
@@ -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,
index 3fb5461b3cd36318ff9f6ca98b0a9e72e7b8cac1..35d046c8d9dbf257b49e99fea0f8f2e8c4726996 100644 (file)
@@ -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
 
index f395f0d0c301103233bba726f75ee9d3fb339593..3e281e5c639ecda0760a873524b5145f30359b25 100644 (file)
@@ -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))
index e6fcb6bbb926b7bca283fffb9e49ba76bbbe7922..9523ca848c44de97123fff24b24a7c365f88aed5 100644 (file)
@@ -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;
index 493c4cd84539dc2052c5a250d845f40907fbc7ff..c4d3ff53905a8c0d983cff76914dd4aecf5dcd21 100755 (executable)
@@ -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);
 }
index 18b0e3552fa0786191bd17843e8dfbe46f71f571..8646c4ebea6437394e32fd0002c3e22c9f4b8c6d 100644 (file)
@@ -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 (file)
index 0000000..5bc7235
--- /dev/null
@@ -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, &copy);
+       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;
+}
index f519b5ad08608d3d92d98a50587365ddd93ade19..4f8ed8fe0757120c61aadcfd71f7635befb7c397 100755 (executable)
@@ -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);
+}
index 294807faab15bf059581603e0d326f2191727084..ce7171dbf0abf3d18c2a83be874a608bf4be3f88 100644 (file)
@@ -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", 
index 4d13e7db11ff526b2158d0dbb1d27474c06ea3b5..57fcf63dcfa716e6decb49f50241355cd0c61424 100644 (file)
@@ -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)
index 3352334f65775ad23e17307c5d3141bdf18f7f42..b7dea2a3279102b4cbf1bacf10dd1d8791ef21da 100644 (file)
@@ -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 {
@@ -545,6 +546,16 @@ krb5_rd_req_in_set_keytab(krb5_context context,
     return 0;
 }
 
+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,
@@ -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);
index e75f28ca5fafb5f4e186ac06ec40e9e211b1c19f..5422c540b93a75c761938c4500c61016fc5be681 100644 (file)
@@ -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++){
index fdc2a1b3a5d8a8e8a71871c25aeb4d81a2804041..81372c158e2d4cbb072f4c3d768fdab1531c40ba 100644 (file)
@@ -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) {
index f9825914eee13b8f579f178f32661c62fa066a7c..42528653011b5815d3ca08ef55486340343f5445 100644 (file)
@@ -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 (file)
index 0000000..e9e0837
--- /dev/null
@@ -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 (file)
index 0000000..1e38b2e
--- /dev/null
@@ -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 (file)
index 0000000..430e805
--- /dev/null
@@ -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 (file)
index 0000000..6b02f1e
--- /dev/null
@@ -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 (file)
index 0000000..402b4b1
--- /dev/null
@@ -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 (file)
index 0000000..497b1e7
--- /dev/null
@@ -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 (file)
index 0000000..1537d16
--- /dev/null
@@ -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__ */
index 6a14547c62dade38929e4f65f41607ba5e5f147f..0f45bc57b2218736a4b027ef945c5dd56501a118 100644 (file)
@@ -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 (file)
index 0000000..048f284
--- /dev/null
@@ -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 (file)
index 0000000..d6f3077
--- /dev/null
@@ -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;
+}
index a4bde71e9b160a91cf7d6727799b6ccead929bd2..3e54f6d58a6ebe7f00c985429e9ab9bed1ccb441 100644 (file)
@@ -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
index 5b45c943629e45a6562298f7418f3312d80e06e6..b7a6f3ceff1d7026460cf0c775ba017cf959f108 100644 (file)
@@ -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
 #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_ */
index 92c709b494493e404241ef94ea50b8f5bac7ed48..5f5a2c4a4a4f0efd28ef0b87b0c395d002c4de9c 100644 (file)
@@ -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);
 }