summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/heimdal/cf/check-var.m42
-rw-r--r--source4/heimdal/kdc/digest.c542
-rw-r--r--source4/heimdal/kdc/headers.h9
-rw-r--r--source4/heimdal/kdc/kdc-private.h56
-rw-r--r--source4/heimdal/kdc/kdc.h6
-rw-r--r--source4/heimdal/kdc/kdc_locl.h4
-rw-r--r--source4/heimdal/kdc/kerberos5.c273
-rw-r--r--source4/heimdal/kdc/krb5tgs.c338
-rw-r--r--source4/heimdal/kdc/kx509.c370
-rwxr-xr-xsource4/heimdal/kdc/pkinit.c202
-rw-r--r--source4/heimdal/kdc/process.c11
-rw-r--r--source4/heimdal/kdc/windc.c108
-rw-r--r--source4/heimdal/kdc/windc_plugin.h80
-rw-r--r--source4/heimdal/lib/asn1/asn1-common.h3
-rw-r--r--source4/heimdal/lib/asn1/der-protos.h25
-rw-r--r--source4/heimdal/lib/asn1/der_copy.c9
-rw-r--r--source4/heimdal/lib/asn1/der_format.c11
-rw-r--r--source4/heimdal/lib/asn1/der_free.c9
-rw-r--r--source4/heimdal/lib/asn1/der_get.c9
-rw-r--r--source4/heimdal/lib/asn1/der_length.c8
-rw-r--r--source4/heimdal/lib/asn1/der_put.c9
-rw-r--r--source4/heimdal/lib/asn1/digest.asn142
-rw-r--r--source4/heimdal/lib/asn1/gen.c13
-rw-r--r--source4/heimdal/lib/asn1/gen_copy.c5
-rw-r--r--source4/heimdal/lib/asn1/gen_decode.c14
-rw-r--r--source4/heimdal/lib/asn1/gen_encode.c46
-rw-r--r--source4/heimdal/lib/asn1/gen_free.c5
-rw-r--r--source4/heimdal/lib/asn1/gen_length.c5
-rw-r--r--source4/heimdal/lib/asn1/k5.asn16
-rw-r--r--source4/heimdal/lib/asn1/kx509.asn120
-rw-r--r--source4/heimdal/lib/asn1/lex.l8
-rw-r--r--source4/heimdal/lib/asn1/parse.c388
-rw-r--r--source4/heimdal/lib/asn1/parse.y11
-rw-r--r--source4/heimdal/lib/asn1/rfc2459.asn122
-rw-r--r--source4/heimdal/lib/asn1/symbol.h5
-rw-r--r--source4/heimdal/lib/com_err/lex.c74
-rw-r--r--source4/heimdal/lib/com_err/parse.c1874
-rw-r--r--source4/heimdal/lib/com_err/parse.h76
-rw-r--r--source4/heimdal/lib/des/bn.c445
-rw-r--r--source4/heimdal/lib/des/dh-imath.c243
-rw-r--r--source4/heimdal/lib/des/dh.c294
-rw-r--r--source4/heimdal/lib/des/dsa.c125
-rw-r--r--source4/heimdal/lib/des/engine.c345
-rw-r--r--source4/heimdal/lib/des/imath/LICENSE21
-rwxr-xr-xsource4/heimdal/lib/des/imath/imath.c3246
-rwxr-xr-xsource4/heimdal/lib/des/imath/imath.h220
-rwxr-xr-xsource4/heimdal/lib/des/imath/iprime.c186
-rwxr-xr-xsource4/heimdal/lib/des/imath/iprime.h51
-rw-r--r--source4/heimdal/lib/des/pkcs12.c145
-rw-r--r--source4/heimdal/lib/des/resource.h18
-rw-r--r--source4/heimdal/lib/des/rsa-imath.c661
-rw-r--r--source4/heimdal/lib/des/rsa.c471
-rw-r--r--source4/heimdal/lib/des/rsa.h11
-rw-r--r--source4/heimdal/lib/gssapi/gssapi/gssapi.h8
-rw-r--r--source4/heimdal/lib/gssapi/gssapi_mech.h1
-rw-r--r--source4/heimdal/lib/gssapi/krb5/accept_sec_context.c143
-rw-r--r--source4/heimdal/lib/gssapi/krb5/acquire_cred.c112
-rw-r--r--source4/heimdal/lib/gssapi/krb5/add_cred.c31
-rw-r--r--source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c7
-rw-r--r--source4/heimdal/lib/gssapi/krb5/arcfour.c56
-rwxr-xr-xsource4/heimdal/lib/gssapi/krb5/cfx.c133
-rwxr-xr-xsource4/heimdal/lib/gssapi/krb5/cfx.h17
-rw-r--r--source4/heimdal/lib/gssapi/krb5/compare_name.c7
-rw-r--r--source4/heimdal/lib/gssapi/krb5/compat.c23
-rw-r--r--source4/heimdal/lib/gssapi/krb5/context_time.c16
-rw-r--r--source4/heimdal/lib/gssapi/krb5/copy_ccache.c38
-rw-r--r--source4/heimdal/lib/gssapi/krb5/delete_sec_context.c15
-rw-r--r--source4/heimdal/lib/gssapi/krb5/display_name.c9
-rw-r--r--source4/heimdal/lib/gssapi/krb5/display_status.c168
-rw-r--r--source4/heimdal/lib/gssapi/krb5/duplicate_name.c8
-rw-r--r--source4/heimdal/lib/gssapi/krb5/export_name.c9
-rw-r--r--source4/heimdal/lib/gssapi/krb5/export_sec_context.c5
-rw-r--r--source4/heimdal/lib/gssapi/krb5/external.c4
-rw-r--r--source4/heimdal/lib/gssapi/krb5/get_mic.c50
-rw-r--r--source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h34
-rw-r--r--source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h8
-rw-r--r--source4/heimdal/lib/gssapi/krb5/import_name.c24
-rw-r--r--source4/heimdal/lib/gssapi/krb5/import_sec_context.c36
-rw-r--r--source4/heimdal/lib/gssapi/krb5/init.c86
-rw-r--r--source4/heimdal/lib/gssapi/krb5/init_sec_context.c130
-rw-r--r--source4/heimdal/lib/gssapi/krb5/inquire_context.c6
-rw-r--r--source4/heimdal/lib/gssapi/krb5/inquire_cred.c10
-rw-r--r--source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c8
-rw-r--r--source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c49
-rw-r--r--source4/heimdal/lib/gssapi/krb5/process_context_token.c6
-rw-r--r--source4/heimdal/lib/gssapi/krb5/release_cred.c15
-rw-r--r--source4/heimdal/lib/gssapi/krb5/release_name.c9
-rw-r--r--source4/heimdal/lib/gssapi/krb5/set_cred_option.c21
-rw-r--r--source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c15
-rw-r--r--source4/heimdal/lib/gssapi/krb5/unwrap.c43
-rw-r--r--source4/heimdal/lib/gssapi/krb5/verify_mic.c47
-rw-r--r--source4/heimdal/lib/gssapi/krb5/wrap.c109
-rw-r--r--source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c13
-rw-r--r--source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c30
-rw-r--r--source4/heimdal/lib/gssapi/mech/gss_mech_switch.c5
-rw-r--r--source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c4
-rw-r--r--source4/heimdal/lib/gssapi/mech/gss_utils.c13
-rw-r--r--source4/heimdal/lib/gssapi/mech/utils.h3
-rw-r--r--source4/heimdal/lib/gssapi/spnego/accept_sec_context.c978
-rw-r--r--source4/heimdal/lib/gssapi/spnego/compat.c154
-rw-r--r--source4/heimdal/lib/gssapi/spnego/context_stubs.c88
-rw-r--r--source4/heimdal/lib/gssapi/spnego/init_sec_context.c219
-rw-r--r--source4/heimdal/lib/gssapi/spnego/spnego-private.h25
-rw-r--r--source4/heimdal/lib/gssapi/spnego/spnego.asn117
-rw-r--r--source4/heimdal/lib/gssapi/spnego/spnego_locl.h27
-rw-r--r--source4/heimdal/lib/hdb/hdb.c2
-rw-r--r--source4/heimdal/lib/hdb/hdb.h18
-rw-r--r--source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x22
-rw-r--r--source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x22
-rw-r--r--source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x22
-rw-r--r--source4/heimdal/lib/hx509/ca.c893
-rw-r--r--source4/heimdal/lib/hx509/cert.c2214
-rw-r--r--source4/heimdal/lib/hx509/cms.c1279
-rw-r--r--source4/heimdal/lib/hx509/collector.c324
-rw-r--r--source4/heimdal/lib/hx509/crmf.asn1113
-rw-r--r--source4/heimdal/lib/hx509/crypto.c2438
-rw-r--r--source4/heimdal/lib/hx509/error.c141
-rw-r--r--source4/heimdal/lib/hx509/file.c115
-rw-r--r--source4/heimdal/lib/hx509/hx509-protos.h824
-rw-r--r--source4/heimdal/lib/hx509/hx509.h111
-rw-r--r--source4/heimdal/lib/hx509/hx509_err.c157
-rw-r--r--source4/heimdal/lib/hx509/hx509_err.et100
-rw-r--r--source4/heimdal/lib/hx509/hx_locl.h184
-rw-r--r--source4/heimdal/lib/hx509/keyset.c439
-rw-r--r--source4/heimdal/lib/hx509/ks_dir.c223
-rw-r--r--source4/heimdal/lib/hx509/ks_file.c794
-rw-r--r--source4/heimdal/lib/hx509/ks_mem.c223
-rw-r--r--source4/heimdal/lib/hx509/ks_null.c92
-rw-r--r--source4/heimdal/lib/hx509/ks_p11.c1183
-rw-r--r--source4/heimdal/lib/hx509/ks_p12.c697
-rw-r--r--source4/heimdal/lib/hx509/lock.c242
-rw-r--r--source4/heimdal/lib/hx509/name.c550
-rw-r--r--source4/heimdal/lib/hx509/ocsp.asn1113
-rw-r--r--source4/heimdal/lib/hx509/peer.c148
-rw-r--r--source4/heimdal/lib/hx509/pkcs10.asn125
-rw-r--r--source4/heimdal/lib/hx509/print.c538
-rw-r--r--source4/heimdal/lib/hx509/req.c217
-rw-r--r--source4/heimdal/lib/hx509/revoke.c1020
-rw-r--r--source4/heimdal/lib/hx509/test_name.c92
-rw-r--r--source4/heimdal/lib/krb5/acache.c9
-rw-r--r--source4/heimdal/lib/krb5/config_file.c8
-rw-r--r--source4/heimdal/lib/krb5/context.c4
-rw-r--r--source4/heimdal/lib/krb5/crypto.c17
-rw-r--r--source4/heimdal/lib/krb5/fcache.c63
-rw-r--r--source4/heimdal/lib/krb5/get_cred.c4
-rw-r--r--source4/heimdal/lib/krb5/init_creds.c7
-rw-r--r--source4/heimdal/lib/krb5/init_creds_pw.c36
-rw-r--r--source4/heimdal/lib/krb5/krb5-private.h34
-rw-r--r--source4/heimdal/lib/krb5/krb5-protos.h189
-rw-r--r--source4/heimdal/lib/krb5/krb5.h9
-rw-r--r--source4/heimdal/lib/krb5/krb5_locl.h14
-rw-r--r--source4/heimdal/lib/krb5/krbhst.c27
-rw-r--r--source4/heimdal/lib/krb5/log.c4
-rwxr-xr-xsource4/heimdal/lib/krb5/mit_glue.c17
-rw-r--r--source4/heimdal/lib/krb5/mk_req_ext.c6
-rw-r--r--source4/heimdal/lib/krb5/pac.c1034
-rwxr-xr-xsource4/heimdal/lib/krb5/pkinit.c220
-rw-r--r--source4/heimdal/lib/krb5/plugin.c10
-rw-r--r--source4/heimdal/lib/krb5/principal.c4
-rw-r--r--source4/heimdal/lib/krb5/rd_req.c43
-rw-r--r--source4/heimdal/lib/krb5/store.c3
-rw-r--r--source4/heimdal/lib/krb5/ticket.c38
-rw-r--r--source4/heimdal/lib/krb5/warn.c8
-rw-r--r--source4/heimdal/lib/ntlm/heimntlm-protos.h120
-rw-r--r--source4/heimdal/lib/ntlm/heimntlm.h95
-rw-r--r--source4/heimdal/lib/ntlm/ntlm.c1078
-rw-r--r--source4/heimdal/lib/roken/closefrom.c60
-rw-r--r--source4/heimdal/lib/roken/dumpdata.c57
-rw-r--r--source4/heimdal/lib/roken/erealloc.c56
-rw-r--r--source4/heimdal/lib/roken/parse_bytes.h56
-rw-r--r--source4/heimdal/lib/roken/resolve.c6
-rw-r--r--source4/heimdal/lib/roken/simple_exec.c331
-rw-r--r--source4/heimdal/lib/roken/strcollect.c96
-rw-r--r--source4/heimdal/lib/roken/vis.c47
-rw-r--r--source4/heimdal/lib/roken/vis.hin35
-rw-r--r--source4/heimdal/lib/vers/print_version.c6
176 files changed, 30855 insertions, 2843 deletions
diff --git a/source4/heimdal/cf/check-var.m4 b/source4/heimdal/cf/check-var.m4
index 41401f6dd93..b33b5c6e285 100644
--- a/source4/heimdal/cf/check-var.m4
+++ b/source4/heimdal/cf/check-var.m4
@@ -23,3 +23,5 @@ if test "$ac_foo" = yes; then
fi
])
+AC_WARNING_ENABLE([obsolete])
+AU_DEFUN([AC_CHECK_VAR], [rk_CHECK_VAR([$2], [$1])], [foo])
diff --git a/source4/heimdal/kdc/digest.c b/source4/heimdal/kdc/digest.c
index a5517fb8963..2c012a2ead5 100644
--- a/source4/heimdal/kdc/digest.c
+++ b/source4/heimdal/kdc/digest.c
@@ -32,10 +32,112 @@
*/
#include "kdc_locl.h"
-#include <digest_asn1.h>
#include <hex.h>
-RCSID("$Id: digest.c,v 1.7 2006/10/22 20:11:44 lha Exp $");
+RCSID("$Id: digest.c,v 1.19 2006/12/28 17:03:51 lha Exp $");
+
+#define CHAP_MD5 0x10
+#define DIGEST_MD5 0x08
+#define NTLM_V2 0x04
+#define NTLM_V1_SESSION 0x02
+#define NTLM_V1 0x01
+
+const struct units _kdc_digestunits[] = {
+ {"chap-md5", 1U << 4},
+ {"digest-md5", 1U << 3},
+ {"ntlm-v2", 1U << 2},
+ {"ntlm-v1-session", 1U << 1},
+ {"ntlm-v1", 1U << 0},
+ {NULL, 0}
+};
+
+
+static krb5_error_code
+get_digest_key(krb5_context context,
+ krb5_kdc_configuration *config,
+ hdb_entry_ex *server,
+ krb5_crypto *crypto)
+{
+ krb5_error_code ret;
+ krb5_enctype enctype;
+ Key *key;
+
+ ret = _kdc_get_preferred_key(context,
+ config,
+ server,
+ "digest-service",
+ &enctype,
+ &key);
+ if (ret)
+ return ret;
+ return krb5_crypto_init(context, &key->key, 0, crypto);
+}
+
+/*
+ *
+ */
+
+static char *
+get_ntlm_targetname(krb5_context context,
+ hdb_entry_ex *client)
+{
+ char *targetname, *p;
+
+ targetname = strdup(krb5_principal_get_realm(context,
+ client->entry.principal));
+ if (targetname == NULL)
+ return NULL;
+
+ p = strchr(targetname, '.');
+ if (p)
+ *p = '\0';
+
+ strupr(targetname);
+ return targetname;
+}
+
+static krb5_error_code
+fill_targetinfo(krb5_context context,
+ char *targetname,
+ hdb_entry_ex *client,
+ krb5_data *data)
+{
+ struct ntlm_targetinfo ti;
+ krb5_error_code ret;
+ struct ntlm_buf d;
+ krb5_principal p;
+ const char *str;
+
+ memset(&ti, 0, sizeof(ti));
+
+ ti.domainname = targetname;
+ p = client->entry.principal;
+ str = krb5_principal_get_comp_string(context, p, 0);
+ if (str != NULL &&
+ (strcmp("host", str) == 0 ||
+ strcmp("ftp", str) == 0 ||
+ strcmp("imap", str) == 0 ||
+ strcmp("pop", str) == 0 ||
+ strcmp("smtp", str)))
+ {
+ str = krb5_principal_get_comp_string(context, p, 1);
+ ti.dnsservername = rk_UNCONST(str);
+ }
+
+ ret = heim_ntlm_encode_targetinfo(&ti, 1, &d);
+ if (ret)
+ return ret;
+
+ data->data = d.data;
+ data->length = d.length;
+
+ return 0;
+}
+
+
+/*
+ *
+ */
krb5_error_code
_kdc_do_digest(krb5_context context,
@@ -57,11 +159,13 @@ _kdc_do_digest(krb5_context context,
krb5_storage *sp = NULL;
Checksum res;
hdb_entry_ex *server = NULL, *user = NULL;
- char *password = NULL;
+ hdb_entry_ex *client = NULL;
+ char *client_name = NULL, *password = NULL;
krb5_data serverNonce;
if(!config->enable_digest) {
- kdc_log(context, config, 0, "Rejected digest request from %s", from);
+ kdc_log(context, config, 0,
+ "Rejected digest request (disabled) from %s", from);
return KRB5KDC_ERR_POLICY;
}
@@ -125,6 +229,7 @@ _kdc_do_digest(krb5_context context,
krb5_free_principal(context, principal);
goto out;
}
+ krb5_clear_error_string(context);
ret = _kdc_db_fetch(context, config, principal,
HDB_F_GET_SERVER, NULL, &server);
@@ -137,12 +242,17 @@ _kdc_do_digest(krb5_context context,
/* check the client is allowed to do digest auth */
{
krb5_principal principal = NULL;
- hdb_entry_ex *client;
ret = krb5_ticket_get_client(context, ticket, &principal);
if (ret)
goto out;
+ ret = krb5_unparse_name(context, principal, &client_name);
+ if (ret) {
+ krb5_free_principal(context, principal);
+ goto out;
+ }
+
ret = _kdc_db_fetch(context, config, principal,
HDB_F_GET_CLIENT, NULL, &client);
krb5_free_principal(context, principal);
@@ -150,13 +260,15 @@ _kdc_do_digest(krb5_context context,
goto out;
if (client->entry.flags.allow_digest == 0) {
+ kdc_log(context, config, 0,
+ "Client %s tried to use digest "
+ "but is not allowed to",
+ client_name);
krb5_set_error_string(context,
"Client is not permitted to use digest");
ret = KRB5KDC_ERR_POLICY;
- _kdc_free_ent (context, client);
goto out;
}
- _kdc_free_ent (context, client);
}
/* unpack request */
@@ -192,6 +304,9 @@ _kdc_do_digest(krb5_context context,
goto out;
}
+ kdc_log(context, config, 0, "Valid digest request from %s (%s)",
+ client_name, from);
+
/*
* Process the inner request
*/
@@ -289,22 +404,9 @@ _kdc_do_digest(krb5_context context,
goto out;
}
- {
- Key *key;
- krb5_enctype enctype;
-
- ret = _kdc_get_preferred_key(context,
- config,
- server,
- "digest-service",
- &enctype,
- &key);
- if (ret)
- goto out;
- ret = krb5_crypto_init(context, &key->key, 0, &crypto);
- if (ret)
- goto out;
- }
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
ret = krb5_create_checksum(context,
crypto,
@@ -337,6 +439,9 @@ _kdc_do_digest(krb5_context context,
goto out;
}
+ kdc_log(context, config, 0, "Digest %s init request successful from %s",
+ ireq.u.init.type, from);
+
break;
}
case choice_DigestReqInner_digestRequest: {
@@ -349,7 +454,11 @@ _kdc_do_digest(krb5_context context,
krb5_set_error_string(context, "out of memory");
goto out;
}
- krb5_store_stringz(sp, ireq.u.digestRequest.type);
+ ret = krb5_store_stringz(sp, ireq.u.digestRequest.type);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce);
if (ireq.u.digestRequest.identifier) {
@@ -421,22 +530,9 @@ _kdc_do_digest(krb5_context context,
serverNonce.length = ssize;
}
- {
- Key *key;
- krb5_enctype enctype;
-
- ret = _kdc_get_preferred_key(context,
- config,
- server,
- "digest-service",
- &enctype,
- &key);
- if (ret)
- goto out;
- ret = krb5_crypto_init(context, &key->key, 0, &crypto);
- if (ret)
- goto out;
- }
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
ret = krb5_verify_checksum(context, crypto,
KRB5_KU_DIGEST_OPAQUE,
@@ -493,6 +589,11 @@ _kdc_do_digest(krb5_context context,
unsigned char md[MD5_DIGEST_LENGTH];
char id;
+ if ((config->digests_allowed & CHAP_MD5) == 0) {
+ kdc_log(context, config, 0, "Digest CHAP MD5 not allowed");
+ goto out;
+ }
+
if (ireq.u.digestRequest.identifier == NULL) {
krb5_set_error_string(context, "Identifier missing "
"from CHAP request");
@@ -524,6 +625,11 @@ _kdc_do_digest(krb5_context context,
unsigned char md[MD5_DIGEST_LENGTH];
char *A1, *A2;
+ if ((config->digests_allowed & DIGEST_MD5) == 0) {
+ kdc_log(context, config, 0, "Digest SASL MD5 not allowed");
+ goto out;
+ }
+
if (ireq.u.digestRequest.nonceCount == NULL)
goto out;
if (ireq.u.digestRequest.clientNonce == NULL)
@@ -627,6 +733,358 @@ _kdc_do_digest(krb5_context context,
r.u.error.code = EINVAL;
}
+ kdc_log(context, config, 0, "Digest %s request successful %s",
+ ireq.u.digestRequest.type, from);
+
+ break;
+ }
+ case choice_DigestReqInner_ntlmInit:
+
+ if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) {
+ kdc_log(context, config, 0, "NTLM not allowed");
+ goto out;
+ }
+
+
+ r.element = choice_DigestRepInner_ntlmInitReply;
+
+ r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE;
+
+ if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) {
+ kdc_log(context, config, 0, "NTLM client have no unicode");
+ goto out;
+ }
+
+ if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM)
+ r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM;
+ else {
+ kdc_log(context, config, 0, "NTLM client doesn't support NTLM");
+ goto out;
+ }
+
+ r.u.ntlmInitReply.flags |=
+ NTLM_NEG_TARGET_DOMAIN |
+ NTLM_ENC_128;
+
+#define ALL \
+ NTLM_NEG_SIGN| \
+ NTLM_NEG_SEAL| \
+ NTLM_NEG_ALWAYS_SIGN| \
+ NTLM_NEG_NTLM2_SESSION| \
+ NTLM_NEG_KEYEX
+
+ r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL));
+
+#undef ALL
+
+ r.u.ntlmInitReply.targetname =
+ get_ntlm_targetname(context, client);
+ if (r.u.ntlmInitReply.targetname == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ r.u.ntlmInitReply.challange.data = malloc(8);
+ if (r.u.ntlmInitReply.challange.data == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ r.u.ntlmInitReply.challange.length = 8;
+ if (RAND_bytes(r.u.ntlmInitReply.challange.data,
+ r.u.ntlmInitReply.challange.length) != 1)
+ {
+ krb5_set_error_string(context, "out of random error");
+ ret = ENOMEM;
+ goto out;
+ }
+ /* XXX fix targetinfo */
+ ALLOC(r.u.ntlmInitReply.targetinfo);
+ if (r.u.ntlmInitReply.targetinfo == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = fill_targetinfo(context,
+ r.u.ntlmInitReply.targetname,
+ client,
+ r.u.ntlmInitReply.targetinfo);
+ if (ret) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Save data encryted in opaque for the second part of the
+ * ntlm authentication
+ */
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+
+ ret = krb5_storage_write(sp, r.u.ntlmInitReply.challange.data, 8);
+ if (ret != 8) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "storage write challange");
+ goto out;
+ }
+ ret = krb5_store_uint32(sp, r.u.ntlmInitReply.flags);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
+
+ ret = krb5_storage_to_data(sp, &buf);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
+
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
+
+ ret = krb5_encrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE,
+ buf.data, buf.length, &r.u.ntlmInitReply.opaque);
+ krb5_data_free(&buf);
+ krb5_crypto_destroy(context, crypto);
+ crypto = NULL;
+ if (ret)
+ goto out;
+
+ kdc_log(context, config, 0, "NTLM init from %s", from);
+
+ break;
+
+ case choice_DigestReqInner_ntlmRequest: {
+ krb5_principal clientprincipal;
+ unsigned char sessionkey[16];
+ unsigned char challange[8];
+ uint32_t flags;
+ Key *key = NULL;
+ int version;
+
+ r.element = choice_DigestRepInner_ntlmResponse;
+ r.u.ntlmResponse.success = 0;
+ r.u.ntlmResponse.flags = 0;
+ r.u.ntlmResponse.sessionkey = NULL;
+ r.u.ntlmResponse.tickets = NULL;
+
+ /* get username */
+ ret = krb5_parse_name(context,
+ ireq.u.ntlmRequest.username,
+ &clientprincipal);
+ if (ret)
+ goto out;
+
+ ret = _kdc_db_fetch(context, config, clientprincipal,
+ HDB_F_GET_CLIENT, NULL, &user);
+ krb5_free_principal(context, clientprincipal);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM user %s not in database",
+ ireq.u.ntlmRequest.username);
+ goto out;
+ }
+
+ ret = get_digest_key(context, config, server, &crypto);
+ if (ret)
+ goto out;
+
+ ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE,
+ ireq.u.ntlmRequest.opaque.data,
+ ireq.u.ntlmRequest.opaque.length, &buf);
+ krb5_crypto_destroy(context, crypto);
+ crypto = NULL;
+ if (ret)
+ goto out;
+
+ sp = krb5_storage_from_data(&buf);
+ if (sp == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+
+ ret = krb5_storage_read(sp, challange, sizeof(challange));
+ if (ret != sizeof(challange)) {
+ krb5_set_error_string(context, "NTLM storage read challange");
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = krb5_ret_uint32(sp, &flags);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM storage read flags");
+ goto out;
+ }
+ krb5_data_free(&buf);
+
+ if ((flags & NTLM_NEG_NTLM) == 0) {
+ ret = EINVAL;
+ krb5_set_error_string(context, "NTLM not negotiated");
+ goto out;
+ }
+
+ ret = hdb_enctype2key(context, &user->entry,
+ ETYPE_ARCFOUR_HMAC_MD5, &key);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM missing arcfour key");
+ goto out;
+ }
+
+ /* check if this is NTLMv2 */
+ if (ireq.u.ntlmRequest.ntlm.length != 24) {
+ struct ntlm_buf infotarget, answer;
+ char *targetname;
+
+ if ((config->digests_allowed & NTLM_V2) == 0) {
+ kdc_log(context, config, 0, "NTLM v2 not allowed");
+ goto out;
+ }
+
+ version = 2;
+
+ targetname = get_ntlm_targetname(context, client);
+ if (targetname == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ answer.length = ireq.u.ntlmRequest.ntlm.length;
+ answer.data = ireq.u.ntlmRequest.ntlm.data;
+
+ ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data,
+ key->key.keyvalue.length,
+ ireq.u.ntlmRequest.username,
+ targetname,
+ 0,
+ challange,
+ &answer,
+ &infotarget,
+ sessionkey);
+ free(targetname);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM v2 verify failed");
+ goto out;
+ }
+
+ /* XXX verify infotarget matches client (checksum ?) */
+
+ free(infotarget.data);
+ /* */
+
+ } else {
+ struct ntlm_buf answer;
+
+ version = 1;
+
+ if (flags & NTLM_NEG_NTLM2_SESSION) {
+ char sessionhash[MD5_DIGEST_LENGTH];
+ MD5_CTX md5ctx;
+
+ if ((config->digests_allowed & NTLM_V1_SESSION) == 0) {
+ kdc_log(context, config, 0, "NTLM v1-session not allowed");
+ goto out;
+ }
+
+ if (ireq.u.ntlmRequest.lm.length != 24) {
+ krb5_set_error_string(context, "LM hash have wrong length "
+ "for NTLM session key");
+ ret = EINVAL;
+ goto out;
+ }
+
+ MD5_Init(&md5ctx);
+ MD5_Update(&md5ctx, challange, sizeof(challange));
+ MD5_Update(&md5ctx, ireq.u.ntlmRequest.lm.data, 8);
+ MD5_Final(sessionhash, &md5ctx);
+ memcpy(challange, sessionhash, sizeof(challange));
+ } else {
+ if ((config->digests_allowed & NTLM_V1) == 0) {
+ kdc_log(context, config, 0, "NTLM v1 not allowed");
+ goto out;
+ }
+ }
+
+ ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data,
+ key->key.keyvalue.length,
+ challange, &answer);
+ if (ret) {
+ krb5_set_error_string(context, "NTLM missing arcfour key");
+ goto out;
+ }
+
+ if (ireq.u.ntlmRequest.ntlm.length != answer.length ||
+ memcmp(ireq.u.ntlmRequest.ntlm.data, answer.data, answer.length) != 0)
+ {
+ free(answer.data);
+ ret = EINVAL;
+ krb5_set_error_string(context, "NTLM hash mismatch");
+ goto out;
+ }
+ free(answer.data);
+
+ {
+ MD4_CTX ctx;
+
+ MD4_Init(&ctx);
+ MD4_Update(&ctx,
+ key->key.keyvalue.data, key->key.keyvalue.length);
+ MD4_Final(sessionkey, &ctx);
+ }
+ }
+
+ if (ireq.u.ntlmRequest.sessionkey) {
+ unsigned char masterkey[MD4_DIGEST_LENGTH];
+ RC4_KEY rc4;
+ size_t len;
+
+ if ((flags & NTLM_NEG_KEYEX) == 0) {
+ krb5_set_error_string(context,
+ "NTLM client failed to neg key "
+ "exchange but still sent key");
+ goto out;
+ }
+
+ len = ireq.u.ntlmRequest.sessionkey->length;
+ if (len != sizeof(masterkey)){
+ krb5_set_error_string(context,
+ "NTLM master key wrong length: %lu",
+ (unsigned long)len);
+ goto out;
+ }
+
+ RC4_set_key(&rc4, sizeof(sessionkey), sessionkey);
+
+ RC4(&rc4, sizeof(masterkey),
+ ireq.u.ntlmRequest.sessionkey->data,
+ masterkey);
+ memset(&rc4, 0, sizeof(rc4));
+
+ r.u.ntlmResponse.sessionkey =
+ malloc(sizeof(*r.u.ntlmResponse.sessionkey));
+ if (r.u.ntlmResponse.sessionkey == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+
+ ret = krb5_data_copy(r.u.ntlmResponse.sessionkey,
+ masterkey, sizeof(masterkey));
+ if (ret) {
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+ }
+
+ r.u.ntlmResponse.success = 1;
+ kdc_log(context, config, 0, "NTLM version %d successful for %s",
+ version, ireq.u.ntlmRequest.username);
+
break;
}
default:
@@ -698,10 +1156,14 @@ out:
_kdc_free_ent (context, user);
if (server)
_kdc_free_ent (context, server);
+ if (client)
+ _kdc_free_ent (context, client);
if (password) {
memset(password, 0, strlen(password));
free (password);
}
+ if (client_name)
+ free (client_name);
krb5_data_free(&buf);
krb5_data_free(&serverNonce);
free_DigestREP(&rep);
diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h
index 87d713b076f..56ddc8090b6 100644
--- a/source4/heimdal/kdc/headers.h
+++ b/source4/heimdal/kdc/headers.h
@@ -32,7 +32,7 @@
*/
/*
- * $Id: headers.h,v 1.18 2006/10/17 02:22:17 lha Exp $
+ * $Id: headers.h,v 1.22 2007/01/04 00:15:34 lha Exp $
*/
#ifndef __HEADERS_H__
@@ -72,6 +72,9 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
@@ -89,10 +92,14 @@
#include <krb5.h>
#include <krb5_locl.h>
#include <digest_asn1.h>
+#include <kx509_asn1.h>
#include <hdb.h>
#include <hdb_err.h>
#include <der.h>
+#include <heimntlm.h>
+#include <windc_plugin.h>
+
#undef ALLOC
#define ALLOC(X) ((X) = malloc(sizeof(*(X))))
#undef ALLOC_SEQ
diff --git a/source4/heimdal/kdc/kdc-private.h b/source4/heimdal/kdc/kdc-private.h
index 6d4fd2a29ba..d896bd10e99 100644
--- a/source4/heimdal/kdc/kdc-private.h
+++ b/source4/heimdal/kdc/kdc-private.h
@@ -15,6 +15,13 @@ _kdc_add_KRB5SignedPath (
EncTicketPart */*tkt*/);
krb5_error_code
+_kdc_add_inital_verified_cas (
+ krb5_context /*context*/,
+ krb5_kdc_configuration */*config*/,
+ pk_client_params */*params*/,
+ EncTicketPart */*tkt*/);
+
+krb5_error_code
_kdc_as_rep (
krb5_context /*context*/,
krb5_kdc_configuration */*config*/,
@@ -90,6 +97,15 @@ _kdc_do_kaserver (
struct sockaddr_in */*addr*/);
krb5_error_code
+_kdc_do_kx509 (
+ krb5_context /*context*/,
+ krb5_kdc_configuration */*config*/,
+ const Kx509Request */*req*/,
+ krb5_data */*reply*/,
+ const char */*from*/,
+ struct sockaddr */*addr*/);
+
+krb5_error_code
_kdc_do_version4 (
krb5_context /*context*/,
krb5_kdc_configuration */*config*/,
@@ -183,6 +199,20 @@ _kdc_maybe_version4 (
int /*len*/);
krb5_error_code
+_kdc_pac_generate (
+ krb5_context /*context*/,
+ hdb_entry_ex */*client*/,
+ krb5_pac */*pac*/);
+
+krb5_error_code
+_kdc_pac_verify (
+ krb5_context /*context*/,
+ const krb5_principal /*client_principal*/,
+ hdb_entry_ex */*client*/,
+ hdb_entry_ex */*server*/,
+ krb5_pac */*pac*/);
+
+krb5_error_code
_kdc_pk_check_client (
krb5_context /*context*/,
krb5_kdc_configuration */*config*/,
@@ -230,6 +260,30 @@ _kdc_tgs_rep (
KDC_REQ */*req*/,
krb5_data */*data*/,
const char */*from*/,
- struct sockaddr */*from_addr*/);
+ struct sockaddr */*from_addr*/,
+ int /*datagram_reply*/);
+
+krb5_error_code
+_kdc_tkt_add_if_relevant_ad (
+ krb5_context /*context*/,
+ EncTicketPart */*tkt*/,
+ int /*type*/,
+ const krb5_data */*data*/);
+
+krb5_error_code
+_kdc_try_kx509_request (
+ void */*ptr*/,
+ size_t /*len*/,
+ Kx509Request */*req*/,
+ size_t */*size*/);
+
+krb5_error_code
+_kdc_windc_client_access (
+ krb5_context /*context*/,
+ struct hdb_entry_ex */*client*/,
+ KDC_REQ */*req*/);
+
+krb5_error_code
+_kdc_windc_init (krb5_context /*context*/);
#endif /* __kdc_private_h__ */
diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h
index 043b6de47d2..ea9eb7125e5 100644
--- a/source4/heimdal/kdc/kdc.h
+++ b/source4/heimdal/kdc/kdc.h
@@ -35,7 +35,7 @@
*/
/*
- * $Id: kdc.h,v 1.9 2006/10/09 15:34:07 lha Exp $
+ * $Id: kdc.h,v 1.11 2006/12/28 21:06:56 lha Exp $
*/
#ifndef __KDC_H__
@@ -81,8 +81,12 @@ typedef struct krb5_kdc_configuration {
int pkinit_dh_min_bits;
int enable_digest;
+ int digests_allowed;
+
size_t max_datagram_reply_length;
+ int enable_kx509;
+
} krb5_kdc_configuration;
#include <kdc-protos.h>
diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h
index ca8672c062d..ed3010b673f 100644
--- a/source4/heimdal/kdc/kdc_locl.h
+++ b/source4/heimdal/kdc/kdc_locl.h
@@ -32,7 +32,7 @@
*/
/*
- * $Id: kdc_locl.h,v 1.74 2005/12/12 12:23:33 lha Exp $
+ * $Id: kdc_locl.h,v 1.76 2006/12/26 17:18:14 lha Exp $
*/
#ifndef __KDC_LOCL_H__
@@ -55,6 +55,8 @@ extern int enable_http;
extern int detach_from_console;
+extern const struct units _kdc_digestunits[];
+
#define _PATH_KDC_CONF HDB_DB_DIR "/kdc.conf"
#define DEFAULT_LOG_DEST "0-1/FILE:" HDB_DB_DIR "/kdc.log"
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
index dd88e2ea503..bf727ee7395 100644
--- a/source4/heimdal/kdc/kerberos5.c
+++ b/source4/heimdal/kdc/kerberos5.c
@@ -33,7 +33,7 @@
#include "kdc_locl.h"
-RCSID("$Id: kerberos5.c,v 1.225 2006/11/10 03:36:32 lha Exp $");
+RCSID("$Id: kerberos5.c,v 1.231 2007/01/04 13:27:27 lha Exp $");
#define MAX_TIME ((time_t)((1U << 31) - 1))
@@ -635,6 +635,69 @@ get_pa_etype_info2(krb5_context context,
}
/*
+ *
+ */
+
+static void
+log_as_req(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_enctype cetype,
+ krb5_enctype setype,
+ const KDC_REQ_BODY *b)
+{
+ krb5_error_code ret;
+ struct rk_strpool *p = NULL;
+ char *str;
+ int i;
+
+ for (i = 0; i < b->etype.len; i++) {
+ ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
+ if (ret == 0) {
+ p = rk_strpoolprintf(p, "%s", str);
+ free(str);
+ } else
+ p = rk_strpoolprintf(p, "%d", b->etype.val[i]);
+ if (p && i + 1 < b->etype.len)
+ p = rk_strpoolprintf(p, ", ");
+ if (p == NULL) {
+ kdc_log(context, config, 0, "out of memory");
+ return;
+ }
+ }
+ if (p == NULL)
+ p = rk_strpoolprintf(p, "no encryption types");
+
+ str = rk_strpoolcollect(p);
+ kdc_log(context, config, 0, "Client supported enctypes: %s", str);
+ free(str);
+
+ {
+ char *cet;
+ char *set;
+
+ ret = krb5_enctype_to_string(context, cetype, &cet);
+ if(ret == 0) {
+ ret = krb5_enctype_to_string(context, setype, &set);
+ if (ret == 0) {
+ kdc_log(context, config, 5, "Using %s/%s", cet, set);
+ free(set);
+ }
+ free(cet);
+ }
+ if (ret != 0)
+ kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
+ }
+
+ {
+ char str[128];
+ unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(),
+ str, sizeof(str));
+ if(*str)
+ kdc_log(context, config, 2, "Requested flags: %s", str);
+ }
+}
+
+/*
* verify the flags on `client' and `server', returning 0
* if they are OK and generating an error messages and returning
* and error code otherwise.
@@ -798,6 +861,39 @@ _kdc_check_addresses(krb5_context context,
return result;
}
+/*
+ *
+ */
+
+static krb5_boolean
+send_pac_p(krb5_context context, KDC_REQ *req)
+{
+ krb5_error_code ret;
+ PA_PAC_REQUEST pacreq;
+ PA_DATA *pa;
+ int i = 0;
+
+ pa = _kdc_find_padata(req, &i, KRB5_PADATA_PA_PAC_REQUEST);
+ if (pa == NULL)
+ return TRUE;
+
+ ret = decode_PA_PAC_REQUEST(pa->padata_value.data,
+ pa->padata_value.length,
+ &pacreq,
+ NULL);
+ if (ret)
+ return TRUE;
+ i = pacreq.include_pac;
+ free_PA_PAC_REQUEST(&pacreq);
+ if (i == 0)
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ *
+ */
+
krb5_error_code
_kdc_as_rep(krb5_context context,
krb5_kdc_configuration *config,
@@ -882,6 +978,10 @@ _kdc_as_rep(krb5_context context,
goto out;
}
+ ret = _kdc_windc_client_access(context, client, req);
+ if(ret)
+ goto out;
+
ret = _kdc_check_flags(context, config,
client, client_name,
server, server_name,
@@ -889,13 +989,6 @@ _kdc_as_rep(krb5_context context,
if(ret)
goto out;
- if (client->check_client_access) {
- ret = client->check_client_access(context, client,
- b->addresses);
- if(ret)
- goto out;
- }
-
memset(&et, 0, sizeof(et));
memset(&ek, 0, sizeof(ek));
@@ -1224,57 +1317,7 @@ _kdc_as_rep(krb5_context context,
}
}
- {
- struct rk_strpool *p = NULL;
- char *str;
- int i;
-
- for (i = 0; i < b->etype.len; i++) {
- ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
- if (ret == 0) {
- p = rk_strpoolprintf(p, "%s", str);
- free(str);
- } else
- p = rk_strpoolprintf(p, "%d", b->etype.val[i]);
- if (p && i + 1 < b->etype.len)
- p = rk_strpoolprintf(p, ", ");
- if (p == NULL) {
- kdc_log(context, config, 0, "out of memory");
- goto out;
- }
- }
- if (p == NULL)
- p = rk_strpoolprintf(p, "no encryption types");
-
- str = rk_strpoolcollect(p);
- kdc_log(context, config, 0, "Client supported enctypes: %s", str);
- free(str);
- }
- {
- char *cet;
- char *set;
-
- ret = krb5_enctype_to_string(context, cetype, &cet);
- if(ret == 0) {
- ret = krb5_enctype_to_string(context, setype, &set);
- if (ret == 0) {
- kdc_log(context, config, 5, "Using %s/%s", cet, set);
- free(set);
- }
- free(cet);
- }
- if (ret != 0)
- kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
- }
-
- {
- char str[128];
- unparse_flags(KDCOptions2int(f), asn1_KDCOptions_units(),
- str, sizeof(str));
- if(*str)
- kdc_log(context, config, 2, "Requested flags: %s", str);
- }
-
+ log_as_req(context, config, cetype, setype, b);
if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
|| (f.request_anonymous && !config->allow_anonymous)) {
@@ -1330,7 +1373,9 @@ _kdc_as_rep(krb5_context context,
goto out;
}
- krb5_generate_random_keyblock(context, sessionetype, &et.key);
+ ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
+ if (ret)
+ goto out;
copy_PrincipalName(&rep.cname, &et.cname);
copy_Realm(&rep.crealm, &et.crealm);
@@ -1469,6 +1514,12 @@ _kdc_as_rep(krb5_context context,
&reply_key, rep.padata);
if (ret)
goto out;
+ ret = _kdc_add_inital_verified_cas(context,
+ config,
+ pkp,
+ &et);
+ if (ret)
+ goto out;
}
#endif
@@ -1479,16 +1530,37 @@ _kdc_as_rep(krb5_context context,
rep.padata = NULL;
}
- /* Add the PAC, via a HDB abstraction */
- if (client->authz_data_as_req) {
- ret = client->authz_data_as_req(context, client,
- req->padata,
- et.authtime,
- &skey->key,
- &et.key,
- &et.authorization_data);
- if (ret)
- goto out;
+ /* Add the PAC */
+ if (send_pac_p(context, req)) {
+ krb5_pac p = NULL;
+ krb5_data data;
+
+ ret = _kdc_pac_generate(context, client, &p);
+ if (ret) {
+ kdc_log(context, config, 0, "PAC generation failed for -- %s",
+ client_name);
+ goto out;
+ }
+ if (p != NULL) {
+ ret = _krb5_pac_sign(context, p, et.authtime,
+ client->entry.principal,
+ &skey->key, /* Server key */
+ &skey->key, /* FIXME: should be krbtgt key */
+ &data);
+ krb5_pac_free(context, p);
+ if (ret) {
+ kdc_log(context, config, 0, "PAC signing failed for -- %s",
+ client_name);
+ goto out;
+ }
+
+ ret = _kdc_tkt_add_if_relevant_ad(context, &et,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ &data);
+ krb5_data_free(&data);
+ if (ret)
+ goto out;
+ }
}
_kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime,
@@ -1552,3 +1624,64 @@ out2:
_kdc_free_ent(context, server);
return ret;
}
+
+/*
+ * Add the AuthorizationData `data´ of `type´ to the last element in
+ * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT
+ */
+
+krb5_error_code
+_kdc_tkt_add_if_relevant_ad(krb5_context context,
+ EncTicketPart *tkt,
+ int type,
+ const krb5_data *data)
+{
+ krb5_error_code ret;
+ size_t size;
+
+ if (tkt->authorization_data == NULL) {
+ tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
+ if (tkt->authorization_data == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ }
+
+ /* add the entry to the last element */
+ {
+ AuthorizationData ad = { 0, NULL };
+ AuthorizationDataElement ade;
+
+ ade.ad_type = type;
+ ade.ad_data = *data;
+
+ ret = add_AuthorizationData(&ad, &ade);
+ if (ret) {
+ krb5_set_error_string(context, "add AuthorizationData failed");
+ return ret;
+ }
+
+ ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData,
+ ade.ad_data.data, ade.ad_data.length,
+ &ad, &size, ret);
+ free_AuthorizationData(&ad);
+ if (ret) {
+ krb5_set_error_string(context, "ASN.1 encode of "
+ "AuthorizationData failed");
+ return ret;
+ }
+ if (ade.ad_data.length != size)
+ krb5_abortx(context, "internal asn.1 encoder error");
+
+ ret = add_AuthorizationData(tkt->authorization_data, &ade);
+ der_free_octet_string(&ade.ad_data);
+ if (ret) {
+ krb5_set_error_string(context, "add AuthorizationData failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index dcf29eb6e98..a056839e5f3 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "kdc_locl.h"
-RCSID("$Id: krb5tgs.c,v 1.16 2006/10/22 15:54:37 lha Exp $");
+RCSID("$Id: krb5tgs.c,v 1.25 2007/01/04 12:49:45 lha Exp $");
/*
* return the realm of a krbtgt-ticket or NULL
@@ -119,7 +119,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
if (server && principals) {
ret = add_KRB5SignedPathPrincipals(principals, server);
if (ret)
- goto out;
+ return ret;
}
{
@@ -131,7 +131,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
&spd, &size, ret);
if (ret)
- goto out;
+ return ret;
if (data.length != size)
krb5_abortx(context, "internal asn.1 encoder error");
}
@@ -159,12 +159,12 @@ _kdc_add_KRB5SignedPath(krb5_context context,
krb5_crypto_destroy(context, crypto);
free(data.data);
if (ret)
- goto out;
+ return ret;
ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
free_Checksum(&sp.cksum);
if (ret)
- goto out;
+ return ret;
if (data.length != size)
krb5_abortx(context, "internal asn.1 encoder error");
@@ -174,46 +174,11 @@ _kdc_add_KRB5SignedPath(krb5_context context,
* authorization data field.
*/
- if (tkt->authorization_data == NULL) {
- tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
- if (tkt->authorization_data == NULL) {
- ret = ENOMEM;
- goto out;
- }
- }
-
- /* add the entry to the last element */
- {
- AuthorizationData ad = { 0, NULL };
- AuthorizationDataElement ade;
-
- ade.ad_type = KRB5_AUTHDATA_SIGNTICKET;
- ade.ad_data = data;
-
- ret = add_AuthorizationData(&ad, &ade);
- krb5_data_free(&data);
- if (ret)
- return ret;
-
- ASN1_MALLOC_ENCODE(AuthorizationData, data.data, data.length,
- &ad, &size, ret);
- free_AuthorizationData(&ad);
- if (ret)
- return ret;
- if (data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
-
- ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
- ade.ad_data = data;
-
- ret = add_AuthorizationData(tkt->authorization_data, &ade);
- krb5_data_free(&data);
- if (ret)
- return ret;
- }
+ ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
+ KRB5_AUTHDATA_SIGNTICKET, &data);
+ krb5_data_free(&data);
-out:
- return 0;
+ return ret;
}
static krb5_error_code
@@ -307,6 +272,87 @@ check_KRB5SignedPath(krb5_context context,
return 0;
}
+/*
+ *
+ */
+
+static krb5_error_code
+check_PAC(krb5_context context,
+ krb5_kdc_configuration *config,
+ const krb5_principal client_principal,
+ hdb_entry_ex *client,
+ hdb_entry_ex *server,
+ const EncryptionKey *server_key,
+ const EncryptionKey *krbtgt_key,
+ EncTicketPart *tkt,
+ krb5_data *rspac,
+ int *require_signedpath)
+{
+ AuthorizationData *ad = tkt->authorization_data;
+ unsigned i, j;
+ krb5_error_code ret;
+
+ if (ad == NULL || ad->len == 0)
+ return 0;
+
+ for (i = 0; i < ad->len; i++) {
+ AuthorizationData child;
+
+ if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+ continue;
+
+ ret = decode_AuthorizationData(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &child,
+ NULL);
+ if (ret) {
+ krb5_set_error_string(context, "Failed to decode "
+ "IF_RELEVANT with %d", ret);
+ return ret;
+ }
+ for (j = 0; j < child.len; j++) {
+
+ if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
+ krb5_pac pac;
+
+ /* Found PAC */
+ ret = krb5_pac_parse(context,
+ child.val[j].ad_data.data,
+ child.val[j].ad_data.length,
+ &pac);
+ free_AuthorizationData(&child);
+ if (ret)
+ return ret;
+
+ ret = krb5_pac_verify(context, pac, tkt->authtime,
+ client_principal,
+ krbtgt_key, NULL);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+
+ ret = _kdc_pac_verify(context, client_principal,
+ client, server, &pac);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+ *require_signedpath = 0;
+
+ ret = _krb5_pac_sign(context, pac, tkt->authtime,
+ client_principal,
+ server_key, krbtgt_key, rspac);
+
+ krb5_pac_free(context, pac);
+
+ return ret;
+ }
+ }
+ free_AuthorizationData(&child);
+ }
+ return 0;
+}
/*
*
@@ -610,9 +656,10 @@ tgs_make_reply(krb5_context context,
KDC_REQ_BODY *b,
krb5_const_principal tgt_name,
const EncTicketPart *tgt,
- const EncTicketPart *adtkt,
+ const EncryptionKey *ekey,
+ const krb5_keyblock *sessionkey,
+ krb5_kvno kvno,
AuthorizationData *auth_data,
- krb5_ticket *tgs_ticket,
hdb_entry_ex *server,
const char *server_name,
hdb_entry_ex *client,
@@ -620,7 +667,7 @@ tgs_make_reply(krb5_context context,
hdb_entry_ex *krbtgt,
krb5_enctype krbtgt_etype,
KRB5SignedPathPrincipals *spp,
- EncryptionKey *tgtkey,
+ const krb5_data *rspac,
const char **e_text,
krb5_data *reply)
{
@@ -629,32 +676,6 @@ tgs_make_reply(krb5_context context,
EncTicketPart et;
KDCOptions f = b->kdc_options;
krb5_error_code ret;
- krb5_enctype etype;
- Key *skey;
- const EncryptionKey *ekey;
- AuthorizationData *new_auth_data = NULL;
-
- if(adtkt) {
- int i;
- ekey = &adtkt->key;
- for(i = 0; i < b->etype.len; i++)
- if (b->etype.val[i] == adtkt->key.keytype)
- break;
- if(i == b->etype.len) {
- krb5_clear_error_string(context);
- return KRB5KDC_ERR_ETYPE_NOSUPP;
- }
- etype = b->etype.val[i];
- }else{
- ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
- &skey, &etype);
- if(ret) {
- kdc_log(context, config, 0,
- "Server (%s) has no support for etypes", server_name);
- return ret;
- }
- ekey = &skey->key;
- }
memset(&rep, 0, sizeof(rep));
memset(&et, 0, sizeof(et));
@@ -768,26 +789,47 @@ tgs_make_reply(krb5_context context,
et.flags.anonymous = tgt->flags.anonymous;
et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
-
- krb5_generate_random_keyblock(context, etype, &et.key);
-
- if (server->authz_data_tgs_req) {
- ret = server->authz_data_tgs_req(context, server,
- client_principal,
- tgs_ticket->ticket.authorization_data,
- tgs_ticket->ticket.authtime,
- tgtkey,
- ekey,
- &et.key,
- &new_auth_data);
- if (ret) {
- new_auth_data = NULL;
+ if (auth_data) {
+ /* XXX Check enc-authorization-data */
+ et.authorization_data = calloc(1, sizeof(*et.authorization_data));
+ if (et.authorization_data == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = copy_AuthorizationData(auth_data, et.authorization_data);
+ if (ret)
+ goto out;
+
+ /* Filter out type KRB5SignedPath */
+ ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
+ if (ret == 0) {
+ if (et.authorization_data->len == 1) {
+ free_AuthorizationData(et.authorization_data);
+ free(et.authorization_data);
+ et.authorization_data = NULL;
+ } else {
+ AuthorizationData *ad = et.authorization_data;
+ free_AuthorizationDataElement(&ad->val[ad->len - 1]);
+ ad->len--;
}
+ }
}
- /* XXX Check enc-authorization-data */
- et.authorization_data = new_auth_data;
+ if(rspac->length) {
+ /*
+ * No not need to filter out the any PAC from the
+ * auth_data since its signed by the KDC.
+ */
+ ret = _kdc_tkt_add_if_relevant_ad(context, &et,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ rspac);
+ if (ret)
+ goto out;
+ }
+ ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
+ if (ret)
+ goto out;
et.crealm = tgt->crealm;
et.cname = tgt_name->name;
@@ -795,6 +837,10 @@ tgs_make_reply(krb5_context context,
/* MIT must have at least one last_req */
ek.last_req.len = 1;
ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
+ if (ek.last_req.val == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
ek.nonce = b->nonce;
ek.flags = et.flags;
ek.authtime = et.authtime;
@@ -817,7 +863,7 @@ tgs_make_reply(krb5_context context,
krbtgt,
krbtgt_etype,
NULL,
- NULL,
+ spp,
&et);
if (ret)
goto out;
@@ -835,8 +881,8 @@ tgs_make_reply(krb5_context context,
etype list, even if we don't want a session key with
DES3? */
ret = _kdc_encode_reply(context, config,
- &rep, &et, &ek, etype,
- adtkt ? 0 : server->entry.kvno,
+ &rep, &et, &ek, et.key.keytype,
+ kvno,
ekey, 0, &tgt->key, e_text, reply);
out:
free_TGS_REP(&rep);
@@ -973,8 +1019,7 @@ tgs_parse_request(krb5_context context,
const struct sockaddr *from_addr,
time_t **csec,
int **cusec,
- AuthorizationData **auth_data,
- EncryptionKey **tgtkey)
+ AuthorizationData **auth_data)
{
krb5_ap_req ap_req;
krb5_error_code ret;
@@ -1060,8 +1105,6 @@ tgs_parse_request(krb5_context context,
ret = KRB5KRB_AP_ERR_BADKEYVER;
goto out;
}
-
- *tgtkey = &tkey->key;
if (b->kdc_options.validate)
verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
@@ -1201,8 +1244,8 @@ tgs_build_reply(krb5_context context,
const char *from,
const char **e_text,
AuthorizationData *auth_data,
- EncryptionKey *tgtkey,
- const struct sockaddr *from_addr)
+ const struct sockaddr *from_addr,
+ int datagram_reply)
{
krb5_error_code ret;
krb5_principal cp = NULL, sp = NULL;
@@ -1211,6 +1254,10 @@ tgs_build_reply(krb5_context context,
hdb_entry_ex *server = NULL, *client = NULL;
EncTicketPart *tgt = &ticket->ticket;
KRB5SignedPathPrincipals *spp = NULL;
+ const EncryptionKey *ekey;
+ krb5_keyblock sessionkey;
+ krb5_kvno kvno;
+ krb5_data rspac;
PrincipalName *s;
Realm r;
@@ -1219,7 +1266,9 @@ tgs_build_reply(krb5_context context,
char opt_str[128];
int require_signedpath = 0;
+ memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
+ krb5_data_zero(&rspac);
s = b->sname;
r = b->realm;
@@ -1436,7 +1485,7 @@ server_lookup:
ret = krb5_verify_checksum(context,
crypto,
- KRB5_KU_TGS_IMPERSONATE,
+ KRB5_KU_OTHER_CKSUM,
datack.data,
datack.length,
&self.cksum);
@@ -1617,6 +1666,67 @@ server_lookup:
goto out;
}
+ /*
+ * Select enctype, return key and kvno.
+ */
+
+ {
+ krb5_enctype etype;
+
+ if(b->kdc_options.enc_tkt_in_skey) {
+ int i;
+ ekey = &adtkt.key;
+ for(i = 0; i < b->etype.len; i++)
+ if (b->etype.val[i] == adtkt.key.keytype)
+ break;
+ if(i == b->etype.len) {
+ krb5_clear_error_string(context);
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
+ }
+ etype = b->etype.val[i];
+ kvno = 0;
+ } else {
+ Key *skey;
+
+ ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
+ &skey, &etype);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Server (%s) has no support for etypes", spp);
+ return ret;
+ }
+ ekey = &skey->key;
+ kvno = server->entry.kvno;
+ }
+
+ ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
+ if (ret)
+ goto out;
+ }
+
+ /* check PAC if there is one */
+ {
+ Key *tkey;
+
+ ret = hdb_enctype2key(context, &krbtgt->entry,
+ krbtgt_etype, &tkey);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Failed to find key for krbtgt PAC check");
+ goto out;
+ }
+
+ ret = check_PAC(context, config, client_principal,
+ client, server, ekey, &tkey->key,
+ tgt, &rspac, &require_signedpath);
+ if (ret) {
+ kdc_log(context, config, 0,
+ "check_PAC check failed for %s (%s) from %s with %s",
+ spn, cpn, from, krb5_get_err_text(context, ret));
+ goto out;
+ }
+ }
+
/* also check the krbtgt for signature */
ret = check_KRB5SignedPath(context,
config,
@@ -1640,9 +1750,10 @@ server_lookup:
b,
client_principal,
tgt,
- b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL,
+ ekey,
+ &sessionkey,
+ kvno,
auth_data,
- ticket,
server,
spn,
client,
@@ -1650,7 +1761,7 @@ server_lookup:
krbtgt,
krbtgt_etype,
spp,
- tgtkey,
+ &rspac,
e_text,
reply);
@@ -1658,6 +1769,8 @@ out:
free(spn);
free(cpn);
+ krb5_data_free(&rspac);
+ krb5_free_keyblock_contents(context, &sessionkey);
if(server)
_kdc_free_ent(context, server);
if(client)
@@ -1685,7 +1798,8 @@ _kdc_tgs_rep(krb5_context context,
KDC_REQ *req,
krb5_data *data,
const char *from,
- struct sockaddr *from_addr)
+ struct sockaddr *from_addr,
+ int datagram_reply)
{
AuthorizationData *auth_data = NULL;
krb5_error_code ret;
@@ -1696,8 +1810,6 @@ _kdc_tgs_rep(krb5_context context,
krb5_ticket *ticket = NULL;
const char *e_text = NULL;
krb5_enctype krbtgt_etype = ETYPE_NULL;
- EncryptionKey *tgtkey = NULL;
-
time_t *csec = NULL;
int *cusec = NULL;
@@ -1726,8 +1838,7 @@ _kdc_tgs_rep(krb5_context context,
&e_text,
from, from_addr,
&csec, &cusec,
- &auth_data,
- &tgtkey);
+ &auth_data);
if (ret) {
kdc_log(context, config, 0,
"Failed parsing TGS-REQ from %s", from);
@@ -1745,14 +1856,21 @@ _kdc_tgs_rep(krb5_context context,
from,
&e_text,
auth_data,
- tgtkey,
- from_addr);
+ from_addr,
+ datagram_reply);
if (ret) {
kdc_log(context, config, 0,
"Failed building TGS-REP to %s", from);
goto out;
}
+ /* */
+ if (datagram_reply && data->length > config->max_datagram_reply_length) {
+ krb5_data_free(data);
+ ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
+ e_text = "Reply packet too large";
+ }
+
out:
if(ret && data->data == NULL){
krb5_mk_error(context,
diff --git a/source4/heimdal/kdc/kx509.c b/source4/heimdal/kdc/kx509.c
new file mode 100644
index 00000000000..d817338f731
--- /dev/null
+++ b/source4/heimdal/kdc/kx509.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kdc_locl.h"
+#include <hex.h>
+
+RCSID("$Id: kx509.c,v 1.1 2006/12/28 21:03:53 lha Exp $");
+
+/*
+ *
+ */
+
+krb5_error_code
+_kdc_try_kx509_request(void *ptr, size_t len, Kx509Request *req, size_t *size)
+{
+ if (len < 4)
+ return -1;
+ if (memcmp("\x00\x00\x02\x00", ptr, 4) != 0)
+ return -1;
+ return decode_Kx509Request(((unsigned char *)ptr) + 4, len - 4, req, size);
+}
+
+/*
+ *
+ */
+
+static const char version_2_0[4] = {0 , 0, 2, 0};
+
+static krb5_error_code
+verify_req_hash(krb5_context context,
+ const Kx509Request *req,
+ krb5_keyblock *key)
+{
+ unsigned char digest[SHA_DIGEST_LENGTH];
+ HMAC_CTX ctx;
+
+ if (req->pk_hash.length != sizeof(digest)) {
+ krb5_set_error_string(context, "pk-hash have wrong length: %lu",
+ (unsigned long)req->pk_hash.length);
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx,
+ key->keyvalue.data, key->keyvalue.length,
+ EVP_sha1(), NULL);
+ if (sizeof(digest) != HMAC_size(&ctx))
+ krb5_abortx(context, "runtime error, hmac buffer wrong size in kx509");
+ HMAC_Update(&ctx, version_2_0, sizeof(version_2_0));
+ HMAC_Update(&ctx, req->pk_key.data, req->pk_key.length);
+ HMAC_Final(&ctx, digest, 0);
+ HMAC_CTX_cleanup(&ctx);
+
+ if (memcmp(req->pk_hash.data, digest, sizeof(digest)) != 0) {
+ krb5_set_error_string(context, "pk-hash is not correct");
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ return 0;
+}
+
+static krb5_error_code
+calculate_reply_hash(krb5_context context,
+ krb5_keyblock *key,
+ Kx509Response *rep)
+{
+ HMAC_CTX ctx;
+
+ HMAC_CTX_init(&ctx);
+
+ HMAC_Init_ex(&ctx,
+ key->keyvalue.data, key->keyvalue.length,
+ EVP_sha1(), NULL);
+ rep->hash->length = HMAC_size(&ctx);
+ rep->hash->data = malloc(rep->hash->length);
+ if (rep->hash->data == NULL) {
+ HMAC_CTX_cleanup(&ctx);
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+
+ HMAC_Update(&ctx, version_2_0, sizeof(version_2_0));
+ if (rep->error_code) {
+ int32_t t = *rep->error_code;
+ do {
+ unsigned char p = (t & 0xff);
+ HMAC_Update(&ctx, &p, 1);
+ t >>= 8;
+ } while (t);
+ }
+ if (rep->certificate)
+ HMAC_Update(&ctx, rep->certificate->data, rep->certificate->length);
+ if (rep->e_text)
+ HMAC_Update(&ctx, *rep->e_text, strlen(*rep->e_text));
+
+ HMAC_Final(&ctx, rep->hash->data, 0);
+ HMAC_CTX_cleanup(&ctx);
+
+ return 0;
+}
+
+/*
+ * Build a certifate for `principal´ that will expire at `endtime´.
+ */
+
+static krb5_error_code
+build_certificate(krb5_context context,
+ krb5_kdc_configuration *config,
+ const krb5_data *key,
+ time_t endtime,
+ krb5_principal principal,
+ krb5_data *certificate)
+{
+ /* XXX write code here to generate certificates */
+ FILE *in, *out;
+ krb5_error_code ret;
+ const char *program;
+ char *str, *strkey;
+ char tstr[64];
+ pid_t pid;
+
+ snprintf(tstr, sizeof(tstr), "%lu", (unsigned long)endtime);
+
+ ret = base64_encode(key->data, key->length, &strkey);
+ if (ret < 0) {
+ krb5_set_error_string(context, "failed to base64 encode key");
+ return ENOMEM;
+ }
+
+ program = krb5_config_get_string(context,
+ NULL,
+ "kdc",
+ "kx509_cert_program",
+ NULL);
+ if (program == NULL) {
+ free(strkey);
+ krb5_set_error_string(context, "no certificate program configured");
+ return ENOENT;
+ }
+
+ ret = krb5_unparse_name(context, principal, &str);
+ if (ret) {
+ free(strkey);
+ return ret;
+ }
+
+ pid = pipe_execv(&in, &out, NULL, program, str, tstr, NULL);
+ free(str);
+ if (pid <= 0) {
+ free(strkey);
+ krb5_set_error_string(context,
+ "Failed to run the cert program %s",
+ program);
+ return ret;
+ }
+ fprintf(in, "%s\n", strkey);
+ fclose(in);
+ free(strkey);
+
+ {
+ unsigned buf[1024 * 10];
+ size_t len;
+
+ len = fread(buf, 1, sizeof(buf), out);
+ fclose(out);
+ if(len == 0) {
+ krb5_set_error_string(context,
+ "Certificate program returned no data");
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ ret = krb5_data_copy(certificate, buf, len);
+ if (ret) {
+ krb5_set_error_string(context, "Failed To copy certificate");
+ return ret;
+ }
+ }
+ kill(pid, SIGKILL);
+ waitpid(pid, NULL, 0);
+ return 0;
+}
+
+/*
+ *
+ */
+
+krb5_error_code
+_kdc_do_kx509(krb5_context context,
+ krb5_kdc_configuration *config,
+ const Kx509Request *req, krb5_data *reply,
+ const char *from, struct sockaddr *addr)
+{
+ krb5_error_code ret;
+ krb5_ticket *ticket = NULL;
+ krb5_flags ap_req_options;
+ krb5_auth_context ac = NULL;
+ krb5_keytab id = NULL;
+ krb5_principal sprincipal = NULL, cprincipal = NULL;
+ char *cname = NULL;
+ Kx509Response rep;
+ size_t size;
+ krb5_keyblock *key = NULL;
+
+ krb5_data_zero(reply);
+ memset(&rep, 0, sizeof(rep));
+
+ if(!config->enable_kx509) {
+ kdc_log(context, config, 0,
+ "Rejected kx509 request (disabled) from %s", from);
+ return KRB5KDC_ERR_POLICY;
+ }
+
+ kdc_log(context, config, 0, "Kx509 request from %s", from);
+
+ ret = krb5_kt_resolve(context, "HDB:", &id);
+ if (ret) {
+ kdc_log(context, config, 0, "Can't open database for digest");
+ goto out;
+ }
+
+ ret = krb5_rd_req(context,
+ &ac,
+ &req->authenticator,
+ NULL,
+ id,
+ &ap_req_options,
+ &ticket);
+ if (ret)
+ goto out;
+
+ ret = krb5_ticket_get_client(context, ticket, &cprincipal);
+ if (ret)
+ goto out;
+
+ ret = krb5_unparse_name(context, cprincipal, &cname);
+ if (ret)
+ goto out;
+
+ /* verify server principal */
+
+ ret = krb5_sname_to_principal(context, NULL, "kca_service",
+ KRB5_NT_UNKNOWN, &sprincipal);
+ if (ret)
+ goto out;
+
+ {
+ krb5_principal principal = NULL;
+
+ ret = krb5_ticket_get_server(context, ticket, &principal);
+ if (ret)
+ goto out;
+
+ ret = krb5_principal_compare(context, sprincipal, principal);
+ krb5_free_principal(context, principal);
+ if (ret != TRUE) {
+ ret = KRB5KDC_ERR_SERVER_NOMATCH;
+ krb5_set_error_string(context,
+ "User %s used wrong Kx509 service principal",
+ cname);
+ goto out;
+ }
+ }
+
+ ret = krb5_auth_con_getkey(context, ac, &key);
+ if (ret || key == NULL) {
+ krb5_set_error_string(context, "Kx509 can't get session key");
+ goto out;
+ }
+
+ ret = verify_req_hash(context, req, key);
+ if (ret)
+ goto out;
+
+ ALLOC(rep.certificate);
+ if (rep.certificate == NULL)
+ goto out;
+ krb5_data_zero(rep.certificate);
+ ALLOC(rep.hash);
+ if (rep.hash == NULL)
+ goto out;
+ krb5_data_zero(rep.hash);
+
+ ret = build_certificate(context, config, &req->pk_key,
+ krb5_ticket_get_endtime(context, ticket),
+ cprincipal, rep.certificate);
+ if (ret)
+ goto out;
+
+ ret = calculate_reply_hash(context, key, &rep);
+ if (ret)
+ goto out;
+
+ /*
+ * Encode reply, [ version | Kx509Response ]
+ */
+
+ {
+ krb5_data data;
+
+ ASN1_MALLOC_ENCODE(Kx509Response, data.data, data.length, &rep,
+ &size, ret);
+ if (ret) {
+ krb5_set_error_string(context, "Failed to encode kx509 reply");
+ goto out;
+ }
+ if (size != data.length)
+ krb5_abortx(context, "ASN1 internal error");
+
+ ret = krb5_data_alloc(reply, data.length + sizeof(version_2_0));
+ if (ret) {
+ free(data.data);
+ goto out;
+ }
+ memcpy(reply->data, version_2_0, sizeof(version_2_0));
+ memcpy(((unsigned char *)reply->data) + sizeof(version_2_0),
+ data.data, data.length);
+ free(data.data);
+ }
+
+ kdc_log(context, config, 0, "Successful Kx509 request for %s", cname);
+
+out:
+ if (ac)
+ krb5_auth_con_free(context, ac);
+ if (ret)
+ krb5_warn(context, ret, "Kx509 request from %s failed", from);
+ if (ticket)
+ krb5_free_ticket(context, ticket);
+ if (id)
+ krb5_kt_close(context, id);
+ if (sprincipal)
+ krb5_free_principal(context, sprincipal);
+ if (cprincipal)
+ krb5_free_principal(context, cprincipal);
+ if (key)
+ krb5_free_keyblock (context, key);
+ if (cname)
+ free(cname);
+ free_Kx509Response(&rep);
+
+ return 0;
+}
diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c
index 6657ab7c448..418a38d0307 100755
--- a/source4/heimdal/kdc/pkinit.c
+++ b/source4/heimdal/kdc/pkinit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "kdc_locl.h"
-RCSID("$Id: pkinit.c,v 1.74 2006/11/10 03:37:43 lha Exp $");
+RCSID("$Id: pkinit.c,v 1.86 2007/01/04 12:54:09 lha Exp $");
#ifdef PKINIT
@@ -68,6 +68,8 @@ struct pk_client_params {
DH *dh;
EncryptionKey reply_key;
char *dh_group_name;
+ hx509_peer_info peer;
+ hx509_certs client_anchors;
};
struct pk_principal_mapping {
@@ -180,6 +182,10 @@ _kdc_pk_free_client_param(krb5_context context,
krb5_free_keyblock_contents(context, &client_params->reply_key);
if (client_params->dh_group_name)
free(client_params->dh_group_name);
+ if (client_params->peer)
+ hx509_peer_info_free(client_params->peer);
+ if (client_params->client_anchors)
+ hx509_certs_free(&client_params->client_anchors);
memset(client_params, 0, sizeof(*client_params));
free(client_params);
}
@@ -302,8 +308,10 @@ get_dh_param(krb5_context context,
ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits,
&dhparam.p, &dhparam.g, &dhparam.q, moduli,
&client_params->dh_group_name);
- if (ret)
+ if (ret) {
+ /* XXX send back proposal of better group */
goto out;
+ }
dh = DH_new();
if (dh == NULL) {
@@ -354,64 +362,6 @@ get_dh_param(krb5_context context,
return ret;
}
-#if 0
-/*
- * XXX We only need this function if there are several certs for the
- * KDC to choose from, and right now, we can't handle that so punt for
- * now.
- *
- * If client has sent a list of CA's trusted by him, make sure our
- * CA is in the list.
- *
- */
-
-static void
-verify_trusted_ca(PA_PK_AS_REQ_19 *r)
-{
-
- if (r.trustedCertifiers != NULL) {
- X509_NAME *kdc_issuer;
- X509 *kdc_cert;
-
- kdc_cert = sk_X509_value(kdc_identity->cert, 0);
- kdc_issuer = X509_get_issuer_name(kdc_cert);
-
- /* XXX will work for heirarchical CA's ? */
- /* XXX also serial_number should be compared */
-
- ret = KRB5_KDC_ERR_KDC_NOT_TRUSTED;
- for (i = 0; i < r.trustedCertifiers->len; i++) {
- TrustedCA_19 *ca = &r.trustedCertifiers->val[i];
-
- switch (ca->element) {
- case choice_TrustedCA_19_caName: {
- X509_NAME *name;
- unsigned char *p;
-
- p = ca->u.caName.data;
- name = d2i_X509_NAME(NULL, &p, ca->u.caName.length);
- if (name == NULL) /* XXX should this be a failure instead ? */
- break;
- if (X509_NAME_cmp(name, kdc_issuer) == 0)
- ret = 0;
- X509_NAME_free(name);
- break;
- }
- case choice_TrustedCA_19_issuerAndSerial:
- /* IssuerAndSerialNumber issuerAndSerial */
- break;
- default:
- break;
- }
- if (ret == 0)
- break;
- }
- if (ret)
- goto out;
- }
-}
-#endif /* 0 */
-
krb5_error_code
_kdc_pk_rd_padata(krb5_context context,
krb5_kdc_configuration *config,
@@ -483,7 +433,61 @@ _kdc_pk_rd_padata(krb5_context context,
goto out;
}
- /* XXX look at r.trustedCertifiers and r.kdcPkId */
+ /* XXX look at r.kdcPkId */
+ if (r.trustedCertifiers) {
+ ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
+ unsigned int i;
+
+ ret = hx509_certs_init(kdc_identity->hx509ctx,
+ "MEMORY:client-anchors",
+ 0, NULL,
+ &client_params->client_anchors);
+ if (ret) {
+ krb5_set_error_string(context, "Can't allocate client anchors: %d", ret);
+ goto out;
+
+ }
+ for (i = 0; i < edi->len; i++) {
+ IssuerAndSerialNumber iasn;
+ hx509_query *q;
+ hx509_cert cert;
+ size_t size;
+
+ if (edi->val[i].issuerAndSerialNumber == NULL)
+ continue;
+
+ ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
+ if (ret) {
+ krb5_set_error_string(context,
+ "Failed to allocate hx509_query");
+ goto out;
+ }
+
+ ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
+ edi->val[i].issuerAndSerialNumber->length,
+ &iasn,
+ &size);
+ if (ret || size != 0) {
+ hx509_query_free(kdc_identity->hx509ctx, q);
+ continue;
+ }
+ ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
+ free_IssuerAndSerialNumber(&iasn);
+ if (ret)
+ continue;
+
+ ret = hx509_certs_find(kdc_identity->hx509ctx,
+ kdc_identity->certs,
+ q,
+ &cert);
+ hx509_query_free(kdc_identity->hx509ctx, q);
+ if (ret)
+ continue;
+ hx509_certs_add(kdc_identity->hx509ctx,
+ client_params->client_anchors, cert);
+ hx509_cert_free(cert);
+ }
+ }
ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
&contentInfoOid,
@@ -611,6 +615,23 @@ _kdc_pk_rd_padata(krb5_context context,
goto out;
}
}
+
+ if (ap.supportedCMSTypes) {
+ ret = hx509_peer_info_alloc(kdc_identity->hx509ctx,
+ &client_params->peer);
+ if (ret) {
+ free_AuthPack(&ap);
+ goto out;
+ }
+ ret = hx509_peer_info_set_cms_algs(kdc_identity->hx509ctx,
+ client_params->peer,
+ ap.supportedCMSTypes->val,
+ ap.supportedCMSTypes->len);
+ if (ret) {
+ free_AuthPack(&ap);
+ goto out;
+ }
+ }
free_AuthPack(&ap);
} else
krb5_abortx(context, "internal pkinit error");
@@ -752,7 +773,8 @@ pk_mk_pa_reply_enckey(krb5_context context,
buf.length,
NULL,
cert,
- kdc_identity->anchors,
+ client_params->peer,
+ client_params->client_anchors,
kdc_identity->certpool,
&signed_data);
hx509_cert_free(cert);
@@ -864,7 +886,8 @@ pk_mk_pa_reply_dh(krb5_context context,
buf.length,
NULL,
cert,
- kdc_identity->anchors,
+ client_params->peer,
+ client_params->client_anchors,
kdc_identity->certpool,
&signed_data);
*kdc_cert = cert;
@@ -948,8 +971,12 @@ _kdc_pk_mk_pa_reply(krb5_context context,
rep.element = choice_PA_PK_AS_REP_encKeyPack;
- krb5_generate_random_keyblock(context, enctype,
- &client_params->reply_key);
+ ret = krb5_generate_random_keyblock(context, enctype,
+ &client_params->reply_key);
+ if (ret) {
+ free_PA_PK_AS_REP(&rep);
+ goto out;
+ }
ret = pk_mk_pa_reply_enckey(context,
client_params,
req,
@@ -1039,8 +1066,12 @@ _kdc_pk_mk_pa_reply(krb5_context context,
pa_type = KRB5_PADATA_PK_AS_REP_19;
rep.element = choice_PA_PK_AS_REP_encKeyPack;
- krb5_generate_random_keyblock(context, enctype,
- &client_params->reply_key);
+ ret = krb5_generate_random_keyblock(context, enctype,
+ &client_params->reply_key);
+ if (ret) {
+ free_PA_PK_AS_REP_Win2k(&rep);
+ goto out;
+ }
ret = pk_mk_pa_reply_enckey(context,
client_params,
req,
@@ -1337,6 +1368,35 @@ add_principal_mapping(krb5_context context,
return 0;
}
+krb5_error_code
+_kdc_add_inital_verified_cas(krb5_context context,
+ krb5_kdc_configuration *config,
+ pk_client_params *params,
+ EncTicketPart *tkt)
+{
+ AD_INITIAL_VERIFIED_CAS cas;
+ krb5_error_code ret;
+ krb5_data data;
+ size_t size;
+
+ memset(&cas, 0, sizeof(cas));
+
+ /* XXX add CAs to cas here */
+
+ ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length,
+ &cas, &size, ret);
+ if (ret)
+ return ret;
+ if (data.length != size)
+ krb5_abortx(context, "internal asn.1 encoder error");
+
+ ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
+ ad_initial_verified_cas, &data);
+ krb5_data_free(&data);
+ return ret;
+}
+
+
krb5_error_code
_kdc_pk_initialize(krb5_context context,
@@ -1372,7 +1432,7 @@ _kdc_pk_initialize(krb5_context context,
NULL,
NULL);
if (ret) {
- krb5_warn(context, ret, "PKINIT: failed to load");
+ krb5_warn(context, ret, "PKINIT: ");
config->enable_pkinit = 0;
return ret;
}
@@ -1411,7 +1471,7 @@ _kdc_pk_initialize(krb5_context context,
NULL,
FALSE,
"kdc",
- "pki-allow-proxy-certificate",
+ "pkinit_allow_proxy_certificate",
NULL);
_krb5_pk_allow_proxy_certificate(kdc_identity, ret);
@@ -1419,7 +1479,7 @@ _kdc_pk_initialize(krb5_context context,
NULL,
HDB_DB_DIR "/pki-mapping",
"kdc",
- "pki-mappings-file",
+ "pkinit_mappings_file",
NULL);
f = fopen(file, "r");
if (f == NULL) {
diff --git a/source4/heimdal/kdc/process.c b/source4/heimdal/kdc/process.c
index ed5cb3d6513..a64efaa05dd 100644
--- a/source4/heimdal/kdc/process.c
+++ b/source4/heimdal/kdc/process.c
@@ -34,7 +34,7 @@
#include "kdc_locl.h"
-RCSID("$Id: process.c,v 1.5 2006/10/09 15:37:39 lha Exp $");
+RCSID("$Id: process.c,v 1.7 2006/12/28 21:09:35 lha Exp $");
/*
* handle the request in `buf, len', from `addr' (or `from' as a string),
@@ -55,6 +55,7 @@ krb5_kdc_process_request(krb5_context context,
KDC_REQ req;
Ticket ticket;
DigestREQ digestreq;
+ Kx509Request kx509req;
krb5_error_code ret;
size_t i;
@@ -70,7 +71,7 @@ krb5_kdc_process_request(krb5_context context,
free_AS_REQ(&req);
return ret;
}else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
- ret = _kdc_tgs_rep(context, config, &req, reply, from, addr);
+ ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply);
free_TGS_REQ(&req);
return ret;
}else if(decode_Ticket(buf, len, &ticket, &i) == 0){
@@ -81,6 +82,10 @@ krb5_kdc_process_request(krb5_context context,
ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
free_DigestREQ(&digestreq);
return ret;
+ } else if (_kdc_try_kx509_request(buf, len, &kx509req, &i) == 0) {
+ ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
+ free_Kx509Request(&kx509req);
+ return ret;
} else if(_kdc_maybe_version4(buf, len)){
*prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */
_kdc_do_version4(context, config, buf, len, reply, from,
@@ -128,7 +133,7 @@ krb5_kdc_process_krb5_request(krb5_context context,
free_AS_REQ(&req);
return ret;
}else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
- ret = _kdc_tgs_rep(context, config, &req, reply, from, addr);
+ ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply);
free_TGS_REQ(&req);
return ret;
}
diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c
new file mode 100644
index 00000000000..41e4ad1bbc8
--- /dev/null
+++ b/source4/heimdal/kdc/windc.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kdc_locl.h"
+
+RCSID("$Id: windc.c,v 1.3 2007/01/04 11:10:06 lha Exp $");
+
+static krb5plugin_windc_ftable *windcft;
+static void *windcctx;
+
+/*
+ * Pick the first WINDC module that we find.
+ */
+
+krb5_error_code
+_kdc_windc_init(krb5_context context)
+{
+ struct krb5_plugin *list = NULL, *e;
+ krb5_error_code ret;
+
+ ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "windc", &list);
+ if(ret != 0 || list == NULL)
+ return 0;
+
+ for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) {
+
+ windcft = _krb5_plugin_get_symbol(e);
+ if (windcft->minor_version < KRB5_WINDC_PLUGING_MINOR)
+ continue;
+
+ (*windcft->init)(context, &windcctx);
+ break;
+ }
+ if (e == NULL) {
+ _krb5_plugin_free(list);
+ krb5_set_error_string(context, "Did not find any WINDC plugin");
+ windcft = NULL;
+ return ENOENT;
+ }
+
+ return 0;
+}
+
+
+krb5_error_code
+_kdc_pac_generate(krb5_context context,
+ hdb_entry_ex *client,
+ krb5_pac *pac)
+{
+ *pac = NULL;
+ if (windcft == NULL)
+ return 0;
+ return (windcft->pac_generate)(windcctx, context, client, pac);
+}
+
+krb5_error_code
+_kdc_pac_verify(krb5_context context,
+ const krb5_principal client_principal,
+ hdb_entry_ex *client,
+ hdb_entry_ex *server,
+ krb5_pac *pac)
+{
+ if (windcft == NULL) {
+ krb5_set_error_string(context, "Can't verify WINDC, no function");
+ return EINVAL;
+ }
+ return (windcft->pac_verify)(windcctx, context, client_principal, client, server, pac);
+}
+
+krb5_error_code
+_kdc_windc_client_access(krb5_context context,
+ struct hdb_entry_ex *client,
+ KDC_REQ *req)
+{
+ if (windcft == NULL)
+ return 0;
+ return (windcft->client_access)(windcctx, context, client, req);
+}
diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h
new file mode 100644
index 00000000000..a3b7534480a
--- /dev/null
+++ b/source4/heimdal/kdc/windc_plugin.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: windc_plugin.h,v 1.2 2007/01/04 11:13:51 lha Exp $ */
+
+#ifndef HEIMDAL_KRB5_PAC_PLUGIN_H
+#define HEIMDAL_KRB5_PAC_PLUGIN_H 1
+
+#include <krb5.h>
+
+/*
+ * The PAC generate function should allocate a krb5_pac using
+ * krb5_pac_init and fill in the PAC structure for the principal using
+ * krb5_pac_add_buffer.
+ *
+ * The PAC verify function should verify all components in the PAC
+ * using krb5_pac_get_types and krb5_pac_get_buffer for all types.
+ *
+ * Check client access function check if the client is authorized.
+ */
+
+struct hdb_entry_ex;
+
+typedef krb5_error_code
+(*krb5plugin_windc_pac_generate)(void *, krb5_context,
+ struct hdb_entry_ex *, krb5_pac *);
+
+typedef krb5_error_code
+(*krb5plugin_windc_pac_verify)(void *, krb5_context,
+ const krb5_principal,
+ struct hdb_entry_ex *, struct hdb_entry_ex *, krb5_pac *);
+
+typedef krb5_error_code
+(*krb5plugin_windc_client_access)(
+ void *, krb5_context, struct hdb_entry_ex *, KDC_REQ *);
+
+
+#define KRB5_WINDC_PLUGING_MINOR 2
+
+typedef struct krb5plugin_windc_ftable {
+ int minor_version;
+ krb5_error_code (*init)(krb5_context, void **);
+ void (*fini)(void *);
+ krb5plugin_windc_pac_generate pac_generate;
+ krb5plugin_windc_pac_verify pac_verify;
+ krb5plugin_windc_client_access client_access;
+} krb5plugin_windc_ftable;
+
+#endif /* HEIMDAL_KRB5_PAC_PLUGIN_H */
+
diff --git a/source4/heimdal/lib/asn1/asn1-common.h b/source4/heimdal/lib/asn1/asn1-common.h
index ab06ae79dd6..5f09cd67946 100644
--- a/source4/heimdal/lib/asn1/asn1-common.h
+++ b/source4/heimdal/lib/asn1/asn1-common.h
@@ -1,4 +1,4 @@
-/* $Id: asn1-common.h,v 1.6 2006/10/14 05:09:47 lha Exp $ */
+/* $Id: asn1-common.h,v 1.7 2006/12/28 17:14:10 lha Exp $ */
#include <stddef.h>
#include <time.h>
@@ -32,6 +32,7 @@ typedef struct heim_universal_string {
uint32_t *data;
} heim_universal_string;
+typedef char *heim_visible_string;
typedef struct heim_oid {
size_t length;
diff --git a/source4/heimdal/lib/asn1/der-protos.h b/source4/heimdal/lib/asn1/der-protos.h
index 3aee392c962..7bfe02ebb44 100644
--- a/source4/heimdal/lib/asn1/der-protos.h
+++ b/source4/heimdal/lib/asn1/der-protos.h
@@ -82,6 +82,11 @@ der_copy_utf8string (
const heim_utf8_string */*from*/,
heim_utf8_string */*to*/);
+int
+der_copy_visible_string (
+ const heim_visible_string */*from*/,
+ heim_visible_string */*to*/);
+
void
der_free_bit_string (heim_bit_string */*k*/);
@@ -112,6 +117,9 @@ der_free_universal_string (heim_universal_string */*k*/);
void
der_free_utf8string (heim_utf8_string */*str*/);
+void
+der_free_visible_string (heim_visible_string */*str*/);
+
int
der_get_bit_string (
const unsigned char */*p*/,
@@ -252,6 +260,13 @@ der_get_utf8string (
size_t */*size*/);
int
+der_get_visible_string (
+ const unsigned char */*p*/,
+ size_t /*len*/,
+ heim_visible_string */*str*/,
+ size_t */*size*/);
+
+int
der_heim_bit_string_cmp (
const heim_bit_string */*p*/,
const heim_bit_string */*q*/);
@@ -332,6 +347,9 @@ der_length_utctime (const time_t */*t*/);
size_t
der_length_utf8string (const heim_utf8_string */*data*/);
+size_t
+der_length_visible_string (const heim_visible_string */*data*/);
+
int
der_match_tag (
const unsigned char */*p*/,
@@ -505,6 +523,13 @@ der_put_utf8string (
size_t */*size*/);
int
+der_put_visible_string (
+ unsigned char */*p*/,
+ size_t /*len*/,
+ const heim_visible_string */*str*/,
+ size_t */*size*/);
+
+int
encode_heim_any (
unsigned char */*p*/,
size_t /*len*/,
diff --git a/source4/heimdal/lib/asn1/der_copy.c b/source4/heimdal/lib/asn1/der_copy.c
index 96eea9c6d7c..15e7b817a04 100644
--- a/source4/heimdal/lib/asn1/der_copy.c
+++ b/source4/heimdal/lib/asn1/der_copy.c
@@ -33,7 +33,7 @@
#include "der_locl.h"
-RCSID("$Id: der_copy.c,v 1.16 2006/10/14 05:30:02 lha Exp $");
+RCSID("$Id: der_copy.c,v 1.17 2006/12/28 17:14:17 lha Exp $");
int
der_copy_general_string (const heim_general_string *from,
@@ -89,6 +89,13 @@ der_copy_universal_string (const heim_universal_string *from,
}
int
+der_copy_visible_string (const heim_visible_string *from,
+ heim_visible_string *to)
+{
+ return der_copy_general_string(from, to);
+}
+
+int
der_copy_octet_string (const heim_octet_string *from, heim_octet_string *to)
{
to->length = from->length;
diff --git a/source4/heimdal/lib/asn1/der_format.c b/source4/heimdal/lib/asn1/der_format.c
index 9655269356d..32cf23cb39b 100644
--- a/source4/heimdal/lib/asn1/der_format.c
+++ b/source4/heimdal/lib/asn1/der_format.c
@@ -34,7 +34,7 @@
#include "der_locl.h"
#include <hex.h>
-RCSID("$Id: der_format.c,v 1.6 2006/10/21 18:24:15 lha Exp $");
+RCSID("$Id: der_format.c,v 1.8 2006/11/27 10:32:21 lha Exp $");
int
der_parse_hex_heim_integer (const char *p, heim_integer *data)
@@ -110,10 +110,13 @@ der_print_heim_oid (const heim_oid *oid, char delim, char **str)
struct rk_strpool *p = NULL;
int i;
+ if (oid->length == 0)
+ return EINVAL;
+
for (i = 0; i < oid->length ; i++) {
- p = rk_strpoolprintf(p, "%d%s",
- oid->components[i],
- i < oid->length - 1 ? " " : "");
+ p = rk_strpoolprintf(p, "%d", oid->components[i]);
+ if (p && i < oid->length - 1)
+ p = rk_strpoolprintf(p, "%c", delim);
if (p == NULL) {
*str = NULL;
return ENOMEM;
diff --git a/source4/heimdal/lib/asn1/der_free.c b/source4/heimdal/lib/asn1/der_free.c
index c3a6a17fff7..6827486d9f7 100644
--- a/source4/heimdal/lib/asn1/der_free.c
+++ b/source4/heimdal/lib/asn1/der_free.c
@@ -33,7 +33,7 @@
#include "der_locl.h"
-RCSID("$Id: der_free.c,v 1.13 2006/10/14 05:30:47 lha Exp $");
+RCSID("$Id: der_free.c,v 1.14 2006/12/28 17:14:21 lha Exp $");
void
der_free_general_string (heim_general_string *str)
@@ -80,6 +80,13 @@ der_free_universal_string (heim_universal_string *k)
}
void
+der_free_visible_string (heim_visible_string *str)
+{
+ free(*str);
+ *str = NULL;
+}
+
+void
der_free_octet_string (heim_octet_string *k)
{
free(k->data);
diff --git a/source4/heimdal/lib/asn1/der_get.c b/source4/heimdal/lib/asn1/der_get.c
index 7808fa81651..a1ed23f10bc 100644
--- a/source4/heimdal/lib/asn1/der_get.c
+++ b/source4/heimdal/lib/asn1/der_get.c
@@ -33,7 +33,7 @@
#include "der_locl.h"
-RCSID("$Id: der_get.c,v 1.50 2006/10/19 16:27:44 lha Exp $");
+RCSID("$Id: der_get.c,v 1.51 2006/12/28 17:14:25 lha Exp $");
#include <version.h>
@@ -215,6 +215,13 @@ der_get_universal_string (const unsigned char *p, size_t len,
}
int
+der_get_visible_string (const unsigned char *p, size_t len,
+ heim_visible_string *str, size_t *size)
+{
+ return der_get_general_string(p, len, str, size);
+}
+
+int
der_get_octet_string (const unsigned char *p, size_t len,
heim_octet_string *data, size_t *size)
{
diff --git a/source4/heimdal/lib/asn1/der_length.c b/source4/heimdal/lib/asn1/der_length.c
index 9b2e9f09981..93cabe466c1 100644
--- a/source4/heimdal/lib/asn1/der_length.c
+++ b/source4/heimdal/lib/asn1/der_length.c
@@ -33,7 +33,7 @@
#include "der_locl.h"
-RCSID("$Id: der_length.c,v 1.19 2006/10/14 05:26:06 lha Exp $");
+RCSID("$Id: der_length.c,v 1.20 2006/12/28 17:14:28 lha Exp $");
size_t
_heim_len_unsigned (unsigned val)
@@ -167,6 +167,12 @@ der_length_universal_string (const heim_universal_string *data)
}
size_t
+der_length_visible_string (const heim_visible_string *data)
+{
+ return strlen(*data);
+}
+
+size_t
der_length_octet_string (const heim_octet_string *k)
{
return k->length;
diff --git a/source4/heimdal/lib/asn1/der_put.c b/source4/heimdal/lib/asn1/der_put.c
index b006f233ca6..9ed8f21906e 100644
--- a/source4/heimdal/lib/asn1/der_put.c
+++ b/source4/heimdal/lib/asn1/der_put.c
@@ -33,7 +33,7 @@
#include "der_locl.h"
-RCSID("$Id: der_put.c,v 1.33 2005/07/12 06:27:23 lha Exp $");
+RCSID("$Id: der_put.c,v 1.34 2006/12/28 17:14:33 lha Exp $");
/*
* All encoding functions take a pointer `p' to first position in
@@ -231,6 +231,13 @@ der_put_universal_string (unsigned char *p, size_t len,
}
int
+der_put_visible_string (unsigned char *p, size_t len,
+ const heim_visible_string *str, size_t *size)
+{
+ return der_put_general_string(p, len, str, size);
+}
+
+int
der_put_octet_string (unsigned char *p, size_t len,
const heim_octet_string *data, size_t *size)
{
diff --git a/source4/heimdal/lib/asn1/digest.asn1 b/source4/heimdal/lib/asn1/digest.asn1
index 1f8f18b5cd9..92bfb232343 100644
--- a/source4/heimdal/lib/asn1/digest.asn1
+++ b/source4/heimdal/lib/asn1/digest.asn1
@@ -1,4 +1,4 @@
--- $Id: digest.asn1,v 1.9 2006/08/25 11:57:54 lha Exp $
+-- $Id: digest.asn1,v 1.10 2006/12/15 19:13:39 lha Exp $
DIGEST DEFINITIONS ::=
BEGIN
@@ -58,9 +58,43 @@ DigestResponse ::= SEQUENCE {
hash-a1 [3] OCTET STRING OPTIONAL
}
+NTLMInit ::= SEQUENCE {
+ flags [0] INTEGER (0..4294967295),
+ hostname [1] UTF8String OPTIONAL,
+ domain [1] UTF8String OPTIONAL
+}
+
+NTLMInitReply ::= SEQUENCE {
+ flags [0] INTEGER (0..4294967295),
+ opaque [1] OCTET STRING,
+ targetname [2] UTF8String,
+ challange [3] OCTET STRING,
+ targetinfo [4] OCTET STRING OPTIONAL
+}
+
+NTLMRequest ::= SEQUENCE {
+ flags [0] INTEGER (0..4294967295),
+ opaque [1] OCTET STRING,
+ username [2] UTF8String,
+ targetname [3] UTF8String,
+ targetinfo [4] OCTET STRING OPTIONAL,
+ lm [5] OCTET STRING,
+ ntlm [6] OCTET STRING,
+ sessionkey [7] OCTET STRING OPTIONAL
+}
+
+NTLMResponse ::= SEQUENCE {
+ success [0] BOOLEAN,
+ flags [1] INTEGER (0..4294967295),
+ sessionkey [2] OCTET STRING OPTIONAL,
+ tickets [3] SEQUENCE OF OCTET STRING OPTIONAL
+}
+
DigestReqInner ::= CHOICE {
init [0] DigestInit,
- digestRequest [1] DigestRequest
+ digestRequest [1] DigestRequest,
+ ntlmInit [2] NTLMInit,
+ ntlmRequest [3] NTLMRequest
}
DigestREQ ::= [APPLICATION 128] SEQUENCE {
@@ -71,7 +105,9 @@ DigestREQ ::= [APPLICATION 128] SEQUENCE {
DigestRepInner ::= CHOICE {
error [0] DigestError,
initReply [1] DigestInitReply,
- response [2] DigestResponse
+ response [2] DigestResponse,
+ ntlmInitReply [3] NTLMInitReply,
+ ntlmResponse [4] NTLMResponse
}
DigestREP ::= [APPLICATION 129] SEQUENCE {
diff --git a/source4/heimdal/lib/asn1/gen.c b/source4/heimdal/lib/asn1/gen.c
index c3af316c888..3bb9022be85 100644
--- a/source4/heimdal/lib/asn1/gen.c
+++ b/source4/heimdal/lib/asn1/gen.c
@@ -33,7 +33,7 @@
#include "gen_locl.h"
-RCSID("$Id: gen.c,v 1.69 2006/10/14 05:11:52 lha Exp $");
+RCSID("$Id: gen.c,v 1.70 2006/12/28 17:14:37 lha Exp $");
FILE *headerfile, *codefile, *logfile;
@@ -136,6 +136,9 @@ init_generate (const char *filename, const char *base)
" uint32_t *data;\n"
"} heim_universal_string;\n\n");
fprintf (headerfile,
+ "typedef char *heim_visible_string;\n\n"
+ );
+ fprintf (headerfile,
"typedef struct heim_oid {\n"
" size_t length;\n"
" unsigned *components;\n"
@@ -504,6 +507,10 @@ define_asn1 (int level, Type *t)
space(level);
fprintf (headerfile, "UniversalString");
break;
+ case TVisibleString:
+ space(level);
+ fprintf (headerfile, "VisibleString");
+ break;
case TOID :
space(level);
fprintf(headerfile, "OBJECT IDENTIFIER");
@@ -736,6 +743,10 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep)
space(level);
fprintf (headerfile, "heim_universal_string %s;\n", name);
break;
+ case TVisibleString:
+ space(level);
+ fprintf (headerfile, "heim_visible_string %s;\n", name);
+ break;
case TOID :
space(level);
fprintf (headerfile, "heim_oid %s;\n", name);
diff --git a/source4/heimdal/lib/asn1/gen_copy.c b/source4/heimdal/lib/asn1/gen_copy.c
index 9455f33c6f3..95646d0a3c8 100644
--- a/source4/heimdal/lib/asn1/gen_copy.c
+++ b/source4/heimdal/lib/asn1/gen_copy.c
@@ -33,7 +33,7 @@
#include "gen_locl.h"
-RCSID("$Id: gen_copy.c,v 1.18 2006/10/14 05:34:19 lha Exp $");
+RCSID("$Id: gen_copy.c,v 1.19 2006/12/28 17:14:42 lha Exp $");
static int used_fail;
@@ -202,6 +202,9 @@ copy_type (const char *from, const char *to, const Type *t, int preserve)
case TUniversalString:
copy_primitive ("universal_string", from, to);
break;
+ case TVisibleString:
+ copy_primitive ("visible_string", from, to);
+ break;
case TTag:
copy_type (from, to, t->subtype, preserve);
break;
diff --git a/source4/heimdal/lib/asn1/gen_decode.c b/source4/heimdal/lib/asn1/gen_decode.c
index 193dab40e1a..19ddbb46db6 100644
--- a/source4/heimdal/lib/asn1/gen_decode.c
+++ b/source4/heimdal/lib/asn1/gen_decode.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -34,7 +34,7 @@
#include "gen_locl.h"
#include "lex.h"
-RCSID("$Id: gen_decode.c,v 1.30 2006/09/24 09:13:12 lha Exp $");
+RCSID("$Id: gen_decode.c,v 1.32 2006/12/29 17:30:32 lha Exp $");
static void
decode_primitive (const char *typename, const char *name, const char *forwstr)
@@ -74,6 +74,7 @@ is_primitive_type(int type)
case TIA5String:
case TBMPString:
case TUniversalString:
+ case TVisibleString:
case TNull:
return 1;
default:
@@ -191,6 +192,11 @@ find_tag (const Type *t,
*ty = PRIM;
*tag = UT_UniversalString;
break;
+ case TVisibleString:
+ *cl = ASN1_C_UNIV;
+ *ty = PRIM;
+ *tag = UT_VisibleString;
+ break;
default:
abort();
}
@@ -580,6 +586,9 @@ decode_type (const char *name, const Type *t, int optional,
case TUniversalString:
decode_primitive ("universal_string", name, forwstr);
break;
+ case TVisibleString:
+ decode_primitive ("visible_string", name, forwstr);
+ break;
case TNull:
fprintf (codefile, "/* NULL */\n");
break;
@@ -620,6 +629,7 @@ generate_type_decode (const Symbol *s)
case TIA5String:
case TBMPString:
case TUniversalString:
+ case TVisibleString:
case TUTCTime:
case TNull:
case TEnumerated:
diff --git a/source4/heimdal/lib/asn1/gen_encode.c b/source4/heimdal/lib/asn1/gen_encode.c
index 4099fbf6433..bc2aff86e5d 100644
--- a/source4/heimdal/lib/asn1/gen_encode.c
+++ b/source4/heimdal/lib/asn1/gen_encode.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "gen_locl.h"
-RCSID("$Id: gen_encode.c,v 1.19 2005/08/23 11:52:16 lha Exp $");
+RCSID("$Id: gen_encode.c,v 1.22 2006/12/29 17:30:03 lha Exp $");
static void
encode_primitive (const char *typename, const char *name)
@@ -151,7 +151,6 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
case TBitString: {
Member *m;
int pos;
- int rest;
if (ASN1_TAILQ_EMPTY(t->members)) {
encode_primitive("bit_string", name);
@@ -163,6 +162,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
"unsigned char c = 0;\n");
if (!rfc1510_bitstring)
fprintf (codefile,
+ "int rest = 0;\n"
"int bit_set = 0;\n");
#if 0
pos = t->members->prev->val;
@@ -181,9 +181,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
if (rfc1510_bitstring) {
if (pos < 31)
pos = 31;
- rest = 7 - (pos % 8);
- } else
- rest = 0;
+ }
ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
while (m->val / 8 < pos / 8) {
@@ -192,20 +190,27 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
"if (c != 0 || bit_set) {\n");
fprintf (codefile,
"if (len < 1) return ASN1_OVERFLOW;\n"
- "*p-- = c; len--; ret++;\n"
- "c = 0;\n");
+ "*p-- = c; len--; ret++;\n");
if (!rfc1510_bitstring)
fprintf (codefile,
+ "if (!bit_set) {\n"
+ "rest = 0;\n"
+ "while(c) { \n"
+ "if (c & 1) break;\n"
+ "c = c >> 1;\n"
+ "rest++;\n"
+ "}\n"
"bit_set = 1;\n"
+ "}\n"
"}\n");
+ fprintf (codefile,
+ "c = 0;\n");
pos -= 8;
}
fprintf (codefile,
"if((%s)->%s) {\n"
"c |= 1<<%d;\n",
name, m->gen_name, 7 - m->val % 8);
- if (!rfc1510_bitstring)
- rest = 7 - m->val % 8;
fprintf (codefile,
"}\n");
}
@@ -218,15 +223,25 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
"*p-- = c; len--; ret++;\n");
if (!rfc1510_bitstring)
fprintf (codefile,
+ "if (!bit_set) {\n"
+ "rest = 0;\n"
+ "if(c) { \n"
+ "while(c) { \n"
+ "if (c & 1) break;\n"
+ "c = c >> 1;\n"
+ "rest++;\n"
+ "}\n"
+ "}\n"
+ "}\n"
"}\n");
-
+
fprintf (codefile,
"if (len < 1) return ASN1_OVERFLOW;\n"
- "*p-- = %d;\n"
+ "*p-- = %s;\n"
"len -= 1;\n"
"ret += 1;\n"
"}\n\n",
- rest);
+ rfc1510_bitstring ? "0" : "rest");
constructed = 0;
break;
}
@@ -467,6 +482,10 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
encode_primitive ("universal_string", name);
constructed = 0;
break;
+ case TVisibleString:
+ encode_primitive ("visible_string", name);
+ constructed = 0;
+ break;
case TNull:
fprintf (codefile, "/* NULL */\n");
constructed = 0;
@@ -503,6 +522,7 @@ generate_type_encode (const Symbol *s)
case TIA5String:
case TBMPString:
case TUniversalString:
+ case TVisibleString:
case TNull:
case TBitString:
case TEnumerated:
diff --git a/source4/heimdal/lib/asn1/gen_free.c b/source4/heimdal/lib/asn1/gen_free.c
index 2b143bf8189..26e02e39dd4 100644
--- a/source4/heimdal/lib/asn1/gen_free.c
+++ b/source4/heimdal/lib/asn1/gen_free.c
@@ -33,7 +33,7 @@
#include "gen_locl.h"
-RCSID("$Id: gen_free.c,v 1.16 2006/10/14 05:33:58 lha Exp $");
+RCSID("$Id: gen_free.c,v 1.17 2006/12/28 17:14:54 lha Exp $");
static void
free_primitive (const char *typename, const char *name)
@@ -160,6 +160,9 @@ free_type (const char *name, const Type *t, int preserve)
case TUniversalString:
free_primitive ("universal_string", name);
break;
+ case TVisibleString:
+ free_primitive ("visible_string", name);
+ break;
case TTag:
free_type (name, t->subtype, preserve);
break;
diff --git a/source4/heimdal/lib/asn1/gen_length.c b/source4/heimdal/lib/asn1/gen_length.c
index 0c92225b924..7f9dc7257b9 100644
--- a/source4/heimdal/lib/asn1/gen_length.c
+++ b/source4/heimdal/lib/asn1/gen_length.c
@@ -33,7 +33,7 @@
#include "gen_locl.h"
-RCSID("$Id: gen_length.c,v 1.21 2006/10/14 05:28:28 lha Exp $");
+RCSID("$Id: gen_length.c,v 1.22 2006/12/28 17:14:57 lha Exp $");
static void
length_primitive (const char *typename,
@@ -238,6 +238,9 @@ length_type (const char *name, const Type *t,
case TUniversalString:
length_primitive ("universal_string", name, variable);
break;
+ case TVisibleString:
+ length_primitive ("visible_string", name, variable);
+ break;
case TNull:
fprintf (codefile, "/* NULL */\n");
break;
diff --git a/source4/heimdal/lib/asn1/k5.asn1 b/source4/heimdal/lib/asn1/k5.asn1
index 3f501f0592c..a86df38a999 100644
--- a/source4/heimdal/lib/asn1/k5.asn1
+++ b/source4/heimdal/lib/asn1/k5.asn1
@@ -1,4 +1,4 @@
--- $Id: k5.asn1,v 1.50 2006/09/11 13:28:59 lha Exp $
+-- $Id: k5.asn1,v 1.51 2006/11/21 05:17:47 lha Exp $
KERBEROS5 DEFINITIONS ::=
BEGIN
@@ -70,11 +70,11 @@ PADATA-TYPE ::= INTEGER {
KRB5-PADATA-TD-REQ-NONCE(107), -- INTEGER
KRB5-PADATA-TD-REQ-SEQ(108), -- INTEGER
KRB5-PADATA-PA-PAC-REQUEST(128), -- jbrezak@exchange.microsoft.com
- KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to
+ KRB5-PADATA-S4U2SELF(129),
+ KRB5-PADATA-PK-AS-09-BINDING(132) -- client send this to
-- tell KDC that is supports
-- the asCheckSum in the
-- PK-AS-REP
- KRB5-PADATA-S4U2SELF(-17)
}
AUTHDATA-TYPE ::= INTEGER {
diff --git a/source4/heimdal/lib/asn1/kx509.asn1 b/source4/heimdal/lib/asn1/kx509.asn1
new file mode 100644
index 00000000000..9706b061c37
--- /dev/null
+++ b/source4/heimdal/lib/asn1/kx509.asn1
@@ -0,0 +1,20 @@
+-- $Id: kx509.asn1,v 1.1 2006/12/28 21:05:23 lha Exp $
+
+KX509 DEFINITIONS ::=
+BEGIN
+
+Kx509Request ::= SEQUENCE {
+ authenticator OCTET STRING,
+ pk-hash OCTET STRING,
+ pk-key OCTET STRING
+}
+
+Kx509Response ::= SEQUENCE {
+ error-code[0] INTEGER (-2147483648..2147483647)
+ OPTIONAL -- DEFAULT 0 --,
+ hash[1] OCTET STRING OPTIONAL,
+ certificate[2] OCTET STRING OPTIONAL,
+ e-text[3] VisibleString OPTIONAL
+}
+
+END
diff --git a/source4/heimdal/lib/asn1/lex.l b/source4/heimdal/lib/asn1/lex.l
index 4b2c5af0621..6ec7b67bb9c 100644
--- a/source4/heimdal/lib/asn1/lex.l
+++ b/source4/heimdal/lib/asn1/lex.l
@@ -32,7 +32,7 @@
* SUCH DAMAGE.
*/
-/* $Id: lex.l,v 1.27 2005/09/13 18:17:16 lha Exp $ */
+/* $Id: lex.l,v 1.31 2006/10/21 11:57:22 lha Exp $ */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -58,6 +58,12 @@ static void unterminated(const char *, unsigned);
%}
+/* This is for broken old lexes (solaris 10 and hpux) */
+%e 2000
+%p 5000
+%a 5000
+%n 1000
+%o 10000
%%
ABSENT { return kw_ABSENT; }
diff --git a/source4/heimdal/lib/asn1/parse.c b/source4/heimdal/lib/asn1/parse.c
index 29d13ed68d2..fc9f195e1f4 100644
--- a/source4/heimdal/lib/asn1/parse.c
+++ b/source4/heimdal/lib/asn1/parse.c
@@ -251,7 +251,7 @@
#include "gen_locl.h"
#include "der.h"
-RCSID("$Id: parse.y,v 1.28 2006/04/28 10:51:35 lha Exp $");
+RCSID("$Id: parse.y,v 1.29 2006/12/28 17:15:02 lha Exp $");
static Type *new_type (Typetype t);
static struct constraint_spec *new_constraint_spec(enum ctype);
@@ -466,16 +466,16 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 4
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 168
+#define YYLAST 169
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 98
/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 67
/* YYNRULES -- Number of rules. */
-#define YYNRULES 130
+#define YYNRULES 131
/* YYNRULES -- Number of states. */
-#define YYNSTATES 201
+#define YYNSTATES 202
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
@@ -538,11 +538,11 @@ static const unsigned short int yyprhs[] =
167, 171, 176, 180, 184, 189, 191, 193, 195, 197,
199, 202, 206, 208, 210, 212, 215, 219, 225, 230,
234, 239, 240, 242, 244, 246, 247, 249, 251, 256,
- 258, 260, 262, 264, 266, 268, 270, 272, 276, 280,
- 283, 285, 288, 292, 294, 298, 303, 305, 306, 310,
- 311, 314, 319, 321, 323, 325, 327, 329, 331, 333,
+ 258, 260, 262, 264, 266, 268, 270, 272, 274, 278,
+ 282, 285, 287, 290, 294, 296, 300, 305, 307, 308,
+ 312, 313, 316, 321, 323, 325, 327, 329, 331, 333,
335, 337, 339, 341, 343, 345, 347, 349, 351, 353,
- 355
+ 355, 357
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
@@ -574,16 +574,16 @@ static const short int yyrhs[] =
139, 141, 111, -1, 96, 140, 89, 97, -1, -1,
76, -1, 6, -1, 60, -1, -1, 27, -1, 38,
-1, 86, 111, 84, 154, -1, 144, -1, 33, -1,
- 78, -1, 61, -1, 36, -1, 10, -1, 79, -1,
- 147, -1, 145, 91, 147, -1, 145, 91, 85, -1,
- 86, 111, -1, 146, -1, 146, 54, -1, 146, 20,
- 154, -1, 149, -1, 148, 91, 149, -1, 86, 92,
- 89, 93, -1, 151, -1, -1, 94, 152, 95, -1,
- -1, 153, 152, -1, 86, 92, 89, 93, -1, 86,
- -1, 89, -1, 155, -1, 156, -1, 160, -1, 159,
- -1, 161, -1, 164, -1, 163, -1, 157, -1, 158,
- -1, 86, -1, 88, -1, 71, -1, 31, -1, 162,
- -1, 89, -1, 49, -1, 151, -1
+ 78, -1, 61, -1, 81, -1, 36, -1, 10, -1,
+ 79, -1, 147, -1, 145, 91, 147, -1, 145, 91,
+ 85, -1, 86, 111, -1, 146, -1, 146, 54, -1,
+ 146, 20, 154, -1, 149, -1, 148, 91, 149, -1,
+ 86, 92, 89, 93, -1, 151, -1, -1, 94, 152,
+ 95, -1, -1, 153, 152, -1, 86, 92, 89, 93,
+ -1, 86, -1, 89, -1, 155, -1, 156, -1, 160,
+ -1, 159, -1, 161, -1, 164, -1, 163, -1, 157,
+ -1, 158, -1, 86, -1, 88, -1, 71, -1, 31,
+ -1, 162, -1, 89, -1, 49, -1, 151, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
@@ -598,11 +598,11 @@ static const unsigned short int yyrline[] =
456, 464, 470, 478, 486, 493, 494, 497, 508, 513,
520, 536, 542, 545, 546, 549, 555, 563, 573, 579,
592, 601, 604, 608, 612, 619, 622, 626, 633, 644,
- 647, 652, 657, 662, 667, 672, 680, 686, 691, 702,
- 713, 719, 725, 733, 739, 746, 759, 760, 763, 770,
- 773, 784, 788, 799, 805, 806, 809, 810, 811, 812,
- 813, 816, 819, 822, 833, 841, 847, 855, 863, 866,
- 871
+ 647, 652, 657, 662, 667, 672, 677, 685, 691, 696,
+ 707, 718, 724, 730, 738, 744, 751, 764, 765, 768,
+ 775, 778, 789, 793, 804, 810, 811, 814, 815, 816,
+ 817, 818, 821, 824, 827, 838, 846, 852, 860, 868,
+ 871, 876
};
#endif
@@ -682,11 +682,11 @@ static const unsigned char yyr1[] =
125, 126, 126, 127, 128, 129, 129, 130, 131, 131,
132, 133, 134, 135, 135, 136, 136, 136, 137, 138,
139, 140, 140, 140, 140, 141, 141, 141, 142, 143,
- 144, 144, 144, 144, 144, 144, 145, 145, 145, 146,
- 147, 147, 147, 148, 148, 149, 150, 150, 151, 152,
- 152, 153, 153, 153, 154, 154, 155, 155, 155, 155,
- 155, 156, 157, 158, 159, 160, 160, 161, 162, 163,
- 164
+ 144, 144, 144, 144, 144, 144, 144, 145, 145, 145,
+ 146, 147, 147, 147, 148, 148, 149, 150, 150, 151,
+ 152, 152, 153, 153, 153, 154, 154, 155, 155, 155,
+ 155, 155, 156, 157, 158, 159, 160, 160, 161, 162,
+ 163, 164
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
@@ -701,11 +701,11 @@ static const unsigned char yyr2[] =
3, 4, 3, 3, 4, 1, 1, 1, 1, 1,
2, 3, 1, 1, 1, 2, 3, 5, 4, 3,
4, 0, 1, 1, 1, 0, 1, 1, 4, 1,
- 1, 1, 1, 1, 1, 1, 1, 3, 3, 2,
- 1, 2, 3, 1, 3, 4, 1, 0, 3, 0,
- 2, 4, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 3,
+ 2, 1, 2, 3, 1, 3, 4, 1, 0, 3,
+ 0, 2, 4, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1
+ 1, 1
};
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -716,76 +716,76 @@ static const unsigned char yydefact[] =
0, 0, 0, 6, 1, 0, 0, 0, 8, 5,
3, 4, 0, 0, 7, 0, 10, 14, 0, 0,
23, 0, 13, 15, 0, 2, 0, 9, 18, 20,
- 21, 0, 11, 16, 0, 0, 94, 42, 0, 0,
- 90, 68, 93, 44, 57, 0, 0, 92, 0, 0,
- 69, 91, 95, 0, 67, 81, 0, 25, 29, 33,
- 32, 28, 35, 36, 34, 37, 38, 39, 40, 31,
- 26, 65, 66, 27, 41, 85, 30, 89, 19, 22,
- 107, 53, 0, 0, 0, 0, 45, 55, 56, 0,
- 0, 0, 0, 24, 83, 84, 82, 0, 0, 0,
- 70, 86, 87, 0, 109, 17, 106, 0, 0, 0,
- 100, 96, 0, 52, 47, 0, 126, 129, 125, 123,
- 124, 128, 130, 0, 114, 115, 121, 122, 117, 116,
- 118, 127, 120, 119, 0, 60, 59, 0, 63, 62,
- 0, 0, 88, 0, 0, 0, 0, 72, 73, 74,
- 79, 112, 113, 0, 109, 0, 0, 103, 99, 0,
- 64, 0, 101, 0, 0, 51, 0, 46, 58, 61,
- 80, 0, 75, 0, 71, 0, 108, 110, 0, 0,
- 54, 98, 97, 102, 0, 49, 48, 0, 0, 0,
- 76, 0, 0, 104, 50, 43, 78, 0, 111, 105,
- 77
+ 21, 0, 11, 16, 0, 0, 95, 42, 0, 0,
+ 90, 68, 94, 44, 57, 0, 0, 92, 0, 0,
+ 69, 91, 96, 93, 0, 67, 81, 0, 25, 29,
+ 33, 32, 28, 35, 36, 34, 37, 38, 39, 40,
+ 31, 26, 65, 66, 27, 41, 85, 30, 89, 19,
+ 22, 108, 53, 0, 0, 0, 0, 45, 55, 56,
+ 0, 0, 0, 0, 24, 83, 84, 82, 0, 0,
+ 0, 70, 86, 87, 0, 110, 17, 107, 0, 0,
+ 0, 101, 97, 0, 52, 47, 0, 127, 130, 126,
+ 124, 125, 129, 131, 0, 115, 116, 122, 123, 118,
+ 117, 119, 128, 121, 120, 0, 60, 59, 0, 63,
+ 62, 0, 0, 88, 0, 0, 0, 0, 72, 73,
+ 74, 79, 113, 114, 0, 110, 0, 0, 104, 100,
+ 0, 64, 0, 102, 0, 0, 51, 0, 46, 58,
+ 61, 80, 0, 75, 0, 71, 0, 109, 111, 0,
+ 0, 54, 99, 98, 103, 0, 49, 48, 0, 0,
+ 0, 76, 0, 0, 105, 50, 43, 78, 0, 112,
+ 106, 77
};
/* YYDEFGOTO[NTERM-NUM]. */
static const short int yydefgoto[] =
{
-1, 2, 8, 13, 18, 19, 21, 22, 23, 27,
- 28, 24, 29, 56, 57, 58, 86, 59, 113, 114,
- 60, 115, 61, 62, 63, 64, 65, 66, 67, 68,
- 69, 70, 71, 72, 73, 100, 146, 147, 148, 149,
- 74, 75, 97, 103, 30, 76, 77, 109, 110, 111,
- 156, 157, 105, 122, 153, 154, 123, 124, 125, 126,
- 127, 128, 129, 130, 131, 132, 133
+ 28, 24, 29, 57, 58, 59, 87, 60, 114, 115,
+ 61, 116, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 101, 147, 148, 149, 150,
+ 75, 76, 98, 104, 30, 77, 78, 110, 111, 112,
+ 157, 158, 106, 123, 154, 155, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -99
+#define YYPACT_NINF -100
static const short int yypact[] =
{
- -46, 20, 13, 21, -99, 11, 23, 25, 54, -99,
- -99, -99, 58, 6, -99, 90, -34, 15, 80, 19,
- 16, 18, 15, -99, 74, -99, -7, -99, 19, -99,
- -99, 15, -99, -99, 24, 42, -99, -99, 17, 26,
- -99, -99, -99, -73, -99, 76, 50, -99, -45, -44,
- -99, -99, -99, 51, -99, 4, -67, -99, -99, -99,
- -99, -99, -99, -99, -99, -99, -99, -99, -99, -99,
- -99, -99, -99, -99, -99, -16, -99, -99, -99, -99,
- 27, 28, 33, 37, 47, 37, -99, -99, -99, 51,
- -72, 51, -71, 22, -99, -99, -99, 35, 47, 12,
- -99, -99, -99, 51, 2, -99, -99, 39, 51, -75,
- -8, -99, 34, 36, -99, 43, -99, -99, -99, -99,
- -99, -99, -99, 48, -99, -99, -99, -99, -99, -99,
- -99, -99, -99, -99, -57, 22, -99, -48, 22, -99,
- -22, 45, -99, 120, 51, 122, 46, -99, -99, -99,
- 22, 52, -99, 53, 2, 57, -9, -99, 22, -53,
- -99, 47, -99, 56, -19, -99, 47, -99, -99, -99,
- -99, 49, -18, 47, -99, 61, -99, -99, 62, 39,
- -99, -99, -99, -99, 59, -99, -99, 60, 63, 128,
- -99, 64, 66, -99, -99, -99, -99, 47, -99, -99,
- -99
+ -65, 19, 33, 5, -100, -29, -17, 11, 53, -100,
+ -100, -100, 47, 13, -100, 90, -34, 18, 81, 20,
+ 16, 21, 18, -100, 76, -100, -7, -100, 20, -100,
+ -100, 18, -100, -100, 23, 43, -100, -100, 24, 25,
+ -100, -100, -100, -4, -100, 77, 46, -100, -48, -45,
+ -100, -100, -100, -100, 51, -100, 4, -64, -100, -100,
+ -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,
+ -100, -100, -100, -100, -100, -100, -16, -100, -100, -100,
+ -100, 26, 27, 31, 36, 52, 36, -100, -100, -100,
+ 51, -71, 51, -70, 32, -100, -100, -100, 37, 52,
+ 12, -100, -100, -100, 51, -39, -100, -100, 39, 51,
+ -78, -6, -100, 35, 40, -100, 38, -100, -100, -100,
+ -100, -100, -100, -100, 56, -100, -100, -100, -100, -100,
+ -100, -100, -100, -100, -100, -72, 32, -100, -57, 32,
+ -100, -36, 45, -100, 122, 51, 123, 50, -100, -100,
+ -100, 32, 44, -100, 49, -39, 57, -22, -100, 32,
+ -19, -100, 52, -100, 59, 10, -100, 52, -100, -100,
+ -100, -100, 58, -14, 52, -100, 61, -100, -100, 62,
+ 39, -100, -100, -100, -100, 60, -100, -100, 63, 64,
+ 133, -100, 65, 67, -100, -100, -100, -100, 52, -100,
+ -100, -100
};
/* YYPGOTO[NTERM-NUM]. */
-static const yysigned_char yypgoto[] =
+static const short int yypgoto[] =
{
- -99, -99, -99, -99, -99, -99, -99, -99, 124, 126,
- -99, 125, -99, -52, -99, -99, -99, -99, 70, -4,
- -99, -99, -99, -99, -99, -99, -99, -99, -99, -99,
- -99, -99, -99, -99, -99, -99, -99, -99, -99, -99,
- -99, -99, -99, -99, -99, -99, -99, -37, -99, 3,
- -99, -15, -99, 81, 9, -99, -98, -99, -99, -99,
- -99, -99, -99, -99, 5, -99, -99
+ -100, -100, -100, -100, -100, -100, -100, -100, 132, 127,
+ -100, 126, -100, -53, -100, -100, -100, -100, 75, -3,
+ -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,
+ -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,
+ -100, -100, -100, -100, -100, -100, -100, 0, -100, 3,
+ -100, -15, -100, 83, 14, -100, -99, -100, -100, -100,
+ -100, -100, -100, -100, 2, -100, -100
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
@@ -795,44 +795,44 @@ static const yysigned_char yypgoto[] =
#define YYTABLE_NINF -13
static const short int yytable[] =
{
- 142, 93, 35, 36, 37, 189, 17, 38, 89, 91,
- 94, 101, 161, 4, 108, 108, 159, 98, 39, 84,
- 160, 85, 102, 136, 139, 99, 40, 41, 5, 42,
- 143, 144, 181, 108, 164, 145, 43, 135, 167, 138,
- 1, 3, 44, 159, 45, 46, 162, 168, 6, 90,
- 92, 150, -12, 137, 47, 140, 158, 48, 49, 7,
- 35, 36, 37, 183, 95, 38, 185, 112, 187, 159,
- 50, 51, 52, 169, 99, 190, 39, 53, 116, 54,
- 96, 9, 179, 12, 40, 41, 180, 42, 151, 55,
- 15, 152, 172, 10, 43, 11, 117, 14, 16, 200,
- 44, 20, 45, 46, 25, 26, 34, 31, 32, 81,
- 80, 82, 47, 87, 99, 48, 49, 88, 118, 108,
- 83, 104, 107, 112, 141, 155, 163, 164, 50, 51,
- 52, 166, 171, 119, 173, 120, 121, 54, 165, 174,
- 197, 104, 170, 188, 175, 121, 33, 55, 176, 178,
- 191, 192, 194, 195, 78, 134, 79, 198, 196, 199,
- 186, 106, 182, 177, 193, 0, 0, 0, 184
+ 143, 94, 35, 36, 37, 90, 17, 38, 92, 190,
+ 95, 102, 5, 160, 162, 109, 109, 161, 39, 165,
+ 99, 1, 103, 168, 137, 140, 40, 41, 100, 42,
+ 144, 145, 6, 4, 160, 146, 43, 136, 169, 139,
+ 3, 9, 44, 7, 45, 46, 91, 152, 163, 93,
+ 153, 151, -12, 10, 47, 160, 159, 48, 49, 170,
+ 35, 36, 37, 184, 96, 38, 182, 109, 188, 180,
+ 50, 51, 52, 181, 53, 191, 39, 54, 100, 55,
+ 97, 11, 12, 117, 40, 41, 14, 42, 85, 56,
+ 86, 138, 173, 141, 43, 186, 113, 15, 16, 201,
+ 44, 118, 45, 46, 20, 25, 26, 31, 34, 81,
+ 82, 32, 47, 89, 88, 48, 49, 109, 83, 84,
+ 105, 108, 113, 119, 100, 156, 142, 164, 50, 51,
+ 52, 165, 53, 166, 172, 174, 176, 55, 120, 167,
+ 121, 122, 171, 175, 177, 198, 105, 56, 122, 179,
+ 192, 193, 189, 195, 33, 79, 196, 80, 199, 197,
+ 200, 135, 187, 183, 107, 194, 185, 0, 0, 178
};
static const short int yycheck[] =
{
- 98, 53, 9, 10, 11, 23, 40, 14, 53, 53,
- 6, 27, 20, 0, 86, 86, 91, 84, 25, 92,
- 95, 94, 38, 95, 95, 92, 33, 34, 7, 36,
- 18, 19, 85, 86, 91, 23, 43, 89, 95, 91,
- 86, 21, 49, 91, 51, 52, 54, 95, 27, 94,
- 94, 103, 86, 90, 61, 92, 108, 64, 65, 38,
- 9, 10, 11, 161, 60, 14, 85, 86, 166, 91,
- 77, 78, 79, 95, 92, 173, 25, 84, 31, 86,
- 76, 70, 91, 29, 33, 34, 95, 36, 86, 96,
- 84, 89, 144, 70, 43, 70, 49, 39, 8, 197,
- 49, 86, 51, 52, 24, 86, 32, 91, 90, 67,
- 86, 94, 61, 37, 92, 64, 65, 67, 71, 86,
- 94, 94, 94, 86, 89, 86, 92, 91, 77, 78,
- 79, 83, 12, 86, 12, 88, 89, 86, 95, 93,
- 12, 94, 97, 94, 92, 89, 22, 96, 95, 92,
- 89, 89, 93, 93, 28, 85, 31, 93, 95, 93,
- 164, 80, 159, 154, 179, -1, -1, -1, 163
+ 99, 54, 9, 10, 11, 53, 40, 14, 53, 23,
+ 6, 27, 7, 91, 20, 86, 86, 95, 25, 91,
+ 84, 86, 38, 95, 95, 95, 33, 34, 92, 36,
+ 18, 19, 27, 0, 91, 23, 43, 90, 95, 92,
+ 21, 70, 49, 38, 51, 52, 94, 86, 54, 94,
+ 89, 104, 86, 70, 61, 91, 109, 64, 65, 95,
+ 9, 10, 11, 162, 60, 14, 85, 86, 167, 91,
+ 77, 78, 79, 95, 81, 174, 25, 84, 92, 86,
+ 76, 70, 29, 31, 33, 34, 39, 36, 92, 96,
+ 94, 91, 145, 93, 43, 85, 86, 84, 8, 198,
+ 49, 49, 51, 52, 86, 24, 86, 91, 32, 86,
+ 67, 90, 61, 67, 37, 64, 65, 86, 94, 94,
+ 94, 94, 86, 71, 92, 86, 89, 92, 77, 78,
+ 79, 91, 81, 95, 12, 12, 92, 86, 86, 83,
+ 88, 89, 97, 93, 95, 12, 94, 96, 89, 92,
+ 89, 89, 94, 93, 22, 28, 93, 31, 93, 95,
+ 93, 86, 165, 160, 81, 180, 164, -1, -1, 155
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -844,22 +844,22 @@ static const unsigned char yystos[] =
86, 104, 105, 106, 109, 24, 86, 107, 108, 110,
142, 91, 90, 106, 32, 9, 10, 11, 14, 25,
33, 34, 36, 43, 49, 51, 52, 61, 64, 65,
- 77, 78, 79, 84, 86, 96, 111, 112, 113, 115,
- 118, 120, 121, 122, 123, 124, 125, 126, 127, 128,
- 129, 130, 131, 132, 138, 139, 143, 144, 107, 109,
- 86, 67, 94, 94, 92, 94, 114, 37, 67, 53,
- 94, 53, 94, 111, 6, 60, 76, 140, 84, 92,
- 133, 27, 38, 141, 94, 150, 151, 94, 86, 145,
- 146, 147, 86, 116, 117, 119, 31, 49, 71, 86,
- 88, 89, 151, 154, 155, 156, 157, 158, 159, 160,
- 161, 162, 163, 164, 116, 111, 95, 145, 111, 95,
- 145, 89, 154, 18, 19, 23, 134, 135, 136, 137,
- 111, 86, 89, 152, 153, 86, 148, 149, 111, 91,
- 95, 20, 54, 92, 91, 95, 83, 95, 95, 95,
- 97, 12, 111, 12, 93, 92, 95, 152, 92, 91,
- 95, 85, 147, 154, 162, 85, 117, 154, 94, 23,
- 154, 89, 89, 149, 93, 93, 95, 12, 93, 93,
- 154
+ 77, 78, 79, 81, 84, 86, 96, 111, 112, 113,
+ 115, 118, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 138, 139, 143, 144, 107,
+ 109, 86, 67, 94, 94, 92, 94, 114, 37, 67,
+ 53, 94, 53, 94, 111, 6, 60, 76, 140, 84,
+ 92, 133, 27, 38, 141, 94, 150, 151, 94, 86,
+ 145, 146, 147, 86, 116, 117, 119, 31, 49, 71,
+ 86, 88, 89, 151, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 116, 111, 95, 145, 111,
+ 95, 145, 89, 154, 18, 19, 23, 134, 135, 136,
+ 137, 111, 86, 89, 152, 153, 86, 148, 149, 111,
+ 91, 95, 20, 54, 92, 91, 95, 83, 95, 95,
+ 95, 97, 12, 111, 12, 93, 92, 95, 152, 92,
+ 91, 95, 85, 147, 154, 162, 85, 117, 154, 94,
+ 23, 154, 89, 89, 149, 93, 93, 95, 12, 93,
+ 93, 154
};
#define yyerrok (yyerrstatus = 0)
@@ -1987,29 +1987,37 @@ yyreduce:
case 93:
#line 663 "parse.y"
{
- (yyval.type) = new_tag(ASN1_C_UNIV, UT_IA5String,
- TE_EXPLICIT, new_type(TIA5String));
+ (yyval.type) = new_tag(ASN1_C_UNIV, UT_VisibleString,
+ TE_EXPLICIT, new_type(TVisibleString));
}
break;
case 94:
#line 668 "parse.y"
{
- (yyval.type) = new_tag(ASN1_C_UNIV, UT_BMPString,
- TE_EXPLICIT, new_type(TBMPString));
+ (yyval.type) = new_tag(ASN1_C_UNIV, UT_IA5String,
+ TE_EXPLICIT, new_type(TIA5String));
}
break;
case 95:
#line 673 "parse.y"
{
+ (yyval.type) = new_tag(ASN1_C_UNIV, UT_BMPString,
+ TE_EXPLICIT, new_type(TBMPString));
+ }
+ break;
+
+ case 96:
+#line 678 "parse.y"
+ {
(yyval.type) = new_tag(ASN1_C_UNIV, UT_UniversalString,
TE_EXPLICIT, new_type(TUniversalString));
}
break;
- case 96:
-#line 681 "parse.y"
+ case 97:
+#line 686 "parse.y"
{
(yyval.members) = emalloc(sizeof(*(yyval.members)));
ASN1_TAILQ_INIT((yyval.members));
@@ -2017,16 +2025,16 @@ yyreduce:
}
break;
- case 97:
-#line 687 "parse.y"
+ case 98:
+#line 692 "parse.y"
{
ASN1_TAILQ_INSERT_TAIL((yyvsp[-2].members), (yyvsp[0].member), members);
(yyval.members) = (yyvsp[-2].members);
}
break;
- case 98:
-#line 692 "parse.y"
+ case 99:
+#line 697 "parse.y"
{
struct member *m = ecalloc(1, sizeof(*m));
m->name = estrdup("...");
@@ -2037,8 +2045,8 @@ yyreduce:
}
break;
- case 99:
-#line 703 "parse.y"
+ case 100:
+#line 708 "parse.y"
{
(yyval.member) = emalloc(sizeof(*(yyval.member)));
(yyval.member)->name = (yyvsp[-1].name);
@@ -2049,8 +2057,8 @@ yyreduce:
}
break;
- case 100:
-#line 714 "parse.y"
+ case 101:
+#line 719 "parse.y"
{
(yyval.member) = (yyvsp[0].member);
(yyval.member)->optional = 0;
@@ -2058,8 +2066,8 @@ yyreduce:
}
break;
- case 101:
-#line 720 "parse.y"
+ case 102:
+#line 725 "parse.y"
{
(yyval.member) = (yyvsp[-1].member);
(yyval.member)->optional = 1;
@@ -2067,8 +2075,8 @@ yyreduce:
}
break;
- case 102:
-#line 726 "parse.y"
+ case 103:
+#line 731 "parse.y"
{
(yyval.member) = (yyvsp[-2].member);
(yyval.member)->optional = 0;
@@ -2076,8 +2084,8 @@ yyreduce:
}
break;
- case 103:
-#line 734 "parse.y"
+ case 104:
+#line 739 "parse.y"
{
(yyval.members) = emalloc(sizeof(*(yyval.members)));
ASN1_TAILQ_INIT((yyval.members));
@@ -2085,16 +2093,16 @@ yyreduce:
}
break;
- case 104:
-#line 740 "parse.y"
+ case 105:
+#line 745 "parse.y"
{
ASN1_TAILQ_INSERT_TAIL((yyvsp[-2].members), (yyvsp[0].member), members);
(yyval.members) = (yyvsp[-2].members);
}
break;
- case 105:
-#line 747 "parse.y"
+ case 106:
+#line 752 "parse.y"
{
(yyval.member) = emalloc(sizeof(*(yyval.member)));
(yyval.member)->name = (yyvsp[-3].name);
@@ -2107,27 +2115,27 @@ yyreduce:
}
break;
- case 107:
-#line 760 "parse.y"
+ case 108:
+#line 765 "parse.y"
{ (yyval.objid) = NULL; }
break;
- case 108:
-#line 764 "parse.y"
+ case 109:
+#line 769 "parse.y"
{
(yyval.objid) = (yyvsp[-1].objid);
}
break;
- case 109:
-#line 770 "parse.y"
+ case 110:
+#line 775 "parse.y"
{
(yyval.objid) = NULL;
}
break;
- case 110:
-#line 774 "parse.y"
+ case 111:
+#line 779 "parse.y"
{
if ((yyvsp[0].objid)) {
(yyval.objid) = (yyvsp[0].objid);
@@ -2138,15 +2146,15 @@ yyreduce:
}
break;
- case 111:
-#line 785 "parse.y"
+ case 112:
+#line 790 "parse.y"
{
(yyval.objid) = new_objid((yyvsp[-3].name), (yyvsp[-1].constant));
}
break;
- case 112:
-#line 789 "parse.y"
+ case 113:
+#line 794 "parse.y"
{
Symbol *s = addsym((yyvsp[0].name));
if(s->stype != SValue ||
@@ -2159,15 +2167,15 @@ yyreduce:
}
break;
- case 113:
-#line 800 "parse.y"
+ case 114:
+#line 805 "parse.y"
{
(yyval.objid) = new_objid(NULL, (yyvsp[0].constant));
}
break;
- case 123:
-#line 823 "parse.y"
+ case 124:
+#line 828 "parse.y"
{
Symbol *s = addsym((yyvsp[0].name));
if(s->stype != SValue)
@@ -2178,8 +2186,8 @@ yyreduce:
}
break;
- case 124:
-#line 834 "parse.y"
+ case 125:
+#line 839 "parse.y"
{
(yyval.value) = emalloc(sizeof(*(yyval.value)));
(yyval.value)->type = stringvalue;
@@ -2187,8 +2195,8 @@ yyreduce:
}
break;
- case 125:
-#line 842 "parse.y"
+ case 126:
+#line 847 "parse.y"
{
(yyval.value) = emalloc(sizeof(*(yyval.value)));
(yyval.value)->type = booleanvalue;
@@ -2196,8 +2204,8 @@ yyreduce:
}
break;
- case 126:
-#line 848 "parse.y"
+ case 127:
+#line 853 "parse.y"
{
(yyval.value) = emalloc(sizeof(*(yyval.value)));
(yyval.value)->type = booleanvalue;
@@ -2205,8 +2213,8 @@ yyreduce:
}
break;
- case 127:
-#line 856 "parse.y"
+ case 128:
+#line 861 "parse.y"
{
(yyval.value) = emalloc(sizeof(*(yyval.value)));
(yyval.value)->type = integervalue;
@@ -2214,14 +2222,14 @@ yyreduce:
}
break;
- case 129:
-#line 867 "parse.y"
+ case 130:
+#line 872 "parse.y"
{
}
break;
- case 130:
-#line 872 "parse.y"
+ case 131:
+#line 877 "parse.y"
{
(yyval.value) = emalloc(sizeof(*(yyval.value)));
(yyval.value)->type = objectidentifiervalue;
@@ -2234,7 +2242,7 @@ yyreduce:
}
/* Line 1126 of yacc.c. */
-#line 2238 "parse.c"
+#line 2246 "parse.c"
yyvsp -= yylen;
yyssp -= yylen;
@@ -2502,7 +2510,7 @@ yyreturn:
}
-#line 879 "parse.y"
+#line 884 "parse.y"
void
diff --git a/source4/heimdal/lib/asn1/parse.y b/source4/heimdal/lib/asn1/parse.y
index 22384782847..029cef9f0f4 100644
--- a/source4/heimdal/lib/asn1/parse.y
+++ b/source4/heimdal/lib/asn1/parse.y
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: parse.y,v 1.27 2005/12/14 09:44:36 lha Exp $ */
+/* $Id: parse.y,v 1.29 2006/12/28 17:15:02 lha Exp $ */
%{
#ifdef HAVE_CONFIG_H
@@ -45,7 +45,7 @@
#include "gen_locl.h"
#include "der.h"
-RCSID("$Id: parse.y,v 1.27 2005/12/14 09:44:36 lha Exp $");
+RCSID("$Id: parse.y,v 1.29 2006/12/28 17:15:02 lha Exp $");
static Type *new_type (Typetype t);
static struct constraint_spec *new_constraint_spec(enum ctype);
@@ -537,8 +537,10 @@ Constraint : '(' ConstraintSpec ')'
{
$$ = $2;
}
+ ;
ConstraintSpec : GeneralConstraint
+ ;
GeneralConstraint: ContentsConstraint
| UserDefinedConstraint
@@ -657,6 +659,11 @@ RestrictedCharactedStringType: kw_GeneralString
$$ = new_tag(ASN1_C_UNIV, UT_PrintableString,
TE_EXPLICIT, new_type(TPrintableString));
}
+ | kw_VisibleString
+ {
+ $$ = new_tag(ASN1_C_UNIV, UT_VisibleString,
+ TE_EXPLICIT, new_type(TVisibleString));
+ }
| kw_IA5String
{
$$ = new_tag(ASN1_C_UNIV, UT_IA5String,
diff --git a/source4/heimdal/lib/asn1/rfc2459.asn1 b/source4/heimdal/lib/asn1/rfc2459.asn1
index eebbc3211b9..430674a5ee8 100644
--- a/source4/heimdal/lib/asn1/rfc2459.asn1
+++ b/source4/heimdal/lib/asn1/rfc2459.asn1
@@ -406,13 +406,31 @@ CRLReason ::= ENUMERATED {
aACompromise (10)
}
+id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+ dod(6) internet(1) security(5) mechanisms(5) pkix(7) }
+
+id-pkix-on OBJECT IDENTIFIER ::= { id-pkix 8 }
+id-pkix-on-dnsSRV OBJECT IDENTIFIER ::= { id-pkix-on 7 }
+
+id-pkix-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+id-pkix-kp-serverAuth OBJECT IDENTIFIER ::= { id-pkix-kp 1 }
+id-pkix-kp-clientAuth OBJECT IDENTIFIER ::= { id-pkix-kp 2 }
+id-pkix-kp-emailProtection OBJECT IDENTIFIER ::= { id-pkix-kp 4 }
+id-pkix-kp-timeStamping OBJECT IDENTIFIER ::= { id-pkix-kp 8 }
+id-pkix-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-pkix-kp 9 }
+
-- RFC 3820 Proxy Certificate Profile
-id-pkix-pe OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
- dod(6) internet(1) security(5) mechanisms(5) pkix(7) 1 }
+id-pkix-pe OBJECT IDENTIFIER ::= { id-pkix 1 }
id-pe-proxyCertInfo OBJECT IDENTIFIER ::= { id-pkix-pe 14 }
+id-pkix-ppl OBJECT IDENTIFIER ::= { id-pkix 21 }
+
+id-pkix-ppl-anyLanguage OBJECT IDENTIFIER ::= { id-pkix-ppl 0 }
+id-pkix-ppl-inheritAll OBJECT IDENTIFIER ::= { id-pkix-ppl 1 }
+id-pkix-ppl-independent OBJECT IDENTIFIER ::= { id-pkix-ppl 2 }
+
ProxyPolicy ::= SEQUENCE {
policyLanguage OBJECT IDENTIFIER,
policy OCTET STRING OPTIONAL
diff --git a/source4/heimdal/lib/asn1/symbol.h b/source4/heimdal/lib/asn1/symbol.h
index 93a6e019bd6..436bd043a18 100644
--- a/source4/heimdal/lib/asn1/symbol.h
+++ b/source4/heimdal/lib/asn1/symbol.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: symbol.h,v 1.13 2005/12/06 19:59:52 lha Exp $ */
+/* $Id: symbol.h,v 1.14 2006/12/28 17:15:05 lha Exp $ */
#ifndef _SYMBOL_H
#define _SYMBOL_H
@@ -60,7 +60,8 @@ enum typetype {
TUTCTime,
TUTF8String,
TBMPString,
- TUniversalString
+ TUniversalString,
+ TVisibleString
};
typedef enum typetype Typetype;
diff --git a/source4/heimdal/lib/com_err/lex.c b/source4/heimdal/lib/com_err/lex.c
index 30b44d0c192..8b7113baa2f 100644
--- a/source4/heimdal/lib/com_err/lex.c
+++ b/source4/heimdal/lib/com_err/lex.c
@@ -1,7 +1,8 @@
-/* A lexical scanner generated by flex */
+#include "config.h"
+/* A lexical scanner generated by flex*/
/* Scanner skeleton version:
- * $Header: /cvs/root/flex/flex/skel.c,v 1.2 2004/05/07 00:28:17 jkh Exp $
+ * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
*/
#define FLEX_SCANNER
@@ -9,6 +10,7 @@
#define YY_FLEX_MINOR_VERSION 5
#include <stdio.h>
+#include <unistd.h>
/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
@@ -22,7 +24,6 @@
#ifdef __cplusplus
#include <stdlib.h>
-#include <unistd.h>
/* Use prototypes in function declarations. */
#define YY_USE_PROTOS
@@ -134,6 +135,15 @@ extern FILE *yyin, *yyout;
#define unput(c) yyunput( c, yytext_ptr )
+/* Some routines like yy_flex_realloc() are emitted as static but are
+ not called by all lexers. This generates warnings in some compilers,
+ notably GCC. Arrange to suppress these. */
+#ifdef __GNUC__
+#define YY_MAY_BE_UNUSED __attribute__((unused))
+#else
+#define YY_MAY_BE_UNUSED
+#endif
+
/* The following is because we cannot portably get our hands on size_t
* (without autoconf's help, which isn't available because we want
* flex-generated scanners to compile on their own).
@@ -240,7 +250,7 @@ YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
-static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )) YY_MAY_BE_UNUSED;
static void yy_flex_free YY_PROTO(( void * ));
#define yy_new_buffer yy_create_buffer
@@ -385,9 +395,9 @@ static char *yy_last_accepting_cpos;
#define YY_MORE_ADJ 0
#define YY_RESTORE_YY_MORE_OFFSET
char *yytext;
-#line 1 "../../../lib/com_err/lex.l"
+#line 1 "lex.l"
#define INITIAL 0
-#line 2 "../../../lib/com_err/lex.l"
+#line 2 "lex.l"
/*
* Copyright (c) 1998 - 2000 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
@@ -442,7 +452,7 @@ static int getstring(void);
#undef ECHO
-#line 446 "lex.c"
+#line 455 "lex.yy.c"
/* Macros after this point can all be overridden by user definitions in
* section 1.
@@ -590,12 +600,12 @@ YY_MALLOC_DECL
YY_DECL
{
register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
+ register char *yy_cp = NULL, *yy_bp = NULL;
register int yy_act;
-#line 59 "../../../lib/com_err/lex.l"
+#line 59 "lex.l"
-#line 599 "lex.c"
+#line 608 "lex.yy.c"
if ( yy_init )
{
@@ -680,85 +690,85 @@ do_action: /* This label is used only to access EOF actions. */
case 1:
YY_RULE_SETUP
-#line 60 "../../../lib/com_err/lex.l"
+#line 60 "lex.l"
{ return ET; }
YY_BREAK
case 2:
YY_RULE_SETUP
-#line 61 "../../../lib/com_err/lex.l"
+#line 61 "lex.l"
{ return ET; }
YY_BREAK
case 3:
YY_RULE_SETUP
-#line 62 "../../../lib/com_err/lex.l"
+#line 62 "lex.l"
{ return EC; }
YY_BREAK
case 4:
YY_RULE_SETUP
-#line 63 "../../../lib/com_err/lex.l"
+#line 63 "lex.l"
{ return EC; }
YY_BREAK
case 5:
YY_RULE_SETUP
-#line 64 "../../../lib/com_err/lex.l"
+#line 64 "lex.l"
{ return PREFIX; }
YY_BREAK
case 6:
YY_RULE_SETUP
-#line 65 "../../../lib/com_err/lex.l"
+#line 65 "lex.l"
{ return INDEX; }
YY_BREAK
case 7:
YY_RULE_SETUP
-#line 66 "../../../lib/com_err/lex.l"
+#line 66 "lex.l"
{ return ID; }
YY_BREAK
case 8:
YY_RULE_SETUP
-#line 67 "../../../lib/com_err/lex.l"
+#line 67 "lex.l"
{ return END; }
YY_BREAK
case 9:
YY_RULE_SETUP
-#line 68 "../../../lib/com_err/lex.l"
+#line 68 "lex.l"
{ yylval.number = atoi(yytext); return NUMBER; }
YY_BREAK
case 10:
YY_RULE_SETUP
-#line 69 "../../../lib/com_err/lex.l"
+#line 69 "lex.l"
;
YY_BREAK
case 11:
YY_RULE_SETUP
-#line 70 "../../../lib/com_err/lex.l"
+#line 70 "lex.l"
;
YY_BREAK
case 12:
YY_RULE_SETUP
-#line 71 "../../../lib/com_err/lex.l"
+#line 71 "lex.l"
{ lineno++; }
YY_BREAK
case 13:
YY_RULE_SETUP
-#line 72 "../../../lib/com_err/lex.l"
+#line 72 "lex.l"
{ return getstring(); }
YY_BREAK
case 14:
YY_RULE_SETUP
-#line 73 "../../../lib/com_err/lex.l"
+#line 73 "lex.l"
{ yylval.string = strdup(yytext); return STRING; }
YY_BREAK
case 15:
YY_RULE_SETUP
-#line 74 "../../../lib/com_err/lex.l"
+#line 74 "lex.l"
{ return *yytext; }
YY_BREAK
case 16:
YY_RULE_SETUP
-#line 75 "../../../lib/com_err/lex.l"
+#line 75 "lex.l"
ECHO;
YY_BREAK
-#line 762 "lex.c"
+#line 771 "lex.yy.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
@@ -1140,6 +1150,7 @@ register char *yy_bp;
#endif /* ifndef YY_NO_UNPUT */
+#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput()
#else
@@ -1211,7 +1222,7 @@ static int input()
return c;
}
-
+#endif /* YY_NO_INPUT */
#ifdef YY_USE_PROTOS
void yyrestart( FILE *input_file )
@@ -1322,11 +1333,6 @@ YY_BUFFER_STATE b;
}
-#ifndef YY_ALWAYS_INTERACTIVE
-#ifndef YY_NEVER_INTERACTIVE
-extern int isatty YY_PROTO(( int ));
-#endif
-#endif
#ifdef YY_USE_PROTOS
void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
@@ -1644,7 +1650,7 @@ int main()
return 0;
}
#endif
-#line 75 "../../../lib/com_err/lex.l"
+#line 75 "lex.l"
#ifndef yywrap /* XXX */
diff --git a/source4/heimdal/lib/com_err/parse.c b/source4/heimdal/lib/com_err/parse.c
index a7160a4d42f..4cef0c492d7 100644
--- a/source4/heimdal/lib/com_err/parse.c
+++ b/source4/heimdal/lib/com_err/parse.c
@@ -1,19 +1,86 @@
+/* A Bison parser, made by GNU Bison 2.1. */
-/* A Bison parser, made from ../../../lib/com_err/parse.y
- by GNU Bison version 1.28 */
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
-#define YYBISON 1 /* Identify Bison output. */
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
-#define ET 257
-#define INDEX 258
-#define PREFIX 259
-#define EC 260
-#define ID 261
-#define END 262
-#define STRING 263
-#define NUMBER 264
+/* Pure parsers. */
+#define YYPURE 0
-#line 1 "../../../lib/com_err/parse.y"
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ET = 258,
+ INDEX = 259,
+ PREFIX = 260,
+ EC = 261,
+ ID = 262,
+ END = 263,
+ STRING = 264,
+ NUMBER = 265
+ };
+#endif
+/* Tokens. */
+#define ET 258
+#define INDEX 259
+#define PREFIX 260
+#define EC 261
+#define ID 262
+#define END 263
+#define STRING 264
+#define NUMBER 265
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "parse.y"
/*
* Copyright (c) 1998 - 2000 Kungliga Tekniska Högskolan
@@ -65,425 +132,834 @@ extern char *yytext;
#endif
-#line 53 "../../../lib/com_err/parse.y"
-typedef union {
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 53 "parse.y"
+typedef union YYSTYPE {
char *string;
int number;
} YYSTYPE;
-#include <stdio.h>
-
-#ifndef __cplusplus
-#ifndef __STDC__
-#define const
-#endif
+/* Line 196 of yacc.c. */
+#line 162 "$base.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
-#define YYFINAL 24
-#define YYFLAG -32768
-#define YYNTBASE 12
-
-#define YYTRANSLATE(x) ((unsigned)(x) <= 264 ? yytranslate[x] : 18)
-
-static const char yytranslate[] = { 0,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 11, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
- 7, 8, 9, 10
-};
+/* Copy the second part of user declarations. */
-#if YYDEBUG != 0
-static const short yyprhs[] = { 0,
- 0, 1, 4, 7, 9, 12, 15, 19, 21, 24,
- 27, 30, 32, 37
-};
-static const short yyrhs[] = { -1,
- 13, 16, 0, 14, 15, 0, 15, 0, 7, 9,
- 0, 3, 9, 0, 3, 9, 9, 0, 17, 0,
- 16, 17, 0, 4, 10, 0, 5, 9, 0, 5,
- 0, 6, 9, 11, 9, 0, 8, 0
-};
+/* Line 219 of yacc.c. */
+#line 174 "$base.c"
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
#endif
-#if YYDEBUG != 0
-static const short yyrline[] = { 0,
- 64, 65, 68, 69, 72, 78, 84, 93, 94, 97,
- 101, 109, 116, 136
-};
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
#endif
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYINCLUDED_STDLIB_H
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifdef __cplusplus
+}
+# endif
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
-#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
-static const char * const yytname[] = { "$","error","$undefined.","ET","INDEX",
-"PREFIX","EC","ID","END","STRING","NUMBER","','","file","header","id","et","statements",
-"statement", NULL
-};
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short int yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
#endif
-static const short yyr1[] = { 0,
- 12, 12, 13, 13, 14, 15, 15, 16, 16, 17,
- 17, 17, 17, 17
-};
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
-static const short yyr2[] = { 0,
- 0, 2, 2, 1, 2, 2, 3, 1, 2, 2,
- 2, 1, 4, 1
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 9
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 23
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 12
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 7
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 15
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 24
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 265
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 11, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10
};
-static const short yydefact[] = { 1,
- 0, 0, 0, 0, 4, 6, 5, 0, 12, 0,
- 14, 2, 8, 3, 7, 10, 11, 0, 9, 0,
- 13, 0, 0, 0
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 10, 12, 15, 18, 22,
+ 24, 27, 30, 33, 35, 40
};
-static const short yydefgoto[] = { 22,
- 3, 4, 5, 12, 13
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 13, 0, -1, -1, 14, 17, -1, 15, 16, -1,
+ 16, -1, 7, 9, -1, 3, 9, -1, 3, 9,
+ 9, -1, 18, -1, 17, 18, -1, 4, 10, -1,
+ 5, 9, -1, 5, -1, 6, 9, 11, 9, -1,
+ 8, -1
};
-static const short yypact[] = { 0,
- -3, -1, -4, 2,-32768, 1,-32768, 3, 5, 6,
--32768, -4,-32768,-32768,-32768,-32768,-32768, -2,-32768, 7,
--32768, 11, 12,-32768
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned char yyrline[] =
+{
+ 0, 64, 64, 65, 68, 69, 72, 78, 84, 93,
+ 94, 97, 101, 109, 116, 136
};
+#endif
-static const short yypgoto[] = {-32768,
--32768,-32768, 13,-32768, 8
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "ET", "INDEX", "PREFIX", "EC", "ID",
+ "END", "STRING", "NUMBER", "','", "$accept", "file", "header", "id",
+ "et", "statements", "statement", 0
};
+#endif
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 44
+};
+# endif
-#define YYLAST 20
-
-
-static const short yytable[] = { 8,
- 9, 10, 1, 11, 1, 6, 2, 7, 20, 15,
- 23, 24, 16, 17, 18, 21, 14, 0, 0, 19
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 12, 13, 13, 14, 14, 15, 16, 16, 17,
+ 17, 18, 18, 18, 18, 18
};
-static const short yycheck[] = { 4,
- 5, 6, 3, 8, 3, 9, 7, 9, 11, 9,
- 0, 0, 10, 9, 9, 9, 4, -1, -1, 12
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 0, 2, 2, 1, 2, 2, 3, 1,
+ 2, 2, 2, 1, 4, 1
};
-/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
-#line 3 "/usr/share/bison.simple"
-/* This file comes from bison-1.28. */
-/* Skeleton output parser for bison,
- Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 2, 0, 0, 0, 0, 0, 5, 7, 6, 1,
+ 0, 13, 0, 15, 3, 9, 4, 8, 11, 12,
+ 0, 10, 0, 14
+};
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 3, 4, 5, 6, 14, 15
+};
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -5
+static const yysigned_char yypact[] =
+{
+ 0, -3, -1, 5, -4, 6, -5, 1, -5, -5,
+ 2, 4, 7, -5, -4, -5, -5, -5, -5, -5,
+ 3, -5, 8, -5
+};
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -5, -5, -5, -5, 10, -5, 9
+};
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 10, 11, 12, 1, 13, 9, 7, 2, 8, 1,
+ 17, 0, 18, 19, 22, 16, 20, 23, 0, 0,
+ 0, 0, 0, 21
+};
-/* This is the parser code that is written into each bison parser
- when the %semantic_parser declaration is not specified in the grammar.
- It was written by Richard Stallman by simplifying the hairy parser
- used when %semantic_parser is specified. */
-
-#ifndef YYSTACK_USE_ALLOCA
-#ifdef alloca
-#define YYSTACK_USE_ALLOCA
-#else /* alloca not defined */
-#ifdef __GNUC__
-#define YYSTACK_USE_ALLOCA
-#define alloca __builtin_alloca
-#else /* not GNU C. */
-#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
-#define YYSTACK_USE_ALLOCA
-#include <alloca.h>
-#else /* not sparc */
-/* We think this test detects Watcom and Microsoft C. */
-/* This used to test MSDOS, but that is a bad idea
- since that symbol is in the user namespace. */
-#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
-#if 0 /* No need for malloc.h, which pollutes the namespace;
- instead, just don't use alloca. */
-#include <malloc.h>
-#endif
-#else /* not MSDOS, or __TURBOC__ */
-#if defined(_AIX)
-/* I don't know what this was needed for, but it pollutes the namespace.
- So I turned it off. rms, 2 May 1997. */
-/* #include <malloc.h> */
- #pragma alloca
-#define YYSTACK_USE_ALLOCA
-#else /* not MSDOS, or __TURBOC__, or _AIX */
-#if 0
-#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
- and on HPUX 10. Eventually we can turn this on. */
-#define YYSTACK_USE_ALLOCA
-#define alloca __builtin_alloca
-#endif /* __hpux */
-#endif
-#endif /* not _AIX */
-#endif /* not MSDOS, or __TURBOC__ */
-#endif /* not sparc */
-#endif /* not GNU C */
-#endif /* alloca not defined */
-#endif /* YYSTACK_USE_ALLOCA not defined */
-
-#ifdef YYSTACK_USE_ALLOCA
-#define YYSTACK_ALLOC alloca
-#else
-#define YYSTACK_ALLOC malloc
-#endif
+static const yysigned_char yycheck[] =
+{
+ 4, 5, 6, 3, 8, 0, 9, 7, 9, 3,
+ 9, -1, 10, 9, 11, 5, 9, 9, -1, -1,
+ -1, -1, -1, 14
+};
-/* Note: there must be only one dollar sign in this file.
- It is replaced by the list of actions, each action
- as one case of the switch. */
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 7, 13, 14, 15, 16, 9, 9, 0,
+ 4, 5, 6, 8, 17, 18, 16, 9, 10, 9,
+ 9, 18, 11, 9
+};
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY -2
+#define YYEMPTY (-2)
#define YYEOF 0
+
#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrlab1
-/* Like YYERROR except do call yyerror.
- This remains here temporarily to ease the
- transition to the new meaning of YYERROR, for GCC.
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
Once GCC version 2 has supplanted version 1, this can go. */
+
#define YYFAIL goto yyerrlab
+
#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(token, value) \
+
+#define YYBACKUP(Token, Value) \
do \
if (yychar == YYEMPTY && yylen == 1) \
- { yychar = (token), yylval = (value); \
- yychar1 = YYTRANSLATE (yychar); \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
YYPOPSTACK; \
goto yybackup; \
} \
else \
- { yyerror ("syntax error: cannot back up"); YYERROR; } \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
while (0)
+
#define YYTERROR 1
#define YYERRCODE 256
-#ifndef YYPURE
-#define YYLEX yylex()
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
#endif
-#ifdef YYPURE
-#ifdef YYLSP_NEEDED
-#ifdef YYLEX_PARAM
-#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
-#else
-#define YYLEX yylex(&yylval, &yylloc)
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
#endif
-#else /* not YYLSP_NEEDED */
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
#ifdef YYLEX_PARAM
-#define YYLEX yylex(&yylval, YYLEX_PARAM)
+# define YYLEX yylex (YYLEX_PARAM)
#else
-#define YYLEX yylex(&yylval)
+# define YYLEX yylex ()
#endif
-#endif /* not YYLSP_NEEDED */
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
-/* If nonreentrant, generate the variables here */
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
-#ifndef YYPURE
-int yychar; /* the lookahead symbol */
-YYSTYPE yylval; /* the semantic value of the */
- /* lookahead symbol */
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
-#ifdef YYLSP_NEEDED
-YYLTYPE yylloc; /* location data for the lookahead */
- /* symbol */
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
#endif
+{
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
+}
-int yynerrs; /* number of parse errors so far */
-#endif /* not YYPURE */
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
-#if YYDEBUG != 0
-int yydebug; /* nonzero means print parse trace */
-/* Since this is uninitialized, it does not stop multiple parsers
- from coexisting. */
-#endif
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
-/* YYINITDEPTH indicates the initial size of the parser's stacks */
+/* YYINITDEPTH -- initial size of the parser's stacks. */
#ifndef YYINITDEPTH
-#define YYINITDEPTH 200
+# define YYINITDEPTH 200
#endif
-/* YYMAXDEPTH is the maximum size the stacks can grow to
- (effective only if the built-in stack extension method is used). */
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
-#if YYMAXDEPTH == 0
-#undef YYMAXDEPTH
-#endif
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
#ifndef YYMAXDEPTH
-#define YYMAXDEPTH 10000
+# define YYMAXDEPTH 10000
#endif
+
-/* Define __yy_memcpy. Note that the size argument
- should be passed with type unsigned int, because that is what the non-GCC
- definitions require. With GCC, __builtin_memcpy takes an arg
- of type size_t, but it can handle unsigned int. */
-
-#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
-#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
-#else /* not GNU C or C++ */
-#ifndef __cplusplus
-
-/* This is the most reliable way to avoid incompatibilities
- in available built-in functions on various systems. */
-static void
-__yy_memcpy (to, from, count)
- char *to;
- char *from;
- unsigned int count;
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
{
- register char *f = from;
- register char *t = to;
- register int i = count;
+ const char *yys = yystr;
- while (i-- > 0)
- *t++ = *f++;
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
-#else /* __cplusplus */
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
-/* This is the most reliable way to avoid incompatibilities
- in available built-in functions on various systems. */
-static void
-__yy_memcpy (char *to, char *from, unsigned int count)
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
{
- register char *t = to;
- register char *f = from;
- register int i = count;
+ if (*yystr == '"')
+ {
+ size_t yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
- while (i-- > 0)
- *t++ = *f++;
+ return yystpcpy (yyres, yystr) - yyres;
}
+# endif
+
+#endif /* YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
-#line 217 "/usr/share/bison.simple"
-/* The user can define YYPARSE_PARAM as the name of an argument to be passed
- into yyparse. The argument should have type void *.
- It should actually point to an object.
- Grammar actions can access the variable by casting it
- to the proper pointer type. */
+/* Prevent warnings from -Wmissing-prototypes. */
#ifdef YYPARSE_PARAM
-#ifdef __cplusplus
-#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
-#define YYPARSE_PARAM_DECL
-#else /* not __cplusplus */
-#define YYPARSE_PARAM_ARG YYPARSE_PARAM
-#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
-#endif /* not __cplusplus */
-#else /* not YYPARSE_PARAM */
-#define YYPARSE_PARAM_ARG
-#define YYPARSE_PARAM_DECL
-#endif /* not YYPARSE_PARAM */
-
-/* Prevent warning if -Wstrict-prototypes. */
-#ifdef __GNUC__
-#ifdef YYPARSE_PARAM
-int yyparse (void *);
-#else
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
int yyparse (void);
+#else
+int yyparse ();
#endif
-#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
int
-yyparse(YYPARSE_PARAM_ARG)
- YYPARSE_PARAM_DECL
+yyparse ()
+
+#endif
+#endif
{
- register int yystate;
- register int yyn;
- register short *yyssp;
- register YYSTYPE *yyvsp;
- int yyerrstatus; /* number of tokens to shift before error messages enabled */
- int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
- short yyssa[YYINITDEPTH]; /* the state stack */
- YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
- short *yyss = yyssa; /* refer to the stacks thru separate pointers */
- YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
-#ifdef YYLSP_NEEDED
- YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
- YYLTYPE *yyls = yylsa;
- YYLTYPE *yylsp;
-#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
-#else
#define YYPOPSTACK (yyvsp--, yyssp--)
-#endif
- int yystacksize = YYINITDEPTH;
- int yyfree_stacks = 0;
+ YYSIZE_T yystacksize = YYINITDEPTH;
-#ifdef YYPURE
- int yychar;
- YYSTYPE yylval;
- int yynerrs;
-#ifdef YYLSP_NEEDED
- YYLTYPE yylloc;
-#endif
-#endif
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
- YYSTYPE yyval; /* the variable used to return */
- /* semantic values from the action */
- /* routines */
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
int yylen;
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Starting parse\n");
-#endif
+ YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
@@ -495,295 +971,251 @@ yyparse(YYPARSE_PARAM_ARG)
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
- yyssp = yyss - 1;
+ yyssp = yyss;
yyvsp = yyvs;
-#ifdef YYLSP_NEEDED
- yylsp = yyls;
-#endif
-/* Push a new state, which is found in yystate . */
-/* In all cases, when you get here, the value and location stacks
- have just been pushed. so pushing a state here evens the stacks. */
-yynewstate:
+ goto yysetstate;
- *++yyssp = yystate;
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
- if (yyssp >= yyss + yystacksize - 1)
- {
- /* Give user a chance to reallocate the stack */
- /* Use copies of these so that the &'s don't force the real ones into memory. */
- YYSTYPE *yyvs1 = yyvs;
- short *yyss1 = yyss;
-#ifdef YYLSP_NEEDED
- YYLTYPE *yyls1 = yyls;
-#endif
+ yysetstate:
+ *yyssp = yystate;
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
/* Get the current used size of the three stacks, in elements. */
- int size = yyssp - yyss + 1;
+ YYSIZE_T yysize = yyssp - yyss + 1;
#ifdef yyoverflow
- /* Each stack pointer address is followed by the size of
- the data in use in that stack, in bytes. */
-#ifdef YYLSP_NEEDED
- /* This used to be a conditional around just the two extra args,
- but that might be undefined if yyoverflow is a macro. */
- yyoverflow("parser stack overflow",
- &yyss1, size * sizeof (*yyssp),
- &yyvs1, size * sizeof (*yyvsp),
- &yyls1, size * sizeof (*yylsp),
- &yystacksize);
-#else
- yyoverflow("parser stack overflow",
- &yyss1, size * sizeof (*yyssp),
- &yyvs1, size * sizeof (*yyvsp),
- &yystacksize);
-#endif
-
- yyss = yyss1; yyvs = yyvs1;
-#ifdef YYLSP_NEEDED
- yyls = yyls1;
-#endif
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short int *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
/* Extend the stack our own way. */
- if (yystacksize >= YYMAXDEPTH)
- {
- yyerror("parser stack overflow");
- if (yyfree_stacks)
- {
- free (yyss);
- free (yyvs);
-#ifdef YYLSP_NEEDED
- free (yyls);
-#endif
- }
- return 2;
- }
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
yystacksize *= 2;
- if (yystacksize > YYMAXDEPTH)
+ if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
-#ifndef YYSTACK_USE_ALLOCA
- yyfree_stacks = 1;
-#endif
- yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
- __yy_memcpy ((char *)yyss, (char *)yyss1,
- size * (unsigned int) sizeof (*yyssp));
- yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
- __yy_memcpy ((char *)yyvs, (char *)yyvs1,
- size * (unsigned int) sizeof (*yyvsp));
-#ifdef YYLSP_NEEDED
- yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
- __yy_memcpy ((char *)yyls, (char *)yyls1,
- size * (unsigned int) sizeof (*yylsp));
-#endif
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
#endif /* no yyoverflow */
- yyssp = yyss + size - 1;
- yyvsp = yyvs + size - 1;
-#ifdef YYLSP_NEEDED
- yylsp = yyls + size - 1;
-#endif
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Stack size increased to %d\n", yystacksize);
-#endif
- if (yyssp >= yyss + yystacksize - 1)
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
YYABORT;
}
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Entering state %d\n", yystate);
-#endif
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
goto yybackup;
- yybackup:
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
/* Do appropriate processing given the current state. */
-/* Read a lookahead token if we need one and don't already have one. */
+/* Read a look-ahead token if we need one and don't already have one. */
/* yyresume: */
- /* First try to decide what to do without reference to lookahead token. */
+ /* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
- if (yyn == YYFLAG)
+ if (yyn == YYPACT_NINF)
goto yydefault;
- /* Not known => get a lookahead token if don't already have one. */
-
- /* yychar is either YYEMPTY or YYEOF
- or a valid token in external form. */
+ /* Not known => get a look-ahead token if don't already have one. */
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Reading a token: ");
-#endif
+ YYDPRINTF ((stderr, "Reading a token: "));
yychar = YYLEX;
}
- /* Convert token to internal form (in yychar1) for indexing tables with */
-
- if (yychar <= 0) /* This means end of input. */
+ if (yychar <= YYEOF)
{
- yychar1 = 0;
- yychar = YYEOF; /* Don't call YYLEX any more */
-
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Now at end of input.\n");
-#endif
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
}
else
{
- yychar1 = YYTRANSLATE(yychar);
-
-#if YYDEBUG != 0
- if (yydebug)
- {
- fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
- /* Give the individual parser a way to print the precise meaning
- of a token, for further debugging info. */
-#ifdef YYPRINT
- YYPRINT (stderr, yychar, yylval);
-#endif
- fprintf (stderr, ")\n");
- }
-#endif
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
}
- yyn += yychar1;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
goto yydefault;
-
yyn = yytable[yyn];
-
- /* yyn is what to do for this token type in this state.
- Negative => reduce, -yyn is rule number.
- Positive => shift, yyn is new state.
- New state is final state => don't bother to shift,
- just return success.
- 0, or most negative number => error. */
-
- if (yyn < 0)
+ if (yyn <= 0)
{
- if (yyn == YYFLAG)
+ if (yyn == 0 || yyn == YYTABLE_NINF)
goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
- else if (yyn == 0)
- goto yyerrlab;
if (yyn == YYFINAL)
YYACCEPT;
- /* Shift the lookahead token. */
-
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
-#endif
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
/* Discard the token being shifted unless it is eof. */
if (yychar != YYEOF)
yychar = YYEMPTY;
*++yyvsp = yylval;
-#ifdef YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
- /* count tokens shifted since error; after three, turn off error status. */
- if (yyerrstatus) yyerrstatus--;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
yystate = yyn;
goto yynewstate;
-/* Do the default action for the current state. */
-yydefault:
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
yyn = yydefact[yystate];
if (yyn == 0)
goto yyerrlab;
+ goto yyreduce;
+
-/* Do a reduction. yyn is the number of a rule to reduce with. */
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
yyreduce:
+ /* yyn is the number of a rule to reduce with. */
yylen = yyr2[yyn];
- if (yylen > 0)
- yyval = yyvsp[1-yylen]; /* implement default value of the action */
-#if YYDEBUG != 0
- if (yydebug)
- {
- int i;
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
- fprintf (stderr, "Reducing via rule %d (line %d), ",
- yyn, yyrline[yyn]);
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
- /* Print the symbols being reduced, and their result. */
- for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
- fprintf (stderr, "%s ", yytname[yyrhs[i]]);
- fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
- }
-#endif
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 6:
+#line 73 "parse.y"
+ {
+ id_str = (yyvsp[0].string);
+ }
+ break;
- switch (yyn) {
+ case 7:
+#line 79 "parse.y"
+ {
+ base_id = name2number((yyvsp[0].string));
+ strlcpy(name, (yyvsp[0].string), sizeof(name));
+ free((yyvsp[0].string));
+ }
+ break;
-case 5:
-#line 73 "../../../lib/com_err/parse.y"
-{
- id_str = yyvsp[0].string;
- ;
- break;}
-case 6:
-#line 79 "../../../lib/com_err/parse.y"
-{
- base_id = name2number(yyvsp[0].string);
- strlcpy(name, yyvsp[0].string, sizeof(name));
- free(yyvsp[0].string);
- ;
- break;}
-case 7:
-#line 85 "../../../lib/com_err/parse.y"
-{
- base_id = name2number(yyvsp[-1].string);
- strlcpy(name, yyvsp[0].string, sizeof(name));
- free(yyvsp[-1].string);
- free(yyvsp[0].string);
- ;
- break;}
-case 10:
-#line 98 "../../../lib/com_err/parse.y"
-{
- number = yyvsp[0].number;
- ;
- break;}
-case 11:
-#line 102 "../../../lib/com_err/parse.y"
-{
+ case 8:
+#line 85 "parse.y"
+ {
+ base_id = name2number((yyvsp[-1].string));
+ strlcpy(name, (yyvsp[0].string), sizeof(name));
+ free((yyvsp[-1].string));
+ free((yyvsp[0].string));
+ }
+ break;
+
+ case 11:
+#line 98 "parse.y"
+ {
+ number = (yyvsp[0].number);
+ }
+ break;
+
+ case 12:
+#line 102 "parse.y"
+ {
free(prefix);
- asprintf (&prefix, "%s_", yyvsp[0].string);
+ asprintf (&prefix, "%s_", (yyvsp[0].string));
if (prefix == NULL)
errx(1, "malloc");
- free(yyvsp[0].string);
- ;
- break;}
-case 12:
-#line 110 "../../../lib/com_err/parse.y"
-{
+ free((yyvsp[0].string));
+ }
+ break;
+
+ case 13:
+#line 110 "parse.y"
+ {
prefix = realloc(prefix, 1);
if (prefix == NULL)
errx(1, "malloc");
*prefix = '\0';
- ;
- break;}
-case 13:
-#line 117 "../../../lib/com_err/parse.y"
-{
+ }
+ break;
+
+ case 14:
+#line 117 "parse.y"
+ {
struct error_code *ec = malloc(sizeof(*ec));
if (ec == NULL)
@@ -792,246 +1224,299 @@ case 13:
ec->next = NULL;
ec->number = number;
if(prefix && *prefix != '\0') {
- asprintf (&ec->name, "%s%s", prefix, yyvsp[-2].string);
+ asprintf (&ec->name, "%s%s", prefix, (yyvsp[-2].string));
if (ec->name == NULL)
errx(1, "malloc");
- free(yyvsp[-2].string);
+ free((yyvsp[-2].string));
} else
- ec->name = yyvsp[-2].string;
- ec->string = yyvsp[0].string;
+ ec->name = (yyvsp[-2].string);
+ ec->string = (yyvsp[0].string);
APPEND(codes, ec);
number++;
- ;
- break;}
-case 14:
-#line 137 "../../../lib/com_err/parse.y"
-{
+ }
+ break;
+
+ case 15:
+#line 137 "parse.y"
+ {
YYACCEPT;
- ;
- break;}
-}
- /* the action file gets copied in in place of this dollarsign */
-#line 543 "/usr/share/bison.simple"
+ }
+ break;
+
+
+ default: break;
+ }
+
+/* Line 1126 of yacc.c. */
+#line 1252 "$base.c"
yyvsp -= yylen;
yyssp -= yylen;
-#ifdef YYLSP_NEEDED
- yylsp -= yylen;
-#endif
-#if YYDEBUG != 0
- if (yydebug)
- {
- short *ssp1 = yyss - 1;
- fprintf (stderr, "state stack now");
- while (ssp1 != yyssp)
- fprintf (stderr, " %d", *++ssp1);
- fprintf (stderr, "\n");
- }
-#endif
+
+ YY_STACK_PRINT (yyss, yyssp);
*++yyvsp = yyval;
-#ifdef YYLSP_NEEDED
- yylsp++;
- if (yylen == 0)
- {
- yylsp->first_line = yylloc.first_line;
- yylsp->first_column = yylloc.first_column;
- yylsp->last_line = (yylsp-1)->last_line;
- yylsp->last_column = (yylsp-1)->last_column;
- yylsp->text = 0;
- }
- else
- {
- yylsp->last_line = (yylsp+yylen-1)->last_line;
- yylsp->last_column = (yylsp+yylen-1)->last_column;
- }
-#endif
- /* Now "shift" the result of the reduction.
- Determine what state that goes to,
- based on the state we popped back to
- and the rule number reduced by. */
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
yyn = yyr1[yyn];
- yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
- if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
yystate = yytable[yystate];
else
- yystate = yydefgoto[yyn - YYNTBASE];
+ yystate = yydefgoto[yyn - YYNTOKENS];
goto yynewstate;
-yyerrlab: /* here on detecting error */
- if (! yyerrstatus)
- /* If not already recovering from an error, report this error. */
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
{
++yynerrs;
-
-#ifdef YYERROR_VERBOSE
+#if YYERROR_VERBOSE
yyn = yypact[yystate];
- if (yyn > YYFLAG && yyn < YYLAST)
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
{
- int size = 0;
- char *msg;
- int x, count;
-
- count = 0;
- /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
- for (x = (yyn < 0 ? -yyn : 0);
- x < (sizeof(yytname) / sizeof(char *)); x++)
- if (yycheck[x + yyn] == x)
- size += strlen(yytname[x]) + 15, count++;
- msg = (char *) malloc(size + 15);
- if (msg != 0)
- {
- strcpy(msg, "parse error");
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ char *yymsg = 0;
+# define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
- if (count < 5)
+#if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+
+ if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyf))
{
- count = 0;
- for (x = (yyn < 0 ? -yyn : 0);
- x < (sizeof(yytname) / sizeof(char *)); x++)
- if (yycheck[x + yyn] == x)
- {
- strcat(msg, count == 0 ? ", expecting `" : " or `");
- strcat(msg, yytname[x]);
- strcat(msg, "'");
- count++;
- }
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
}
- yyerror(msg);
- free(msg);
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
}
else
- yyerror ("parse error; also virtual memory exceeded");
+ {
+ yyerror (YY_("syntax error"));
+ goto yyexhaustedlab;
+ }
}
else
#endif /* YYERROR_VERBOSE */
- yyerror("parse error");
+ yyerror (YY_("syntax error"));
}
- goto yyerrlab1;
-yyerrlab1: /* here on error raised explicitly by an action */
+
if (yyerrstatus == 3)
{
- /* if just tried and failed to reuse lookahead token after an error, discard it. */
-
- /* return failure if at end of input */
- if (yychar == YYEOF)
- YYABORT;
-
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
-#endif
-
- yychar = YYEMPTY;
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding", yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
}
- /* Else will try to reuse lookahead token
- after shifting the error token. */
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
- yyerrstatus = 3; /* Each real token shifted decrements this */
- goto yyerrhandle;
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
-yyerrdefault: /* current state does not do anything special for the error token. */
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (0)
+ goto yyerrorlab;
-#if 0
- /* This is wrong; only states that explicitly want error tokens
- should shift them. */
- yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
- if (yyn) goto yydefault;
-#endif
+yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
-yyerrpop: /* pop the current state because it cannot handle the error token */
- if (yyssp == yyss) YYABORT;
- yyvsp--;
- yystate = *--yyssp;
-#ifdef YYLSP_NEEDED
- yylsp--;
-#endif
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
-#if YYDEBUG != 0
- if (yydebug)
+ for (;;)
{
- short *ssp1 = yyss - 1;
- fprintf (stderr, "Error: state stack now");
- while (ssp1 != yyssp)
- fprintf (stderr, " %d", *++ssp1);
- fprintf (stderr, "\n");
- }
-#endif
-
-yyerrhandle:
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
- yyn = yypact[yystate];
- if (yyn == YYFLAG)
- goto yyerrdefault;
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
- yyn += YYTERROR;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
- goto yyerrdefault;
- yyn = yytable[yyn];
- if (yyn < 0)
- {
- if (yyn == YYFLAG)
- goto yyerrpop;
- yyn = -yyn;
- goto yyreduce;
+ yydestruct ("Error: popping", yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
}
- else if (yyn == 0)
- goto yyerrpop;
if (yyn == YYFINAL)
YYACCEPT;
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Shifting error token, ");
-#endif
-
*++yyvsp = yylval;
-#ifdef YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
yystate = yyn;
goto yynewstate;
- yyacceptlab:
- /* YYACCEPT comes here. */
- if (yyfree_stacks)
- {
- free (yyss);
- free (yyvs);
-#ifdef YYLSP_NEEDED
- free (yyls);
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
#endif
- }
- return 0;
- yyabortlab:
- /* YYABORT comes here. */
- if (yyfree_stacks)
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ while (yyssp != yyss)
{
- free (yyss);
- free (yyvs);
-#ifdef YYLSP_NEEDED
- free (yyls);
-#endif
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
}
- return 1;
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
}
-#line 142 "../../../lib/com_err/parse.y"
+
+
+#line 142 "parse.y"
static long
@@ -1064,3 +1549,4 @@ yyerror (char *s)
{
error_message ("%s\n", s);
}
+
diff --git a/source4/heimdal/lib/com_err/parse.h b/source4/heimdal/lib/com_err/parse.h
index 07e33790d32..2f9755e19b1 100644
--- a/source4/heimdal/lib/com_err/parse.h
+++ b/source4/heimdal/lib/com_err/parse.h
@@ -1,15 +1,71 @@
-typedef union {
+/* A Bison parser, made by GNU Bison 2.1. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ET = 258,
+ INDEX = 259,
+ PREFIX = 260,
+ EC = 261,
+ ID = 262,
+ END = 263,
+ STRING = 264,
+ NUMBER = 265
+ };
+#endif
+/* Tokens. */
+#define ET 258
+#define INDEX 259
+#define PREFIX 260
+#define EC 261
+#define ID 262
+#define END 263
+#define STRING 264
+#define NUMBER 265
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 53 "parse.y"
+typedef union YYSTYPE {
char *string;
int number;
} YYSTYPE;
-#define ET 257
-#define INDEX 258
-#define PREFIX 259
-#define EC 260
-#define ID 261
-#define END 262
-#define STRING 263
-#define NUMBER 264
-
+/* Line 1447 of yacc.c. */
+#line 63 "parse.h"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
extern YYSTYPE yylval;
+
+
+
diff --git a/source4/heimdal/lib/des/bn.c b/source4/heimdal/lib/des/bn.c
new file mode 100644
index 00000000000..c4230b6abcd
--- /dev/null
+++ b/source4/heimdal/lib/des/bn.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id: bn.c,v 1.9 2006/10/14 09:21:09 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <krb5-types.h>
+#include <rfc2459_asn1.h> /* XXX */
+#include <der.h>
+
+#include <bn.h>
+#include <rand.h>
+#include <hex.h>
+
+BIGNUM *
+BN_new(void)
+{
+ heim_integer *hi;
+ hi = calloc(1, sizeof(*hi));
+ return (BIGNUM *)hi;
+}
+
+void
+BN_free(BIGNUM *bn)
+{
+ BN_clear(bn);
+ free(bn);
+}
+
+void
+BN_clear(BIGNUM *bn)
+{
+ heim_integer *hi = (heim_integer *)bn;
+ if (hi->data) {
+ memset(hi->data, 0, hi->length);
+ free(hi->data);
+ }
+ memset(hi, 0, sizeof(*hi));
+}
+
+void
+BN_clear_free(BIGNUM *bn)
+{
+ BN_free(bn);
+}
+
+BIGNUM *
+BN_dup(const BIGNUM *bn)
+{
+ BIGNUM *b = BN_new();
+ if (der_copy_heim_integer((const heim_integer *)bn, (heim_integer *)b)) {
+ BN_free(b);
+ return NULL;
+ }
+ return b;
+}
+
+/*
+ * If the caller really want to know the number of bits used, subtract
+ * one from the length, multiply by 8, and then lookup in the table
+ * how many bits the hightest byte uses.
+ */
+int
+BN_num_bits(const BIGNUM *bn)
+{
+ static unsigned char num2bits[256] = {
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ };
+ const heim_integer *i = (const void *)bn;
+ if (i->length == 0)
+ return 0;
+ return (i->length - 1) * 8 + num2bits[((unsigned char *)i->data)[0]];
+}
+
+int
+BN_num_bytes(const BIGNUM *bn)
+{
+ return ((const heim_integer *)bn)->length;
+}
+
+/*
+ * Ignore negative flag.
+ */
+
+BIGNUM *
+BN_bin2bn(const void *s, int len, BIGNUM *bn)
+{
+ heim_integer *hi = (void *)bn;
+
+ if (len < 0)
+ return NULL;
+
+ if (hi == NULL) {
+ hi = (heim_integer *)BN_new();
+ if (hi == NULL)
+ return NULL;
+ }
+ if (hi->data)
+ BN_clear((BIGNUM *)hi);
+ hi->negative = 0;
+ hi->data = malloc(len);
+ if (hi->data == NULL && len != 0) {
+ if (bn == NULL)
+ BN_free((BIGNUM *)hi);
+ return NULL;
+ }
+ hi->length = len;
+ memcpy(hi->data, s, len);
+ return (BIGNUM *)hi;
+}
+
+int
+BN_bn2bin(const BIGNUM *bn, void *to)
+{
+ const heim_integer *hi = (const void *)bn;
+ memcpy(to, hi->data, hi->length);
+ return hi->length;
+}
+
+int
+BN_hex2bn(BIGNUM **bnp, const char *in)
+{
+ int negative;
+ ssize_t ret;
+ size_t len;
+ void *data;
+
+ len = strlen(in);
+ data = malloc(len);
+ if (data == NULL)
+ return 0;
+
+ if (*in == '-') {
+ negative = 1;
+ in++;
+ } else
+ negative = 0;
+
+ ret = hex_decode(in, data, len);
+ if (ret < 0) {
+ free(data);
+ return 0;
+ }
+
+ *bnp = BN_bin2bn(data, ret, NULL);
+ free(data);
+ if (*bnp == NULL)
+ return 0;
+ BN_set_negative(*bnp, negative);
+ return 1;
+}
+
+char *
+BN_bn2hex(const BIGNUM *bn)
+{
+ ssize_t ret;
+ size_t len;
+ void *data;
+ char *str;
+
+ len = BN_num_bytes(bn);
+ data = malloc(len);
+ if (data == NULL)
+ return 0;
+
+ len = BN_bn2bin(bn, data);
+
+ ret = hex_encode(data, len, &str);
+ free(data);
+ if (ret < 0)
+ return 0;
+
+ return str;
+}
+
+int
+BN_cmp(const BIGNUM *bn1, const BIGNUM *bn2)
+{
+ return der_heim_integer_cmp((const heim_integer *)bn1,
+ (const heim_integer *)bn2);
+}
+
+void
+BN_set_negative(BIGNUM *bn, int flag)
+{
+ ((heim_integer *)bn)->negative = (flag ? 1 : 0);
+}
+
+int
+BN_is_negative(BIGNUM *bn)
+{
+ return ((heim_integer *)bn)->negative ? 1 : 0;
+}
+
+static const unsigned char is_set[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+int
+BN_is_bit_set(const BIGNUM *bn, int bit)
+{
+ heim_integer *hi = (heim_integer *)bn;
+ unsigned char *p = hi->data;
+
+ if ((bit / 8) > hi->length || hi->length == 0)
+ return 0;
+
+ return p[hi->length - 1 - (bit / 8)] & is_set[bit % 8];
+}
+
+int
+BN_set_bit(BIGNUM *bn, int bit)
+{
+ heim_integer *hi = (heim_integer *)bn;
+ unsigned char *p;
+
+ if ((bit / 8) > hi->length || hi->length == 0) {
+ size_t len = (bit + 7) / 8;
+ void *d = realloc(hi->data, len);
+ if (d == NULL)
+ return 0;
+ hi->data = d;
+ p = hi->data;
+ memset(&p[hi->length], 0, len);
+ hi->length = len;
+ } else
+ p = hi->data;
+
+ p[hi->length - 1 - (bit / 8)] |= is_set[bit % 8];
+ return 1;
+}
+
+int
+BN_clear_bit(BIGNUM *bn, int bit)
+{
+ heim_integer *hi = (heim_integer *)bn;
+ unsigned char *p = hi->data;
+
+ if ((bit / 8) > hi->length || hi->length == 0)
+ return 0;
+
+ p[hi->length - 1 - (bit / 8)] &= (unsigned char)(~(is_set[bit % 8]));
+
+ return 1;
+}
+
+int
+BN_set_word(BIGNUM *bn, unsigned long num)
+{
+ unsigned char p[sizeof(num)];
+ unsigned long num2;
+ int i, len;
+
+ for (num2 = num, i = 0; num2 > 0; i++)
+ num2 = num2 >> 8;
+
+ len = i - 1;
+ for (; i > 0; i--) {
+ p[i - 1] = (num & 0xff);
+ num = num >> 8;
+ }
+
+ bn = BN_bin2bn(p, len + 1, bn);
+ return bn != NULL;
+}
+
+unsigned long
+BN_get_word(const BIGNUM *bn)
+{
+ heim_integer *hi = (heim_integer *)bn;
+ unsigned long num = 0;
+ int i;
+
+ if (hi->negative || hi->length > sizeof(num))
+ return ULONG_MAX;
+
+ for (i = 0; i < hi->length; i++)
+ num = ((unsigned char *)hi->data)[i] | (num << 8);
+ return num;
+}
+
+int
+BN_rand(BIGNUM *bn, int bits, int top, int bottom)
+{
+ size_t len = (bits + 7) / 8;
+ heim_integer *i = (heim_integer *)bn;
+
+ BN_clear(bn);
+
+ i->negative = 0;
+ i->data = malloc(len);
+ if (i->data == NULL && len != 0)
+ return 0;
+ i->length = len;
+
+ if (RAND_bytes(i->data, i->length) != 1) {
+ free(i->data);
+ i->data = NULL;
+ return 0;
+ }
+
+ {
+ size_t j = len * 8;
+ while(j > bits) {
+ BN_clear_bit(bn, j - 1);
+ j--;
+ }
+ }
+
+ if (top == -1) {
+ ;
+ } else if (top == 0 && bits > 0) {
+ BN_set_bit(bn, bits - 1);
+ } else if (top == 1 && bits > 1) {
+ BN_set_bit(bn, bits - 1);
+ BN_set_bit(bn, bits - 2);
+ } else {
+ BN_clear(bn);
+ return 0;
+ }
+
+ if (bottom && bits > 0)
+ BN_set_bit(bn, 0);
+
+ return 1;
+}
+
+/*
+ *
+ */
+
+int
+BN_uadd(BIGNUM *res, const BIGNUM *a, const BIGNUM *b)
+{
+ const heim_integer *ai = (const heim_integer *)a;
+ const heim_integer *bi = (const heim_integer *)b;
+ const unsigned char *ap, *bp;
+ unsigned char *cp;
+ heim_integer ci;
+ int carry = 0;
+ ssize_t len;
+
+ if (ai->negative && bi->negative)
+ return 0;
+ if (ai->length < bi->length) {
+ const heim_integer *si = bi;
+ bi = ai; ai = si;
+ }
+
+ ci.negative = 0;
+ ci.length = ai->length + 1;
+ ci.data = malloc(ci.length);
+ if (ci.data == NULL)
+ return 0;
+
+ ap = &((const unsigned char *)ai->data)[ai->length - 1];
+ bp = &((const unsigned char *)bi->data)[bi->length - 1];
+ cp = &((unsigned char *)ci.data)[ci.length - 1];
+
+ for (len = bi->length; len > 0; len--) {
+ carry = *ap + *bp + carry;
+ *cp = carry & 0xff;
+ carry = (carry & ~0xff) ? 1 : 0;
+ ap--; bp--; cp--;
+ }
+ for (len = ai->length - bi->length; len > 0; len--) {
+ carry = *ap + carry;
+ *cp = carry & 0xff;
+ carry = (carry & ~0xff) ? 1 : 0;
+ ap--; cp--;
+ }
+ if (!carry)
+ memmove(cp, cp + 1, --ci.length);
+ else
+ *cp = carry;
+
+ BN_clear(res);
+ *((heim_integer *)res) = ci;
+
+ return 1;
+}
+
+
+/*
+ * Callback when doing slow generation of numbers, like primes.
+ */
+
+void
+BN_GENCB_set(BN_GENCB *gencb, int (*cb_2)(int, int, BN_GENCB *), void *ctx)
+{
+ gencb->ver = 2;
+ gencb->cb.cb_2 = cb_2;
+ gencb->arg = ctx;
+}
+
+int
+BN_GENCB_call(BN_GENCB *cb, int a, int b)
+{
+ if (cb == NULL || cb->cb.cb_2 == NULL)
+ return 1;
+ return cb->cb.cb_2(a, b, cb);
+}
diff --git a/source4/heimdal/lib/des/dh-imath.c b/source4/heimdal/lib/des/dh-imath.c
new file mode 100644
index 00000000000..ebf02c72beb
--- /dev/null
+++ b/source4/heimdal/lib/des/dh-imath.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dh.h>
+
+#include <roken.h>
+
+#include "imath/imath.h"
+
+RCSID("$Id: dh-imath.c,v 1.6 2006/10/20 06:56:57 lha Exp $");
+
+static void
+BN2mpz(mpz_t *s, const BIGNUM *bn)
+{
+ size_t len;
+ void *p;
+
+ len = BN_num_bytes(bn);
+ p = malloc(len);
+ BN_bn2bin(bn, p);
+ mp_int_read_unsigned(s, p, len);
+ free(p);
+}
+
+
+static BIGNUM *
+mpz2BN(mpz_t *s)
+{
+ size_t size;
+ BIGNUM *bn;
+ void *p;
+
+ size = mp_int_unsigned_len(s);
+ p = malloc(size);
+ if (p == NULL && size != 0)
+ return NULL;
+ mp_int_to_unsigned(s, p, size);
+
+ bn = BN_bin2bn(p, size, NULL);
+ free(p);
+ return bn;
+}
+
+/*
+ *
+ */
+
+#define DH_NUM_TRIES 10
+
+static int
+dh_generate_key(DH *dh)
+{
+ mpz_t pub, priv_key, g, p;
+ int have_private_key = (dh->priv_key != NULL);
+ int codes, times = 0;
+ mp_result res;
+
+ if (dh->p == NULL || dh->g == NULL)
+ return 0;
+
+ while (times++ < DH_NUM_TRIES) {
+ if (!have_private_key) {
+ size_t bits = BN_num_bits(dh->p);
+
+ if (dh->priv_key)
+ BN_free(dh->priv_key);
+
+ dh->priv_key = BN_new();
+ if (dh->priv_key == NULL)
+ return 0;
+ if (!BN_rand(dh->priv_key, bits - 1, 0, 0)) {
+ BN_clear_free(dh->priv_key);
+ dh->priv_key = NULL;
+ return 0;
+ }
+ }
+ if (dh->pub_key)
+ BN_free(dh->pub_key);
+
+ mp_int_init(&pub);
+ mp_int_init(&priv_key);
+ mp_int_init(&g);
+ mp_int_init(&p);
+
+ BN2mpz(&priv_key, dh->priv_key);
+ BN2mpz(&g, dh->g);
+ BN2mpz(&p, dh->p);
+
+ res = mp_int_exptmod(&g, &priv_key, &p, &pub);
+
+ mp_int_clear(&priv_key);
+ mp_int_clear(&g);
+ mp_int_clear(&p);
+ if (res != MP_OK)
+ continue;
+
+ dh->pub_key = mpz2BN(&pub);
+ mp_int_clear(&pub);
+ if (dh->pub_key == NULL)
+ return 0;
+
+ if (DH_check_pubkey(dh, dh->pub_key, &codes) && codes == 0)
+ break;
+ if (have_private_key)
+ return 0;
+ }
+
+ if (times >= DH_NUM_TRIES) {
+ if (!have_private_key && dh->priv_key) {
+ BN_free(dh->priv_key);
+ dh->priv_key = NULL;
+ }
+ if (dh->pub_key) {
+ BN_free(dh->pub_key);
+ dh->pub_key = NULL;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh)
+{
+ mpz_t s, priv_key, p, peer_pub;
+ size_t size = 0;
+ mp_result res;
+
+ if (dh->pub_key == NULL || dh->g == NULL || dh->priv_key == NULL)
+ return -1;
+
+ mp_int_init(&p);
+ BN2mpz(&p, dh->p);
+
+ mp_int_init(&peer_pub);
+ BN2mpz(&peer_pub, pub);
+
+ /* check if peers pubkey is reasonable */
+ if (MP_SIGN(&peer_pub) == MP_NEG
+ || mp_int_compare(&peer_pub, &p) >= 0
+ || mp_int_compare_value(&peer_pub, 1) <= 0)
+ {
+ mp_int_clear(&p);
+ mp_int_clear(&peer_pub);
+ return -1;
+ }
+
+ mp_int_init(&priv_key);
+ BN2mpz(&priv_key, dh->priv_key);
+
+ mp_int_init(&s);
+
+ mp_int_exptmod(&peer_pub, &priv_key, &p, &s);
+
+ mp_int_clear(&p);
+ mp_int_clear(&peer_pub);
+ mp_int_clear(&priv_key);
+
+ size = mp_int_unsigned_len(&s);
+ res = mp_int_to_unsigned(&s, shared, size);
+ mp_int_clear(&s);
+
+ return (res == MP_OK) ? size : -1;
+}
+
+static int
+dh_generate_params(DH *dh, int a, int b, BN_GENCB *callback)
+{
+ /* groups should already be known, we don't care about this */
+ return 0;
+}
+
+static int
+dh_init(DH *dh)
+{
+ return 1;
+}
+
+static int
+dh_finish(DH *dh)
+{
+ return 1;
+}
+
+
+/*
+ *
+ */
+
+const DH_METHOD hc_dh_imath_method = {
+ "hcrypto imath DH",
+ dh_generate_key,
+ dh_compute_key,
+ NULL,
+ dh_init,
+ dh_finish,
+ 0,
+ NULL,
+ dh_generate_params
+};
+
+const DH_METHOD *
+DH_imath_method(void)
+{
+ return &hc_dh_imath_method;
+}
diff --git a/source4/heimdal/lib/des/dh.c b/source4/heimdal/lib/des/dh.c
new file mode 100644
index 00000000000..66d611f6d48
--- /dev/null
+++ b/source4/heimdal/lib/des/dh.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id: dh.c,v 1.10 2006/10/19 17:31:51 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dh.h>
+
+#include <roken.h>
+
+/*
+ *
+ */
+
+DH *
+DH_new(void)
+{
+ return DH_new_method(NULL);
+}
+
+DH *
+DH_new_method(ENGINE *engine)
+{
+ DH *dh;
+
+ dh = calloc(1, sizeof(*dh));
+ if (dh == NULL)
+ return NULL;
+
+ dh->references = 1;
+
+ if (engine) {
+ ENGINE_up_ref(engine);
+ dh->engine = engine;
+ } else {
+ dh->engine = ENGINE_get_default_DH();
+ }
+
+ if (dh->engine) {
+ dh->meth = ENGINE_get_DH(dh->engine);
+ if (dh->meth == NULL) {
+ ENGINE_finish(engine);
+ free(dh);
+ return 0;
+ }
+ }
+
+ if (dh->meth == NULL)
+ dh->meth = DH_get_default_method();
+
+ (*dh->meth->init)(dh);
+
+ return dh;
+}
+
+void
+DH_free(DH *dh)
+{
+ if (dh->references <= 0)
+ abort();
+
+ if (--dh->references > 0)
+ return;
+
+ (*dh->meth->finish)(dh);
+
+ if (dh->engine)
+ ENGINE_finish(dh->engine);
+
+#define free_if(f) if (f) { BN_free(f); }
+ free_if(dh->p);
+ free_if(dh->g);
+ free_if(dh->pub_key);
+ free_if(dh->priv_key);
+ free_if(dh->q);
+ free_if(dh->j);
+ free_if(dh->counter);
+#undef free_if
+
+ memset(dh, 0, sizeof(*dh));
+ free(dh);
+}
+
+int
+DH_up_ref(DH *dh)
+{
+ return ++dh->references;
+}
+
+int
+DH_size(const DH *dh)
+{
+ return BN_num_bytes(dh->p);
+}
+
+int
+DH_set_ex_data(DH *dh, int idx, void *data)
+{
+ dh->ex_data.sk = data;
+ return 1;
+}
+
+void *
+DH_get_ex_data(DH *dh, int idx)
+{
+ return dh->ex_data.sk;
+}
+
+int
+DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb)
+{
+ if (dh->meth->generate_params)
+ return dh->meth->generate_params(dh, prime_len, generator, cb);
+ return 0;
+}
+
+/*
+ * Check that
+ *
+ * pub_key > 1 and pub_key < p - 1
+ *
+ * to avoid small subgroups attack.
+ */
+
+int
+DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes)
+{
+ BIGNUM *bn = NULL, *sum = NULL;
+ int ret = 0;
+
+ *codes = 0;
+
+ bn = BN_new();
+ if (bn == NULL)
+ goto out;
+
+ if (!BN_set_word(bn, 1))
+ goto out;
+
+ if (BN_cmp(bn, pub_key) >= 0)
+ *codes |= DH_CHECK_PUBKEY_TOO_SMALL;
+
+ sum = BN_new();
+ if (sum == NULL)
+ goto out;
+
+ BN_uadd(sum, pub_key, bn);
+
+ if (BN_cmp(sum, dh->p) >= 0)
+ *codes |= DH_CHECK_PUBKEY_TOO_LARGE;
+
+ ret = 1;
+out:
+ if (bn)
+ BN_free(bn);
+ if (sum)
+ BN_free(sum);
+
+ return ret;
+}
+
+int
+DH_generate_key(DH *dh)
+{
+ return dh->meth->generate_key(dh);
+}
+
+int
+DH_compute_key(unsigned char *shared_key,
+ const BIGNUM *peer_pub_key, DH *dh)
+{
+ int codes;
+
+ if (!DH_check_pubkey(dh, peer_pub_key, &codes) || codes != 0)
+ return -1;
+
+ return dh->meth->compute_key(shared_key, peer_pub_key, dh);
+}
+
+int
+DH_set_method(DH *dh, const DH_METHOD *method)
+{
+ (*dh->meth->finish)(dh);
+ if (dh->engine) {
+ ENGINE_finish(dh->engine);
+ dh->engine = NULL;
+ }
+ dh->meth = method;
+ (*dh->meth->init)(dh);
+ return 1;
+}
+
+/*
+ *
+ */
+
+static int
+dh_null_generate_key(DH *dh)
+{
+ return 0;
+}
+
+static int
+dh_null_compute_key(unsigned char *shared,const BIGNUM *pub, DH *dh)
+{
+ return 0;
+}
+
+static int
+dh_null_init(DH *dh)
+{
+ return 1;
+}
+
+static int
+dh_null_finish(DH *dh)
+{
+ return 1;
+}
+
+static int
+dh_null_generate_params(DH *dh, int prime_num, int len, BN_GENCB *cb)
+{
+ return 0;
+}
+
+static const DH_METHOD dh_null_method = {
+ "hcrypto null DH",
+ dh_null_generate_key,
+ dh_null_compute_key,
+ NULL,
+ dh_null_init,
+ dh_null_finish,
+ 0,
+ NULL,
+ dh_null_generate_params
+};
+
+extern const DH_METHOD hc_dh_imath_method;
+static const DH_METHOD *dh_default_method = &hc_dh_imath_method;
+
+const DH_METHOD *
+DH_null_method(void)
+{
+ return &dh_null_method;
+}
+
+void
+DH_set_default_method(const DH_METHOD *meth)
+{
+ dh_default_method = meth;
+}
+
+const DH_METHOD *
+DH_get_default_method(void)
+{
+ return dh_default_method;
+}
+
diff --git a/source4/heimdal/lib/des/dsa.c b/source4/heimdal/lib/des/dsa.c
new file mode 100644
index 00000000000..411597b1c66
--- /dev/null
+++ b/source4/heimdal/lib/des/dsa.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id: dsa.c,v 1.2 2006/05/07 11:31:58 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dsa.h>
+
+#include <roken.h>
+
+/*
+ *
+ */
+
+DSA *
+DSA_new(void)
+{
+ DSA *dsa = calloc(1, sizeof(*dsa));
+ dsa->meth = rk_UNCONST(DSA_get_default_method());
+ dsa->references = 1;
+ return dsa;
+}
+
+void
+DSA_free(DSA *dsa)
+{
+ if (dsa->references <= 0)
+ abort();
+
+ if (--dsa->references > 0)
+ return;
+
+ (*dsa->meth->finish)(dsa);
+
+#define free_if(f) if (f) { BN_free(f); }
+ free_if(dsa->p);
+ free_if(dsa->q);
+ free_if(dsa->g);
+ free_if(dsa->pub_key);
+ free_if(dsa->priv_key);
+ free_if(dsa->kinv);
+ free_if(dsa->r);
+#undef free_if
+
+ memset(dsa, 0, sizeof(*dsa));
+ free(dsa);
+
+}
+
+int
+DSA_up_ref(DSA *dsa)
+{
+ return ++dsa->references;
+}
+
+/*
+ *
+ */
+
+static const DSA_METHOD dsa_null_method = {
+ "hcrypto null DSA"
+};
+
+const DSA_METHOD *
+DSA_null_method(void)
+{
+ return &dsa_null_method;
+}
+
+
+const DSA_METHOD *dsa_default_mech = &dsa_null_method;
+
+void
+DSA_set_default_method(const DSA_METHOD *mech)
+{
+ dsa_default_mech = mech;
+}
+
+const DSA_METHOD *
+DSA_get_default_method(void)
+{
+ return dsa_default_mech;
+}
+
+int
+DSA_verify(int type, const unsigned char * digest, int digest_len,
+ const unsigned char *sig, int sig_len, DSA *dsa)
+{
+ return -1;
+}
diff --git a/source4/heimdal/lib/des/engine.c b/source4/heimdal/lib/des/engine.c
new file mode 100644
index 00000000000..b72339c362b
--- /dev/null
+++ b/source4/heimdal/lib/des/engine.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id: engine.c,v 1.11 2006/10/19 14:23:00 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <engine.h>
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#endif
+
+struct hc_engine {
+ int references;
+ char *name;
+ char *id;
+ void (*destroy)(ENGINE *);
+ const RSA_METHOD *rsa;
+ const DH_METHOD *dh;
+ const RAND_METHOD *rand;
+};
+
+int
+ENGINE_finish(ENGINE *engine)
+{
+ if (engine->references-- <= 0)
+ abort();
+ if (engine->references > 0)
+ return 1;
+
+ if (engine->name)
+ free(engine->name);
+ if (engine->id)
+ free(engine->id);
+ if(engine->destroy)
+ (*engine->destroy)(engine);
+
+ memset(engine, 0, sizeof(engine));
+ engine->references = -1;
+
+
+ free(engine);
+ return 1;
+}
+
+int
+ENGINE_up_ref(ENGINE *engine)
+{
+ if (engine->references < 0)
+ abort();
+ engine->references++;
+ return 1;
+}
+
+int
+ENGINE_set_id(ENGINE *engine, const char *id)
+{
+ engine->id = strdup(id);
+ return (engine->id == NULL) ? 0 : 1;
+}
+
+int
+ENGINE_set_name(ENGINE *engine, const char *name)
+{
+ engine->name = strdup(name);
+ return (engine->name == NULL) ? 0 : 1;
+}
+
+int
+ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method)
+{
+ engine->rsa = method;
+ return 1;
+}
+
+int
+ENGINE_set_DH(ENGINE *engine, const DH_METHOD *method)
+{
+ engine->dh = method;
+ return 1;
+}
+
+int
+ENGINE_set_destroy_function(ENGINE *e, void (*destroy)(ENGINE *))
+{
+ e->destroy = destroy;
+ return 1;
+}
+
+const char *
+ENGINE_get_id(const ENGINE *engine)
+{
+ return engine->id;
+}
+
+const char *
+ENGINE_get_name(const ENGINE *engine)
+{
+ return engine->name;
+}
+
+const RSA_METHOD *
+ENGINE_get_RSA(const ENGINE *engine)
+{
+ return engine->rsa;
+}
+
+const DH_METHOD *
+ENGINE_get_DH(const ENGINE *engine)
+{
+ return engine->dh;
+}
+
+const RAND_METHOD *
+ENGINE_get_RAND(const ENGINE *engine)
+{
+ return engine->rand;
+}
+
+/*
+ *
+ */
+
+#define SG_default_engine(type) \
+static ENGINE *type##_engine; \
+int \
+ENGINE_set_default_##type(ENGINE *engine) \
+{ \
+ if (type##_engine) \
+ ENGINE_finish(type##_engine); \
+ type##_engine = engine; \
+ if (type##_engine) \
+ ENGINE_up_ref(type##_engine); \
+ return 1; \
+} \
+ENGINE * \
+ENGINE_get_default_##type(void) \
+{ \
+ if (type##_engine) \
+ ENGINE_up_ref(type##_engine); \
+ return type##_engine; \
+}
+
+SG_default_engine(RSA)
+SG_default_engine(DH)
+
+#undef SG_default_engine
+
+/*
+ *
+ */
+
+static ENGINE **engines;
+static unsigned int num_engines;
+
+static int
+add_engine(ENGINE *engine)
+{
+ ENGINE **d, *dup;
+
+ dup = ENGINE_by_id(engine->id);
+ if (dup) {
+ ENGINE_finish(dup);
+ return 0;
+ }
+
+ d = realloc(engines, (num_engines + 1) * sizeof(*engines));
+ if (d == NULL)
+ return 1;
+ engines = d;
+ engines[num_engines++] = engine;
+
+ return 1;
+}
+
+void
+ENGINE_load_builtin_engines(void)
+{
+ ENGINE *engine;
+ int ret;
+
+ engine = calloc(1, sizeof(*engine));
+ if (engine == NULL)
+ return;
+
+ ENGINE_set_id(engine, "builtin");
+ ENGINE_set_name(engine,
+ "Heimdal crypto builtin engine version " PACKAGE_VERSION);
+ ENGINE_set_RSA(engine, RSA_imath_method());
+ ENGINE_set_DH(engine, DH_imath_method());
+
+ ret = add_engine(engine);
+ if (ret != 1)
+ ENGINE_finish(engine);
+}
+
+ENGINE *
+ENGINE_by_dso(const char *path, const char *id)
+{
+#ifdef HAVE_DLOPEN
+ ENGINE *engine;
+ void *handle;
+ int ret;
+
+ engine = calloc(1, sizeof(*engine));
+ if (engine == NULL)
+ return NULL;
+
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
+ /* printf("error: %s\n", dlerror()); */
+ free(engine);
+ return NULL;
+ }
+
+ {
+ unsigned long version;
+ openssl_v_check v_check;
+
+ v_check = (openssl_v_check)dlsym(handle, "v_check");
+ if (v_check == NULL) {
+ dlclose(handle);
+ free(engine);
+ return NULL;
+ }
+
+ version = (*v_check)(OPENSSL_DYNAMIC_VERSION);
+ if (version == 0) {
+ dlclose(handle);
+ free(engine);
+ return NULL;
+ }
+ }
+
+ {
+ openssl_bind_engine bind_engine;
+
+ bind_engine = (openssl_bind_engine)dlsym(handle, "bind_engine");
+ if (bind_engine == NULL) {
+ dlclose(handle);
+ free(engine);
+ return NULL;
+ }
+
+ ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */
+ if (ret != 1) {
+ dlclose(handle);
+ free(engine);
+ return NULL;
+ }
+ }
+
+ ENGINE_up_ref(engine);
+
+ ret = add_engine(engine);
+ if (ret != 1) {
+ dlclose(handle);
+ ENGINE_finish(engine);
+ return NULL;
+ }
+
+ return engine;
+#else
+ return NULL;
+#endif
+}
+
+ENGINE *
+ENGINE_by_id(const char *id)
+{
+ int i;
+
+ for (i = 0; i < num_engines; i++) {
+ if (strcmp(id, engines[i]->id) == 0) {
+ ENGINE_up_ref(engines[i]);
+ return engines[i];
+ }
+ }
+ return NULL;
+}
+
+void
+ENGINE_add_conf_module(void)
+{
+ ENGINE *engine;
+
+ /*
+ * XXX Parse configuration file instead
+ */
+
+ engine = ENGINE_by_dso("/usr/heimdal/lib/hc-modules/hc-gmp.so", NULL);
+ if (engine == NULL)
+ return;
+ {
+ const RSA_METHOD *method = ENGINE_get_RSA(engine);
+ if (method)
+ RSA_set_default_method(method);
+ }
+ {
+ const DH_METHOD *method = ENGINE_get_DH(engine);
+ if (method)
+ DH_set_default_method(method);
+ }
+
+}
diff --git a/source4/heimdal/lib/des/imath/LICENSE b/source4/heimdal/lib/des/imath/LICENSE
new file mode 100644
index 00000000000..cecfb114040
--- /dev/null
+++ b/source4/heimdal/lib/des/imath/LICENSE
@@ -0,0 +1,21 @@
+IMath is Copyright 2002-2006 Michael J. Fromberger
+You may use it subject to the following Licensing Terms:
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/source4/heimdal/lib/des/imath/imath.c b/source4/heimdal/lib/des/imath/imath.c
new file mode 100755
index 00000000000..0a124fa13fc
--- /dev/null
+++ b/source4/heimdal/lib/des/imath/imath.c
@@ -0,0 +1,3246 @@
+/*
+ Name: imath.c
+ Purpose: Arbitrary precision integer arithmetic routines.
+ Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/>
+ Info: $Id: imath.c,v 1.6 2007/01/08 10:17:31 lha Exp $
+
+ Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+#include "imath.h"
+
+#if DEBUG
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <assert.h>
+
+/* {{{ Constants */
+
+const mp_result MP_OK = 0; /* no error, all is well */
+const mp_result MP_FALSE = 0; /* boolean false */
+const mp_result MP_TRUE = -1; /* boolean true */
+const mp_result MP_MEMORY = -2; /* out of memory */
+const mp_result MP_RANGE = -3; /* argument out of range */
+const mp_result MP_UNDEF = -4; /* result undefined */
+const mp_result MP_TRUNC = -5; /* output truncated */
+const mp_result MP_BADARG = -6; /* invalid null argument */
+
+const mp_sign MP_NEG = 1; /* value is strictly negative */
+const mp_sign MP_ZPOS = 0; /* value is non-negative */
+
+static const char *s_unknown_err = "unknown result code";
+static const char *s_error_msg[] = {
+ "error code 0",
+ "boolean true",
+ "out of memory",
+ "argument out of range",
+ "result undefined",
+ "output truncated",
+ "invalid null argument",
+ NULL
+};
+
+/* }}} */
+
+/* Argument checking macros
+ Use CHECK() where a return value is required; NRCHECK() elsewhere */
+#define CHECK(TEST) assert(TEST)
+#define NRCHECK(TEST) assert(TEST)
+
+/* {{{ Logarithm table for computing output sizes */
+
+/* The ith entry of this table gives the value of log_i(2).
+
+ An integer value n requires ceil(log_i(n)) digits to be represented
+ in base i. Since it is easy to compute lg(n), by counting bits, we
+ can compute log_i(n) = lg(n) * log_i(2).
+
+ The use of this table eliminates a dependency upon linkage against
+ the standard math libraries.
+ */
+static const double s_log2[] = {
+ 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */
+ 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */
+ 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */
+ 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */
+ 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */
+ 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */
+ 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */
+ 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */
+ 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */
+ 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */
+ 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */
+ 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */
+ 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */
+ 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */
+ 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */
+ 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */
+ 0.166666667
+};
+
+/* }}} */
+/* {{{ Various macros */
+
+/* Return the number of digits needed to represent a static value */
+#define MP_VALUE_DIGITS(V) \
+((sizeof(V)+(sizeof(mp_digit)-1))/sizeof(mp_digit))
+
+/* Round precision P to nearest word boundary */
+#define ROUND_PREC(P) ((mp_size)(2*(((P)+1)/2)))
+
+/* Set array P of S digits to zero */
+#define ZERO(P, S) \
+do{mp_size i__=(S)*sizeof(mp_digit);mp_digit *p__=(P);memset(p__,0,i__);}while(0)
+
+/* Copy S digits from array P to array Q */
+#define COPY(P, Q, S) \
+do{mp_size i__=(S)*sizeof(mp_digit);mp_digit *p__=(P),*q__=(Q);\
+memcpy(q__,p__,i__);}while(0)
+
+/* Reverse N elements of type T in array A */
+#define REV(T, A, N) \
+do{T *u_=(A),*v_=u_+(N)-1;while(u_<v_){T xch=*u_;*u_++=*v_;*v_--=xch;}}while(0)
+
+#if TRACEABLE_CLAMP
+#define CLAMP(Z) s_clamp(Z)
+#else
+#define CLAMP(Z) \
+do{mp_int z_=(Z);mp_size uz_=MP_USED(z_);mp_digit *dz_=MP_DIGITS(z_)+uz_-1;\
+while(uz_ > 1 && (*dz_-- == 0)) --uz_;MP_USED(z_)=uz_;}while(0)
+#endif
+
+#define MIN(A, B) ((B)<(A)?(B):(A))
+#define MAX(A, B) ((B)>(A)?(B):(A))
+#define SWAP(T, A, B) do{T t_=(A);A=(B);B=t_;}while(0)
+
+#define TEMP(K) (temp + (K))
+#define SETUP(E, C) \
+do{if((res = (E)) != MP_OK) goto CLEANUP; ++(C);}while(0)
+
+#define CMPZ(Z) \
+(((Z)->used==1&&(Z)->digits[0]==0)?0:((Z)->sign==MP_NEG)?-1:1)
+
+#define UMUL(X, Y, Z) \
+do{mp_size ua_=MP_USED(X),ub_=MP_USED(Y);mp_size o_=ua_+ub_;\
+ZERO(MP_DIGITS(Z),o_);\
+(void) s_kmul(MP_DIGITS(X),MP_DIGITS(Y),MP_DIGITS(Z),ua_,ub_);\
+MP_USED(Z)=o_;CLAMP(Z);}while(0)
+
+#define USQR(X, Z) \
+do{mp_size ua_=MP_USED(X),o_=ua_+ua_;ZERO(MP_DIGITS(Z),o_);\
+(void) s_ksqr(MP_DIGITS(X),MP_DIGITS(Z),ua_);MP_USED(Z)=o_;CLAMP(Z);}while(0)
+
+#define UPPER_HALF(W) ((mp_word)((W) >> MP_DIGIT_BIT))
+#define LOWER_HALF(W) ((mp_digit)(W))
+#define HIGH_BIT_SET(W) ((W) >> (MP_WORD_BIT - 1))
+#define ADD_WILL_OVERFLOW(W, V) ((MP_WORD_MAX - (V)) < (W))
+
+/* }}} */
+/* {{{ Default configuration settings */
+
+/* Default number of digits allocated to a new mp_int */
+#if IMATH_TEST
+mp_size default_precision = MP_DEFAULT_PREC;
+#else
+static const mp_size default_precision = MP_DEFAULT_PREC;
+#endif
+
+/* Minimum number of digits to invoke recursive multiply */
+#if IMATH_TEST
+mp_size multiply_threshold = MP_MULT_THRESH;
+#else
+static const mp_size multiply_threshold = MP_MULT_THRESH;
+#endif
+
+/* }}} */
+
+/* Allocate a buffer of (at least) num digits, or return
+ NULL if that couldn't be done. */
+static mp_digit *s_alloc(mp_size num);
+#if TRACEABLE_FREE
+static void s_free(void *ptr);
+#else
+#define s_free(P) free(P)
+#endif
+
+/* Insure that z has at least min digits allocated, resizing if
+ necessary. Returns true if successful, false if out of memory. */
+int s_pad(mp_int z, mp_size min);
+
+/* Normalize by removing leading zeroes (except when z = 0) */
+#if TRACEABLE_CLAMP
+static void s_clamp(mp_int z);
+#endif
+
+/* Fill in a "fake" mp_int on the stack with a given value */
+static void s_fake(mp_int z, int value, mp_digit vbuf[]);
+
+/* Compare two runs of digits of given length, returns <0, 0, >0 */
+static int s_cdig(mp_digit *da, mp_digit *db, mp_size len);
+
+/* Pack the unsigned digits of v into array t */
+static int s_vpack(int v, mp_digit t[]);
+
+/* Compare magnitudes of a and b, returns <0, 0, >0 */
+static int s_ucmp(mp_int a, mp_int b);
+
+/* Compare magnitudes of a and v, returns <0, 0, >0 */
+static int s_vcmp(mp_int a, int v);
+
+/* Unsigned magnitude addition; assumes dc is big enough.
+ Carry out is returned (no memory allocated). */
+static mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b);
+
+/* Unsigned magnitude subtraction. Assumes dc is big enough. */
+static void s_usub(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b);
+
+/* Unsigned recursive multiplication. Assumes dc is big enough. */
+static int s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b);
+
+/* Unsigned magnitude multiplication. Assumes dc is big enough. */
+static void s_umul(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b);
+
+/* Unsigned recursive squaring. Assumes dc is big enough. */
+static int s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a);
+
+/* Unsigned magnitude squaring. Assumes dc is big enough. */
+static void s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a);
+
+/* Single digit addition. Assumes a is big enough. */
+static void s_dadd(mp_int a, mp_digit b);
+
+/* Single digit multiplication. Assumes a is big enough. */
+static void s_dmul(mp_int a, mp_digit b);
+
+/* Single digit multiplication on buffers; assumes dc is big enough. */
+static void s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc,
+ mp_size size_a);
+
+/* Single digit division. Replaces a with the quotient,
+ returns the remainder. */
+static mp_digit s_ddiv(mp_int a, mp_digit b);
+
+/* Quick division by a power of 2, replaces z (no allocation) */
+static void s_qdiv(mp_int z, mp_size p2);
+
+/* Quick remainder by a power of 2, replaces z (no allocation) */
+static void s_qmod(mp_int z, mp_size p2);
+
+/* Quick multiplication by a power of 2, replaces z.
+ Allocates if necessary; returns false in case this fails. */
+static int s_qmul(mp_int z, mp_size p2);
+
+/* Quick subtraction from a power of 2, replaces z.
+ Allocates if necessary; returns false in case this fails. */
+static int s_qsub(mp_int z, mp_size p2);
+
+/* Return maximum k such that 2^k divides z. */
+static int s_dp2k(mp_int z);
+
+/* Return k >= 0 such that z = 2^k, or -1 if there is no such k. */
+static int s_isp2(mp_int z);
+
+/* Set z to 2^k. May allocate; returns false in case this fails. */
+static int s_2expt(mp_int z, int k);
+
+/* Normalize a and b for division, returns normalization constant */
+static int s_norm(mp_int a, mp_int b);
+
+/* Compute constant mu for Barrett reduction, given modulus m, result
+ replaces z, m is untouched. */
+static mp_result s_brmu(mp_int z, mp_int m);
+
+/* Reduce a modulo m, using Barrett's algorithm. */
+static int s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2);
+
+/* Modular exponentiation, using Barrett reduction */
+mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c);
+
+/* Unsigned magnitude division. Assumes |a| > |b|. Allocates
+ temporaries; overwrites a with quotient, b with remainder. */
+static mp_result s_udiv(mp_int a, mp_int b);
+
+/* Compute the number of digits in radix r required to represent the
+ given value. Does not account for sign flags, terminators, etc. */
+static int s_outlen(mp_int z, mp_size r);
+
+/* Guess how many digits of precision will be needed to represent a
+ radix r value of the specified number of digits. Returns a value
+ guaranteed to be no smaller than the actual number required. */
+static mp_size s_inlen(int len, mp_size r);
+
+/* Convert a character to a digit value in radix r, or
+ -1 if out of range */
+static int s_ch2val(char c, int r);
+
+/* Convert a digit value to a character */
+static char s_val2ch(int v, int caps);
+
+/* Take 2's complement of a buffer in place */
+static void s_2comp(unsigned char *buf, int len);
+
+/* Convert a value to binary, ignoring sign. On input, *limpos is the
+ bound on how many bytes should be written to buf; on output, *limpos
+ is set to the number of bytes actually written. */
+static mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad);
+
+#if DEBUG
+/* Dump a representation of the mp_int to standard output */
+void s_print(char *tag, mp_int z);
+void s_print_buf(char *tag, mp_digit *buf, mp_size num);
+#endif
+
+/* {{{ mp_int_init(z) */
+
+mp_result mp_int_init(mp_int z)
+{
+ if(z == NULL)
+ return MP_BADARG;
+
+ z->single = 0;
+ z->digits = &(z->single);
+ z->alloc = 1;
+ z->used = 1;
+ z->sign = MP_ZPOS;
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_alloc() */
+
+mp_int mp_int_alloc(void)
+{
+ mp_int out = malloc(sizeof(mpz_t));
+
+ if(out != NULL)
+ mp_int_init(out);
+
+ return out;
+}
+
+/* }}} */
+
+/* {{{ mp_int_init_size(z, prec) */
+
+mp_result mp_int_init_size(mp_int z, mp_size prec)
+{
+ CHECK(z != NULL);
+
+ if(prec == 0)
+ prec = default_precision;
+ else if(prec == 1)
+ return mp_int_init(z);
+ else
+ prec = (mp_size) ROUND_PREC(prec);
+
+ if((MP_DIGITS(z) = s_alloc(prec)) == NULL)
+ return MP_MEMORY;
+
+ z->digits[0] = 0;
+ MP_USED(z) = 1;
+ MP_ALLOC(z) = prec;
+ MP_SIGN(z) = MP_ZPOS;
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_init_copy(z, old) */
+
+mp_result mp_int_init_copy(mp_int z, mp_int old)
+{
+ mp_result res;
+ mp_size uold;
+
+ CHECK(z != NULL && old != NULL);
+
+ uold = MP_USED(old);
+ if(uold == 1) {
+ mp_int_init(z);
+ }
+ else {
+ mp_size target = MAX(uold, default_precision);
+
+ if((res = mp_int_init_size(z, target)) != MP_OK)
+ return res;
+ }
+
+ MP_USED(z) = uold;
+ MP_SIGN(z) = MP_SIGN(old);
+ COPY(MP_DIGITS(old), MP_DIGITS(z), uold);
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_init_value(z, value) */
+
+mp_result mp_int_init_value(mp_int z, int value)
+{
+ mpz_t vtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+ s_fake(&vtmp, value, vbuf);
+ return mp_int_init_copy(z, &vtmp);
+}
+
+/* }}} */
+
+/* {{{ mp_int_set_value(z, value) */
+
+mp_result mp_int_set_value(mp_int z, int value)
+{
+ mpz_t vtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+ s_fake(&vtmp, value, vbuf);
+ return mp_int_copy(&vtmp, z);
+}
+
+/* }}} */
+
+/* {{{ mp_int_clear(z) */
+
+void mp_int_clear(mp_int z)
+{
+ if(z == NULL)
+ return;
+
+ if(MP_DIGITS(z) != NULL) {
+ if((void *) MP_DIGITS(z) != (void *) z)
+ s_free(MP_DIGITS(z));
+
+ MP_DIGITS(z) = NULL;
+ }
+}
+
+/* }}} */
+
+/* {{{ mp_int_free(z) */
+
+void mp_int_free(mp_int z)
+{
+ NRCHECK(z != NULL);
+
+ mp_int_clear(z);
+ free(z);
+}
+
+/* }}} */
+
+/* {{{ mp_int_copy(a, c) */
+
+mp_result mp_int_copy(mp_int a, mp_int c)
+{
+ CHECK(a != NULL && c != NULL);
+
+ if(a != c) {
+ mp_size ua = MP_USED(a);
+ mp_digit *da, *dc;
+
+ if(!s_pad(c, ua))
+ return MP_MEMORY;
+
+ da = MP_DIGITS(a); dc = MP_DIGITS(c);
+ COPY(da, dc, ua);
+
+ MP_USED(c) = ua;
+ MP_SIGN(c) = MP_SIGN(a);
+ }
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_swap(a, c) */
+
+void mp_int_swap(mp_int a, mp_int c)
+{
+ if(a != c) {
+ mpz_t tmp = *a;
+
+ *a = *c;
+ *c = tmp;
+ }
+}
+
+/* }}} */
+
+/* {{{ mp_int_zero(z) */
+
+void mp_int_zero(mp_int z)
+{
+ NRCHECK(z != NULL);
+
+ z->digits[0] = 0;
+ MP_USED(z) = 1;
+ MP_SIGN(z) = MP_ZPOS;
+}
+
+/* }}} */
+
+/* {{{ mp_int_abs(a, c) */
+
+mp_result mp_int_abs(mp_int a, mp_int c)
+{
+ mp_result res;
+
+ CHECK(a != NULL && c != NULL);
+
+ if((res = mp_int_copy(a, c)) != MP_OK)
+ return res;
+
+ MP_SIGN(c) = MP_ZPOS;
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_neg(a, c) */
+
+mp_result mp_int_neg(mp_int a, mp_int c)
+{
+ mp_result res;
+
+ CHECK(a != NULL && c != NULL);
+
+ if((res = mp_int_copy(a, c)) != MP_OK)
+ return res;
+
+ if(CMPZ(c) != 0)
+ MP_SIGN(c) = 1 - MP_SIGN(a);
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_add(a, b, c) */
+
+mp_result mp_int_add(mp_int a, mp_int b, mp_int c)
+{
+ mp_size ua, ub, uc, max;
+
+ CHECK(a != NULL && b != NULL && c != NULL);
+
+ ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c);
+ max = MAX(ua, ub);
+
+ if(MP_SIGN(a) == MP_SIGN(b)) {
+ /* Same sign -- add magnitudes, preserve sign of addends */
+ mp_digit carry;
+
+ if(!s_pad(c, max))
+ return MP_MEMORY;
+
+ carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub);
+ uc = max;
+
+ if(carry) {
+ if(!s_pad(c, max + 1))
+ return MP_MEMORY;
+
+ c->digits[max] = carry;
+ ++uc;
+ }
+
+ MP_USED(c) = uc;
+ MP_SIGN(c) = MP_SIGN(a);
+
+ }
+ else {
+ /* Different signs -- subtract magnitudes, preserve sign of greater */
+ mp_int x, y;
+ int cmp = s_ucmp(a, b); /* magnitude comparision, sign ignored */
+
+ /* Set x to max(a, b), y to min(a, b) to simplify later code */
+ if(cmp >= 0) {
+ x = a; y = b;
+ }
+ else {
+ x = b; y = a;
+ }
+
+ if(!s_pad(c, MP_USED(x)))
+ return MP_MEMORY;
+
+ /* Subtract smaller from larger */
+ s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y));
+ MP_USED(c) = MP_USED(x);
+ CLAMP(c);
+
+ /* Give result the sign of the larger */
+ MP_SIGN(c) = MP_SIGN(x);
+ }
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_add_value(a, value, c) */
+
+mp_result mp_int_add_value(mp_int a, int value, mp_int c)
+{
+ mpz_t vtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+ s_fake(&vtmp, value, vbuf);
+
+ return mp_int_add(a, &vtmp, c);
+}
+
+/* }}} */
+
+/* {{{ mp_int_sub(a, b, c) */
+
+mp_result mp_int_sub(mp_int a, mp_int b, mp_int c)
+{
+ mp_size ua, ub, uc, max;
+
+ CHECK(a != NULL && b != NULL && c != NULL);
+
+ ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c);
+ max = MAX(ua, ub);
+
+ if(MP_SIGN(a) != MP_SIGN(b)) {
+ /* Different signs -- add magnitudes and keep sign of a */
+ mp_digit carry;
+
+ if(!s_pad(c, max))
+ return MP_MEMORY;
+
+ carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub);
+ uc = max;
+
+ if(carry) {
+ if(!s_pad(c, max + 1))
+ return MP_MEMORY;
+
+ c->digits[max] = carry;
+ ++uc;
+ }
+
+ MP_USED(c) = uc;
+ MP_SIGN(c) = MP_SIGN(a);
+
+ }
+ else {
+ /* Same signs -- subtract magnitudes */
+ mp_int x, y;
+ mp_sign osign;
+ int cmp = s_ucmp(a, b);
+
+ if(!s_pad(c, max))
+ return MP_MEMORY;
+
+ if(cmp >= 0) {
+ x = a; y = b; osign = MP_ZPOS;
+ }
+ else {
+ x = b; y = a; osign = MP_NEG;
+ }
+
+ if(MP_SIGN(a) == MP_NEG && cmp != 0)
+ osign = 1 - osign;
+
+ s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y));
+ MP_USED(c) = MP_USED(x);
+ CLAMP(c);
+
+ MP_SIGN(c) = osign;
+ }
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_sub_value(a, value, c) */
+
+mp_result mp_int_sub_value(mp_int a, int value, mp_int c)
+{
+ mpz_t vtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+ s_fake(&vtmp, value, vbuf);
+
+ return mp_int_sub(a, &vtmp, c);
+}
+
+/* }}} */
+
+/* {{{ mp_int_mul(a, b, c) */
+
+mp_result mp_int_mul(mp_int a, mp_int b, mp_int c)
+{
+ mp_digit *out;
+ mp_size osize, ua, ub, p = 0;
+ mp_sign osign;
+
+ CHECK(a != NULL && b != NULL && c != NULL);
+
+ /* If either input is zero, we can shortcut multiplication */
+ if(mp_int_compare_zero(a) == 0 || mp_int_compare_zero(b) == 0) {
+ mp_int_zero(c);
+ return MP_OK;
+ }
+
+ /* Output is positive if inputs have same sign, otherwise negative */
+ osign = (MP_SIGN(a) == MP_SIGN(b)) ? MP_ZPOS : MP_NEG;
+
+ /* If the output is not equal to any of the inputs, we'll write the
+ results there directly; otherwise, allocate a temporary space. */
+ ua = MP_USED(a); ub = MP_USED(b);
+ osize = ua + ub;
+
+ if(c == a || c == b) {
+ p = ROUND_PREC(osize);
+ p = MAX(p, default_precision);
+
+ if((out = s_alloc(p)) == NULL)
+ return MP_MEMORY;
+ }
+ else {
+ if(!s_pad(c, osize))
+ return MP_MEMORY;
+
+ out = MP_DIGITS(c);
+ }
+ ZERO(out, osize);
+
+ if(!s_kmul(MP_DIGITS(a), MP_DIGITS(b), out, ua, ub))
+ return MP_MEMORY;
+
+ /* If we allocated a new buffer, get rid of whatever memory c was
+ already using, and fix up its fields to reflect that.
+ */
+ if(out != MP_DIGITS(c)) {
+ if((void *) MP_DIGITS(c) != (void *) c)
+ s_free(MP_DIGITS(c));
+ MP_DIGITS(c) = out;
+ MP_ALLOC(c) = p;
+ }
+
+ MP_USED(c) = osize; /* might not be true, but we'll fix it ... */
+ CLAMP(c); /* ... right here */
+ MP_SIGN(c) = osign;
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_mul_value(a, value, c) */
+
+mp_result mp_int_mul_value(mp_int a, int value, mp_int c)
+{
+ mpz_t vtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+ s_fake(&vtmp, value, vbuf);
+
+ return mp_int_mul(a, &vtmp, c);
+}
+
+/* }}} */
+
+/* {{{ mp_int_mul_pow2(a, p2, c) */
+
+mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c)
+{
+ mp_result res;
+ CHECK(a != NULL && c != NULL && p2 >= 0);
+
+ if((res = mp_int_copy(a, c)) != MP_OK)
+ return res;
+
+ if(s_qmul(c, (mp_size) p2))
+ return MP_OK;
+ else
+ return MP_MEMORY;
+}
+
+/* }}} */
+
+/* {{{ mp_int_sqr(a, c) */
+
+mp_result mp_int_sqr(mp_int a, mp_int c)
+{
+ mp_digit *out;
+ mp_size osize, p = 0;
+
+ CHECK(a != NULL && c != NULL);
+
+ /* Get a temporary buffer big enough to hold the result */
+ osize = (mp_size) 2 * MP_USED(a);
+ if(a == c) {
+ p = ROUND_PREC(osize);
+ p = MAX(p, default_precision);
+
+ if((out = s_alloc(p)) == NULL)
+ return MP_MEMORY;
+ }
+ else {
+ if(!s_pad(c, osize))
+ return MP_MEMORY;
+
+ out = MP_DIGITS(c);
+ }
+ ZERO(out, osize);
+
+ s_ksqr(MP_DIGITS(a), out, MP_USED(a));
+
+ /* Get rid of whatever memory c was already using, and fix up its
+ fields to reflect the new digit array it's using
+ */
+ if(out != MP_DIGITS(c)) {
+ if((void *) MP_DIGITS(c) != (void *) c)
+ s_free(MP_DIGITS(c));
+ MP_DIGITS(c) = out;
+ MP_ALLOC(c) = p;
+ }
+
+ MP_USED(c) = osize; /* might not be true, but we'll fix it ... */
+ CLAMP(c); /* ... right here */
+ MP_SIGN(c) = MP_ZPOS;
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_div(a, b, q, r) */
+
+mp_result mp_int_div(mp_int a, mp_int b, mp_int q, mp_int r)
+{
+ int cmp, last = 0, lg;
+ mp_result res = MP_OK;
+ mpz_t temp[2];
+ mp_int qout, rout;
+ mp_sign sa = MP_SIGN(a), sb = MP_SIGN(b);
+
+ CHECK(a != NULL && b != NULL && q != r);
+
+ if(CMPZ(b) == 0)
+ return MP_UNDEF;
+ else if((cmp = s_ucmp(a, b)) < 0) {
+ /* If |a| < |b|, no division is required:
+ q = 0, r = a
+ */
+ if(r && (res = mp_int_copy(a, r)) != MP_OK)
+ return res;
+
+ if(q)
+ mp_int_zero(q);
+
+ return MP_OK;
+ }
+ else if(cmp == 0) {
+ /* If |a| = |b|, no division is required:
+ q = 1 or -1, r = 0
+ */
+ if(r)
+ mp_int_zero(r);
+
+ if(q) {
+ mp_int_zero(q);
+ q->digits[0] = 1;
+
+ if(sa != sb)
+ MP_SIGN(q) = MP_NEG;
+ }
+
+ return MP_OK;
+ }
+
+ /* When |a| > |b|, real division is required. We need someplace to
+ store quotient and remainder, but q and r are allowed to be NULL
+ or to overlap with the inputs.
+ */
+ if((lg = s_isp2(b)) < 0) {
+ if(q && b != q && (res = mp_int_copy(a, q)) == MP_OK) {
+ qout = q;
+ }
+ else {
+ qout = TEMP(last);
+ SETUP(mp_int_init_copy(TEMP(last), a), last);
+ }
+
+ if(r && a != r && (res = mp_int_copy(b, r)) == MP_OK) {
+ rout = r;
+ }
+ else {
+ rout = TEMP(last);
+ SETUP(mp_int_init_copy(TEMP(last), b), last);
+ }
+
+ if((res = s_udiv(qout, rout)) != MP_OK) goto CLEANUP;
+ }
+ else {
+ if(q && (res = mp_int_copy(a, q)) != MP_OK) goto CLEANUP;
+ if(r && (res = mp_int_copy(a, r)) != MP_OK) goto CLEANUP;
+
+ if(q) s_qdiv(q, (mp_size) lg); qout = q;
+ if(r) s_qmod(r, (mp_size) lg); rout = r;
+ }
+
+ /* Recompute signs for output */
+ if(rout) {
+ MP_SIGN(rout) = sa;
+ if(CMPZ(rout) == 0)
+ MP_SIGN(rout) = MP_ZPOS;
+ }
+ if(qout) {
+ MP_SIGN(qout) = (sa == sb) ? MP_ZPOS : MP_NEG;
+ if(CMPZ(qout) == 0)
+ MP_SIGN(qout) = MP_ZPOS;
+ }
+
+ if(q && (res = mp_int_copy(qout, q)) != MP_OK) goto CLEANUP;
+ if(r && (res = mp_int_copy(rout, r)) != MP_OK) goto CLEANUP;
+
+ CLEANUP:
+ while(--last >= 0)
+ mp_int_clear(TEMP(last));
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_mod(a, m, c) */
+
+mp_result mp_int_mod(mp_int a, mp_int m, mp_int c)
+{
+ mp_result res;
+ mpz_t tmp;
+ mp_int out;
+
+ if(m == c) {
+ mp_int_init(&tmp);
+ out = &tmp;
+ }
+ else {
+ out = c;
+ }
+
+ if((res = mp_int_div(a, m, NULL, out)) != MP_OK)
+ goto CLEANUP;
+
+ if(CMPZ(out) < 0)
+ res = mp_int_add(out, m, c);
+ else
+ res = mp_int_copy(out, c);
+
+ CLEANUP:
+ if(out != c)
+ mp_int_clear(&tmp);
+
+ return res;
+}
+
+/* }}} */
+
+
+/* {{{ mp_int_div_value(a, value, q, r) */
+
+mp_result mp_int_div_value(mp_int a, int value, mp_int q, int *r)
+{
+ mpz_t vtmp, rtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+ mp_result res;
+
+ mp_int_init(&rtmp);
+ s_fake(&vtmp, value, vbuf);
+
+ if((res = mp_int_div(a, &vtmp, q, &rtmp)) != MP_OK)
+ goto CLEANUP;
+
+ if(r)
+ (void) mp_int_to_int(&rtmp, r); /* can't fail */
+
+ CLEANUP:
+ mp_int_clear(&rtmp);
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_div_pow2(a, p2, q, r) */
+
+mp_result mp_int_div_pow2(mp_int a, int p2, mp_int q, mp_int r)
+{
+ mp_result res = MP_OK;
+
+ CHECK(a != NULL && p2 >= 0 && q != r);
+
+ if(q != NULL && (res = mp_int_copy(a, q)) == MP_OK)
+ s_qdiv(q, (mp_size) p2);
+
+ if(res == MP_OK && r != NULL && (res = mp_int_copy(a, r)) == MP_OK)
+ s_qmod(r, (mp_size) p2);
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_expt(a, b, c) */
+
+mp_result mp_int_expt(mp_int a, int b, mp_int c)
+{
+ mpz_t t;
+ mp_result res;
+ unsigned int v = abs(b);
+
+ CHECK(b >= 0 && c != NULL);
+
+ if((res = mp_int_init_copy(&t, a)) != MP_OK)
+ return res;
+
+ (void) mp_int_set_value(c, 1);
+ while(v != 0) {
+ if(v & 1) {
+ if((res = mp_int_mul(c, &t, c)) != MP_OK)
+ goto CLEANUP;
+ }
+
+ v >>= 1;
+ if(v == 0) break;
+
+ if((res = mp_int_sqr(&t, &t)) != MP_OK)
+ goto CLEANUP;
+ }
+
+ CLEANUP:
+ mp_int_clear(&t);
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_expt_value(a, b, c) */
+
+mp_result mp_int_expt_value(int a, int b, mp_int c)
+{
+ mpz_t t;
+ mp_result res;
+ unsigned int v = abs(b);
+
+ CHECK(b >= 0 && c != NULL);
+
+ if((res = mp_int_init_value(&t, a)) != MP_OK)
+ return res;
+
+ (void) mp_int_set_value(c, 1);
+ while(v != 0) {
+ if(v & 1) {
+ if((res = mp_int_mul(c, &t, c)) != MP_OK)
+ goto CLEANUP;
+ }
+
+ v >>= 1;
+ if(v == 0) break;
+
+ if((res = mp_int_sqr(&t, &t)) != MP_OK)
+ goto CLEANUP;
+ }
+
+ CLEANUP:
+ mp_int_clear(&t);
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_compare(a, b) */
+
+int mp_int_compare(mp_int a, mp_int b)
+{
+ mp_sign sa;
+
+ CHECK(a != NULL && b != NULL);
+
+ sa = MP_SIGN(a);
+ if(sa == MP_SIGN(b)) {
+ int cmp = s_ucmp(a, b);
+
+ /* If they're both zero or positive, the normal comparison
+ applies; if both negative, the sense is reversed. */
+ if(sa == MP_ZPOS)
+ return cmp;
+ else
+ return -cmp;
+
+ }
+ else {
+ if(sa == MP_ZPOS)
+ return 1;
+ else
+ return -1;
+ }
+}
+
+/* }}} */
+
+/* {{{ mp_int_compare_unsigned(a, b) */
+
+int mp_int_compare_unsigned(mp_int a, mp_int b)
+{
+ NRCHECK(a != NULL && b != NULL);
+
+ return s_ucmp(a, b);
+}
+
+/* }}} */
+
+/* {{{ mp_int_compare_zero(z) */
+
+int mp_int_compare_zero(mp_int z)
+{
+ NRCHECK(z != NULL);
+
+ if(MP_USED(z) == 1 && z->digits[0] == 0)
+ return 0;
+ else if(MP_SIGN(z) == MP_ZPOS)
+ return 1;
+ else
+ return -1;
+}
+
+/* }}} */
+
+/* {{{ mp_int_compare_value(z, value) */
+
+int mp_int_compare_value(mp_int z, int value)
+{
+ mp_sign vsign = (value < 0) ? MP_NEG : MP_ZPOS;
+ int cmp;
+
+ CHECK(z != NULL);
+
+ if(vsign == MP_SIGN(z)) {
+ cmp = s_vcmp(z, value);
+
+ if(vsign == MP_ZPOS)
+ return cmp;
+ else
+ return -cmp;
+ }
+ else {
+ if(value < 0)
+ return 1;
+ else
+ return -1;
+ }
+}
+
+/* }}} */
+
+/* {{{ mp_int_exptmod(a, b, m, c) */
+
+mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, mp_int c)
+{
+ mp_result res;
+ mp_size um;
+ mpz_t temp[3];
+ mp_int s;
+ int last = 0;
+
+ CHECK(a != NULL && b != NULL && c != NULL && m != NULL);
+
+ /* Zero moduli and negative exponents are not considered. */
+ if(CMPZ(m) == 0)
+ return MP_UNDEF;
+ if(CMPZ(b) < 0)
+ return MP_RANGE;
+
+ um = MP_USED(m);
+ SETUP(mp_int_init_size(TEMP(0), 2 * um), last);
+ SETUP(mp_int_init_size(TEMP(1), 2 * um), last);
+
+ if(c == b || c == m) {
+ SETUP(mp_int_init_size(TEMP(2), 2 * um), last);
+ s = TEMP(2);
+ }
+ else {
+ s = c;
+ }
+
+ if((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP;
+
+ if((res = s_brmu(TEMP(1), m)) != MP_OK) goto CLEANUP;
+
+ if((res = s_embar(TEMP(0), b, m, TEMP(1), s)) != MP_OK)
+ goto CLEANUP;
+
+ res = mp_int_copy(s, c);
+
+ CLEANUP:
+ while(--last >= 0)
+ mp_int_clear(TEMP(last));
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_exptmod_evalue(a, value, m, c) */
+
+mp_result mp_int_exptmod_evalue(mp_int a, int value, mp_int m, mp_int c)
+{
+ mpz_t vtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+ s_fake(&vtmp, value, vbuf);
+
+ return mp_int_exptmod(a, &vtmp, m, c);
+}
+
+/* }}} */
+
+/* {{{ mp_int_exptmod_bvalue(v, b, m, c) */
+
+mp_result mp_int_exptmod_bvalue(int value, mp_int b,
+ mp_int m, mp_int c)
+{
+ mpz_t vtmp;
+ mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+ s_fake(&vtmp, value, vbuf);
+
+ return mp_int_exptmod(&vtmp, b, m, c);
+}
+
+/* }}} */
+
+/* {{{ mp_int_exptmod_known(a, b, m, mu, c) */
+
+mp_result mp_int_exptmod_known(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c)
+{
+ mp_result res;
+ mp_size um;
+ mpz_t temp[2];
+ mp_int s;
+ int last = 0;
+
+ CHECK(a && b && m && c);
+
+ /* Zero moduli and negative exponents are not considered. */
+ if(CMPZ(m) == 0)
+ return MP_UNDEF;
+ if(CMPZ(b) < 0)
+ return MP_RANGE;
+
+ um = MP_USED(m);
+ SETUP(mp_int_init_size(TEMP(0), 2 * um), last);
+
+ if(c == b || c == m) {
+ SETUP(mp_int_init_size(TEMP(1), 2 * um), last);
+ s = TEMP(1);
+ }
+ else {
+ s = c;
+ }
+
+ if((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP;
+
+ if((res = s_embar(TEMP(0), b, m, mu, s)) != MP_OK)
+ goto CLEANUP;
+
+ res = mp_int_copy(s, c);
+
+ CLEANUP:
+ while(--last >= 0)
+ mp_int_clear(TEMP(last));
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_redux_const(m, c) */
+
+mp_result mp_int_redux_const(mp_int m, mp_int c)
+{
+ CHECK(m != NULL && c != NULL && m != c);
+
+ return s_brmu(c, m);
+}
+
+/* }}} */
+
+/* {{{ mp_int_invmod(a, m, c) */
+
+mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c)
+{
+ mp_result res;
+ mp_sign sa;
+ int last = 0;
+ mpz_t temp[2];
+
+ CHECK(a != NULL && m != NULL && c != NULL);
+
+ if(CMPZ(a) == 0 || CMPZ(m) <= 0)
+ return MP_RANGE;
+
+ sa = MP_SIGN(a); /* need this for the result later */
+
+ for(last = 0; last < 2; ++last)
+ mp_int_init(TEMP(last));
+
+ if((res = mp_int_egcd(a, m, TEMP(0), TEMP(1), NULL)) != MP_OK)
+ goto CLEANUP;
+
+ if(mp_int_compare_value(TEMP(0), 1) != 0) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+
+ /* It is first necessary to constrain the value to the proper range */
+ if((res = mp_int_mod(TEMP(1), m, TEMP(1))) != MP_OK)
+ goto CLEANUP;
+
+ /* Now, if 'a' was originally negative, the value we have is
+ actually the magnitude of the negative representative; to get the
+ positive value we have to subtract from the modulus. Otherwise,
+ the value is okay as it stands.
+ */
+ if(sa == MP_NEG)
+ res = mp_int_sub(m, TEMP(1), c);
+ else
+ res = mp_int_copy(TEMP(1), c);
+
+ CLEANUP:
+ while(--last >= 0)
+ mp_int_clear(TEMP(last));
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_gcd(a, b, c) */
+
+/* Binary GCD algorithm due to Josef Stein, 1961 */
+mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c)
+{
+ int ca, cb, k = 0;
+ mpz_t u, v, t;
+ mp_result res;
+
+ CHECK(a != NULL && b != NULL && c != NULL);
+
+ ca = CMPZ(a);
+ cb = CMPZ(b);
+ if(ca == 0 && cb == 0)
+ return MP_UNDEF;
+ else if(ca == 0)
+ return mp_int_abs(b, c);
+ else if(cb == 0)
+ return mp_int_abs(a, c);
+
+ mp_int_init(&t);
+ if((res = mp_int_init_copy(&u, a)) != MP_OK)
+ goto U;
+ if((res = mp_int_init_copy(&v, b)) != MP_OK)
+ goto V;
+
+ MP_SIGN(&u) = MP_ZPOS; MP_SIGN(&v) = MP_ZPOS;
+
+ { /* Divide out common factors of 2 from u and v */
+ int div2_u = s_dp2k(&u), div2_v = s_dp2k(&v);
+
+ k = MIN(div2_u, div2_v);
+ s_qdiv(&u, (mp_size) k);
+ s_qdiv(&v, (mp_size) k);
+ }
+
+ if(mp_int_is_odd(&u)) {
+ if((res = mp_int_neg(&v, &t)) != MP_OK)
+ goto CLEANUP;
+ }
+ else {
+ if((res = mp_int_copy(&u, &t)) != MP_OK)
+ goto CLEANUP;
+ }
+
+ for(;;) {
+ s_qdiv(&t, s_dp2k(&t));
+
+ if(CMPZ(&t) > 0) {
+ if((res = mp_int_copy(&t, &u)) != MP_OK)
+ goto CLEANUP;
+ }
+ else {
+ if((res = mp_int_neg(&t, &v)) != MP_OK)
+ goto CLEANUP;
+ }
+
+ if((res = mp_int_sub(&u, &v, &t)) != MP_OK)
+ goto CLEANUP;
+
+ if(CMPZ(&t) == 0)
+ break;
+ }
+
+ if((res = mp_int_abs(&u, c)) != MP_OK)
+ goto CLEANUP;
+ if(!s_qmul(c, (mp_size) k))
+ res = MP_MEMORY;
+
+ CLEANUP:
+ mp_int_clear(&v);
+ V: mp_int_clear(&u);
+ U: mp_int_clear(&t);
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_egcd(a, b, c, x, y) */
+
+/* This is the binary GCD algorithm again, but this time we keep track
+ of the elementary matrix operations as we go, so we can get values
+ x and y satisfying c = ax + by.
+ */
+mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c,
+ mp_int x, mp_int y)
+{
+ int k, last = 0, ca, cb;
+ mpz_t temp[8];
+ mp_result res;
+
+ CHECK(a != NULL && b != NULL && c != NULL &&
+ (x != NULL || y != NULL));
+
+ ca = CMPZ(a);
+ cb = CMPZ(b);
+ if(ca == 0 && cb == 0)
+ return MP_UNDEF;
+ else if(ca == 0) {
+ if((res = mp_int_abs(b, c)) != MP_OK) return res;
+ mp_int_zero(x); (void) mp_int_set_value(y, 1); return MP_OK;
+ }
+ else if(cb == 0) {
+ if((res = mp_int_abs(a, c)) != MP_OK) return res;
+ (void) mp_int_set_value(x, 1); mp_int_zero(y); return MP_OK;
+ }
+
+ /* Initialize temporaries:
+ A:0, B:1, C:2, D:3, u:4, v:5, ou:6, ov:7 */
+ for(last = 0; last < 4; ++last)
+ mp_int_init(TEMP(last));
+ TEMP(0)->digits[0] = 1;
+ TEMP(3)->digits[0] = 1;
+
+ SETUP(mp_int_init_copy(TEMP(4), a), last);
+ SETUP(mp_int_init_copy(TEMP(5), b), last);
+
+ /* We will work with absolute values here */
+ MP_SIGN(TEMP(4)) = MP_ZPOS;
+ MP_SIGN(TEMP(5)) = MP_ZPOS;
+
+ { /* Divide out common factors of 2 from u and v */
+ int div2_u = s_dp2k(TEMP(4)), div2_v = s_dp2k(TEMP(5));
+
+ k = MIN(div2_u, div2_v);
+ s_qdiv(TEMP(4), k);
+ s_qdiv(TEMP(5), k);
+ }
+
+ SETUP(mp_int_init_copy(TEMP(6), TEMP(4)), last);
+ SETUP(mp_int_init_copy(TEMP(7), TEMP(5)), last);
+
+ for(;;) {
+ while(mp_int_is_even(TEMP(4))) {
+ s_qdiv(TEMP(4), 1);
+
+ if(mp_int_is_odd(TEMP(0)) || mp_int_is_odd(TEMP(1))) {
+ if((res = mp_int_add(TEMP(0), TEMP(7), TEMP(0))) != MP_OK)
+ goto CLEANUP;
+ if((res = mp_int_sub(TEMP(1), TEMP(6), TEMP(1))) != MP_OK)
+ goto CLEANUP;
+ }
+
+ s_qdiv(TEMP(0), 1);
+ s_qdiv(TEMP(1), 1);
+ }
+
+ while(mp_int_is_even(TEMP(5))) {
+ s_qdiv(TEMP(5), 1);
+
+ if(mp_int_is_odd(TEMP(2)) || mp_int_is_odd(TEMP(3))) {
+ if((res = mp_int_add(TEMP(2), TEMP(7), TEMP(2))) != MP_OK)
+ goto CLEANUP;
+ if((res = mp_int_sub(TEMP(3), TEMP(6), TEMP(3))) != MP_OK)
+ goto CLEANUP;
+ }
+
+ s_qdiv(TEMP(2), 1);
+ s_qdiv(TEMP(3), 1);
+ }
+
+ if(mp_int_compare(TEMP(4), TEMP(5)) >= 0) {
+ if((res = mp_int_sub(TEMP(4), TEMP(5), TEMP(4))) != MP_OK) goto CLEANUP;
+ if((res = mp_int_sub(TEMP(0), TEMP(2), TEMP(0))) != MP_OK) goto CLEANUP;
+ if((res = mp_int_sub(TEMP(1), TEMP(3), TEMP(1))) != MP_OK) goto CLEANUP;
+ }
+ else {
+ if((res = mp_int_sub(TEMP(5), TEMP(4), TEMP(5))) != MP_OK) goto CLEANUP;
+ if((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK) goto CLEANUP;
+ if((res = mp_int_sub(TEMP(3), TEMP(1), TEMP(3))) != MP_OK) goto CLEANUP;
+ }
+
+ if(CMPZ(TEMP(4)) == 0) {
+ if(x && (res = mp_int_copy(TEMP(2), x)) != MP_OK) goto CLEANUP;
+ if(y && (res = mp_int_copy(TEMP(3), y)) != MP_OK) goto CLEANUP;
+ if(c) {
+ if(!s_qmul(TEMP(5), k)) {
+ res = MP_MEMORY;
+ goto CLEANUP;
+ }
+
+ res = mp_int_copy(TEMP(5), c);
+ }
+
+ break;
+ }
+ }
+
+ CLEANUP:
+ while(--last >= 0)
+ mp_int_clear(TEMP(last));
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_divisible_value(a, v) */
+
+int mp_int_divisible_value(mp_int a, int v)
+{
+ int rem = 0;
+
+ if(mp_int_div_value(a, v, NULL, &rem) != MP_OK)
+ return 0;
+
+ return rem == 0;
+}
+
+/* }}} */
+
+/* {{{ mp_int_is_pow2(z) */
+
+int mp_int_is_pow2(mp_int z)
+{
+ CHECK(z != NULL);
+
+ return s_isp2(z);
+}
+
+/* }}} */
+
+/* {{{ mp_int_sqrt(a, c) */
+
+mp_result mp_int_sqrt(mp_int a, mp_int c)
+{
+ mp_result res = MP_OK;
+ mpz_t temp[2];
+ int last = 0;
+
+ CHECK(a != NULL && c != NULL);
+
+ /* The square root of a negative value does not exist in the integers. */
+ if(MP_SIGN(a) == MP_NEG)
+ return MP_UNDEF;
+
+ SETUP(mp_int_init_copy(TEMP(last), a), last);
+ SETUP(mp_int_init(TEMP(last)), last);
+
+ for(;;) {
+ if((res = mp_int_sqr(TEMP(0), TEMP(1))) != MP_OK)
+ goto CLEANUP;
+
+ if(mp_int_compare_unsigned(a, TEMP(1)) == 0) break;
+
+ if((res = mp_int_copy(a, TEMP(1))) != MP_OK)
+ goto CLEANUP;
+ if((res = mp_int_div(TEMP(1), TEMP(0), TEMP(1), NULL)) != MP_OK)
+ goto CLEANUP;
+ if((res = mp_int_add(TEMP(0), TEMP(1), TEMP(1))) != MP_OK)
+ goto CLEANUP;
+ if((res = mp_int_div_pow2(TEMP(1), 1, TEMP(1), NULL)) != MP_OK)
+ goto CLEANUP;
+
+ if(mp_int_compare_unsigned(TEMP(0), TEMP(1)) == 0) break;
+ if((res = mp_int_sub_value(TEMP(0), 1, TEMP(0))) != MP_OK) goto CLEANUP;
+ if(mp_int_compare_unsigned(TEMP(0), TEMP(1)) == 0) break;
+
+ if((res = mp_int_copy(TEMP(1), TEMP(0))) != MP_OK) goto CLEANUP;
+ }
+
+ res = mp_int_copy(TEMP(0), c);
+
+ CLEANUP:
+ while(--last >= 0)
+ mp_int_clear(TEMP(last));
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_to_int(z, out) */
+
+mp_result mp_int_to_int(mp_int z, int *out)
+{
+ unsigned int uv = 0;
+ mp_size uz;
+ mp_digit *dz;
+ mp_sign sz;
+
+ CHECK(z != NULL);
+
+ /* Make sure the value is representable as an int */
+ sz = MP_SIGN(z);
+ if((sz == MP_ZPOS && mp_int_compare_value(z, INT_MAX) > 0) ||
+ mp_int_compare_value(z, INT_MIN) < 0)
+ return MP_RANGE;
+
+ uz = MP_USED(z);
+ dz = MP_DIGITS(z) + uz - 1;
+
+ while(uz > 0) {
+ uv <<= MP_DIGIT_BIT/2;
+ uv = (uv << (MP_DIGIT_BIT/2)) | *dz--;
+ --uz;
+ }
+
+ if(out)
+ *out = (sz == MP_NEG) ? -(int)uv : (int)uv;
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_to_string(z, radix, str, limit) */
+
+mp_result mp_int_to_string(mp_int z, mp_size radix,
+ char *str, int limit)
+{
+ mp_result res;
+ int cmp = 0;
+
+ CHECK(z != NULL && str != NULL && limit >= 2);
+
+ if(radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
+ return MP_RANGE;
+
+ if(CMPZ(z) == 0) {
+ *str++ = s_val2ch(0, 1);
+ }
+ else {
+ mpz_t tmp;
+ char *h, *t;
+
+ if((res = mp_int_init_copy(&tmp, z)) != MP_OK)
+ return res;
+
+ if(MP_SIGN(z) == MP_NEG) {
+ *str++ = '-';
+ --limit;
+ }
+ h = str;
+
+ /* Generate digits in reverse order until finished or limit reached */
+ for(/* */; limit > 0; --limit) {
+ mp_digit d;
+
+ if((cmp = CMPZ(&tmp)) == 0)
+ break;
+
+ d = s_ddiv(&tmp, (mp_digit)radix);
+ *str++ = s_val2ch(d, 1);
+ }
+ t = str - 1;
+
+ /* Put digits back in correct output order */
+ while(h < t) {
+ char tc = *h;
+ *h++ = *t;
+ *t-- = tc;
+ }
+
+ mp_int_clear(&tmp);
+ }
+
+ *str = '\0';
+ if(cmp == 0)
+ return MP_OK;
+ else
+ return MP_TRUNC;
+}
+
+/* }}} */
+
+/* {{{ mp_int_string_len(z, radix) */
+
+mp_result mp_int_string_len(mp_int z, mp_size radix)
+{
+ int len;
+
+ CHECK(z != NULL);
+
+ if(radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
+ return MP_RANGE;
+
+ len = s_outlen(z, radix) + 1; /* for terminator */
+
+ /* Allow for sign marker on negatives */
+ if(MP_SIGN(z) == MP_NEG)
+ len += 1;
+
+ return len;
+}
+
+/* }}} */
+
+/* {{{ mp_int_read_string(z, radix, *str) */
+
+/* Read zero-terminated string into z */
+mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str)
+{
+ return mp_int_read_cstring(z, radix, str, NULL);
+
+}
+
+/* }}} */
+
+/* {{{ mp_int_read_cstring(z, radix, *str, **end) */
+
+mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, char **end)
+{
+ int ch;
+
+ CHECK(z != NULL && str != NULL);
+
+ if(radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
+ return MP_RANGE;
+
+ /* Skip leading whitespace */
+ while(isspace((int)*str))
+ ++str;
+
+ /* Handle leading sign tag (+/-, positive default) */
+ switch(*str) {
+ case '-':
+ MP_SIGN(z) = MP_NEG;
+ ++str;
+ break;
+ case '+':
+ ++str; /* fallthrough */
+ default:
+ MP_SIGN(z) = MP_ZPOS;
+ break;
+ }
+
+ /* Skip leading zeroes */
+ while((ch = s_ch2val(*str, radix)) == 0)
+ ++str;
+
+ /* Make sure there is enough space for the value */
+ if(!s_pad(z, s_inlen(strlen(str), radix)))
+ return MP_MEMORY;
+
+ MP_USED(z) = 1; z->digits[0] = 0;
+
+ while(*str != '\0' && ((ch = s_ch2val(*str, radix)) >= 0)) {
+ s_dmul(z, (mp_digit)radix);
+ s_dadd(z, (mp_digit)ch);
+ ++str;
+ }
+
+ CLAMP(z);
+
+ /* Override sign for zero, even if negative specified. */
+ if(CMPZ(z) == 0)
+ MP_SIGN(z) = MP_ZPOS;
+
+ if(end != NULL)
+ *end = (char *)str;
+
+ /* Return a truncation error if the string has unprocessed
+ characters remaining, so the caller can tell if the whole string
+ was done */
+ if(*str != '\0')
+ return MP_TRUNC;
+ else
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_count_bits(z) */
+
+mp_result mp_int_count_bits(mp_int z)
+{
+ mp_size nbits = 0, uz;
+ mp_digit d;
+
+ CHECK(z != NULL);
+
+ uz = MP_USED(z);
+ if(uz == 1 && z->digits[0] == 0)
+ return 1;
+
+ --uz;
+ nbits = uz * MP_DIGIT_BIT;
+ d = z->digits[uz];
+
+ while(d != 0) {
+ d >>= 1;
+ ++nbits;
+ }
+
+ return nbits;
+}
+
+/* }}} */
+
+/* {{{ mp_int_to_binary(z, buf, limit) */
+
+mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit)
+{
+ static const int PAD_FOR_2C = 1;
+
+ mp_result res;
+ int limpos = limit;
+
+ CHECK(z != NULL && buf != NULL);
+
+ res = s_tobin(z, buf, &limpos, PAD_FOR_2C);
+
+ if(MP_SIGN(z) == MP_NEG)
+ s_2comp(buf, limpos);
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_int_read_binary(z, buf, len) */
+
+mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len)
+{
+ mp_size need, i;
+ unsigned char *tmp;
+ mp_digit *dz;
+
+ CHECK(z != NULL && buf != NULL && len > 0);
+
+ /* Figure out how many digits are needed to represent this value */
+ need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT;
+ if(!s_pad(z, need))
+ return MP_MEMORY;
+
+ mp_int_zero(z);
+
+ /* If the high-order bit is set, take the 2's complement before
+ reading the value (it will be restored afterward) */
+ if(buf[0] >> (CHAR_BIT - 1)) {
+ MP_SIGN(z) = MP_NEG;
+ s_2comp(buf, len);
+ }
+
+ dz = MP_DIGITS(z);
+ for(tmp = buf, i = len; i > 0; --i, ++tmp) {
+ s_qmul(z, (mp_size) CHAR_BIT);
+ *dz |= *tmp;
+ }
+
+ /* Restore 2's complement if we took it before */
+ if(MP_SIGN(z) == MP_NEG)
+ s_2comp(buf, len);
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_binary_len(z) */
+
+mp_result mp_int_binary_len(mp_int z)
+{
+ mp_result res = mp_int_count_bits(z);
+ int bytes = mp_int_unsigned_len(z);
+
+ if(res <= 0)
+ return res;
+
+ bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT;
+
+ /* If the highest-order bit falls exactly on a byte boundary, we
+ need to pad with an extra byte so that the sign will be read
+ correctly when reading it back in. */
+ if(bytes * CHAR_BIT == res)
+ ++bytes;
+
+ return bytes;
+}
+
+/* }}} */
+
+/* {{{ mp_int_to_unsigned(z, buf, limit) */
+
+mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit)
+{
+ static const int NO_PADDING = 0;
+
+ CHECK(z != NULL && buf != NULL);
+
+ return s_tobin(z, buf, &limit, NO_PADDING);
+}
+
+/* }}} */
+
+/* {{{ mp_int_read_unsigned(z, buf, len) */
+
+mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len)
+{
+ mp_size need, i;
+ unsigned char *tmp;
+ mp_digit *dz;
+
+ CHECK(z != NULL && buf != NULL && len > 0);
+
+ /* Figure out how many digits are needed to represent this value */
+ need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT;
+ if(!s_pad(z, need))
+ return MP_MEMORY;
+
+ mp_int_zero(z);
+
+ dz = MP_DIGITS(z);
+ for(tmp = buf, i = len; i > 0; --i, ++tmp) {
+ (void) s_qmul(z, CHAR_BIT);
+ *dz |= *tmp;
+ }
+
+ return MP_OK;
+}
+
+/* }}} */
+
+/* {{{ mp_int_unsigned_len(z) */
+
+mp_result mp_int_unsigned_len(mp_int z)
+{
+ mp_result res = mp_int_count_bits(z);
+ int bytes;
+
+ if(res <= 0)
+ return res;
+
+ bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT;
+
+ return bytes;
+}
+
+/* }}} */
+
+/* {{{ mp_error_string(res) */
+
+const char *mp_error_string(mp_result res)
+{
+ int ix;
+ if(res > 0)
+ return s_unknown_err;
+
+ res = -res;
+ for(ix = 0; ix < res && s_error_msg[ix] != NULL; ++ix)
+ ;
+
+ if(s_error_msg[ix] != NULL)
+ return s_error_msg[ix];
+ else
+ return s_unknown_err;
+}
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* Private functions for internal use. These make assumptions. */
+
+/* {{{ s_alloc(num) */
+
+static mp_digit *s_alloc(mp_size num)
+{
+ mp_digit *out = malloc(num * sizeof(mp_digit));
+
+ assert(out != NULL); /* for debugging */
+
+ return out;
+}
+
+/* }}} */
+
+/* {{{ s_realloc(old, num) */
+
+static mp_digit *s_realloc(mp_digit *old, mp_size num)
+{
+ mp_digit *new = realloc(old, num * sizeof(mp_digit));
+
+ assert(new != NULL); /* for debugging */
+
+ return new;
+}
+
+/* }}} */
+
+/* {{{ s_free(ptr) */
+
+#if TRACEABLE_FREE
+static void s_free(void *ptr)
+{
+ free(ptr);
+}
+#endif
+
+/* }}} */
+
+/* {{{ s_pad(z, min) */
+
+int s_pad(mp_int z, mp_size min)
+{
+ if(MP_ALLOC(z) < min) {
+ mp_size nsize = ROUND_PREC(min);
+ mp_digit *tmp;
+
+ if((void *)z->digits == (void *)z) {
+ if((tmp = s_alloc(nsize)) == NULL)
+ return 0;
+
+ COPY(MP_DIGITS(z), tmp, MP_USED(z));
+ }
+ else if((tmp = s_realloc(MP_DIGITS(z), nsize)) == NULL)
+ return 0;
+
+ MP_DIGITS(z) = tmp;
+ MP_ALLOC(z) = nsize;
+ }
+
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ s_clamp(z) */
+
+#if TRACEABLE_CLAMP
+static void s_clamp(mp_int z)
+{
+ mp_size uz = MP_USED(z);
+ mp_digit *zd = MP_DIGITS(z) + uz - 1;
+
+ while(uz > 1 && (*zd-- == 0))
+ --uz;
+
+ MP_USED(z) = uz;
+}
+#endif
+
+/* }}} */
+
+/* {{{ s_fake(z, value, vbuf) */
+
+static void s_fake(mp_int z, int value, mp_digit vbuf[])
+{
+ mp_size uv = (mp_size) s_vpack(value, vbuf);
+
+ z->used = uv;
+ z->alloc = MP_VALUE_DIGITS(value);
+ z->sign = (value < 0) ? MP_NEG : MP_ZPOS;
+ z->digits = vbuf;
+}
+
+/* }}} */
+
+/* {{{ s_cdig(da, db, len) */
+
+static int s_cdig(mp_digit *da, mp_digit *db, mp_size len)
+{
+ mp_digit *dat = da + len - 1, *dbt = db + len - 1;
+
+ for(/* */; len != 0; --len, --dat, --dbt) {
+ if(*dat > *dbt)
+ return 1;
+ else if(*dat < *dbt)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* }}} */
+
+/* {{{ s_vpack(v, t[]) */
+
+static int s_vpack(int v, mp_digit t[])
+{
+ unsigned int uv = (unsigned int)((v < 0) ? -v : v);
+ int ndig = 0;
+
+ if(uv == 0)
+ t[ndig++] = 0;
+ else {
+ while(uv != 0) {
+ t[ndig++] = (mp_digit) uv;
+ uv >>= MP_DIGIT_BIT/2;
+ uv >>= MP_DIGIT_BIT/2;
+ }
+ }
+
+ return ndig;
+}
+
+/* }}} */
+
+/* {{{ s_ucmp(a, b) */
+
+static int s_ucmp(mp_int a, mp_int b)
+{
+ mp_size ua = MP_USED(a), ub = MP_USED(b);
+
+ if(ua > ub)
+ return 1;
+ else if(ub > ua)
+ return -1;
+ else
+ return s_cdig(MP_DIGITS(a), MP_DIGITS(b), ua);
+}
+
+/* }}} */
+
+/* {{{ s_vcmp(a, v) */
+
+static int s_vcmp(mp_int a, int v)
+{
+ mp_digit vdig[MP_VALUE_DIGITS(v)];
+ int ndig = 0;
+ mp_size ua = MP_USED(a);
+
+ ndig = s_vpack(v, vdig);
+
+ if(ua > ndig)
+ return 1;
+ else if(ua < ndig)
+ return -1;
+ else
+ return s_cdig(MP_DIGITS(a), vdig, ndig);
+}
+
+/* }}} */
+
+/* {{{ s_uadd(da, db, dc, size_a, size_b) */
+
+static mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b)
+{
+ mp_size pos;
+ mp_word w = 0;
+
+ /* Insure that da is the longer of the two to simplify later code */
+ if(size_b > size_a) {
+ SWAP(mp_digit *, da, db);
+ SWAP(mp_size, size_a, size_b);
+ }
+
+ /* Add corresponding digits until the shorter number runs out */
+ for(pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) {
+ w = w + (mp_word) *da + (mp_word) *db;
+ *dc = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ }
+
+ /* Propagate carries as far as necessary */
+ for(/* */; pos < size_a; ++pos, ++da, ++dc) {
+ w = w + *da;
+
+ *dc = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ }
+
+ /* Return carry out */
+ return (mp_digit)w;
+}
+
+/* }}} */
+
+/* {{{ s_usub(da, db, dc, size_a, size_b) */
+
+static void s_usub(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b)
+{
+ mp_size pos;
+ mp_word w = 0;
+
+ /* We assume that |a| >= |b| so this should definitely hold */
+ assert(size_a >= size_b);
+
+ /* Subtract corresponding digits and propagate borrow */
+ for(pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) {
+ w = ((mp_word)MP_DIGIT_MAX + 1 + /* MP_RADIX */
+ (mp_word)*da) - w - (mp_word)*db;
+
+ *dc = LOWER_HALF(w);
+ w = (UPPER_HALF(w) == 0);
+ }
+
+ /* Finish the subtraction for remaining upper digits of da */
+ for(/* */; pos < size_a; ++pos, ++da, ++dc) {
+ w = ((mp_word)MP_DIGIT_MAX + 1 + /* MP_RADIX */
+ (mp_word)*da) - w;
+
+ *dc = LOWER_HALF(w);
+ w = (UPPER_HALF(w) == 0);
+ }
+
+ /* If there is a borrow out at the end, it violates the precondition */
+ assert(w == 0);
+}
+
+/* }}} */
+
+/* {{{ s_kmul(da, db, dc, size_a, size_b) */
+
+static int s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b)
+{
+ mp_size bot_size;
+
+ /* Make sure b is the smaller of the two input values */
+ if(size_b > size_a) {
+ SWAP(mp_digit *, da, db);
+ SWAP(mp_size, size_a, size_b);
+ }
+
+ /* Insure that the bottom is the larger half in an odd-length split;
+ the code below relies on this being true.
+ */
+ bot_size = (size_a + 1) / 2;
+
+ /* If the values are big enough to bother with recursion, use the
+ Karatsuba algorithm to compute the product; otherwise use the
+ normal multiplication algorithm
+ */
+ if(multiply_threshold &&
+ size_a >= multiply_threshold &&
+ size_b > bot_size) {
+
+ mp_digit *t1, *t2, *t3, carry;
+
+ mp_digit *a_top = da + bot_size;
+ mp_digit *b_top = db + bot_size;
+
+ mp_size at_size = size_a - bot_size;
+ mp_size bt_size = size_b - bot_size;
+ mp_size buf_size = 2 * bot_size;
+
+ /* Do a single allocation for all three temporary buffers needed;
+ each buffer must be big enough to hold the product of two
+ bottom halves, and one buffer needs space for the completed
+ product; twice the space is plenty.
+ */
+ if((t1 = s_alloc(4 * buf_size)) == NULL) return 0;
+ t2 = t1 + buf_size;
+ t3 = t2 + buf_size;
+ ZERO(t1, 4 * buf_size);
+
+ /* t1 and t2 are initially used as temporaries to compute the inner product
+ (a1 + a0)(b1 + b0) = a1b1 + a1b0 + a0b1 + a0b0
+ */
+ carry = s_uadd(da, a_top, t1, bot_size, at_size); /* t1 = a1 + a0 */
+ t1[bot_size] = carry;
+
+ carry = s_uadd(db, b_top, t2, bot_size, bt_size); /* t2 = b1 + b0 */
+ t2[bot_size] = carry;
+
+ (void) s_kmul(t1, t2, t3, bot_size + 1, bot_size + 1); /* t3 = t1 * t2 */
+
+ /* Now we'll get t1 = a0b0 and t2 = a1b1, and subtract them out so that
+ we're left with only the pieces we want: t3 = a1b0 + a0b1
+ */
+ ZERO(t1, bot_size + 1);
+ ZERO(t2, bot_size + 1);
+ (void) s_kmul(da, db, t1, bot_size, bot_size); /* t1 = a0 * b0 */
+ (void) s_kmul(a_top, b_top, t2, at_size, bt_size); /* t2 = a1 * b1 */
+
+ /* Subtract out t1 and t2 to get the inner product */
+ s_usub(t3, t1, t3, buf_size + 2, buf_size);
+ s_usub(t3, t2, t3, buf_size + 2, buf_size);
+
+ /* Assemble the output value */
+ COPY(t1, dc, buf_size);
+ (void) s_uadd(t3, dc + bot_size, dc + bot_size,
+ buf_size + 1, buf_size + 1);
+
+ (void) s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size,
+ buf_size, buf_size);
+
+ s_free(t1); /* note t2 and t3 are just internal pointers to t1 */
+ }
+ else {
+ s_umul(da, db, dc, size_a, size_b);
+ }
+
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ s_umul(da, db, dc, size_a, size_b) */
+
+static void s_umul(mp_digit *da, mp_digit *db, mp_digit *dc,
+ mp_size size_a, mp_size size_b)
+{
+ mp_size a, b;
+ mp_word w;
+
+ for(a = 0; a < size_a; ++a, ++dc, ++da) {
+ mp_digit *dct = dc;
+ mp_digit *dbt = db;
+
+ if(*da == 0)
+ continue;
+
+ w = 0;
+ for(b = 0; b < size_b; ++b, ++dbt, ++dct) {
+ w = (mp_word)*da * (mp_word)*dbt + w + (mp_word)*dct;
+
+ *dct = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ }
+
+ *dct = (mp_digit)w;
+ }
+}
+
+/* }}} */
+
+/* {{{ s_ksqr(da, dc, size_a) */
+
+static int s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a)
+{
+ if(multiply_threshold && size_a > multiply_threshold) {
+ mp_size bot_size = (size_a + 1) / 2;
+ mp_digit *a_top = da + bot_size;
+ mp_digit *t1, *t2, *t3;
+ mp_size at_size = size_a - bot_size;
+ mp_size buf_size = 2 * bot_size;
+
+ if((t1 = s_alloc(4 * buf_size)) == NULL) return 0;
+ t2 = t1 + buf_size;
+ t3 = t2 + buf_size;
+ ZERO(t1, 4 * buf_size);
+
+ (void) s_ksqr(da, t1, bot_size); /* t1 = a0 ^ 2 */
+ (void) s_ksqr(a_top, t2, at_size); /* t2 = a1 ^ 2 */
+
+ (void) s_kmul(da, a_top, t3, bot_size, at_size); /* t3 = a0 * a1 */
+
+ /* Quick multiply t3 by 2, shifting left (can't overflow) */
+ {
+ int i, top = bot_size + at_size;
+ mp_word w, save = 0;
+
+ for(i = 0; i < top; ++i) {
+ w = t3[i];
+ w = (w << 1) | save;
+ t3[i] = LOWER_HALF(w);
+ save = UPPER_HALF(w);
+ }
+ t3[i] = LOWER_HALF(save);
+ }
+
+ /* Assemble the output value */
+ COPY(t1, dc, 2 * bot_size);
+ (void) s_uadd(t3, dc + bot_size, dc + bot_size,
+ buf_size + 1, buf_size + 1);
+
+ (void) s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size,
+ buf_size, buf_size);
+
+ free(t1); /* note that t2 and t2 are internal pointers only */
+
+ }
+ else {
+ s_usqr(da, dc, size_a);
+ }
+
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ s_usqr(da, dc, size_a) */
+
+static void s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a)
+{
+ mp_size i, j;
+ mp_word w;
+
+ for(i = 0; i < size_a; ++i, dc += 2, ++da) {
+ mp_digit *dct = dc, *dat = da;
+
+ if(*da == 0)
+ continue;
+
+ /* Take care of the first digit, no rollover */
+ w = (mp_word)*dat * (mp_word)*dat + (mp_word)*dct;
+ *dct = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ ++dat; ++dct;
+
+ for(j = i + 1; j < size_a; ++j, ++dat, ++dct) {
+ mp_word t = (mp_word)*da * (mp_word)*dat;
+ mp_word u = w + (mp_word)*dct, ov = 0;
+
+ /* Check if doubling t will overflow a word */
+ if(HIGH_BIT_SET(t))
+ ov = 1;
+
+ w = t + t;
+
+ /* Check if adding u to w will overflow a word */
+ if(ADD_WILL_OVERFLOW(w, u))
+ ov = 1;
+
+ w += u;
+
+ *dct = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ if(ov) {
+ w += MP_DIGIT_MAX; /* MP_RADIX */
+ ++w;
+ }
+ }
+
+ w = w + *dct;
+ *dct = (mp_digit)w;
+ while((w = UPPER_HALF(w)) != 0) {
+ ++dct; w = w + *dct;
+ *dct = LOWER_HALF(w);
+ }
+
+ assert(w == 0);
+ }
+}
+
+/* }}} */
+
+/* {{{ s_dadd(a, b) */
+
+static void s_dadd(mp_int a, mp_digit b)
+{
+ mp_word w = 0;
+ mp_digit *da = MP_DIGITS(a);
+ mp_size ua = MP_USED(a);
+
+ w = (mp_word)*da + b;
+ *da++ = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+
+ for(ua -= 1; ua > 0; --ua, ++da) {
+ w = (mp_word)*da + w;
+
+ *da = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ }
+
+ if(w) {
+ *da = (mp_digit)w;
+ MP_USED(a) += 1;
+ }
+}
+
+/* }}} */
+
+/* {{{ s_dmul(a, b) */
+
+static void s_dmul(mp_int a, mp_digit b)
+{
+ mp_word w = 0;
+ mp_digit *da = MP_DIGITS(a);
+ mp_size ua = MP_USED(a);
+
+ while(ua > 0) {
+ w = (mp_word)*da * b + w;
+ *da++ = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ --ua;
+ }
+
+ if(w) {
+ *da = (mp_digit)w;
+ MP_USED(a) += 1;
+ }
+}
+
+/* }}} */
+
+/* {{{ s_dbmul(da, b, dc, size_a) */
+
+static void s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc, mp_size size_a)
+{
+ mp_word w = 0;
+
+ while(size_a > 0) {
+ w = (mp_word)*da++ * (mp_word)b + w;
+
+ *dc++ = LOWER_HALF(w);
+ w = UPPER_HALF(w);
+ --size_a;
+ }
+
+ if(w)
+ *dc = LOWER_HALF(w);
+}
+
+/* }}} */
+
+/* {{{ s_ddiv(da, d, dc, size_a) */
+
+static mp_digit s_ddiv(mp_int a, mp_digit b)
+{
+ mp_word w = 0, qdigit;
+ mp_size ua = MP_USED(a);
+ mp_digit *da = MP_DIGITS(a) + ua - 1;
+
+ for(/* */; ua > 0; --ua, --da) {
+ w = (w << MP_DIGIT_BIT) | *da;
+
+ if(w >= b) {
+ qdigit = w / b;
+ w = w % b;
+ }
+ else {
+ qdigit = 0;
+ }
+
+ *da = (mp_digit)qdigit;
+ }
+
+ CLAMP(a);
+ return (mp_digit)w;
+}
+
+/* }}} */
+
+/* {{{ s_qdiv(z, p2) */
+
+static void s_qdiv(mp_int z, mp_size p2)
+{
+ mp_size ndig = p2 / MP_DIGIT_BIT, nbits = p2 % MP_DIGIT_BIT;
+ mp_size uz = MP_USED(z);
+
+ if(ndig) {
+ mp_size mark;
+ mp_digit *to, *from;
+
+ if(ndig >= uz) {
+ mp_int_zero(z);
+ return;
+ }
+
+ to = MP_DIGITS(z); from = to + ndig;
+
+ for(mark = ndig; mark < uz; ++mark)
+ *to++ = *from++;
+
+ MP_USED(z) = uz - ndig;
+ }
+
+ if(nbits) {
+ mp_digit d = 0, *dz, save;
+ mp_size up = MP_DIGIT_BIT - nbits;
+
+ uz = MP_USED(z);
+ dz = MP_DIGITS(z) + uz - 1;
+
+ for(/* */; uz > 0; --uz, --dz) {
+ save = *dz;
+
+ *dz = (*dz >> nbits) | (d << up);
+ d = save;
+ }
+
+ CLAMP(z);
+ }
+
+ if(MP_USED(z) == 1 && z->digits[0] == 0)
+ MP_SIGN(z) = MP_ZPOS;
+}
+
+/* }}} */
+
+/* {{{ s_qmod(z, p2) */
+
+static void s_qmod(mp_int z, mp_size p2)
+{
+ mp_size start = p2 / MP_DIGIT_BIT + 1, rest = p2 % MP_DIGIT_BIT;
+ mp_size uz = MP_USED(z);
+ mp_digit mask = (1 << rest) - 1;
+
+ if(start <= uz) {
+ MP_USED(z) = start;
+ z->digits[start - 1] &= mask;
+ CLAMP(z);
+ }
+}
+
+/* }}} */
+
+/* {{{ s_qmul(z, p2) */
+
+static int s_qmul(mp_int z, mp_size p2)
+{
+ mp_size uz, need, rest, extra, i;
+ mp_digit *from, *to, d;
+
+ if(p2 == 0)
+ return 1;
+
+ uz = MP_USED(z);
+ need = p2 / MP_DIGIT_BIT; rest = p2 % MP_DIGIT_BIT;
+
+ /* Figure out if we need an extra digit at the top end; this occurs
+ if the topmost `rest' bits of the high-order digit of z are not
+ zero, meaning they will be shifted off the end if not preserved */
+ extra = 0;
+ if(rest != 0) {
+ mp_digit *dz = MP_DIGITS(z) + uz - 1;
+
+ if((*dz >> (MP_DIGIT_BIT - rest)) != 0)
+ extra = 1;
+ }
+
+ if(!s_pad(z, uz + need + extra))
+ return 0;
+
+ /* If we need to shift by whole digits, do that in one pass, then
+ to back and shift by partial digits.
+ */
+ if(need > 0) {
+ from = MP_DIGITS(z) + uz - 1;
+ to = from + need;
+
+ for(i = 0; i < uz; ++i)
+ *to-- = *from--;
+
+ ZERO(MP_DIGITS(z), need);
+ uz += need;
+ }
+
+ if(rest) {
+ d = 0;
+ for(i = need, from = MP_DIGITS(z) + need; i < uz; ++i, ++from) {
+ mp_digit save = *from;
+
+ *from = (*from << rest) | (d >> (MP_DIGIT_BIT - rest));
+ d = save;
+ }
+
+ d >>= (MP_DIGIT_BIT - rest);
+ if(d != 0) {
+ *from = d;
+ uz += extra;
+ }
+ }
+
+ MP_USED(z) = uz;
+ CLAMP(z);
+
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ s_qsub(z, p2) */
+
+/* Subtract |z| from 2^p2, assuming 2^p2 > |z|, and set z to be positive */
+static int s_qsub(mp_int z, mp_size p2)
+{
+ mp_digit hi = (1 << (p2 % MP_DIGIT_BIT)), *zp;
+ mp_size tdig = (p2 / MP_DIGIT_BIT), pos;
+ mp_word w = 0;
+
+ if(!s_pad(z, tdig + 1))
+ return 0;
+
+ for(pos = 0, zp = MP_DIGITS(z); pos < tdig; ++pos, ++zp) {
+ w = ((mp_word) MP_DIGIT_MAX + 1) - w - (mp_word)*zp;
+
+ *zp = LOWER_HALF(w);
+ w = UPPER_HALF(w) ? 0 : 1;
+ }
+
+ w = ((mp_word) MP_DIGIT_MAX + 1 + hi) - w - (mp_word)*zp;
+ *zp = LOWER_HALF(w);
+
+ assert(UPPER_HALF(w) != 0); /* no borrow out should be possible */
+
+ MP_SIGN(z) = MP_ZPOS;
+ CLAMP(z);
+
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ s_dp2k(z) */
+
+static int s_dp2k(mp_int z)
+{
+ int k = 0;
+ mp_digit *dp = MP_DIGITS(z), d;
+
+ if(MP_USED(z) == 1 && *dp == 0)
+ return 1;
+
+ while(*dp == 0) {
+ k += MP_DIGIT_BIT;
+ ++dp;
+ }
+
+ d = *dp;
+ while((d & 1) == 0) {
+ d >>= 1;
+ ++k;
+ }
+
+ return k;
+}
+
+/* }}} */
+
+/* {{{ s_isp2(z) */
+
+static int s_isp2(mp_int z)
+{
+ mp_size uz = MP_USED(z), k = 0;
+ mp_digit *dz = MP_DIGITS(z), d;
+
+ while(uz > 1) {
+ if(*dz++ != 0)
+ return -1;
+ k += MP_DIGIT_BIT;
+ --uz;
+ }
+
+ d = *dz;
+ while(d > 1) {
+ if(d & 1)
+ return -1;
+ ++k; d >>= 1;
+ }
+
+ return (int) k;
+}
+
+/* }}} */
+
+/* {{{ s_2expt(z, k) */
+
+static int s_2expt(mp_int z, int k)
+{
+ mp_size ndig, rest;
+ mp_digit *dz;
+
+ ndig = (k + MP_DIGIT_BIT) / MP_DIGIT_BIT;
+ rest = k % MP_DIGIT_BIT;
+
+ if(!s_pad(z, ndig))
+ return 0;
+
+ dz = MP_DIGITS(z);
+ ZERO(dz, ndig);
+ *(dz + ndig - 1) = (1 << rest);
+ MP_USED(z) = ndig;
+
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ s_norm(a, b) */
+
+static int s_norm(mp_int a, mp_int b)
+{
+ mp_digit d = b->digits[MP_USED(b) - 1];
+ int k = 0;
+
+ while(d < (mp_digit) (1 << (MP_DIGIT_BIT - 1))) { /* d < (MP_RADIX / 2) */
+ d <<= 1;
+ ++k;
+ }
+
+ /* These multiplications can't fail */
+ if(k != 0) {
+ (void) s_qmul(a, (mp_size) k);
+ (void) s_qmul(b, (mp_size) k);
+ }
+
+ return k;
+}
+
+/* }}} */
+
+/* {{{ s_brmu(z, m) */
+
+static mp_result s_brmu(mp_int z, mp_int m)
+{
+ mp_size um = MP_USED(m) * 2;
+
+ if(!s_pad(z, um))
+ return MP_MEMORY;
+
+ s_2expt(z, MP_DIGIT_BIT * um);
+ return mp_int_div(z, m, z, NULL);
+}
+
+/* }}} */
+
+/* {{{ s_reduce(x, m, mu, q1, q2) */
+
+static int s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2)
+{
+ mp_size um = MP_USED(m), umb_p1, umb_m1;
+
+ umb_p1 = (um + 1) * MP_DIGIT_BIT;
+ umb_m1 = (um - 1) * MP_DIGIT_BIT;
+
+ if(mp_int_copy(x, q1) != MP_OK)
+ return 0;
+
+ /* Compute q2 = floor((floor(x / b^(k-1)) * mu) / b^(k+1)) */
+ s_qdiv(q1, umb_m1);
+ UMUL(q1, mu, q2);
+ s_qdiv(q2, umb_p1);
+
+ /* Set x = x mod b^(k+1) */
+ s_qmod(x, umb_p1);
+
+ /* Now, q is a guess for the quotient a / m.
+ Compute x - q * m mod b^(k+1), replacing x. This may be off
+ by a factor of 2m, but no more than that.
+ */
+ UMUL(q2, m, q1);
+ s_qmod(q1, umb_p1);
+ (void) mp_int_sub(x, q1, x); /* can't fail */
+
+ /* The result may be < 0; if it is, add b^(k+1) to pin it in the
+ proper range. */
+ if((CMPZ(x) < 0) && !s_qsub(x, umb_p1))
+ return 0;
+
+ /* If x > m, we need to back it off until it is in range.
+ This will be required at most twice. */
+ if(mp_int_compare(x, m) >= 0)
+ (void) mp_int_sub(x, m, x);
+ if(mp_int_compare(x, m) >= 0)
+ (void) mp_int_sub(x, m, x);
+
+ /* At this point, x has been properly reduced. */
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ s_embar(a, b, m, mu, c) */
+
+/* Perform modular exponentiation using Barrett's method, where mu is
+ the reduction constant for m. Assumes a < m, b > 0. */
+mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c)
+{
+ mp_digit *db, *dbt, umu, d;
+ mpz_t temp[3];
+ mp_result res;
+ int last = 0;
+
+ umu = MP_USED(mu); db = MP_DIGITS(b); dbt = db + MP_USED(b) - 1;
+
+ while(last < 3)
+ SETUP(mp_int_init_size(TEMP(last), 4 * umu), last);
+
+ (void) mp_int_set_value(c, 1);
+
+ /* Take care of low-order digits */
+ while(db < dbt) {
+ int i;
+
+ for(d = *db, i = MP_DIGIT_BIT; i > 0; --i, d >>= 1) {
+ if(d & 1) {
+ /* The use of a second temporary avoids allocation */
+ UMUL(c, a, TEMP(0));
+ if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+ res = MP_MEMORY; goto CLEANUP;
+ }
+ mp_int_copy(TEMP(0), c);
+ }
+
+
+ USQR(a, TEMP(0));
+ assert(MP_SIGN(TEMP(0)) == MP_ZPOS);
+ if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+ res = MP_MEMORY; goto CLEANUP;
+ }
+ assert(MP_SIGN(TEMP(0)) == MP_ZPOS);
+ mp_int_copy(TEMP(0), a);
+
+
+ }
+
+ ++db;
+ }
+
+ /* Take care of highest-order digit */
+ d = *dbt;
+ for(;;) {
+ if(d & 1) {
+ UMUL(c, a, TEMP(0));
+ if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+ res = MP_MEMORY; goto CLEANUP;
+ }
+ mp_int_copy(TEMP(0), c);
+ }
+
+ d >>= 1;
+ if(!d) break;
+
+ USQR(a, TEMP(0));
+ if(!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+ res = MP_MEMORY; goto CLEANUP;
+ }
+ (void) mp_int_copy(TEMP(0), a);
+ }
+
+ CLEANUP:
+ while(--last >= 0)
+ mp_int_clear(TEMP(last));
+
+ return res;
+}
+
+/* }}} */
+
+/* {{{ s_udiv(a, b) */
+
+/* Precondition: a >= b and b > 0
+ Postcondition: a' = a / b, b' = a % b
+ */
+static mp_result s_udiv(mp_int a, mp_int b)
+{
+ mpz_t q, r, t;
+ mp_size ua, ub, qpos = 0;
+ mp_digit *da, btop;
+ mp_result res = MP_OK;
+ int k, skip = 0;
+
+ /* Force signs to positive */
+ MP_SIGN(a) = MP_ZPOS;
+ MP_SIGN(b) = MP_ZPOS;
+
+ /* Normalize, per Knuth */
+ k = s_norm(a, b);
+
+ ua = MP_USED(a); ub = MP_USED(b); btop = b->digits[ub - 1];
+ if((res = mp_int_init_size(&q, ua)) != MP_OK) return res;
+ if((res = mp_int_init_size(&t, ua + 1)) != MP_OK) goto CLEANUP;
+
+ da = MP_DIGITS(a);
+ r.digits = da + ua - 1; /* The contents of r are shared with a */
+ r.used = 1;
+ r.sign = MP_ZPOS;
+ r.alloc = MP_ALLOC(a);
+ ZERO(t.digits, t.alloc);
+
+ /* Solve for quotient digits, store in q.digits in reverse order */
+ while(r.digits >= da) {
+ if (qpos > q.alloc) {
+ char buf[1024];
+ printf("qpos = %d q.alloc = %d da = %d ua = %d\n",
+ (int)qpos, (int)q.alloc, (int)da, (int)ua);
+ mp_int_to_string(a, 10, buf, sizeof(buf));
+ printf("a = %s\n", buf);
+ mp_int_to_string(b, 10, buf, sizeof(buf));
+ printf("b = %s\n", buf);
+ assert(qpos <= q.alloc);
+ }
+
+ if(s_ucmp(b, &r) > 0) {
+ r.digits -= 1;
+ r.used += 1;
+
+ if(++skip > 1)
+ q.digits[qpos++] = 0;
+
+ CLAMP(&r);
+ }
+ else {
+ mp_word pfx = r.digits[r.used - 1];
+ mp_word qdigit;
+
+ if(r.used > 1 && (pfx < btop || r.digits[r.used - 2] == 0)) {
+ pfx <<= MP_DIGIT_BIT / 2;
+ pfx <<= MP_DIGIT_BIT / 2;
+ pfx |= r.digits[r.used - 2];
+ }
+
+ qdigit = pfx / btop;
+ if(qdigit > MP_DIGIT_MAX)
+ qdigit = 1;
+
+ s_dbmul(MP_DIGITS(b), (mp_digit) qdigit, t.digits, ub);
+ t.used = ub + 1; CLAMP(&t);
+ while(s_ucmp(&t, &r) > 0) {
+ --qdigit;
+ (void) mp_int_sub(&t, b, &t); /* cannot fail */
+ }
+
+ s_usub(r.digits, t.digits, r.digits, r.used, t.used);
+ CLAMP(&r);
+
+ q.digits[qpos++] = (mp_digit) qdigit;
+ ZERO(t.digits, t.used);
+ skip = 0;
+ }
+ }
+
+ /* Put quotient digits in the correct order, and discard extra zeroes */
+ q.used = qpos;
+ REV(mp_digit, q.digits, qpos);
+ CLAMP(&q);
+
+ /* Denormalize the remainder */
+ CLAMP(a);
+ if(k != 0)
+ s_qdiv(a, k);
+
+ mp_int_copy(a, b); /* ok: 0 <= r < b */
+ mp_int_copy(&q, a); /* ok: q <= a */
+
+ mp_int_clear(&t);
+ CLEANUP:
+ mp_int_clear(&q);
+ return res;
+}
+
+/* }}} */
+
+/* {{{ s_outlen(z, r) */
+
+/* Precondition: 2 <= r < 64 */
+static int s_outlen(mp_int z, mp_size r)
+{
+ mp_result bits;
+ double raw;
+
+ bits = mp_int_count_bits(z);
+ raw = (double)bits * s_log2[r];
+
+ return (int)(raw + 0.999999);
+}
+
+/* }}} */
+
+/* {{{ s_inlen(len, r) */
+
+static mp_size s_inlen(int len, mp_size r)
+{
+ double raw = (double)len / s_log2[r];
+ mp_size bits = (mp_size)(raw + 0.5);
+
+ return (mp_size)((bits + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT);
+}
+
+/* }}} */
+
+/* {{{ s_ch2val(c, r) */
+
+static int s_ch2val(char c, int r)
+{
+ int out;
+
+ if(isdigit((unsigned char) c))
+ out = c - '0';
+ else if(r > 10 && isalpha((unsigned char) c))
+ out = toupper(c) - 'A' + 10;
+ else
+ return -1;
+
+ return (out >= r) ? -1 : out;
+}
+
+/* }}} */
+
+/* {{{ s_val2ch(v, caps) */
+
+static char s_val2ch(int v, int caps)
+{
+ assert(v >= 0);
+
+ if(v < 10)
+ return v + '0';
+ else {
+ char out = (v - 10) + 'a';
+
+ if(caps)
+ return toupper(out);
+ else
+ return out;
+ }
+}
+
+/* }}} */
+
+/* {{{ s_2comp(buf, len) */
+
+static void s_2comp(unsigned char *buf, int len)
+{
+ int i;
+ unsigned short s = 1;
+
+ for(i = len - 1; i >= 0; --i) {
+ unsigned char c = ~buf[i];
+
+ s = c + s;
+ c = s & UCHAR_MAX;
+ s >>= CHAR_BIT;
+
+ buf[i] = c;
+ }
+
+ /* last carry out is ignored */
+}
+
+/* }}} */
+
+/* {{{ s_tobin(z, buf, *limpos) */
+
+static mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad)
+{
+ mp_size uz;
+ mp_digit *dz;
+ int pos = 0, limit = *limpos;
+
+ uz = MP_USED(z); dz = MP_DIGITS(z);
+ while(uz > 0 && pos < limit) {
+ mp_digit d = *dz++;
+ int i;
+
+ for(i = sizeof(mp_digit); i > 0 && pos < limit; --i) {
+ buf[pos++] = (unsigned char)d;
+ d >>= CHAR_BIT;
+
+ /* Don't write leading zeroes */
+ if(d == 0 && uz == 1)
+ i = 0; /* exit loop without signaling truncation */
+ }
+
+ /* Detect truncation (loop exited with pos >= limit) */
+ if(i > 0) break;
+
+ --uz;
+ }
+
+ if(pad != 0 && (buf[pos - 1] >> (CHAR_BIT - 1))) {
+ if(pos < limit)
+ buf[pos++] = 0;
+ else
+ uz = 1;
+ }
+
+ /* Digits are in reverse order, fix that */
+ REV(unsigned char, buf, pos);
+
+ /* Return the number of bytes actually written */
+ *limpos = pos;
+
+ return (uz == 0) ? MP_OK : MP_TRUNC;
+}
+
+/* }}} */
+
+/* {{{ s_print(tag, z) */
+
+#if DEBUG
+void s_print(char *tag, mp_int z)
+{
+ int i;
+
+ fprintf(stderr, "%s: %c ", tag,
+ (MP_SIGN(z) == MP_NEG) ? '-' : '+');
+
+ for(i = MP_USED(z) - 1; i >= 0; --i)
+ fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), z->digits[i]);
+
+ fputc('\n', stderr);
+
+}
+
+void s_print_buf(char *tag, mp_digit *buf, mp_size num)
+{
+ int i;
+
+ fprintf(stderr, "%s: ", tag);
+
+ for(i = num - 1; i >= 0; --i)
+ fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), buf[i]);
+
+ fputc('\n', stderr);
+}
+#endif
+
+/* }}} */
+
+/* HERE THERE BE DRAGONS */
diff --git a/source4/heimdal/lib/des/imath/imath.h b/source4/heimdal/lib/des/imath/imath.h
new file mode 100755
index 00000000000..93cc35654d4
--- /dev/null
+++ b/source4/heimdal/lib/des/imath/imath.h
@@ -0,0 +1,220 @@
+/*
+ Name: imath.h
+ Purpose: Arbitrary precision integer arithmetic routines.
+ Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/>
+ Info: $Id: imath.h,v 1.3 2006/10/21 16:32:15 lha Exp $
+
+ Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+#ifndef IMATH_H_
+#define IMATH_H_
+
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char mp_sign;
+typedef unsigned int mp_size;
+typedef int mp_result;
+#ifdef USE_LONG_LONG
+typedef unsigned int mp_digit;
+typedef unsigned long long mp_word;
+#else
+typedef unsigned short mp_digit;
+typedef unsigned int mp_word;
+#endif
+
+typedef struct mpz {
+ mp_digit single;
+ mp_digit *digits;
+ mp_size alloc;
+ mp_size used;
+ mp_sign sign;
+} mpz_t, *mp_int;
+
+#define MP_DIGITS(Z) ((Z)->digits)
+#define MP_ALLOC(Z) ((Z)->alloc)
+#define MP_USED(Z) ((Z)->used)
+#define MP_SIGN(Z) ((Z)->sign)
+
+extern const mp_result MP_OK;
+extern const mp_result MP_FALSE;
+extern const mp_result MP_TRUE;
+extern const mp_result MP_MEMORY;
+extern const mp_result MP_RANGE;
+extern const mp_result MP_UNDEF;
+extern const mp_result MP_TRUNC;
+extern const mp_result MP_BADARG;
+
+#define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT)
+#define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT)
+
+#ifdef USE_LONG_LONG
+# ifndef ULONG_LONG_MAX
+# ifdef ULLONG_MAX
+# define ULONG_LONG_MAX ULLONG_MAX
+# else
+# error "Maximum value of unsigned long long not defined!"
+# endif
+# endif
+# define MP_DIGIT_MAX (ULONG_MAX * 1ULL)
+# define MP_WORD_MAX ULONG_LONG_MAX
+#else
+# define MP_DIGIT_MAX (USHRT_MAX * 1UL)
+# define MP_WORD_MAX (UINT_MAX * 1UL)
+#endif
+
+#define MP_MIN_RADIX 2
+#define MP_MAX_RADIX 36
+
+/* Values with fewer than this many significant digits use the
+ standard multiplication algorithm; otherwise, a recursive algorithm
+ is used. Choose a value to suit your platform.
+ */
+#define MP_MULT_THRESH 32
+
+#define MP_DEFAULT_PREC 8 /* default memory allocation, in digits */
+
+extern const mp_sign MP_NEG;
+extern const mp_sign MP_ZPOS;
+
+#define mp_int_is_odd(Z) ((Z)->digits[0] & 1)
+#define mp_int_is_even(Z) !((Z)->digits[0] & 1)
+
+mp_result mp_int_init(mp_int z);
+mp_int mp_int_alloc(void);
+mp_result mp_int_init_size(mp_int z, mp_size prec);
+mp_result mp_int_init_copy(mp_int z, mp_int old);
+mp_result mp_int_init_value(mp_int z, int value);
+mp_result mp_int_set_value(mp_int z, int value);
+void mp_int_clear(mp_int z);
+void mp_int_free(mp_int z);
+
+mp_result mp_int_copy(mp_int a, mp_int c); /* c = a */
+void mp_int_swap(mp_int a, mp_int c); /* swap a, c */
+void mp_int_zero(mp_int z); /* z = 0 */
+mp_result mp_int_abs(mp_int a, mp_int c); /* c = |a| */
+mp_result mp_int_neg(mp_int a, mp_int c); /* c = -a */
+mp_result mp_int_add(mp_int a, mp_int b, mp_int c); /* c = a + b */
+mp_result mp_int_add_value(mp_int a, int value, mp_int c);
+mp_result mp_int_sub(mp_int a, mp_int b, mp_int c); /* c = a - b */
+mp_result mp_int_sub_value(mp_int a, int value, mp_int c);
+mp_result mp_int_mul(mp_int a, mp_int b, mp_int c); /* c = a * b */
+mp_result mp_int_mul_value(mp_int a, int value, mp_int c);
+mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c);
+mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */
+mp_result mp_int_div(mp_int a, mp_int b, /* q = a / b */
+ mp_int q, mp_int r); /* r = a % b */
+mp_result mp_int_div_value(mp_int a, int value, /* q = a / value */
+ mp_int q, int *r); /* r = a % value */
+mp_result mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */
+ mp_int q, mp_int r); /* r = q % 2^p2 */
+mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); /* c = a % m */
+#define mp_int_mod_value(A, V, R) mp_int_div_value((A), (V), 0, (R))
+mp_result mp_int_expt(mp_int a, int b, mp_int c); /* c = a^b */
+mp_result mp_int_expt_value(int a, int b, mp_int c); /* c = a^b */
+
+int mp_int_compare(mp_int a, mp_int b); /* a <=> b */
+int mp_int_compare_unsigned(mp_int a, mp_int b); /* |a| <=> |b| */
+int mp_int_compare_zero(mp_int z); /* a <=> 0 */
+int mp_int_compare_value(mp_int z, int value); /* a <=> v */
+
+/* Returns true if v|a, false otherwise (including errors) */
+int mp_int_divisible_value(mp_int a, int v);
+
+/* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */
+int mp_int_is_pow2(mp_int z);
+
+mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m,
+ mp_int c); /* c = a^b (mod m) */
+mp_result mp_int_exptmod_evalue(mp_int a, int value,
+ mp_int m, mp_int c); /* c = a^v (mod m) */
+mp_result mp_int_exptmod_bvalue(int value, mp_int b,
+ mp_int m, mp_int c); /* c = v^b (mod m) */
+mp_result mp_int_exptmod_known(mp_int a, mp_int b,
+ mp_int m, mp_int mu,
+ mp_int c); /* c = a^b (mod m) */
+mp_result mp_int_redux_const(mp_int m, mp_int c);
+
+mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); /* c = 1/a (mod m) */
+
+mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c); /* c = gcd(a, b) */
+
+mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */
+ mp_int x, mp_int y); /* c = ax + by */
+
+mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */
+
+/* Convert to an int, if representable (returns MP_RANGE if not). */
+mp_result mp_int_to_int(mp_int z, int *out);
+
+/* Convert to nul-terminated string with the specified radix, writing at
+ most limit characters including the nul terminator */
+mp_result mp_int_to_string(mp_int z, mp_size radix,
+ char *str, int limit);
+
+/* Return the number of characters required to represent
+ z in the given radix. May over-estimate. */
+mp_result mp_int_string_len(mp_int z, mp_size radix);
+
+/* Read zero-terminated string into z */
+mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str);
+mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str,
+ char **end);
+
+/* Return the number of significant bits in z */
+mp_result mp_int_count_bits(mp_int z);
+
+/* Convert z to two's complement binary, writing at most limit bytes */
+mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit);
+
+/* Read a two's complement binary value into z from the given buffer */
+mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len);
+
+/* Return the number of bytes required to represent z in binary. */
+mp_result mp_int_binary_len(mp_int z);
+
+/* Convert z to unsigned binary, writing at most limit bytes */
+mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit);
+
+/* Read an unsigned binary value into z from the given buffer */
+mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len);
+
+/* Return the number of bytes required to represent z as unsigned output */
+mp_result mp_int_unsigned_len(mp_int z);
+
+/* Return a statically allocated string describing error code res */
+const char *mp_error_string(mp_result res);
+
+#if DEBUG
+void s_print(char *tag, mp_int z);
+void s_print_buf(char *tag, mp_digit *buf, mp_size num);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* end IMATH_H_ */
diff --git a/source4/heimdal/lib/des/imath/iprime.c b/source4/heimdal/lib/des/imath/iprime.c
new file mode 100755
index 00000000000..582ade0f542
--- /dev/null
+++ b/source4/heimdal/lib/des/imath/iprime.c
@@ -0,0 +1,186 @@
+/*
+ Name: iprime.c
+ Purpose: Pseudoprimality testing routines
+ Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/>
+ Info: $Id: iprime.c,v 1.5 2007/01/05 21:01:48 lha Exp $
+
+ Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+#include "iprime.h"
+#include <stdlib.h>
+
+static const int s_ptab[] = {
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
+ 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
+ 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
+ 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263,
+ 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
+ 331, 337, 347, 349, 353, 359, 367, 373, 379, 383,
+ 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
+ 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
+ 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
+ 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
+ 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
+ 709, 719, 727, 733, 739, 743, 751, 757, 761, 769,
+ 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
+ 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
+ 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
+ 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
+ 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091,
+ 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
+ 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
+ 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277,
+ 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307,
+ 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
+ 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
+ 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493,
+ 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559,
+ 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609,
+ 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
+ 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
+ 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
+ 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871,
+ 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931,
+ 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997,
+ 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
+ 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111,
+ 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161,
+ 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
+ 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297,
+ 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
+ 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411,
+ 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
+ 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
+ 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633,
+ 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
+ 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729,
+ 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791,
+ 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851,
+ 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917,
+ 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
+ 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061,
+ 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137,
+ 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209,
+ 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271,
+ 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
+ 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
+ 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467,
+ 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533,
+ 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583,
+ 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
+ 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709,
+ 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779,
+ 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851,
+ 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917,
+ 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
+ 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049,
+ 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111,
+ 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
+ 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
+ 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
+ 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391,
+ 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457,
+ 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519,
+ 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597,
+ 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
+ 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729,
+ 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799,
+ 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889,
+ 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951,
+ 4957, 4967, 4969, 4973, 4987, 4993, 4999
+};
+static const int s_ptab_size = sizeof(s_ptab)/sizeof(s_ptab[0]);
+
+
+/* {{{ mp_int_is_prime(z) */
+
+/* Test whether z is likely to be prime:
+ MP_TRUE means it is probably prime
+ MP_FALSE means it is definitely composite
+ */
+mp_result mp_int_is_prime(mp_int z)
+{
+ int i, rem;
+ mp_result res;
+
+ /* First check for divisibility by small primes; this eliminates a
+ large number of composite candidates quickly
+ */
+ for(i = 0; i < s_ptab_size; ++i) {
+ if((res = mp_int_div_value(z, s_ptab[i], NULL, &rem)) != MP_OK)
+ return res;
+
+ if(rem == 0)
+ return MP_FALSE;
+ }
+
+ /* Now try Fermat's test for several prime witnesses (since we now
+ know from the above that z is not a multiple of any of them)
+ */
+ {
+ mpz_t tmp;
+
+ if((res = mp_int_init(&tmp)) != MP_OK) return res;
+
+ for(i = 0; i < 10 && i < s_ptab_size; ++i) {
+ if((res = mp_int_exptmod_bvalue(s_ptab[i], z, z, &tmp)) != MP_OK)
+ return res;
+
+ if(mp_int_compare_value(&tmp, s_ptab[i]) != 0) {
+ mp_int_clear(&tmp);
+ return MP_FALSE;
+ }
+ }
+
+ mp_int_clear(&tmp);
+ }
+
+ return MP_TRUE;
+}
+
+/* }}} */
+
+/* {{{ mp_int_find_prime(z) */
+
+/* Find the first apparent prime in ascending order from z */
+mp_result mp_int_find_prime(mp_int z)
+{
+ mp_result res;
+
+ if(mp_int_is_even(z) && ((res = mp_int_add_value(z, 1, z)) != MP_OK))
+ return res;
+
+ while((res = mp_int_is_prime(z)) == MP_FALSE) {
+ if((res = mp_int_add_value(z, 2, z)) != MP_OK)
+ break;
+
+ }
+
+ return res;
+}
+
+/* }}} */
+
+/* Here there be dragons */
diff --git a/source4/heimdal/lib/des/imath/iprime.h b/source4/heimdal/lib/des/imath/iprime.h
new file mode 100755
index 00000000000..cd54a731278
--- /dev/null
+++ b/source4/heimdal/lib/des/imath/iprime.h
@@ -0,0 +1,51 @@
+/*
+ Name: iprime.h
+ Purpose: Pseudoprimality testing routines
+ Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/>
+ Info: $Id: iprime.h,v 1.3 2006/10/21 16:32:30 lha Exp $
+
+ Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+#ifndef IPRIME_H_
+#define IPRIME_H_
+
+#include "imath.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Test whether z is likely to be prime
+ MP_YES means it is probably prime
+ MP_NO means it is definitely composite
+ */
+mp_result mp_int_is_prime(mp_int z);
+
+/* Find the first apparent prime in ascending order from z */
+mp_result mp_int_find_prime(mp_int z);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* IPRIME_H_ */
diff --git a/source4/heimdal/lib/des/pkcs12.c b/source4/heimdal/lib/des/pkcs12.c
new file mode 100644
index 00000000000..cc922857545
--- /dev/null
+++ b/source4/heimdal/lib/des/pkcs12.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id: pkcs12.c,v 1.1 2006/01/13 08:26:49 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <pkcs12.h>
+#include <bn.h>
+
+#include <roken.h>
+
+int
+PKCS12_key_gen(const void *key, size_t keylen,
+ const void *salt, size_t saltlen,
+ int id, int iteration, size_t outkeysize,
+ void *out, const EVP_MD *md)
+{
+ unsigned char *v, *I, hash[EVP_MAX_MD_SIZE];
+ unsigned int size, size_I = 0;
+ unsigned char idc = id;
+ EVP_MD_CTX ctx;
+ unsigned char *outp = out;
+ int i, vlen;
+
+ EVP_MD_CTX_init(&ctx);
+
+ vlen = EVP_MD_block_size(md);
+ v = malloc(vlen + 1);
+ if (v == NULL)
+ return 0;
+
+ I = calloc(1, vlen * 2);
+ if (I == NULL) {
+ free(v);
+ return 0;
+ }
+
+ if (salt && saltlen > 0) {
+ for (i = 0; i < vlen; i++)
+ I[i] = ((unsigned char*)salt)[i % saltlen];
+ size_I += vlen;
+ }
+ if (key && keylen > 0) {
+ for (i = 0; i < vlen / 2; i++) {
+ I[(i * 2) + size_I] = 0;
+ I[(i * 2) + size_I + 1] = ((unsigned char*)key)[i % (keylen + 1)];
+ }
+ size_I += vlen;
+ }
+
+ while (1) {
+ BIGNUM *bnB, *bnOne;
+
+ if (!EVP_DigestInit_ex(&ctx, md, NULL))
+ return 0;
+ for (i = 0; i < vlen; i++)
+ EVP_DigestUpdate(&ctx, &idc, 1);
+ EVP_DigestUpdate(&ctx, I, size_I);
+ EVP_DigestFinal_ex(&ctx, hash, &size);
+
+ for (i = 1; i < iteration; i++)
+ EVP_Digest(hash, size, hash, &size, md, NULL);
+
+ memcpy(outp, hash, min(outkeysize, size));
+ if (outkeysize < size)
+ break;
+ outkeysize -= size;
+ outp += size;
+
+ for (i = 0; i < vlen; i++)
+ v[i] = hash[i % size];
+
+ bnB = BN_bin2bn(v, vlen, NULL);
+ bnOne = BN_new();
+ BN_set_word(bnOne, 1);
+
+ BN_uadd(bnB, bnB, bnOne);
+
+ for (i = 0; i < vlen * 2; i += vlen) {
+ BIGNUM *bnI;
+ int j;
+
+ bnI = BN_bin2bn(I + i, vlen, NULL);
+
+ BN_uadd(bnI, bnI, bnB);
+
+ j = BN_num_bytes(bnI);
+ if (j > vlen) {
+ assert(j == vlen + 1);
+ BN_bn2bin(bnI, v);
+ memcpy(I + i, v + 1, vlen);
+ } else {
+ memset(I + i, 0, vlen - j);
+ BN_bn2bin(bnI, I + i + vlen - j);
+ }
+ BN_free(bnI);
+ }
+ BN_free(bnB);
+ BN_free(bnOne);
+ size_I = vlen * 2;
+ }
+
+ EVP_MD_CTX_cleanup(&ctx);
+ free(I);
+ free(v);
+
+ return 1;
+}
diff --git a/source4/heimdal/lib/des/resource.h b/source4/heimdal/lib/des/resource.h
new file mode 100644
index 00000000000..02c6a7c6d93
--- /dev/null
+++ b/source4/heimdal/lib/des/resource.h
@@ -0,0 +1,18 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by passwd_dialog.rc
+//
+#define IDD_PASSWD_DIALOG 101
+#define IDC_EDIT1 1000
+#define IDC_PASSWD_EDIT 1001
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1002
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/source4/heimdal/lib/des/rsa-imath.c b/source4/heimdal/lib/des/rsa-imath.c
new file mode 100644
index 00000000000..298affadfe6
--- /dev/null
+++ b/source4/heimdal/lib/des/rsa-imath.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id: rsa-imath.c,v 1.23 2007/01/06 13:45:25 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <krb5-types.h>
+#include <assert.h>
+
+#include <rsa.h>
+
+#include <roken.h>
+
+#include "imath/imath.h"
+#include "imath/iprime.h"
+
+static void
+BN2mpz(mpz_t *s, const BIGNUM *bn)
+{
+ size_t len;
+ void *p;
+
+ mp_int_init(s);
+
+ len = BN_num_bytes(bn);
+ p = malloc(len);
+ BN_bn2bin(bn, p);
+ mp_int_read_unsigned(s, p, len);
+ free(p);
+}
+
+static BIGNUM *
+mpz2BN(mpz_t *s)
+{
+ size_t size;
+ BIGNUM *bn;
+ void *p;
+
+ size = mp_int_unsigned_len(s);
+ p = malloc(size);
+ if (p == NULL && size != 0)
+ return NULL;
+ mp_int_to_unsigned(s, p, size);
+
+ bn = BN_bin2bn(p, size, NULL);
+ free(p);
+ return bn;
+}
+
+static int random_num(mp_int, size_t);
+
+static void
+setup_blind(mp_int n, mp_int b, mp_int bi)
+{
+ mp_int_init(b);
+ mp_int_init(bi);
+ random_num(b, mp_int_count_bits(n));
+ mp_int_mod(b, n, b);
+ mp_int_invmod(b, n, bi);
+}
+
+static void
+blind(mp_int in, mp_int b, mp_int e, mp_int n)
+{
+ mpz_t t1;
+ mp_int_init(&t1);
+ /* in' = (in * b^e) mod n */
+ mp_int_exptmod(b, e, n, &t1);
+ mp_int_mul(&t1, in, in);
+ mp_int_mod(in, n, in);
+ mp_int_clear(&t1);
+}
+
+static void
+unblind(mp_int out, mp_int bi, mp_int n)
+{
+ /* out' = (out * 1/b) mod n */
+ mp_int_mul(out, bi, out);
+ mp_int_mod(out, n, out);
+}
+
+static mp_result
+rsa_private_calculate(mp_int in, mp_int p, mp_int q,
+ mp_int dmp1, mp_int dmq1, mp_int iqmp,
+ mp_int out)
+{
+ mpz_t vp, vq, u;
+ mp_int_init(&vp); mp_int_init(&vq); mp_int_init(&u);
+
+ /* vq = c ^ (d mod (q - 1)) mod q */
+ /* vp = c ^ (d mod (p - 1)) mod p */
+ mp_int_mod(in, p, &u);
+ mp_int_exptmod(&u, dmp1, p, &vp);
+ mp_int_mod(in, q, &u);
+ mp_int_exptmod(&u, dmq1, q, &vq);
+
+ /* C2 = 1/q mod p (iqmp) */
+ /* u = (vp - vq)C2 mod p. */
+ mp_int_sub(&vp, &vq, &u);
+ if (mp_int_compare_zero(&u) < 0)
+ mp_int_add(&u, p, &u);
+ mp_int_mul(&u, iqmp, &u);
+ mp_int_mod(&u, p, &u);
+
+ /* c ^ d mod n = vq + u q */
+ mp_int_mul(&u, q, &u);
+ mp_int_add(&u, &vq, out);
+
+ mp_int_clear(&vp);
+ mp_int_clear(&vq);
+ mp_int_clear(&u);
+
+ return MP_OK;
+}
+
+/*
+ *
+ */
+
+static int
+imath_rsa_public_encrypt(int flen, const unsigned char* from,
+ unsigned char* to, RSA* rsa, int padding)
+{
+ unsigned char *p, *p0;
+ mp_result res;
+ size_t size, padlen;
+ mpz_t enc, dec, n, e;
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+
+ size = RSA_size(rsa);
+
+ if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen)
+ return -2;
+
+ BN2mpz(&n, rsa->n);
+ BN2mpz(&e, rsa->e);
+
+ p = p0 = malloc(size - 1);
+ if (p0 == NULL) {
+ mp_int_clear(&e);
+ mp_int_clear(&n);
+ return -3;
+ }
+
+ padlen = size - flen - 3;
+ assert(padlen >= 8);
+
+ *p++ = 2;
+ if (RAND_bytes(p, padlen) != 1) {
+ mp_int_clear(&e);
+ mp_int_clear(&n);
+ free(p0);
+ return -4;
+ }
+ while(padlen) {
+ if (*p == 0)
+ *p = 1;
+ padlen--;
+ p++;
+ }
+ *p++ = 0;
+ memcpy(p, from, flen);
+ p += flen;
+ assert((p - p0) == size - 1);
+
+ mp_int_init(&enc);
+ mp_int_init(&dec);
+ mp_int_read_unsigned(&dec, p0, size - 1);
+ free(p0);
+
+ res = mp_int_exptmod(&dec, &e, &n, &enc);
+
+ mp_int_clear(&dec);
+ mp_int_clear(&e);
+ mp_int_clear(&n);
+ {
+ size_t ssize;
+ ssize = mp_int_unsigned_len(&enc);
+ assert(size >= ssize);
+ mp_int_to_unsigned(&enc, to, ssize);
+ size = ssize;
+ }
+ mp_int_clear(&enc);
+
+ return size;
+}
+
+static int
+imath_rsa_public_decrypt(int flen, const unsigned char* from,
+ unsigned char* to, RSA* rsa, int padding)
+{
+ unsigned char *p;
+ mp_result res;
+ size_t size;
+ mpz_t s, us, n, e;
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+
+ if (flen > RSA_size(rsa))
+ return -2;
+
+ BN2mpz(&n, rsa->n);
+ BN2mpz(&e, rsa->e);
+
+#if 0
+ /* Check that the exponent is larger then 3 */
+ if (mp_int_compare_value(&e, 3) <= 0) {
+ mp_int_clear(&n);
+ mp_int_clear(&e);
+ return -3;
+ }
+#endif
+
+ mp_int_init(&s);
+ mp_int_init(&us);
+ mp_int_read_unsigned(&s, rk_UNCONST(from), flen);
+
+ if (mp_int_compare(&s, &n) >= 0) {
+ mp_int_clear(&n);
+ mp_int_clear(&e);
+ return -4;
+ }
+
+ res = mp_int_exptmod(&s, &e, &n, &us);
+
+ mp_int_clear(&s);
+ mp_int_clear(&n);
+ mp_int_clear(&e);
+
+ if (res != MP_OK)
+ return -5;
+ p = to;
+
+
+ size = mp_int_unsigned_len(&us);
+ assert(size <= RSA_size(rsa));
+ mp_int_to_unsigned(&us, p, size);
+
+ mp_int_clear(&us);
+
+ /* head zero was skipped by mp_int_to_unsigned */
+ if (*p == 0)
+ return -6;
+ if (*p != 1)
+ return -7;
+ size--; p++;
+ while (size && *p == 0xff) {
+ size--; p++;
+ }
+ if (size == 0 || *p != 0)
+ return -8;
+ size--; p++;
+
+ memmove(to, p, size);
+
+ return size;
+}
+
+static int
+imath_rsa_private_encrypt(int flen, const unsigned char* from,
+ unsigned char* to, RSA* rsa, int padding)
+{
+ unsigned char *p, *p0;
+ mp_result res;
+ size_t size;
+ mpz_t in, out, n, e, b, bi;
+ int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0;
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+
+ size = RSA_size(rsa);
+
+ if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen)
+ return -2;
+
+ p0 = p = malloc(size);
+ *p++ = 0;
+ *p++ = 1;
+ memset(p, 0xff, size - flen - 3);
+ p += size - flen - 3;
+ *p++ = 0;
+ memcpy(p, from, flen);
+ p += flen;
+ assert((p - p0) == size);
+
+ BN2mpz(&n, rsa->n);
+ BN2mpz(&e, rsa->e);
+
+ mp_int_init(&in);
+ mp_int_init(&out);
+ mp_int_read_unsigned(&in, p0, size);
+ free(p0);
+
+ if(mp_int_compare_zero(&in) < 0 ||
+ mp_int_compare(&in, &n) >= 0) {
+ size = 0;
+ goto out;
+ }
+
+ if (blinding) {
+ setup_blind(&n, &b, &bi);
+ blind(&in, &b, &e, &n);
+ }
+
+ if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) {
+ mpz_t p, q, dmp1, dmq1, iqmp;
+
+ BN2mpz(&p, rsa->p);
+ BN2mpz(&q, rsa->q);
+ BN2mpz(&dmp1, rsa->dmp1);
+ BN2mpz(&dmq1, rsa->dmq1);
+ BN2mpz(&iqmp, rsa->iqmp);
+
+ res = rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out);
+
+ mp_int_clear(&p);
+ mp_int_clear(&q);
+ mp_int_clear(&dmp1);
+ mp_int_clear(&dmq1);
+ mp_int_clear(&iqmp);
+ } else {
+ mpz_t d;
+
+ BN2mpz(&d, rsa->d);
+ res = mp_int_exptmod(&in, &d, &n, &out);
+ mp_int_clear(&d);
+ if (res != MP_OK) {
+ size = 0;
+ goto out;
+ }
+ }
+
+ if (blinding) {
+ unblind(&out, &bi, &n);
+ mp_int_clear(&b);
+ mp_int_clear(&bi);
+ }
+
+ {
+ size_t ssize;
+ ssize = mp_int_unsigned_len(&out);
+ assert(size >= ssize);
+ mp_int_to_unsigned(&out, to, size);
+ size = ssize;
+ }
+
+out:
+ mp_int_clear(&e);
+ mp_int_clear(&n);
+ mp_int_clear(&in);
+ mp_int_clear(&out);
+
+ return size;
+}
+
+static int
+imath_rsa_private_decrypt(int flen, const unsigned char* from,
+ unsigned char* to, RSA* rsa, int padding)
+{
+ unsigned char *ptr;
+ mp_result res;
+ size_t size;
+ mpz_t in, out, n, e, b, bi;
+ int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0;
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+
+ size = RSA_size(rsa);
+ if (flen > size)
+ return -2;
+
+ mp_int_init(&in);
+ mp_int_init(&out);
+
+ BN2mpz(&n, rsa->n);
+ BN2mpz(&e, rsa->e);
+
+ res = mp_int_read_unsigned(&in, rk_UNCONST(from), flen);
+ if (res != MP_OK) {
+ size = -1;
+ goto out;
+ }
+
+ if(mp_int_compare_zero(&in) < 0 ||
+ mp_int_compare(&in, &n) >= 0) {
+ size = 0;
+ goto out;
+ }
+
+ if (blinding) {
+ setup_blind(&n, &b, &bi);
+ blind(&in, &b, &e, &n);
+ }
+
+ if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) {
+ mpz_t p, q, dmp1, dmq1, iqmp;
+
+ BN2mpz(&p, rsa->p);
+ BN2mpz(&q, rsa->q);
+ BN2mpz(&dmp1, rsa->dmp1);
+ BN2mpz(&dmq1, rsa->dmq1);
+ BN2mpz(&iqmp, rsa->iqmp);
+
+ res = rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out);
+
+ mp_int_clear(&p);
+ mp_int_clear(&q);
+ mp_int_clear(&dmp1);
+ mp_int_clear(&dmq1);
+ mp_int_clear(&iqmp);
+ } else {
+ mpz_t d;
+
+ if(mp_int_compare_zero(&in) < 0 ||
+ mp_int_compare(&in, &n) >= 0)
+ return MP_RANGE;
+
+ BN2mpz(&d, rsa->d);
+ res = mp_int_exptmod(&in, &d, &n, &out);
+ mp_int_clear(&d);
+ if (res != MP_OK) {
+ size = 0;
+ goto out;
+ }
+ }
+
+ if (blinding) {
+ unblind(&out, &bi, &n);
+ mp_int_clear(&b);
+ mp_int_clear(&bi);
+ }
+
+ ptr = to;
+ {
+ size_t ssize;
+ ssize = mp_int_unsigned_len(&out);
+ assert(size >= ssize);
+ mp_int_to_unsigned(&out, ptr, ssize);
+ size = ssize;
+ }
+
+ /* head zero was skipped by mp_int_to_unsigned */
+ if (*ptr != 2)
+ return -3;
+ size--; ptr++;
+ while (size && *ptr != 0) {
+ size--; ptr++;
+ }
+ if (size == 0)
+ return -4;
+ size--; ptr++;
+
+ memmove(to, ptr, size);
+
+out:
+ mp_int_clear(&e);
+ mp_int_clear(&n);
+ mp_int_clear(&in);
+ mp_int_clear(&out);
+
+ return size;
+}
+
+static int
+random_num(mp_int num, size_t len)
+{
+ unsigned char *p;
+ mp_result res;
+
+ len = (len + 7) / 8;
+ p = malloc(len);
+ if (p == NULL)
+ return 1;
+ if (RAND_bytes(p, len) != 1) {
+ free(p);
+ return 1;
+ }
+ res = mp_int_read_unsigned(num, p, len);
+ free(p);
+ if (res != MP_OK)
+ return 1;
+ return 0;
+}
+
+#define CHECK(f, v) if ((f) != (v)) { goto out; }
+
+static int
+imath_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb)
+{
+ mpz_t el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3;
+ int counter, ret;
+
+ if (bits < 789)
+ return -1;
+
+ ret = -1;
+
+ mp_int_init(&el);
+ mp_int_init(&p);
+ mp_int_init(&q);
+ mp_int_init(&n);
+ mp_int_init(&d);
+ mp_int_init(&dmp1);
+ mp_int_init(&dmq1);
+ mp_int_init(&iqmp);
+ mp_int_init(&t1);
+ mp_int_init(&t2);
+ mp_int_init(&t3);
+
+ BN2mpz(&el, e);
+
+ /* generate p and q so that p != q and bits(pq) ~ bits */
+ counter = 0;
+ do {
+ BN_GENCB_call(cb, 2, counter++);
+ CHECK(random_num(&p, bits / 2 + 1), 0);
+ CHECK(mp_int_find_prime(&p), MP_TRUE);
+
+ CHECK(mp_int_sub_value(&p, 1, &t1), MP_OK);
+ CHECK(mp_int_gcd(&t1, &el, &t2), MP_OK);
+ } while(mp_int_compare_value(&t2, 1) != 0);
+
+ BN_GENCB_call(cb, 3, 0);
+
+ counter = 0;
+ do {
+ BN_GENCB_call(cb, 2, counter++);
+ CHECK(random_num(&q, bits / 2 + 1), 0);
+ CHECK(mp_int_find_prime(&q), MP_TRUE);
+
+ if (mp_int_compare(&p, &q) == 0) /* don't let p and q be the same */
+ continue;
+
+ CHECK(mp_int_sub_value(&q, 1, &t1), MP_OK);
+ CHECK(mp_int_gcd(&t1, &el, &t2), MP_OK);
+ } while(mp_int_compare_value(&t2, 1) != 0);
+
+ /* make p > q */
+ if (mp_int_compare(&p, &q) < 0)
+ mp_int_swap(&p, &q);
+
+ BN_GENCB_call(cb, 3, 1);
+
+ /* calculate n, n = p * q */
+ CHECK(mp_int_mul(&p, &q, &n), MP_OK);
+
+ /* calculate d, d = 1/e mod (p - 1)(q - 1) */
+ CHECK(mp_int_sub_value(&p, 1, &t1), MP_OK);
+ CHECK(mp_int_sub_value(&q, 1, &t2), MP_OK);
+ CHECK(mp_int_mul(&t1, &t2, &t3), MP_OK);
+ CHECK(mp_int_invmod(&el, &t3, &d), MP_OK);
+
+ /* calculate dmp1 dmp1 = d mod (p-1) */
+ CHECK(mp_int_mod(&d, &t1, &dmp1), MP_OK);
+ /* calculate dmq1 dmq1 = d mod (q-1) */
+ CHECK(mp_int_mod(&d, &t2, &dmq1), MP_OK);
+ /* calculate iqmp iqmp = 1/q mod p */
+ CHECK(mp_int_invmod(&q, &p, &iqmp), MP_OK);
+
+ /* fill in RSA key */
+
+ rsa->e = mpz2BN(&el);
+ rsa->p = mpz2BN(&p);
+ rsa->q = mpz2BN(&q);
+ rsa->n = mpz2BN(&n);
+ rsa->d = mpz2BN(&d);
+ rsa->dmp1 = mpz2BN(&dmp1);
+ rsa->dmq1 = mpz2BN(&dmq1);
+ rsa->iqmp = mpz2BN(&iqmp);
+
+ ret = 1;
+out:
+ mp_int_clear(&el);
+ mp_int_clear(&p);
+ mp_int_clear(&q);
+ mp_int_clear(&n);
+ mp_int_clear(&d);
+ mp_int_clear(&dmp1);
+ mp_int_clear(&dmq1);
+ mp_int_clear(&iqmp);
+ mp_int_clear(&t1);
+ mp_int_clear(&t2);
+ mp_int_clear(&t3);
+
+ return ret;
+}
+
+static int
+imath_rsa_init(RSA *rsa)
+{
+ return 1;
+}
+
+static int
+imath_rsa_finish(RSA *rsa)
+{
+ return 1;
+}
+
+const RSA_METHOD hc_rsa_imath_method = {
+ "hcrypto imath RSA",
+ imath_rsa_public_encrypt,
+ imath_rsa_public_decrypt,
+ imath_rsa_private_encrypt,
+ imath_rsa_private_decrypt,
+ NULL,
+ NULL,
+ imath_rsa_init,
+ imath_rsa_finish,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ imath_rsa_generate_key
+};
+
+const RSA_METHOD *
+RSA_imath_method(void)
+{
+ return &hc_rsa_imath_method;
+}
diff --git a/source4/heimdal/lib/des/rsa.c b/source4/heimdal/lib/des/rsa.c
new file mode 100644
index 00000000000..241afb2e463
--- /dev/null
+++ b/source4/heimdal/lib/des/rsa.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id: rsa.c,v 1.19 2007/01/09 10:04:20 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <krb5-types.h>
+#include <rfc2459_asn1.h>
+
+#include <rsa.h>
+
+#include <roken.h>
+
+RSA *
+RSA_new(void)
+{
+ return RSA_new_method(NULL);
+}
+
+RSA *
+RSA_new_method(ENGINE *engine)
+{
+ RSA *rsa;
+
+ rsa = calloc(1, sizeof(*rsa));
+ if (rsa == NULL)
+ return NULL;
+
+ rsa->references = 1;
+
+ if (engine) {
+ ENGINE_up_ref(engine);
+ rsa->engine = engine;
+ } else {
+ rsa->engine = ENGINE_get_default_RSA();
+ }
+
+ if (rsa->engine) {
+ rsa->meth = ENGINE_get_RSA(rsa->engine);
+ if (rsa->meth == NULL) {
+ ENGINE_finish(engine);
+ free(rsa);
+ return 0;
+ }
+ }
+
+ if (rsa->meth == NULL)
+ rsa->meth = rk_UNCONST(RSA_get_default_method());
+
+ (*rsa->meth->init)(rsa);
+
+ return rsa;
+}
+
+
+void
+RSA_free(RSA *rsa)
+{
+ if (rsa->references <= 0)
+ abort();
+
+ if (--rsa->references > 0)
+ return;
+
+ (*rsa->meth->finish)(rsa);
+
+ if (rsa->engine)
+ ENGINE_finish(rsa->engine);
+
+#define free_if(f) if (f) { BN_free(f); }
+ free_if(rsa->n);
+ free_if(rsa->e);
+ free_if(rsa->d);
+ free_if(rsa->p);
+ free_if(rsa->q);
+ free_if(rsa->dmp1);
+ free_if(rsa->dmq1);
+#undef free_if
+
+ memset(rsa, 0, sizeof(*rsa));
+ free(rsa);
+}
+
+int
+RSA_up_ref(RSA *rsa)
+{
+ return ++rsa->references;
+}
+
+const RSA_METHOD *
+RSA_get_method(const RSA *rsa)
+{
+ return rsa->meth;
+}
+
+int
+RSA_set_method(RSA *rsa, const RSA_METHOD *method)
+{
+ (*rsa->meth->finish)(rsa);
+
+ if (rsa->engine) {
+ ENGINE_finish(rsa->engine);
+ rsa->engine = NULL;
+ }
+
+ rsa->meth = method;
+ (*rsa->meth->init)(rsa);
+ return 1;
+}
+
+int
+RSA_set_app_data(RSA *rsa, void *arg)
+{
+ rsa->ex_data.sk = arg;
+ return 1;
+}
+
+void *
+RSA_get_app_data(RSA *rsa)
+{
+ return rsa->ex_data.sk;
+}
+
+int
+RSA_check_key(const RSA *key)
+{
+ static const unsigned char inbuf[] = "hello, world!";
+ RSA *rsa = rk_UNCONST(key);
+ void *buffer;
+ int ret;
+
+ /*
+ * XXX I have no clue how to implement this w/o a bignum library.
+ * Well, when we have a RSA key pair, we can try to encrypt/sign
+ * and then decrypt/verify.
+ */
+
+ if ((rsa->d == NULL || rsa->n == NULL) &&
+ (rsa->p == NULL || rsa->q || rsa->dmp1 == NULL || rsa->dmq1 == NULL || rsa->iqmp == NULL))
+ return 0;
+
+ buffer = malloc(RSA_size(rsa));
+ if (buffer == NULL)
+ return 0;
+
+ ret = RSA_private_encrypt(sizeof(inbuf), inbuf, buffer,
+ rsa, RSA_PKCS1_PADDING);
+ if (ret == -1) {
+ free(buffer);
+ return 0;
+ }
+
+ ret = RSA_public_decrypt(ret, buffer, buffer,
+ rsa, RSA_PKCS1_PADDING);
+ if (ret == -1) {
+ free(buffer);
+ return 0;
+ }
+
+ if (ret == sizeof(inbuf) && memcmp(buffer, inbuf, sizeof(inbuf)) == 0) {
+ free(buffer);
+ return 1;
+ }
+ free(buffer);
+ return 0;
+}
+
+int
+RSA_size(const RSA *rsa)
+{
+ return BN_num_bytes(rsa->n);
+}
+
+#define RSAFUNC(name, body) \
+int \
+name(int flen,const unsigned char* f, unsigned char* t, RSA* r, int p){\
+ return body; \
+}
+
+RSAFUNC(RSA_public_encrypt, (r)->meth->rsa_pub_enc(flen, f, t, r, p))
+RSAFUNC(RSA_public_decrypt, (r)->meth->rsa_pub_dec(flen, f, t, r, p))
+RSAFUNC(RSA_private_encrypt, (r)->meth->rsa_priv_enc(flen, f, t, r, p))
+RSAFUNC(RSA_private_decrypt, (r)->meth->rsa_priv_dec(flen, f, t, r, p))
+
+/* XXX */
+int
+RSA_sign(int type, const unsigned char *from, unsigned int flen,
+ unsigned char *to, unsigned int *tlen, RSA *rsa)
+{
+ return -1;
+}
+
+int
+RSA_verify(int type, const unsigned char *from, unsigned int flen,
+ unsigned char *to, unsigned int tlen, RSA *rsa)
+{
+ return -1;
+}
+
+/*
+ * A NULL RSA_METHOD that returns failure for all operations. This is
+ * used as the default RSA method is we don't have any native
+ * support.
+ */
+
+static RSAFUNC(null_rsa_public_encrypt, -1)
+static RSAFUNC(null_rsa_public_decrypt, -1)
+static RSAFUNC(null_rsa_private_encrypt, -1)
+static RSAFUNC(null_rsa_private_decrypt, -1)
+
+/*
+ *
+ */
+
+int
+RSA_generate_key_ex(RSA *r, int bits, BIGNUM *e, BN_GENCB *cb)
+{
+ if (r->meth->rsa_keygen)
+ return (*r->meth->rsa_keygen)(r, bits, e, cb);
+ return 0;
+}
+
+
+/*
+ *
+ */
+
+static int
+null_rsa_init(RSA *rsa)
+{
+ return 1;
+}
+
+static int
+null_rsa_finish(RSA *rsa)
+{
+ return 1;
+}
+
+static const RSA_METHOD rsa_null_method = {
+ "hcrypto null RSA",
+ null_rsa_public_encrypt,
+ null_rsa_public_decrypt,
+ null_rsa_private_encrypt,
+ null_rsa_private_decrypt,
+ NULL,
+ NULL,
+ null_rsa_init,
+ null_rsa_finish,
+ 0,
+ NULL,
+ NULL,
+ NULL
+};
+
+const RSA_METHOD *
+RSA_null_method(void)
+{
+ return &rsa_null_method;
+}
+
+extern const RSA_METHOD hc_rsa_imath_method;
+static const RSA_METHOD *default_rsa_method = &hc_rsa_imath_method;
+
+const RSA_METHOD *
+RSA_get_default_method(void)
+{
+ return default_rsa_method;
+}
+
+void
+RSA_set_default_method(const RSA_METHOD *meth)
+{
+ default_rsa_method = meth;
+}
+
+/*
+ *
+ */
+
+static BIGNUM *
+heim_int2BN(const heim_integer *i)
+{
+ BIGNUM *bn;
+
+ bn = BN_bin2bn(i->data, i->length, NULL);
+ if (bn)
+ BN_set_negative(bn, i->negative);
+ return bn;
+}
+
+static int
+bn2heim_int(BIGNUM *bn, heim_integer *integer)
+{
+ integer->length = BN_num_bytes(bn);
+ integer->data = malloc(integer->length);
+ if (integer->data == NULL) {
+ integer->length = 0;
+ return ENOMEM;
+ }
+ BN_bn2bin(bn, integer->data);
+ integer->negative = BN_is_negative(bn);
+ return 0;
+}
+
+
+RSA *
+d2i_RSAPrivateKey(RSA *rsa, const unsigned char **pp, size_t len)
+{
+ RSAPrivateKey data;
+ RSA *k = rsa;
+ size_t size;
+ int ret;
+
+ ret = decode_RSAPrivateKey(*pp, len, &data, &size);
+ if (ret)
+ return NULL;
+
+ *pp += size;
+
+ if (k == NULL) {
+ k = RSA_new();
+ if (k == NULL) {
+ free_RSAPrivateKey(&data);
+ return NULL;
+ }
+ }
+
+ k->n = heim_int2BN(&data.modulus);
+ k->e = heim_int2BN(&data.publicExponent);
+ k->d = heim_int2BN(&data.privateExponent);
+ k->p = heim_int2BN(&data.prime1);
+ k->q = heim_int2BN(&data.prime2);
+ k->dmp1 = heim_int2BN(&data.exponent1);
+ k->dmq1 = heim_int2BN(&data.exponent2);
+ k->iqmp = heim_int2BN(&data.coefficient);
+ free_RSAPrivateKey(&data);
+
+ if (k->n == NULL || k->e == NULL || k->d == NULL || k->p == NULL ||
+ k->q == NULL || k->dmp1 == NULL || k->dmq1 == NULL || k->iqmp == NULL)
+ {
+ RSA_free(k);
+ return NULL;
+ }
+
+ return k;
+}
+
+int
+i2d_RSAPrivateKey(RSA *rsa, unsigned char **pp)
+{
+ RSAPrivateKey data;
+ size_t size;
+ int ret;
+
+ if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL || rsa->p == NULL ||
+ rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 == NULL ||
+ rsa->iqmp == NULL)
+ return -1;
+
+ memset(&data, 0, sizeof(data));
+
+ ret = bn2heim_int(rsa->n, &data.modulus);
+ ret |= bn2heim_int(rsa->e, &data.publicExponent);
+ ret |= bn2heim_int(rsa->d, &data.privateExponent);
+ ret |= bn2heim_int(rsa->p, &data.prime1);
+ ret |= bn2heim_int(rsa->q, &data.prime2);
+ ret |= bn2heim_int(rsa->dmp1, &data.exponent1);
+ ret |= bn2heim_int(rsa->dmq1, &data.exponent2);
+ ret |= bn2heim_int(rsa->iqmp, &data.coefficient);
+ if (ret) {
+ free_RSAPrivateKey(&data);
+ return -1;
+ }
+
+ if (pp == NULL) {
+ size = length_RSAPrivateKey(&data);
+ free_RSAPrivateKey(&data);
+ } else {
+ void *p;
+ size_t len;
+
+ ASN1_MALLOC_ENCODE(RSAPrivateKey, p, len, &data, &size, ret);
+ free_RSAPrivateKey(&data);
+ if (ret)
+ return -1;
+ if (len != size)
+ abort();
+
+ memcpy(*pp, p, size);
+ free(p);
+
+ *pp += size;
+
+ }
+ return size;
+}
+
+int
+i2d_RSAPublicKey(RSA *rsa, unsigned char **pp)
+{
+ RSAPublicKey data;
+ size_t size;
+ int ret;
+
+ memset(&data, 0, sizeof(data));
+
+ if (bn2heim_int(rsa->n, &data.modulus) ||
+ bn2heim_int(rsa->e, &data.publicExponent))
+ {
+ free_RSAPublicKey(&data);
+ return -1;
+ }
+
+ if (pp == NULL) {
+ size = length_RSAPublicKey(&data);
+ free_RSAPublicKey(&data);
+ } else {
+ void *p;
+ size_t len;
+
+ ASN1_MALLOC_ENCODE(RSAPublicKey, p, len, &data, &size, ret);
+ free_RSAPublicKey(&data);
+ if (ret)
+ return -1;
+ if (len != size)
+ abort();
+
+ memcpy(*pp, p, size);
+ free(p);
+
+ *pp += size;
+ }
+
+ return size;
+}
diff --git a/source4/heimdal/lib/des/rsa.h b/source4/heimdal/lib/des/rsa.h
index 137dd9894b6..0aceb9f9dad 100644
--- a/source4/heimdal/lib/des/rsa.h
+++ b/source4/heimdal/lib/des/rsa.h
@@ -32,7 +32,7 @@
*/
/*
- * $Id: rsa.h,v 1.5 2006/05/07 11:34:02 lha Exp $
+ * $Id: rsa.h,v 1.9 2007/01/05 20:26:23 lha Exp $
*/
#ifndef _HEIM_RSA_H
@@ -59,7 +59,9 @@
#define RSA_private_decrypt hc_RSA_private_decrypt
#define RSA_sign hc_RSA_sign
#define RSA_verify hc_RSA_verify
+#define RSA_generate_key_ex hc_RSA_generate_key_ex
#define d2i_RSAPrivateKey hc_d2i_RSAPrivateKey
+#define i2d_RSAPrivateKey hc_i2d_RSAPrivateKey
#define i2d_RSAPublicKey hc_i2d_RSAPublicKey
/*
@@ -119,9 +121,10 @@ struct RSA {
void *mt_blinding;
};
-#define RSA_FLAG_SIGN_VER 0x40
+#define RSA_FLAG_NO_BLINDING 0x0080
#define RSA_PKCS1_PADDING 1
+#define RSA_PKCS1_OAEP_PADDING 4
#define RSA_PKCS1_PADDING_SIZE 11
/*
@@ -162,7 +165,11 @@ int RSA_sign(int, const unsigned char *, unsigned int,
int RSA_verify(int, const unsigned char *, unsigned int,
unsigned char *, unsigned int, RSA *);
+int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *);
+
RSA * d2i_RSAPrivateKey(RSA *, const unsigned char **, size_t);
+int i2d_RSAPrivateKey(RSA *, unsigned char **);
+
int i2d_RSAPublicKey(RSA *, unsigned char **);
#endif /* _HEIM_RSA_H */
diff --git a/source4/heimdal/lib/gssapi/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi/gssapi.h
index f89e5dfbeed..8077aeb2239 100644
--- a/source4/heimdal/lib/gssapi/gssapi/gssapi.h
+++ b/source4/heimdal/lib/gssapi/gssapi/gssapi.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: gssapi.h,v 1.6 2006/11/10 00:39:50 lha Exp $ */
+/* $Id: gssapi.h,v 1.7 2006/12/15 20:02:54 lha Exp $ */
#ifndef GSSAPI_GSSAPI_H_
#define GSSAPI_GSSAPI_H_
@@ -300,6 +300,12 @@ extern gss_OID GSS_C_NT_EXPORT_NAME;
extern gss_OID GSS_SASL_DIGEST_MD5_MECHANISM;
+/*
+ * NTLM mechanism
+ */
+
+extern gss_OID GSS_NTLM_MECHANISM;
+
/* Major status codes */
#define GSS_S_COMPLETE 0
diff --git a/source4/heimdal/lib/gssapi/gssapi_mech.h b/source4/heimdal/lib/gssapi/gssapi_mech.h
index a05919b5109..2bb5ecedf50 100644
--- a/source4/heimdal/lib/gssapi/gssapi_mech.h
+++ b/source4/heimdal/lib/gssapi/gssapi_mech.h
@@ -344,5 +344,6 @@ __gss_get_mechanism(gss_OID /* oid */);
gssapi_mech_interface __gss_spnego_initialize(void);
gssapi_mech_interface __gss_krb5_initialize(void);
+gssapi_mech_interface __gss_ntlm_initialize(void);
#endif /* GSSAPI_MECH_H */
diff --git a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c
index 6ac80461c35..434fbee352e 100644
--- a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: accept_sec_context.c,v 1.65 2006/11/07 14:52:05 lha Exp $");
+RCSID("$Id: accept_sec_context.c,v 1.66 2006/11/13 18:00:54 lha Exp $");
HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
krb5_keytab _gsskrb5_keytab;
@@ -41,20 +41,21 @@ krb5_keytab _gsskrb5_keytab;
OM_uint32
_gsskrb5_register_acceptor_identity (const char *identity)
{
+ krb5_context context;
krb5_error_code ret;
- ret = _gsskrb5_init();
+ ret = _gsskrb5_init(&context);
if(ret)
return GSS_S_FAILURE;
HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
if(_gsskrb5_keytab != NULL) {
- krb5_kt_close(_gsskrb5_context, _gsskrb5_keytab);
+ krb5_kt_close(context, _gsskrb5_keytab);
_gsskrb5_keytab = NULL;
}
if (identity == NULL) {
- ret = krb5_kt_default(_gsskrb5_context, &_gsskrb5_keytab);
+ ret = krb5_kt_default(context, &_gsskrb5_keytab);
} else {
char *p;
@@ -63,7 +64,7 @@ _gsskrb5_register_acceptor_identity (const char *identity)
HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
return GSS_S_FAILURE;
}
- ret = krb5_kt_resolve(_gsskrb5_context, p, &_gsskrb5_keytab);
+ ret = krb5_kt_resolve(context, p, &_gsskrb5_keytab);
free(p);
}
HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
@@ -120,6 +121,7 @@ static OM_uint32
gsskrb5_accept_delegated_token
(OM_uint32 * minor_status,
gsskrb5_ctx ctx,
+ krb5_context context,
gss_cred_id_t * delegated_cred_handle
)
{
@@ -131,33 +133,31 @@ gsskrb5_accept_delegated_token
/* XXX Create a new delegated_cred_handle? */
if (delegated_cred_handle == NULL) {
- kret = krb5_cc_default (_gsskrb5_context, &ccache);
+ kret = krb5_cc_default (context, &ccache);
} else {
*delegated_cred_handle = NULL;
- kret = krb5_cc_gen_new (_gsskrb5_context, &krb5_mcc_ops, &ccache);
+ kret = krb5_cc_gen_new (context, &krb5_mcc_ops, &ccache);
}
if (kret) {
ctx->flags &= ~GSS_C_DELEG_FLAG;
goto out;
}
- kret = krb5_cc_initialize(_gsskrb5_context, ccache, ctx->source);
+ kret = krb5_cc_initialize(context, ccache, ctx->source);
if (kret) {
ctx->flags &= ~GSS_C_DELEG_FLAG;
goto out;
}
- krb5_auth_con_removeflags(_gsskrb5_context,
+ krb5_auth_con_removeflags(context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_TIME,
&ac_flags);
- kret = krb5_rd_cred2(_gsskrb5_context,
+ kret = krb5_rd_cred2(context,
ctx->auth_context,
ccache,
&ctx->fwd_data);
- if (kret)
- _gsskrb5_set_error_string();
- krb5_auth_con_setflags(_gsskrb5_context,
+ krb5_auth_con_setflags(context,
ctx->auth_context,
ac_flags);
if (kret) {
@@ -181,16 +181,16 @@ gsskrb5_accept_delegated_token
handle = (gsskrb5_cred) *delegated_cred_handle;
handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
- krb5_cc_close(_gsskrb5_context, ccache);
+ krb5_cc_close(context, ccache);
ccache = NULL;
}
out:
if (ccache) {
if (delegated_cred_handle == NULL)
- krb5_cc_close(_gsskrb5_context, ccache);
+ krb5_cc_close(context, ccache);
else
- krb5_cc_destroy(_gsskrb5_context, ccache);
+ krb5_cc_destroy(context, ccache);
}
return ret;
}
@@ -198,13 +198,14 @@ out:
static OM_uint32
gsskrb5_acceptor_ready(OM_uint32 * minor_status,
gsskrb5_ctx ctx,
+ krb5_context context,
gss_cred_id_t *delegated_cred_handle)
{
OM_uint32 ret;
int32_t seq_number;
int is_cfx = 0;
- krb5_auth_getremoteseqnumber (_gsskrb5_context,
+ krb5_auth_getremoteseqnumber (context,
ctx->auth_context,
&seq_number);
@@ -222,7 +223,7 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status,
* isn't a mutual authentication context
*/
if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {
- krb5_auth_con_setlocalseqnumber(_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber(context,
ctx->auth_context,
seq_number);
}
@@ -233,6 +234,7 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status,
if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {
ret = gsskrb5_accept_delegated_token(minor_status,
ctx,
+ context,
delegated_cred_handle);
if (ret)
return ret;
@@ -250,6 +252,7 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status,
static OM_uint32
gsskrb5_acceptor_start(OM_uint32 * minor_status,
gsskrb5_ctx ctx,
+ krb5_context context,
const gss_cred_id_t acceptor_cred_handle,
const gss_buffer_t input_token_buffer,
const gss_channel_bindings_t input_chan_bindings,
@@ -301,49 +304,46 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
krb5_rd_req_in_ctx in = NULL;
krb5_rd_req_out_ctx out = NULL;
- kret = krb5_rd_req_in_ctx_alloc(_gsskrb5_context, &in);
+ kret = krb5_rd_req_in_ctx_alloc(context, &in);
if (kret == 0)
- kret = krb5_rd_req_in_set_keytab(_gsskrb5_context, in, keytab);
+ kret = krb5_rd_req_in_set_keytab(context, in, keytab);
if (kret) {
if (in)
- krb5_rd_req_in_ctx_free(_gsskrb5_context, in);
+ krb5_rd_req_in_ctx_free(context, in);
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
- kret = krb5_rd_req_ctx(_gsskrb5_context,
+ kret = krb5_rd_req_ctx(context,
&ctx->auth_context,
&indata,
(acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred->principal,
in, &out);
- krb5_rd_req_in_ctx_free(_gsskrb5_context, in);
+ krb5_rd_req_in_ctx_free(context, in);
if (kret) {
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
/*
* We need to remember some data on the context_handle.
*/
- kret = krb5_rd_req_out_get_ap_req_options(_gsskrb5_context, out,
+ kret = krb5_rd_req_out_get_ap_req_options(context, out,
&ap_options);
if (kret == 0)
- kret = krb5_rd_req_out_get_ticket(_gsskrb5_context, out,
+ kret = krb5_rd_req_out_get_ticket(context, out,
&ctx->ticket);
if (kret == 0)
- kret = krb5_rd_req_out_get_keyblock(_gsskrb5_context, out,
+ kret = krb5_rd_req_out_get_keyblock(context, out,
&ctx->service_keyblock);
ctx->lifetime = ctx->ticket->ticket.endtime;
- krb5_rd_req_out_ctx_free(_gsskrb5_context, out);
+ krb5_rd_req_out_ctx_free(context, out);
if (kret) {
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
}
@@ -353,22 +353,20 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
* We need to copy the principal names to the context and the
* calling layer.
*/
- kret = krb5_copy_principal(_gsskrb5_context,
+ kret = krb5_copy_principal(context,
ctx->ticket->client,
&ctx->source);
if (kret) {
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
}
- kret = krb5_copy_principal(_gsskrb5_context,
+ kret = krb5_copy_principal(context,
ctx->ticket->server,
&ctx->target);
if (kret) {
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
@@ -376,18 +374,17 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
* We need to setup some compat stuff, this assumes that
* context_handle->target is already set.
*/
- ret = _gss_DES3_get_mic_compat(minor_status, ctx);
+ ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
if (ret)
return ret;
if (src_name != NULL) {
- kret = krb5_copy_principal (_gsskrb5_context,
+ kret = krb5_copy_principal (context,
ctx->ticket->client,
(gsskrb5_name*)src_name);
if (kret) {
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
}
@@ -398,13 +395,12 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
{
krb5_authenticator authenticator;
- kret = krb5_auth_con_getauthenticator(_gsskrb5_context,
+ kret = krb5_auth_con_getauthenticator(context,
ctx->auth_context,
&authenticator);
if(kret) {
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
@@ -415,22 +411,21 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
&ctx->flags,
&ctx->fwd_data);
- krb5_free_authenticator(_gsskrb5_context, &authenticator);
+ krb5_free_authenticator(context, &authenticator);
if (ret) {
return ret;
}
} else {
krb5_crypto crypto;
- kret = krb5_crypto_init(_gsskrb5_context,
+ kret = krb5_crypto_init(context,
ctx->auth_context->keyblock,
0, &crypto);
if(kret) {
- krb5_free_authenticator(_gsskrb5_context, &authenticator);
+ krb5_free_authenticator(context, &authenticator);
ret = GSS_S_FAILURE;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
@@ -439,16 +434,15 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
* GSSAPI checksum here
*/
- kret = krb5_verify_checksum(_gsskrb5_context,
+ kret = krb5_verify_checksum(context,
crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
authenticator->cksum);
- krb5_free_authenticator(_gsskrb5_context, &authenticator);
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_free_authenticator(context, &authenticator);
+ krb5_crypto_destroy(context, crypto);
if(kret) {
ret = GSS_S_BAD_SIG;
*minor_status = kret;
- _gsskrb5_set_error_string ();
return ret;
}
@@ -467,23 +461,22 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
if (is_cfx != 0
|| (ap_options & AP_OPTS_USE_SUBKEY)) {
- kret = krb5_auth_con_addflags(_gsskrb5_context,
+ kret = krb5_auth_con_addflags(context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_USE_SUBKEY,
NULL);
ctx->more_flags |= ACCEPTOR_SUBKEY;
}
- kret = krb5_mk_rep(_gsskrb5_context,
+ kret = krb5_mk_rep(context,
ctx->auth_context,
&outbuf);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
}
- if (ctx->flags & GSS_C_DCE_STYLE) {
+ if (IS_DCE_STYLE(ctx)) {
output_token->length = outbuf.length;
output_token->value = outbuf.data;
} else {
@@ -510,6 +503,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
if (time_rec) {
ret = _gsskrb5_lifetime_left(minor_status,
+ context,
ctx->lifetime,
time_rec);
if (ret) {
@@ -521,7 +515,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
* When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
* the client.
*/
- if (ctx->flags & GSS_C_DCE_STYLE) {
+ if (IS_DCE_STYLE(ctx)) {
/*
* Return flags to caller, but we haven't processed
* delgations yet
@@ -533,7 +527,8 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
return GSS_S_CONTINUE_NEEDED;
}
- ret = gsskrb5_acceptor_ready(minor_status, ctx, delegated_cred_handle);
+ ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
+ delegated_cred_handle);
if (ret_flags)
*ret_flags = ctx->flags;
@@ -544,6 +539,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status,
static OM_uint32
acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
gsskrb5_ctx ctx,
+ krb5_context context,
const gss_cred_id_t acceptor_cred_handle,
const gss_buffer_t input_token_buffer,
const gss_channel_bindings_t input_chan_bindings,
@@ -572,29 +568,26 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
* the remote seq_number to the old value
*/
{
- kret = krb5_auth_con_getlocalseqnumber(_gsskrb5_context,
+ kret = krb5_auth_con_getlocalseqnumber(context,
ctx->auth_context,
&l_seq_number);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
- kret = krb5_auth_getremoteseqnumber(_gsskrb5_context,
+ kret = krb5_auth_getremoteseqnumber(context,
ctx->auth_context,
&r_seq_number);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
- kret = krb5_auth_con_setremoteseqnumber(_gsskrb5_context,
+ kret = krb5_auth_con_setremoteseqnumber(context,
ctx->auth_context,
l_seq_number);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
@@ -609,19 +602,18 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
krb5_ap_rep_enc_part *repl;
int32_t auth_flags;
- krb5_auth_con_removeflags(_gsskrb5_context,
+ krb5_auth_con_removeflags(context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_TIME,
&auth_flags);
- kret = krb5_rd_rep(_gsskrb5_context, ctx->auth_context, &inbuf, &repl);
+ kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
- krb5_free_ap_rep_enc_part(_gsskrb5_context, repl);
- krb5_auth_con_setflags(_gsskrb5_context, ctx->auth_context, auth_flags);
+ krb5_free_ap_rep_enc_part(context, repl);
+ krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
}
/* We need to check the liftime */
@@ -629,6 +621,7 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
OM_uint32 lifetime_rec;
ret = _gsskrb5_lifetime_left(minor_status,
+ context,
ctx->lifetime,
&lifetime_rec);
if (ret) {
@@ -645,12 +638,11 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
if (ret_flags) *ret_flags = ctx->flags;
if (src_name) {
- kret = krb5_copy_principal(_gsskrb5_context,
+ kret = krb5_copy_principal(context,
ctx->source,
(gsskrb5_name*)src_name);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
}
}
@@ -664,20 +656,19 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
{
int32_t tmp_r_seq_number, tmp_l_seq_number;
- kret = krb5_auth_getremoteseqnumber(_gsskrb5_context,
+ kret = krb5_auth_getremoteseqnumber(context,
ctx->auth_context,
&tmp_r_seq_number);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
- kret = krb5_auth_con_getlocalseqnumber(_gsskrb5_context,
+ kret = krb5_auth_con_getlocalseqnumber(context,
ctx->auth_context,
&tmp_l_seq_number);
if (kret) {
- _gsskrb5_set_error_string ();
+
*minor_status = kret;
return GSS_S_FAILURE;
}
@@ -695,17 +686,17 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
* the old one for the GSS_wrap() calls
*/
{
- kret = krb5_auth_con_setremoteseqnumber(_gsskrb5_context,
+ kret = krb5_auth_con_setremoteseqnumber(context,
ctx->auth_context,
r_seq_number);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
}
- return gsskrb5_acceptor_ready(minor_status, ctx, delegated_cred_handle);
+ return gsskrb5_acceptor_ready(minor_status, ctx, context,
+ delegated_cred_handle);
}
@@ -722,10 +713,11 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
OM_uint32 * time_rec,
gss_cred_id_t * delegated_cred_handle)
{
+ krb5_context context;
OM_uint32 ret;
gsskrb5_ctx ctx;
- GSSAPI_KRB5_INIT();
+ GSSAPI_KRB5_INIT(&context);
output_token->length = 0;
output_token->value = NULL;
@@ -738,6 +730,7 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
if (*context_handle == GSS_C_NO_CONTEXT) {
ret = _gsskrb5_create_ctx(minor_status,
context_handle,
+ context,
input_chan_bindings,
ACCEPTOR_START);
if (ret)
@@ -758,6 +751,7 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
case ACCEPTOR_START:
ret = gsskrb5_acceptor_start(minor_status,
ctx,
+ context,
acceptor_cred_handle,
input_token_buffer,
input_chan_bindings,
@@ -771,6 +765,7 @@ _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
case ACCEPTOR_WAIT_FOR_DCESTYLE:
ret = acceptor_wait_for_dcestyle(minor_status,
ctx,
+ context,
acceptor_cred_handle,
input_token_buffer,
input_chan_bindings,
diff --git a/source4/heimdal/lib/gssapi/krb5/acquire_cred.c b/source4/heimdal/lib/gssapi/krb5/acquire_cred.c
index df6e1374025..e811a99a8be 100644
--- a/source4/heimdal/lib/gssapi/krb5/acquire_cred.c
+++ b/source4/heimdal/lib/gssapi/krb5/acquire_cred.c
@@ -33,13 +33,14 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: acquire_cred.c,v 1.31 2006/10/07 22:13:55 lha Exp $");
+RCSID("$Id: acquire_cred.c,v 1.33 2006/11/20 18:09:30 lha Exp $");
OM_uint32
__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
- krb5_ccache id,
- krb5_principal principal,
- OM_uint32 *lifetime)
+ krb5_context context,
+ krb5_ccache id,
+ krb5_principal principal,
+ OM_uint32 *lifetime)
{
krb5_creds in_cred, *out_cred;
krb5_const_realm realm;
@@ -48,32 +49,30 @@ __gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
memset(&in_cred, 0, sizeof(in_cred));
in_cred.client = principal;
- realm = krb5_principal_get_realm(_gsskrb5_context, principal);
+ realm = krb5_principal_get_realm(context, principal);
if (realm == NULL) {
_gsskrb5_clear_status ();
*minor_status = KRB5_PRINC_NOMATCH; /* XXX */
return GSS_S_FAILURE;
}
- kret = krb5_make_principal(_gsskrb5_context, &in_cred.server,
+ kret = krb5_make_principal(context, &in_cred.server,
realm, KRB5_TGS_NAME, realm, NULL);
if (kret) {
- _gsskrb5_set_error_string();
*minor_status = kret;
return GSS_S_FAILURE;
}
- kret = krb5_get_credentials(_gsskrb5_context, 0,
+ kret = krb5_get_credentials(context, 0,
id, &in_cred, &out_cred);
- krb5_free_principal(_gsskrb5_context, in_cred.server);
+ krb5_free_principal(context, in_cred.server);
if (kret) {
- _gsskrb5_set_error_string();
*minor_status = kret;
return GSS_S_FAILURE;
}
*lifetime = out_cred->times.endtime;
- krb5_free_creds(_gsskrb5_context, out_cred);
+ krb5_free_creds(context, out_cred);
return GSS_S_COMPLETE;
}
@@ -82,7 +81,7 @@ __gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
static krb5_error_code
-get_keytab(krb5_keytab *keytab)
+get_keytab(krb5_context context, krb5_keytab *keytab)
{
char kt_name[256];
krb5_error_code kret;
@@ -90,13 +89,13 @@ get_keytab(krb5_keytab *keytab)
HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
if (_gsskrb5_keytab != NULL) {
- kret = krb5_kt_get_name(_gsskrb5_context,
+ kret = krb5_kt_get_name(context,
_gsskrb5_keytab,
kt_name, sizeof(kt_name));
if (kret == 0)
- kret = krb5_kt_resolve(_gsskrb5_context, kt_name, keytab);
+ kret = krb5_kt_resolve(context, kt_name, keytab);
} else
- kret = krb5_kt_default(_gsskrb5_context, keytab);
+ kret = krb5_kt_default(context, keytab);
HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
@@ -105,6 +104,7 @@ get_keytab(krb5_keytab *keytab)
static OM_uint32 acquire_initiator_cred
(OM_uint32 * minor_status,
+ krb5_context context,
const gss_name_t desired_name,
OM_uint32 time_req,
const gss_OID_set desired_mechs,
@@ -132,33 +132,33 @@ static OM_uint32 acquire_initiator_cred
* caches, otherwise, fall back to default cache. Ignore
* errors. */
if (handle->principal)
- kret = krb5_cc_cache_match (_gsskrb5_context,
+ kret = krb5_cc_cache_match (context,
handle->principal,
NULL,
&ccache);
if (ccache == NULL) {
- kret = krb5_cc_default(_gsskrb5_context, &ccache);
+ kret = krb5_cc_default(context, &ccache);
if (kret)
goto end;
}
- kret = krb5_cc_get_principal(_gsskrb5_context, ccache,
+ kret = krb5_cc_get_principal(context, ccache,
&def_princ);
if (kret != 0) {
/* we'll try to use a keytab below */
- krb5_cc_destroy(_gsskrb5_context, ccache);
+ krb5_cc_destroy(context, ccache);
ccache = NULL;
kret = 0;
} else if (handle->principal == NULL) {
- kret = krb5_copy_principal(_gsskrb5_context, def_princ,
+ kret = krb5_copy_principal(context, def_princ,
&handle->principal);
if (kret)
goto end;
} else if (handle->principal != NULL &&
- krb5_principal_compare(_gsskrb5_context, handle->principal,
+ krb5_principal_compare(context, handle->principal,
def_princ) == FALSE) {
/* Before failing, lets check the keytab */
- krb5_free_principal(_gsskrb5_context, def_princ);
+ krb5_free_principal(context, def_princ);
def_princ = NULL;
}
if (def_princ == NULL) {
@@ -166,30 +166,30 @@ static OM_uint32 acquire_initiator_cred
* so attempt to get a TGT using a keytab.
*/
if (handle->principal == NULL) {
- kret = krb5_get_default_principal(_gsskrb5_context,
+ kret = krb5_get_default_principal(context,
&handle->principal);
if (kret)
goto end;
}
- kret = get_keytab(&keytab);
+ kret = get_keytab(context, &keytab);
if (kret)
goto end;
- kret = krb5_get_init_creds_opt_alloc(_gsskrb5_context, &opt);
+ kret = krb5_get_init_creds_opt_alloc(context, &opt);
if (kret)
goto end;
- kret = krb5_get_init_creds_keytab(_gsskrb5_context, &cred,
+ kret = krb5_get_init_creds_keytab(context, &cred,
handle->principal, keytab, 0, NULL, opt);
- krb5_get_init_creds_opt_free(opt);
+ krb5_get_init_creds_opt_free(context, opt);
if (kret)
goto end;
- kret = krb5_cc_gen_new(_gsskrb5_context, &krb5_mcc_ops,
+ kret = krb5_cc_gen_new(context, &krb5_mcc_ops,
&ccache);
if (kret)
goto end;
- kret = krb5_cc_initialize(_gsskrb5_context, ccache, cred.client);
+ kret = krb5_cc_initialize(context, ccache, cred.client);
if (kret)
goto end;
- kret = krb5_cc_store_cred(_gsskrb5_context, ccache, &cred);
+ kret = krb5_cc_store_cred(context, ccache, &cred);
if (kret)
goto end;
handle->lifetime = cred.times.endtime;
@@ -197,9 +197,10 @@ static OM_uint32 acquire_initiator_cred
} else {
ret = __gsskrb5_ccache_lifetime(minor_status,
- ccache,
- handle->principal,
- &handle->lifetime);
+ context,
+ ccache,
+ handle->principal,
+ &handle->lifetime);
if (ret != GSS_S_COMPLETE)
goto end;
kret = 0;
@@ -210,17 +211,16 @@ static OM_uint32 acquire_initiator_cred
end:
if (cred.client != NULL)
- krb5_free_cred_contents(_gsskrb5_context, &cred);
+ krb5_free_cred_contents(context, &cred);
if (def_princ != NULL)
- krb5_free_principal(_gsskrb5_context, def_princ);
+ krb5_free_principal(context, def_princ);
if (keytab != NULL)
- krb5_kt_close(_gsskrb5_context, keytab);
+ krb5_kt_close(context, keytab);
if (ret != GSS_S_COMPLETE) {
if (ccache != NULL)
- krb5_cc_close(_gsskrb5_context, ccache);
+ krb5_cc_close(context, ccache);
if (kret != 0) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
}
}
return (ret);
@@ -228,6 +228,7 @@ end:
static OM_uint32 acquire_acceptor_cred
(OM_uint32 * minor_status,
+ krb5_context context,
const gss_name_t desired_name,
OM_uint32 time_req,
const gss_OID_set desired_mechs,
@@ -242,7 +243,7 @@ static OM_uint32 acquire_acceptor_cred
kret = 0;
ret = GSS_S_FAILURE;
- kret = get_keytab(&handle->keytab);
+ kret = get_keytab(context, &handle->keytab);
if (kret)
goto end;
@@ -250,21 +251,20 @@ static OM_uint32 acquire_acceptor_cred
if (handle->principal) {
krb5_keytab_entry entry;
- kret = krb5_kt_get_entry(_gsskrb5_context, handle->keytab,
+ kret = krb5_kt_get_entry(context, handle->keytab,
handle->principal, 0, 0, &entry);
if (kret)
goto end;
- krb5_kt_free_entry(_gsskrb5_context, &entry);
+ krb5_kt_free_entry(context, &entry);
}
ret = GSS_S_COMPLETE;
end:
if (ret != GSS_S_COMPLETE) {
if (handle->keytab != NULL)
- krb5_kt_close(_gsskrb5_context, handle->keytab);
+ krb5_kt_close(context, handle->keytab);
if (kret != 0) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
}
}
return (ret);
@@ -281,6 +281,7 @@ OM_uint32 _gsskrb5_acquire_cred
OM_uint32 * time_rec
)
{
+ krb5_context context;
gsskrb5_cred handle;
OM_uint32 ret;
@@ -289,7 +290,7 @@ OM_uint32 _gsskrb5_acquire_cred
return GSS_S_FAILURE;
}
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT(&context);
*output_cred_handle = NULL;
if (time_rec)
@@ -320,31 +321,33 @@ OM_uint32 _gsskrb5_acquire_cred
if (desired_name != GSS_C_NO_NAME) {
krb5_principal name = (krb5_principal)desired_name;
- ret = krb5_copy_principal(_gsskrb5_context, name, &handle->principal);
+ ret = krb5_copy_principal(context, name, &handle->principal);
if (ret) {
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
- _gsskrb5_set_error_string();
*minor_status = ret;
free(handle);
return GSS_S_FAILURE;
}
}
if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
- ret = acquire_initiator_cred(minor_status, desired_name, time_req,
- desired_mechs, cred_usage, handle, actual_mechs, time_rec);
+ ret = acquire_initiator_cred(minor_status, context,
+ desired_name, time_req,
+ desired_mechs, cred_usage, handle,
+ actual_mechs, time_rec);
if (ret != GSS_S_COMPLETE) {
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
- krb5_free_principal(_gsskrb5_context, handle->principal);
+ krb5_free_principal(context, handle->principal);
free(handle);
return (ret);
}
}
if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
- ret = acquire_acceptor_cred(minor_status, desired_name, time_req,
+ ret = acquire_acceptor_cred(minor_status, context,
+ desired_name, time_req,
desired_mechs, cred_usage, handle, actual_mechs, time_rec);
if (ret != GSS_S_COMPLETE) {
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
- krb5_free_principal(_gsskrb5_context, handle->principal);
+ krb5_free_principal(context, handle->principal);
free(handle);
return (ret);
}
@@ -360,15 +363,16 @@ OM_uint32 _gsskrb5_acquire_cred
if (handle->mechanisms != NULL)
_gsskrb5_release_oid_set(NULL, &handle->mechanisms);
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
- krb5_free_principal(_gsskrb5_context, handle->principal);
+ krb5_free_principal(context, handle->principal);
free(handle);
return (ret);
}
*minor_status = 0;
if (time_rec) {
ret = _gsskrb5_lifetime_left(minor_status,
- handle->lifetime,
- time_rec);
+ context,
+ handle->lifetime,
+ time_rec);
if (ret)
return ret;
diff --git a/source4/heimdal/lib/gssapi/krb5/add_cred.c b/source4/heimdal/lib/gssapi/krb5/add_cred.c
index 4892e847986..3b0272af800 100644
--- a/source4/heimdal/lib/gssapi/krb5/add_cred.c
+++ b/source4/heimdal/lib/gssapi/krb5/add_cred.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: add_cred.c,v 1.9 2006/10/07 22:13:58 lha Exp $");
+RCSID("$Id: add_cred.c,v 1.10 2006/11/13 18:01:01 lha Exp $");
OM_uint32 _gsskrb5_add_cred (
OM_uint32 *minor_status,
@@ -48,6 +48,7 @@ OM_uint32 _gsskrb5_add_cred (
OM_uint32 *initiator_time_rec,
OM_uint32 *acceptor_time_rec)
{
+ krb5_context context;
OM_uint32 ret, lifetime;
gsskrb5_cred cred, handle;
krb5_const_principal dname;
@@ -56,6 +57,8 @@ OM_uint32 _gsskrb5_add_cred (
cred = (gsskrb5_cred)input_cred_handle;
dname = (krb5_const_principal)desired_name;
+ GSSAPI_KRB5_INIT (&context);
+
if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) {
*minor_status = 0;
return GSS_S_BAD_MECH;
@@ -83,7 +86,7 @@ OM_uint32 _gsskrb5_add_cred (
/* check that we have the same name */
if (dname != NULL &&
- krb5_principal_compare(_gsskrb5_context, dname,
+ krb5_principal_compare(context, dname,
cred->principal) != FALSE) {
if (output_cred_handle)
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
@@ -112,7 +115,7 @@ OM_uint32 _gsskrb5_add_cred (
ret = GSS_S_FAILURE;
- kret = krb5_copy_principal(_gsskrb5_context, cred->principal,
+ kret = krb5_copy_principal(context, cred->principal,
&handle->principal);
if (kret) {
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
@@ -127,7 +130,7 @@ OM_uint32 _gsskrb5_add_cred (
ret = GSS_S_FAILURE;
- kret = krb5_kt_get_type(_gsskrb5_context, cred->keytab,
+ kret = krb5_kt_get_type(context, cred->keytab,
name, KRB5_KT_PREFIX_MAX_LEN);
if (kret) {
*minor_status = kret;
@@ -136,7 +139,7 @@ OM_uint32 _gsskrb5_add_cred (
len = strlen(name);
name[len++] = ':';
- kret = krb5_kt_get_name(_gsskrb5_context, cred->keytab,
+ kret = krb5_kt_get_name(context, cred->keytab,
name + len,
sizeof(name) - len);
if (kret) {
@@ -144,7 +147,7 @@ OM_uint32 _gsskrb5_add_cred (
goto failure;
}
- kret = krb5_kt_resolve(_gsskrb5_context, name,
+ kret = krb5_kt_resolve(context, name,
&handle->keytab);
if (kret){
*minor_status = kret;
@@ -158,21 +161,21 @@ OM_uint32 _gsskrb5_add_cred (
ret = GSS_S_FAILURE;
- type = krb5_cc_get_type(_gsskrb5_context, cred->ccache);
+ type = krb5_cc_get_type(context, cred->ccache);
if (type == NULL){
*minor_status = ENOMEM;
goto failure;
}
if (strcmp(type, "MEMORY") == 0) {
- ret = krb5_cc_gen_new(_gsskrb5_context, &krb5_mcc_ops,
+ ret = krb5_cc_gen_new(context, &krb5_mcc_ops,
&handle->ccache);
if (ret) {
*minor_status = ret;
goto failure;
}
- ret = krb5_cc_copy_cache(_gsskrb5_context, cred->ccache,
+ ret = krb5_cc_copy_cache(context, cred->ccache,
handle->ccache);
if (ret) {
*minor_status = ret;
@@ -180,7 +183,7 @@ OM_uint32 _gsskrb5_add_cred (
}
} else {
- name = krb5_cc_get_name(_gsskrb5_context, cred->ccache);
+ name = krb5_cc_get_name(context, cred->ccache);
if (name == NULL) {
*minor_status = ENOMEM;
goto failure;
@@ -192,7 +195,7 @@ OM_uint32 _gsskrb5_add_cred (
goto failure;
}
- kret = krb5_cc_resolve(_gsskrb5_context, type_name,
+ kret = krb5_cc_resolve(context, type_name,
&handle->ccache);
free(type_name);
if (kret) {
@@ -234,11 +237,11 @@ OM_uint32 _gsskrb5_add_cred (
if (handle) {
if (handle->principal)
- krb5_free_principal(_gsskrb5_context, handle->principal);
+ krb5_free_principal(context, handle->principal);
if (handle->keytab)
- krb5_kt_close(_gsskrb5_context, handle->keytab);
+ krb5_kt_close(context, handle->keytab);
if (handle->ccache)
- krb5_cc_destroy(_gsskrb5_context, handle->ccache);
+ krb5_cc_destroy(context, handle->ccache);
if (handle->mechanisms)
_gsskrb5_release_oid_set(NULL, &handle->mechanisms);
free(handle);
diff --git a/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c b/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c
index 9aec53faaae..18a90fe9a76 100644
--- a/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c
+++ b/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c
@@ -36,7 +36,8 @@
#include <roken.h>
krb5_error_code
-_gsskrb5i_address_to_krb5addr(OM_uint32 gss_addr_type,
+_gsskrb5i_address_to_krb5addr(krb5_context context,
+ OM_uint32 gss_addr_type,
gss_buffer_desc *gss_addr,
int16_t port,
krb5_address *address)
@@ -61,7 +62,7 @@ _gsskrb5i_address_to_krb5addr(OM_uint32 gss_addr_type,
return GSS_S_FAILURE;
}
- problem = krb5_h_addr2sockaddr (_gsskrb5_context,
+ problem = krb5_h_addr2sockaddr (context,
addr_type,
gss_addr->value,
&sa,
@@ -70,7 +71,7 @@ _gsskrb5i_address_to_krb5addr(OM_uint32 gss_addr_type,
if (problem)
return GSS_S_FAILURE;
- problem = krb5_sockaddr2address (_gsskrb5_context, &sa, address);
+ problem = krb5_sockaddr2address (context, &sa, address);
return problem;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c
index 2c43ed8b321..d1bdbb641ff 100644
--- a/source4/heimdal/lib/gssapi/krb5/arcfour.c
+++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: arcfour.c,v 1.30 2006/11/07 19:05:16 lha Exp $");
+RCSID("$Id: arcfour.c,v 1.31 2006/11/13 18:01:08 lha Exp $");
/*
* Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
@@ -114,7 +114,8 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key,
static krb5_error_code
-arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
+arcfour_mic_cksum(krb5_context context,
+ krb5_keyblock *key, unsigned usage,
u_char *sgn_cksum, size_t sgn_cksum_sz,
const u_char *v1, size_t l1,
const void *v2, size_t l2,
@@ -138,13 +139,13 @@ arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
memcpy(ptr + l1, v2, l2);
memcpy(ptr + l1 + l2, v3, l3);
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret) {
free(ptr);
return ret;
}
- ret = krb5_create_checksum(_gsskrb5_context,
+ ret = krb5_create_checksum(context,
crypto,
usage,
0,
@@ -155,7 +156,7 @@ arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
free_Checksum(&CKSUM);
}
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return ret;
}
@@ -164,6 +165,7 @@ arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
OM_uint32
_gssapi_get_mic_arcfour(OM_uint32 * minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
gss_qop_t qop_req,
const gss_buffer_t message_buffer,
gss_buffer_t message_token,
@@ -200,7 +202,8 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
p = NULL;
- ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
+ ret = arcfour_mic_cksum(context,
+ key, KRB5_KU_USAGE_SIGN,
p0 + 16, 8, /* SGN_CKSUM */
p0, 8, /* TOK_ID, SGN_ALG, Filer */
message_buffer->value, message_buffer->length,
@@ -211,7 +214,7 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
return GSS_S_FAILURE;
}
- ret = arcfour_mic_key(_gsskrb5_context, key,
+ ret = arcfour_mic_key(context, key,
p0 + 16, 8, /* SGN_CKSUM */
k6_data, sizeof(k6_data));
if (ret) {
@@ -221,13 +224,13 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
}
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- krb5_auth_con_getlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_getlocalseqnumber (context,
context_handle->auth_context,
&seq_number);
p = p0 + 8; /* SND_SEQ */
_gsskrb5_encode_be_om_uint32(seq_number, p);
- krb5_auth_con_setlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber (context,
context_handle->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
@@ -248,6 +251,7 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
OM_uint32
_gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
gss_qop_t * qop_state,
@@ -279,7 +283,8 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
return GSS_S_BAD_MIC;
p += 4;
- ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
+ ret = arcfour_mic_cksum(context,
+ key, KRB5_KU_USAGE_SIGN,
cksum_data, sizeof(cksum_data),
p - 8, 8,
message_buffer->value, message_buffer->length,
@@ -289,7 +294,7 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
return GSS_S_FAILURE;
}
- ret = arcfour_mic_key(_gsskrb5_context, key,
+ ret = arcfour_mic_key(context, key,
cksum_data, sizeof(cksum_data),
k6_data, sizeof(k6_data));
if (ret) {
@@ -339,6 +344,7 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
OM_uint32
_gssapi_wrap_arcfour(OM_uint32 * minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
const gss_buffer_t input_message_buffer,
@@ -396,13 +402,13 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
p = NULL;
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- krb5_auth_con_getlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_getlocalseqnumber (context,
context_handle->auth_context,
&seq_number);
_gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
- krb5_auth_con_setlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber (context,
context_handle->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
@@ -420,7 +426,8 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
if (!IS_DCE_STYLE(context_handle))
p[input_message_buffer->length] = 1; /* padding */
- ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
+ ret = arcfour_mic_cksum(context,
+ key, KRB5_KU_USAGE_SEAL,
p0 + 16, 8, /* SGN_CKSUM */
p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
p0 + 24, 8, /* Confounder */
@@ -442,7 +449,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
for (i = 0; i < 16; i++)
Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
}
- ret = arcfour_mic_key(_gsskrb5_context, &Klocal,
+ ret = arcfour_mic_key(context, &Klocal,
p0 + 8, 4, /* SND_SEQ */
k6_data, sizeof(k6_data));
memset(Klocaldata, 0, sizeof(Klocaldata));
@@ -463,7 +470,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
}
memset(k6_data, 0, sizeof(k6_data));
- ret = arcfour_mic_key(_gsskrb5_context, key,
+ ret = arcfour_mic_key(context, key,
p0 + 16, 8, /* SGN_CKSUM */
k6_data, sizeof(k6_data));
if (ret) {
@@ -490,6 +497,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t input_message_buffer,
gss_buffer_t output_message_buffer,
int *conf_state,
@@ -562,7 +570,7 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
return GSS_S_BAD_MIC;
p = NULL;
- ret = arcfour_mic_key(_gsskrb5_context, key,
+ ret = arcfour_mic_key(context, key,
p0 + 16, 8, /* SGN_CKSUM */
k6_data, sizeof(k6_data));
if (ret) {
@@ -601,7 +609,7 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
for (i = 0; i < 16; i++)
Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
}
- ret = arcfour_mic_key(_gsskrb5_context, &Klocal,
+ ret = arcfour_mic_key(context, &Klocal,
SND_SEQ, 4,
k6_data, sizeof(k6_data));
memset(Klocaldata, 0, sizeof(Klocaldata));
@@ -643,7 +651,8 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
output_message_buffer->length -= padlen;
}
- ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
+ ret = arcfour_mic_cksum(context,
+ key, KRB5_KU_USAGE_SEAL,
cksum_data, sizeof(cksum_data),
p0, 8,
Confounder, sizeof(Confounder),
@@ -721,6 +730,7 @@ max_wrap_length_arcfour(const gsskrb5_ctx ctx,
OM_uint32
_gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
const gsskrb5_ctx ctx,
+ krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
OM_uint32 req_output_size,
@@ -730,9 +740,8 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
krb5_error_code ret;
krb5_crypto crypto;
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
return GSS_S_FAILURE;
}
@@ -740,13 +749,12 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
ret = max_wrap_length_arcfour(ctx, crypto,
req_output_size, max_input_size);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_COMPLETE;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/cfx.c b/source4/heimdal/lib/gssapi/krb5/cfx.c
index cb3f9ee5d31..e75fe5da9d8 100755
--- a/source4/heimdal/lib/gssapi/krb5/cfx.c
+++ b/source4/heimdal/lib/gssapi/krb5/cfx.c
@@ -32,7 +32,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: cfx.c,v 1.24 2006/10/24 21:13:22 lha Exp $");
+RCSID("$Id: cfx.c,v 1.25 2006/11/13 18:01:14 lha Exp $");
/*
* Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt
@@ -43,7 +43,8 @@ RCSID("$Id: cfx.c,v 1.24 2006/10/24 21:13:22 lha Exp $");
#define CFXAcceptorSubkey (1 << 2)
krb5_error_code
-_gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto,
+_gsskrb5cfx_wrap_length_cfx(krb5_context context,
+ krb5_crypto crypto,
int conf_req_flag,
size_t input_length,
size_t *output_length,
@@ -57,11 +58,11 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto,
*output_length = sizeof(gss_cfx_wrap_token_desc);
*padlength = 0;
- ret = krb5_crypto_get_checksum_type(_gsskrb5_context, crypto, &type);
+ ret = krb5_crypto_get_checksum_type(context, crypto, &type);
if (ret)
return ret;
- ret = krb5_checksumsize(_gsskrb5_context, type, cksumsize);
+ ret = krb5_checksumsize(context, type, cksumsize);
if (ret)
return ret;
@@ -71,7 +72,7 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto,
/* Header is concatenated with data before encryption */
input_length += sizeof(gss_cfx_wrap_token_desc);
- ret = krb5_crypto_getpadsize(_gsskrb5_context, crypto, &padsize);
+ ret = krb5_crypto_getpadsize(context, crypto, &padsize);
if (ret) {
return ret;
}
@@ -83,7 +84,7 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto,
input_length += *padlength;
}
- *output_length += krb5_get_wrapped_length(_gsskrb5_context,
+ *output_length += krb5_get_wrapped_length(context,
crypto, input_length);
} else {
/* Checksum is concatenated with data */
@@ -96,7 +97,8 @@ _gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto,
}
krb5_error_code
-_gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto,
+_gsskrb5cfx_max_wrap_length_cfx(krb5_context context,
+ krb5_crypto crypto,
int conf_req_flag,
size_t input_length,
OM_uint32 *output_length)
@@ -116,7 +118,7 @@ _gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto,
wrapped_size = input_length + 1;
do {
wrapped_size--;
- sz = krb5_get_wrapped_length(_gsskrb5_context,
+ sz = krb5_get_wrapped_length(context,
crypto, wrapped_size);
} while (wrapped_size && sz > input_length);
if (wrapped_size == 0) {
@@ -136,11 +138,11 @@ _gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto,
krb5_cksumtype type;
size_t cksumsize;
- ret = krb5_crypto_get_checksum_type(_gsskrb5_context, crypto, &type);
+ ret = krb5_crypto_get_checksum_type(context, crypto, &type);
if (ret)
return ret;
- ret = krb5_checksumsize(_gsskrb5_context, type, &cksumsize);
+ ret = krb5_checksumsize(context, type, &cksumsize);
if (ret)
return ret;
@@ -157,6 +159,7 @@ _gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto,
OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
OM_uint32 req_output_size,
@@ -166,23 +169,21 @@ OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
krb5_error_code ret;
krb5_crypto crypto;
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
return GSS_S_FAILURE;
}
- ret = _gsskrb5cfx_max_wrap_length_cfx(crypto, conf_req_flag,
+ ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag,
req_output_size, max_input_size);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_COMPLETE;
}
@@ -233,6 +234,7 @@ rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
const gss_buffer_t input_message_buffer,
@@ -250,20 +252,19 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
int32_t seq_number;
u_char *p;
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
return GSS_S_FAILURE;
}
- ret = _gsskrb5cfx_wrap_length_cfx(crypto, conf_req_flag,
+ ret = _gsskrb5cfx_wrap_length_cfx(context,
+ crypto, conf_req_flag,
input_message_buffer->length,
&wrapped_len, &cksumsize, &padlength);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
@@ -274,7 +275,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
output_message_buffer->value = malloc(output_message_buffer->length);
if (output_message_buffer->value == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
@@ -324,12 +325,12 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
token->RRC[1] = 0;
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- krb5_auth_con_getlocalseqnumber(_gsskrb5_context,
+ krb5_auth_con_getlocalseqnumber(context,
context_handle->auth_context,
&seq_number);
_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
- krb5_auth_con_setlocalseqnumber(_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber(context,
context_handle->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
@@ -364,15 +365,14 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
memcpy(p + input_message_buffer->length + padlength,
token, sizeof(*token));
- ret = krb5_encrypt(_gsskrb5_context, crypto,
+ ret = krb5_encrypt(context, crypto,
usage, p,
input_message_buffer->length + padlength +
sizeof(*token),
&cipher);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_FAILURE;
}
@@ -382,9 +382,8 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_FAILURE;
}
@@ -397,22 +396,21 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
buf = malloc(input_message_buffer->length + sizeof(*token));
if (buf == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_FAILURE;
}
memcpy(buf, input_message_buffer->value, input_message_buffer->length);
memcpy(buf + input_message_buffer->length, token, sizeof(*token));
- ret = krb5_create_checksum(_gsskrb5_context, crypto,
+ ret = krb5_create_checksum(context, crypto,
usage, 0, buf,
input_message_buffer->length +
sizeof(*token),
&cksum);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
free(buf);
return GSS_S_FAILURE;
@@ -434,9 +432,8 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
ret = rrc_rotate(p,
input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
free_Checksum(&cksum);
return GSS_S_FAILURE;
@@ -444,7 +441,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
free_Checksum(&cksum);
}
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
if (conf_state != NULL) {
*conf_state = conf_req_flag;
@@ -456,6 +453,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t input_message_buffer,
gss_buffer_t output_message_buffer,
int *conf_state,
@@ -539,9 +537,8 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
/*
* Decrypt and/or verify checksum
*/
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
return GSS_S_FAILURE;
}
@@ -559,23 +556,22 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
/* Rotate by RRC; bogus to do this in-place XXX */
*minor_status = rrc_rotate(p, len, rrc, TRUE);
if (*minor_status != 0) {
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
if (token_flags & CFXSealed) {
- ret = krb5_decrypt(_gsskrb5_context, crypto, usage,
+ ret = krb5_decrypt(context, crypto, usage,
p, len, &data);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_BAD_MIC;
}
/* Check that there is room for the pad and token header */
if (data.length < ec + sizeof(*token)) {
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
krb5_data_free(&data);
return GSS_S_DEFECTIVE_TOKEN;
}
@@ -588,7 +584,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
/* Check the integrity of the header */
if (memcmp(p, token, sizeof(*token)) != 0) {
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
krb5_data_free(&data);
return GSS_S_BAD_MIC;
}
@@ -599,12 +595,11 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
Checksum cksum;
/* Determine checksum type */
- ret = krb5_crypto_get_checksum_type(_gsskrb5_context,
+ ret = krb5_crypto_get_checksum_type(context,
crypto, &cksum.cksumtype);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
@@ -613,7 +608,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
/* Check we have at least as much data as the checksum */
if (len < cksum.checksum.length) {
*minor_status = ERANGE;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_BAD_MIC;
}
@@ -625,7 +620,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
output_message_buffer->value = malloc(len + sizeof(*token));
if (output_message_buffer->value == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
@@ -642,21 +637,20 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
token->RRC[0] = 0;
token->RRC[1] = 0;
- ret = krb5_verify_checksum(_gsskrb5_context, crypto,
+ ret = krb5_verify_checksum(context, crypto,
usage,
output_message_buffer->value,
len + sizeof(*token),
&cksum);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_BAD_MIC;
}
}
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
if (qop_state != NULL) {
*qop_state = GSS_C_QOP_DEFAULT;
@@ -668,6 +662,7 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
gss_qop_t qop_req,
const gss_buffer_t message_buffer,
gss_buffer_t message_token,
@@ -682,9 +677,8 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
size_t len;
int32_t seq_number;
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
return GSS_S_FAILURE;
}
@@ -693,7 +687,7 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
buf = malloc(len);
if (buf == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
@@ -710,12 +704,12 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
memset(token->Filler, 0xFF, 5);
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- krb5_auth_con_getlocalseqnumber(_gsskrb5_context,
+ krb5_auth_con_getlocalseqnumber(context,
context_handle->auth_context,
&seq_number);
_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
- krb5_auth_con_setlocalseqnumber(_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber(context,
context_handle->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
@@ -726,16 +720,15 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
}
- ret = krb5_create_checksum(_gsskrb5_context, crypto,
+ ret = krb5_create_checksum(context, crypto,
usage, 0, buf, len, &cksum);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
free(buf);
return GSS_S_FAILURE;
}
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
/* Determine MIC length */
message_token->length = sizeof(*token) + cksum.checksum.length;
@@ -761,6 +754,7 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
gss_qop_t *qop_state,
@@ -830,19 +824,17 @@ OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
/*
* Verify checksum
*/
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
return GSS_S_FAILURE;
}
- ret = krb5_crypto_get_checksum_type(_gsskrb5_context, crypto,
+ ret = krb5_crypto_get_checksum_type(context, crypto,
&cksum.cksumtype);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
@@ -858,20 +850,19 @@ OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
buf = malloc(message_buffer->length + sizeof(*token));
if (buf == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
memcpy(buf, message_buffer->value, message_buffer->length);
memcpy(buf + message_buffer->length, token, sizeof(*token));
- ret = krb5_verify_checksum(_gsskrb5_context, crypto,
+ ret = krb5_verify_checksum(context, crypto,
usage,
buf,
sizeof(*token) + message_buffer->length,
&cksum);
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
if (ret != 0) {
- _gsskrb5_set_error_string();
*minor_status = ret;
free(buf);
return GSS_S_BAD_MIC;
diff --git a/source4/heimdal/lib/gssapi/krb5/cfx.h b/source4/heimdal/lib/gssapi/krb5/cfx.h
index 1120544fbeb..ce021aa0993 100755
--- a/source4/heimdal/lib/gssapi/krb5/cfx.h
+++ b/source4/heimdal/lib/gssapi/krb5/cfx.h
@@ -30,7 +30,7 @@
* SUCH DAMAGE.
*/
-/* $Id: cfx.h,v 1.7 2006/07/19 14:16:33 lha Exp $ */
+/* $Id: cfx.h,v 1.8 2006/11/13 18:01:17 lha Exp $ */
#ifndef GSSAPI_CFX_H_
#define GSSAPI_CFX_H_ 1
@@ -62,19 +62,4 @@ typedef struct gss_cfx_delete_token_desc_struct {
u_char SND_SEQ[8];
} gss_cfx_delete_token_desc, *gss_cfx_delete_token;
-krb5_error_code
-_gsskrb5cfx_wrap_length_cfx(krb5_crypto crypto,
- int conf_req_flag,
- size_t input_length,
- size_t *output_length,
- size_t *cksumsize,
- uint16_t *padlength);
-
-krb5_error_code
-_gsskrb5cfx_max_wrap_length_cfx(krb5_crypto crypto,
- int conf_req_flag,
- size_t input_length,
- OM_uint32 *output_length);
-
-
#endif /* GSSAPI_CFX_H_ */
diff --git a/source4/heimdal/lib/gssapi/krb5/compare_name.c b/source4/heimdal/lib/gssapi/krb5/compare_name.c
index 3e0f7edfee3..6b537468df5 100644
--- a/source4/heimdal/lib/gssapi/krb5/compare_name.c
+++ b/source4/heimdal/lib/gssapi/krb5/compare_name.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: compare_name.c,v 1.7 2006/10/07 22:14:15 lha Exp $");
+RCSID("$Id: compare_name.c,v 1.8 2006/11/13 18:01:20 lha Exp $");
OM_uint32 _gsskrb5_compare_name
(OM_uint32 * minor_status,
@@ -44,10 +44,11 @@ OM_uint32 _gsskrb5_compare_name
{
krb5_const_principal princ1 = (krb5_const_principal)name1;
krb5_const_principal princ2 = (krb5_const_principal)name2;
+ krb5_context context;
- GSSAPI_KRB5_INIT();
+ GSSAPI_KRB5_INIT(&context);
- *name_equal = krb5_principal_compare (_gsskrb5_context,
+ *name_equal = krb5_principal_compare (context,
princ1, princ2);
*minor_status = 0;
return GSS_S_COMPLETE;
diff --git a/source4/heimdal/lib/gssapi/krb5/compat.c b/source4/heimdal/lib/gssapi/krb5/compat.c
index 0ea2fce0e83..3e64df03dbe 100644
--- a/source4/heimdal/lib/gssapi/krb5/compat.c
+++ b/source4/heimdal/lib/gssapi/krb5/compat.c
@@ -33,11 +33,12 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: compat.c,v 1.13 2006/10/07 22:14:17 lha Exp $");
+RCSID("$Id: compat.c,v 1.14 2006/11/13 18:01:23 lha Exp $");
static krb5_error_code
-check_compat(OM_uint32 *minor_status, krb5_const_principal name,
+check_compat(OM_uint32 *minor_status,
+ krb5_context context, krb5_const_principal name,
const char *option, krb5_boolean *compat,
krb5_boolean match_val)
{
@@ -46,27 +47,27 @@ check_compat(OM_uint32 *minor_status, krb5_const_principal name,
krb5_principal match;
- p = krb5_config_get_strings(_gsskrb5_context, NULL, "gssapi",
+ p = krb5_config_get_strings(context, NULL, "gssapi",
option, NULL);
if(p == NULL)
return 0;
match = NULL;
for(q = p; *q; q++) {
- ret = krb5_parse_name(_gsskrb5_context, *q, &match);
+ ret = krb5_parse_name(context, *q, &match);
if (ret)
break;
- if (krb5_principal_match(_gsskrb5_context, name, match)) {
+ if (krb5_principal_match(context, name, match)) {
*compat = match_val;
break;
}
- krb5_free_principal(_gsskrb5_context, match);
+ krb5_free_principal(context, match);
match = NULL;
}
if (match)
- krb5_free_principal(_gsskrb5_context, match);
+ krb5_free_principal(context, match);
krb5_config_free_strings(p);
if (ret) {
@@ -83,17 +84,19 @@ check_compat(OM_uint32 *minor_status, krb5_const_principal name,
*/
OM_uint32
-_gss_DES3_get_mic_compat(OM_uint32 *minor_status, gsskrb5_ctx ctx)
+_gss_DES3_get_mic_compat(OM_uint32 *minor_status,
+ gsskrb5_ctx ctx,
+ krb5_context context)
{
krb5_boolean use_compat = FALSE;
OM_uint32 ret;
if ((ctx->more_flags & COMPAT_OLD_DES3_SELECTED) == 0) {
- ret = check_compat(minor_status, ctx->target,
+ ret = check_compat(minor_status, context, ctx->target,
"broken_des3_mic", &use_compat, TRUE);
if (ret)
return ret;
- ret = check_compat(minor_status, ctx->target,
+ ret = check_compat(minor_status, context, ctx->target,
"correct_des3_mic", &use_compat, FALSE);
if (ret)
return ret;
diff --git a/source4/heimdal/lib/gssapi/krb5/context_time.c b/source4/heimdal/lib/gssapi/krb5/context_time.c
index 4e9d9f5d1d7..9012dd0b7f6 100644
--- a/source4/heimdal/lib/gssapi/krb5/context_time.c
+++ b/source4/heimdal/lib/gssapi/krb5/context_time.c
@@ -33,12 +33,13 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: context_time.c,v 1.13 2006/10/07 22:14:19 lha Exp $");
+RCSID("$Id: context_time.c,v 1.14 2006/11/13 18:01:26 lha Exp $");
OM_uint32
_gsskrb5_lifetime_left(OM_uint32 *minor_status,
- OM_uint32 lifetime,
- OM_uint32 *lifetime_rec)
+ krb5_context context,
+ OM_uint32 lifetime,
+ OM_uint32 *lifetime_rec)
{
krb5_timestamp timeret;
krb5_error_code kret;
@@ -48,10 +49,9 @@ _gsskrb5_lifetime_left(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
- kret = krb5_timeofday(_gsskrb5_context, &timeret);
+ kret = krb5_timeofday(context, &timeret);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
}
@@ -70,17 +70,19 @@ OM_uint32 _gsskrb5_context_time
OM_uint32 * time_rec
)
{
+ krb5_context context;
OM_uint32 lifetime;
OM_uint32 major_status;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
lifetime = ctx->lifetime;
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
- major_status = _gsskrb5_lifetime_left(minor_status, lifetime, time_rec);
+ major_status = _gsskrb5_lifetime_left(minor_status, context,
+ lifetime, time_rec);
if (major_status != GSS_S_COMPLETE)
return major_status;
diff --git a/source4/heimdal/lib/gssapi/krb5/copy_ccache.c b/source4/heimdal/lib/gssapi/krb5/copy_ccache.c
index 91d21a1aec4..4387a4e6ef2 100644
--- a/source4/heimdal/lib/gssapi/krb5/copy_ccache.c
+++ b/source4/heimdal/lib/gssapi/krb5/copy_ccache.c
@@ -33,11 +33,12 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: copy_ccache.c,v 1.16 2006/11/08 02:42:50 lha Exp $");
+RCSID("$Id: copy_ccache.c,v 1.17 2006/11/13 18:01:29 lha Exp $");
#if 0
OM_uint32
gss_krb5_copy_ccache(OM_uint32 *minor_status,
+ krb5_context context,
gss_cred_id_t cred,
krb5_ccache out)
{
@@ -51,11 +52,10 @@ gss_krb5_copy_ccache(OM_uint32 *minor_status,
return GSS_S_FAILURE;
}
- kret = krb5_cc_copy_cache(_gsskrb5_context, cred->ccache, out);
+ kret = krb5_cc_copy_cache(context, cred->ccache, out);
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
}
*minor_status = 0;
@@ -71,13 +71,14 @@ _gsskrb5_import_cred(OM_uint32 *minor_status,
krb5_keytab keytab,
gss_cred_id_t *cred)
{
+ krb5_context context;
krb5_error_code kret;
gsskrb5_cred handle;
OM_uint32 ret;
*cred = NULL;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
handle = calloc(1, sizeof(*handle));
if (handle == NULL) {
@@ -94,11 +95,10 @@ _gsskrb5_import_cred(OM_uint32 *minor_status,
handle->usage |= GSS_C_INITIATE;
- kret = krb5_cc_get_principal(_gsskrb5_context, id,
+ kret = krb5_cc_get_principal(context, id,
&handle->principal);
if (kret) {
free(handle);
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
@@ -106,11 +106,11 @@ _gsskrb5_import_cred(OM_uint32 *minor_status,
if (keytab_principal) {
krb5_boolean match;
- match = krb5_principal_compare(_gsskrb5_context,
+ match = krb5_principal_compare(context,
handle->principal,
keytab_principal);
if (match == FALSE) {
- krb5_free_principal(_gsskrb5_context, handle->principal);
+ krb5_free_principal(context, handle->principal);
free(handle);
_gsskrb5_clear_status ();
*minor_status = EINVAL;
@@ -119,21 +119,22 @@ _gsskrb5_import_cred(OM_uint32 *minor_status,
}
ret = __gsskrb5_ccache_lifetime(minor_status,
- id,
- handle->principal,
- &handle->lifetime);
+ context,
+ id,
+ handle->principal,
+ &handle->lifetime);
if (ret != GSS_S_COMPLETE) {
- krb5_free_principal(_gsskrb5_context, handle->principal);
+ krb5_free_principal(context, handle->principal);
free(handle);
return ret;
}
- kret = krb5_cc_get_full_name(_gsskrb5_context, id, &str);
+ kret = krb5_cc_get_full_name(context, id, &str);
if (kret)
goto out;
- kret = krb5_cc_resolve(_gsskrb5_context, str, &handle->ccache);
+ kret = krb5_cc_resolve(context, str, &handle->ccache);
free(str);
if (kret)
goto out;
@@ -146,18 +147,18 @@ _gsskrb5_import_cred(OM_uint32 *minor_status,
handle->usage |= GSS_C_ACCEPT;
if (keytab_principal && handle->principal == NULL) {
- kret = krb5_copy_principal(_gsskrb5_context,
+ kret = krb5_copy_principal(context,
keytab_principal,
&handle->principal);
if (kret)
goto out;
}
- kret = krb5_kt_get_full_name(_gsskrb5_context, keytab, &str);
+ kret = krb5_kt_get_full_name(context, keytab, &str);
if (kret)
goto out;
- kret = krb5_kt_resolve(_gsskrb5_context, str, &handle->keytab);
+ kret = krb5_kt_resolve(context, str, &handle->keytab);
free(str);
if (kret)
goto out;
@@ -180,9 +181,8 @@ _gsskrb5_import_cred(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
out:
- _gsskrb5_set_error_string ();
if (handle->principal)
- krb5_free_principal(_gsskrb5_context, handle->principal);
+ krb5_free_principal(context, handle->principal);
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
free(handle);
*minor_status = kret;
diff --git a/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c b/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c
index e890d7d2c26..c7f2ee262d0 100644
--- a/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c
@@ -33,16 +33,17 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: delete_sec_context.c,v 1.19 2006/10/07 22:14:28 lha Exp $");
+RCSID("$Id: delete_sec_context.c,v 1.20 2006/11/13 18:01:32 lha Exp $");
OM_uint32
_gsskrb5_delete_sec_context(OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
gss_buffer_t output_token)
{
+ krb5_context context;
gsskrb5_ctx ctx;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
*minor_status = 0;
@@ -59,17 +60,17 @@ _gsskrb5_delete_sec_context(OM_uint32 * minor_status,
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
- krb5_auth_con_free (_gsskrb5_context, ctx->auth_context);
+ krb5_auth_con_free (context, ctx->auth_context);
if(ctx->source)
- krb5_free_principal (_gsskrb5_context, ctx->source);
+ krb5_free_principal (context, ctx->source);
if(ctx->target)
- krb5_free_principal (_gsskrb5_context, ctx->target);
+ krb5_free_principal (context, ctx->target);
if (ctx->ticket)
- krb5_free_ticket (_gsskrb5_context, ctx->ticket);
+ krb5_free_ticket (context, ctx->ticket);
if(ctx->order)
_gssapi_msg_order_destroy(&ctx->order);
if (ctx->service_keyblock)
- krb5_free_keyblock (_gsskrb5_context, ctx->service_keyblock);
+ krb5_free_keyblock (context, ctx->service_keyblock);
krb5_data_free(&ctx->fwd_data);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
diff --git a/source4/heimdal/lib/gssapi/krb5/display_name.c b/source4/heimdal/lib/gssapi/krb5/display_name.c
index 8fce7d85724..4956c2d77f4 100644
--- a/source4/heimdal/lib/gssapi/krb5/display_name.c
+++ b/source4/heimdal/lib/gssapi/krb5/display_name.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: display_name.c,v 1.12 2006/10/07 22:14:31 lha Exp $");
+RCSID("$Id: display_name.c,v 1.13 2006/11/13 18:01:36 lha Exp $");
OM_uint32 _gsskrb5_display_name
(OM_uint32 * minor_status,
@@ -42,16 +42,17 @@ OM_uint32 _gsskrb5_display_name
gss_OID * output_name_type
)
{
+ krb5_context context;
krb5_const_principal name = (krb5_const_principal)input_name;
krb5_error_code kret;
char *buf;
size_t len;
- GSSAPI_KRB5_INIT ();
- kret = krb5_unparse_name (_gsskrb5_context, name, &buf);
+ GSSAPI_KRB5_INIT (&context);
+
+ kret = krb5_unparse_name (context, name, &buf);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
}
len = strlen (buf);
diff --git a/source4/heimdal/lib/gssapi/krb5/display_status.c b/source4/heimdal/lib/gssapi/krb5/display_status.c
index 11926ca5579..b0155a7fdfd 100644
--- a/source4/heimdal/lib/gssapi/krb5/display_status.c
+++ b/source4/heimdal/lib/gssapi/krb5/display_status.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 1998 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: display_status.c,v 1.16 2006/10/07 22:14:33 lha Exp $");
+RCSID("$Id: display_status.c,v 1.17 2006/11/13 18:01:38 lha Exp $");
static const char *
calling_error(OM_uint32 v)
@@ -114,117 +114,87 @@ supplementary_error(OM_uint32 v)
void
_gsskrb5_clear_status (void)
{
- struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(1);
- if (ctx == NULL)
+ krb5_context context;
+
+ if (_gsskrb5_init (&context) != 0)
return;
- HEIMDAL_MUTEX_lock(&ctx->mutex);
- if (ctx->error_string)
- free(ctx->error_string);
- ctx->error_string = NULL;
- HEIMDAL_MUTEX_unlock(&ctx->mutex);
+ krb5_clear_error_string(context);
}
void
_gsskrb5_set_status (const char *fmt, ...)
{
- struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(1);
+ krb5_context context;
va_list args;
+ char *str;
- if (ctx == NULL)
+ if (_gsskrb5_init (&context) != 0)
return;
- HEIMDAL_MUTEX_lock(&ctx->mutex);
+
va_start(args, fmt);
- if (ctx->error_string)
- free(ctx->error_string);
- /* ignore failures, will use status code instead */
- vasprintf(&ctx->error_string, fmt, args);
+ vasprintf(&str, fmt, args);
va_end(args);
- HEIMDAL_MUTEX_unlock(&ctx->mutex);
-}
-
-void
-_gsskrb5_set_error_string (void)
-{
- char *e;
-
- e = krb5_get_error_string(_gsskrb5_context);
- if (e) {
- _gsskrb5_set_status("%s", e);
- krb5_free_error_string(_gsskrb5_context, e);
- } else
- _gsskrb5_clear_status();
-}
-
-char *
-_gsskrb5_get_error_string (void)
-{
- struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(0);
- char *ret;
-
- if (ctx == NULL)
- return NULL;
- HEIMDAL_MUTEX_lock(&ctx->mutex);
- ret = ctx->error_string;
- ctx->error_string = NULL;
- HEIMDAL_MUTEX_unlock(&ctx->mutex);
- return ret;
+ if (str) {
+ krb5_set_error_string(context, str);
+ free(str);
+ }
}
OM_uint32 _gsskrb5_display_status
- (OM_uint32 *minor_status,
- OM_uint32 status_value,
- int status_type,
- const gss_OID mech_type,
- OM_uint32 *message_context,
- gss_buffer_t status_string)
+(OM_uint32 *minor_status,
+ OM_uint32 status_value,
+ int status_type,
+ const gss_OID mech_type,
+ OM_uint32 *message_context,
+ gss_buffer_t status_string)
{
- char *buf;
-
- GSSAPI_KRB5_INIT ();
-
- status_string->length = 0;
- status_string->value = NULL;
-
- if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 &&
- gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) {
- *minor_status = 0;
- return GSS_C_GSS_CODE;
- }
-
- if (status_type == GSS_C_GSS_CODE) {
- if (GSS_SUPPLEMENTARY_INFO(status_value))
- asprintf(&buf, "%s",
- supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value)));
- else
- asprintf (&buf, "%s %s",
- calling_error(GSS_CALLING_ERROR(status_value)),
- routine_error(GSS_ROUTINE_ERROR(status_value)));
- } else if (status_type == GSS_C_MECH_CODE) {
- buf = _gsskrb5_get_error_string ();
- if (buf == NULL) {
- const char *tmp = krb5_get_err_text (_gsskrb5_context,
- status_value);
- if (tmp == NULL)
- asprintf(&buf, "unknown mech error-code %u",
- (unsigned)status_value);
- else
- buf = strdup(tmp);
- }
- } else {
- *minor_status = EINVAL;
- return GSS_S_BAD_STATUS;
- }
-
- if (buf == NULL) {
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
-
- *message_context = 0;
- *minor_status = 0;
-
- status_string->length = strlen(buf);
- status_string->value = buf;
+ krb5_context context;
+ char *buf;
+
+ GSSAPI_KRB5_INIT (&context);
+
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 &&
+ gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) {
+ *minor_status = 0;
+ return GSS_C_GSS_CODE;
+ }
+
+ if (status_type == GSS_C_GSS_CODE) {
+ if (GSS_SUPPLEMENTARY_INFO(status_value))
+ asprintf(&buf, "%s",
+ supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value)));
+ else
+ asprintf (&buf, "%s %s",
+ calling_error(GSS_CALLING_ERROR(status_value)),
+ routine_error(GSS_ROUTINE_ERROR(status_value)));
+ } else if (status_type == GSS_C_MECH_CODE) {
+ buf = krb5_get_error_string(context);
+ if (buf == NULL) {
+ const char *tmp = krb5_get_err_text (context, status_value);
+ if (tmp == NULL)
+ asprintf(&buf, "unknown mech error-code %u",
+ (unsigned)status_value);
+ else
+ buf = strdup(tmp);
+ }
+ } else {
+ *minor_status = EINVAL;
+ return GSS_S_BAD_STATUS;
+ }
+
+ if (buf == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ *message_context = 0;
+ *minor_status = 0;
+
+ status_string->length = strlen(buf);
+ status_string->value = buf;
- return GSS_S_COMPLETE;
+ return GSS_S_COMPLETE;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/duplicate_name.c b/source4/heimdal/lib/gssapi/krb5/duplicate_name.c
index 475ae61efce..8375257180d 100644
--- a/source4/heimdal/lib/gssapi/krb5/duplicate_name.c
+++ b/source4/heimdal/lib/gssapi/krb5/duplicate_name.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: duplicate_name.c,v 1.10 2006/10/07 22:14:35 lha Exp $");
+RCSID("$Id: duplicate_name.c,v 1.11 2006/11/13 18:01:42 lha Exp $");
OM_uint32 _gsskrb5_duplicate_name (
OM_uint32 * minor_status,
@@ -41,16 +41,16 @@ OM_uint32 _gsskrb5_duplicate_name (
gss_name_t * dest_name
)
{
+ krb5_context context;
krb5_const_principal src = (krb5_const_principal)src_name;
krb5_principal *dest = (krb5_principal *)dest_name;
krb5_error_code kret;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
- kret = krb5_copy_principal (_gsskrb5_context, src, dest);
+ kret = krb5_copy_principal (context, src, dest);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
} else {
*minor_status = 0;
diff --git a/source4/heimdal/lib/gssapi/krb5/export_name.c b/source4/heimdal/lib/gssapi/krb5/export_name.c
index d00c458898a..646fdafb7c4 100644
--- a/source4/heimdal/lib/gssapi/krb5/export_name.c
+++ b/source4/heimdal/lib/gssapi/krb5/export_name.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: export_name.c,v 1.8 2006/10/07 22:14:40 lha Exp $");
+RCSID("$Id: export_name.c,v 1.9 2006/11/13 18:01:50 lha Exp $");
OM_uint32 _gsskrb5_export_name
(OM_uint32 * minor_status,
@@ -41,16 +41,17 @@ OM_uint32 _gsskrb5_export_name
gss_buffer_t exported_name
)
{
+ krb5_context context;
krb5_const_principal princ = (krb5_const_principal)input_name;
krb5_error_code kret;
char *buf, *name;
size_t len;
- GSSAPI_KRB5_INIT ();
- kret = krb5_unparse_name (_gsskrb5_context, princ, &name);
+ GSSAPI_KRB5_INIT (&context);
+
+ kret = krb5_unparse_name (context, princ, &name);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
}
len = strlen (name);
diff --git a/source4/heimdal/lib/gssapi/krb5/export_sec_context.c b/source4/heimdal/lib/gssapi/krb5/export_sec_context.c
index aff03a0b675..ffa671a4a14 100644
--- a/source4/heimdal/lib/gssapi/krb5/export_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/export_sec_context.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: export_sec_context.c,v 1.11 2006/10/07 22:14:42 lha Exp $");
+RCSID("$Id: export_sec_context.c,v 1.12 2006/11/13 18:01:55 lha Exp $");
OM_uint32
_gsskrb5_export_sec_context (
@@ -42,6 +42,7 @@ _gsskrb5_export_sec_context (
gss_buffer_t interprocess_token
)
{
+ krb5_context context;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle;
krb5_storage *sp;
krb5_auth_context ac;
@@ -52,7 +53,7 @@ _gsskrb5_export_sec_context (
OM_uint32 minor;
krb5_error_code kret;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
diff --git a/source4/heimdal/lib/gssapi/krb5/external.c b/source4/heimdal/lib/gssapi/krb5/external.c
index 0681bd40386..bf7f64cf20e 100644
--- a/source4/heimdal/lib/gssapi/krb5/external.c
+++ b/source4/heimdal/lib/gssapi/krb5/external.c
@@ -34,7 +34,7 @@
#include "krb5/gsskrb5_locl.h"
#include <gssapi_mech.h>
-RCSID("$Id: external.c,v 1.22 2006/11/08 23:00:20 lha Exp $");
+RCSID("$Id: external.c,v 1.23 2006/11/13 18:01:57 lha Exp $");
/*
* The implementation must reserve static storage for a
@@ -369,7 +369,7 @@ gss_OID GSS_SASL_DIGEST_MD5_MECHANISM = &gss_sasl_digest_md5_mechanism_desc;
* Context for krb5 calls.
*/
-krb5_context _gsskrb5_context;
+krb5_context context;
/*
*
diff --git a/source4/heimdal/lib/gssapi/krb5/get_mic.c b/source4/heimdal/lib/gssapi/krb5/get_mic.c
index 5a078d634d0..790c9b61663 100644
--- a/source4/heimdal/lib/gssapi/krb5/get_mic.c
+++ b/source4/heimdal/lib/gssapi/krb5/get_mic.c
@@ -33,12 +33,13 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: get_mic.c,v 1.34 2006/10/18 15:59:23 lha Exp $");
+RCSID("$Id: get_mic.c,v 1.35 2006/11/13 18:02:00 lha Exp $");
static OM_uint32
mic_des
(OM_uint32 * minor_status,
const gsskrb5_ctx ctx,
+ krb5_context context,
gss_qop_t qop_req,
const gss_buffer_t message_buffer,
gss_buffer_t message_token,
@@ -94,9 +95,9 @@ mic_des
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
/* sequence number */
- krb5_auth_con_getlocalseqnumber (_gsskrb5_context,
- ctx->auth_context,
- &seq_number);
+ krb5_auth_con_getlocalseqnumber (context,
+ ctx->auth_context,
+ &seq_number);
p -= 16; /* SND_SEQ */
p[0] = (seq_number >> 0) & 0xFF;
@@ -111,7 +112,7 @@ mic_des
DES_cbc_encrypt ((void *)p, (void *)p, 8,
&schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
- krb5_auth_con_setlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber (context,
ctx->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
@@ -127,6 +128,7 @@ static OM_uint32
mic_des3
(OM_uint32 * minor_status,
const gsskrb5_ctx ctx,
+ krb5_context context,
gss_qop_t qop_req,
const gss_buffer_t message_buffer,
gss_buffer_t message_token,
@@ -180,18 +182,17 @@ mic_des3
memcpy (tmp, p - 8, 8);
memcpy (tmp + 8, message_buffer->value, message_buffer->length);
- kret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ kret = krb5_crypto_init(context, key, 0, &crypto);
if (kret) {
free (message_token->value);
message_token->value = NULL;
message_token->length = 0;
free (tmp);
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
- kret = krb5_create_checksum (_gsskrb5_context,
+ kret = krb5_create_checksum (context,
crypto,
KRB5_KU_USAGE_SIGN,
0,
@@ -199,12 +200,11 @@ mic_des3
message_buffer->length + 8,
&cksum);
free (tmp);
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
if (kret) {
free (message_token->value);
message_token->value = NULL;
message_token->length = 0;
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
@@ -213,7 +213,7 @@ mic_des3
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
/* sequence number */
- krb5_auth_con_getlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_getlocalseqnumber (context,
ctx->auth_context,
&seq_number);
@@ -225,13 +225,12 @@ mic_des3
(ctx->more_flags & LOCAL) ? 0 : 0xFF,
4);
- kret = krb5_crypto_init(_gsskrb5_context, key,
+ kret = krb5_crypto_init(context, key,
ETYPE_DES3_CBC_NONE, &crypto);
if (kret) {
free (message_token->value);
message_token->value = NULL;
message_token->length = 0;
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
@@ -241,16 +240,15 @@ mic_des3
else
memcpy(ivec, p + 8, 8);
- kret = krb5_encrypt_ivec (_gsskrb5_context,
+ kret = krb5_encrypt_ivec (context,
crypto,
KRB5_KU_USAGE_SEQ,
seq, 8, &encdata, ivec);
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
if (kret) {
free (message_token->value);
message_token->value = NULL;
message_token->length = 0;
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
@@ -260,7 +258,7 @@ mic_des3
memcpy (p, encdata.data, encdata.length);
krb5_data_free (&encdata);
- krb5_auth_con_setlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber (context,
ctx->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
@@ -278,40 +276,42 @@ OM_uint32 _gsskrb5_get_mic
gss_buffer_t message_token
)
{
+ krb5_context context;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
krb5_keyblock *key;
OM_uint32 ret;
krb5_keytype keytype;
+ GSSAPI_KRB5_INIT (&context);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
- ret = _gsskrb5i_get_token_key(ctx, &key);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
- krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype);
+ krb5_enctype_to_keytype (context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_DES :
- ret = mic_des (minor_status, ctx, qop_req,
+ ret = mic_des (minor_status, ctx, context, qop_req,
message_buffer, message_token, key);
break;
case KEYTYPE_DES3 :
- ret = mic_des3 (minor_status, ctx, qop_req,
+ ret = mic_des3 (minor_status, ctx, context, qop_req,
message_buffer, message_token, key);
break;
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
- ret = _gssapi_get_mic_arcfour (minor_status, ctx, qop_req,
+ ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
message_buffer, message_token, key);
break;
default :
- ret = _gssapi_mic_cfx (minor_status, ctx, qop_req,
+ ret = _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
message_buffer, message_token, key);
break;
}
- krb5_free_keyblock (_gsskrb5_context, key);
+ krb5_free_keyblock (context, key);
return ret;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h b/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h
index 426c0ab2007..15bd5c77dae 100644
--- a/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h
+++ b/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h
@@ -10,6 +10,7 @@ __gss_krb5_initialize (void);
OM_uint32
__gsskrb5_ccache_lifetime (
OM_uint32 */*minor_status*/,
+ krb5_context /*context*/,
krb5_ccache /*id*/,
krb5_principal /*principal*/,
OM_uint32 */*lifetime*/);
@@ -17,7 +18,8 @@ __gsskrb5_ccache_lifetime (
OM_uint32
_gss_DES3_get_mic_compat (
OM_uint32 */*minor_status*/,
- gsskrb5_ctx /*ctx*/);
+ gsskrb5_ctx /*ctx*/,
+ krb5_context /*context*/);
OM_uint32
_gssapi_decapsulate (
@@ -44,6 +46,7 @@ OM_uint32
_gssapi_get_mic_arcfour (
OM_uint32 * /*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
gss_qop_t /*qop_req*/,
const gss_buffer_t /*message_buffer*/,
gss_buffer_t /*message_token*/,
@@ -59,6 +62,7 @@ OM_uint32
_gssapi_mic_cfx (
OM_uint32 */*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
gss_qop_t /*qop_req*/,
const gss_buffer_t /*message_buffer*/,
gss_buffer_t /*message_token*/,
@@ -99,6 +103,7 @@ OM_uint32
_gssapi_unwrap_arcfour (
OM_uint32 */*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
const gss_buffer_t /*input_message_buffer*/,
gss_buffer_t /*output_message_buffer*/,
int */*conf_state*/,
@@ -109,6 +114,7 @@ OM_uint32
_gssapi_unwrap_cfx (
OM_uint32 */*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
const gss_buffer_t /*input_message_buffer*/,
gss_buffer_t /*output_message_buffer*/,
int */*conf_state*/,
@@ -125,6 +131,7 @@ OM_uint32
_gssapi_verify_mic_arcfour (
OM_uint32 * /*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
const gss_buffer_t /*message_buffer*/,
const gss_buffer_t /*token_buffer*/,
gss_qop_t * /*qop_state*/,
@@ -135,6 +142,7 @@ OM_uint32
_gssapi_verify_mic_cfx (
OM_uint32 */*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
const gss_buffer_t /*message_buffer*/,
const gss_buffer_t /*token_buffer*/,
gss_qop_t */*qop_state*/,
@@ -150,6 +158,7 @@ OM_uint32
_gssapi_wrap_arcfour (
OM_uint32 * /*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
int /*conf_req_flag*/,
gss_qop_t /*qop_req*/,
const gss_buffer_t /*input_message_buffer*/,
@@ -161,6 +170,7 @@ OM_uint32
_gssapi_wrap_cfx (
OM_uint32 */*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
int /*conf_req_flag*/,
gss_qop_t /*qop_req*/,
const gss_buffer_t /*input_message_buffer*/,
@@ -172,6 +182,7 @@ OM_uint32
_gssapi_wrap_size_arcfour (
OM_uint32 */*minor_status*/,
const gsskrb5_ctx /*ctx*/,
+ krb5_context /*context*/,
int /*conf_req_flag*/,
gss_qop_t /*qop_req*/,
OM_uint32 /*req_output_size*/,
@@ -182,6 +193,7 @@ OM_uint32
_gssapi_wrap_size_cfx (
OM_uint32 */*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
int /*conf_req_flag*/,
gss_qop_t /*qop_req*/,
OM_uint32 /*req_output_size*/,
@@ -268,6 +280,7 @@ OM_uint32
_gsskrb5_create_ctx (
OM_uint32 * /*minor_status*/,
gss_ctx_id_t * /*context_handle*/,
+ krb5_context /*context*/,
const gss_channel_bindings_t /*input_chan_bindings*/,
enum gss_ctx_id_t_state /*state*/);
@@ -359,9 +372,6 @@ _gsskrb5_export_sec_context (
gss_ctx_id_t * /*context_handle*/,
gss_buffer_t interprocess_token );
-char *
-_gsskrb5_get_error_string (void);
-
ssize_t
_gsskrb5_get_mech (
const u_char */*ptr*/,
@@ -376,9 +386,6 @@ _gsskrb5_get_mic (
const gss_buffer_t /*message_buffer*/,
gss_buffer_t message_token );
-struct gssapi_thr_context *
-_gsskrb5_get_thread_context (int /*createp*/);
-
OM_uint32
_gsskrb5_get_tkt_flags (
OM_uint32 */*minor_status*/,
@@ -412,7 +419,7 @@ _gsskrb5_indicate_mechs (
gss_OID_set * mech_set );
krb5_error_code
-_gsskrb5_init (void);
+_gsskrb5_init (krb5_context */*context*/);
OM_uint32
_gsskrb5_init_sec_context (
@@ -496,6 +503,7 @@ _gsskrb5_krb5_ccache_name (
OM_uint32
_gsskrb5_lifetime_left (
OM_uint32 */*minor_status*/,
+ krb5_context /*context*/,
OM_uint32 /*lifetime*/,
OM_uint32 */*lifetime_rec*/);
@@ -552,9 +560,6 @@ _gsskrb5_set_cred_option (
const gss_OID /*desired_object*/,
const gss_buffer_t /*value*/);
-void
-_gsskrb5_set_error_string (void);
-
OM_uint32
_gsskrb5_set_sec_context_option (
OM_uint32 */*minor_status*/,
@@ -635,6 +640,7 @@ OM_uint32
_gsskrb5_verify_mic_internal (
OM_uint32 * /*minor_status*/,
const gsskrb5_ctx /*context_handle*/,
+ krb5_context /*context*/,
const gss_buffer_t /*message_buffer*/,
const gss_buffer_t /*token_buffer*/,
gss_qop_t * /*qop_state*/,
@@ -661,6 +667,7 @@ _gsskrb5_wrap_size_limit (
krb5_error_code
_gsskrb5cfx_max_wrap_length_cfx (
+ krb5_context /*context*/,
krb5_crypto /*crypto*/,
int /*conf_req_flag*/,
size_t /*input_length*/,
@@ -668,6 +675,7 @@ _gsskrb5cfx_max_wrap_length_cfx (
krb5_error_code
_gsskrb5cfx_wrap_length_cfx (
+ krb5_context /*context*/,
krb5_crypto /*crypto*/,
int /*conf_req_flag*/,
size_t /*input_length*/,
@@ -677,6 +685,7 @@ _gsskrb5cfx_wrap_length_cfx (
krb5_error_code
_gsskrb5i_address_to_krb5addr (
+ krb5_context /*context*/,
OM_uint32 /*gss_addr_type*/,
gss_buffer_desc */*gss_addr*/,
int16_t /*port*/,
@@ -685,16 +694,19 @@ _gsskrb5i_address_to_krb5addr (
krb5_error_code
_gsskrb5i_get_acceptor_subkey (
const gsskrb5_ctx /*ctx*/,
+ krb5_context /*context*/,
krb5_keyblock **/*key*/);
krb5_error_code
_gsskrb5i_get_initiator_subkey (
const gsskrb5_ctx /*ctx*/,
+ krb5_context /*context*/,
krb5_keyblock **/*key*/);
OM_uint32
_gsskrb5i_get_token_key (
const gsskrb5_ctx /*ctx*/,
+ krb5_context /*context*/,
krb5_keyblock **/*key*/);
void
diff --git a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h
index 39c800bf31b..1983a9b8e4d 100644
--- a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h
+++ b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: gsskrb5_locl.h,v 1.8 2006/11/10 00:36:40 lha Exp $ */
+/* $Id: gsskrb5_locl.h,v 1.9 2006/11/13 18:02:03 lha Exp $ */
#ifndef GSSKRB5_LOCL_H
#define GSSKRB5_LOCL_H
@@ -100,8 +100,6 @@ typedef struct Principal *gsskrb5_name;
*
*/
-extern krb5_context _gsskrb5_context;
-
extern krb5_keytab _gsskrb5_keytab;
extern HEIMDAL_MUTEX gssapi_keytab_mutex;
@@ -116,9 +114,9 @@ struct gssapi_thr_context {
#include <krb5/gsskrb5-private.h>
-#define GSSAPI_KRB5_INIT() do { \
+#define GSSAPI_KRB5_INIT(ctx) do { \
krb5_error_code kret_gss_init; \
- if((kret_gss_init = _gsskrb5_init ()) != 0) { \
+ if((kret_gss_init = _gsskrb5_init (ctx)) != 0) { \
*minor_status = kret_gss_init; \
return GSS_S_FAILURE; \
} \
diff --git a/source4/heimdal/lib/gssapi/krb5/import_name.c b/source4/heimdal/lib/gssapi/krb5/import_name.c
index dc24ed5cf20..15311b46149 100644
--- a/source4/heimdal/lib/gssapi/krb5/import_name.c
+++ b/source4/heimdal/lib/gssapi/krb5/import_name.c
@@ -33,23 +33,23 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: import_name.c,v 1.17 2006/10/07 22:14:51 lha Exp $");
+RCSID("$Id: import_name.c,v 1.18 2006/11/13 18:02:06 lha Exp $");
static OM_uint32
parse_krb5_name (OM_uint32 *minor_status,
+ krb5_context context,
const char *name,
gss_name_t *output_name)
{
krb5_principal princ;
krb5_error_code kerr;
- kerr = krb5_parse_name (_gsskrb5_context, name, &princ);
+ kerr = krb5_parse_name (context, name, &princ);
if (kerr == 0) {
*output_name = (gss_name_t)princ;
return GSS_S_COMPLETE;
}
- _gsskrb5_set_error_string ();
*minor_status = kerr;
if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
@@ -60,6 +60,7 @@ parse_krb5_name (OM_uint32 *minor_status,
static OM_uint32
import_krb5_name (OM_uint32 *minor_status,
+ krb5_context context,
const gss_buffer_t input_name_buffer,
gss_name_t *output_name)
{
@@ -76,7 +77,7 @@ import_krb5_name (OM_uint32 *minor_status,
input_name_buffer->length);
tmp[input_name_buffer->length] = '\0';
- ret = parse_krb5_name(minor_status, tmp, output_name);
+ ret = parse_krb5_name(minor_status, context, tmp, output_name);
free(tmp);
return ret;
@@ -84,6 +85,7 @@ import_krb5_name (OM_uint32 *minor_status,
static OM_uint32
import_hostbased_name (OM_uint32 *minor_status,
+ krb5_context context,
const gss_buffer_t input_name_buffer,
gss_name_t *output_name)
{
@@ -117,7 +119,7 @@ import_hostbased_name (OM_uint32 *minor_status,
host = local_hostname;
}
- kerr = krb5_sname_to_principal (_gsskrb5_context,
+ kerr = krb5_sname_to_principal (context,
host,
tmp,
KRB5_NT_SRV_HST,
@@ -128,8 +130,6 @@ import_hostbased_name (OM_uint32 *minor_status,
*output_name = (gss_name_t)princ;
return GSS_S_COMPLETE;
}
- _gsskrb5_set_error_string ();
- *minor_status = kerr;
if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
return GSS_S_BAD_NAME;
@@ -139,6 +139,7 @@ import_hostbased_name (OM_uint32 *minor_status,
static OM_uint32
import_export_name (OM_uint32 *minor_status,
+ krb5_context context,
const gss_buffer_t input_name_buffer,
gss_name_t *output_name)
{
@@ -178,7 +179,7 @@ import_export_name (OM_uint32 *minor_status,
memcpy(name, p, length);
name[length] = '\0';
- ret = parse_krb5_name(minor_status, name, output_name);
+ ret = parse_krb5_name(minor_status, context, name, output_name);
free(name);
return ret;
@@ -191,14 +192,17 @@ OM_uint32 _gsskrb5_import_name
gss_name_t * output_name
)
{
- GSSAPI_KRB5_INIT ();
+ krb5_context context;
*minor_status = 0;
*output_name = GSS_C_NO_NAME;
+ GSSAPI_KRB5_INIT (&context);
+
if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE) ||
gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE_X))
return import_hostbased_name (minor_status,
+ context,
input_name_buffer,
output_name);
else if (gss_oid_equal(input_name_type, GSS_C_NO_OID)
@@ -206,10 +210,12 @@ OM_uint32 _gsskrb5_import_name
|| gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME))
/* default printable syntax */
return import_krb5_name (minor_status,
+ context,
input_name_buffer,
output_name);
else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
return import_export_name(minor_status,
+ context,
input_name_buffer,
output_name);
} else {
diff --git a/source4/heimdal/lib/gssapi/krb5/import_sec_context.c b/source4/heimdal/lib/gssapi/krb5/import_sec_context.c
index 8131e2621d1..bbdc1d36d0c 100644
--- a/source4/heimdal/lib/gssapi/krb5/import_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/import_sec_context.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: import_sec_context.c,v 1.17 2006/10/07 22:14:53 lha Exp $");
+RCSID("$Id: import_sec_context.c,v 1.18 2006/11/13 18:02:09 lha Exp $");
OM_uint32
_gsskrb5_import_sec_context (
@@ -43,6 +43,7 @@ _gsskrb5_import_sec_context (
)
{
OM_uint32 ret = GSS_S_FAILURE;
+ krb5_context context;
krb5_error_code kret;
krb5_storage *sp;
krb5_auth_context ac;
@@ -56,7 +57,7 @@ _gsskrb5_import_sec_context (
gsskrb5_ctx ctx;
gss_name_t name;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
*context_handle = GSS_C_NO_CONTEXT;
@@ -77,10 +78,9 @@ _gsskrb5_import_sec_context (
}
HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
- kret = krb5_auth_con_init (_gsskrb5_context,
+ kret = krb5_auth_con_init (context,
&ctx->auth_context);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
@@ -108,11 +108,11 @@ _gsskrb5_import_sec_context (
goto failure;
}
- krb5_auth_con_setaddrs (_gsskrb5_context, ac, localp, remotep);
+ krb5_auth_con_setaddrs (context, ac, localp, remotep);
if (localp)
- krb5_free_address (_gsskrb5_context, localp);
+ krb5_free_address (context, localp);
if (remotep)
- krb5_free_address (_gsskrb5_context, remotep);
+ krb5_free_address (context, remotep);
localp = remotep = NULL;
if (krb5_ret_int16 (sp, &ac->local_port) != 0)
@@ -123,20 +123,20 @@ _gsskrb5_import_sec_context (
if (flags & SC_KEYBLOCK) {
if (krb5_ret_keyblock (sp, &keyblock) != 0)
goto failure;
- krb5_auth_con_setkey (_gsskrb5_context, ac, &keyblock);
- krb5_free_keyblock_contents (_gsskrb5_context, &keyblock);
+ krb5_auth_con_setkey (context, ac, &keyblock);
+ krb5_free_keyblock_contents (context, &keyblock);
}
if (flags & SC_LOCAL_SUBKEY) {
if (krb5_ret_keyblock (sp, &keyblock) != 0)
goto failure;
- krb5_auth_con_setlocalsubkey (_gsskrb5_context, ac, &keyblock);
- krb5_free_keyblock_contents (_gsskrb5_context, &keyblock);
+ krb5_auth_con_setlocalsubkey (context, ac, &keyblock);
+ krb5_free_keyblock_contents (context, &keyblock);
}
if (flags & SC_REMOTE_SUBKEY) {
if (krb5_ret_keyblock (sp, &keyblock) != 0)
goto failure;
- krb5_auth_con_setremotesubkey (_gsskrb5_context, ac, &keyblock);
- krb5_free_keyblock_contents (_gsskrb5_context, &keyblock);
+ krb5_auth_con_setremotesubkey (context, ac, &keyblock);
+ krb5_free_keyblock_contents (context, &keyblock);
}
if (krb5_ret_uint32 (sp, &ac->local_seqnumber))
goto failure;
@@ -209,16 +209,16 @@ _gsskrb5_import_sec_context (
return GSS_S_COMPLETE;
failure:
- krb5_auth_con_free (_gsskrb5_context,
+ krb5_auth_con_free (context,
ctx->auth_context);
if (ctx->source != NULL)
- krb5_free_principal(_gsskrb5_context, ctx->source);
+ krb5_free_principal(context, ctx->source);
if (ctx->target != NULL)
- krb5_free_principal(_gsskrb5_context, ctx->target);
+ krb5_free_principal(context, ctx->target);
if (localp)
- krb5_free_address (_gsskrb5_context, localp);
+ krb5_free_address (context, localp);
if (remotep)
- krb5_free_address (_gsskrb5_context, remotep);
+ krb5_free_address (context, remotep);
if(ctx->order)
_gssapi_msg_order_destroy(&ctx->order);
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
diff --git a/source4/heimdal/lib/gssapi/krb5/init.c b/source4/heimdal/lib/gssapi/krb5/init.c
index cbef8740b7a..3eece8e0864 100644
--- a/source4/heimdal/lib/gssapi/krb5/init.c
+++ b/source4/heimdal/lib/gssapi/krb5/init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2001, 2003, 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,79 +33,51 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: init.c,v 1.9 2006/10/07 22:14:58 lha Exp $");
+RCSID("$Id: init.c,v 1.10 2006/11/13 18:02:12 lha Exp $");
-static HEIMDAL_MUTEX _gsskrb5_context_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER;
static int created_key;
-static HEIMDAL_thread_key gssapi_context_key;
+static HEIMDAL_thread_key context_key;
static void
-gssapi_destroy_thread_context(void *ptr)
+destroy_context(void *ptr)
{
- struct gssapi_thr_context *ctx = ptr;
+ krb5_context context = ptr;
- if (ctx == NULL)
+ if (context == NULL)
return;
- if (ctx->error_string)
- free(ctx->error_string);
- HEIMDAL_MUTEX_destroy(&ctx->mutex);
- free(ctx);
-}
-
-
-struct gssapi_thr_context *
-_gsskrb5_get_thread_context(int createp)
-{
- struct gssapi_thr_context *ctx;
- int ret;
-
- HEIMDAL_MUTEX_lock(&_gsskrb5_context_mutex);
-
- if (!created_key)
- abort();
- ctx = HEIMDAL_getspecific(gssapi_context_key);
- if (ctx == NULL) {
- if (!createp)
- goto fail;
- ctx = malloc(sizeof(*ctx));
- if (ctx == NULL)
- goto fail;
- ctx->error_string = NULL;
- HEIMDAL_MUTEX_init(&ctx->mutex);
- HEIMDAL_setspecific(gssapi_context_key, ctx, ret);
- if (ret)
- goto fail;
- }
- HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex);
- return ctx;
- fail:
- HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex);
- if (ctx)
- free(ctx);
- return NULL;
+ krb5_free_context(context);
}
krb5_error_code
-_gsskrb5_init (void)
+_gsskrb5_init (krb5_context *context)
{
krb5_error_code ret = 0;
- HEIMDAL_MUTEX_lock(&_gsskrb5_context_mutex);
+ HEIMDAL_MUTEX_lock(&context_mutex);
- if(_gsskrb5_context == NULL)
- ret = krb5_init_context (&_gsskrb5_context);
- if (ret == 0 && !created_key) {
- HEIMDAL_key_create(&gssapi_context_key,
- gssapi_destroy_thread_context,
- ret);
+ if (!created_key) {
+ HEIMDAL_key_create(&context_key, destroy_context, ret);
if (ret) {
- krb5_free_context(_gsskrb5_context);
- _gsskrb5_context = NULL;
- } else
- created_key = 1;
+ HEIMDAL_MUTEX_unlock(&context_mutex);
+ return ret;
+ }
+ created_key = 1;
}
+ HEIMDAL_MUTEX_unlock(&context_mutex);
- HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex);
+ *context = HEIMDAL_getspecific(context_key);
+ if (*context == NULL) {
+
+ ret = krb5_init_context(context);
+ if (ret == 0) {
+ HEIMDAL_setspecific(context_key, *context, ret);
+ if (ret) {
+ krb5_free_context(*context);
+ *context = NULL;
+ }
+ }
+ }
return ret;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
index 27d859ddd88..d5f183b0baa 100644
--- a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: init_sec_context.c,v 1.73 2006/11/07 17:40:01 lha Exp $");
+RCSID("$Id: init_sec_context.c,v 1.75 2006/12/13 10:33:20 lha Exp $");
/*
* copy the addresses from `input_chan_bindings' (if any) to
@@ -41,7 +41,8 @@ RCSID("$Id: init_sec_context.c,v 1.73 2006/11/07 17:40:01 lha Exp $");
*/
static OM_uint32
-set_addresses (krb5_auth_context ac,
+set_addresses (krb5_context context,
+ krb5_auth_context ac,
const gss_channel_bindings_t input_chan_bindings)
{
/* Port numbers are expected to be in application_data.value,
@@ -64,29 +65,31 @@ set_addresses (krb5_auth_context ac,
ac->remote_port =
*((int16_t *) input_chan_bindings->application_data.value + 1);
- kret = _gsskrb5i_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
+ kret = _gsskrb5i_address_to_krb5addr(context,
+ input_chan_bindings->acceptor_addrtype,
&input_chan_bindings->acceptor_address,
ac->remote_port,
&acceptor_addr);
if (kret)
return kret;
- kret = _gsskrb5i_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
+ kret = _gsskrb5i_address_to_krb5addr(context,
+ input_chan_bindings->initiator_addrtype,
&input_chan_bindings->initiator_address,
ac->local_port,
&initiator_addr);
if (kret) {
- krb5_free_address (_gsskrb5_context, &acceptor_addr);
+ krb5_free_address (context, &acceptor_addr);
return kret;
}
- kret = krb5_auth_con_setaddrs(_gsskrb5_context,
+ kret = krb5_auth_con_setaddrs(context,
ac,
&initiator_addr, /* local address */
&acceptor_addr); /* remote address */
- krb5_free_address (_gsskrb5_context, &initiator_addr);
- krb5_free_address (_gsskrb5_context, &acceptor_addr);
+ krb5_free_address (context, &initiator_addr);
+ krb5_free_address (context, &acceptor_addr);
#if 0
free(input_chan_bindings->application_data.value);
@@ -101,6 +104,7 @@ OM_uint32
_gsskrb5_create_ctx(
OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
+ krb5_context context,
const gss_channel_bindings_t input_chan_bindings,
enum gss_ctx_id_t_state state)
{
@@ -127,23 +131,22 @@ _gsskrb5_create_ctx(
ctx->order = NULL;
HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
- kret = krb5_auth_con_init (_gsskrb5_context, &ctx->auth_context);
+ kret = krb5_auth_con_init (context, &ctx->auth_context);
if (kret) {
*minor_status = kret;
- _gsskrb5_set_error_string ();
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
return GSS_S_FAILURE;
}
- kret = set_addresses(ctx->auth_context, input_chan_bindings);
+ kret = set_addresses(context, ctx->auth_context, input_chan_bindings);
if (kret) {
*minor_status = kret;
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
- krb5_auth_con_free(_gsskrb5_context, ctx->auth_context);
+ krb5_auth_con_free(context, ctx->auth_context);
return GSS_S_BAD_BINDINGS;
}
@@ -152,7 +155,7 @@ _gsskrb5_create_ctx(
* We need a sequence number
*/
- krb5_auth_con_addflags(_gsskrb5_context,
+ krb5_auth_con_addflags(context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE |
KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
@@ -167,6 +170,7 @@ _gsskrb5_create_ctx(
static OM_uint32
gsskrb5_get_creds(
OM_uint32 * minor_status,
+ krb5_context context,
krb5_ccache ccache,
gsskrb5_ctx ctx,
krb5_const_principal target_name,
@@ -188,7 +192,7 @@ gsskrb5_get_creds(
if (time_req && time_req != GSS_C_INDEFINITE) {
krb5_timestamp ts;
- krb5_timeofday (_gsskrb5_context, &ts);
+ krb5_timeofday (context, &ts);
this_cred.times.endtime = ts + time_req;
} else {
this_cred.times.endtime = 0;
@@ -196,20 +200,20 @@ gsskrb5_get_creds(
this_cred.session.keytype = KEYTYPE_NULL;
- kret = krb5_get_credentials(_gsskrb5_context,
+ kret = krb5_get_credentials(context,
0,
ccache,
&this_cred,
cred);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
ctx->lifetime = (*cred)->times.endtime;
- ret = _gsskrb5_lifetime_left(minor_status, ctx->lifetime, &lifetime_rec);
+ ret = _gsskrb5_lifetime_left(minor_status, context,
+ ctx->lifetime, &lifetime_rec);
if (ret) return ret;
if (lifetime_rec == 0) {
@@ -225,14 +229,15 @@ gsskrb5_get_creds(
static OM_uint32
gsskrb5_initiator_ready(
OM_uint32 * minor_status,
- gsskrb5_ctx ctx)
+ gsskrb5_ctx ctx,
+ krb5_context context)
{
OM_uint32 ret;
int32_t seq_number;
int is_cfx = 0;
OM_uint32 flags = ctx->flags;
- krb5_auth_getremoteseqnumber (_gsskrb5_context,
+ krb5_auth_getremoteseqnumber (context,
ctx->auth_context,
&seq_number);
@@ -255,7 +260,8 @@ gsskrb5_initiator_ready(
*/
static void
-do_delegation (krb5_auth_context ac,
+do_delegation (krb5_context context,
+ krb5_auth_context ac,
krb5_ccache ccache,
krb5_creds *cred,
krb5_const_principal name,
@@ -269,11 +275,11 @@ do_delegation (krb5_auth_context ac,
memset (&creds, 0, sizeof(creds));
krb5_data_zero (fwd_data);
- kret = krb5_cc_get_principal(_gsskrb5_context, ccache, &creds.client);
+ kret = krb5_cc_get_principal(context, ccache, &creds.client);
if (kret)
goto out;
- kret = krb5_build_principal(_gsskrb5_context,
+ kret = krb5_build_principal(context,
&creds.server,
strlen(creds.client->realm),
creds.client->realm,
@@ -293,7 +299,7 @@ do_delegation (krb5_auth_context ac,
name->name.name_string.len < 2)
goto out;
- kret = krb5_get_forwarded_creds(_gsskrb5_context,
+ kret = krb5_get_forwarded_creds(context,
ac,
ccache,
KDCOptions2int(fwd_flags),
@@ -308,9 +314,9 @@ do_delegation (krb5_auth_context ac,
*flags |= GSS_C_DELEG_FLAG;
if (creds.client)
- krb5_free_principal(_gsskrb5_context, creds.client);
+ krb5_free_principal(context, creds.client);
if (creds.server)
- krb5_free_principal(_gsskrb5_context, creds.server);
+ krb5_free_principal(context, creds.server);
}
/*
@@ -322,6 +328,7 @@ init_auth
(OM_uint32 * minor_status,
gsskrb5_cred initiator_cred_handle,
gsskrb5_ctx ctx,
+ krb5_context context,
krb5_const_principal name,
const gss_OID mech_type,
OM_uint32 req_flags,
@@ -356,9 +363,8 @@ init_auth
*actual_mech_type = GSS_KRB5_MECHANISM;
if (initiator_cred_handle == NULL) {
- kret = krb5_cc_default (_gsskrb5_context, &ccache);
+ kret = krb5_cc_default (context, &ccache);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
@@ -366,28 +372,27 @@ init_auth
} else
ccache = initiator_cred_handle->ccache;
- kret = krb5_cc_get_principal (_gsskrb5_context, ccache, &ctx->source);
+ kret = krb5_cc_get_principal (context, ccache, &ctx->source);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
}
- kret = krb5_copy_principal (_gsskrb5_context, name, &ctx->target);
+ kret = krb5_copy_principal (context, name, &ctx->target);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
}
- ret = _gss_DES3_get_mic_compat(minor_status, ctx);
+ ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
if (ret)
goto failure;
ret = gsskrb5_get_creds(minor_status,
+ context,
ccache,
ctx,
ctx->target,
@@ -400,8 +405,9 @@ init_auth
ctx->lifetime = cred->times.endtime;
ret = _gsskrb5_lifetime_left(minor_status,
- ctx->lifetime,
- &lifetime_rec);
+ context,
+ ctx->lifetime,
+ &lifetime_rec);
if (ret) {
goto failure;
}
@@ -412,15 +418,14 @@ init_auth
goto failure;
}
- krb5_auth_con_setkey(_gsskrb5_context,
+ krb5_auth_con_setkey(context,
ctx->auth_context,
&cred->session);
- kret = krb5_auth_con_generatelocalsubkey(_gsskrb5_context,
+ kret = krb5_auth_con_generatelocalsubkey(context,
ctx->auth_context,
&cred->session);
if(kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
@@ -436,7 +441,7 @@ init_auth
if (!cred->flags.b.ok_as_delegate) {
krb5_boolean delegate;
- krb5_appdefault_boolean(_gsskrb5_context,
+ krb5_appdefault_boolean(context,
"gssapi", name->realm,
"ok-as-delegate", FALSE, &delegate);
if (delegate)
@@ -446,7 +451,8 @@ init_auth
flags = 0;
ap_options = 0;
if (req_flags & GSS_C_DELEG_FLAG)
- do_delegation (ctx->auth_context,
+ do_delegation (context,
+ ctx->auth_context,
ccache, cred, name, &fwd_data, &flags);
if (req_flags & GSS_C_MUTUAL_FLAG) {
@@ -471,9 +477,9 @@ init_auth
flags |= GSS_C_EXTENDED_ERROR_FLAG;
if (req_flags & GSS_C_CONF_FLAG)
- flags |= GSS_C_CONF_FLAG;
+ flags |= GSS_C_CONF_FLAG;
if (req_flags & GSS_C_INTEG_FLAG)
- flags |= GSS_C_INTEG_FLAG;
+ flags |= GSS_C_INTEG_FLAG;
flags |= GSS_C_TRANS_FLAG;
@@ -493,7 +499,7 @@ init_auth
enctype = ctx->auth_context->keyblock->keytype;
- kret = krb5_build_authenticator (_gsskrb5_context,
+ kret = krb5_build_authenticator (context,
ctx->auth_context,
enctype,
cred,
@@ -503,13 +509,12 @@ init_auth
KRB5_KU_AP_REQ_AUTH);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
}
- kret = krb5_build_ap_req (_gsskrb5_context,
+ kret = krb5_build_ap_req (context,
enctype,
cred,
ap_options,
@@ -517,7 +522,6 @@ init_auth
&outbuf);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
@@ -529,22 +533,22 @@ init_auth
goto failure;
krb5_data_free (&outbuf);
- krb5_free_creds(_gsskrb5_context, cred);
+ krb5_free_creds(context, cred);
free_Checksum(&cksum);
if (initiator_cred_handle == NULL)
- krb5_cc_close(_gsskrb5_context, ccache);
+ krb5_cc_close(context, ccache);
if (flags & GSS_C_MUTUAL_FLAG) {
ctx->state = INITIATOR_WAIT_FOR_MUTAL;
return GSS_S_CONTINUE_NEEDED;
}
- return gsskrb5_initiator_ready(minor_status, ctx);
+ return gsskrb5_initiator_ready(minor_status, ctx, context);
failure:
if(cred)
- krb5_free_creds(_gsskrb5_context, cred);
+ krb5_free_creds(context, cred);
if (ccache && initiator_cred_handle == NULL)
- krb5_cc_close(_gsskrb5_context, ccache);
+ krb5_cc_close(context, ccache);
return ret;
@@ -554,6 +558,7 @@ static OM_uint32
repl_mutual
(OM_uint32 * minor_status,
gsskrb5_ctx ctx,
+ krb5_context context,
const gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
@@ -593,28 +598,27 @@ repl_mutual
}
}
- kret = krb5_rd_rep (_gsskrb5_context,
+ kret = krb5_rd_rep (context,
ctx->auth_context,
&indata,
&repl);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
- krb5_free_ap_rep_enc_part (_gsskrb5_context,
+ krb5_free_ap_rep_enc_part (context,
repl);
_gsskrb5i_is_cfx(ctx, &is_cfx);
if (is_cfx) {
krb5_keyblock *key = NULL;
- kret = krb5_auth_con_getremotesubkey(_gsskrb5_context,
+ kret = krb5_auth_con_getremotesubkey(context,
ctx->auth_context,
&key);
if (kret == 0 && key != NULL) {
ctx->more_flags |= ACCEPTOR_SUBKEY;
- krb5_free_keyblock (_gsskrb5_context, key);
+ krb5_free_keyblock (context, key);
}
}
@@ -622,6 +626,7 @@ repl_mutual
*minor_status = 0;
if (time_rec) {
ret = _gsskrb5_lifetime_left(minor_status,
+ context,
ctx->lifetime,
time_rec);
} else {
@@ -635,16 +640,15 @@ repl_mutual
krb5_data outbuf;
/* Do don't do sequence number for the mk-rep */
- krb5_auth_con_removeflags(_gsskrb5_context,
+ krb5_auth_con_removeflags(context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE,
&con_flags);
- kret = krb5_mk_rep(_gsskrb5_context,
+ kret = krb5_mk_rep(context,
ctx->auth_context,
&outbuf);
if (kret) {
- _gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
@@ -652,13 +656,13 @@ repl_mutual
output_token->length = outbuf.length;
output_token->value = outbuf.data;
- krb5_auth_con_removeflags(_gsskrb5_context,
+ krb5_auth_con_removeflags(context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE,
NULL);
}
- return gsskrb5_initiator_ready(minor_status, ctx);
+ return gsskrb5_initiator_ready(minor_status, ctx, context);
}
/*
@@ -681,12 +685,13 @@ OM_uint32 _gsskrb5_init_sec_context
OM_uint32 * time_rec
)
{
+ krb5_context context;
gsskrb5_cred cred = (gsskrb5_cred)initiator_cred_handle;
krb5_const_principal name = (krb5_const_principal)target_name;
gsskrb5_ctx ctx;
OM_uint32 ret;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
output_token->length = 0;
output_token->value = NULL;
@@ -722,6 +727,7 @@ OM_uint32 _gsskrb5_init_sec_context
ret = _gsskrb5_create_ctx(minor_status,
context_handle,
+ context,
input_chan_bindings,
INITIATOR_START);
if (ret)
@@ -742,6 +748,7 @@ OM_uint32 _gsskrb5_init_sec_context
ret = init_auth(minor_status,
cred,
ctx,
+ context,
name,
mech_type,
req_flags,
@@ -756,6 +763,7 @@ OM_uint32 _gsskrb5_init_sec_context
case INITIATOR_WAIT_FOR_MUTAL:
ret = repl_mutual(minor_status,
ctx,
+ context,
mech_type,
req_flags,
time_req,
diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_context.c b/source4/heimdal/lib/gssapi/krb5/inquire_context.c
index ef43e6852c4..bdaa01b1086 100644
--- a/source4/heimdal/lib/gssapi/krb5/inquire_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/inquire_context.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: inquire_context.c,v 1.10 2006/10/07 22:15:03 lha Exp $");
+RCSID("$Id: inquire_context.c,v 1.11 2006/11/13 18:02:18 lha Exp $");
OM_uint32 _gsskrb5_inquire_context (
OM_uint32 * minor_status,
@@ -47,6 +47,7 @@ OM_uint32 _gsskrb5_inquire_context (
int * open_context
)
{
+ krb5_context context;
OM_uint32 ret;
gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle;
gss_name_t name;
@@ -56,6 +57,8 @@ OM_uint32 _gsskrb5_inquire_context (
if (targ_name)
*targ_name = GSS_C_NO_NAME;
+ GSSAPI_KRB5_INIT (&context);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
if (src_name) {
@@ -74,6 +77,7 @@ OM_uint32 _gsskrb5_inquire_context (
if (lifetime_rec) {
ret = _gsskrb5_lifetime_left(minor_status,
+ context,
ctx->lifetime,
lifetime_rec);
if (ret)
diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_cred.c b/source4/heimdal/lib/gssapi/krb5/inquire_cred.c
index 05937293657..74018559a0b 100644
--- a/source4/heimdal/lib/gssapi/krb5/inquire_cred.c
+++ b/source4/heimdal/lib/gssapi/krb5/inquire_cred.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: inquire_cred.c,v 1.12 2006/10/07 22:15:06 lha Exp $");
+RCSID("$Id: inquire_cred.c,v 1.13 2006/11/13 18:02:21 lha Exp $");
OM_uint32 _gsskrb5_inquire_cred
(OM_uint32 * minor_status,
@@ -44,6 +44,7 @@ OM_uint32 _gsskrb5_inquire_cred
gss_OID_set * mechanisms
)
{
+ krb5_context context;
gss_cred_id_t aqcred_init = GSS_C_NO_CREDENTIAL;
gss_cred_id_t aqcred_accept = GSS_C_NO_CREDENTIAL;
gsskrb5_cred acred = NULL, icred = NULL;
@@ -56,6 +57,8 @@ OM_uint32 _gsskrb5_inquire_cred
if (mechanisms)
*mechanisms = GSS_C_NO_OID_SET;
+ GSSAPI_KRB5_INIT (&context);
+
if (cred_handle == GSS_C_NO_CREDENTIAL) {
ret = _gsskrb5_acquire_cred(minor_status,
GSS_C_NO_NAME,
@@ -105,7 +108,7 @@ OM_uint32 _gsskrb5_inquire_cred
goto out;
} else if (acred && acred->usage == GSS_C_ACCEPT) {
krb5_principal princ;
- *minor_status = krb5_sname_to_principal(_gsskrb5_context, NULL,
+ *minor_status = krb5_sname_to_principal(context, NULL,
NULL, KRB5_NT_SRV_HST,
&princ);
if (*minor_status) {
@@ -115,7 +118,7 @@ OM_uint32 _gsskrb5_inquire_cred
*output_name = (gss_name_t)princ;
} else {
krb5_principal princ;
- *minor_status = krb5_get_default_principal(_gsskrb5_context,
+ *minor_status = krb5_get_default_principal(context,
&princ);
if (*minor_status) {
ret = GSS_S_FAILURE;
@@ -131,6 +134,7 @@ OM_uint32 _gsskrb5_inquire_cred
if (icred) ilife = icred->lifetime;
ret = _gsskrb5_lifetime_left(minor_status,
+ context,
min(alife,ilife),
lifetime);
if (ret)
diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c
index 26927c740ce..1a36896019f 100644
--- a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c
+++ b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c
@@ -32,7 +32,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: inquire_cred_by_oid.c,v 1.4 2006/10/07 22:15:10 lha Exp $");
+RCSID("$Id: inquire_cred_by_oid.c,v 1.5 2006/11/13 18:02:24 lha Exp $");
OM_uint32 _gsskrb5_inquire_cred_by_oid
(OM_uint32 * minor_status,
@@ -40,11 +40,14 @@ OM_uint32 _gsskrb5_inquire_cred_by_oid
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
+ krb5_context context;
gsskrb5_cred cred = (gsskrb5_cred)cred_handle;
krb5_error_code ret;
gss_buffer_desc buffer;
char *str;
+ GSSAPI_KRB5_INIT (&context);
+
if (gss_oid_equal(desired_object, GSS_KRB5_COPY_CCACHE_X) == 0) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
@@ -58,11 +61,10 @@ OM_uint32 _gsskrb5_inquire_cred_by_oid
return GSS_S_FAILURE;
}
- ret = krb5_cc_get_full_name(_gsskrb5_context, cred->ccache, &str);
+ ret = krb5_cc_get_full_name(context, cred->ccache, &str);
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
if (ret) {
*minor_status = ret;
- _gsskrb5_set_error_string ();
return GSS_S_FAILURE;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c b/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c
index ee4210d74a5..97e86a95c7b 100644
--- a/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c
+++ b/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c
@@ -32,7 +32,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: inquire_sec_context_by_oid.c,v 1.11 2006/11/07 14:34:35 lha Exp $");
+RCSID("$Id: inquire_sec_context_by_oid.c,v 1.12 2006/11/13 18:02:27 lha Exp $");
static int
oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix)
@@ -106,6 +106,7 @@ enum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY };
static OM_uint32 inquire_sec_context_get_subkey
(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
enum keytype keytype,
gss_buffer_set_t *data_set)
{
@@ -127,19 +128,13 @@ static OM_uint32 inquire_sec_context_get_subkey
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
switch(keytype) {
case ACCEPTOR_KEY:
- ret = _gsskrb5i_get_acceptor_subkey(context_handle, &key);
- if (ret)
- _gsskrb5_set_error_string ();
+ ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key);
break;
case INITIATOR_KEY:
- ret = _gsskrb5i_get_initiator_subkey(context_handle, &key);
- if (ret)
- _gsskrb5_set_error_string ();
+ ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key);
break;
case TOKEN_KEY:
- ret = _gsskrb5i_get_token_key(context_handle, &key);
- if (ret)
- _gsskrb5_set_error_string ();
+ ret = _gsskrb5i_get_token_key(context_handle, context, &key);
break;
default:
_gsskrb5_set_status("%d is not a valid subkey type", keytype);
@@ -156,17 +151,13 @@ static OM_uint32 inquire_sec_context_get_subkey
}
ret = krb5_store_keyblock(sp, *key);
- krb5_free_keyblock (_gsskrb5_context, key);
- if (ret) {
- _gsskrb5_set_error_string ();
+ krb5_free_keyblock (context, key);
+ if (ret)
goto out;
- }
ret = krb5_storage_to_data(sp, &data);
- if (ret) {
- _gsskrb5_set_error_string ();
+ if (ret)
goto out;
- }
{
gss_buffer_desc value;
@@ -193,6 +184,7 @@ out:
static OM_uint32 inquire_sec_context_authz_data
(OM_uint32 *minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
unsigned ad_type,
gss_buffer_set_t *data_set)
{
@@ -211,13 +203,12 @@ static OM_uint32 inquire_sec_context_authz_data
return GSS_S_NO_CONTEXT;
}
- ret = krb5_ticket_get_authorization_data_type(_gsskrb5_context,
+ ret = krb5_ticket_get_authorization_data_type(context,
context_handle->ticket,
ad_type,
&data);
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
@@ -276,6 +267,7 @@ static OM_uint32 inquire_sec_context_has_updated_spnego
static OM_uint32
export_lucid_sec_context_v1(OM_uint32 *minor_status,
gsskrb5_ctx context_handle,
+ krb5_context context,
gss_buffer_set_t *data_set)
{
krb5_storage *sp = NULL;
@@ -288,8 +280,6 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status,
*minor_status = 0;
- GSSAPI_KRB5_INIT ();
-
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
_gsskrb5i_is_cfx(context_handle, &is_cfx);
@@ -307,12 +297,12 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status,
if (ret) goto out;
ret = krb5_store_int32(sp, context_handle->lifetime);
if (ret) goto out;
- krb5_auth_con_getlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_getlocalseqnumber (context,
context_handle->auth_context,
&number);
ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
ret = krb5_store_uint32(sp, (uint32_t)number);
- krb5_auth_getremoteseqnumber (_gsskrb5_context,
+ krb5_auth_getremoteseqnumber (context,
context_handle->auth_context,
&number);
ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
@@ -320,7 +310,7 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status,
ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0);
if (ret) goto out;
- ret = _gsskrb5i_get_token_key(context_handle, &key);
+ ret = _gsskrb5i_get_token_key(context_handle, context, &key);
if (ret) goto out;
if (is_cfx == 0) {
@@ -387,7 +377,7 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status,
out:
if (key)
- krb5_free_keyblock (_gsskrb5_context, key);
+ krb5_free_keyblock (context, key);
if (sp)
krb5_storage_free(sp);
if (ret) {
@@ -485,7 +475,6 @@ out:
if (sp)
krb5_storage_free(sp);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
maj_stat = GSS_S_FAILURE;
}
@@ -501,6 +490,7 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
+ krb5_context context;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
unsigned suffix;
@@ -509,6 +499,8 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid
return GSS_S_NO_CONTEXT;
}
+ GSSAPI_KRB5_INIT (&context);
+
if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
return inquire_sec_context_tkt_flags(minor_status,
ctx,
@@ -520,16 +512,19 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid
} else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
return inquire_sec_context_get_subkey(minor_status,
ctx,
+ context,
TOKEN_KEY,
data_set);
} else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
return inquire_sec_context_get_subkey(minor_status,
ctx,
+ context,
INITIATOR_KEY,
data_set);
} else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
return inquire_sec_context_get_subkey(minor_status,
ctx,
+ context,
ACCEPTOR_KEY,
data_set);
} else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
@@ -539,6 +534,7 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid
&suffix)) {
return inquire_sec_context_authz_data(minor_status,
ctx,
+ context,
suffix,
data_set);
} else if (oid_prefix_equal(desired_object,
@@ -547,6 +543,7 @@ OM_uint32 _gsskrb5_inquire_sec_context_by_oid
if (suffix == 1)
return export_lucid_sec_context_v1(minor_status,
ctx,
+ context,
data_set);
*minor_status = 0;
return GSS_S_FAILURE;
diff --git a/source4/heimdal/lib/gssapi/krb5/process_context_token.c b/source4/heimdal/lib/gssapi/krb5/process_context_token.c
index 99568c9dd08..411d689635e 100644
--- a/source4/heimdal/lib/gssapi/krb5/process_context_token.c
+++ b/source4/heimdal/lib/gssapi/krb5/process_context_token.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: process_context_token.c,v 1.4 2006/10/07 22:15:19 lha Exp $");
+RCSID("$Id: process_context_token.c,v 1.5 2006/11/13 18:02:30 lha Exp $");
OM_uint32 _gsskrb5_process_context_token (
OM_uint32 *minor_status,
@@ -41,6 +41,7 @@ OM_uint32 _gsskrb5_process_context_token (
const gss_buffer_t token_buffer
)
{
+ krb5_context context;
OM_uint32 ret = GSS_S_FAILURE;
gss_buffer_desc empty_buffer;
gss_qop_t qop_state;
@@ -48,10 +49,13 @@ OM_uint32 _gsskrb5_process_context_token (
empty_buffer.length = 0;
empty_buffer.value = NULL;
+ GSSAPI_KRB5_INIT (&context);
+
qop_state = GSS_C_QOP_DEFAULT;
ret = _gsskrb5_verify_mic_internal(minor_status,
(gsskrb5_ctx)context_handle,
+ context,
token_buffer, &empty_buffer,
GSS_C_QOP_DEFAULT, "\x01\x02");
diff --git a/source4/heimdal/lib/gssapi/krb5/release_cred.c b/source4/heimdal/lib/gssapi/krb5/release_cred.c
index 662461ccfd6..f6d98b29c6d 100644
--- a/source4/heimdal/lib/gssapi/krb5/release_cred.c
+++ b/source4/heimdal/lib/gssapi/krb5/release_cred.c
@@ -33,13 +33,14 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: release_cred.c,v 1.13 2006/10/07 22:15:24 lha Exp $");
+RCSID("$Id: release_cred.c,v 1.14 2006/11/13 18:02:34 lha Exp $");
OM_uint32 _gsskrb5_release_cred
(OM_uint32 * minor_status,
gss_cred_id_t * cred_handle
)
{
+ krb5_context context;
gsskrb5_cred cred;
*minor_status = 0;
@@ -50,21 +51,21 @@ OM_uint32 _gsskrb5_release_cred
cred = (gsskrb5_cred)*cred_handle;
*cred_handle = GSS_C_NO_CREDENTIAL;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
if (cred->principal != NULL)
- krb5_free_principal(_gsskrb5_context, cred->principal);
+ krb5_free_principal(context, cred->principal);
if (cred->keytab != NULL)
- krb5_kt_close(_gsskrb5_context, cred->keytab);
+ krb5_kt_close(context, cred->keytab);
if (cred->ccache != NULL) {
const krb5_cc_ops *ops;
- ops = krb5_cc_get_ops(_gsskrb5_context, cred->ccache);
+ ops = krb5_cc_get_ops(context, cred->ccache);
if (cred->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE)
- krb5_cc_destroy(_gsskrb5_context, cred->ccache);
+ krb5_cc_destroy(context, cred->ccache);
else
- krb5_cc_close(_gsskrb5_context, cred->ccache);
+ krb5_cc_close(context, cred->ccache);
}
_gsskrb5_release_oid_set(NULL, &cred->mechanisms);
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
diff --git a/source4/heimdal/lib/gssapi/krb5/release_name.c b/source4/heimdal/lib/gssapi/krb5/release_name.c
index a92ad939a58..cc9c0934f75 100644
--- a/source4/heimdal/lib/gssapi/krb5/release_name.c
+++ b/source4/heimdal/lib/gssapi/krb5/release_name.c
@@ -33,23 +33,24 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: release_name.c,v 1.10 2006/10/07 22:15:26 lha Exp $");
+RCSID("$Id: release_name.c,v 1.11 2006/11/13 18:02:37 lha Exp $");
OM_uint32 _gsskrb5_release_name
(OM_uint32 * minor_status,
gss_name_t * input_name
)
{
+ krb5_context context;
krb5_principal name = (krb5_principal)*input_name;
- GSSAPI_KRB5_INIT ();
-
if (minor_status)
*minor_status = 0;
+ GSSAPI_KRB5_INIT (&context);
+
*input_name = GSS_C_NO_NAME;
- krb5_free_principal(_gsskrb5_context, name);
+ krb5_free_principal(context, name);
return GSS_S_COMPLETE;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/set_cred_option.c b/source4/heimdal/lib/gssapi/krb5/set_cred_option.c
index 5807ef01661..849760ee4a6 100644
--- a/source4/heimdal/lib/gssapi/krb5/set_cred_option.c
+++ b/source4/heimdal/lib/gssapi/krb5/set_cred_option.c
@@ -32,7 +32,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: set_cred_option.c,v 1.4 2006/10/24 20:14:13 lha Exp $");
+RCSID("$Id: set_cred_option.c,v 1.5 2006/11/13 18:02:39 lha Exp $");
static gss_OID_desc gss_krb5_import_cred_x_oid_desc =
{9, (void *)"\x2b\x06\x01\x04\x01\xa9\x4a\x13\x04"}; /* XXX */
@@ -41,6 +41,7 @@ gss_OID GSS_KRB5_IMPORT_CRED_X = &gss_krb5_import_cred_x_oid_desc;
static OM_uint32
import_cred(OM_uint32 *minor_status,
+ krb5_context context,
gss_cred_id_t *cred_handle,
const gss_buffer_t value)
{
@@ -71,7 +72,7 @@ import_cred(OM_uint32 *minor_status,
goto out;
}
if (str[0]) {
- ret = krb5_cc_resolve(_gsskrb5_context, str, &id);
+ ret = krb5_cc_resolve(context, str, &id);
if (ret) {
*minor_status = ret;
major_stat = GSS_S_FAILURE;
@@ -84,7 +85,7 @@ import_cred(OM_uint32 *minor_status,
/* keytab principal name */
ret = krb5_ret_string(sp, &str);
if (ret == 0 && str[0])
- ret = krb5_parse_name(_gsskrb5_context, str, &keytab_principal);
+ ret = krb5_parse_name(context, str, &keytab_principal);
if (ret) {
*minor_status = ret;
major_stat = GSS_S_FAILURE;
@@ -101,7 +102,7 @@ import_cred(OM_uint32 *minor_status,
goto out;
}
if (str[0]) {
- ret = krb5_kt_resolve(_gsskrb5_context, str, &keytab);
+ ret = krb5_kt_resolve(context, str, &keytab);
if (ret) {
*minor_status = ret;
major_stat = GSS_S_FAILURE;
@@ -115,11 +116,11 @@ import_cred(OM_uint32 *minor_status,
keytab, cred_handle);
out:
if (id)
- krb5_cc_close(_gsskrb5_context, id);
+ krb5_cc_close(context, id);
if (keytab_principal)
- krb5_free_principal(_gsskrb5_context, keytab_principal);
+ krb5_free_principal(context, keytab_principal);
if (keytab)
- krb5_kt_close(_gsskrb5_context, keytab);
+ krb5_kt_close(context, keytab);
if (str)
free(str);
if (sp)
@@ -136,7 +137,9 @@ _gsskrb5_set_cred_option
const gss_OID desired_object,
const gss_buffer_t value)
{
- GSSAPI_KRB5_INIT ();
+ krb5_context context;
+
+ GSSAPI_KRB5_INIT (&context);
if (value == GSS_C_NO_BUFFER) {
*minor_status = EINVAL;
@@ -144,7 +147,7 @@ _gsskrb5_set_cred_option
}
if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_CRED_X)) {
- return import_cred(minor_status, cred_handle, value);
+ return import_cred(minor_status, context, cred_handle, value);
}
*minor_status = EINVAL;
diff --git a/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c b/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c
index dc1495efc1b..4a5f60ce942 100644
--- a/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c
+++ b/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c
@@ -36,7 +36,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: set_sec_context_option.c,v 1.8 2006/11/08 23:06:42 lha Exp $");
+RCSID("$Id: set_sec_context_option.c,v 1.10 2006/12/14 11:02:16 lha Exp $");
static OM_uint32
get_bool(OM_uint32 *minor_status,
@@ -58,9 +58,10 @@ _gsskrb5_set_sec_context_option
const gss_OID desired_object,
const gss_buffer_t value)
{
+ krb5_context context;
OM_uint32 maj_stat;
- GSSAPI_KRB5_INIT ();
+ GSSAPI_KRB5_INIT (&context);
if (value == GSS_C_NO_BUFFER) {
*minor_status = EINVAL;
@@ -96,7 +97,7 @@ _gsskrb5_set_sec_context_option
if (maj_stat != GSS_S_COMPLETE)
return maj_stat;
- krb5_set_dns_canonicalize_hostname(_gsskrb5_context, flag);
+ krb5_set_dns_canonicalize_hostname(context, flag);
return GSS_S_COMPLETE;
} else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) {
@@ -128,14 +129,14 @@ _gsskrb5_set_sec_context_option
return GSS_S_CALL_INACCESSIBLE_READ;
}
str = malloc(value->length + 1);
- if (str) {
+ if (str == NULL) {
*minor_status = 0;
return GSS_S_UNAVAILABLE;
}
memcpy(str, value->value, value->length);
str[value->length] = '\0';
- krb5_set_default_realm(_gsskrb5_context, str);
+ krb5_set_default_realm(context, str);
free(str);
*minor_status = 0;
@@ -144,7 +145,7 @@ _gsskrb5_set_sec_context_option
} else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) {
if (value == NULL || value->length == 0) {
- krb5_set_send_to_kdc_func(_gsskrb5_context, NULL, NULL);
+ krb5_set_send_to_kdc_func(context, NULL, NULL);
} else {
struct gsskrb5_send_to_kdc c;
@@ -153,7 +154,7 @@ _gsskrb5_set_sec_context_option
return GSS_S_FAILURE;
}
memcpy(&c, value->value, sizeof(c));
- krb5_set_send_to_kdc_func(_gsskrb5_context,
+ krb5_set_send_to_kdc_func(context,
(krb5_send_to_kdc_func)c.func,
c.ptr);
}
diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c
index 758390080cd..3dd76185615 100644
--- a/source4/heimdal/lib/gssapi/krb5/unwrap.c
+++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c
@@ -33,7 +33,7 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: unwrap.c,v 1.38 2006/10/18 15:59:28 lha Exp $");
+RCSID("$Id: unwrap.c,v 1.39 2006/11/13 18:02:51 lha Exp $");
static OM_uint32
unwrap_des
@@ -175,6 +175,7 @@ static OM_uint32
unwrap_des3
(OM_uint32 * minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t input_message_buffer,
gss_buffer_t output_message_buffer,
int * conf_state,
@@ -226,18 +227,16 @@ unwrap_des3
/* decrypt data */
krb5_data tmp;
- ret = krb5_crypto_init(_gsskrb5_context, key,
+ ret = krb5_crypto_init(context, key,
ETYPE_DES3_CBC_NONE, &crypto);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
- ret = krb5_decrypt(_gsskrb5_context, crypto, KRB5_KU_USAGE_SEAL,
+ ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL,
p, input_message_buffer->length - len, &tmp);
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
@@ -259,10 +258,9 @@ unwrap_des3
p -= 28;
- ret = krb5_crypto_init(_gsskrb5_context, key,
+ ret = krb5_crypto_init(context, key,
ETYPE_DES3_CBC_NONE, &crypto);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
return GSS_S_FAILURE;
@@ -271,15 +269,14 @@ unwrap_des3
DES_cblock ivec;
memcpy(&ivec, p + 8, 8);
- ret = krb5_decrypt_ivec (_gsskrb5_context,
+ ret = krb5_decrypt_ivec (context,
crypto,
KRB5_KU_USAGE_SEQ,
p, 8, &seq_data,
&ivec);
}
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
return GSS_S_FAILURE;
@@ -325,21 +322,19 @@ unwrap_des3
csum.checksum.length = 20;
csum.checksum.data = cksum;
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
- ret = krb5_verify_checksum (_gsskrb5_context, crypto,
+ ret = krb5_verify_checksum (context, crypto,
KRB5_KU_USAGE_SIGN,
p + 20,
input_message_buffer->length - len + 8,
&csum);
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
@@ -367,6 +362,7 @@ OM_uint32 _gsskrb5_unwrap
)
{
krb5_keyblock *key;
+ krb5_context context;
OM_uint32 ret;
krb5_keytype keytype;
gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
@@ -374,17 +370,18 @@ OM_uint32 _gsskrb5_unwrap
output_message_buffer->value = NULL;
output_message_buffer->length = 0;
+ GSSAPI_KRB5_INIT (&context);
+
if (qop_state != NULL)
*qop_state = GSS_C_QOP_DEFAULT;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
- ret = _gsskrb5i_get_token_key(ctx, &key);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
- krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype);
+ krb5_enctype_to_keytype (context, key->keytype, &keytype);
*minor_status = 0;
@@ -395,22 +392,22 @@ OM_uint32 _gsskrb5_unwrap
conf_state, qop_state, key);
break;
case KEYTYPE_DES3 :
- ret = unwrap_des3 (minor_status, ctx,
+ ret = unwrap_des3 (minor_status, ctx, context,
input_message_buffer, output_message_buffer,
conf_state, qop_state, key);
break;
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
- ret = _gssapi_unwrap_arcfour (minor_status, ctx,
+ ret = _gssapi_unwrap_arcfour (minor_status, ctx, context,
input_message_buffer, output_message_buffer,
conf_state, qop_state, key);
break;
default :
- ret = _gssapi_unwrap_cfx (minor_status, ctx,
+ ret = _gssapi_unwrap_cfx (minor_status, ctx, context,
input_message_buffer, output_message_buffer,
conf_state, qop_state, key);
break;
}
- krb5_free_keyblock (_gsskrb5_context, key);
+ krb5_free_keyblock (context, key);
return ret;
}
diff --git a/source4/heimdal/lib/gssapi/krb5/verify_mic.c b/source4/heimdal/lib/gssapi/krb5/verify_mic.c
index 920937cafcd..29b3a7f4bb3 100644
--- a/source4/heimdal/lib/gssapi/krb5/verify_mic.c
+++ b/source4/heimdal/lib/gssapi/krb5/verify_mic.c
@@ -33,12 +33,13 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: verify_mic.c,v 1.36 2006/10/18 15:59:30 lha Exp $");
+RCSID("$Id: verify_mic.c,v 1.37 2006/11/13 18:02:54 lha Exp $");
static OM_uint32
verify_mic_des
(OM_uint32 * minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
gss_qop_t * qop_state,
@@ -131,6 +132,7 @@ static OM_uint32
verify_mic_des3
(OM_uint32 * minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
gss_qop_t * qop_state,
@@ -164,10 +166,9 @@ verify_mic_des3
return GSS_S_BAD_MIC;
p += 4;
- ret = krb5_crypto_init(_gsskrb5_context, key,
+ ret = krb5_crypto_init(context, key,
ETYPE_DES3_CBC_NONE, &crypto);
if (ret){
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
@@ -180,14 +181,13 @@ retry:
else
memcpy(ivec, p + 8, 8);
- ret = krb5_decrypt_ivec (_gsskrb5_context,
+ ret = krb5_decrypt_ivec (context,
crypto,
KRB5_KU_USAGE_SEQ,
p, 8, &seq_data, ivec);
if (ret) {
if (docompat++) {
- _gsskrb5_set_error_string ();
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
*minor_status = ret;
return GSS_S_FAILURE;
} else
@@ -197,7 +197,7 @@ retry:
if (seq_data.length != 8) {
krb5_data_free (&seq_data);
if (docompat++) {
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
return GSS_S_BAD_MIC;
} else
goto retry;
@@ -215,7 +215,7 @@ retry:
krb5_data_free (&seq_data);
if (cmp != 0) {
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
*minor_status = 0;
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
return GSS_S_BAD_MIC;
@@ -223,7 +223,7 @@ retry:
ret = _gssapi_msg_order_check(context_handle->order, seq_number);
if (ret) {
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
*minor_status = 0;
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
return ret;
@@ -233,7 +233,7 @@ retry:
tmp = malloc (message_buffer->length + 8);
if (tmp == NULL) {
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
@@ -246,21 +246,20 @@ retry:
csum.checksum.length = 20;
csum.checksum.data = p + 8;
- ret = krb5_verify_checksum (_gsskrb5_context, crypto,
+ ret = krb5_verify_checksum (context, crypto,
KRB5_KU_USAGE_SIGN,
tmp, message_buffer->length + 8,
&csum);
free (tmp);
if (ret) {
- _gsskrb5_set_error_string ();
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
*minor_status = ret;
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
return GSS_S_BAD_MIC;
}
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
return GSS_S_COMPLETE;
}
@@ -268,6 +267,7 @@ OM_uint32
_gsskrb5_verify_mic_internal
(OM_uint32 * minor_status,
const gsskrb5_ctx context_handle,
+ krb5_context context,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
gss_qop_t * qop_state,
@@ -279,39 +279,40 @@ _gsskrb5_verify_mic_internal
krb5_keytype keytype;
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- ret = _gsskrb5i_get_token_key(context_handle, &key);
+ ret = _gsskrb5i_get_token_key(context_handle, context, &key);
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
*minor_status = 0;
- krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype);
+ krb5_enctype_to_keytype (context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_DES :
- ret = verify_mic_des (minor_status, context_handle,
+ ret = verify_mic_des (minor_status, context_handle, context,
message_buffer, token_buffer, qop_state, key,
type);
break;
case KEYTYPE_DES3 :
- ret = verify_mic_des3 (minor_status, context_handle,
+ ret = verify_mic_des3 (minor_status, context_handle, context,
message_buffer, token_buffer, qop_state, key,
type);
break;
case KEYTYPE_ARCFOUR :
case KEYTYPE_ARCFOUR_56 :
ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
+ context,
message_buffer, token_buffer,
qop_state, key, type);
break;
default :
ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
+ context,
message_buffer, token_buffer, qop_state,
key);
break;
}
- krb5_free_keyblock (_gsskrb5_context, key);
+ krb5_free_keyblock (context, key);
return ret;
}
@@ -325,13 +326,17 @@ _gsskrb5_verify_mic
gss_qop_t * qop_state
)
{
+ krb5_context context;
OM_uint32 ret;
+ GSSAPI_KRB5_INIT (&context);
+
if (qop_state != NULL)
*qop_state = GSS_C_QOP_DEFAULT;
ret = _gsskrb5_verify_mic_internal(minor_status,
- (gsskrb5_ctx)context_handle,
+ (gsskrb5_ctx)context_handle,
+ context,
message_buffer, token_buffer,
qop_state, "\x01\x01");
diff --git a/source4/heimdal/lib/gssapi/krb5/wrap.c b/source4/heimdal/lib/gssapi/krb5/wrap.c
index ebbc975b8a3..79cfb48ed2a 100644
--- a/source4/heimdal/lib/gssapi/krb5/wrap.c
+++ b/source4/heimdal/lib/gssapi/krb5/wrap.c
@@ -33,74 +33,80 @@
#include "krb5/gsskrb5_locl.h"
-RCSID("$Id: wrap.c,v 1.37 2006/10/18 15:59:33 lha Exp $");
+RCSID("$Id: wrap.c,v 1.39 2006/11/14 09:49:56 lha Exp $");
/*
* Return initiator subkey, or if that doesn't exists, the subkey.
*/
krb5_error_code
-_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx, krb5_keyblock **key)
+_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
+ krb5_context context,
+ krb5_keyblock **key)
{
krb5_error_code ret;
*key = NULL;
if (ctx->more_flags & LOCAL) {
- ret = krb5_auth_con_getlocalsubkey(_gsskrb5_context,
+ ret = krb5_auth_con_getlocalsubkey(context,
ctx->auth_context,
key);
} else {
- ret = krb5_auth_con_getremotesubkey(_gsskrb5_context,
+ ret = krb5_auth_con_getremotesubkey(context,
ctx->auth_context,
key);
}
- if (*key == NULL)
- ret = krb5_auth_con_getkey(_gsskrb5_context,
+ if (ret == 0 && *key == NULL)
+ ret = krb5_auth_con_getkey(context,
ctx->auth_context,
key);
- if (*key == NULL) {
- _gsskrb5_set_status("No initiator subkey available");
+ if (ret == 0 && *key == NULL) {
+ krb5_set_error_string(context, "No initiator subkey available");
return GSS_KRB5_S_KG_NO_SUBKEY;
}
return ret;
}
krb5_error_code
-_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx, krb5_keyblock **key)
+_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
+ krb5_context context,
+ krb5_keyblock **key)
{
krb5_error_code ret;
*key = NULL;
if (ctx->more_flags & LOCAL) {
- ret = krb5_auth_con_getremotesubkey(_gsskrb5_context,
+ ret = krb5_auth_con_getremotesubkey(context,
ctx->auth_context,
key);
} else {
- ret = krb5_auth_con_getlocalsubkey(_gsskrb5_context,
+ ret = krb5_auth_con_getlocalsubkey(context,
ctx->auth_context,
key);
}
- if (*key == NULL) {
- _gsskrb5_set_status("No acceptor subkey available");
+ if (ret == 0 && *key == NULL) {
+ krb5_set_error_string(context, "No acceptor subkey available");
return GSS_KRB5_S_KG_NO_SUBKEY;
}
return ret;
}
OM_uint32
-_gsskrb5i_get_token_key(const gsskrb5_ctx ctx, krb5_keyblock **key)
+_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
+ krb5_context context,
+ krb5_keyblock **key)
{
- _gsskrb5i_get_acceptor_subkey(ctx, key);
+ _gsskrb5i_get_acceptor_subkey(ctx, context, key);
if(*key == NULL) {
/*
* Only use the initiator subkey or ticket session key if an
* acceptor subkey was not required.
*/
if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
- _gsskrb5i_get_initiator_subkey(ctx, key);
+ _gsskrb5i_get_initiator_subkey(ctx, context, key);
}
if (*key == NULL) {
- _gsskrb5_set_status("No token key available");
+ krb5_set_error_string(context, "No token key available");
return GSS_KRB5_S_KG_NO_SUBKEY;
}
return 0;
@@ -140,20 +146,22 @@ _gsskrb5_wrap_size_limit (
OM_uint32 * max_input_size
)
{
+ krb5_context context;
krb5_keyblock *key;
OM_uint32 ret;
krb5_keytype keytype;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
+ GSSAPI_KRB5_INIT (&context);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
- ret = _gsskrb5i_get_token_key(ctx, &key);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
- krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype);
+ krb5_enctype_to_keytype (context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_DES :
@@ -161,7 +169,7 @@ _gsskrb5_wrap_size_limit (
break;
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
- ret = _gssapi_wrap_size_arcfour(minor_status, ctx,
+ ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
conf_req_flag, qop_req,
req_output_size, max_input_size, key);
break;
@@ -169,12 +177,12 @@ _gsskrb5_wrap_size_limit (
ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
break;
default :
- ret = _gssapi_wrap_size_cfx(minor_status, ctx,
+ ret = _gssapi_wrap_size_cfx(minor_status, ctx, context,
conf_req_flag, qop_req,
req_output_size, max_input_size, key);
break;
}
- krb5_free_keyblock (_gsskrb5_context, key);
+ krb5_free_keyblock (context, key);
*minor_status = 0;
return ret;
}
@@ -183,6 +191,7 @@ static OM_uint32
wrap_des
(OM_uint32 * minor_status,
const gsskrb5_ctx ctx,
+ krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
const gss_buffer_t input_message_buffer,
@@ -257,9 +266,9 @@ wrap_des
/* sequence number */
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
- krb5_auth_con_getlocalseqnumber (_gsskrb5_context,
- ctx->auth_context,
- &seq_number);
+ krb5_auth_con_getlocalseqnumber (context,
+ ctx->auth_context,
+ &seq_number);
p -= 16;
p[0] = (seq_number >> 0) & 0xFF;
@@ -274,7 +283,7 @@ wrap_des
DES_cbc_encrypt ((void *)p, (void *)p, 8,
&schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
- krb5_auth_con_setlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber (context,
ctx->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
@@ -309,6 +318,7 @@ static OM_uint32
wrap_des3
(OM_uint32 * minor_status,
const gsskrb5_ctx ctx,
+ krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
const gss_buffer_t input_message_buffer,
@@ -365,9 +375,8 @@ wrap_des3
input_message_buffer->length);
memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
- ret = krb5_crypto_init(_gsskrb5_context, key, 0, &crypto);
+ ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret) {
- _gsskrb5_set_error_string ();
free (output_message_buffer->value);
output_message_buffer->length = 0;
output_message_buffer->value = NULL;
@@ -375,16 +384,15 @@ wrap_des3
return GSS_S_FAILURE;
}
- ret = krb5_create_checksum (_gsskrb5_context,
+ ret = krb5_create_checksum (context,
crypto,
KRB5_KU_USAGE_SIGN,
0,
p + 20,
datalen + 8,
&cksum);
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
if (ret) {
- _gsskrb5_set_error_string ();
free (output_message_buffer->value);
output_message_buffer->length = 0;
output_message_buffer->value = NULL;
@@ -400,7 +408,7 @@ wrap_des3
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
/* sequence number */
- krb5_auth_con_getlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_getlocalseqnumber (context,
ctx->auth_context,
&seq_number);
@@ -413,7 +421,7 @@ wrap_des3
4);
- ret = krb5_crypto_init(_gsskrb5_context, key, ETYPE_DES3_CBC_NONE,
+ ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
&crypto);
if (ret) {
free (output_message_buffer->value);
@@ -427,15 +435,14 @@ wrap_des3
DES_cblock ivec;
memcpy (&ivec, p + 8, 8);
- ret = krb5_encrypt_ivec (_gsskrb5_context,
+ ret = krb5_encrypt_ivec (context,
crypto,
KRB5_KU_USAGE_SEQ,
seq, 8, &encdata,
&ivec);
}
- krb5_crypto_destroy (_gsskrb5_context, crypto);
+ krb5_crypto_destroy (context, crypto);
if (ret) {
- _gsskrb5_set_error_string ();
free (output_message_buffer->value);
output_message_buffer->length = 0;
output_message_buffer->value = NULL;
@@ -448,7 +455,7 @@ wrap_des3
memcpy (p, encdata.data, encdata.length);
krb5_data_free (&encdata);
- krb5_auth_con_setlocalseqnumber (_gsskrb5_context,
+ krb5_auth_con_setlocalseqnumber (context,
ctx->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
@@ -459,21 +466,19 @@ wrap_des3
if(conf_req_flag) {
krb5_data tmp;
- ret = krb5_crypto_init(_gsskrb5_context, key,
+ ret = krb5_crypto_init(context, key,
ETYPE_DES3_CBC_NONE, &crypto);
if (ret) {
- _gsskrb5_set_error_string ();
free (output_message_buffer->value);
output_message_buffer->length = 0;
output_message_buffer->value = NULL;
*minor_status = ret;
return GSS_S_FAILURE;
}
- ret = krb5_encrypt(_gsskrb5_context, crypto, KRB5_KU_USAGE_SEAL,
+ ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
p, datalen, &tmp);
- krb5_crypto_destroy(_gsskrb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
if (ret) {
- _gsskrb5_set_error_string ();
free (output_message_buffer->value);
output_message_buffer->length = 0;
output_message_buffer->value = NULL;
@@ -501,44 +506,46 @@ OM_uint32 _gsskrb5_wrap
gss_buffer_t output_message_buffer
)
{
+ krb5_context context;
krb5_keyblock *key;
OM_uint32 ret;
krb5_keytype keytype;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
+ GSSAPI_KRB5_INIT (&context);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
- ret = _gsskrb5i_get_token_key(ctx, &key);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
- _gsskrb5_set_error_string ();
*minor_status = ret;
return GSS_S_FAILURE;
}
- krb5_enctype_to_keytype (_gsskrb5_context, key->keytype, &keytype);
+ krb5_enctype_to_keytype (context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_DES :
- ret = wrap_des (minor_status, ctx, conf_req_flag,
+ ret = wrap_des (minor_status, ctx, context, conf_req_flag,
qop_req, input_message_buffer, conf_state,
output_message_buffer, key);
break;
case KEYTYPE_DES3 :
- ret = wrap_des3 (minor_status, ctx, conf_req_flag,
+ ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
qop_req, input_message_buffer, conf_state,
output_message_buffer, key);
break;
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
- ret = _gssapi_wrap_arcfour (minor_status, ctx, conf_req_flag,
+ ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
qop_req, input_message_buffer, conf_state,
output_message_buffer, key);
break;
default :
- ret = _gssapi_wrap_cfx (minor_status, ctx, conf_req_flag,
+ ret = _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
qop_req, input_message_buffer, conf_state,
output_message_buffer, key);
break;
}
- krb5_free_keyblock (_gsskrb5_context, key);
+ krb5_free_keyblock (context, key);
return ret;
}
diff --git a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
index 73207806a03..7df8a3483ea 100644
--- a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
+++ b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
@@ -27,7 +27,7 @@
*/
#include "mech_locl.h"
-RCSID("$Id: gss_accept_sec_context.c,v 1.7 2006/11/10 03:30:12 lha Exp $");
+RCSID("$Id: gss_accept_sec_context.c,v 1.9 2006/12/15 20:12:20 lha Exp $");
static OM_uint32
parse_header(const gss_buffer_t input_token, gss_OID mech_oid)
@@ -91,6 +91,8 @@ parse_header(const gss_buffer_t input_token, gss_OID mech_oid)
static gss_OID_desc krb5_mechanism =
{9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
+static gss_OID_desc ntlm_mechanism =
+ {10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")};
static gss_OID_desc spnego_mechanism =
{6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02")};
@@ -112,7 +114,14 @@ choose_mech(const gss_buffer_t input, gss_OID mech_oid)
* Lets guess what mech is really is, callback function to mech ??
*/
- if (input->length != 0 && ((const char *)input->value)[0] == 0x6E) {
+ if (input->length > 8 &&
+ memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0)
+ {
+ *mech_oid = ntlm_mechanism;
+ return GSS_S_COMPLETE;
+ } else if (input->length != 0 &&
+ ((const char *)input->value)[0] == 0x6E)
+ {
/* Could be a raw AP-REQ (check for APPLICATION tag) */
*mech_oid = krb5_mechanism;
return GSS_S_COMPLETE;
diff --git a/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c b/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c
index ccaf91ba9de..0d50bbd92bf 100644
--- a/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c
+++ b/source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c
@@ -27,7 +27,23 @@
*/
#include "mech_locl.h"
-RCSID("$Id: gss_init_sec_context.c,v 1.3 2006/07/06 22:30:09 lha Exp $");
+RCSID("$Id: gss_init_sec_context.c,v 1.4 2006/11/14 12:33:11 lha Exp $");
+
+static gss_cred_id_t
+_gss_mech_cred_find(gss_cred_id_t cred_handle, gss_OID mech_type)
+{
+ struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
+ struct _gss_mechanism_cred *mc;
+
+ if (cred == NULL)
+ return GSS_C_NO_CREDENTIAL;
+
+ SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
+ if (gss_oid_equal(mech_type, mc->gmc_mech_oid))
+ return mc->gmc_cred;
+ }
+ return GSS_C_NO_CREDENTIAL;
+}
OM_uint32
gss_init_sec_context(OM_uint32 * minor_status,
@@ -49,8 +65,6 @@ gss_init_sec_context(OM_uint32 * minor_status,
struct _gss_name *name = (struct _gss_name *) target_name;
struct _gss_mechanism_name *mn;
struct _gss_context *ctx = (struct _gss_context *) *context_handle;
- struct _gss_cred *cred = (struct _gss_cred *) initiator_cred_handle;
- struct _gss_mechanism_cred *mc;
gss_cred_id_t cred_handle;
int allocated_ctx;
gss_OID mech_type = input_mech_type;
@@ -97,15 +111,7 @@ gss_init_sec_context(OM_uint32 * minor_status,
/*
* If we have a cred, find the cred for this mechanism.
*/
- cred_handle = GSS_C_NO_CREDENTIAL;
- if (cred) {
- SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
- if (gss_oid_equal(mech_type, mc->gmc_mech_oid)) {
- cred_handle = mc->gmc_cred;
- break;
- }
- }
- }
+ cred_handle = _gss_mech_cred_find(initiator_cred_handle, mech_type);
major_status = m->gm_init_sec_context(minor_status,
cred_handle,
diff --git a/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c b/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c
index 3d01ba69d49..b8fdefdca13 100644
--- a/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c
+++ b/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c
@@ -28,7 +28,7 @@
#include "mech_locl.h"
#include <heim_threads.h>
-RCSID("$Id: gss_mech_switch.c,v 1.7 2006/10/09 11:13:30 lha Exp $");
+RCSID("$Id: gss_mech_switch.c,v 1.8 2006/12/15 20:05:43 lha Exp $");
#ifndef _PATH_GSS_MECH
#define _PATH_GSS_MECH "/etc/gss/mech"
@@ -169,6 +169,8 @@ add_builtin(gssapi_mech_interface mech)
{
struct _gss_mech_switch *m;
OM_uint32 minor_status;
+ if (!mech)
+ return 0;
m = malloc(sizeof(*m));
if (m == NULL)
@@ -214,6 +216,7 @@ _gss_load_mech(void)
add_builtin(__gss_krb5_initialize());
add_builtin(__gss_spnego_initialize());
+ add_builtin(__gss_ntlm_initialize());
fp = fopen(_PATH_GSS_MECH, "r");
if (!fp) {
diff --git a/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c b/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c
index f8e013da180..f813d72ac8b 100644
--- a/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c
+++ b/source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c
@@ -31,7 +31,7 @@
*/
#include "mech_locl.h"
-RCSID("$Id: gss_set_cred_option.c,v 1.7 2006/07/01 08:50:49 lha Exp $");
+RCSID("$Id: gss_set_cred_option.c,v 1.8 2006/11/13 08:59:43 lha Exp $");
OM_uint32
gss_set_cred_option (OM_uint32 *minor_status,
@@ -102,7 +102,7 @@ gss_set_cred_option (OM_uint32 *minor_status,
major_status = m->gm_set_cred_option(minor_status,
&mc->gmc_cred, object, value);
- if (major_status == GSS_S_BAD_MECH)
+ if (major_status == GSS_S_COMPLETE)
one_ok = 1;
}
}
diff --git a/source4/heimdal/lib/gssapi/mech/gss_utils.c b/source4/heimdal/lib/gssapi/mech/gss_utils.c
index 33ee0332096..d674fb163b2 100644
--- a/source4/heimdal/lib/gssapi/mech/gss_utils.c
+++ b/source4/heimdal/lib/gssapi/mech/gss_utils.c
@@ -27,7 +27,7 @@
*/
#include "mech_locl.h"
-RCSID("$Id: gss_utils.c,v 1.2 2006/06/28 09:00:25 lha Exp $");
+RCSID("$Id: gss_utils.c,v 1.3 2006/12/18 13:01:25 lha Exp $");
OM_uint32
_gss_copy_oid(OM_uint32 *minor_status,
@@ -46,6 +46,17 @@ _gss_copy_oid(OM_uint32 *minor_status,
return (GSS_S_COMPLETE);
}
+OM_uint32
+_gss_free_oid(OM_uint32 *minor_status, gss_OID oid)
+{
+ *minor_status = 0;
+ if (oid->elements) {
+ free(oid->elements);
+ oid->elements = NULL;
+ oid->length = 0;
+ }
+ return (GSS_S_COMPLETE);
+}
OM_uint32
_gss_copy_buffer(OM_uint32 *minor_status,
diff --git a/source4/heimdal/lib/gssapi/mech/utils.h b/source4/heimdal/lib/gssapi/mech/utils.h
index 75a507298c0..42e92c3f42b 100644
--- a/source4/heimdal/lib/gssapi/mech/utils.h
+++ b/source4/heimdal/lib/gssapi/mech/utils.h
@@ -24,9 +24,10 @@
* SUCH DAMAGE.
*
* $FreeBSD: src/lib/libgssapi/utils.h,v 1.1 2005/12/29 14:40:20 dfr Exp $
- * $Id: utils.h,v 1.3 2006/07/20 01:48:25 lha Exp $
+ * $Id: utils.h,v 1.4 2006/12/18 13:01:40 lha Exp $
*/
+OM_uint32 _gss_free_oid(OM_uint32 *, gss_OID);
OM_uint32 _gss_copy_oid(OM_uint32 *, const gss_OID, gss_OID);
OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status,
const gss_buffer_t from_buf, gss_buffer_t to_buf);
diff --git a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c
index 8a885a3e2f7..2c86b3f794e 100644
--- a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c
+++ b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* Portions Copyright (c) 2004 PADL Software Pty Ltd.
*
@@ -33,203 +33,85 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: accept_sec_context.c,v 1.6 2006/10/07 22:26:57 lha Exp $");
-
-OM_uint32
-_gss_spnego_encode_response(OM_uint32 *minor_status,
- const NegTokenResp *resp,
- gss_buffer_t data,
- u_char **ret_buf)
-{
- OM_uint32 ret;
- u_char *buf;
- size_t buf_size, buf_len;
-
- buf_size = 1024;
- buf = malloc(buf_size);
- if (buf == NULL) {
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
-
- do {
- ret = encode_NegTokenResp(buf + buf_size - 1,
- buf_size,
- resp, &buf_len);
- if (ret == 0) {
- size_t tmp;
-
- ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
- buf_size - buf_len,
- buf_len,
- ASN1_C_CONTEXT,
- CONS,
- 1,
- &tmp);
- if (ret == 0)
- buf_len += tmp;
- }
- if (ret) {
- if (ret == ASN1_OVERFLOW) {
- u_char *tmp;
-
- buf_size *= 2;
- tmp = realloc (buf, buf_size);
- if (tmp == NULL) {
- *minor_status = ENOMEM;
- free(buf);
- return GSS_S_FAILURE;
- }
- buf = tmp;
- } else {
- *minor_status = ret;
- free(buf);
- return GSS_S_FAILURE;
- }
- }
- } while (ret == ASN1_OVERFLOW);
-
- data->value = buf + buf_size - buf_len;
- data->length = buf_len;
- *ret_buf = buf;
-
- return GSS_S_COMPLETE;
-}
+RCSID("$Id: accept_sec_context.c,v 1.16 2006/12/19 12:10:35 lha Exp $");
static OM_uint32
send_reject (OM_uint32 *minor_status,
gss_buffer_t output_token)
{
- NegTokenResp resp;
- gss_buffer_desc data;
- u_char *buf;
- OM_uint32 ret;
+ NegotiationToken nt;
+ size_t size;
+
+ nt.element = choice_NegotiationToken_negTokenResp;
- ALLOC(resp.negResult, 1);
- if (resp.negResult == NULL) {
+ ALLOC(nt.u.negTokenResp.negResult, 1);
+ if (nt.u.negTokenResp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- *(resp.negResult) = reject;
- resp.supportedMech = NULL;
- resp.responseToken = NULL;
- resp.mechListMIC = NULL;
+ *(nt.u.negTokenResp.negResult) = reject;
+ nt.u.negTokenResp.supportedMech = NULL;
+ nt.u.negTokenResp.responseToken = NULL;
+ nt.u.negTokenResp.mechListMIC = NULL;
- ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf);
- free_NegTokenResp(&resp);
- if (ret != GSS_S_COMPLETE)
- return ret;
+ ASN1_MALLOC_ENCODE(NegotiationToken,
+ output_token->value, output_token->length, &nt,
+ &size, *minor_status);
+ free_NegotiationToken(&nt);
+ if (*minor_status != 0)
+ return GSS_S_FAILURE;
- output_token->value = malloc(data.length);
- if (output_token->value == NULL) {
- *minor_status = ENOMEM;
- ret = GSS_S_FAILURE;
- } else {
- output_token->length = data.length;
- memcpy(output_token->value, data.value, output_token->length);
- }
- free(buf);
- if (ret != GSS_S_COMPLETE)
- return ret;
return GSS_S_BAD_MECH;
}
-OM_uint32
-_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
- int includeMSCompatOID,
- const gssspnego_cred cred_handle,
- MechTypeList *mechtypelist,
- gss_OID *preferred_mech)
+static OM_uint32
+acceptor_approved(gss_name_t target_name, gss_OID mech)
{
- OM_uint32 ret;
- gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
- int i, count;
-
- if (cred_handle != NULL) {
- ret = gss_inquire_cred(minor_status,
- cred_handle->negotiated_cred_id,
- NULL,
- NULL,
- NULL,
- &supported_mechs);
- } else {
- ret = gss_indicate_mechs(minor_status, &supported_mechs);
- }
+ gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
+ gss_OID_set oidset;
+ OM_uint32 junk, ret;
- if (ret != GSS_S_COMPLETE) {
- return ret;
- }
+ if (target_name == GSS_C_NO_NAME)
+ return GSS_S_COMPLETE;
- if (supported_mechs->count == 0) {
- *minor_status = ENOENT;
- gss_release_oid_set(minor_status, &supported_mechs);
- return GSS_S_FAILURE;
- }
-
- count = supported_mechs->count;
- if (includeMSCompatOID)
- count++;
-
- mechtypelist->len = 0;
- mechtypelist->val = calloc(count, sizeof(MechType));
- if (mechtypelist->val == NULL) {
- *minor_status = ENOMEM;
- gss_release_oid_set(minor_status, &supported_mechs);
- return GSS_S_FAILURE;
- }
-
- for (i = 0; i < supported_mechs->count; i++) {
- ret = _gss_spnego_add_mech_type(&supported_mechs->elements[i],
- includeMSCompatOID,
- mechtypelist);
- if (ret != 0) {
- *minor_status = ENOMEM;
- ret = GSS_S_FAILURE;
- break;
- }
- }
-
- if (ret == GSS_S_COMPLETE && preferred_mech != NULL) {
- ret = gss_duplicate_oid(minor_status,
- &supported_mechs->elements[0],
- preferred_mech);
- }
-
- if (ret != GSS_S_COMPLETE) {
- free_MechTypeList(mechtypelist);
- mechtypelist->len = 0;
- mechtypelist->val = NULL;
- }
- gss_release_oid_set(minor_status, &supported_mechs);
-
- return ret;
+ gss_create_empty_oid_set(&junk, &oidset);
+ gss_add_oid_set_member(&junk, mech, &oidset);
+
+ ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset,
+ GSS_C_ACCEPT, &cred, NULL, NULL);
+ gss_release_oid_set(&junk, &oidset);
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+ gss_release_cred(&junk, &cred);
+
+ return GSS_S_COMPLETE;
}
static OM_uint32
send_supported_mechs (OM_uint32 *minor_status,
gss_buffer_t output_token)
{
- NegTokenInit ni;
+ NegotiationTokenWin nt;
char hostname[MAXHOSTNAMELEN], *p;
gss_buffer_desc name_buf;
gss_OID name_type;
gss_name_t target_princ;
gss_name_t canon_princ;
- OM_uint32 ret, minor;
- u_char *buf;
- size_t buf_size, buf_len;
+ OM_uint32 minor;
+ size_t buf_len;
gss_buffer_desc data;
+ OM_uint32 ret;
- memset(&ni, 0, sizeof(ni));
+ memset(&nt, 0, sizeof(nt));
- ni.reqFlags = NULL;
- ni.mechToken = NULL;
- ni.negHints = NULL;
- ni.mechListMIC = NULL;
+ nt.element = choice_NegotiationTokenWin_negTokenInit;
+ nt.u.negTokenInit.reqFlags = NULL;
+ nt.u.negTokenInit.mechToken = NULL;
+ nt.u.negTokenInit.negHints = NULL;
- ret = _gss_spnego_indicate_mechtypelist(minor_status, 1,
- NULL,
- &ni.mechTypes, NULL);
+ ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME,
+ acceptor_approved, 1, NULL,
+ &nt.u.negTokenInit.mechTypes, NULL);
if (ret != GSS_S_COMPLETE) {
return ret;
}
@@ -237,7 +119,7 @@ send_supported_mechs (OM_uint32 *minor_status,
memset(&target_princ, 0, sizeof(target_princ));
if (gethostname(hostname, sizeof(hostname) - 1) != 0) {
*minor_status = errno;
- free_NegTokenInit(&ni);
+ free_NegotiationTokenWin(&nt);
return GSS_S_FAILURE;
}
@@ -255,6 +137,7 @@ send_supported_mechs (OM_uint32 *minor_status,
GSS_C_NO_OID,
&target_princ);
if (ret != GSS_S_COMPLETE) {
+ free_NegotiationTokenWin(&nt);
return ret;
}
@@ -267,6 +150,7 @@ send_supported_mechs (OM_uint32 *minor_status,
GSS_C_NO_OID,
&canon_princ);
if (ret != GSS_S_COMPLETE) {
+ free_NegotiationTokenWin(&nt);
gss_release_name(&minor, &target_princ);
return ret;
}
@@ -274,6 +158,7 @@ send_supported_mechs (OM_uint32 *minor_status,
ret = gss_display_name(minor_status, canon_princ,
&name_buf, &name_type);
if (ret != GSS_S_COMPLETE) {
+ free_NegotiationTokenWin(&nt);
gss_release_name(&minor, &canon_princ);
gss_release_name(&minor, &target_princ);
return ret;
@@ -282,81 +167,38 @@ send_supported_mechs (OM_uint32 *minor_status,
gss_release_name(&minor, &canon_princ);
gss_release_name(&minor, &target_princ);
- ALLOC(ni.negHints, 1);
- if (ni.negHints == NULL) {
+ ALLOC(nt.u.negTokenInit.negHints, 1);
+ if (nt.u.negTokenInit.negHints == NULL) {
*minor_status = ENOMEM;
gss_release_buffer(&minor, &name_buf);
- free_NegTokenInit(&ni);
+ free_NegotiationTokenWin(&nt);
return GSS_S_FAILURE;
}
- ALLOC(ni.negHints->hintName, 1);
- if (ni.negHints->hintName == NULL) {
+ ALLOC(nt.u.negTokenInit.negHints->hintName, 1);
+ if (nt.u.negTokenInit.negHints->hintName == NULL) {
*minor_status = ENOMEM;
gss_release_buffer(&minor, &name_buf);
- free_NegTokenInit(&ni);
+ free_NegotiationTokenWin(&nt);
return GSS_S_FAILURE;
}
- *(ni.negHints->hintName) = name_buf.value;
+ *(nt.u.negTokenInit.negHints->hintName) = name_buf.value;
name_buf.value = NULL;
- ni.negHints->hintAddress = NULL;
+ nt.u.negTokenInit.negHints->hintAddress = NULL;
- buf_size = 1024;
- buf = malloc(buf_size);
- if (buf == NULL) {
- free_NegTokenInit(&ni);
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
+ ASN1_MALLOC_ENCODE(NegotiationTokenWin,
+ data.value, data.length, &nt, &buf_len, ret);
+ free_NegotiationTokenWin(&nt);
+ if (ret) {
+ return ret;
}
+ if (data.length != buf_len)
+ abort();
- do {
- ret = encode_NegTokenInit(buf + buf_size - 1,
- buf_size,
- &ni, &buf_len);
- if (ret == 0) {
- size_t tmp;
-
- ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
- buf_size - buf_len,
- buf_len,
- ASN1_C_CONTEXT,
- CONS,
- 0,
- &tmp);
- if (ret == 0)
- buf_len += tmp;
- }
- if (ret) {
- if (ret == ASN1_OVERFLOW) {
- u_char *tmp;
-
- buf_size *= 2;
- tmp = realloc (buf, buf_size);
- if (tmp == NULL) {
- *minor_status = ENOMEM;
- free(buf);
- free_NegTokenInit(&ni);
- return GSS_S_FAILURE;
- }
- buf = tmp;
- } else {
- *minor_status = ret;
- free(buf);
- free_NegTokenInit(&ni);
- return GSS_S_FAILURE;
- }
- }
- } while (ret == ASN1_OVERFLOW);
+ ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token);
- data.value = buf + buf_size - buf_len;
- data.length = buf_len;
-
- ret = gss_encapsulate_token(&data,
- GSS_SPNEGO_MECHANISM,
- output_token);
- free (buf);
- free_NegTokenInit (&ni);
+ free (data.value);
if (ret != GSS_S_COMPLETE)
return ret;
@@ -374,16 +216,17 @@ send_accept (OM_uint32 *minor_status,
gss_buffer_t mech_buf,
gss_buffer_t output_token)
{
- NegTokenResp resp;
- gss_buffer_desc data;
- u_char *buf;
+ NegotiationToken nt;
OM_uint32 ret;
gss_buffer_desc mech_mic_buf;
+ size_t size;
- memset(&resp, 0, sizeof(resp));
+ memset(&nt, 0, sizeof(nt));
- ALLOC(resp.negResult, 1);
- if (resp.negResult == NULL) {
+ nt.element = choice_NegotiationToken_negTokenResp;
+
+ ALLOC(nt.u.negTokenResp.negResult, 1);
+ if (nt.u.negTokenResp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
@@ -392,79 +235,85 @@ send_accept (OM_uint32 *minor_status,
if (mech_token != GSS_C_NO_BUFFER
&& mech_token->length != 0
&& mech_buf != GSS_C_NO_BUFFER)
- *(resp.negResult) = accept_incomplete;
+ *(nt.u.negTokenResp.negResult) = accept_incomplete;
else
- *(resp.negResult) = accept_completed;
+ *(nt.u.negTokenResp.negResult) = accept_completed;
} else {
if (initial_response && context_handle->require_mic)
- *(resp.negResult) = request_mic;
+ *(nt.u.negTokenResp.negResult) = request_mic;
else
- *(resp.negResult) = accept_incomplete;
+ *(nt.u.negTokenResp.negResult) = accept_incomplete;
}
if (initial_response) {
- ALLOC(resp.supportedMech, 1);
- if (resp.supportedMech == NULL) {
- free_NegTokenResp(&resp);
+ ALLOC(nt.u.negTokenResp.supportedMech, 1);
+ if (nt.u.negTokenResp.supportedMech == NULL) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
ret = der_get_oid(context_handle->preferred_mech_type->elements,
context_handle->preferred_mech_type->length,
- resp.supportedMech,
+ nt.u.negTokenResp.supportedMech,
NULL);
if (ret) {
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
} else {
- resp.supportedMech = NULL;
+ nt.u.negTokenResp.supportedMech = NULL;
}
if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {
- ALLOC(resp.responseToken, 1);
- if (resp.responseToken == NULL) {
- free_NegTokenResp(&resp);
+ ALLOC(nt.u.negTokenResp.responseToken, 1);
+ if (nt.u.negTokenResp.responseToken == NULL) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- resp.responseToken->length = mech_token->length;
- resp.responseToken->data = mech_token->value;
+ nt.u.negTokenResp.responseToken->length = mech_token->length;
+ nt.u.negTokenResp.responseToken->data = mech_token->value;
mech_token->length = 0;
mech_token->value = NULL;
} else {
- resp.responseToken = NULL;
+ nt.u.negTokenResp.responseToken = NULL;
}
if (mech_buf != GSS_C_NO_BUFFER) {
- ALLOC(resp.mechListMIC, 1);
- if (resp.mechListMIC == NULL) {
- free_NegTokenResp(&resp);
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
-
ret = gss_get_mic(minor_status,
context_handle->negotiated_ctx_id,
0,
mech_buf,
&mech_mic_buf);
- if (ret != GSS_S_COMPLETE) {
- free_NegTokenResp(&resp);
+ if (ret == GSS_S_COMPLETE) {
+ ALLOC(nt.u.negTokenResp.mechListMIC, 1);
+ if (nt.u.negTokenResp.mechListMIC == NULL) {
+ gss_release_buffer(minor_status, &mech_mic_buf);
+ free_NegotiationToken(&nt);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length;
+ nt.u.negTokenResp.mechListMIC->data = mech_mic_buf.value;
+ } else if (ret == GSS_S_UNAVAILABLE) {
+ nt.u.negTokenResp.mechListMIC = NULL;
+ } else {
+ free_NegotiationToken(&nt);
return ret;
}
- resp.mechListMIC->length = mech_mic_buf.length;
- resp.mechListMIC->data = mech_mic_buf.value;
} else
- resp.mechListMIC = NULL;
+ nt.u.negTokenResp.mechListMIC = NULL;
- ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf);
- if (ret != GSS_S_COMPLETE) {
- free_NegTokenResp(&resp);
- return ret;
+ ASN1_MALLOC_ENCODE(NegotiationToken,
+ output_token->value, output_token->length,
+ &nt, &size, ret);
+ if (ret) {
+ free_NegotiationToken(&nt);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
}
/*
@@ -472,23 +321,12 @@ send_accept (OM_uint32 *minor_status,
* it is a SubsequentContextToken (note though RFC 1964
* specifies encapsulation for all _Kerberos_ tokens).
*/
- output_token->value = malloc(data.length);
- if (output_token->value == NULL) {
- *minor_status = ENOMEM;
- ret = GSS_S_FAILURE;
- } else {
- output_token->length = data.length;
- memcpy(output_token->value, data.value, output_token->length);
- }
- free(buf);
- if (ret != GSS_S_COMPLETE) {
- free_NegTokenResp(&resp);
- return ret;
- }
- ret = (*(resp.negResult) == accept_completed) ? GSS_S_COMPLETE :
- GSS_S_CONTINUE_NEEDED;
- free_NegTokenResp(&resp);
+ if (*(nt.u.negTokenResp.negResult) == accept_completed)
+ ret = GSS_S_COMPLETE;
+ else
+ ret = GSS_S_CONTINUE_NEEDED;
+ free_NegotiationToken(&nt);
return ret;
}
@@ -530,8 +368,164 @@ verify_mechlist_mic
return ret;
}
-OM_uint32
-_gss_spnego_accept_sec_context
+static OM_uint32
+select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p,
+ gss_OID *mech_p)
+{
+ char mechbuf[64];
+ size_t mech_len;
+ gss_OID_desc oid;
+ OM_uint32 ret, junk;
+
+ ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
+ sizeof(mechbuf),
+ mechType,
+ &mech_len);
+ if (ret) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ oid.length = mech_len;
+ oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
+
+ if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {
+ return GSS_S_BAD_MECH;
+ }
+
+ *minor_status = 0;
+
+ /* Translate broken MS Kebreros OID */
+ if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc)) {
+ gssapi_mech_interface mech;
+
+ mech = __gss_get_mechanism(&_gss_spnego_krb5_mechanism_oid_desc);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+
+ ret = gss_duplicate_oid(minor_status,
+ &_gss_spnego_mskrb_mechanism_oid_desc,
+ mech_p);
+ } else {
+ gssapi_mech_interface mech;
+
+ mech = __gss_get_mechanism(&oid);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+
+ ret = gss_duplicate_oid(minor_status,
+ &mech->gm_mech_oid,
+ mech_p);
+ }
+
+ if (verify_p) {
+ gss_name_t name = GSS_C_NO_NAME;
+ gss_buffer_desc namebuf;
+ char *str = NULL, *host, hostname[MAXHOSTNAMELEN];
+
+ host = getenv("GSSAPI_SPNEGO_NAME");
+ if (host == NULL || issuid()) {
+ if (gethostname(hostname, sizeof(hostname)) != 0) {
+ *minor_status = errno;
+ return GSS_S_FAILURE;
+ }
+ asprintf(&str, "host@%s", hostname);
+ host = str;
+ }
+
+ namebuf.length = strlen(host);
+ namebuf.value = host;
+
+ ret = gss_import_name(minor_status, &namebuf,
+ GSS_C_NT_HOSTBASED_SERVICE, &name);
+ if (str)
+ free(str);
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+
+ ret = acceptor_approved(name, *mech_p);
+ gss_release_name(&junk, &name);
+ }
+
+ return ret;
+}
+
+
+static OM_uint32
+acceptor_complete(OM_uint32 * minor_status,
+ gssspnego_ctx ctx,
+ int *get_mic,
+ gss_buffer_t mech_buf,
+ gss_buffer_t mech_input_token,
+ gss_buffer_t mech_output_token,
+ heim_octet_string *mic,
+ gss_buffer_t output_token)
+{
+ OM_uint32 ret;
+ int require_mic, verify_mic;
+ gss_buffer_desc buf;
+
+ buf.length = 0;
+ buf.value = NULL;
+
+ ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic);
+ if (ret)
+ return ret;
+
+ ctx->require_mic = require_mic;
+
+ if (mic != NULL)
+ require_mic = 1;
+
+ if (ctx->open && require_mic) {
+ if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
+ verify_mic = 1;
+ *get_mic = 0;
+ } else if (mech_output_token != GSS_C_NO_BUFFER &&
+ mech_output_token->length == 0) { /* Odd */
+ *get_mic = verify_mic = 1;
+ } else { /* Even/One */
+ verify_mic = 0;
+ *get_mic = 1;
+ }
+
+ if (verify_mic || get_mic) {
+ int eret;
+ size_t buf_len;
+
+ ASN1_MALLOC_ENCODE(MechTypeList,
+ mech_buf->value, mech_buf->length,
+ &ctx->initiator_mech_types, &buf_len, eret);
+ if (eret) {
+ *minor_status = eret;
+ return GSS_S_FAILURE;
+ }
+ if (buf.length != buf_len)
+ abort();
+ }
+
+ if (verify_mic) {
+ ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic);
+ if (ret) {
+ if (get_mic)
+ send_reject (minor_status, output_token);
+ if (buf.value)
+ free(buf.value);
+ return ret;
+ }
+ ctx->verified_mic = 1;
+ }
+ if (buf.value)
+ free(buf.value);
+
+ } else
+ *get_mic = verify_mic = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+
+static OM_uint32
+acceptor_start
(OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
const gss_cred_id_t acceptor_cred_handle,
@@ -547,40 +541,21 @@ _gss_spnego_accept_sec_context
{
OM_uint32 ret, ret2, minor;
NegTokenInit ni;
- NegTokenResp na;
- size_t ni_len, na_len;
+ size_t ni_len;
int i;
gss_buffer_desc data;
size_t len, taglen;
- int initialToken;
- unsigned int negResult = accept_incomplete;
gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
- gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
+ gss_buffer_desc mech_output_token;
gss_buffer_desc mech_buf;
gss_OID preferred_mech_type = GSS_C_NO_OID;
gssspnego_ctx ctx;
gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle;
+ int get_mic = 0;
+ int first_ok = 0;
- *minor_status = 0;
-
- output_token->length = 0;
- output_token->value = NULL;
-
- if (src_name != NULL)
- *src_name = GSS_C_NO_NAME;
-
- if (mech_type != NULL)
- *mech_type = GSS_C_NO_OID;
-
- if (ret_flags != NULL)
- *ret_flags = 0;
-
- if (time_rec != NULL)
- *time_rec = 0;
-
- if (delegated_cred_handle != NULL)
- *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
-
+ mech_output_token.value = NULL;
+ mech_output_token.length = 0;
mech_buf.value = NULL;
if (*context_handle == GSS_C_NO_CONTEXT) {
@@ -590,8 +565,7 @@ _gss_spnego_accept_sec_context
return ret;
if (input_token_buffer->length == 0) {
- return send_supported_mechs (minor_status,
- output_token);
+ return send_supported_mechs (minor_status, output_token);
}
}
@@ -604,16 +578,12 @@ _gss_spnego_accept_sec_context
ret = gss_decapsulate_token (input_token_buffer,
GSS_SPNEGO_MECHANISM,
&data);
- initialToken = (ret == GSS_S_COMPLETE);
-
- if (!initialToken) {
- data.value = input_token_buffer->value;
- data.length = input_token_buffer->length;
- }
+ if (ret)
+ return ret;
ret = der_match_tag_and_length(data.value, data.length,
ASN1_C_CONTEXT, CONS,
- initialToken ? 0 : 1,
+ 0,
&len, &taglen);
if (ret) {
*minor_status = ret;
@@ -625,70 +595,263 @@ _gss_spnego_accept_sec_context
return GSS_S_FAILURE;
}
- if (initialToken) {
- ret = decode_NegTokenInit((const unsigned char *)data.value + taglen,
+ ret = decode_NegTokenInit((const unsigned char *)data.value + taglen,
len, &ni, &ni_len);
- } else {
- ret = decode_NegTokenResp((const unsigned char *)data.value + taglen,
- len, &na, &na_len);
- }
if (ret) {
*minor_status = ret;
return GSS_S_DEFECTIVE_TOKEN;
}
- if (!initialToken && na.negResult != NULL) {
- negResult = *(na.negResult);
+ if (ni.mechTypes.len < 1) {
+ free_NegTokenInit(&ni);
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
}
- if (negResult == reject || negResult == request_mic) {
- /* request_mic should only be sent by acceptor */
- free_NegTokenResp(&na);
- return GSS_S_DEFECTIVE_TOKEN;
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+
+ ret = copy_MechTypeList(&ni.mechTypes, &ctx->initiator_mech_types);
+ if (ret) {
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ free_NegTokenInit(&ni);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
}
- if (initialToken) {
- for (i = 0; i < ni.mechTypes.len; ++i) {
- /* Call glue layer to find first mech we support */
- ret = _gss_spnego_select_mech(minor_status, &ni.mechTypes.val[i],
- &preferred_mech_type);
+ /*
+ * First we try the opportunistic token if we have support for it,
+ * don't try to verify we have credential for the token,
+ * gss_accept_sec_context will (hopefully) tell us that.
+ * If that failes,
+ */
+
+ ret = select_mech(minor_status,
+ &ni.mechTypes.val[0],
+ 0,
+ &preferred_mech_type);
+
+ if (ret == 0 && ni.mechToken != NULL) {
+ gss_cred_id_t mech_delegated_cred = GSS_C_NO_CREDENTIAL;
+ gss_cred_id_t mech_cred;
+ gss_buffer_desc ibuf;
+
+ ibuf.length = ni.mechToken->length;
+ ibuf.value = ni.mechToken->data;
+ mech_input_token = &ibuf;
+
+ if (acceptor_cred != NULL)
+ mech_cred = acceptor_cred->negotiated_cred_id;
+ else
+ mech_cred = GSS_C_NO_CREDENTIAL;
+
+ if (ctx->mech_src_name != GSS_C_NO_NAME)
+ gss_release_name(&minor, &ctx->mech_src_name);
+
+ if (ctx->delegated_cred_id != GSS_C_NO_CREDENTIAL)
+ _gss_spnego_release_cred(&minor, &ctx->delegated_cred_id);
+
+ ret = gss_accept_sec_context(&minor,
+ &ctx->negotiated_ctx_id,
+ mech_cred,
+ mech_input_token,
+ input_chan_bindings,
+ &ctx->mech_src_name,
+ &ctx->negotiated_mech_type,
+ &mech_output_token,
+ &ctx->mech_flags,
+ &ctx->mech_time_rec,
+ &mech_delegated_cred);
+ if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
+ if (delegated_cred_handle)
+ ret = _gss_spnego_alloc_cred(minor_status,
+ mech_delegated_cred,
+ delegated_cred_handle);
+ else
+ gss_release_cred(&ret2, &mech_delegated_cred);
+
+ ctx->preferred_mech_type = preferred_mech_type;
+ ctx->negotiated_mech_type = preferred_mech_type;
+ if (ret == GSS_S_COMPLETE)
+ ctx->open = 1;
+
+ ret = acceptor_complete(minor_status,
+ ctx,
+ &get_mic,
+ &mech_buf,
+ mech_input_token,
+ &mech_output_token,
+ ni.mechListMIC,
+ output_token);
+ if (ret != GSS_S_COMPLETE)
+ goto out;
+
+ first_ok = 1;
+ }
+ }
+
+ /*
+ * If opportunistic token failed, lets try the other mechs.
+ */
+
+ if (!first_ok) {
+
+ /* Call glue layer to find first mech we support */
+ for (i = 1; i < ni.mechTypes.len; ++i) {
+ ret = select_mech(minor_status,
+ &ni.mechTypes.val[i],
+ 1,
+ &preferred_mech_type);
if (ret == 0)
break;
}
if (preferred_mech_type == GSS_C_NO_OID) {
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free_NegTokenInit(&ni);
return GSS_S_BAD_MECH;
}
+
+ ctx->preferred_mech_type = preferred_mech_type;
+ ctx->negotiated_mech_type = preferred_mech_type;
}
- HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ /*
+ * The initial token always have a response
+ */
- if (initialToken) {
- ctx->preferred_mech_type = preferred_mech_type;
- ctx->initiator_mech_types.len = ni.mechTypes.len;
- ctx->initiator_mech_types.val = ni.mechTypes.val;
- ni.mechTypes.len = 0;
- ni.mechTypes.val = NULL;
+ ret = send_accept (minor_status,
+ ctx,
+ &mech_output_token,
+ 1,
+ get_mic ? &mech_buf : NULL,
+ output_token);
+ if (ret)
+ goto out;
+
+out:
+ if (mech_output_token.value != NULL)
+ gss_release_buffer(&minor, &mech_output_token);
+ if (mech_buf.value != NULL) {
+ free(mech_buf.value);
+ mech_buf.value = NULL;
+ }
+ free_NegTokenInit(&ni);
+
+ if (ret == GSS_S_COMPLETE) {
+ if (src_name != NULL && ctx->mech_src_name != NULL) {
+ spnego_name name;
+
+ name = calloc(1, sizeof(*name));
+ if (name) {
+ name->mech = ctx->mech_src_name;
+ ctx->mech_src_name = NULL;
+ *src_name = (gss_name_t)name;
+ } else
+ *src_name = GSS_C_NO_NAME;
+ }
+ if (delegated_cred_handle != NULL) {
+ *delegated_cred_handle = ctx->delegated_cred_id;
+ ctx->delegated_cred_id = GSS_C_NO_CREDENTIAL;
+ }
+ }
+
+ if (mech_type != NULL)
+ *mech_type = ctx->negotiated_mech_type;
+ if (ret_flags != NULL)
+ *ret_flags = ctx->mech_flags;
+ if (time_rec != NULL)
+ *time_rec = ctx->mech_time_rec;
+
+ if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ return ret;
}
+ _gss_spnego_internal_delete_sec_context(&minor, context_handle,
+ GSS_C_NO_BUFFER);
+
+ return ret;
+}
+
+
+static OM_uint32
+acceptor_continue
+ (OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token_buffer,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t *delegated_cred_handle
+ )
+{
+ OM_uint32 ret, ret2, minor;
+ NegTokenResp na;
+ size_t na_len;
+ gss_buffer_desc data;
+ size_t len, taglen;
+ unsigned int negResult = accept_incomplete;
+ gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
+ gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
+ gss_buffer_desc mech_buf;
+ gssspnego_ctx ctx;
+ gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle;
+
+ mech_buf.value = NULL;
+
+ ctx = (gssspnego_ctx)*context_handle;
+
+ /*
+ * The GSS-API encapsulation is only present on the initial
+ * context token (negTokenInit).
+ */
+
+ data.value = input_token_buffer->value;
+ data.length = input_token_buffer->length;
+
+ ret = der_match_tag_and_length(data.value, data.length,
+ ASN1_C_CONTEXT, CONS,
+ 1,
+ &len, &taglen);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ if (len > data.length - taglen) {
+ *minor_status = ASN1_OVERRUN;
+ return GSS_S_FAILURE;
+ }
+
+ ret = decode_NegTokenResp((const unsigned char *)data.value + taglen,
+ len, &na, &na_len);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (na.negResult != NULL) {
+ negResult = *(na.negResult);
+ }
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+
{
gss_buffer_desc ibuf, obuf;
- int require_mic, verify_mic, get_mic;
+ int require_mic, get_mic;
int require_response;
heim_octet_string *mic;
- if (initialToken) {
- if (ni.mechToken != NULL) {
- ibuf.length = ni.mechToken->length;
- ibuf.value = ni.mechToken->data;
- mech_input_token = &ibuf;
- }
+ if (na.responseToken != NULL) {
+ ibuf.length = na.responseToken->length;
+ ibuf.value = na.responseToken->data;
+ mech_input_token = &ibuf;
} else {
- if (na.responseToken != NULL) {
- ibuf.length = na.responseToken->length;
- ibuf.value = na.responseToken->data;
- mech_input_token = &ibuf;
- }
+ ibuf.value = NULL;
+ ibuf.length = 0;
}
if (mech_input_token != GSS_C_NO_BUFFER) {
@@ -737,10 +900,7 @@ _gss_spnego_accept_sec_context
mech_output_token = &obuf;
}
if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
- if (initialToken)
- free_NegTokenInit(&ni);
- else
- free_NegTokenResp(&na);
+ free_NegTokenResp(&na);
send_reject (minor_status, output_token);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
@@ -758,50 +918,19 @@ _gss_spnego_accept_sec_context
ctx->require_mic = require_mic;
- mic = initialToken ? ni.mechListMIC : na.mechListMIC;
+ mic = na.mechListMIC;
if (mic != NULL)
require_mic = 1;
- if (ctx->open && require_mic) {
- if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
- verify_mic = 1;
- get_mic = 0;
- } else if (mech_output_token != GSS_C_NO_BUFFER &&
- mech_output_token->length == 0) { /* Odd */
- get_mic = verify_mic = 1;
- } else { /* Even/One */
- verify_mic = 0;
- get_mic = 1;
- }
-
- if (verify_mic || get_mic) {
- int eret;
- size_t buf_len;
-
- ASN1_MALLOC_ENCODE(MechTypeList,
- mech_buf.value, mech_buf.length,
- &ctx->initiator_mech_types, &buf_len, eret);
- if (eret) {
- ret2 = GSS_S_FAILURE;
- *minor_status = eret;
- goto out;
- }
- if (mech_buf.length != buf_len)
- abort();
- }
-
- if (verify_mic) {
- ret2 = verify_mechlist_mic(minor_status, ctx, &mech_buf, mic);
- if (ret2) {
- if (get_mic)
- send_reject (minor_status, output_token);
- goto out;
- }
-
- ctx->verified_mic = 1;
- }
- } else
- verify_mic = get_mic = 0;
+ if (ret == GSS_S_COMPLETE)
+ ret = acceptor_complete(minor_status,
+ ctx,
+ &get_mic,
+ &mech_buf,
+ mech_input_token,
+ mech_output_token,
+ na.mechListMIC,
+ output_token);
if (ctx->mech_flags & GSS_C_DCE_STYLE)
require_response = (negResult != accept_completed);
@@ -814,12 +943,13 @@ _gss_spnego_accept_sec_context
*/
if ((mech_output_token != GSS_C_NO_BUFFER &&
mech_output_token->length != 0)
+ || (ctx->open && negResult == accept_incomplete)
|| require_response
|| get_mic) {
ret2 = send_accept (minor_status,
ctx,
mech_output_token,
- initialToken,
+ 0,
get_mic ? &mech_buf : NULL,
output_token);
if (ret2)
@@ -833,10 +963,7 @@ _gss_spnego_accept_sec_context
gss_release_buffer(&minor, mech_output_token);
if (mech_buf.value != NULL)
free(mech_buf.value);
- if (initialToken)
- free_NegTokenInit(&ni);
- else
- free_NegTokenResp(&na);
+ free_NegTokenResp(&na);
}
if (ret == GSS_S_COMPLETE) {
@@ -871,3 +998,48 @@ _gss_spnego_accept_sec_context
return ret;
}
+OM_uint32
+_gss_spnego_accept_sec_context
+ (OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token_buffer,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t *delegated_cred_handle
+ )
+{
+ _gss_accept_sec_context_t *func;
+
+ *minor_status = 0;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (mech_type != NULL)
+ *mech_type = GSS_C_NO_OID;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ func = acceptor_start;
+ else
+ func = acceptor_continue;
+
+
+ return (*func)(minor_status, context_handle, acceptor_cred_handle,
+ input_token_buffer, input_chan_bindings,
+ src_name, mech_type, output_token, ret_flags,
+ time_rec, delegated_cred_handle);
+}
diff --git a/source4/heimdal/lib/gssapi/spnego/compat.c b/source4/heimdal/lib/gssapi/spnego/compat.c
index aeae0882580..786eac13400 100644
--- a/source4/heimdal/lib/gssapi/spnego/compat.c
+++ b/source4/heimdal/lib/gssapi/spnego/compat.c
@@ -32,7 +32,7 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: compat.c,v 1.6 2006/10/07 22:26:59 lha Exp $");
+RCSID("$Id: compat.c,v 1.9 2006/12/18 17:52:26 lha Exp $");
/*
* Apparently Microsoft got the OID wrong, and used
@@ -42,10 +42,10 @@ RCSID("$Id: compat.c,v 1.6 2006/10/07 22:26:59 lha Exp $");
* prefer to deal with this here rather than inside the
* Kerberos mechanism.
*/
-static gss_OID_desc gss_mskrb_mechanism_oid_desc =
+gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc =
{9, (void *)"\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"};
-static gss_OID_desc gss_krb5_mechanism_oid_desc =
+gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc =
{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
/*
@@ -191,8 +191,8 @@ _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
if (*require_mic) {
if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) {
*require_mic = 0;
- } else if (gss_oid_equal(ctx->negotiated_mech_type, &gss_krb5_mechanism_oid_desc) &&
- gss_oid_equal(ctx->preferred_mech_type, &gss_mskrb_mechanism_oid_desc)) {
+ } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) &&
+ gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) {
*require_mic = 0;
}
}
@@ -200,86 +200,122 @@ _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
-int _gss_spnego_add_mech_type(gss_OID mech_type,
- int includeMSCompatOID,
- MechTypeList *mechtypelist)
+static int
+add_mech_type(gss_OID mech_type,
+ int includeMSCompatOID,
+ MechTypeList *mechtypelist)
{
+ MechType mech;
int ret;
if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM))
return 0;
if (includeMSCompatOID &&
- gss_oid_equal(mech_type, &gss_krb5_mechanism_oid_desc)) {
- ret = der_get_oid(gss_mskrb_mechanism_oid_desc.elements,
- gss_mskrb_mechanism_oid_desc.length,
- &mechtypelist->val[mechtypelist->len],
+ gss_oid_equal(mech_type, &_gss_spnego_krb5_mechanism_oid_desc)) {
+ ret = der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc.elements,
+ _gss_spnego_mskrb_mechanism_oid_desc.length,
+ &mech,
NULL);
if (ret)
return ret;
- mechtypelist->len++;
+ ret = add_MechTypeList(mechtypelist, &mech);
+ free_MechType(&mech);
+ if (ret)
+ return ret;
}
- ret = der_get_oid(mech_type->elements,
- mech_type->length,
- &mechtypelist->val[mechtypelist->len],
- NULL);
+ ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL);
if (ret)
return ret;
- mechtypelist->len++;
-
- return 0;
+ ret = add_MechTypeList(mechtypelist, &mech);
+ free_MechType(&mech);
+ return ret;
}
+
OM_uint32
-_gss_spnego_select_mech(OM_uint32 *minor_status,
- MechType *mechType,
- gss_OID *mech_p)
+_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
+ gss_name_t target_name,
+ OM_uint32 (*func)(gss_name_t, gss_OID),
+ int includeMSCompatOID,
+ const gssspnego_cred cred_handle,
+ MechTypeList *mechtypelist,
+ gss_OID *preferred_mech)
{
- char mechbuf[64];
- size_t mech_len;
- gss_OID_desc oid;
+ gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
+ gss_OID first_mech = GSS_C_NO_OID;
OM_uint32 ret;
-
- ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
- sizeof(mechbuf),
- mechType,
- &mech_len);
- if (ret) {
- return GSS_S_DEFECTIVE_TOKEN;
+ int i;
+
+ mechtypelist->len = 0;
+ mechtypelist->val = NULL;
+
+ if (cred_handle != NULL) {
+ ret = gss_inquire_cred(minor_status,
+ cred_handle->negotiated_cred_id,
+ NULL,
+ NULL,
+ NULL,
+ &supported_mechs);
+ } else {
+ ret = gss_indicate_mechs(minor_status, &supported_mechs);
}
- oid.length = mech_len;
- oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
-
- if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {
- return GSS_S_BAD_MECH;
+ if (ret != GSS_S_COMPLETE) {
+ return ret;
}
- *minor_status = 0;
-
- /* Translate broken MS Kebreros OID */
- if (gss_oid_equal(&oid, &gss_mskrb_mechanism_oid_desc)) {
- gssapi_mech_interface mech;
-
- mech = __gss_get_mechanism(&gss_krb5_mechanism_oid_desc);
- if (mech == NULL)
- return GSS_S_BAD_MECH;
+ if (supported_mechs->count == 0) {
+ *minor_status = ENOENT;
+ gss_release_oid_set(minor_status, &supported_mechs);
+ return GSS_S_FAILURE;
+ }
- ret = gss_duplicate_oid(minor_status,
- &gss_mskrb_mechanism_oid_desc,
- mech_p);
- } else {
- gssapi_mech_interface mech;
+ ret = (*func)(target_name, GSS_KRB5_MECHANISM);
+ if (ret == GSS_S_COMPLETE) {
+ ret = add_mech_type(GSS_KRB5_MECHANISM,
+ includeMSCompatOID,
+ mechtypelist);
+ if (!GSS_ERROR(ret))
+ first_mech = GSS_KRB5_MECHANISM;
+ }
+ ret = GSS_S_COMPLETE;
+
+ for (i = 0; i < supported_mechs->count; i++) {
+ OM_uint32 subret;
+ if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM))
+ continue;
+ if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM))
+ continue;
+
+ subret = (*func)(target_name, &supported_mechs->elements[i]);
+ if (subret != GSS_S_COMPLETE)
+ continue;
+
+ ret = add_mech_type(&supported_mechs->elements[i],
+ includeMSCompatOID,
+ mechtypelist);
+ if (ret != 0) {
+ *minor_status = ret;
+ ret = GSS_S_FAILURE;
+ break;
+ }
+ if (first_mech == GSS_C_NO_OID)
+ first_mech = &supported_mechs->elements[i];
+ }
- mech = __gss_get_mechanism(&oid);
- if (mech == NULL)
- return GSS_S_BAD_MECH;
+ if (mechtypelist->len == 0) {
+ gss_release_oid_set(minor_status, &supported_mechs);
+ *minor_status = 0;
+ return GSS_S_BAD_MECH;
+ }
- ret = gss_duplicate_oid(minor_status,
- &mech->gm_mech_oid,
- mech_p);
+ if (preferred_mech != NULL) {
+ ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech);
+ if (ret != GSS_S_COMPLETE)
+ free_MechTypeList(mechtypelist);
}
+ gss_release_oid_set(minor_status, &supported_mechs);
return ret;
}
-
diff --git a/source4/heimdal/lib/gssapi/spnego/context_stubs.c b/source4/heimdal/lib/gssapi/spnego/context_stubs.c
index 902ddbbdf9c..57bc45a4927 100644
--- a/source4/heimdal/lib/gssapi/spnego/context_stubs.c
+++ b/source4/heimdal/lib/gssapi/spnego/context_stubs.c
@@ -32,7 +32,7 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: context_stubs.c,v 1.8 2006/10/07 22:27:01 lha Exp $");
+RCSID("$Id: context_stubs.c,v 1.9 2006/12/18 12:59:44 lha Exp $");
static OM_uint32
spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs)
@@ -282,7 +282,21 @@ OM_uint32 _gss_spnego_compare_name
int * name_equal
)
{
- return gss_compare_name(minor_status, name1, name2, name_equal);
+ spnego_name n1 = (spnego_name)name1;
+ spnego_name n2 = (spnego_name)name2;
+
+ *name_equal = 0;
+
+ if (!gss_oid_equal(&n1->type, &n2->type))
+ return GSS_S_COMPLETE;
+ if (n1->value.length != n2->value.length)
+ return GSS_S_COMPLETE;
+ if (memcmp(n1->value.value, n2->value.value, n2->value.length) != 0)
+ return GSS_S_COMPLETE;
+
+ *name_equal = 1;
+
+ return GSS_S_COMPLETE;
}
OM_uint32 _gss_spnego_display_name
@@ -292,19 +306,51 @@ OM_uint32 _gss_spnego_display_name
gss_OID * output_name_type
)
{
- return gss_display_name(minor_status, input_name,
+ spnego_name name = (spnego_name)input_name;
+
+ *minor_status = 0;
+
+ if (name->mech == GSS_C_NO_NAME)
+ return GSS_S_FAILURE;
+
+ return gss_display_name(minor_status, name->mech,
output_name_buffer, output_name_type);
}
OM_uint32 _gss_spnego_import_name
(OM_uint32 * minor_status,
- const gss_buffer_t input_name_buffer,
- const gss_OID input_name_type,
+ const gss_buffer_t name_buffer,
+ const gss_OID name_type,
gss_name_t * output_name
)
{
- return gss_import_name(minor_status, input_name_buffer,
- input_name_type, output_name);
+ spnego_name name;
+ OM_uint32 maj_stat;
+
+ *minor_status = 0;
+
+ name = calloc(1, sizeof(*name));
+ if (name == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ maj_stat = _gss_copy_oid(minor_status, name_type, &name->type);
+ if (maj_stat) {
+ free(name);
+ return GSS_S_FAILURE;
+ }
+
+ maj_stat = _gss_copy_buffer(minor_status, name_buffer, &name->value);
+ if (maj_stat) {
+ gss_name_t rname = (gss_name_t)name;
+ _gss_spnego_release_name(minor_status, &rname);
+ return GSS_S_FAILURE;
+ }
+ name->mech = GSS_C_NO_NAME;
+ *output_name = (gss_name_t)name;
+
+ return GSS_S_COMPLETE;
}
OM_uint32 _gss_spnego_export_name
@@ -313,8 +359,17 @@ OM_uint32 _gss_spnego_export_name
gss_buffer_t exported_name
)
{
- return gss_export_name(minor_status, input_name,
- exported_name);
+ spnego_name name;
+ *minor_status = 0;
+
+ if (input_name == GSS_C_NO_NAME)
+ return GSS_S_BAD_NAME;
+
+ name = (spnego_name)input_name;
+ if (name->mech == GSS_C_NO_NAME)
+ return GSS_S_BAD_NAME;
+
+ return gss_export_name(minor_status, name->mech, exported_name);
}
OM_uint32 _gss_spnego_release_name
@@ -322,7 +377,20 @@ OM_uint32 _gss_spnego_release_name
gss_name_t * input_name
)
{
- return gss_release_name(minor_status, input_name);
+ *minor_status = 0;
+
+ if (*input_name != GSS_C_NO_NAME) {
+ OM_uint32 junk;
+ spnego_name name = (spnego_name)*input_name;
+ _gss_free_oid(&junk, &name->type);
+ gss_release_buffer(&junk, &name->value);
+ if (name->mech != GSS_C_NO_NAME)
+ gss_release_name(&junk, &name->mech);
+ free(name);
+
+ *input_name = GSS_C_NO_NAME;
+ }
+ return GSS_S_COMPLETE;
}
OM_uint32 _gss_spnego_inquire_context (
diff --git a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c
index 5a652fdb2e5..a221281a707 100644
--- a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c
+++ b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c
@@ -33,7 +33,39 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: init_sec_context.c,v 1.6 2006/10/14 10:09:15 lha Exp $");
+RCSID("$Id: init_sec_context.c,v 1.11 2006/12/18 15:42:03 lha Exp $");
+
+/*
+ * Is target_name an sane target for `mech´.
+ */
+
+static OM_uint32
+initiator_approved(gss_name_t target_name, gss_OID mech)
+{
+ OM_uint32 min_stat, maj_stat;
+ gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+ gss_buffer_desc out;
+
+ maj_stat = gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &ctx,
+ target_name,
+ mech,
+ 0,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER,
+ NULL,
+ &out,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ return GSS_S_BAD_MECH;
+ gss_release_buffer(&min_stat, &out);
+ gss_delete_sec_context(&min_stat, &ctx, NULL);
+
+ return GSS_S_COMPLETE;
+}
/*
* Send a reply. Note that we only need to send a reply if we
@@ -50,11 +82,10 @@ spnego_reply_internal(OM_uint32 *minor_status,
gss_buffer_t mech_token,
gss_buffer_t output_token)
{
- NegTokenResp resp;
+ NegotiationToken nt;
gss_buffer_desc mic_buf;
OM_uint32 ret;
- gss_buffer_desc data;
- u_char *buf;
+ size_t size;
if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) {
output_token->length = 0;
@@ -63,85 +94,83 @@ spnego_reply_internal(OM_uint32 *minor_status,
return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE;
}
- memset(&resp, 0, sizeof(resp));
+ memset(&nt, 0, sizeof(nt));
- ALLOC(resp.negResult, 1);
- if (resp.negResult == NULL) {
+ nt.element = choice_NegotiationToken_negTokenResp;
+
+ ALLOC(nt.u.negTokenResp.negResult, 1);
+ if (nt.u.negTokenResp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- resp.supportedMech = NULL;
+ nt.u.negTokenResp.supportedMech = NULL;
output_token->length = 0;
output_token->value = NULL;
if (mech_token->length == 0) {
- resp.responseToken = NULL;
- *(resp.negResult) = accept_completed;
+ nt.u.negTokenResp.responseToken = NULL;
+ *(nt.u.negTokenResp.negResult) = accept_completed;
} else {
- ALLOC(resp.responseToken, 1);
- if (resp.responseToken == NULL) {
- free_NegTokenResp(&resp);
+ ALLOC(nt.u.negTokenResp.responseToken, 1);
+ if (nt.u.negTokenResp.responseToken == NULL) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- resp.responseToken->length = mech_token->length;
- resp.responseToken->data = mech_token->value;
+ nt.u.negTokenResp.responseToken->length = mech_token->length;
+ nt.u.negTokenResp.responseToken->data = mech_token->value;
mech_token->length = 0;
mech_token->value = NULL;
- *(resp.negResult) = accept_incomplete;
+ *(nt.u.negTokenResp.negResult) = accept_incomplete;
}
if (mech_buf != GSS_C_NO_BUFFER) {
- ALLOC(resp.mechListMIC, 1);
- if (resp.mechListMIC == NULL) {
- free_NegTokenResp(&resp);
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
ret = gss_get_mic(minor_status,
context_handle->negotiated_ctx_id,
0,
mech_buf,
&mic_buf);
- if (ret) {
- free_NegTokenResp(&resp);
+ if (ret == GSS_S_COMPLETE) {
+ ALLOC(nt.u.negTokenResp.mechListMIC, 1);
+ if (nt.u.negTokenResp.mechListMIC == NULL) {
+ gss_release_buffer(minor_status, &mic_buf);
+ free_NegotiationToken(&nt);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ nt.u.negTokenResp.mechListMIC->length = mic_buf.length;
+ nt.u.negTokenResp.mechListMIC->data = mic_buf.value;
+ } else if (ret == GSS_S_UNAVAILABLE) {
+ nt.u.negTokenResp.mechListMIC = NULL;
+ } if (ret) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
-
- resp.mechListMIC->length = mic_buf.length;
- resp.mechListMIC->data = mic_buf.value;
} else {
- resp.mechListMIC = NULL;
+ nt.u.negTokenResp.mechListMIC = NULL;
}
- ret = _gss_spnego_encode_response (minor_status, &resp,
- &data, &buf);
+ ASN1_MALLOC_ENCODE(NegotiationToken,
+ output_token->value, output_token->length,
+ &nt, &size, ret);
if (ret) {
- free_NegTokenResp(&resp);
- return ret;
- }
-
- output_token->value = malloc(data.length);
- if (output_token->value == NULL) {
- *minor_status = ENOMEM;
- ret = GSS_S_FAILURE;
- } else {
- output_token->length = data.length;
- memcpy(output_token->value, data.value, output_token->length);
+ free_NegotiationToken(&nt);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
}
- free(buf);
- if (*(resp.negResult) == accept_completed)
+ if (*(nt.u.negTokenResp.negResult) == accept_completed)
ret = GSS_S_COMPLETE;
else
ret = GSS_S_CONTINUE_NEEDED;
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&nt);
return ret;
}
@@ -172,12 +201,16 @@ spnego_initial
size_t ni_len;
gss_ctx_id_t context;
gssspnego_ctx ctx;
+ spnego_name name = (spnego_name)target_name;
+
+ *minor_status = 0;
memset (&ni, 0, sizeof(ni));
*context_handle = GSS_C_NO_CONTEXT;
- *minor_status = 0;
+ if (target_name == GSS_C_NO_NAME)
+ return GSS_S_BAD_NAME;
sub = _gss_spnego_alloc_sec_context(&minor, &context);
if (GSS_ERROR(sub)) {
@@ -190,7 +223,17 @@ spnego_initial
ctx->local = 1;
- sub = _gss_spnego_indicate_mechtypelist(&minor, 0,
+ sub = gss_import_name(&minor, &name->value, &name->type, &ctx->target_name);
+ if (GSS_ERROR(sub)) {
+ *minor_status = minor;
+ _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
+ return sub;
+ }
+
+ sub = _gss_spnego_indicate_mechtypelist(&minor,
+ ctx->target_name,
+ initiator_approved,
+ 0,
cred,
&ni.mechTypes,
&ctx->preferred_mech_type);
@@ -212,8 +255,8 @@ spnego_initial
(cred != NULL) ? cred->negotiated_cred_id :
GSS_C_NO_CREDENTIAL,
&ctx->negotiated_ctx_id,
- target_name,
- GSS_C_NO_OID,
+ ctx->target_name,
+ ctx->preferred_mech_type,
req_flags,
time_req,
input_chan_bindings,
@@ -228,6 +271,8 @@ spnego_initial
_gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
return sub;
}
+ if (sub == GSS_S_COMPLETE)
+ ctx->maybe_open = 1;
if (mech_token.length != 0) {
ALLOC(ni.mechToken, 1);
@@ -345,8 +390,6 @@ spnego_reply
{
OM_uint32 ret, minor;
NegTokenResp resp;
- u_char oidbuf[17];
- size_t oidlen;
size_t len, taglen;
gss_OID_desc mech;
int require_mic;
@@ -385,34 +428,73 @@ spnego_reply
if (resp.negResult == NULL
|| *(resp.negResult) == reject
- || resp.supportedMech == NULL) {
+ /* || resp.supportedMech == NULL */
+ )
+ {
free_NegTokenResp(&resp);
return GSS_S_BAD_MECH;
}
- ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
- sizeof(oidbuf),
- resp.supportedMech,
- &oidlen);
- if (ret || (oidlen == GSS_SPNEGO_MECHANISM->length &&
- memcmp(oidbuf + sizeof(oidbuf) - oidlen,
- GSS_SPNEGO_MECHANISM->elements,
- oidlen) == 0)) {
+ /*
+ * Pick up the mechanism that the acceptor selected, only allow it
+ * to be sent in packet.
+ */
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+
+ if (resp.supportedMech) {
+
+ if (ctx->oidlen) {
+ free_NegTokenResp(&resp);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ return GSS_S_BAD_MECH;
+ }
+ ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1,
+ sizeof(ctx->oidbuf),
+ resp.supportedMech,
+ &ctx->oidlen);
/* Avoid recursively embedded SPNEGO */
+ if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length &&
+ memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
+ GSS_SPNEGO_MECHANISM->elements,
+ ctx->oidlen) == 0))
+ {
+ free_NegTokenResp(&resp);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ return GSS_S_BAD_MECH;
+ }
+
+ /* check if the acceptor took our optimistic token */
+ if (ctx->oidlen != ctx->preferred_mech_type->length ||
+ memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
+ ctx->preferred_mech_type->elements,
+ ctx->oidlen) != 0)
+ {
+ gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id,
+ GSS_C_NO_BUFFER);
+ ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
+ }
+ } else if (ctx->oidlen == 0) {
free_NegTokenResp(&resp);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return GSS_S_BAD_MECH;
}
- HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
-
- if (resp.responseToken != NULL) {
+ if (resp.responseToken != NULL ||
+ ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
gss_buffer_desc mech_input_token;
- mech_input_token.length = resp.responseToken->length;
- mech_input_token.value = resp.responseToken->data;
+ if (resp.responseToken) {
+ mech_input_token.length = resp.responseToken->length;
+ mech_input_token.value = resp.responseToken->data;
+ } else {
+ mech_input_token.length = 0;
+ mech_input_token.value = NULL;
+ }
- mech.length = oidlen;
- mech.elements = oidbuf + sizeof(oidbuf) - oidlen;
+
+ mech.length = ctx->oidlen;
+ mech.elements = ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen;
/* Fall through as if the negotiated mechanism
was requested explicitly */
@@ -420,7 +502,7 @@ spnego_reply
(cred != NULL) ? cred->negotiated_cred_id :
GSS_C_NO_CREDENTIAL,
&ctx->negotiated_ctx_id,
- target_name,
+ ctx->target_name,
&mech,
req_flags,
time_req,
@@ -439,6 +521,9 @@ spnego_reply
if (ret == GSS_S_COMPLETE) {
ctx->open = 1;
}
+ } else if (*(resp.negResult) == accept_completed) {
+ if (ctx->maybe_open)
+ ctx->open = 1;
}
if (*(resp.negResult) == request_mic) {
diff --git a/source4/heimdal/lib/gssapi/spnego/spnego-private.h b/source4/heimdal/lib/gssapi/spnego/spnego-private.h
index df50f65580d..d80db0018ad 100644
--- a/source4/heimdal/lib/gssapi/spnego/spnego-private.h
+++ b/source4/heimdal/lib/gssapi/spnego/spnego-private.h
@@ -46,12 +46,6 @@ _gss_spnego_add_cred (
OM_uint32 * /*initiator_time_rec*/,
OM_uint32 * acceptor_time_rec );
-int
-_gss_spnego_add_mech_type (
- gss_OID /*mech_type*/,
- int /*includeMSCompatOID*/,
- MechTypeList */*mechtypelist*/);
-
OM_uint32
_gss_spnego_alloc_cred (
OM_uint32 */*minor_status*/,
@@ -112,13 +106,6 @@ _gss_spnego_duplicate_name (
gss_name_t * dest_name );
OM_uint32
-_gss_spnego_encode_response (
- OM_uint32 */*minor_status*/,
- const NegTokenResp */*resp*/,
- gss_buffer_t /*data*/,
- u_char **/*ret_buf*/);
-
-OM_uint32
_gss_spnego_export_name (
OM_uint32 * /*minor_status*/,
const gss_name_t /*input_name*/,
@@ -141,8 +128,8 @@ _gss_spnego_get_mic (
OM_uint32
_gss_spnego_import_name (
OM_uint32 * /*minor_status*/,
- const gss_buffer_t /*input_name_buffer*/,
- const gss_OID /*input_name_type*/,
+ const gss_buffer_t /*name_buffer*/,
+ const gss_OID /*name_type*/,
gss_name_t * output_name );
OM_uint32
@@ -154,6 +141,8 @@ _gss_spnego_import_sec_context (
OM_uint32
_gss_spnego_indicate_mechtypelist (
OM_uint32 */*minor_status*/,
+ gss_name_t /*target_name*/,
+ OM_uint32 (*/*func*/)(gss_name_t, gss_OID),
int /*includeMSCompatOID*/,
const gssspnego_cred /*cred_handle*/,
MechTypeList */*mechtypelist*/,
@@ -271,12 +260,6 @@ _gss_spnego_seal (
gss_buffer_t output_message_buffer );
OM_uint32
-_gss_spnego_select_mech (
- OM_uint32 */*minor_status*/,
- MechType */*mechType*/,
- gss_OID */*mech_p*/);
-
-OM_uint32
_gss_spnego_set_sec_context_option (
OM_uint32 * /*minor_status*/,
gss_ctx_id_t * /*context_handle*/,
diff --git a/source4/heimdal/lib/gssapi/spnego/spnego.asn1 b/source4/heimdal/lib/gssapi/spnego/spnego.asn1
index 187ce0a0a6d..76fafa356c3 100644
--- a/source4/heimdal/lib/gssapi/spnego/spnego.asn1
+++ b/source4/heimdal/lib/gssapi/spnego/spnego.asn1
@@ -1,4 +1,4 @@
--- $Id: spnego.asn1,v 1.1.1.1 2006/06/28 08:34:45 lha Exp $
+-- $Id: spnego.asn1,v 1.3 2006/12/18 18:28:49 lha Exp $
SPNEGO DEFINITIONS ::=
BEGIN
@@ -22,14 +22,21 @@ NegHints ::= SEQUENCE {
hintAddress [1] OCTET STRING OPTIONAL
}
+NegTokenInitWin ::= SEQUENCE {
+ mechTypes [0] MechTypeList,
+ reqFlags [1] ContextFlags OPTIONAL,
+ mechToken [2] OCTET STRING OPTIONAL,
+ negHints [3] NegHints OPTIONAL
+ }
+
NegTokenInit ::= SEQUENCE {
mechTypes [0] MechTypeList,
reqFlags [1] ContextFlags OPTIONAL,
mechToken [2] OCTET STRING OPTIONAL,
- negHints [3] NegHints OPTIONAL,
- mechListMIC [4] OCTET STRING OPTIONAL
+ mechListMIC [3] OCTET STRING OPTIONAL
}
+
-- NB: negResult is not OPTIONAL in the new SPNEGO spec but
-- Windows clients do not always send it
NegTokenResp ::= SEQUENCE {
@@ -48,4 +55,8 @@ NegotiationToken ::= CHOICE {
negTokenResp[1] NegTokenResp
}
+NegotiationTokenWin ::= CHOICE {
+ negTokenInit[0] NegTokenInitWin
+}
+
END
diff --git a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h
index 255e07d0563..45dff04313b 100644
--- a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h
+++ b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h
@@ -30,7 +30,7 @@
* SUCH DAMAGE.
*/
-/* $Id: spnego_locl.h,v 1.12 2006/11/07 19:53:40 lha Exp $ */
+/* $Id: spnego_locl.h,v 1.15 2006/12/18 15:42:03 lha Exp $ */
#ifndef SPNEGO_LOCL_H
#define SPNEGO_LOCL_H
@@ -67,6 +67,7 @@
#include <gssapi_mech.h>
#include "spnego_asn1.h"
+#include "mech/utils.h"
#include <der.h>
#include <roken.h>
@@ -86,13 +87,29 @@ typedef struct {
OM_uint32 mech_time_rec;
gss_name_t mech_src_name;
gss_cred_id_t delegated_cred_id;
- int open : 1;
- int local : 1;
- int require_mic : 1;
- int verified_mic : 1;
+ unsigned int open : 1;
+ unsigned int local : 1;
+ unsigned int require_mic : 1;
+ unsigned int verified_mic : 1;
+ unsigned int maybe_open : 1;
HEIMDAL_MUTEX ctx_id_mutex;
+
+ gss_name_t target_name;
+
+ u_char oidbuf[17];
+ size_t oidlen;
+
} *gssspnego_ctx;
+typedef struct {
+ gss_OID_desc type;
+ gss_buffer_desc value;
+ gss_name_t mech;
+} *spnego_name;
+
+extern gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc;
+extern gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc;
+
#include <spnego/spnego-private.h>
#endif /* SPNEGO_LOCL_H */
diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c
index d1fa4ffd6a6..cd4f24a7321 100644
--- a/source4/heimdal/lib/hdb/hdb.c
+++ b/source4/heimdal/lib/hdb/hdb.c
@@ -33,7 +33,7 @@
#include "hdb_locl.h"
-RCSID("$Id: hdb.c,v 1.62 2006/10/06 16:47:22 lha Exp $");
+RCSID("$Id: hdb.c,v 1.64 2006/11/28 14:24:27 lha Exp $");
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h
index 69c91d12ad3..dcfceb58f07 100644
--- a/source4/heimdal/lib/hdb/hdb.h
+++ b/source4/heimdal/lib/hdb/hdb.h
@@ -60,24 +60,6 @@ typedef struct hdb_entry_ex {
void *ctx;
hdb_entry entry;
void (*free_entry)(krb5_context, struct hdb_entry_ex *);
- krb5_error_code (*check_client_access)(krb5_context, struct hdb_entry_ex *,
- HostAddresses *);
- krb5_error_code (*authz_data_as_req)(krb5_context,
- struct hdb_entry_ex *,
- METHOD_DATA* pa_data_seq,
- time_t authtime,
- const EncryptionKey *tgtkey,
- const EncryptionKey *sessionkey,
- AuthorizationData **out);
- krb5_error_code (*authz_data_tgs_req)(krb5_context,
- struct hdb_entry_ex *,
- krb5_principal client,
- AuthorizationData *in,
- time_t authtime,
- const EncryptionKey *tgtkey,
- const EncryptionKey *servicekey,
- const EncryptionKey *sessionkey,
- AuthorizationData **out);
} hdb_entry_ex;
diff --git a/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x
new file mode 100644
index 00000000000..e17bad6ed8f
--- /dev/null
+++ b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp.x
@@ -0,0 +1,22 @@
+/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/ocsp.asn1 */
+/* Do not edit */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <krb5-types.h>
+#include <ocsp_asn1.h>
+#include <asn1_err.h>
+#include <der.h>
+#include <parse_units.h>
+
+static unsigned oid_id_pkix_ocsp_variable_num[9] = {1, 3, 6, 1, 5, 5, 7, 48, 1 };
+static const heim_oid oid_id_pkix_ocsp_variable = { 9, oid_id_pkix_ocsp_variable_num };
+
+const heim_oid *oid_id_pkix_ocsp(void)
+{
+return &oid_id_pkix_ocsp_variable;
+}
+
diff --git a/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x
new file mode 100644
index 00000000000..6f030f1713e
--- /dev/null
+++ b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_basic.x
@@ -0,0 +1,22 @@
+/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/ocsp.asn1 */
+/* Do not edit */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <krb5-types.h>
+#include <ocsp_asn1.h>
+#include <asn1_err.h>
+#include <der.h>
+#include <parse_units.h>
+
+static unsigned oid_id_pkix_ocsp_basic_variable_num[10] = {1, 3, 6, 1, 5, 5, 7, 48, 1, 1 };
+static const heim_oid oid_id_pkix_ocsp_basic_variable = { 10, oid_id_pkix_ocsp_basic_variable_num };
+
+const heim_oid *oid_id_pkix_ocsp_basic(void)
+{
+return &oid_id_pkix_ocsp_basic_variable;
+}
+
diff --git a/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x
new file mode 100644
index 00000000000..36d7422a0dd
--- /dev/null
+++ b/source4/heimdal/lib/hx509/asn1_id_pkix_ocsp_nonce.x
@@ -0,0 +1,22 @@
+/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/ocsp.asn1 */
+/* Do not edit */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <krb5-types.h>
+#include <ocsp_asn1.h>
+#include <asn1_err.h>
+#include <der.h>
+#include <parse_units.h>
+
+static unsigned oid_id_pkix_ocsp_nonce_variable_num[10] = {1, 3, 6, 1, 5, 5, 7, 48, 1, 2 };
+static const heim_oid oid_id_pkix_ocsp_nonce_variable = { 10, oid_id_pkix_ocsp_nonce_variable_num };
+
+const heim_oid *oid_id_pkix_ocsp_nonce(void)
+{
+return &oid_id_pkix_ocsp_nonce_variable;
+}
+
diff --git a/source4/heimdal/lib/hx509/ca.c b/source4/heimdal/lib/hx509/ca.c
new file mode 100644
index 00000000000..1a5b4947be0
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ca.c
@@ -0,0 +1,893 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+#include <pkinit_asn1.h>
+RCSID("$Id: ca.c,v 1.12 2007/01/05 18:40:46 lha Exp $");
+
+struct hx509_ca_tbs {
+ hx509_name subject;
+ SubjectPublicKeyInfo spki;
+ ExtKeyUsage eku;
+ GeneralNames san;
+ unsigned key_usage;
+ heim_integer serial;
+ struct {
+ unsigned int proxy:1;
+ unsigned int ca:1;
+ unsigned int key:1;
+ unsigned int serial:1;
+ } flags;
+ time_t notBefore;
+ time_t notAfter;
+ int pathLenConstraint; /* both for CA and Proxy */
+};
+
+int
+hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
+{
+ *tbs = calloc(1, sizeof(**tbs));
+ if (*tbs == NULL)
+ return ENOMEM;
+
+ (*tbs)->subject = NULL;
+ (*tbs)->san.len = 0;
+ (*tbs)->san.val = NULL;
+ (*tbs)->eku.len = 0;
+ (*tbs)->eku.val = NULL;
+ (*tbs)->pathLenConstraint = 0;
+
+ return 0;
+}
+
+void
+hx509_ca_tbs_free(hx509_ca_tbs *tbs)
+{
+ if (tbs == NULL || *tbs == NULL)
+ return;
+
+ free_SubjectPublicKeyInfo(&(*tbs)->spki);
+ free_GeneralNames(&(*tbs)->san);
+ free_ExtKeyUsage(&(*tbs)->eku);
+ der_free_heim_integer(&(*tbs)->serial);
+
+ hx509_name_free(&(*tbs)->subject);
+
+ memset(*tbs, 0, sizeof(**tbs));
+ free(*tbs);
+ *tbs = NULL;
+}
+
+int
+hx509_ca_tbs_set_notBefore(hx509_context context,
+ hx509_ca_tbs tbs,
+ time_t t)
+{
+ tbs->notBefore = t;
+ return 0;
+}
+
+int
+hx509_ca_tbs_set_notAfter(hx509_context context,
+ hx509_ca_tbs tbs,
+ time_t t)
+{
+ tbs->notAfter = t;
+ return 0;
+}
+
+int
+hx509_ca_tbs_set_notAfter_lifetime(hx509_context context,
+ hx509_ca_tbs tbs,
+ time_t delta)
+{
+ return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta);
+}
+
+int
+hx509_ca_tbs_set_ca(hx509_context context,
+ hx509_ca_tbs tbs,
+ int pathLenConstraint)
+{
+ tbs->flags.ca = 1;
+ tbs->pathLenConstraint = pathLenConstraint;
+ return 0;
+}
+
+int
+hx509_ca_tbs_set_proxy(hx509_context context,
+ hx509_ca_tbs tbs,
+ int pathLenConstraint)
+{
+ tbs->flags.proxy = 1;
+ tbs->pathLenConstraint = pathLenConstraint;
+ return 0;
+}
+
+
+int
+hx509_ca_tbs_set_spki(hx509_context context,
+ hx509_ca_tbs tbs,
+ const SubjectPublicKeyInfo *spki)
+{
+ int ret;
+ free_SubjectPublicKeyInfo(&tbs->spki);
+ ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki);
+ tbs->flags.key = !ret;
+ return ret;
+}
+
+int
+hx509_ca_tbs_set_serialnumber(hx509_context context,
+ hx509_ca_tbs tbs,
+ const heim_integer *serialNumber)
+{
+ int ret;
+ der_free_heim_integer(&tbs->serial);
+ ret = der_copy_heim_integer(serialNumber, &tbs->serial);
+ tbs->flags.serial = !ret;
+ return ret;
+}
+
+int
+hx509_ca_tbs_add_eku(hx509_context contex,
+ hx509_ca_tbs tbs,
+ const heim_oid *oid)
+{
+ void *ptr;
+ int ret;
+
+ ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1));
+ if (ptr == NULL)
+ return ENOMEM;
+ tbs->eku.val = ptr;
+ ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]);
+ if (ret)
+ return ret;
+ tbs->eku.len += 1;
+ return 0;
+}
+
+int
+hx509_ca_tbs_add_san_otherName(hx509_context context,
+ hx509_ca_tbs tbs,
+ const heim_oid *oid,
+ const heim_octet_string *os)
+{
+ GeneralName gn;
+
+ memset(&gn, 0, sizeof(gn));
+ gn.element = choice_GeneralName_otherName;
+ gn.u.otherName.type_id = *oid;
+ gn.u.otherName.value = *os;
+
+ return add_GeneralNames(&tbs->san, &gn);
+}
+
+
+int
+hx509_ca_tbs_add_san_pkinit(hx509_context context,
+ hx509_ca_tbs tbs,
+ const char *principal)
+{
+ heim_octet_string os;
+ KRB5PrincipalName p;
+ size_t size;
+ int ret;
+ char *s = NULL;
+
+ memset(&p, 0, sizeof(p));
+
+ /* parse principal */
+ {
+ const char *str;
+ char *q;
+ int n;
+
+ /* count number of component */
+ n = 1;
+ for(str = principal; *str != '\0' && *str != '@'; str++){
+ if(*str=='\\'){
+ if(str[1] == '\0' || str[1] == '@') {
+ ret = HX509_PARSING_NAME_FAILED;
+ hx509_set_error_string(context, 0, ret,
+ "trailing \\ in principal name");
+ goto out;
+ }
+ str++;
+ } else if(*str == '/')
+ n++;
+ }
+ p.principalName.name_string.val =
+ calloc(n, sizeof(*p.principalName.name_string.val));
+ if (p.principalName.name_string.val == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "malloc: out of memory");
+ goto out;
+ }
+ p.principalName.name_string.len = n;
+
+ p.principalName.name_type = KRB5_NT_PRINCIPAL;
+ q = s = strdup(principal);
+ if (q == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "malloc: out of memory");
+ goto out;
+ }
+ p.realm = strrchr(q, '@');
+ if (p.realm == NULL) {
+ ret = HX509_PARSING_NAME_FAILED;
+ hx509_set_error_string(context, 0, ret, "Missing @ in principal");
+ goto out;
+ };
+ *p.realm++ = '\0';
+
+ n = 0;
+ while (q) {
+ p.principalName.name_string.val[n++] = q;
+ q = strchr(q, '/');
+ if (q)
+ *q++ = '\0';
+ }
+ }
+
+ ASN1_MALLOC_ENCODE(KRB5PrincipalName, os.data, os.length, &p, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != os.length)
+ _hx509_abort("internal ASN.1 encoder error");
+
+ ret = hx509_ca_tbs_add_san_otherName(context,
+ tbs,
+ oid_id_pkinit_san(),
+ &os);
+ free(os.data);
+out:
+ if (p.principalName.name_string.val)
+ free (p.principalName.name_string.val);
+ if (s)
+ free(s);
+ return ret;
+}
+
+int
+hx509_ca_tbs_add_san_hostname(hx509_context context,
+ hx509_ca_tbs tbs,
+ const char *dnsname)
+{
+ GeneralName gn;
+
+ memset(&gn, 0, sizeof(gn));
+ gn.element = choice_GeneralName_dNSName;
+ gn.u.dNSName = rk_UNCONST(dnsname);
+
+ return add_GeneralNames(&tbs->san, &gn);
+}
+
+int
+hx509_ca_tbs_add_san_rfc822name(hx509_context context,
+ hx509_ca_tbs tbs,
+ const char *rfc822Name)
+{
+ GeneralName gn;
+
+ memset(&gn, 0, sizeof(gn));
+ gn.element = choice_GeneralName_rfc822Name;
+ gn.u.rfc822Name = rk_UNCONST(rfc822Name);
+
+ return add_GeneralNames(&tbs->san, &gn);
+}
+
+
+int
+hx509_ca_tbs_set_subject(hx509_context context,
+ hx509_ca_tbs tbs,
+ hx509_name subject)
+{
+ if (tbs->subject)
+ hx509_name_free(&tbs->subject);
+ return hx509_name_copy(context, subject, &tbs->subject);
+}
+
+static int
+add_extension(hx509_context context,
+ TBSCertificate *tbsc,
+ int critical_flag,
+ const heim_oid *oid,
+ const heim_octet_string *data)
+{
+ Extension ext;
+ int ret;
+
+ memset(&ext, 0, sizeof(ext));
+
+ if (critical_flag) {
+ ext.critical = malloc(sizeof(*ext.critical));
+ if (ext.critical == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ *ext.critical = TRUE;
+ }
+
+ ret = der_copy_oid(oid, &ext.extnID);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ ret = der_copy_octet_string(data, &ext.extnValue);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ ret = add_Extensions(tbsc->extensions, &ext);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+out:
+ free_Extension(&ext);
+ return ret;
+}
+
+static int
+build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject)
+{
+ char *tstr;
+ time_t t;
+ int ret;
+
+ ret = copy_Name(issuer, subject);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret,
+ "Failed to copy subject name");
+ return ret;
+ }
+
+ t = time(NULL);
+ asprintf(&tstr, "ts-%lu", (unsigned long)t);
+ if (tstr == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM,
+ "Failed to copy subject name");
+ return ENOMEM;
+ }
+ /* prefix with CN=<ts>,...*/
+ ret = _hx509_name_modify(context, subject, 1, oid_id_at_commonName(), tstr);
+ free(tstr);
+ if (ret)
+ free_Name(subject);
+ return ret;
+}
+
+static int
+ca_sign(hx509_context context,
+ hx509_ca_tbs tbs,
+ hx509_private_key signer,
+ const AuthorityKeyIdentifier *ai,
+ const Name *issuername,
+ hx509_cert *certificate)
+{
+ heim_octet_string data;
+ Certificate c;
+ TBSCertificate *tbsc;
+ size_t size;
+ int ret;
+ const AlgorithmIdentifier *sigalg;
+ time_t notBefore;
+ time_t notAfter;
+ unsigned key_usage;
+
+ sigalg = hx509_signature_rsa_with_sha1();
+
+ memset(&c, 0, sizeof(c));
+
+ /*
+ * Default values are: Valid since 24h ago, valid one year into
+ * the future, KeyUsage digitalSignature and keyEncipherment set,
+ * and keyCertSign for CA certificates.
+ */
+ notBefore = tbs->notBefore;
+ if (notBefore == 0)
+ notBefore = time(NULL) - 3600 * 24;
+ notAfter = tbs->notAfter;
+ if (notAfter == 0)
+ notAfter = time(NULL) + 3600 * 24 * 365;
+
+ key_usage = tbs->key_usage;
+ if (key_usage == 0) {
+ KeyUsage ku;
+ memset(&ku, 0, sizeof(ku));
+ ku.digitalSignature = 1;
+ ku.keyEncipherment = 1;
+ key_usage = KeyUsage2int(ku);
+ }
+
+ if (tbs->flags.ca) {
+ KeyUsage ku;
+ memset(&ku, 0, sizeof(ku));
+ ku.keyCertSign = 1;
+ key_usage |= KeyUsage2int(ku);
+ }
+
+ /*
+ *
+ */
+
+ tbsc = &c.tbsCertificate;
+
+ if (tbs->flags.key == 0) {
+ ret = EINVAL;
+ hx509_set_error_string(context, 0, ret, "No public key set");
+ return ret;
+ }
+ if (tbs->subject == NULL && !tbs->flags.proxy) {
+ ret = EINVAL;
+ hx509_set_error_string(context, 0, ret, "No subject name set");
+ return ret;
+ }
+ if (tbs->flags.ca && tbs->flags.proxy) {
+ ret = EINVAL;
+ hx509_set_error_string(context, 0, ret, "Can't be proxy and CA "
+ "at the same time");
+ return ret;
+ }
+ if (tbs->flags.proxy) {
+ if (tbs->san.len > 0) {
+ hx509_set_error_string(context, 0, EINVAL,
+ "Proxy certificate is not allowed "
+ "to have SubjectAltNames");
+ return EINVAL;
+ }
+ }
+
+ /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */
+ tbsc->version = calloc(1, sizeof(*tbsc->version));
+ if (tbsc->version == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ *tbsc->version = rfc3280_version_3;
+ /* serialNumber CertificateSerialNumber, */
+ if (tbs->flags.serial) {
+ ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ } else {
+ tbsc->serialNumber.length = 20;
+ tbsc->serialNumber.data = malloc(tbsc->serialNumber.length);
+ if (tbsc->serialNumber.data == NULL){
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ /* XXX diffrent */
+ RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length);
+ ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f;
+ }
+ /* signature AlgorithmIdentifier, */
+ ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Failed to copy sigature alg");
+ goto out;
+ }
+ /* issuer Name, */
+ if (issuername)
+ ret = copy_Name(issuername, &tbsc->issuer);
+ else
+ ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Failed to copy issuer name");
+ goto out;
+ }
+ /* validity Validity, */
+ tbsc->validity.notBefore.element = choice_Time_generalTime;
+ tbsc->validity.notBefore.u.generalTime = notBefore;
+ tbsc->validity.notAfter.element = choice_Time_generalTime;
+ tbsc->validity.notAfter.u.generalTime = notAfter;
+ /* subject Name, */
+ if (tbs->flags.proxy) {
+ ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject);
+ if (ret)
+ goto out;
+ } else {
+ ret = hx509_name_to_Name(tbs->subject, &tbsc->subject);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret,
+ "Failed to copy subject name");
+ goto out;
+ }
+ }
+ /* subjectPublicKeyInfo SubjectPublicKeyInfo, */
+ ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Failed to copy spki");
+ goto out;
+ }
+ /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */
+ /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */
+ /* extensions [3] EXPLICIT Extensions OPTIONAL */
+ tbsc->extensions = calloc(1, sizeof(*tbsc->extensions));
+ if (tbsc->extensions == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+
+ /* add KeyUsage */
+ {
+ KeyUsage ku;
+
+ ku = int2KeyUsage(key_usage);
+ ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != data.length)
+ _hx509_abort("internal ASN.1 encoder error");
+ ret = add_extension(context, tbsc, 1,
+ oid_id_x509_ce_keyUsage(), &data);
+ free(data.data);
+ if (ret)
+ goto out;
+ }
+
+ /* add ExtendedKeyUsage */
+ if (tbs->eku.len > 0) {
+ ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
+ &tbs->eku, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != data.length)
+ _hx509_abort("internal ASN.1 encoder error");
+ ret = add_extension(context, tbsc, 0,
+ oid_id_x509_ce_extKeyUsage(), &data);
+ free(data.data);
+ if (ret)
+ goto out;
+ }
+
+ /* add Subject Alternative Name */
+ if (tbs->san.len > 0) {
+ ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
+ &tbs->san, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != data.length)
+ _hx509_abort("internal ASN.1 encoder error");
+ ret = add_extension(context, tbsc, 0,
+ oid_id_x509_ce_subjectAltName(),
+ &data);
+ free(data.data);
+ if (ret)
+ goto out;
+ }
+
+ /* Add Authority Key Identifier */
+ if (ai) {
+ ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length,
+ ai, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != data.length)
+ _hx509_abort("internal ASN.1 encoder error");
+ ret = add_extension(context, tbsc, 0,
+ oid_id_x509_ce_authorityKeyIdentifier(),
+ &data);
+ free(data.data);
+ if (ret)
+ goto out;
+ }
+
+ /* Add Subject Key Identifier */
+ {
+ SubjectKeyIdentifier si;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ {
+ SHA_CTX m;
+
+ SHA1_Init(&m);
+ SHA1_Update(&m, tbs->spki.subjectPublicKey.data,
+ tbs->spki.subjectPublicKey.length / 8);
+ SHA1_Final (hash, &m);
+ }
+
+ si.data = hash;
+ si.length = sizeof(hash);
+
+ ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length,
+ &si, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != data.length)
+ _hx509_abort("internal ASN.1 encoder error");
+ ret = add_extension(context, tbsc, 0,
+ oid_id_x509_ce_subjectKeyIdentifier(),
+ &data);
+ free(data.data);
+ if (ret)
+ goto out;
+ }
+
+ /* Add BasicConstraints */
+ {
+ BasicConstraints bc;
+ int aCA = 1;
+ uint32_t path;
+
+ memset(&bc, 0, sizeof(bc));
+
+ if (tbs->flags.ca) {
+ bc.cA = &aCA;
+ if (tbs->pathLenConstraint >= 0) {
+ path = tbs->pathLenConstraint;
+ bc.pathLenConstraint = &path;
+ }
+ }
+
+ ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length,
+ &bc, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != data.length)
+ _hx509_abort("internal ASN.1 encoder error");
+ ret = add_extension(context, tbsc, 0,
+ oid_id_x509_ce_basicConstraints(),
+ &data);
+ free(data.data);
+ if (ret)
+ goto out;
+ }
+
+ /* add Proxy */
+ if (tbs->flags.proxy) {
+ ProxyCertInfo info;
+
+ memset(&info, 0, sizeof(info));
+
+ if (tbs->pathLenConstraint >= 0) {
+ info.pCPathLenConstraint =
+ malloc(sizeof(*info.pCPathLenConstraint));
+ if (info.pCPathLenConstraint == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ *info.pCPathLenConstraint = tbs->pathLenConstraint;
+ }
+
+ ret = der_copy_oid(oid_id_pkix_ppl_inheritAll(),
+ &info.proxyPolicy.policyLanguage);
+ if (ret) {
+ free_ProxyCertInfo(&info);
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+
+ ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length,
+ &info, &size, ret);
+ free_ProxyCertInfo(&info);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ if (size != data.length)
+ _hx509_abort("internal ASN.1 encoder error");
+ ret = add_extension(context, tbsc, 0,
+ oid_id_pe_proxyCertInfo(),
+ &data);
+ free(data.data);
+ if (ret)
+ goto out;
+ }
+
+
+ ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "malloc out of memory");
+ goto out;
+ }
+ if (data.length != size)
+ _hx509_abort("internal ASN.1 encoder error");
+
+ ret = _hx509_create_signature_bitstring(context,
+ signer,
+ sigalg,
+ &data,
+ &c.signatureAlgorithm,
+ &c.signatureValue);
+ free(data.data);
+ if (ret)
+ goto out;
+
+ ret = hx509_cert_init(context, &c, certificate);
+ if (ret)
+ goto out;
+
+ free_Certificate(&c);
+
+ return 0;
+
+out:
+ free_Certificate(&c);
+ return ret;
+}
+
+static int
+get_AuthorityKeyIdentifier(hx509_context context,
+ const Certificate *certificate,
+ AuthorityKeyIdentifier *ai)
+{
+ SubjectKeyIdentifier si;
+ int ret;
+
+ ret = _hx509_find_extension_subject_key_id(certificate, &si);
+ if (ret == 0) {
+ ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier));
+ if (ai->keyIdentifier == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ ret = der_copy_octet_string(&si, ai->keyIdentifier);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ } else {
+ GeneralNames gns;
+ GeneralName gn;
+ Name name;
+
+ memset(&gn, 0, sizeof(gn));
+ memset(&gns, 0, sizeof(gns));
+ memset(&name, 0, sizeof(name));
+
+ ai->authorityCertIssuer =
+ calloc(1, sizeof(*ai->authorityCertIssuer));
+ if (ai->authorityCertIssuer == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ ai->authorityCertSerialNumber =
+ calloc(1, sizeof(*ai->authorityCertSerialNumber));
+ if (ai->authorityCertSerialNumber == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+
+ /*
+ * XXX unbreak when asn1 compiler handle IMPLICIT
+ *
+ * This is so horrible.
+ */
+
+ ret = copy_Name(&certificate->tbsCertificate.subject, &name);
+ if (ai->authorityCertSerialNumber == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+
+ gn.element = choice_GeneralName_directoryName;
+ gn.u.directoryName.element =
+ choice_GeneralName_directoryName_rdnSequence;
+ gn.u.directoryName.u.rdnSequence = name.u.rdnSequence;
+
+ ret = add_GeneralNames(&gns, &gn);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+
+ ai->authorityCertIssuer->val = gns.val;
+ ai->authorityCertIssuer->len = gns.len;
+
+ ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber,
+ ai->authorityCertSerialNumber);
+ if (ai->authorityCertSerialNumber == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "Out of memory");
+ goto out;
+ }
+ }
+out:
+ if (ret)
+ free_AuthorityKeyIdentifier(ai);
+ return ret;
+}
+
+
+int
+hx509_ca_sign(hx509_context context,
+ hx509_ca_tbs tbs,
+ hx509_cert signer,
+ hx509_cert *certificate)
+{
+ const Certificate *signer_cert;
+ AuthorityKeyIdentifier ai;
+ int ret;
+
+ memset(&ai, 0, sizeof(ai));
+
+ signer_cert = _hx509_get_cert(signer);
+
+ ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai);
+ if (ret)
+ goto out;
+
+ ret = ca_sign(context,
+ tbs,
+ _hx509_cert_private_key(signer),
+ &ai,
+ &signer_cert->tbsCertificate.subject,
+ certificate);
+
+out:
+ free_AuthorityKeyIdentifier(&ai);
+
+ return ret;
+}
+
+int
+hx509_ca_sign_self(hx509_context context,
+ hx509_ca_tbs tbs,
+ hx509_private_key signer,
+ hx509_cert *certificate)
+{
+ return ca_sign(context,
+ tbs,
+ signer,
+ NULL,
+ NULL,
+ certificate);
+}
diff --git a/source4/heimdal/lib/hx509/cert.c b/source4/heimdal/lib/hx509/cert.c
new file mode 100644
index 00000000000..f84c61a7982
--- /dev/null
+++ b/source4/heimdal/lib/hx509/cert.c
@@ -0,0 +1,2214 @@
+/*
+ * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: cert.c,v 1.82 2007/01/09 10:52:03 lha Exp $");
+#include "crypto-headers.h"
+
+struct hx509_verify_ctx_data {
+ hx509_certs trust_anchors;
+ int flags;
+#define HX509_VERIFY_CTX_F_TIME_SET 1
+#define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
+#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
+#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
+ time_t time_now;
+ unsigned int max_depth;
+#define HX509_VERIFY_MAX_DEPTH 30
+ hx509_revoke_ctx revoke_ctx;
+};
+
+#define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
+#define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
+
+struct _hx509_cert_attrs {
+ size_t len;
+ hx509_cert_attribute *val;
+};
+
+struct hx509_cert_data {
+ unsigned int ref;
+ char *friendlyname;
+ Certificate *data;
+ hx509_private_key private_key;
+ struct _hx509_cert_attrs attrs;
+ hx509_name basename;
+ _hx509_cert_release_func release;
+ void *ctx;
+};
+
+typedef struct hx509_name_constraints {
+ NameConstraints *val;
+ size_t len;
+} hx509_name_constraints;
+
+#define GeneralSubtrees_SET(g,var) \
+ (g)->len = (var)->len, (g)->val = (var)->val;
+
+/*
+ *
+ */
+
+void
+_hx509_abort(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+ fflush(stdout);
+ abort();
+}
+
+/*
+ *
+ */
+
+int
+hx509_context_init(hx509_context *context)
+{
+ *context = calloc(1, sizeof(**context));
+ if (*context == NULL)
+ return ENOMEM;
+
+ _hx509_ks_mem_register(*context);
+ _hx509_ks_file_register(*context);
+ _hx509_ks_pkcs12_register(*context);
+ _hx509_ks_pkcs11_register(*context);
+ _hx509_ks_dir_register(*context);
+
+ ENGINE_add_conf_module();
+ OpenSSL_add_all_algorithms();
+
+ (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
+
+ initialize_hx_error_table_r(&(*context)->et_list);
+ initialize_asn1_error_table_r(&(*context)->et_list);
+
+ return 0;
+}
+
+void
+hx509_context_set_missing_revoke(hx509_context context, int flag)
+{
+ if (flag)
+ context->flags |= HX509_CTX_VERIFY_MISSING_OK;
+ else
+ context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
+}
+
+void
+hx509_context_free(hx509_context *context)
+{
+ hx509_clear_error_string(*context);
+ if ((*context)->ks_ops) {
+ free((*context)->ks_ops);
+ (*context)->ks_ops = NULL;
+ }
+ (*context)->ks_num_ops = 0;
+ free_error_table ((*context)->et_list);
+ free(*context);
+ *context = NULL;
+}
+
+
+/*
+ *
+ */
+
+Certificate *
+_hx509_get_cert(hx509_cert cert)
+{
+ return cert->data;
+}
+
+/*
+ *
+ */
+
+#if 0
+void
+_hx509_print_cert_subject(hx509_cert cert)
+{
+ char *subject_name;
+ hx509_name name;
+ int ret;
+
+ ret = hx509_cert_get_subject(cert, &name);
+ if (ret)
+ abort();
+
+ ret = hx509_name_to_string(name, &subject_name);
+ hx509_name_free(&name);
+ if (ret)
+ abort();
+
+ printf("name: %s\n", subject_name);
+
+ free(subject_name);
+}
+#endif
+
+/*
+ *
+ */
+
+int
+_hx509_cert_get_version(const Certificate *t)
+{
+ return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
+}
+
+int
+hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
+{
+ int ret;
+
+ *cert = malloc(sizeof(**cert));
+ if (*cert == NULL)
+ return ENOMEM;
+ (*cert)->ref = 1;
+ (*cert)->friendlyname = NULL;
+ (*cert)->attrs.len = 0;
+ (*cert)->attrs.val = NULL;
+ (*cert)->private_key = NULL;
+ (*cert)->basename = NULL;
+ (*cert)->release = NULL;
+ (*cert)->ctx = NULL;
+
+ (*cert)->data = calloc(1, sizeof(*(*cert)->data));
+ if ((*cert)->data == NULL) {
+ free(*cert);
+ return ENOMEM;
+ }
+ ret = copy_Certificate(c, (*cert)->data);
+ if (ret) {
+ free((*cert)->data);
+ free(*cert);
+ }
+ return ret;
+}
+
+void
+_hx509_cert_set_release(hx509_cert cert,
+ _hx509_cert_release_func release,
+ void *ctx)
+{
+ cert->release = release;
+ cert->ctx = ctx;
+}
+
+
+/* Doesn't make a copy of `private_key'. */
+
+int
+_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
+{
+ if (cert->private_key)
+ _hx509_private_key_free(&cert->private_key);
+ cert->private_key = _hx509_private_key_ref(private_key);
+ return 0;
+}
+
+void
+hx509_cert_free(hx509_cert cert)
+{
+ int i;
+
+ if (cert == NULL)
+ return;
+
+ if (cert->ref <= 0)
+ _hx509_abort("refcount <= 0");
+ if (--cert->ref > 0)
+ return;
+
+ if (cert->release)
+ (cert->release)(cert, cert->ctx);
+
+ if (cert->private_key)
+ _hx509_private_key_free(&cert->private_key);
+
+ free_Certificate(cert->data);
+ free(cert->data);
+
+ for (i = 0; i < cert->attrs.len; i++) {
+ der_free_octet_string(&cert->attrs.val[i]->data);
+ der_free_oid(&cert->attrs.val[i]->oid);
+ free(cert->attrs.val[i]);
+ }
+ free(cert->attrs.val);
+ free(cert->friendlyname);
+ if (cert->basename)
+ hx509_name_free(&cert->basename);
+ memset(cert, 0, sizeof(cert));
+ free(cert);
+}
+
+hx509_cert
+hx509_cert_ref(hx509_cert cert)
+{
+ if (cert->ref <= 0)
+ _hx509_abort("refcount <= 0");
+ cert->ref++;
+ if (cert->ref == 0)
+ _hx509_abort("refcount == 0");
+ return cert;
+}
+
+int
+hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
+{
+ hx509_verify_ctx c;
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL)
+ return ENOMEM;
+
+ c->max_depth = HX509_VERIFY_MAX_DEPTH;
+
+ *ctx = c;
+
+ return 0;
+}
+
+void
+hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
+{
+ if (ctx)
+ memset(ctx, 0, sizeof(*ctx));
+ free(ctx);
+}
+
+void
+hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
+{
+ ctx->trust_anchors = set;
+}
+
+void
+hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
+{
+ ctx->revoke_ctx = revoke_ctx;
+}
+
+void
+hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
+{
+ ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
+ ctx->time_now = t;
+}
+
+void
+hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
+{
+ if (boolean)
+ ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
+ else
+ ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
+}
+
+void
+hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
+{
+ if (boolean)
+ ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
+ else
+ ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
+}
+
+static const Extension *
+find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
+{
+ const TBSCertificate *c = &cert->tbsCertificate;
+
+ if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
+ return NULL;
+
+ for (;*idx < c->extensions->len; (*idx)++) {
+ if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
+ return &c->extensions->val[(*idx)++];
+ }
+ return NULL;
+}
+
+static int
+find_extension_auth_key_id(const Certificate *subject,
+ AuthorityKeyIdentifier *ai)
+{
+ const Extension *e;
+ size_t size;
+ int i = 0;
+
+ memset(ai, 0, sizeof(*ai));
+
+ e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i);
+ if (e == NULL)
+ return HX509_EXTENSION_NOT_FOUND;
+
+ return decode_AuthorityKeyIdentifier(e->extnValue.data,
+ e->extnValue.length,
+ ai, &size);
+}
+
+int
+_hx509_find_extension_subject_key_id(const Certificate *issuer,
+ SubjectKeyIdentifier *si)
+{
+ const Extension *e;
+ size_t size;
+ int i = 0;
+
+ memset(si, 0, sizeof(*si));
+
+ e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i);
+ if (e == NULL)
+ return HX509_EXTENSION_NOT_FOUND;
+
+ return decode_SubjectKeyIdentifier(e->extnValue.data,
+ e->extnValue.length,
+ si, &size);
+}
+
+static int
+find_extension_name_constraints(const Certificate *subject,
+ NameConstraints *nc)
+{
+ const Extension *e;
+ size_t size;
+ int i = 0;
+
+ memset(nc, 0, sizeof(*nc));
+
+ e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i);
+ if (e == NULL)
+ return HX509_EXTENSION_NOT_FOUND;
+
+ return decode_NameConstraints(e->extnValue.data,
+ e->extnValue.length,
+ nc, &size);
+}
+
+static int
+find_extension_subject_alt_name(const Certificate *cert, int *i,
+ GeneralNames *sa)
+{
+ const Extension *e;
+ size_t size;
+
+ memset(sa, 0, sizeof(*sa));
+
+ e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i);
+ if (e == NULL)
+ return HX509_EXTENSION_NOT_FOUND;
+
+ return decode_GeneralNames(e->extnValue.data,
+ e->extnValue.length,
+ sa, &size);
+}
+
+static int
+find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
+{
+ const Extension *e;
+ size_t size;
+ int i = 0;
+
+ memset(eku, 0, sizeof(*eku));
+
+ e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i);
+ if (e == NULL)
+ return HX509_EXTENSION_NOT_FOUND;
+
+ return decode_ExtKeyUsage(e->extnValue.data,
+ e->extnValue.length,
+ eku, &size);
+}
+
+static int
+add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
+{
+ void *p;
+ int ret;
+
+ p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
+ if (p == NULL)
+ return ENOMEM;
+ list->val = p;
+ ret = der_copy_octet_string(entry, &list->val[list->len]);
+ if (ret)
+ return ret;
+ list->len++;
+ return 0;
+}
+
+void
+hx509_free_octet_string_list(hx509_octet_string_list *list)
+{
+ int i;
+ for (i = 0; i < list->len; i++)
+ der_free_octet_string(&list->val[i]);
+ free(list->val);
+ list->val = NULL;
+ list->len = 0;
+}
+
+int
+hx509_cert_find_subjectAltName_otherName(hx509_cert cert,
+ const heim_oid *oid,
+ hx509_octet_string_list *list)
+{
+ GeneralNames sa;
+ int ret, i, j;
+
+ list->val = NULL;
+ list->len = 0;
+
+ i = 0;
+ while (1) {
+ ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
+ i++;
+ if (ret == HX509_EXTENSION_NOT_FOUND) {
+ ret = 0;
+ break;
+ } else if (ret != 0)
+ break;
+
+
+ for (j = 0; j < sa.len; j++) {
+ if (sa.val[j].element == choice_GeneralName_otherName &&
+ der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
+ {
+ ret = add_to_list(list, &sa.val[j].u.otherName.value);
+ if (ret) {
+ free_GeneralNames(&sa);
+ return ret;
+ }
+ }
+ }
+ free_GeneralNames(&sa);
+ }
+ return ret;
+}
+
+
+static int
+check_key_usage(hx509_context context, const Certificate *cert,
+ unsigned flags, int req_present)
+{
+ const Extension *e;
+ KeyUsage ku;
+ size_t size;
+ int ret, i = 0;
+ unsigned ku_flags;
+
+ if (_hx509_cert_get_version(cert) < 3)
+ return 0;
+
+ e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
+ if (e == NULL) {
+ if (req_present) {
+ hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
+ "Required extension key "
+ "usage missing from certifiate");
+ return HX509_KU_CERT_MISSING;
+ }
+ return 0;
+ }
+
+ ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
+ if (ret)
+ return ret;
+ ku_flags = KeyUsage2int(ku);
+ if ((ku_flags & flags) != flags) {
+ unsigned missing = (~ku_flags) & flags;
+ char buf[256], *name;
+
+ unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
+ _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
+ hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
+ "Key usage %s required but missing "
+ "from certifiate %s", buf, name);
+ free(name);
+ return HX509_KU_CERT_MISSING;
+ }
+ return 0;
+}
+
+int
+_hx509_check_key_usage(hx509_context context, hx509_cert cert,
+ unsigned flags, int req_present)
+{
+ return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
+}
+
+enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
+
+static int
+check_basic_constraints(hx509_context context, const Certificate *cert,
+ enum certtype type, int depth)
+{
+ BasicConstraints bc;
+ const Extension *e;
+ size_t size;
+ int ret, i = 0;
+
+ if (_hx509_cert_get_version(cert) < 3)
+ return 0;
+
+ e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i);
+ if (e == NULL) {
+ switch(type) {
+ case PROXY_CERT:
+ case EE_CERT:
+ return 0;
+ case CA_CERT: {
+ char *name;
+ ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
+ assert(ret == 0);
+ hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
+ "basicConstraints missing from "
+ "CA certifiacte %s", name);
+ free(name);
+ return HX509_EXTENSION_NOT_FOUND;
+ }
+ }
+ }
+
+ ret = decode_BasicConstraints(e->extnValue.data,
+ e->extnValue.length, &bc,
+ &size);
+ if (ret)
+ return ret;
+ switch(type) {
+ case PROXY_CERT:
+ if (bc.cA != NULL && *bc.cA)
+ ret = HX509_PARENT_IS_CA;
+ break;
+ case EE_CERT:
+ ret = 0;
+ break;
+ case CA_CERT:
+ if (bc.cA == NULL || !*bc.cA)
+ ret = HX509_PARENT_NOT_CA;
+ else if (bc.pathLenConstraint)
+ if (depth - 1 > *bc.pathLenConstraint)
+ ret = HX509_CA_PATH_TOO_DEEP;
+ break;
+ }
+ free_BasicConstraints(&bc);
+ return ret;
+}
+
+int
+_hx509_cert_is_parent_cmp(const Certificate *subject,
+ const Certificate *issuer,
+ int allow_self_signed)
+{
+ int diff;
+ AuthorityKeyIdentifier ai;
+ SubjectKeyIdentifier si;
+ int ret_ai, ret_si;
+
+ diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
+ &subject->tbsCertificate.issuer);
+ if (diff)
+ return diff;
+
+ memset(&ai, 0, sizeof(ai));
+ memset(&si, 0, sizeof(si));
+
+ /*
+ * Try to find AuthorityKeyIdentifier, if its not present in the
+ * subject certificate nor the parent.
+ */
+
+ ret_ai = find_extension_auth_key_id(subject, &ai);
+ if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
+ return 1;
+ ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
+ if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
+ return -1;
+
+ if (ret_si && ret_ai)
+ goto out;
+ if (ret_ai)
+ goto out;
+ if (ret_si) {
+ if (allow_self_signed) {
+ diff = 0;
+ goto out;
+ } else if (ai.keyIdentifier) {
+ diff = -1;
+ goto out;
+ }
+ }
+
+ if (ai.keyIdentifier == NULL) {
+ Name name;
+
+ if (ai.authorityCertIssuer == NULL)
+ return -1;
+ if (ai.authorityCertSerialNumber == NULL)
+ return -1;
+
+ diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
+ &issuer->tbsCertificate.serialNumber);
+ if (diff)
+ return diff;
+ if (ai.authorityCertIssuer->len != 1)
+ return -1;
+ if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
+ return -1;
+
+ name.element =
+ ai.authorityCertIssuer->val[0].u.directoryName.element;
+ name.u.rdnSequence =
+ ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
+
+ diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
+ &name);
+ if (diff)
+ return diff;
+ diff = 0;
+ } else
+ diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
+ if (diff)
+ goto out;
+
+ out:
+ free_AuthorityKeyIdentifier(&ai);
+ free_SubjectKeyIdentifier(&si);
+ return diff;
+}
+
+static int
+certificate_is_anchor(hx509_context context,
+ hx509_certs trust_anchors,
+ const hx509_cert cert)
+{
+ hx509_query q;
+ hx509_cert c;
+ int ret;
+
+ if (trust_anchors == NULL)
+ return 0;
+
+ _hx509_query_clear(&q);
+
+ q.match = HX509_QUERY_MATCH_CERTIFICATE;
+ q.certificate = _hx509_get_cert(cert);
+
+ ret = hx509_certs_find(context, trust_anchors, &q, &c);
+ if (ret == 0)
+ hx509_cert_free(c);
+ return ret == 0;
+}
+
+static int
+certificate_is_self_signed(const Certificate *cert)
+{
+ return _hx509_cert_is_parent_cmp(cert, cert, 1) == 0;
+}
+
+/*
+ * The subjectName is "null" when its empty set of relative DBs.
+ */
+
+static int
+subject_null_p(const Certificate *c)
+{
+ return c->tbsCertificate.subject.u.rdnSequence.len == 0;
+}
+
+
+static int
+find_parent(hx509_context context,
+ time_t time_now,
+ hx509_certs trust_anchors,
+ hx509_path *path,
+ hx509_certs pool,
+ hx509_cert current,
+ hx509_cert *parent)
+{
+ AuthorityKeyIdentifier ai;
+ hx509_query q;
+ int ret;
+
+ *parent = NULL;
+ memset(&ai, 0, sizeof(ai));
+
+ _hx509_query_clear(&q);
+
+ if (!subject_null_p(current->data)) {
+ q.match |= HX509_QUERY_FIND_ISSUER_CERT;
+ q.subject = _hx509_get_cert(current);
+ } else {
+ ret = find_extension_auth_key_id(current->data, &ai);
+ if (ret) {
+ hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
+ "Subjectless certificate missing AuthKeyID");
+ return HX509_CERTIFICATE_MALFORMED;
+ }
+
+ if (ai.keyIdentifier == NULL) {
+ free_AuthorityKeyIdentifier(&ai);
+ hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
+ "Subjectless certificate missing keyIdentifier "
+ "inside AuthKeyID");
+ return HX509_CERTIFICATE_MALFORMED;
+ }
+
+ q.subject_id = ai.keyIdentifier;
+ q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
+ }
+
+ q.path = path;
+ q.match |= HX509_QUERY_NO_MATCH_PATH;
+
+ if (pool) {
+ q.timenow = time_now;
+ q.match |= HX509_QUERY_MATCH_TIME;
+
+ ret = hx509_certs_find(context, pool, &q, parent);
+ if (ret == 0) {
+ free_AuthorityKeyIdentifier(&ai);
+ return 0;
+ }
+ q.match &= ~HX509_QUERY_MATCH_TIME;
+ }
+
+ if (trust_anchors) {
+ ret = hx509_certs_find(context, trust_anchors, &q, parent);
+ if (ret == 0) {
+ free_AuthorityKeyIdentifier(&ai);
+ return ret;
+ }
+ }
+ free_AuthorityKeyIdentifier(&ai);
+
+ {
+ hx509_name name;
+ char *str;
+
+ ret = hx509_cert_get_subject(current, &name);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return HX509_ISSUER_NOT_FOUND;
+ }
+ ret = hx509_name_to_string(name, &str);
+ hx509_name_free(&name);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return HX509_ISSUER_NOT_FOUND;
+ }
+
+ hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
+ "Failed to find issuer for "
+ "certificate with subject: %s", str);
+ free(str);
+ }
+ return HX509_ISSUER_NOT_FOUND;
+}
+
+/*
+ *
+ */
+
+static int
+is_proxy_cert(hx509_context context, const Certificate *cert, ProxyCertInfo *rinfo)
+{
+ ProxyCertInfo info;
+ const Extension *e;
+ size_t size;
+ int ret, i = 0;
+
+ if (rinfo)
+ memset(rinfo, 0, sizeof(*rinfo));
+
+ e = find_extension(cert, oid_id_pe_proxyCertInfo(), &i);
+ if (e == NULL) {
+ hx509_clear_error_string(context);
+ return HX509_EXTENSION_NOT_FOUND;
+ }
+
+ ret = decode_ProxyCertInfo(e->extnValue.data,
+ e->extnValue.length,
+ &info,
+ &size);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return ret;
+ }
+ if (size != e->extnValue.length) {
+ free_ProxyCertInfo(&info);
+ hx509_clear_error_string(context);
+ return HX509_EXTRA_DATA_AFTER_STRUCTURE;
+ }
+ if (rinfo)
+ *rinfo = info;
+
+ return 0;
+}
+
+/*
+ * Path operations are like MEMORY based keyset, but with exposed
+ * internal so we can do easy searches.
+ */
+
+int
+_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
+{
+ hx509_cert *val;
+ val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
+ if (val == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+
+ path->val = val;
+ path->val[path->len] = hx509_cert_ref(cert);
+ path->len++;
+
+ return 0;
+}
+
+void
+_hx509_path_free(hx509_path *path)
+{
+ unsigned i;
+
+ for (i = 0; i < path->len; i++)
+ hx509_cert_free(path->val[i]);
+ free(path->val);
+ path->val = NULL;
+ path->len = 0;
+}
+
+/*
+ * Find path by looking up issuer for the top certificate and continue
+ * until an anchor certificate is found or max limit is found. A
+ * certificate never included twice in the path.
+ *
+ * If the trust anchors are not given, calculate optimistic path, just
+ * follow the chain upward until we no longer find a parent or we hit
+ * the max path limit. In this case, a failure will always be returned
+ * depending on what error condition is hit first.
+ *
+ * The path includes a path from the top certificate to the anchor
+ * certificate.
+ *
+ * The caller needs to free `path´ both on successful built path and
+ * failure.
+ */
+
+int
+_hx509_calculate_path(hx509_context context,
+ int flags,
+ time_t time_now,
+ hx509_certs anchors,
+ unsigned int max_depth,
+ hx509_cert cert,
+ hx509_certs pool,
+ hx509_path *path)
+{
+ hx509_cert parent, current;
+ int ret;
+
+ if (max_depth == 0)
+ max_depth = HX509_VERIFY_MAX_DEPTH;
+
+ ret = _hx509_path_append(context, path, cert);
+ if (ret)
+ return ret;
+
+ current = hx509_cert_ref(cert);
+
+ while (!certificate_is_anchor(context, anchors, current)) {
+
+ ret = find_parent(context, time_now, anchors, path,
+ pool, current, &parent);
+ hx509_cert_free(current);
+ if (ret)
+ return ret;
+
+ ret = _hx509_path_append(context, path, parent);
+ if (ret)
+ return ret;
+ current = parent;
+
+ if (path->len > max_depth) {
+ hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
+ "Path too long while bulding certificate chain");
+ return HX509_PATH_TOO_LONG;
+ }
+ }
+
+ if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
+ path->len > 0 &&
+ certificate_is_anchor(context, anchors, path->val[path->len - 1]))
+ {
+ hx509_cert_free(path->val[path->len - 1]);
+ path->len--;
+ }
+
+ hx509_cert_free(current);
+ return 0;
+}
+
+static int
+AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
+ const AlgorithmIdentifier *q)
+{
+ int diff;
+ diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
+ if (diff)
+ return diff;
+ if (p->parameters) {
+ if (q->parameters)
+ return heim_any_cmp(p->parameters,
+ q->parameters);
+ else
+ return 1;
+ } else {
+ if (q->parameters)
+ return -1;
+ else
+ return 0;
+ }
+}
+
+int
+_hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
+{
+ int diff;
+ diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
+ if (diff)
+ return diff;
+ diff = AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
+ &q->signatureAlgorithm);
+ if (diff)
+ return diff;
+ diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
+ &q->tbsCertificate._save);
+ return diff;
+}
+
+int
+hx509_cert_cmp(hx509_cert p, hx509_cert q)
+{
+ return _hx509_Certificate_cmp(p->data, q->data);
+}
+
+int
+hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
+{
+ return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
+}
+
+int
+hx509_cert_get_subject(hx509_cert p, hx509_name *name)
+{
+ return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
+}
+
+int
+hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
+ hx509_name *name)
+{
+ if (c->basename)
+ return hx509_name_copy(context, c->basename, name);
+ if (is_proxy_cert(context, c->data, NULL) == 0) {
+ int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
+ hx509_set_error_string(context, 0, ret,
+ "Proxy certificate have not been "
+ "canonicalize yet, no base name");
+ return ret;
+ }
+ return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
+}
+
+int
+hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
+{
+ return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
+}
+
+hx509_private_key
+_hx509_cert_private_key(hx509_cert p)
+{
+ return p->private_key;
+}
+
+int
+_hx509_cert_private_key_exportable(hx509_cert p)
+{
+ if (p->private_key == NULL)
+ return 0;
+ return _hx509_private_key_exportable(p->private_key);
+}
+
+int
+_hx509_cert_private_decrypt(hx509_context context,
+ const heim_octet_string *ciphertext,
+ const heim_oid *encryption_oid,
+ hx509_cert p,
+ heim_octet_string *cleartext)
+{
+ cleartext->data = NULL;
+ cleartext->length = 0;
+
+ if (p->private_key == NULL) {
+ hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
+ "Private key missing");
+ return HX509_PRIVATE_KEY_MISSING;
+ }
+
+ return _hx509_private_key_private_decrypt(context,
+ ciphertext,
+ encryption_oid,
+ p->private_key,
+ cleartext);
+}
+
+int
+_hx509_cert_public_encrypt(hx509_context context,
+ const heim_octet_string *cleartext,
+ const hx509_cert p,
+ heim_oid *encryption_oid,
+ heim_octet_string *ciphertext)
+{
+ return _hx509_public_encrypt(context,
+ cleartext, p->data,
+ encryption_oid, ciphertext);
+}
+
+/*
+ *
+ */
+
+time_t
+_hx509_Time2time_t(const Time *t)
+{
+ switch(t->element) {
+ case choice_Time_utcTime:
+ return t->u.utcTime;
+ case choice_Time_generalTime:
+ return t->u.generalTime;
+ }
+ return 0;
+}
+
+/*
+ *
+ */
+
+static int
+init_name_constraints(hx509_name_constraints *nc)
+{
+ memset(nc, 0, sizeof(*nc));
+ return 0;
+}
+
+static int
+add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
+ hx509_name_constraints *nc)
+{
+ NameConstraints tnc;
+ int ret;
+
+ ret = find_extension_name_constraints(c, &tnc);
+ if (ret == HX509_EXTENSION_NOT_FOUND)
+ return 0;
+ else if (ret) {
+ hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
+ return ret;
+ } else if (not_ca) {
+ ret = HX509_VERIFY_CONSTRAINTS;
+ hx509_set_error_string(context, 0, ret, "Not a CA and "
+ "have NameConstraints");
+ } else {
+ NameConstraints *val;
+ val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
+ if (val == NULL) {
+ hx509_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+ nc->val = val;
+ ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
+ if (ret) {
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ nc->len += 1;
+ }
+out:
+ free_NameConstraints(&tnc);
+ return ret;
+}
+
+static int
+match_RDN(const RelativeDistinguishedName *c,
+ const RelativeDistinguishedName *n)
+{
+ int i;
+
+ if (c->len != n->len)
+ return HX509_NAME_CONSTRAINT_ERROR;
+
+ for (i = 0; i < n->len; i++) {
+ if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ }
+ return 0;
+}
+
+static int
+match_X501Name(const Name *c, const Name *n)
+{
+ int i, ret;
+
+ if (c->element != choice_Name_rdnSequence
+ || n->element != choice_Name_rdnSequence)
+ return 0;
+ if (c->u.rdnSequence.len > n->u.rdnSequence.len)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ for (i = 0; i < c->u.rdnSequence.len; i++) {
+ ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+
+static int
+match_general_name(const GeneralName *c, const GeneralName *n, int *match)
+{
+ /*
+ * Name constraints only apply to the same name type, see RFC3280,
+ * 4.2.1.11.
+ */
+ assert(c->element == n->element);
+
+ switch(c->element) {
+ case choice_GeneralName_otherName:
+ if (der_heim_oid_cmp(&c->u.otherName.type_id,
+ &n->u.otherName.type_id) != 0)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ if (heim_any_cmp(&c->u.otherName.value,
+ &n->u.otherName.value) != 0)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ *match = 1;
+ return 0;
+ case choice_GeneralName_rfc822Name: {
+ const char *s;
+ size_t len1, len2;
+ s = strchr(c->u.rfc822Name, '@');
+ if (s) {
+ if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ } else {
+ s = strchr(n->u.rfc822Name, '@');
+ if (s == NULL)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ len1 = strlen(c->u.rfc822Name);
+ len2 = strlen(s + 1);
+ if (len1 > len2)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ if (len1 < len2 && s[len2 - len1] != '.')
+ return HX509_NAME_CONSTRAINT_ERROR;
+ }
+ *match = 1;
+ return 0;
+ }
+ case choice_GeneralName_dNSName: {
+ size_t len1, len2;
+
+ len1 = strlen(c->u.dNSName);
+ len2 = strlen(n->u.dNSName);
+ if (len1 > len2)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ if (strcasecmp(&n->u.dNSName[len2 - len1], c->u.dNSName) != 0)
+ return HX509_NAME_CONSTRAINT_ERROR;
+ *match = 1;
+ return 0;
+ }
+ case choice_GeneralName_directoryName: {
+ Name c_name, n_name;
+ int ret;
+
+ c_name._save.data = NULL;
+ c_name._save.length = 0;
+ c_name.element = c->u.directoryName.element;
+ c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
+
+ n_name._save.data = NULL;
+ n_name._save.length = 0;
+ n_name.element = n->u.directoryName.element;
+ n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
+
+ ret = match_X501Name(&c_name, &n_name);
+ if (ret == 0)
+ *match = 1;
+ return ret;
+ }
+ case choice_GeneralName_uniformResourceIdentifier:
+ case choice_GeneralName_iPAddress:
+ case choice_GeneralName_registeredID:
+ default:
+ return HX509_NAME_CONSTRAINT_ERROR;
+ }
+}
+
+static int
+match_alt_name(const GeneralName *n, const Certificate *c,
+ int *same, int *match)
+{
+ GeneralNames sa;
+ int ret, i, j;
+
+ i = 0;
+ do {
+ ret = find_extension_subject_alt_name(c, &i, &sa);
+ if (ret == HX509_EXTENSION_NOT_FOUND) {
+ ret = 0;
+ break;
+ } else if (ret != 0)
+ break;
+
+ for (j = 0; j < sa.len; j++) {
+ if (n->element == sa.val[j].element) {
+ *same = 1;
+ ret = match_general_name(n, &sa.val[j], match);
+ }
+ }
+ free_GeneralNames(&sa);
+ } while (1);
+
+ return ret;
+}
+
+
+static int
+match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
+{
+ int name, alt_name, same;
+ unsigned int i;
+ int ret = 0;
+
+ name = alt_name = same = *match = 0;
+ for (i = 0; i < t->len; i++) {
+ if (t->val[i].minimum && t->val[i].maximum)
+ return HX509_RANGE;
+
+ /*
+ * If the constraint apply to directoryNames, test is with
+ * subjectName of the certificate if the certificate have a
+ * non-null (empty) subjectName.
+ */
+
+ if (t->val[i].base.element == choice_GeneralName_directoryName
+ && !subject_null_p(c))
+ {
+ GeneralName certname;
+
+
+ certname.element = choice_GeneralName_directoryName;
+ certname.u.directoryName.element =
+ c->tbsCertificate.subject.element;
+ certname.u.directoryName.u.rdnSequence =
+ c->tbsCertificate.subject.u.rdnSequence;
+
+ ret = match_general_name(&t->val[i].base, &certname, &name);
+ }
+
+ /* Handle subjectAltNames, this is icky since they
+ * restrictions only apply if the subjectAltName is of the
+ * same type. So if there have been a match of type, require
+ * altname to be set.
+ */
+ ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
+ }
+ if (name && (!same || alt_name))
+ *match = 1;
+ return ret;
+}
+
+static int
+check_name_constraints(hx509_context context,
+ const hx509_name_constraints *nc,
+ const Certificate *c)
+{
+ int match, ret;
+ int i;
+
+ for (i = 0 ; i < nc->len; i++) {
+ GeneralSubtrees gs;
+
+ if (nc->val[i].permittedSubtrees) {
+ GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
+ ret = match_tree(&gs, c, &match);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return ret;
+ }
+ /* allow null subjectNames, they wont matches anything */
+ if (match == 0 && !subject_null_p(c)) {
+ hx509_clear_error_string(context);
+ return HX509_VERIFY_CONSTRAINTS;
+ }
+ }
+ if (nc->val[i].excludedSubtrees) {
+ GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
+ ret = match_tree(&gs, c, &match);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return ret;
+ }
+ if (match) {
+ hx509_clear_error_string(context);
+ return HX509_VERIFY_CONSTRAINTS;
+ }
+ }
+ }
+ return 0;
+}
+
+static void
+free_name_constraints(hx509_name_constraints *nc)
+{
+ int i;
+
+ for (i = 0 ; i < nc->len; i++)
+ free_NameConstraints(&nc->val[i]);
+ free(nc->val);
+}
+
+int
+hx509_verify_path(hx509_context context,
+ hx509_verify_ctx ctx,
+ hx509_cert cert,
+ hx509_certs pool)
+{
+ hx509_name_constraints nc;
+ hx509_path path;
+#if 0
+ const AlgorithmIdentifier *alg_id;
+#endif
+ int ret, i, proxy_cert_depth;
+ enum certtype type;
+ Name proxy_issuer;
+
+ memset(&proxy_issuer, 0, sizeof(proxy_issuer));
+
+ ret = init_name_constraints(&nc);
+ if (ret)
+ return ret;
+
+ path.val = NULL;
+ path.len = 0;
+
+ if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
+ ctx->time_now = time(NULL);
+
+ /*
+ * Calculate the path from the certificate user presented to the
+ * to an anchor.
+ */
+ ret = _hx509_calculate_path(context, 0, ctx->time_now,
+ ctx->trust_anchors, ctx->max_depth,
+ cert, pool, &path);
+ if (ret)
+ goto out;
+
+#if 0
+ alg_id = path.val[path->len - 1]->data->tbsCertificate.signature;
+#endif
+
+ /*
+ * Check CA and proxy certificate chain from the top of the
+ * certificate chain. Also check certificate is valid with respect
+ * to the current time.
+ *
+ */
+
+ proxy_cert_depth = 0;
+
+ if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
+ type = PROXY_CERT;
+ else
+ type = EE_CERT;
+
+ for (i = 0; i < path.len; i++) {
+ Certificate *c;
+ time_t t;
+
+ c = _hx509_get_cert(path.val[i]);
+
+ /*
+ * Lets do some basic check on issuer like
+ * keyUsage.keyCertSign and basicConstraints.cA bit depending
+ * on what type of certificate this is.
+ */
+
+ switch (type) {
+ case CA_CERT:
+ /* XXX make constants for keyusage */
+ ret = check_key_usage(context, c, 1 << 5,
+ REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "Key usage missing from CA certificate");
+ goto out;
+ }
+ break;
+ case PROXY_CERT: {
+ ProxyCertInfo info;
+
+ if (is_proxy_cert(context, c, &info) == 0) {
+ int j;
+
+ if (info.pCPathLenConstraint != NULL &&
+ *info.pCPathLenConstraint < i)
+ {
+ free_ProxyCertInfo(&info);
+ ret = HX509_PATH_TOO_LONG;
+ hx509_set_error_string(context, 0, ret,
+ "Proxy certificate chain "
+ "longer then allowed");
+ goto out;
+ }
+ /* XXX MUST check info.proxyPolicy */
+ free_ProxyCertInfo(&info);
+
+ j = 0;
+ if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
+ ret = HX509_PROXY_CERT_INVALID;
+ hx509_set_error_string(context, 0, ret,
+ "Proxy certificate have explicity "
+ "forbidden subjectAltName");
+ goto out;
+ }
+
+ j = 0;
+ if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
+ ret = HX509_PROXY_CERT_INVALID;
+ hx509_set_error_string(context, 0, ret,
+ "Proxy certificate have explicity "
+ "forbidden issuerAltName");
+ goto out;
+ }
+
+ /*
+ * The subject name of the proxy certificate should be
+ * CN=XXX,<proxy issuer>, prune of CN and check if its
+ * the same over the whole chain of proxy certs and
+ * then check with the EE cert when we get to it.
+ */
+
+ if (proxy_cert_depth) {
+ ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject);
+ if (ret) {
+ ret = HX509_PROXY_CERT_NAME_WRONG;
+ hx509_set_error_string(context, 0, ret,
+ "Base proxy name not right");
+ goto out;
+ }
+ }
+
+ free_Name(&proxy_issuer);
+
+ ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
+ if (ret) {
+ hx509_clear_error_string(context);
+ goto out;
+ }
+
+ j = proxy_issuer.u.rdnSequence.len;
+ if (proxy_issuer.u.rdnSequence.len < 2
+ || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
+ || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
+ oid_id_at_commonName()))
+ {
+ ret = HX509_PROXY_CERT_NAME_WRONG;
+ hx509_set_error_string(context, 0, ret,
+ "Proxy name too short or "
+ "does not have Common name "
+ "at the top");
+ goto out;
+ }
+
+ free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
+ proxy_issuer.u.rdnSequence.len -= 1;
+
+ ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer);
+ if (ret != 0) {
+ ret = HX509_PROXY_CERT_NAME_WRONG;
+ hx509_set_error_string(context, 0, ret,
+ "Proxy issuer name not as expected");
+ goto out;
+ }
+
+ break;
+ } else {
+ /*
+ * Now we are done with the proxy certificates, this
+ * cert was an EE cert and we we will fall though to
+ * EE checking below.
+ */
+ type = EE_CERT;
+ /* FALLTHOUGH */
+ }
+ }
+ case EE_CERT:
+ /*
+ * If there where any proxy certificates in the chain
+ * (proxy_cert_depth > 0), check that the proxy issuer
+ * matched proxy certificates "base" subject.
+ */
+ if (proxy_cert_depth) {
+
+ ret = _hx509_name_cmp(&proxy_issuer,
+ &c->tbsCertificate.subject);
+ if (ret) {
+ ret = HX509_PROXY_CERT_NAME_WRONG;
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ if (cert->basename)
+ hx509_name_free(&cert->basename);
+
+ ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
+ if (ret) {
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ }
+
+ break;
+ }
+
+ ret = check_basic_constraints(context, c, type, i - proxy_cert_depth);
+ if (ret)
+ goto out;
+
+ /*
+ * Don't check the trust anchors expiration time since they
+ * are transported out of band, from RFC3820.
+ */
+ if (i + 1 != path.len || CHECK_TA(ctx)) {
+
+ t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
+ if (t > ctx->time_now) {
+ ret = HX509_CERT_USED_BEFORE_TIME;
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
+ if (t < ctx->time_now) {
+ ret = HX509_CERT_USED_AFTER_TIME;
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ }
+
+ if (type == EE_CERT)
+ type = CA_CERT;
+ else if (type == PROXY_CERT)
+ proxy_cert_depth++;
+ }
+
+ /*
+ * Verify constraints, do this backward so path constraints are
+ * checked in the right order.
+ */
+
+ for (ret = 0, i = path.len - 1; i >= 0; i--) {
+ Certificate *c;
+
+ c = _hx509_get_cert(path.val[i]);
+
+#if 0
+ /* check that algorithm and parameters is the same */
+ /* XXX this is wrong */
+ ret = alg_cmp(&c->tbsCertificate.signature, alg_id);
+ if (ret) {
+ hx509_clear_error_string(context);
+ ret = HX509_PATH_ALGORITHM_CHANGED;
+ goto out;
+ }
+#endif
+
+ /* verify name constraints, not for selfsigned and anchor */
+ if (!certificate_is_self_signed(c) || i == path.len - 1) {
+ ret = check_name_constraints(context, &nc, c);
+ if (ret) {
+ goto out;
+ }
+ }
+ ret = add_name_constraints(context, c, i == 0, &nc);
+ if (ret)
+ goto out;
+
+ /* XXX verify all other silly constraints */
+
+ }
+
+ /*
+ * Verify that no certificates has been revoked.
+ */
+
+ if (ctx->revoke_ctx) {
+ hx509_certs certs;
+
+ ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
+ NULL, &certs);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < path.len; i++) {
+ ret = hx509_certs_add(context, certs, path.val[i]);
+ if (ret) {
+ hx509_certs_free(&certs);
+ goto out;
+ }
+ }
+ ret = hx509_certs_merge(context, certs, pool);
+ if (ret) {
+ hx509_certs_free(&certs);
+ goto out;
+ }
+
+ for (i = 0; i < path.len - 1; i++) {
+ int parent = (i < path.len - 1) ? i + 1 : i;
+
+ ret = hx509_revoke_verify(context,
+ ctx->revoke_ctx,
+ certs,
+ ctx->time_now,
+ path.val[i],
+ path.val[parent]);
+ if (ret) {
+ hx509_certs_free(&certs);
+ goto out;
+ }
+ }
+ hx509_certs_free(&certs);
+ }
+
+#if 0
+ for (i = path.len - 1; i >= 0; i--) {
+ _hx509_print_cert_subject(path.val[i]);
+ }
+#endif
+
+ /*
+ * Verify signatures, do this backward so public key working
+ * parameter is passed up from the anchor up though the chain.
+ */
+
+ for (i = path.len - 1; i >= 0; i--) {
+ Certificate *signer, *c;
+
+ c = _hx509_get_cert(path.val[i]);
+
+ /* is last in chain (trust anchor) */
+ if (i == path.len - 1) {
+ signer = path.val[i]->data;
+
+ /* if trust anchor is not self signed, don't check sig */
+ if (!certificate_is_self_signed(signer))
+ continue;
+ } else {
+ /* take next certificate in chain */
+ signer = path.val[i + 1]->data;
+ }
+
+ /* verify signatureValue */
+ ret = _hx509_verify_signature_bitstring(context,
+ signer,
+ &c->signatureAlgorithm,
+ &c->tbsCertificate._save,
+ &c->signatureValue);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "Failed to verify signature of certificate");
+ goto out;
+ }
+ }
+
+out:
+ free_Name(&proxy_issuer);
+ free_name_constraints(&nc);
+ _hx509_path_free(&path);
+
+ return ret;
+}
+
+int
+hx509_verify_signature(hx509_context context,
+ const hx509_cert signer,
+ const AlgorithmIdentifier *alg,
+ const heim_octet_string *data,
+ const heim_octet_string *sig)
+{
+ return _hx509_verify_signature(context, signer->data, alg, data, sig);
+}
+
+int
+hx509_verify_hostname(hx509_context context,
+ const hx509_cert cert,
+ int require_match,
+ const char *hostname,
+ const struct sockaddr *sa,
+ /* XXX krb5_socklen_t */ int sa_size)
+{
+ if (sa && sa_size <= 0)
+ return EINVAL;
+ return 0;
+}
+
+int
+_hx509_set_cert_attribute(hx509_context context,
+ hx509_cert cert,
+ const heim_oid *oid,
+ const heim_octet_string *attr)
+{
+ hx509_cert_attribute a;
+ void *d;
+
+ if (hx509_cert_get_attribute(cert, oid) != NULL)
+ return 0;
+
+ d = realloc(cert->attrs.val,
+ sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
+ if (d == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+ cert->attrs.val = d;
+
+ a = malloc(sizeof(*a));
+ if (a == NULL)
+ return ENOMEM;
+
+ der_copy_octet_string(attr, &a->data);
+ der_copy_oid(oid, &a->oid);
+
+ cert->attrs.val[cert->attrs.len] = a;
+ cert->attrs.len++;
+
+ return 0;
+}
+
+hx509_cert_attribute
+hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
+{
+ int i;
+ for (i = 0; i < cert->attrs.len; i++)
+ if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
+ return cert->attrs.val[i];
+ return NULL;
+}
+
+int
+hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
+{
+ if (cert->friendlyname)
+ free(cert->friendlyname);
+ cert->friendlyname = strdup(name);
+ if (cert->friendlyname == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+
+const char *
+hx509_cert_get_friendly_name(hx509_cert cert)
+{
+ hx509_cert_attribute a;
+ PKCS9_friendlyName n;
+ size_t sz;
+ int ret, i;
+
+ if (cert->friendlyname)
+ return cert->friendlyname;
+
+ a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
+ if (a == NULL) {
+ /* XXX use subject name ? */
+ return NULL;
+ }
+
+ ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
+ if (ret)
+ return NULL;
+
+ if (n.len != 1) {
+ free_PKCS9_friendlyName(&n);
+ return NULL;
+ }
+
+ cert->friendlyname = malloc(n.val[0].length + 1);
+ if (cert->friendlyname == NULL) {
+ free_PKCS9_friendlyName(&n);
+ return NULL;
+ }
+
+ for (i = 0; i < n.val[0].length; i++) {
+ if (n.val[0].data[i] <= 0xff)
+ cert->friendlyname[i] = n.val[0].data[i] & 0xff;
+ else
+ cert->friendlyname[i] = 'X';
+ }
+ cert->friendlyname[i] = '\0';
+ free_PKCS9_friendlyName(&n);
+
+ return cert->friendlyname;
+}
+
+void
+_hx509_query_clear(hx509_query *q)
+{
+ memset(q, 0, sizeof(*q));
+}
+
+int
+hx509_query_alloc(hx509_context context, hx509_query **q)
+{
+ *q = calloc(1, sizeof(**q));
+ if (*q == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+void
+hx509_query_match_option(hx509_query *q, hx509_query_option option)
+{
+ switch(option) {
+ case HX509_QUERY_OPTION_PRIVATE_KEY:
+ q->match |= HX509_QUERY_PRIVATE_KEY;
+ break;
+ case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
+ q->match |= HX509_QUERY_KU_ENCIPHERMENT;
+ break;
+ case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
+ q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
+ break;
+ case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
+ q->match |= HX509_QUERY_KU_KEYCERTSIGN;
+ break;
+ case HX509_QUERY_OPTION_END:
+ default:
+ break;
+ }
+}
+
+int
+hx509_query_match_issuer_serial(hx509_query *q,
+ const Name *issuer,
+ const heim_integer *serialNumber)
+{
+ int ret;
+ if (q->serial) {
+ der_free_heim_integer(q->serial);
+ free(q->serial);
+ }
+ q->serial = malloc(sizeof(*q->serial));
+ if (q->serial == NULL)
+ return ENOMEM;
+ ret = der_copy_heim_integer(serialNumber, q->serial);
+ if (ret) {
+ free(q->serial);
+ q->serial = NULL;
+ return ret;
+ }
+ if (q->issuer_name) {
+ free_Name(q->issuer_name);
+ free(q->issuer_name);
+ }
+ q->issuer_name = malloc(sizeof(*q->issuer_name));
+ if (q->issuer_name == NULL)
+ return ENOMEM;
+ ret = copy_Name(issuer, q->issuer_name);
+ if (ret) {
+ free(q->issuer_name);
+ q->issuer_name = NULL;
+ return ret;
+ }
+ q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
+ return 0;
+}
+
+
+int
+hx509_query_match_friendly_name(hx509_query *q, const char *name)
+{
+ if (q->friendlyname)
+ free(q->friendlyname);
+ q->friendlyname = strdup(name);
+ if (q->friendlyname == NULL)
+ return ENOMEM;
+ q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
+ return 0;
+}
+
+int
+hx509_query_match_cmp_func(hx509_query *q,
+ int (*func)(void *, hx509_cert),
+ void *ctx)
+{
+ if (func)
+ q->match |= HX509_QUERY_MATCH_FUNCTION;
+ else
+ q->match &= ~HX509_QUERY_MATCH_FUNCTION;
+ q->cmp_func = func;
+ q->cmp_func_ctx = ctx;
+ return 0;
+}
+
+
+void
+hx509_query_free(hx509_context context, hx509_query *q)
+{
+ if (q->serial) {
+ der_free_heim_integer(q->serial);
+ free(q->serial);
+ q->serial = NULL;
+ }
+ if (q->issuer_name) {
+ free_Name(q->issuer_name);
+ free(q->issuer_name);
+ q->issuer_name = NULL;
+ }
+ if (q) {
+ free(q->friendlyname);
+ memset(q, 0, sizeof(*q));
+ }
+ free(q);
+}
+
+int
+_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
+{
+ Certificate *c = _hx509_get_cert(cert);
+
+ if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
+ _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
+ return 0;
+
+ if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
+ _hx509_Certificate_cmp(q->certificate, c) != 0)
+ return 0;
+
+ if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
+ && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
+ return 0;
+
+ if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
+ && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
+ return 0;
+
+ if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
+ && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
+ return 0;
+
+ if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
+ SubjectKeyIdentifier si;
+ int ret;
+
+ ret = _hx509_find_extension_subject_key_id(c, &si);
+ if (ret == 0) {
+ if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
+ ret = 1;
+ free_SubjectKeyIdentifier(&si);
+ }
+ if (ret)
+ return 0;
+ }
+ if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
+ return 0;
+ if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
+ _hx509_cert_private_key(cert) == NULL)
+ return 0;
+
+ {
+ unsigned ku = 0;
+ if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
+ ku |= (1 << 0);
+ if (q->match & HX509_QUERY_KU_NONREPUDIATION)
+ ku |= (1 << 1);
+ if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
+ ku |= (1 << 2);
+ if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
+ ku |= (1 << 3);
+ if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
+ ku |= (1 << 4);
+ if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
+ ku |= (1 << 5);
+ if (q->match & HX509_QUERY_KU_CRLSIGN)
+ ku |= (1 << 6);
+ if (ku && check_key_usage(context, c, ku, TRUE))
+ return 0;
+ }
+ if ((q->match & HX509_QUERY_ANCHOR))
+ return 0;
+
+ if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
+ hx509_cert_attribute a;
+
+ a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
+ if (a == NULL)
+ return 0;
+ if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
+ return 0;
+ }
+
+ if (q->match & HX509_QUERY_NO_MATCH_PATH) {
+ size_t i;
+
+ for (i = 0; i < q->path->len; i++)
+ if (hx509_cert_cmp(q->path->val[i], cert) == 0)
+ return 0;
+ }
+ if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
+ const char *name = hx509_cert_get_friendly_name(cert);
+ if (name == NULL)
+ return 0;
+ if (strcasecmp(q->friendlyname, name) != 0)
+ return 0;
+ }
+ if (q->match & HX509_QUERY_MATCH_FUNCTION) {
+ int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
+ if (ret != 0)
+ return 0;
+ }
+
+ if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
+ heim_octet_string os;
+ int ret;
+
+ os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
+ os.length =
+ c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
+
+ ret = _hx509_verify_signature(context,
+ NULL,
+ hx509_signature_sha1(),
+ &os,
+ q->keyhash_sha1);
+ if (ret != 0)
+ return 0;
+ }
+
+ if (q->match & HX509_QUERY_MATCH_TIME) {
+ time_t t;
+ t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
+ if (t > q->timenow)
+ return 0;
+ t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
+ if (t < q->timenow)
+ return 0;
+ }
+
+ if (q->match & ~HX509_QUERY_MASK)
+ return 0;
+
+ return 1;
+}
+
+int
+hx509_cert_check_eku(hx509_context context, hx509_cert cert,
+ const heim_oid *eku, int allow_any_eku)
+{
+ ExtKeyUsage e;
+ int ret, i;
+
+ ret = find_extension_eku(_hx509_get_cert(cert), &e);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return ret;
+ }
+
+ for (i = 0; i < e.len; i++) {
+ if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
+ free_ExtKeyUsage(&e);
+ return 0;
+ }
+ if (allow_any_eku) {
+#if 0
+ if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
+ free_ExtKeyUsage(&e);
+ return 0;
+ }
+#endif
+ }
+ }
+ free_ExtKeyUsage(&e);
+ hx509_clear_error_string(context);
+ return HX509_CERTIFICATE_MISSING_EKU;
+}
+
+int
+_hx509_cert_get_keyusage(hx509_context context,
+ hx509_cert c,
+ KeyUsage *ku)
+{
+ Certificate *cert;
+ const Extension *e;
+ size_t size;
+ int ret, i = 0;
+
+ memset(ku, 0, sizeof(*ku));
+
+ cert = _hx509_get_cert(c);
+
+ if (_hx509_cert_get_version(cert) < 3)
+ return 0;
+
+ e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
+ if (e == NULL)
+ return HX509_KU_CERT_MISSING;
+
+ ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
+ if (ret)
+ return ret;
+ return 0;
+}
diff --git a/source4/heimdal/lib/hx509/cms.c b/source4/heimdal/lib/hx509/cms.c
new file mode 100644
index 00000000000..4ed70b8f84b
--- /dev/null
+++ b/source4/heimdal/lib/hx509/cms.c
@@ -0,0 +1,1279 @@
+/*
+ * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: cms.c,v 1.48 2007/01/08 18:45:03 lha Exp $");
+
+#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
+#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
+
+int
+hx509_cms_wrap_ContentInfo(const heim_oid *oid,
+ const heim_octet_string *buf,
+ heim_octet_string *res)
+{
+ ContentInfo ci;
+ size_t size;
+ int ret;
+
+ memset(res, 0, sizeof(*res));
+ memset(&ci, 0, sizeof(ci));
+
+ ret = der_copy_oid(oid, &ci.contentType);
+ if (ret)
+ return ret;
+ ALLOC(ci.content, 1);
+ if (ci.content == NULL) {
+ free_ContentInfo(&ci);
+ return ENOMEM;
+ }
+ ci.content->data = malloc(buf->length);
+ if (ci.content->data == NULL) {
+ free_ContentInfo(&ci);
+ return ENOMEM;
+ }
+ memcpy(ci.content->data, buf->data, buf->length);
+ ci.content->length = buf->length;
+
+ ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
+ free_ContentInfo(&ci);
+ if (ret)
+ return ret;
+ if (res->length != size)
+ _hx509_abort("internal ASN.1 encoder error");
+
+ return 0;
+}
+
+int
+hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
+ heim_oid *oid,
+ heim_octet_string *out,
+ int *have_data)
+{
+ ContentInfo ci;
+ size_t size;
+ int ret;
+
+ memset(oid, 0, sizeof(*oid));
+ memset(out, 0, sizeof(*out));
+
+ ret = decode_ContentInfo(in->data, in->length, &ci, &size);
+ if (ret)
+ return ret;
+
+ ret = der_copy_oid(&ci.contentType, oid);
+ if (ret) {
+ free_ContentInfo(&ci);
+ return ret;
+ }
+ if (ci.content) {
+ ret = der_copy_octet_string(ci.content, out);
+ if (ret) {
+ der_free_oid(oid);
+ free_ContentInfo(&ci);
+ return ret;
+ }
+ } else
+ memset(out, 0, sizeof(*out));
+
+ if (have_data)
+ *have_data = (ci.content != NULL) ? 1 : 0;
+
+ free_ContentInfo(&ci);
+
+ return 0;
+}
+
+static int
+fill_CMSIdentifier(const hx509_cert cert, CMSIdentifier *id)
+{
+ hx509_name name;
+ int ret;
+
+ id->element = choice_CMSIdentifier_issuerAndSerialNumber;
+ ret = hx509_cert_get_issuer(cert, &name);
+ if (ret)
+ return ret;
+ ret = copy_Name(&name->der_name,
+ &id->u.issuerAndSerialNumber.issuer);
+ hx509_name_free(&name);
+ if (ret)
+ return ret;
+
+ ret = hx509_cert_get_serialnumber(cert,
+ &id->u.issuerAndSerialNumber.serialNumber);
+ return ret;
+}
+
+static int
+unparse_CMSIdentifier(hx509_context context,
+ CMSIdentifier *id,
+ char **str)
+{
+ int ret;
+
+ *str = NULL;
+ switch (id->element) {
+ case choice_CMSIdentifier_issuerAndSerialNumber: {
+ IssuerAndSerialNumber *iasn;
+ char *serial, *name;
+
+ iasn = &id->u.issuerAndSerialNumber;
+
+ ret = _hx509_Name_to_string(&iasn->issuer, &name);
+ if(ret)
+ return ret;
+ ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+ asprintf(str, "certificate issued by %s with serial number %s",
+ name, serial);
+ free(name);
+ free(serial);
+ break;
+ }
+ case choice_CMSIdentifier_subjectKeyIdentifier: {
+ KeyIdentifier *ki = &id->u.subjectKeyIdentifier;
+ char *keyid;
+ ssize_t len;
+
+ len = hex_encode(ki->data, ki->length, &keyid);
+ if (len < 0)
+ return ENOMEM;
+
+ asprintf(str, "certificate with id %s", keyid);
+ free(keyid);
+ break;
+ }
+ default:
+ asprintf(str, "certificate have unknown CMSidentifier type");
+ break;
+ }
+ if (*str == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+static int
+find_CMSIdentifier(hx509_context context,
+ CMSIdentifier *client,
+ hx509_certs certs,
+ hx509_cert *signer_cert,
+ int match)
+{
+ hx509_query q;
+ hx509_cert cert;
+ Certificate c;
+ int ret;
+
+ memset(&c, 0, sizeof(c));
+ _hx509_query_clear(&q);
+
+ *signer_cert = NULL;
+
+ switch (client->element) {
+ case choice_CMSIdentifier_issuerAndSerialNumber:
+ q.serial = &client->u.issuerAndSerialNumber.serialNumber;
+ q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
+ q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
+ break;
+ case choice_CMSIdentifier_subjectKeyIdentifier:
+ q.subject_id = &client->u.subjectKeyIdentifier;
+ q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
+ break;
+ default:
+ hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
+ "unknown CMS identifier element");
+ return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
+ }
+
+ q.match |= match;
+
+ q.match |= HX509_QUERY_MATCH_TIME;
+ q.timenow = time(NULL);
+
+ ret = hx509_certs_find(context, certs, &q, &cert);
+ if (ret == HX509_CERT_NOT_FOUND) {
+ char *str;
+
+ ret = unparse_CMSIdentifier(context, client, &str);
+ if (ret == 0) {
+ hx509_set_error_string(context, 0,
+ HX509_CMS_NO_RECIPIENT_CERTIFICATE,
+ "Failed to find %s", str);
+ } else
+ hx509_clear_error_string(context);
+ return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
+ } else if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND,
+ HX509_CMS_NO_RECIPIENT_CERTIFICATE,
+ "Failed to find CMS id in cert store");
+ return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
+ }
+
+ *signer_cert = cert;
+
+ return 0;
+}
+
+int
+hx509_cms_unenvelope(hx509_context context,
+ hx509_certs certs,
+ int flags,
+ const void *data,
+ size_t length,
+ const heim_octet_string *encryptedContent,
+ heim_oid *contentType,
+ heim_octet_string *content)
+{
+ heim_octet_string key;
+ EnvelopedData ed;
+ hx509_cert cert;
+ AlgorithmIdentifier *ai;
+ const heim_octet_string *enccontent;
+ heim_octet_string *params, params_data;
+ heim_octet_string ivec;
+ size_t size;
+ int ret, i, matched = 0, findflags = 0;
+
+
+ memset(&key, 0, sizeof(key));
+ memset(&ed, 0, sizeof(ed));
+ memset(&ivec, 0, sizeof(ivec));
+ memset(content, 0, sizeof(*content));
+ memset(contentType, 0, sizeof(*contentType));
+
+ if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
+ findflags |= HX509_QUERY_KU_ENCIPHERMENT;
+
+ ret = decode_EnvelopedData(data, length, &ed, &size);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret,
+ "Failed to decode EnvelopedData");
+ return ret;
+ }
+
+ if (ed.recipientInfos.len == 0) {
+ ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
+ hx509_set_error_string(context, 0, ret,
+ "No recipient info in enveloped data");
+ goto out;
+ }
+
+ enccontent = ed.encryptedContentInfo.encryptedContent;
+ if (enccontent == NULL) {
+ if (encryptedContent == NULL) {
+ ret = HX509_CMS_NO_DATA_AVAILABLE;
+ hx509_set_error_string(context, 0, ret,
+ "Content missing from encrypted data");
+ goto out;
+ }
+ enccontent = encryptedContent;
+ }
+
+ cert = NULL;
+ for (i = 0; i < ed.recipientInfos.len; i++) {
+ KeyTransRecipientInfo *ri;
+ char *str;
+ int ret2;
+
+ ri = &ed.recipientInfos.val[i];
+
+ /* ret = search_keyset(ri,
+ * PRIVATE_KEY,
+ * ki->keyEncryptionAlgorithm.algorithm);
+ */
+
+ ret = find_CMSIdentifier(context, &ri->rid, certs, &cert,
+ HX509_QUERY_PRIVATE_KEY|findflags);
+ if (ret)
+ continue;
+
+ matched = 1; /* found a matching certificate, let decrypt */
+
+ ret = _hx509_cert_private_decrypt(context,
+ &ri->encryptedKey,
+ &ri->keyEncryptionAlgorithm.algorithm,
+ cert, &key);
+
+ hx509_cert_free(cert);
+ if (ret == 0)
+ break; /* succuessfully decrypted cert */
+ cert = NULL;
+ ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
+ if (ret2 == 0) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "Failed to decrypt with %s", str);
+ free(str);
+ }
+ }
+
+ if (!matched) {
+ ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
+ hx509_set_error_string(context, 0, ret,
+ "No private key matched any certificate");
+ goto out;
+ }
+
+ if (cert == NULL) {
+ ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "No private key decrypted the transfer key");
+ goto out;
+ }
+
+ ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret,
+ "Failed to copy EnvelopedData content oid");
+ goto out;
+ }
+
+ ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
+ if (ai->parameters) {
+ params_data.data = ai->parameters->data;
+ params_data.length = ai->parameters->length;
+ params = &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
index 00000000000..ec172f46f44
--- /dev/null
+++ b/source4/heimdal/lib/hx509/collector.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: collector.c,v 1.16 2007/01/09 10:52:04 lha Exp $");
+
+struct private_key {
+ AlgorithmIdentifier alg;
+ hx509_private_key private_key;
+ heim_octet_string localKeyId;
+};
+
+struct hx509_collector {
+ hx509_lock lock;
+ hx509_certs unenvelop_certs;
+ hx509_certs certs;
+ struct {
+ struct private_key **data;
+ size_t len;
+ } val;
+};
+
+
+struct hx509_collector *
+_hx509_collector_alloc(hx509_context context, hx509_lock lock)
+{
+ struct hx509_collector *c;
+ int ret;
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL)
+ return NULL;
+ c->lock = lock;
+
+ ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert",
+ 0,NULL, &c->unenvelop_certs);
+ if (ret) {
+ free(c);
+ return NULL;
+ }
+ c->val.data = NULL;
+ c->val.len = 0;
+ ret = hx509_certs_init(context, "MEMORY:collector-tmp-store",
+ 0, NULL, &c->certs);
+ if (ret) {
+ hx509_certs_free(&c->unenvelop_certs);
+ free(c);
+ return NULL;
+ }
+
+ return c;
+}
+
+hx509_lock
+_hx509_collector_get_lock(struct hx509_collector *c)
+{
+ return c->lock;
+}
+
+
+int
+_hx509_collector_certs_add(hx509_context context,
+ struct hx509_collector *c,
+ hx509_cert cert)
+{
+ return hx509_certs_add(context, c->certs, cert);
+}
+
+static void
+free_private_key(struct private_key *key)
+{
+ free_AlgorithmIdentifier(&key->alg);
+ if (key->private_key)
+ _hx509_private_key_free(&key->private_key);
+ der_free_octet_string(&key->localKeyId);
+ free(key);
+}
+
+int
+_hx509_collector_private_key_add(hx509_context context,
+ struct hx509_collector *c,
+ const AlgorithmIdentifier *alg,
+ hx509_private_key private_key,
+ const heim_octet_string *key_data,
+ const heim_octet_string *localKeyId)
+{
+ struct private_key *key;
+ void *d;
+ int ret;
+
+ key = calloc(1, sizeof(*key));
+ if (key == NULL)
+ return ENOMEM;
+
+ d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0]));
+ if (d == NULL) {
+ free(key);
+ hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
+ return ENOMEM;
+ }
+ c->val.data = d;
+
+ ret = copy_AlgorithmIdentifier(alg, &key->alg);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Failed to copy "
+ "AlgorithmIdentifier");
+ goto out;
+ }
+ if (private_key) {
+ key->private_key = private_key;
+ } else {
+ ret = _hx509_parse_private_key(context, &alg->algorithm,
+ key_data->data, key_data->length,
+ &key->private_key);
+ if (ret)
+ goto out;
+ }
+ if (localKeyId) {
+ ret = der_copy_octet_string(localKeyId, &key->localKeyId);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret,
+ "Failed to copy localKeyId");
+ goto out;
+ }
+ } else
+ memset(&key->localKeyId, 0, sizeof(key->localKeyId));
+
+ c->val.data[c->val.len] = key;
+ c->val.len++;
+
+out:
+ if (ret)
+ free_private_key(key);
+
+ return ret;
+}
+
+static int
+match_localkeyid(hx509_context context,
+ struct private_key *value,
+ hx509_certs certs)
+{
+ hx509_cert cert;
+ hx509_query q;
+ int ret;
+
+ if (value->localKeyId.length == 0) {
+ hx509_set_error_string(context, 0, HX509_LOCAL_ATTRIBUTE_MISSING,
+ "No local key attribute on private key");
+ return HX509_LOCAL_ATTRIBUTE_MISSING;
+ }
+
+ _hx509_query_clear(&q);
+ q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID;
+
+ q.local_key_id = &value->localKeyId;
+
+ ret = hx509_certs_find(context, certs, &q, &cert);
+ if (ret == 0) {
+
+ if (value->private_key)
+ _hx509_cert_assign_key(cert, value->private_key);
+ hx509_cert_free(cert);
+ }
+ return ret;
+}
+
+static int
+match_keys(hx509_context context, struct private_key *value, hx509_certs certs)
+{
+ hx509_cursor cursor;
+ hx509_cert c;
+ int ret, found = HX509_CERT_NOT_FOUND;
+
+ if (value->private_key == NULL) {
+ hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
+ "No private key to compare with");
+ return HX509_PRIVATE_KEY_MISSING;
+ }
+
+ ret = hx509_certs_start_seq(context, certs, &cursor);
+ if (ret)
+ return ret;
+
+ c = NULL;
+ while (1) {
+ ret = hx509_certs_next_cert(context, certs, cursor, &c);
+ if (ret)
+ break;
+ if (c == NULL)
+ break;
+ if (_hx509_cert_private_key(c)) {
+ hx509_cert_free(c);
+ continue;
+ }
+
+ ret = _hx509_match_keys(c, value->private_key);
+ if (ret) {
+ _hx509_cert_assign_key(c, value->private_key);
+ hx509_cert_free(c);
+ found = 0;
+ break;
+ }
+ hx509_cert_free(c);
+ }
+
+ hx509_certs_end_seq(context, certs, cursor);
+
+ if (found)
+ hx509_clear_error_string(context);
+
+ return found;
+}
+
+int
+_hx509_collector_collect_certs(hx509_context context,
+ struct hx509_collector *c,
+ hx509_certs *ret_certs)
+{
+ hx509_certs certs;
+ int ret, i;
+
+ *ret_certs = NULL;
+
+ ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs);
+ if (ret)
+ return ret;
+
+ ret = hx509_certs_merge(context, certs, c->certs);
+ if (ret) {
+ hx509_certs_free(&certs);
+ return ret;
+ }
+
+ for (i = 0; i < c->val.len; i++) {
+ ret = match_localkeyid(context, c->val.data[i], certs);
+ if (ret == 0)
+ continue;
+ ret = match_keys(context, c->val.data[i], certs);
+ if (ret == 0)
+ continue;
+ }
+
+ *ret_certs = certs;
+
+ return 0;
+}
+
+int
+_hx509_collector_collect_private_keys(hx509_context context,
+ struct hx509_collector *c,
+ hx509_private_key **keys)
+{
+ int i, nkeys;
+
+ *keys = NULL;
+
+ for (i = 0, nkeys = 0; i < c->val.len; i++)
+ if (c->val.data[i]->private_key)
+ nkeys++;
+
+ *keys = calloc(nkeys + 1, sizeof(**keys));
+ if (*keys == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory");
+ return ENOMEM;
+ }
+
+ for (i = 0, nkeys = 0; i < c->val.len; i++) {
+ if (c->val.data[i]->private_key) {
+ (*keys)[nkeys++] = c->val.data[i]->private_key;
+ c->val.data[i]->private_key = NULL;
+ }
+ }
+ (*keys)[nkeys++] = NULL;
+
+ return 0;
+}
+
+
+void
+_hx509_collector_free(struct hx509_collector *c)
+{
+ int i;
+
+ if (c->unenvelop_certs)
+ hx509_certs_free(&c->unenvelop_certs);
+ if (c->certs)
+ hx509_certs_free(&c->certs);
+ for (i = 0; i < c->val.len; i++)
+ free_private_key(c->val.data[i]);
+ if (c->val.data)
+ free(c->val.data);
+ free(c);
+}
diff --git a/source4/heimdal/lib/hx509/crmf.asn1 b/source4/heimdal/lib/hx509/crmf.asn1
new file mode 100644
index 00000000000..4f02b268724
--- /dev/null
+++ b/source4/heimdal/lib/hx509/crmf.asn1
@@ -0,0 +1,113 @@
+-- $Id: crmf.asn1,v 1.1 2006/04/18 13:05:21 lha Exp $
+PKCS10 DEFINITIONS ::=
+
+BEGIN
+
+IMPORTS
+ Time,
+ GeneralName,
+ SubjectPublicKeyInfo,
+ RelativeDistinguishedName,
+ AttributeTypeAndValue,
+ Extension,
+ AlgorithmIdentifier
+ FROM rfc2459
+ heim_any
+ FROM heim;
+
+CRMFRDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+Controls ::= SEQUENCE -- SIZE(1..MAX) -- OF AttributeTypeAndValue
+
+-- XXX IMPLICIT brokenness
+POPOSigningKey ::= SEQUENCE {
+ poposkInput [0] IMPLICIT POPOSigningKeyInput OPTIONAL,
+ algorithmIdentifier AlgorithmIdentifier,
+ signature BIT STRING }
+
+PKMACValue ::= SEQUENCE {
+ algId AlgorithmIdentifier,
+ value BIT STRING
+}
+
+-- XXX IMPLICIT brokenness
+POPOSigningKeyInput ::= SEQUENCE {
+ authInfo CHOICE {
+ sender [0] IMPLICIT GeneralName,
+ publicKeyMAC PKMACValue
+ },
+ publicKey SubjectPublicKeyInfo
+} -- from CertTemplate
+
+
+PBMParameter ::= SEQUENCE {
+ salt OCTET STRING,
+ owf AlgorithmIdentifier,
+ iterationCount INTEGER,
+ mac AlgorithmIdentifier
+}
+
+SubsequentMessage ::= INTEGER {
+ encrCert (0),
+ challengeResp (1)
+}
+
+-- XXX IMPLICIT brokenness
+POPOPrivKey ::= CHOICE {
+ thisMessage [0] BIT STRING, -- Deprecated
+ subsequentMessage [1] IMPLICIT SubsequentMessage,
+ dhMAC [2] BIT STRING, -- Deprecated
+ agreeMAC [3] IMPLICIT PKMACValue,
+ encryptedKey [4] heim_any
+}
+
+-- XXX IMPLICIT brokenness
+ProofOfPossession ::= CHOICE {
+ raVerified [0] NULL,
+ signature [1] POPOSigningKey,
+ keyEncipherment [2] POPOPrivKey,
+ keyAgreement [3] POPOPrivKey
+}
+
+CertTemplate ::= SEQUENCE {
+ version [0] INTEGER OPTIONAL,
+ serialNumber [1] INTEGER OPTIONAL,
+ signingAlg [2] SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters heim_any OPTIONAL
+ } -- AlgorithmIdentifier -- OPTIONAL,
+ issuer [3] IMPLICIT CHOICE {
+ rdnSequence CRMFRDNSequence
+ } -- Name -- OPTIONAL,
+ validity [4] SEQUENCE {
+ notBefore [0] Time OPTIONAL,
+ notAfter [1] Time OPTIONAL
+ } -- OptionalValidity -- OPTIONAL,
+ subject [5] IMPLICIT CHOICE {
+ rdnSequence CRMFRDNSequence
+ } -- Name -- OPTIONAL,
+ publicKey [6] IMPLICIT SEQUENCE {
+ algorithm AlgorithmIdentifier,
+ subjectPublicKey BIT STRING OPTIONAL
+ } -- SubjectPublicKeyInfo -- OPTIONAL,
+ issuerUID [7] IMPLICIT BIT STRING OPTIONAL,
+ subjectUID [8] IMPLICIT BIT STRING OPTIONAL,
+ extensions [9] IMPLICIT SEQUENCE OF Extension OPTIONAL
+}
+
+CertRequest ::= SEQUENCE {
+ certReqId INTEGER,
+ certTemplate CertTemplate,
+ controls Controls OPTIONAL
+}
+
+CertReqMsg ::= SEQUENCE {
+ certReq CertRequest,
+ popo ProofOfPossession OPTIONAL,
+ regInfo SEQUENCE OF AttributeTypeAndValue OPTIONAL }
+
+CertReqMessages ::= SEQUENCE OF CertReqMsg
+
+
+END
+
diff --git a/source4/heimdal/lib/hx509/crypto.c b/source4/heimdal/lib/hx509/crypto.c
new file mode 100644
index 00000000000..dac0a8160b8
--- /dev/null
+++ b/source4/heimdal/lib/hx509/crypto.c
@@ -0,0 +1,2438 @@
+/*
+ * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: crypto.c,v 1.63 2007/01/09 10:52:05 lha Exp $");
+
+struct hx509_crypto;
+
+struct signature_alg;
+
+enum crypto_op_type {
+ COT_SIGN
+};
+
+
+struct hx509_private_key_ops {
+ const char *pemtype;
+ const heim_oid *(*key_oid)(void);
+ int (*get_spki)(hx509_context,
+ const hx509_private_key,
+ SubjectPublicKeyInfo *);
+ int (*export)(hx509_context context,
+ const hx509_private_key,
+ heim_octet_string *);
+ int (*import)(hx509_context,
+ const void *data,
+ size_t len,
+ hx509_private_key private_key);
+ int (*generate_private_key)(hx509_context context,
+ hx509_private_key private_key);
+ int (*handle_alg)(const hx509_private_key,
+ const AlgorithmIdentifier *,
+ enum crypto_op_type);
+ int (*sign)(hx509_context context,
+ const hx509_private_key,
+ const AlgorithmIdentifier *,
+ const heim_octet_string *,
+ AlgorithmIdentifier *,
+ heim_octet_string *);
+#if 0
+ const AlgorithmIdentifier *(*preferred_sig_alg)
+ (const hx509_private_key,
+ const hx509_peer_info);
+ int (*unwrap)(hx509_context context,
+ const hx509_private_key,
+ const AlgorithmIdentifier *,
+ const heim_octet_string *,
+ heim_octet_string *);
+#endif
+};
+
+struct hx509_private_key {
+ unsigned int ref;
+ const struct signature_alg *md;
+ const heim_oid *signature_alg;
+ union {
+ RSA *rsa;
+ void *keydata;
+ } private_key;
+ /* new crypto layer */
+ hx509_private_key_ops *ops;
+};
+
+/*
+ *
+ */
+
+struct signature_alg {
+ char *name;
+ const heim_oid *(*sig_oid)(void);
+ const AlgorithmIdentifier *(*sig_alg)(void);
+ const heim_oid *(*key_oid)(void);
+ const heim_oid *(*digest_oid)(void);
+ int flags;
+#define PROVIDE_CONF 1
+#define REQUIRE_SIGNER 2
+
+#define SIG_DIGEST 0x100
+#define SIG_PUBLIC_SIG 0x200
+#define SIG_PUBLIC_ENC 0x400
+#define SIG_SECRET 0x800
+
+ int (*verify_signature)(hx509_context context,
+ const struct signature_alg *,
+ const Certificate *,
+ const AlgorithmIdentifier *,
+ const heim_octet_string *,
+ const heim_octet_string *);
+ int (*create_signature)(hx509_context,
+ const struct signature_alg *,
+ const hx509_private_key,
+ const AlgorithmIdentifier *,
+ const heim_octet_string *,
+ AlgorithmIdentifier *,
+ heim_octet_string *);
+ int (*private_key2SPKI)(hx509_context,
+ hx509_private_key,
+ SubjectPublicKeyInfo *);
+};
+
+/*
+ *
+ */
+
+static BIGNUM *
+heim_int2BN(const heim_integer *i)
+{
+ BIGNUM *bn;
+
+ bn = BN_bin2bn(i->data, i->length, NULL);
+ BN_set_negative(bn, i->negative);
+ return bn;
+}
+
+static int
+rsa_verify_signature(hx509_context context,
+ const struct signature_alg *sig_alg,
+ const Certificate *signer,
+ const AlgorithmIdentifier *alg,
+ const heim_octet_string *data,
+ const heim_octet_string *sig)
+{
+ const SubjectPublicKeyInfo *spi;
+ DigestInfo di;
+ unsigned char *to;
+ int tosize, retsize;
+ int ret;
+ RSA *rsa;
+ RSAPublicKey pk;
+ size_t size;
+
+ memset(&di, 0, sizeof(di));
+
+ spi = &signer->tbsCertificate.subjectPublicKeyInfo;
+
+ rsa = RSA_new();
+ if (rsa == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+ ret = decode_RSAPublicKey(spi->subjectPublicKey.data,
+ spi->subjectPublicKey.length / 8,
+ &pk, &size);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "Failed to decode RSAPublicKey");
+ goto out;
+ }
+
+ rsa->n = heim_int2BN(&pk.modulus);
+ rsa->e = heim_int2BN(&pk.publicExponent);
+
+ free_RSAPublicKey(&pk);
+
+ if (rsa->n == NULL || rsa->e == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ goto out;
+ }
+
+ tosize = RSA_size(rsa);
+ to = malloc(tosize);
+ if (to == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ goto out;
+ }
+
+ retsize = RSA_public_decrypt(sig->length, (unsigned char *)sig->data,
+ to, rsa, RSA_PKCS1_PADDING);
+ if (retsize <= 0) {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ hx509_set_error_string(context, 0, ret,
+ "RSA public decrypt failed: %d", retsize);
+ free(to);
+ goto out;
+ }
+ if (retsize > tosize)
+ _hx509_abort("internal rsa decryption failure: ret > tosize");
+ ret = decode_DigestInfo(to, retsize, &di, &size);
+ free(to);
+ if (ret) {
+ goto out;
+ }
+
+ /* Check for extra data inside the sigature */
+ if (size != retsize) {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ hx509_set_error_string(context, 0, ret, "size from decryption mismatch");
+ goto out;
+ }
+
+ if (sig_alg->digest_oid &&
+ der_heim_oid_cmp(&di.digestAlgorithm.algorithm,
+ (*sig_alg->digest_oid)()) != 0)
+ {
+ ret = HX509_CRYPTO_OID_MISMATCH;
+ hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch");
+ goto out;
+ }
+
+ /* verify that the parameters are NULL or the NULL-type */
+ if (di.digestAlgorithm.parameters != NULL &&
+ (di.digestAlgorithm.parameters->length != 2 ||
+ memcmp(di.digestAlgorithm.parameters->data, "\x05\x00", 2) != 0))
+ {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ hx509_set_error_string(context, 0, ret, "Extra parameters inside RSA signature");
+ goto out;
+ }
+
+ ret = _hx509_verify_signature(context,
+ NULL,
+ &di.digestAlgorithm,
+ data,
+ &di.digest);
+ out:
+ free_DigestInfo(&di);
+ RSA_free(rsa);
+ return ret;
+}
+
+static int
+rsa_create_signature(hx509_context context,
+ const struct signature_alg *sig_alg,
+ const hx509_private_key signer,
+ const AlgorithmIdentifier *alg,
+ const heim_octet_string *data,
+ AlgorithmIdentifier *signatureAlgorithm,
+ heim_octet_string *sig)
+{
+ const AlgorithmIdentifier *digest_alg;
+ heim_octet_string indata;
+ const heim_oid *sig_oid;
+ DigestInfo di;
+ size_t size;
+ int ret;
+
+ if (alg)
+ sig_oid = &alg->algorithm;
+ else
+ sig_oid = signer->signature_alg;
+
+ if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha256WithRSAEncryption()) == 0) {
+ digest_alg = hx509_signature_sha256();
+ } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha1WithRSAEncryption()) == 0) {
+ digest_alg = hx509_signature_sha1();
+ } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) {
+ digest_alg = hx509_signature_md5();
+ } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) {
+ digest_alg = hx509_signature_md5();
+ } else if (der_heim_oid_cmp(sig_oid, oid_id_dsa_with_sha1()) == 0) {
+ digest_alg = hx509_signature_sha1();
+ } else
+ return HX509_ALG_NOT_SUPP;
+
+ if (signatureAlgorithm) {
+ ret = _hx509_set_digest_alg(signatureAlgorithm,
+ sig_oid, "\x05\x00", 2);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return ret;
+ }
+ }
+
+ memset(&di, 0, sizeof(di));
+
+ ret = _hx509_create_signature(context,
+ NULL,
+ digest_alg,
+ data,
+ &di.digestAlgorithm,
+ &di.digest);
+ if (ret)
+ return ret;
+ ASN1_MALLOC_ENCODE(DigestInfo,
+ indata.data,
+ indata.length,
+ &di,
+ &size,
+ ret);
+ free_DigestInfo(&di);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ return ret;
+ }
+ if (indata.length != size)
+ _hx509_abort("internal ASN.1 encoder error");
+
+ sig->length = RSA_size(signer->private_key.rsa);
+ sig->data = malloc(sig->length);
+ if (sig->data == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+
+ ret = RSA_private_encrypt(indata.length, indata.data,
+ sig->data,
+ signer->private_key.rsa,
+ RSA_PKCS1_PADDING);
+ der_free_octet_string(&indata);
+ if (ret <= 0) {
+ ret = HX509_CMS_FAILED_CREATE_SIGATURE;
+ hx509_set_error_string(context, 0, ret,
+ "RSA private decrypt failed: %d", ret);
+ return ret;
+ }
+ if (ret > sig->length)
+ _hx509_abort("RSA signature prelen longer the output len");
+
+ sig->length = ret;
+
+ return 0;
+}
+
+static int
+rsa_private_key_import(hx509_context context,
+ const void *data,
+ size_t len,
+ hx509_private_key private_key)
+{
+ const unsigned char *p = data;
+
+ private_key->private_key.rsa =
+ d2i_RSAPrivateKey(NULL, &p, len);
+ if (private_key->private_key.rsa == NULL) {
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "Failed to parse RSA key");
+ return HX509_PARSING_KEY_FAILED;
+ }
+ private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption();
+
+ return 0;
+}
+
+static int
+rsa_private_key2SPKI(hx509_context context,
+ hx509_private_key private_key,
+ SubjectPublicKeyInfo *spki)
+{
+ int len, ret;
+
+ memset(spki, 0, sizeof(*spki));
+
+ len = i2d_RSAPublicKey(private_key->private_key.rsa, NULL);
+
+ spki->subjectPublicKey.data = malloc(len);
+ if (spki->subjectPublicKey.data == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory");
+ return ENOMEM;
+ }
+ spki->subjectPublicKey.length = len * 8;
+
+ ret = _hx509_set_digest_alg(&spki->algorithm,
+ oid_id_pkcs1_rsaEncryption(),
+ "\x05\x00", 2);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "malloc - out of memory");
+ free(spki->subjectPublicKey.data);
+ spki->subjectPublicKey.data = NULL;
+ spki->subjectPublicKey.length = 0;
+ return ret;
+ }
+
+ {
+ unsigned char *pp = spki->subjectPublicKey.data;
+ i2d_RSAPublicKey(private_key->private_key.rsa, &pp);
+ }
+
+ return 0;
+}
+
+static int
+cb_func(int a, int b, BN_GENCB *c)
+{
+ return 1;
+}
+
+static int
+rsa_generate_private_key(hx509_context context, hx509_private_key private_key)
+{
+ BN_GENCB cb;
+ BIGNUM *e;
+ int ret;
+
+ static const int default_rsa_e = 65537;
+ static const int default_rsa_bits = 1024;
+
+ private_key->private_key.rsa = RSA_new();
+ if (private_key->private_key.rsa == NULL) {
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "Failed to generate RSA key");
+ return HX509_PARSING_KEY_FAILED;
+ }
+
+ e = BN_new();
+ BN_set_word(e, default_rsa_e);
+
+ BN_GENCB_set(&cb, cb_func, NULL);
+ ret = RSA_generate_key_ex(private_key->private_key.rsa,
+ default_rsa_bits, e, &cb);
+ BN_free(e);
+ if (ret != 1) {
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "Failed to generate RSA key");
+ return HX509_PARSING_KEY_FAILED;
+ }
+ private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption();
+
+ return 0;
+}
+
+static int
+rsa_private_key_export(hx509_context context,
+ const hx509_private_key key,
+ heim_octet_string *data)
+{
+ int ret;
+
+ data->data = NULL;
+ data->length = 0;
+
+ ret = i2d_RSAPrivateKey(key->private_key.rsa, NULL);
+ if (ret <= 0) {
+ ret = EINVAL;
+ hx509_set_error_string(context, 0, ret,
+ "Private key is not exportable");
+ return ret;
+ }
+
+ data->data = malloc(ret);
+ if (data->data == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "malloc out of memory");
+ return ret;
+ }
+ data->length = ret;
+
+ {
+ unsigned char *p = data->data;
+ i2d_RSAPrivateKey(key->private_key.rsa, &p);
+ }
+
+ return 0;
+}
+
+
+static hx509_private_key_ops rsa_private_key_ops = {
+ "RSA PRIVATE KEY",
+ oid_id_pkcs1_rsaEncryption,
+ rsa_private_key2SPKI,
+ rsa_private_key_export,
+ rsa_private_key_import,
+ rsa_generate_private_key
+};
+
+
+/*
+ *
+ */
+
+static int
+dsa_verify_signature(hx509_context context,
+ const struct signature_alg *sig_alg,
+ const Certificate *signer,
+ const AlgorithmIdentifier *alg,
+ const heim_octet_string *data,
+ const heim_octet_string *sig)
+{
+ const SubjectPublicKeyInfo *spi;
+ DSAPublicKey pk;
+ DSAParams param;
+ size_t size;
+ DSA *dsa;
+ int ret;
+
+ spi = &signer->tbsCertificate.subjectPublicKeyInfo;
+
+ dsa = DSA_new();
+ if (dsa == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+
+ ret = decode_DSAPublicKey(spi->subjectPublicKey.data,
+ spi->subjectPublicKey.length / 8,
+ &pk, &size);
+ if (ret)
+ goto out;
+
+ dsa->pub_key = heim_int2BN(&pk);
+
+ free_DSAPublicKey(&pk);
+
+ if (dsa->pub_key == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ goto out;
+ }
+
+ if (spi->algorithm.parameters == NULL) {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ hx509_set_error_string(context, 0, ret, "DSA parameters missing");
+ goto out;
+ }
+
+ ret = decode_DSAParams(spi->algorithm.parameters->data,
+ spi->algorithm.parameters->length,
+ &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
index 00000000000..770b71981a4
--- /dev/null
+++ b/source4/heimdal/lib/hx509/error.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: error.c,v 1.4 2006/11/16 15:08:09 lha Exp $");
+
+struct hx509_error_data {
+ hx509_error next;
+ int code;
+ char *msg;
+};
+
+static void
+free_error_string(hx509_error msg)
+{
+ while(msg) {
+ hx509_error m2 = msg->next;
+ free(msg->msg);
+ free(msg);
+ msg = m2;
+ }
+}
+
+void
+hx509_clear_error_string(hx509_context context)
+{
+ free_error_string(context->error);
+ context->error = NULL;
+}
+
+void
+hx509_set_error_stringv(hx509_context context, int flags, int code,
+ const char *fmt, va_list ap)
+{
+ hx509_error msg;
+
+ msg = calloc(1, sizeof(*msg));
+ if (msg == NULL) {
+ hx509_clear_error_string(context);
+ return;
+ }
+
+ if (vasprintf(&msg->msg, fmt, ap) == -1) {
+ hx509_clear_error_string(context);
+ free(msg);
+ return;
+ }
+ msg->code = code;
+
+ if (flags & HX509_ERROR_APPEND) {
+ msg->next = context->error;
+ context->error = msg;
+ } else {
+ free_error_string(context->error);
+ context->error = msg;
+ }
+}
+
+void
+hx509_set_error_string(hx509_context context, int flags, int code, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ hx509_set_error_stringv(context, flags, code, fmt, ap);
+ va_end(ap);
+}
+
+char *
+hx509_get_error_string(hx509_context context, int error_code)
+{
+ struct rk_strpool *p = NULL;
+ hx509_error msg;
+
+ if (context->error == NULL) {
+ const char *cstr;
+ char *str;
+
+ cstr = com_right(context->et_list, error_code);
+ if (cstr)
+ return strdup(cstr);
+ cstr = strerror(error_code);
+ if (cstr)
+ return strdup(cstr);
+ if (asprintf(&str, "<unknown error: %d>", error_code) == -1)
+ return NULL;
+ return str;
+ }
+
+ for (msg = context->error; msg; msg = msg->next)
+ p = rk_strpoolprintf(p, "%s%s", msg->msg,
+ msg->next != NULL ? "; " : "");
+
+ return rk_strpoolcollect(p);
+}
+
+void
+hx509_err(hx509_context context, int exit_code, int error_code, char *fmt, ...)
+{
+ va_list ap;
+ char *msg, *str;
+
+ va_start(ap, fmt);
+ vasprintf(&str, fmt, ap);
+ va_end(ap);
+ msg = hx509_get_error_string(context, error_code);
+ if (msg == NULL)
+ msg = "no error";
+
+ errx(exit_code, "%s: %s", str, msg);
+}
diff --git a/source4/heimdal/lib/hx509/file.c b/source4/heimdal/lib/hx509/file.c
new file mode 100644
index 00000000000..39497fc3a9a
--- /dev/null
+++ b/source4/heimdal/lib/hx509/file.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$ID$");
+
+int
+_hx509_map_file(const char *fn, void **data, size_t *length, struct stat *rsb)
+{
+ struct stat sb;
+ size_t len;
+ ssize_t l;
+ int ret;
+ void *d;
+ int fd;
+
+ *data = NULL;
+ *length = 0;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0)
+ return errno;
+
+ if (fstat(fd, &sb) < 0) {
+ ret = errno;
+ close(fd);
+ return ret;
+ }
+
+ len = sb.st_size;
+
+ d = malloc(len);
+ if (d == NULL) {
+ close(fd);
+ return ENOMEM;
+ }
+
+ l = read(fd, d, len);
+ close(fd);
+ if (l < 0 || l != len) {
+ free(d);
+ return EINVAL;
+ }
+
+ if (rsb)
+ *rsb = sb;
+ *data = d;
+ *length = len;
+ return 0;
+}
+
+void
+_hx509_unmap_file(void *data, size_t len)
+{
+ free(data);
+}
+
+int
+_hx509_write_file(const char *fn, const void *data, size_t length)
+{
+ ssize_t sz;
+ const unsigned char *p = data;
+ int fd;
+
+ fd = open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644);
+ if (fd < 0)
+ return errno;
+
+ do {
+ sz = write(fd, p, length);
+ if (sz < 0) {
+ int saved_errno = errno;
+ close(fd);
+ return saved_errno;
+ }
+ if (sz == 0)
+ break;
+ length -= sz;
+ } while (length > 0);
+
+ if (close(fd) == -1)
+ return errno;
+
+ return 0;
+}
diff --git a/source4/heimdal/lib/hx509/hx509-protos.h b/source4/heimdal/lib/hx509/hx509-protos.h
new file mode 100644
index 00000000000..4fcab70ff89
--- /dev/null
+++ b/source4/heimdal/lib/hx509/hx509-protos.h
@@ -0,0 +1,824 @@
+/* This is a generated file */
+#ifndef __hx509_protos_h__
+#define __hx509_protos_h__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+hx509_bitstring_print (
+ const heim_bit_string */*b*/,
+ hx509_vprint_func /*func*/,
+ void */*ctx*/);
+
+int
+hx509_ca_sign (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ hx509_cert /*signer*/,
+ hx509_cert */*certificate*/);
+
+int
+hx509_ca_sign_self (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ hx509_private_key /*signer*/,
+ hx509_cert */*certificate*/);
+
+int
+hx509_ca_tbs_add_eku (
+ hx509_context /*contex*/,
+ hx509_ca_tbs /*tbs*/,
+ const heim_oid */*oid*/);
+
+int
+hx509_ca_tbs_add_san_hostname (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ const char */*dnsname*/);
+
+int
+hx509_ca_tbs_add_san_otherName (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ const heim_oid */*oid*/,
+ const heim_octet_string */*os*/);
+
+int
+hx509_ca_tbs_add_san_pkinit (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ const char */*principal*/);
+
+int
+hx509_ca_tbs_add_san_rfc822name (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ const char */*rfc822Name*/);
+
+void
+hx509_ca_tbs_free (hx509_ca_tbs */*tbs*/);
+
+int
+hx509_ca_tbs_init (
+ hx509_context /*context*/,
+ hx509_ca_tbs */*tbs*/);
+
+int
+hx509_ca_tbs_set_ca (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ int /*pathLenConstraint*/);
+
+int
+hx509_ca_tbs_set_notAfter (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ time_t /*t*/);
+
+int
+hx509_ca_tbs_set_notAfter_lifetime (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ time_t /*delta*/);
+
+int
+hx509_ca_tbs_set_notBefore (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ time_t /*t*/);
+
+int
+hx509_ca_tbs_set_proxy (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ int /*pathLenConstraint*/);
+
+int
+hx509_ca_tbs_set_serialnumber (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ const heim_integer */*serialNumber*/);
+
+int
+hx509_ca_tbs_set_spki (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ const SubjectPublicKeyInfo */*spki*/);
+
+int
+hx509_ca_tbs_set_subject (
+ hx509_context /*context*/,
+ hx509_ca_tbs /*tbs*/,
+ hx509_name /*subject*/);
+
+int
+hx509_cert_check_eku (
+ hx509_context /*context*/,
+ hx509_cert /*cert*/,
+ const heim_oid */*eku*/,
+ int /*allow_any_eku*/);
+
+int
+hx509_cert_cmp (
+ hx509_cert /*p*/,
+ hx509_cert /*q*/);
+
+int
+hx509_cert_find_subjectAltName_otherName (
+ hx509_cert /*cert*/,
+ const heim_oid */*oid*/,
+ hx509_octet_string_list */*list*/);
+
+void
+hx509_cert_free (hx509_cert /*cert*/);
+
+hx509_cert_attribute
+hx509_cert_get_attribute (
+ hx509_cert /*cert*/,
+ const heim_oid */*oid*/);
+
+int
+hx509_cert_get_base_subject (
+ hx509_context /*context*/,
+ hx509_cert /*c*/,
+ hx509_name */*name*/);
+
+const char *
+hx509_cert_get_friendly_name (hx509_cert /*cert*/);
+
+int
+hx509_cert_get_issuer (
+ hx509_cert /*p*/,
+ hx509_name */*name*/);
+
+int
+hx509_cert_get_serialnumber (
+ hx509_cert /*p*/,
+ heim_integer */*i*/);
+
+int
+hx509_cert_get_subject (
+ hx509_cert /*p*/,
+ hx509_name */*name*/);
+
+int
+hx509_cert_init (
+ hx509_context /*context*/,
+ const Certificate */*c*/,
+ hx509_cert */*cert*/);
+
+int
+hx509_cert_keyusage_print (
+ hx509_context /*context*/,
+ hx509_cert /*c*/,
+ char **/*s*/);
+
+hx509_cert
+hx509_cert_ref (hx509_cert /*cert*/);
+
+int
+hx509_cert_set_friendly_name (
+ hx509_cert /*cert*/,
+ const char */*name*/);
+
+int
+hx509_certs_add (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ hx509_cert /*cert*/);
+
+int
+hx509_certs_append (
+ hx509_context /*context*/,
+ hx509_certs /*to*/,
+ hx509_lock /*lock*/,
+ const char */*name*/);
+
+int
+hx509_certs_end_seq (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ hx509_cursor /*cursor*/);
+
+int
+hx509_certs_find (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ const hx509_query */*q*/,
+ hx509_cert */*r*/);
+
+void
+hx509_certs_free (hx509_certs */*certs*/);
+
+int
+hx509_certs_info (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ int (*/*func*/)(void *, char *),
+ void */*ctx*/);
+
+int
+hx509_certs_init (
+ hx509_context /*context*/,
+ const char */*name*/,
+ int /*flags*/,
+ hx509_lock /*lock*/,
+ hx509_certs */*certs*/);
+
+int
+hx509_certs_iter (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ int (*/*fn*/)(hx509_context, void *, hx509_cert),
+ void */*ctx*/);
+
+int
+hx509_certs_merge (
+ hx509_context /*context*/,
+ hx509_certs /*to*/,
+ hx509_certs /*from*/);
+
+int
+hx509_certs_next_cert (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ hx509_cursor /*cursor*/,
+ hx509_cert */*cert*/);
+
+int
+hx509_certs_start_seq (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ hx509_cursor */*cursor*/);
+
+int
+hx509_certs_store (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ int /*flags*/,
+ hx509_lock /*lock*/);
+
+int
+hx509_ci_print_names (
+ hx509_context /*context*/,
+ void */*ctx*/,
+ hx509_cert /*c*/);
+
+void
+hx509_clear_error_string (hx509_context /*context*/);
+
+int
+hx509_cms_create_signed_1 (
+ hx509_context /*context*/,
+ const heim_oid */*eContentType*/,
+ const void */*data*/,
+ size_t /*length*/,
+ const AlgorithmIdentifier */*digest_alg*/,
+ hx509_cert /*cert*/,
+ hx509_peer_info /*peer*/,
+ hx509_certs /*anchors*/,
+ hx509_certs /*pool*/,
+ heim_octet_string */*signed_data*/);
+
+int
+hx509_cms_decrypt_encrypted (
+ hx509_context /*context*/,
+ hx509_lock /*lock*/,
+ const void */*data*/,
+ size_t /*length*/,
+ heim_oid */*contentType*/,
+ heim_octet_string */*content*/);
+
+int
+hx509_cms_envelope_1 (
+ hx509_context /*context*/,
+ hx509_cert /*cert*/,
+ const void */*data*/,
+ size_t /*length*/,
+ const heim_oid */*encryption_type*/,
+ const heim_oid */*contentType*/,
+ heim_octet_string */*content*/);
+
+int
+hx509_cms_unenvelope (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ int /*flags*/,
+ const void */*data*/,
+ size_t /*length*/,
+ const heim_octet_string */*encryptedContent*/,
+ heim_oid */*contentType*/,
+ heim_octet_string */*content*/);
+
+int
+hx509_cms_unwrap_ContentInfo (
+ const heim_octet_string */*in*/,
+ heim_oid */*oid*/,
+ heim_octet_string */*out*/,
+ int */*have_data*/);
+
+int
+hx509_cms_verify_signed (
+ hx509_context /*context*/,
+ hx509_verify_ctx /*ctx*/,
+ const void */*data*/,
+ size_t /*length*/,
+ hx509_certs /*store*/,
+ heim_oid */*contentType*/,
+ heim_octet_string */*content*/,
+ hx509_certs */*signer_certs*/);
+
+int
+hx509_cms_wrap_ContentInfo (
+ const heim_oid */*oid*/,
+ const heim_octet_string */*buf*/,
+ heim_octet_string */*res*/);
+
+void
+hx509_context_free (hx509_context */*context*/);
+
+int
+hx509_context_init (hx509_context */*context*/);
+
+void
+hx509_context_set_missing_revoke (
+ hx509_context /*context*/,
+ int /*flag*/);
+
+int
+hx509_crypto_available (
+ hx509_context /*context*/,
+ int /*type*/,
+ hx509_cert /*source*/,
+ AlgorithmIdentifier **/*val*/,
+ unsigned int */*plen*/);
+
+int
+hx509_crypto_decrypt (
+ hx509_crypto /*crypto*/,
+ const void */*data*/,
+ const size_t /*length*/,
+ heim_octet_string */*ivec*/,
+ heim_octet_string */*clear*/);
+
+void
+hx509_crypto_destroy (hx509_crypto /*crypto*/);
+
+int
+hx509_crypto_encrypt (
+ hx509_crypto /*crypto*/,
+ const void */*data*/,
+ const size_t /*length*/,
+ heim_octet_string */*ivec*/,
+ heim_octet_string **/*ciphertext*/);
+
+const heim_oid *
+hx509_crypto_enctype_by_name (const char */*name*/);
+
+void
+hx509_crypto_free_algs (
+ AlgorithmIdentifier */*val*/,
+ unsigned int /*len*/);
+
+int
+hx509_crypto_get_params (
+ hx509_context /*context*/,
+ hx509_crypto /*crypto*/,
+ const heim_octet_string */*ivec*/,
+ heim_octet_string */*param*/);
+
+int
+hx509_crypto_init (
+ hx509_context /*context*/,
+ const char */*provider*/,
+ const heim_oid */*enctype*/,
+ hx509_crypto */*crypto*/);
+
+const char *
+hx509_crypto_provider (hx509_crypto /*crypto*/);
+
+int
+hx509_crypto_select (
+ const hx509_context /*context*/,
+ int /*type*/,
+ const hx509_private_key /*source*/,
+ hx509_peer_info /*peer*/,
+ AlgorithmIdentifier */*selected*/);
+
+int
+hx509_crypto_set_key_data (
+ hx509_crypto /*crypto*/,
+ const void */*data*/,
+ size_t /*length*/);
+
+int
+hx509_crypto_set_key_name (
+ hx509_crypto /*crypto*/,
+ const char */*name*/);
+
+int
+hx509_crypto_set_params (
+ hx509_context /*context*/,
+ hx509_crypto /*crypto*/,
+ const heim_octet_string */*param*/,
+ heim_octet_string */*ivec*/);
+
+int
+hx509_crypto_set_random_key (
+ hx509_crypto /*crypto*/,
+ heim_octet_string */*key*/);
+
+void
+hx509_err (
+ hx509_context /*context*/,
+ int /*exit_code*/,
+ int /*error_code*/,
+ char */*fmt*/,
+ ...);
+
+void
+hx509_free_octet_string_list (hx509_octet_string_list */*list*/);
+
+char *
+hx509_get_error_string (
+ hx509_context /*context*/,
+ int /*error_code*/);
+
+int
+hx509_get_one_cert (
+ hx509_context /*context*/,
+ hx509_certs /*certs*/,
+ hx509_cert */*c*/);
+
+int
+hx509_lock_add_cert (
+ hx509_context /*context*/,
+ hx509_lock /*lock*/,
+ hx509_cert /*cert*/);
+
+int
+hx509_lock_add_certs (
+ hx509_context /*context*/,
+ hx509_lock /*lock*/,
+ hx509_certs /*certs*/);
+
+int
+hx509_lock_add_password (
+ hx509_lock /*lock*/,
+ const char */*password*/);
+
+int
+hx509_lock_command_string (
+ hx509_lock /*lock*/,
+ const char */*string*/);
+
+void
+hx509_lock_free (hx509_lock /*lock*/);
+
+int
+hx509_lock_init (
+ hx509_context /*context*/,
+ hx509_lock */*lock*/);
+
+int
+hx509_lock_prompt (
+ hx509_lock /*lock*/,
+ hx509_prompt */*prompt*/);
+
+void
+hx509_lock_reset_certs (
+ hx509_context /*context*/,
+ hx509_lock /*lock*/);
+
+void
+hx509_lock_reset_passwords (hx509_lock /*lock*/);
+
+void
+hx509_lock_reset_promper (hx509_lock /*lock*/);
+
+int
+hx509_lock_set_prompter (
+ hx509_lock /*lock*/,
+ hx509_prompter_fct /*prompt*/,
+ void */*data*/);
+
+int
+hx509_name_copy (
+ hx509_context /*context*/,
+ const hx509_name /*from*/,
+ hx509_name */*to*/);
+
+void
+hx509_name_free (hx509_name */*name*/);
+
+int
+hx509_name_is_null_p (const hx509_name /*name*/);
+
+int
+hx509_name_to_Name (
+ const hx509_name /*from*/,
+ Name */*to*/);
+
+int
+hx509_name_to_der_name (
+ const hx509_name /*name*/,
+ void **/*data*/,
+ size_t */*length*/);
+
+int
+hx509_name_to_string (
+ const hx509_name /*name*/,
+ char **/*str*/);
+
+int
+hx509_ocsp_request (
+ hx509_context /*context*/,
+ hx509_certs /*reqcerts*/,
+ hx509_certs /*pool*/,
+ hx509_cert /*signer*/,
+ const AlgorithmIdentifier */*digest*/,
+ heim_octet_string */*request*/,
+ heim_octet_string */*nonce*/);
+
+int
+hx509_ocsp_verify (
+ hx509_context /*context*/,
+ time_t /*now*/,
+ hx509_cert /*cert*/,
+ int /*flags*/,
+ const void */*data*/,
+ size_t /*length*/,
+ time_t */*expiration*/);
+
+void
+hx509_oid_print (
+ const heim_oid */*oid*/,
+ hx509_vprint_func /*func*/,
+ void */*ctx*/);
+
+int
+hx509_oid_sprint (
+ const heim_oid */*oid*/,
+ char **/*str*/);
+
+int
+hx509_parse_name (
+ hx509_context /*context*/,
+ const char */*str*/,
+ hx509_name */*name*/);
+
+int
+hx509_peer_info_alloc (
+ hx509_context /*context*/,
+ hx509_peer_info */*peer*/);
+
+int
+hx509_peer_info_free (hx509_peer_info /*peer*/);
+
+int
+hx509_peer_info_set_cert (
+ hx509_peer_info /*peer*/,
+ hx509_cert /*cert*/);
+
+int
+hx509_peer_info_set_cms_algs (
+ hx509_context /*context*/,
+ hx509_peer_info /*peer*/,
+ const AlgorithmIdentifier */*val*/,
+ size_t /*len*/);
+
+void
+hx509_print_func (
+ hx509_vprint_func /*func*/,
+ void */*ctx*/,
+ const char */*fmt*/,
+ ...);
+
+void
+hx509_print_stdout (
+ void */*ctx*/,
+ const char */*fmt*/,
+ va_list /*va*/);
+
+int
+hx509_prompt_hidden (hx509_prompt_type /*type*/);
+
+int
+hx509_query_alloc (
+ hx509_context /*context*/,
+ hx509_query **/*q*/);
+
+void
+hx509_query_free (
+ hx509_context /*context*/,
+ hx509_query */*q*/);
+
+int
+hx509_query_match_cmp_func (
+ hx509_query */*q*/,
+ int (*/*func*/)(void *, hx509_cert),
+ void */*ctx*/);
+
+int
+hx509_query_match_friendly_name (
+ hx509_query */*q*/,
+ const char */*name*/);
+
+int
+hx509_query_match_issuer_serial (
+ hx509_query */*q*/,
+ const Name */*issuer*/,
+ const heim_integer */*serialNumber*/);
+
+void
+hx509_query_match_option (
+ hx509_query */*q*/,
+ hx509_query_option /*option*/);
+
+int
+hx509_revoke_add_crl (
+ hx509_context /*context*/,
+ hx509_revoke_ctx /*ctx*/,
+ const char */*path*/);
+
+int
+hx509_revoke_add_ocsp (
+ hx509_context /*context*/,
+ hx509_revoke_ctx /*ctx*/,
+ const char */*path*/);
+
+void
+hx509_revoke_free (hx509_revoke_ctx */*ctx*/);
+
+int
+hx509_revoke_init (
+ hx509_context /*context*/,
+ hx509_revoke_ctx */*ctx*/);
+
+int
+hx509_revoke_ocsp_print (
+ hx509_context /*context*/,
+ const char */*path*/,
+ FILE */*out*/);
+
+int
+hx509_revoke_verify (
+ hx509_context /*context*/,
+ hx509_revoke_ctx /*ctx*/,
+ hx509_certs /*certs*/,
+ time_t /*now*/,
+ hx509_cert /*cert*/,
+ hx509_cert /*parent_cert*/);
+
+void
+hx509_set_error_string (
+ hx509_context /*context*/,
+ int /*flags*/,
+ int /*code*/,
+ const char */*fmt*/,
+ ...);
+
+void
+hx509_set_error_stringv (
+ hx509_context /*context*/,
+ int /*flags*/,
+ int /*code*/,
+ const char */*fmt*/,
+ va_list /*ap*/);
+
+const AlgorithmIdentifier *
+hx509_signature_md2 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_md5 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_rsa (void);
+
+const AlgorithmIdentifier *
+hx509_signature_rsa_with_md2 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_rsa_with_md5 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_rsa_with_sha1 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_rsa_with_sha256 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_rsa_with_sha384 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_rsa_with_sha512 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_sha1 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_sha256 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_sha384 (void);
+
+const AlgorithmIdentifier *
+hx509_signature_sha512 (void);
+
+int
+hx509_unparse_der_name (
+ const void */*data*/,
+ size_t /*length*/,
+ char **/*str*/);
+
+int
+hx509_validate_cert (
+ hx509_context /*context*/,
+ hx509_validate_ctx /*ctx*/,
+ hx509_cert /*cert*/);
+
+void
+hx509_validate_ctx_add_flags (
+ hx509_validate_ctx /*ctx*/,
+ int /*flags*/);
+
+void
+hx509_validate_ctx_free (hx509_validate_ctx /*ctx*/);
+
+int
+hx509_validate_ctx_init (
+ hx509_context /*context*/,
+ hx509_validate_ctx */*ctx*/);
+
+void
+hx509_validate_ctx_set_print (
+ hx509_validate_ctx /*ctx*/,
+ hx509_vprint_func /*func*/,
+ void */*c*/);
+
+void
+hx509_verify_attach_anchors (
+ hx509_verify_ctx /*ctx*/,
+ hx509_certs /*set*/);
+
+void
+hx509_verify_attach_revoke (
+ hx509_verify_ctx /*ctx*/,
+ hx509_revoke_ctx /*revoke_ctx*/);
+
+void
+hx509_verify_destroy_ctx (hx509_verify_ctx /*ctx*/);
+
+int
+hx509_verify_hostname (
+ hx509_context /*context*/,
+ const hx509_cert /*cert*/,
+ int /*require_match*/,
+ const char */*hostname*/,
+ const struct sockaddr */*sa*/,
+ int /*sa_size*/);
+
+int
+hx509_verify_init_ctx (
+ hx509_context /*context*/,
+ hx509_verify_ctx */*ctx*/);
+
+int
+hx509_verify_path (
+ hx509_context /*context*/,
+ hx509_verify_ctx /*ctx*/,
+ hx509_cert /*cert*/,
+ hx509_certs /*pool*/);
+
+void
+hx509_verify_set_proxy_certificate (
+ hx509_verify_ctx /*ctx*/,
+ int /*boolean*/);
+
+void
+hx509_verify_set_strict_rfc3280_verification (
+ hx509_verify_ctx /*ctx*/,
+ int /*boolean*/);
+
+void
+hx509_verify_set_time (
+ hx509_verify_ctx /*ctx*/,
+ time_t /*t*/);
+
+int
+hx509_verify_signature (
+ hx509_context /*context*/,
+ const hx509_cert /*signer*/,
+ const AlgorithmIdentifier */*alg*/,
+ const heim_octet_string */*data*/,
+ const heim_octet_string */*sig*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __hx509_protos_h__ */
diff --git a/source4/heimdal/lib/hx509/hx509.h b/source4/heimdal/lib/hx509/hx509.h
new file mode 100644
index 00000000000..70f29ea92d1
--- /dev/null
+++ b/source4/heimdal/lib/hx509/hx509.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: hx509.h,v 1.16 2007/01/09 10:52:05 lha Exp $ */
+
+typedef struct hx509_cert_attribute_data *hx509_cert_attribute;
+typedef struct hx509_cert_data *hx509_cert;
+typedef struct hx509_certs_data *hx509_certs;
+typedef struct hx509_context_data *hx509_context;
+typedef struct hx509_crypto_data *hx509_crypto;
+typedef struct hx509_lock_data *hx509_lock;
+typedef struct hx509_name_data *hx509_name;
+typedef struct hx509_private_key *hx509_private_key;
+typedef struct hx509_validate_ctx_data *hx509_validate_ctx;
+typedef struct hx509_verify_ctx_data *hx509_verify_ctx;
+typedef struct hx509_revoke_ctx_data *hx509_revoke_ctx;
+typedef struct hx509_query_data hx509_query;
+typedef void * hx509_cursor;
+typedef struct hx509_request_data *hx509_request;
+typedef struct hx509_error_data *hx509_error;
+typedef struct hx509_peer_info *hx509_peer_info;
+typedef struct hx509_ca_tbs *hx509_ca_tbs;
+
+typedef void (*hx509_vprint_func)(void *, const char *, va_list);
+
+enum {
+ HX509_VALIDATE_F_VALIDATE = 1,
+ HX509_VALIDATE_F_VERBOSE = 2
+};
+
+struct hx509_cert_attribute_data {
+ heim_oid oid;
+ heim_octet_string data;
+};
+
+typedef enum {
+ HX509_PROMPT_TYPE_PASSWORD = 0x1, /* password, hidden */
+ HX509_PROMPT_TYPE_QUESTION = 0x2, /* question, not hidden */
+ HX509_PROMPT_TYPE_INFO = 0x4 /* infomation, reply doesn't matter */
+} hx509_prompt_type;
+
+typedef struct hx509_prompt {
+ const char *prompt;
+ hx509_prompt_type type;
+ heim_octet_string reply;
+} hx509_prompt;
+
+typedef int (*hx509_prompter_fct)(void *, const hx509_prompt *);
+
+typedef struct hx509_octet_string_list {
+ size_t len;
+ heim_octet_string *val;
+} hx509_octet_string_list;
+
+/*
+ * Options passed to hx509_query_match_option.
+ */
+typedef enum {
+ HX509_QUERY_OPTION_PRIVATE_KEY = 1,
+ HX509_QUERY_OPTION_KU_ENCIPHERMENT = 2,
+ HX509_QUERY_OPTION_KU_DIGITALSIGNATURE = 3,
+ HX509_QUERY_OPTION_KU_KEYCERTSIGN = 4,
+ HX509_QUERY_OPTION_END = 0xffff
+} hx509_query_option;
+
+/* flags to hx509_certs_init */
+#define HX509_CERTS_CREATE 0x01
+
+/* flags to hx509_set_error_string */
+#define HX509_ERROR_APPEND 0x01
+
+/* flags to hx509_cms_unenvelope */
+#define HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT 0x01
+
+/* selectors passed to hx509_crypto_select and hx509_crypto_available */
+#define HX509_SELECT_ALL 0
+#define HX509_SELECT_DIGEST 1
+#define HX509_SELECT_PUBLIC_SIG 2
+#define HX509_SELECT_PUBLIC_ENC 3
+
+#include <hx509-protos.h>
diff --git a/source4/heimdal/lib/hx509/hx509_err.c b/source4/heimdal/lib/hx509/hx509_err.c
new file mode 100644
index 00000000000..339759d6b75
--- /dev/null
+++ b/source4/heimdal/lib/hx509/hx509_err.c
@@ -0,0 +1,157 @@
+/* Generated from /home/data/samba/samba4/svn/source/heimdal/lib/hx509/hx509_err.et */
+/* $Id: hx509_err.et,v 1.19 2006/12/30 23:05:39 lha Exp $ */
+
+#include <stddef.h>
+#include <com_err.h>
+#include "hx509_err.h"
+
+static const char *hx_error_strings[] = {
+ /* 000 */ "ASN.1 failed call to system time library",
+ /* 001 */ "Extension not found",
+ /* 002 */ "Certification path not found",
+ /* 003 */ "Parent certificate is not a CA",
+ /* 004 */ "CA path too deep",
+ /* 005 */ "Signature algorithm not supported",
+ /* 006 */ "Signature algorithm doesn't match certificate key",
+ /* 007 */ "Certificate used before it became valid",
+ /* 008 */ "Certificate used after it became invalid",
+ /* 009 */ "Private key required for the operation is missing",
+ /* 010 */ "Algorithm not supported",
+ /* 011 */ "Issuer couldn't be found",
+ /* 012 */ "Error verifing constraints",
+ /* 013 */ "Number too large",
+ /* 014 */ "Error while verifing name constraints",
+ /* 015 */ "Path is too long, failed to find valid anchor",
+ /* 016 */ "Required keyusage for this certificate is missing",
+ /* 017 */ "Certificate not found",
+ /* 018 */ "Unknown lock command",
+ /* 019 */ "Parent certificate is a CA",
+ /* 020 */ "Extra data was found after the structure",
+ /* 021 */ "Proxy certificate is invalid",
+ /* 022 */ "Proxy certificate name is wrong",
+ /* 023 */ "Name is malformated",
+ /* 024 */ "Certificate is malformated",
+ /* 025 */ "Certificate is missing a required EKU",
+ /* 026 */ "Proxy certificate not canonicalize",
+ /* 027 */ "Reserved hx error (27)",
+ /* 028 */ "Reserved hx error (28)",
+ /* 029 */ "Reserved hx error (29)",
+ /* 030 */ "Reserved hx error (30)",
+ /* 031 */ "Reserved hx error (31)",
+ /* 032 */ "Failed to create signature",
+ /* 033 */ "Missing signer data",
+ /* 034 */ "Couldn't find signers certificate",
+ /* 035 */ "No data to perform the operation on",
+ /* 036 */ "Data in the message is invalid",
+ /* 037 */ "Padding in the message invalid",
+ /* 038 */ "Couldn't find recipient certificate",
+ /* 039 */ "Mismatch bewteen signed type and unsigned type",
+ /* 040 */ "Reserved hx error (40)",
+ /* 041 */ "Reserved hx error (41)",
+ /* 042 */ "Reserved hx error (42)",
+ /* 043 */ "Reserved hx error (43)",
+ /* 044 */ "Reserved hx error (44)",
+ /* 045 */ "Reserved hx error (45)",
+ /* 046 */ "Reserved hx error (46)",
+ /* 047 */ "Reserved hx error (47)",
+ /* 048 */ "Reserved hx error (48)",
+ /* 049 */ "Reserved hx error (49)",
+ /* 050 */ "Reserved hx error (50)",
+ /* 051 */ "Reserved hx error (51)",
+ /* 052 */ "Reserved hx error (52)",
+ /* 053 */ "Reserved hx error (53)",
+ /* 054 */ "Reserved hx error (54)",
+ /* 055 */ "Reserved hx error (55)",
+ /* 056 */ "Reserved hx error (56)",
+ /* 057 */ "Reserved hx error (57)",
+ /* 058 */ "Reserved hx error (58)",
+ /* 059 */ "Reserved hx error (59)",
+ /* 060 */ "Reserved hx error (60)",
+ /* 061 */ "Reserved hx error (61)",
+ /* 062 */ "Reserved hx error (62)",
+ /* 063 */ "Reserved hx error (63)",
+ /* 064 */ "Internal error in the crypto engine",
+ /* 065 */ "External error in the crypto engine",
+ /* 066 */ "Signature missing for data",
+ /* 067 */ "Signature is not valid",
+ /* 068 */ "Sigature doesn't provide confidentiality",
+ /* 069 */ "Invalid format on signature",
+ /* 070 */ "Mismatch bewteen oids",
+ /* 071 */ "No prompter function defined",
+ /* 072 */ "Signature require signer, but non available",
+ /* 073 */ "RSA public encyption failed",
+ /* 074 */ "RSA public encyption failed",
+ /* 075 */ "RSA private decryption failed",
+ /* 076 */ "RSA private decryption failed",
+ /* 077 */ "Reserved hx error (77)",
+ /* 078 */ "Reserved hx error (78)",
+ /* 079 */ "Reserved hx error (79)",
+ /* 080 */ "Reserved hx error (80)",
+ /* 081 */ "Reserved hx error (81)",
+ /* 082 */ "Reserved hx error (82)",
+ /* 083 */ "Reserved hx error (83)",
+ /* 084 */ "Reserved hx error (84)",
+ /* 085 */ "Reserved hx error (85)",
+ /* 086 */ "Reserved hx error (86)",
+ /* 087 */ "Reserved hx error (87)",
+ /* 088 */ "Reserved hx error (88)",
+ /* 089 */ "Reserved hx error (89)",
+ /* 090 */ "Reserved hx error (90)",
+ /* 091 */ "Reserved hx error (91)",
+ /* 092 */ "Reserved hx error (92)",
+ /* 093 */ "Reserved hx error (93)",
+ /* 094 */ "Reserved hx error (94)",
+ /* 095 */ "Reserved hx error (95)",
+ /* 096 */ "CRL used before it became valid",
+ /* 097 */ "CRL used after it became invalid",
+ /* 098 */ "CRL have invalid format",
+ /* 099 */ "Certificate is included in CRL",
+ /* 100 */ "No revoke status found for certificates",
+ /* 101 */ "Unknown extension",
+ /* 102 */ "Got wrong CRL/OCSP data from server",
+ /* 103 */ "Doesn't have same parent as other certificaes",
+ /* 104 */ "Reserved hx error (104)",
+ /* 105 */ "Reserved hx error (105)",
+ /* 106 */ "Reserved hx error (106)",
+ /* 107 */ "Reserved hx error (107)",
+ /* 108 */ "No local key attribute",
+ /* 109 */ "Failed to parse key",
+ /* 110 */ "Unsupported operation",
+ /* 111 */ "Unimplemented operation",
+ /* 112 */ "Failed to parse name",
+ /* 113 */ "Reserved hx error (113)",
+ /* 114 */ "Reserved hx error (114)",
+ /* 115 */ "Reserved hx error (115)",
+ /* 116 */ "Reserved hx error (116)",
+ /* 117 */ "Reserved hx error (117)",
+ /* 118 */ "Reserved hx error (118)",
+ /* 119 */ "Reserved hx error (119)",
+ /* 120 */ "Reserved hx error (120)",
+ /* 121 */ "Reserved hx error (121)",
+ /* 122 */ "Reserved hx error (122)",
+ /* 123 */ "Reserved hx error (123)",
+ /* 124 */ "Reserved hx error (124)",
+ /* 125 */ "Reserved hx error (125)",
+ /* 126 */ "Reserved hx error (126)",
+ /* 127 */ "Reserved hx error (127)",
+ /* 128 */ "No smartcard reader/device found",
+ /* 129 */ "No smartcard in reader",
+ /* 130 */ "No supported mech(s)",
+ /* 131 */ "Token or slot failed in inconsistent way",
+ /* 132 */ "Failed to open session to slot",
+ /* 133 */ "Failed to login to slot",
+ /* 134 */ "Failed to load PKCS module",
+ NULL
+};
+
+#define num_errors 135
+
+void initialize_hx_error_table_r(struct et_list **list)
+{
+ initialize_error_table_r(list, hx_error_strings, num_errors, ERROR_TABLE_BASE_hx);
+}
+
+void initialize_hx_error_table(void)
+{
+ init_error_table(hx_error_strings, ERROR_TABLE_BASE_hx, num_errors);
+}
diff --git a/source4/heimdal/lib/hx509/hx509_err.et b/source4/heimdal/lib/hx509/hx509_err.et
new file mode 100644
index 00000000000..54ec177e473
--- /dev/null
+++ b/source4/heimdal/lib/hx509/hx509_err.et
@@ -0,0 +1,100 @@
+#
+# Error messages for the hx509 library
+#
+# This might look like a com_err file, but is not
+#
+id "$Id: hx509_err.et,v 1.19 2006/12/30 23:05:39 lha Exp $"
+
+error_table hx
+prefix HX509
+
+# path validateion and construction related errors
+error_code BAD_TIMEFORMAT, "ASN.1 failed call to system time library"
+error_code EXTENSION_NOT_FOUND, "Extension not found"
+error_code NO_PATH, "Certification path not found"
+error_code PARENT_NOT_CA, "Parent certificate is not a CA"
+error_code CA_PATH_TOO_DEEP, "CA path too deep"
+error_code SIG_ALG_NO_SUPPORTED, "Signature algorithm not supported"
+error_code SIG_ALG_DONT_MATCH_KEY_ALG, "Signature algorithm doesn't match certificate key"
+error_code CERT_USED_BEFORE_TIME, "Certificate used before it became valid"
+error_code CERT_USED_AFTER_TIME, "Certificate used after it became invalid"
+error_code PRIVATE_KEY_MISSING, "Private key required for the operation is missing"
+error_code ALG_NOT_SUPP, "Algorithm not supported"
+error_code ISSUER_NOT_FOUND, "Issuer couldn't be found"
+error_code VERIFY_CONSTRAINTS, "Error verifing constraints"
+error_code RANGE, "Number too large"
+error_code NAME_CONSTRAINT_ERROR, "Error while verifing name constraints"
+error_code PATH_TOO_LONG, "Path is too long, failed to find valid anchor"
+error_code KU_CERT_MISSING, "Required keyusage for this certificate is missing"
+error_code CERT_NOT_FOUND, "Certificate not found"
+error_code UNKNOWN_LOCK_COMMAND, "Unknown lock command"
+error_code PARENT_IS_CA, "Parent certificate is a CA"
+error_code EXTRA_DATA_AFTER_STRUCTURE, "Extra data was found after the structure"
+error_code PROXY_CERT_INVALID, "Proxy certificate is invalid"
+error_code PROXY_CERT_NAME_WRONG, "Proxy certificate name is wrong"
+error_code NAME_MALFORMED, "Name is malformated"
+error_code CERTIFICATE_MALFORMED, "Certificate is malformated"
+error_code CERTIFICATE_MISSING_EKU, "Certificate is missing a required EKU"
+error_code PROXY_CERTIFICATE_NOT_CANONICALIZED, "Proxy certificate not canonicalize"
+
+# cms related errors
+index 32
+prefix HX509_CMS
+error_code FAILED_CREATE_SIGATURE, "Failed to create signature"
+error_code MISSING_SIGNER_DATA, "Missing signer data"
+error_code SIGNER_NOT_FOUND, "Couldn't find signers certificate"
+error_code NO_DATA_AVAILABLE, "No data to perform the operation on"
+error_code INVALID_DATA, "Data in the message is invalid"
+error_code PADDING_ERROR, "Padding in the message invalid"
+error_code NO_RECIPIENT_CERTIFICATE, "Couldn't find recipient certificate"
+error_code DATA_OID_MISMATCH, "Mismatch bewteen signed type and unsigned type"
+
+# crypto related errors
+index 64
+prefix HX509_CRYPTO
+error_code INTERNAL_ERROR, "Internal error in the crypto engine"
+error_code EXTERNAL_ERROR, "External error in the crypto engine"
+error_code SIGNATURE_MISSING, "Signature missing for data"
+error_code BAD_SIGNATURE, "Signature is not valid"
+error_code SIG_NO_CONF, "Sigature doesn't provide confidentiality"
+error_code SIG_INVALID_FORMAT, "Invalid format on signature"
+error_code OID_MISMATCH, "Mismatch bewteen oids"
+error_code NO_PROMPTER, "No prompter function defined"
+error_code SIGNATURE_WITHOUT_SIGNER, "Signature require signer, but non available"
+error_code RSA_PUBLIC_ENCRYPT, "RSA public encyption failed"
+error_code RSA_PRIVATE_ENCRYPT, "RSA public encyption failed"
+error_code RSA_PUBLIC_DECRYPT, "RSA private decryption failed"
+error_code RSA_PRIVATE_DECRYPT, "RSA private decryption failed"
+
+# revoke related errors
+index 96
+prefix HX509
+error_code CRL_USED_BEFORE_TIME, "CRL used before it became valid"
+error_code CRL_USED_AFTER_TIME, "CRL used after it became invalid"
+error_code CRL_INVALID_FORMAT, "CRL have invalid format"
+error_code CRL_CERT_REVOKED, "Certificate is included in CRL"
+error_code REVOKE_STATUS_MISSING, "No revoke status found for certificates"
+error_code CRL_UNKNOWN_EXTENSION, "Unknown extension"
+error_code REVOKE_WRONG_DATA, "Got wrong CRL/OCSP data from server"
+error_code REVOKE_NOT_SAME_PARENT, "Doesn't have same parent as other certificaes"
+
+# misc error
+index 108
+error_code LOCAL_ATTRIBUTE_MISSING, "No local key attribute"
+error_code PARSING_KEY_FAILED, "Failed to parse key"
+error_code UNSUPPORTED_OPERATION, "Unsupported operation"
+error_code UNIMPLEMENTED_OPERATION, "Unimplemented operation"
+error_code PARSING_NAME_FAILED, "Failed to parse name"
+
+# keystore related error
+index 128
+prefix HX509_PKCS11
+error_code NO_SLOT, "No smartcard reader/device found"
+error_code NO_TOKEN, "No smartcard in reader"
+error_code NO_MECH, "No supported mech(s)"
+error_code TOKEN_CONFUSED, "Token or slot failed in inconsistent way"
+error_code OPEN_SESSION, "Failed to open session to slot"
+error_code LOGIN, "Failed to login to slot"
+error_code LOAD, "Failed to load PKCS module"
+
+end
diff --git a/source4/heimdal/lib/hx509/hx_locl.h b/source4/heimdal/lib/hx509/hx_locl.h
new file mode 100644
index 00000000000..78d158f8b19
--- /dev/null
+++ b/source4/heimdal/lib/hx509/hx_locl.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: hx_locl.h,v 1.30 2007/01/09 10:52:06 lha Exp $ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <err.h>
+#include <getarg.h>
+#include <base64.h>
+#include <hex.h>
+#include <roken.h>
+#include <com_err.h>
+#include <parse_units.h>
+#include <parse_bytes.h>
+
+#include <krb5-types.h>
+
+#include <rfc2459_asn1.h>
+#include <cms_asn1.h>
+#include <pkcs8_asn1.h>
+#include <pkcs9_asn1.h>
+#include <pkcs12_asn1.h>
+#include <ocsp_asn1.h>
+#include <pkcs10_asn1.h>
+#include <asn1_err.h>
+#include <pkinit_asn1.h>
+
+#include <der.h>
+
+#include "crypto-headers.h"
+
+struct hx509_keyset_ops;
+struct hx509_collector;
+typedef struct hx509_path hx509_path;
+
+#include <hx509.h>
+
+typedef void (*_hx509_cert_release_func)(struct hx509_cert_data *, void *);
+
+typedef struct hx509_private_key_ops hx509_private_key_ops;
+
+#include <hx509-private.h>
+#include <hx509_err.h>
+
+struct hx509_peer_info {
+ hx509_cert cert;
+ AlgorithmIdentifier *val;
+ size_t len;
+};
+
+#define HX509_CERTS_FIND_SERIALNUMBER 1
+#define HX509_CERTS_FIND_ISSUER 2
+#define HX509_CERTS_FIND_SUBJECT 4
+#define HX509_CERTS_FIND_ISSUER_KEY_ID 8
+#define HX509_CERTS_FIND_SUBJECT_KEY_ID 16
+
+struct hx509_name_data {
+ Name der_name;
+};
+
+struct hx509_path {
+ size_t len;
+ hx509_cert *val;
+};
+
+struct hx509_query_data {
+ int match;
+#define HX509_QUERY_FIND_ISSUER_CERT 0x000001
+#define HX509_QUERY_MATCH_SERIALNUMBER 0x000002
+#define HX509_QUERY_MATCH_ISSUER_NAME 0x000004
+#define HX509_QUERY_MATCH_SUBJECT_NAME 0x000008
+#define HX509_QUERY_MATCH_SUBJECT_KEY_ID 0x000010
+#define HX509_QUERY_MATCH_ISSUER_ID 0x000020
+#define HX509_QUERY_PRIVATE_KEY 0x000040
+#define HX509_QUERY_KU_ENCIPHERMENT 0x000080
+#define HX509_QUERY_KU_DIGITALSIGNATURE 0x000100
+#define HX509_QUERY_KU_KEYCERTSIGN 0x000200
+#define HX509_QUERY_KU_CRLSIGN 0x000400
+#define HX509_QUERY_KU_NONREPUDIATION 0x000800
+#define HX509_QUERY_KU_KEYAGREEMENT 0x001000
+#define HX509_QUERY_KU_DATAENCIPHERMENT 0x002000
+#define HX509_QUERY_ANCHOR 0x004000
+#define HX509_QUERY_MATCH_CERTIFICATE 0x008000
+#define HX509_QUERY_MATCH_LOCAL_KEY_ID 0x010000
+#define HX509_QUERY_NO_MATCH_PATH 0x020000
+#define HX509_QUERY_MATCH_FRIENDLY_NAME 0x040000
+#define HX509_QUERY_MATCH_FUNCTION 0x080000
+#define HX509_QUERY_MATCH_KEY_HASH_SHA1 0x100000
+#define HX509_QUERY_MATCH_TIME 0x200000
+#define HX509_QUERY_MASK 0x3fffff
+ Certificate *subject;
+ Certificate *certificate;
+ heim_integer *serial;
+ heim_octet_string *subject_id;
+ heim_octet_string *local_key_id;
+ Name *issuer_name;
+ Name *subject_name;
+ hx509_path *path;
+ char *friendlyname;
+ int (*cmp_func)(void *, hx509_cert);
+ void *cmp_func_ctx;
+ heim_octet_string *keyhash_sha1;
+ time_t timenow;
+};
+
+struct hx509_keyset_ops {
+ char *name;
+ int flags;
+ int (*init)(hx509_context, hx509_certs, void **,
+ int, const char *, hx509_lock);
+ int (*store)(hx509_context, hx509_certs, void *, int, hx509_lock);
+ int (*free)(hx509_certs, void *);
+ int (*add)(hx509_context, hx509_certs, void *, hx509_cert);
+ int (*query)(hx509_context, hx509_certs, void *,
+ const hx509_query *, hx509_cert *);
+ int (*iter_start)(hx509_context, hx509_certs, void *, void **);
+ int (*iter)(hx509_context, hx509_certs, void *, void *, hx509_cert *);
+ int (*iter_end)(hx509_context, hx509_certs, void *, void *);
+ int (*printinfo)(hx509_context, hx509_certs,
+ void *, int (*)(void *, char *), void *);
+ int (*getkeys)(hx509_context, hx509_certs, void *, hx509_private_key **);
+ int (*addkey)(hx509_context, hx509_certs, void *, hx509_private_key);
+};
+
+struct _hx509_password {
+ size_t len;
+ char **val;
+};
+
+extern hx509_lock _hx509_empty_lock;
+
+struct hx509_context_data {
+ struct hx509_keyset_ops **ks_ops;
+ int ks_num_ops;
+ int flags;
+#define HX509_CTX_VERIFY_MISSING_OK 1
+ int ocsp_time_diff;
+#define HX509_DEFAULT_OCSP_TIME_DIFF (5*60)
+ hx509_error error;
+ struct et_list *et_list;
+};
+
+/* _hx509_calculate_path flag field */
+#define HX509_CALCULATE_PATH_NO_ANCHOR 1
diff --git a/source4/heimdal/lib/hx509/keyset.c b/source4/heimdal/lib/hx509/keyset.c
new file mode 100644
index 00000000000..c3d5ee210c2
--- /dev/null
+++ b/source4/heimdal/lib/hx509/keyset.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: keyset.c,v 1.18 2007/01/09 10:52:07 lha Exp $");
+
+struct hx509_certs_data {
+ struct hx509_keyset_ops *ops;
+ void *ops_data;
+};
+
+static struct hx509_keyset_ops *
+_hx509_ks_type(hx509_context context, const char *type)
+{
+ int i;
+
+ for (i = 0; i < context->ks_num_ops; i++)
+ if (strcasecmp(type, context->ks_ops[i]->name) == 0)
+ return context->ks_ops[i];
+
+ return NULL;
+}
+
+void
+_hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
+{
+ struct hx509_keyset_ops **val;
+
+ if (_hx509_ks_type(context, ops->name))
+ return;
+
+ val = realloc(context->ks_ops,
+ (context->ks_num_ops + 1) * sizeof(context->ks_ops[0]));
+ if (val == NULL)
+ return;
+ val[context->ks_num_ops] = ops;
+ context->ks_ops = val;
+ context->ks_num_ops++;
+}
+
+int
+hx509_certs_init(hx509_context context,
+ const char *name, int flags,
+ hx509_lock lock, hx509_certs *certs)
+{
+ struct hx509_keyset_ops *ops;
+ const char *residue;
+ hx509_certs c;
+ char *type;
+ int ret;
+
+ *certs = NULL;
+
+ residue = strchr(name, ':');
+ if (residue) {
+ type = malloc(residue - name + 1);
+ if (type)
+ strlcpy(type, name, residue - name + 1);
+ residue++;
+ if (residue[0] == '\0')
+ residue = NULL;
+ } else {
+ type = strdup("MEMORY");
+ residue = name;
+ }
+ if (type == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ ops = _hx509_ks_type(context, type);
+ free(type);
+ if (ops == NULL) {
+ hx509_set_error_string(context, 0, ENOENT,
+ "Keyset type %s is not supported", type);
+ return ENOENT;
+ }
+ c = calloc(1, sizeof(*c));
+ if (c == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+ c->ops = ops;
+
+ ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
+ if (ret) {
+ free(c);
+ return ret;
+ }
+
+ *certs = c;
+ return 0;
+}
+
+int
+hx509_certs_store(hx509_context context,
+ hx509_certs certs,
+ int flags,
+ hx509_lock lock)
+{
+ if (certs->ops->store == NULL) {
+ hx509_set_error_string(context, 0, EINVAL,
+ "keystore if type %s doesn't support "
+ "store operation",
+ certs->ops->name);
+ return EINVAL;
+ }
+
+ return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
+}
+
+
+void
+hx509_certs_free(hx509_certs *certs)
+{
+ if (*certs) {
+ (*(*certs)->ops->free)(*certs, (*certs)->ops_data);
+ free(*certs);
+ *certs = NULL;
+ }
+}
+
+int
+hx509_certs_start_seq(hx509_context context,
+ hx509_certs certs,
+ hx509_cursor *cursor)
+{
+ int ret;
+
+ if (certs->ops->iter_start == NULL) {
+ hx509_set_error_string(context, 0, ENOENT,
+ "Keyset type %s doesn't support iteration",
+ certs->ops->name);
+ return ENOENT;
+ }
+
+ ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int
+hx509_certs_next_cert(hx509_context context,
+ hx509_certs certs,
+ hx509_cursor cursor,
+ hx509_cert *cert)
+{
+ *cert = NULL;
+ return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
+}
+
+int
+hx509_certs_end_seq(hx509_context context,
+ hx509_certs certs,
+ hx509_cursor cursor)
+{
+ (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor);
+ return 0;
+}
+
+
+int
+hx509_certs_iter(hx509_context context,
+ hx509_certs certs,
+ int (*fn)(hx509_context, void *, hx509_cert),
+ void *ctx)
+{
+ hx509_cursor cursor;
+ hx509_cert c;
+ int ret;
+
+ ret = hx509_certs_start_seq(context, certs, &cursor);
+ if (ret)
+ return ret;
+
+ while (1) {
+ ret = hx509_certs_next_cert(context, certs, cursor, &c);
+ if (ret)
+ break;
+ if (c == NULL) {
+ ret = 0;
+ break;
+ }
+ ret = (*fn)(context, ctx, c);
+ hx509_cert_free(c);
+ if (ret)
+ break;
+ }
+
+ hx509_certs_end_seq(context, certs, cursor);
+
+ return ret;
+}
+
+int
+hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
+{
+ Certificate *cert;
+ hx509_name n;
+ char *s, *i;
+
+ cert = _hx509_get_cert(c);
+
+ _hx509_name_from_Name(&cert->tbsCertificate.subject, &n);
+ hx509_name_to_string(n, &s);
+ hx509_name_free(&n);
+ _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n);
+ hx509_name_to_string(n, &i);
+ hx509_name_free(&n);
+ fprintf(ctx, "subject: %s\nissuer: %s\n", s, i);
+ free(s);
+ free(i);
+ return 0;
+}
+
+/*
+ * The receiving keyset `certs´ will either increase reference counter
+ * of the `cert´ or make a deep copy, either way, the caller needs to
+ * free the `cert´ itself.
+ */
+
+int
+hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
+{
+ if (certs->ops->add == NULL) {
+ hx509_set_error_string(context, 0, ENOENT,
+ "Keyset type %s doesn't support add operation",
+ certs->ops->name);
+ return ENOENT;
+ }
+
+ return (*certs->ops->add)(context, certs, certs->ops_data, cert);
+}
+
+int
+hx509_certs_find(hx509_context context,
+ hx509_certs certs,
+ const hx509_query *q,
+ hx509_cert *r)
+{
+ hx509_cursor cursor;
+ hx509_cert c;
+ int ret;
+
+ *r = NULL;
+
+ if (certs->ops->query)
+ return (*certs->ops->query)(context, certs, certs->ops_data, q, r);
+
+ ret = hx509_certs_start_seq(context, certs, &cursor);
+ if (ret)
+ return ret;
+
+ c = NULL;
+ while (1) {
+ ret = hx509_certs_next_cert(context, certs, cursor, &c);
+ if (ret)
+ break;
+ if (c == NULL)
+ break;
+ if (_hx509_query_match_cert(context, q, c)) {
+ *r = c;
+ break;
+ }
+ hx509_cert_free(c);
+ }
+
+ hx509_certs_end_seq(context, certs, cursor);
+ if (ret)
+ return ret;
+ if (c == NULL) {
+ hx509_clear_error_string(context);
+ return HX509_CERT_NOT_FOUND;
+ }
+
+ return 0;
+}
+
+static int
+certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
+{
+ return hx509_certs_add(context, (hx509_certs)ctx, c);
+}
+
+int
+hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
+{
+ return hx509_certs_iter(context, from, certs_merge_func, to);
+}
+
+int
+hx509_certs_append(hx509_context context,
+ hx509_certs to,
+ hx509_lock lock,
+ const char *name)
+{
+ hx509_certs s;
+ int ret;
+
+ ret = hx509_certs_init(context, name, 0, lock, &s);
+ if (ret)
+ return ret;
+ ret = hx509_certs_merge(context, to, s);
+ hx509_certs_free(&s);
+ return ret;
+}
+
+int
+hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
+{
+ hx509_cursor cursor;
+ int ret;
+
+ *c = NULL;
+
+ ret = hx509_certs_start_seq(context, certs, &cursor);
+ if (ret)
+ return ret;
+
+ ret = hx509_certs_next_cert(context, certs, cursor, c);
+ if (ret)
+ return ret;
+
+ hx509_certs_end_seq(context, certs, cursor);
+ return 0;
+}
+
+static int
+certs_info_stdio(void *ctx, char *str)
+{
+ FILE *f = ctx;
+ fprintf(f, "%s\n", str);
+ return 0;
+}
+
+int
+hx509_certs_info(hx509_context context,
+ hx509_certs certs,
+ int (*func)(void *, char *),
+ void *ctx)
+{
+ if (func == NULL) {
+ func = certs_info_stdio;
+ if (ctx == NULL)
+ ctx = stdout;
+ }
+ if (certs->ops->printinfo == NULL) {
+ (*func)(ctx, "No info function for certs");
+ return 0;
+ }
+ return (*certs->ops->printinfo)(context, certs, certs->ops_data,
+ func, ctx);
+}
+
+void
+_hx509_pi_printf(int (*func)(void *, char *), void *ctx,
+ char *fmt, ...)
+{
+ va_list ap;
+ char *str;
+
+ va_start(ap, fmt);
+ vasprintf(&str, fmt, ap);
+ va_end(ap);
+ if (str == NULL)
+ return;
+ (*func)(ctx, str);
+ free(str);
+}
+
+int
+_hx509_certs_keys_get(hx509_context context,
+ hx509_certs certs,
+ hx509_private_key **keys)
+{
+ if (certs->ops->getkeys == NULL) {
+ *keys = NULL;
+ return 0;
+ }
+ return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys);
+}
+
+int
+_hx509_certs_keys_add(hx509_context context,
+ hx509_certs certs,
+ hx509_private_key key)
+{
+ if (certs->ops->addkey == NULL) {
+ hx509_set_error_string(context, 0, EINVAL,
+ "keystore if type %s doesn't support "
+ "key add operation",
+ certs->ops->name);
+ return EINVAL;
+ }
+ return (*certs->ops->addkey)(context, certs, certs->ops_data, key);
+}
+
+
+void
+_hx509_certs_keys_free(hx509_context context,
+ hx509_private_key *keys)
+{
+ int i;
+ for (i = 0; keys[i]; i++)
+ _hx509_private_key_free(&keys[i]);
+ free(keys);
+}
diff --git a/source4/heimdal/lib/hx509/ks_dir.c b/source4/heimdal/lib/hx509/ks_dir.c
new file mode 100644
index 00000000000..01dcf5795b4
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ks_dir.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: ks_dir.c,v 1.7 2007/01/09 10:52:08 lha Exp $");
+#include <dirent.h>
+
+/*
+ * The DIR keyset module is strange compared to the other modules
+ * since it does lazy evaluation and really doesn't keep any local
+ * state except for the directory iteration and cert iteration of
+ * files. DIR ignores most errors so that the consumer doesn't get
+ * failes for stray files in directories.
+ */
+
+struct dircursor {
+ DIR *dir;
+ hx509_certs certs;
+ void *iter;
+};
+
+/*
+ *
+ */
+
+static int
+dir_init(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
+{
+ *data = NULL;
+
+ {
+ struct stat sb;
+ int ret;
+
+ ret = stat(residue, &sb);
+ if (ret == -1) {
+ hx509_set_error_string(context, 0, ENOENT,
+ "No such file %s", residue);
+ return ENOENT;
+ }
+
+ if ((sb.st_mode & S_IFDIR) == 0) {
+ hx509_set_error_string(context, 0, ENOTDIR,
+ "%s is not a directory", residue);
+ return ENOTDIR;
+ }
+ }
+
+ *data = strdup(residue);
+ if (*data == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+static int
+dir_free(hx509_certs certs, void *data)
+{
+ free(data);
+ return 0;
+}
+
+
+
+static int
+dir_iter_start(hx509_context context,
+ hx509_certs certs, void *data, void **cursor)
+{
+ struct dircursor *d;
+
+ *cursor = NULL;
+
+ d = calloc(1, sizeof(*d));
+ if (d == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ d->dir = opendir(data);
+ if (d->dir == NULL) {
+ hx509_clear_error_string(context);
+ free(d);
+ return errno;
+ }
+ d->certs = NULL;
+ d->iter = NULL;
+
+ *cursor = d;
+ return 0;
+}
+
+static int
+dir_iter(hx509_context context,
+ hx509_certs certs, void *data, void *iter, hx509_cert *cert)
+{
+ struct dircursor *d = iter;
+ int ret = 0;
+
+ *cert = NULL;
+
+ do {
+ struct dirent *dir;
+ char *fn;
+
+ if (d->certs) {
+ ret = hx509_certs_next_cert(context, d->certs, d->iter, cert);
+ if (ret) {
+ hx509_certs_end_seq(context, d->certs, d->iter);
+ d->iter = NULL;
+ hx509_certs_free(&d->certs);
+ return ret;
+ }
+ if (*cert) {
+ ret = 0;
+ break;
+ }
+ hx509_certs_end_seq(context, d->certs, d->iter);
+ d->iter = NULL;
+ hx509_certs_free(&d->certs);
+ }
+
+ dir = readdir(d->dir);
+ if (dir == NULL) {
+ ret = 0;
+ break;
+ }
+ if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
+ continue;
+
+ if (asprintf(&fn, "FILE:%s/%s", (char *)data, dir->d_name) == -1)
+ return ENOMEM;
+
+ ret = hx509_certs_init(context, fn, 0, NULL, &d->certs);
+ if (ret == 0) {
+
+ ret = hx509_certs_start_seq(context, d->certs, &d->iter);
+ if (ret)
+ hx509_certs_free(&d->certs);
+ }
+ /* ignore errors */
+ if (ret) {
+ d->certs = NULL;
+ ret = 0;
+ }
+
+ free(fn);
+ } while(ret == 0);
+
+ return ret;
+}
+
+
+static int
+dir_iter_end(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void *cursor)
+{
+ struct dircursor *d = cursor;
+
+ if (d->certs) {
+ hx509_certs_end_seq(context, d->certs, d->iter);
+ d->iter = NULL;
+ hx509_certs_free(&d->certs);
+ }
+ closedir(d->dir);
+ free(d);
+ return 0;
+}
+
+
+static struct hx509_keyset_ops keyset_dir = {
+ "DIR",
+ 0,
+ dir_init,
+ NULL,
+ dir_free,
+ NULL,
+ NULL,
+ dir_iter_start,
+ dir_iter,
+ dir_iter_end
+};
+
+void
+_hx509_ks_dir_register(hx509_context context)
+{
+ _hx509_ks_register(context, &keyset_dir);
+}
diff --git a/source4/heimdal/lib/hx509/ks_file.c b/source4/heimdal/lib/hx509/ks_file.c
new file mode 100644
index 00000000000..db0f475129d
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ks_file.c
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: ks_file.c,v 1.31 2007/01/09 10:52:08 lha Exp $");
+
+struct ks_file {
+ hx509_certs certs;
+ char *fn;
+};
+
+struct header {
+ char *header;
+ char *value;
+ struct header *next;
+};
+
+static int
+add_headers(struct header **headers, const char *header, const char *value)
+{
+ struct header *h;
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ return ENOMEM;
+ h->header = strdup(header);
+ if (h->header == NULL) {
+ free(h);
+ return ENOMEM;
+ }
+ h->value = strdup(value);
+ if (h->value == NULL) {
+ free(h->header);
+ free(h);
+ return ENOMEM;
+ }
+
+ h->next = *headers;
+ *headers = h;
+
+ return 0;
+}
+
+static void
+free_headers(struct header *headers)
+{
+ struct header *h;
+ while (headers) {
+ h = headers;
+ headers = headers->next;
+ free(h->header);
+ free(h->value);
+ free(h);
+ }
+}
+
+static const char *
+find_header(const struct header *headers, const char *header)
+{
+ while(headers) {
+ if (strcmp(header, headers->header) == 0)
+ return headers->value;
+ headers = headers->next;
+ }
+ return NULL;
+}
+
+/*
+ *
+ */
+
+static int
+parse_certificate(hx509_context context, const char *fn,
+ struct hx509_collector *c,
+ const struct header *headers,
+ const void *data, size_t len)
+{
+ hx509_cert cert;
+ Certificate t;
+ size_t size;
+ int ret;
+
+ ret = decode_Certificate(data, len, &t, &size);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret,
+ "Failed to parse certificate in %s",
+ fn);
+ return ret;
+ }
+
+ ret = hx509_cert_init(context, &t, &cert);
+ free_Certificate(&t);
+ if (ret)
+ return ret;
+
+ ret = _hx509_collector_certs_add(context, c, cert);
+ hx509_cert_free(cert);
+ return ret;
+}
+
+static int
+try_decrypt(hx509_context context,
+ struct hx509_collector *collector,
+ const AlgorithmIdentifier *alg,
+ const EVP_CIPHER *c,
+ const void *ivdata,
+ const void *password,
+ size_t passwordlen,
+ const void *cipher,
+ size_t len)
+{
+ heim_octet_string clear;
+ size_t keylen;
+ void *key;
+ int ret;
+
+ keylen = EVP_CIPHER_key_length(c);
+
+ key = malloc(keylen);
+ if (key == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ ret = EVP_BytesToKey(c, EVP_md5(), ivdata,
+ password, passwordlen,
+ 1, key, NULL);
+ if (ret <= 0) {
+ hx509_set_error_string(context, 0, HX509_CRYPTO_INTERNAL_ERROR,
+ "Failed to do string2key for private key");
+ return HX509_CRYPTO_INTERNAL_ERROR;
+ }
+
+ clear.data = malloc(len);
+ if (clear.data == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM,
+ "Out of memory to decrypt for private key");
+ ret = ENOMEM;
+ goto out;
+ }
+ clear.length = len;
+
+ {
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_CipherInit_ex(&ctx, c, NULL, key, ivdata, 0);
+ EVP_Cipher(&ctx, clear.data, cipher, len);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ }
+
+ ret = _hx509_collector_private_key_add(context,
+ collector,
+ alg,
+ NULL,
+ &clear,
+ NULL);
+
+ memset(clear.data, 0, clear.length);
+ free(clear.data);
+out:
+ memset(key, 0, keylen);
+ free(key);
+ return ret;
+}
+
+static int
+parse_rsa_private_key(hx509_context context, const char *fn,
+ struct hx509_collector *c,
+ const struct header *headers,
+ const void *data, size_t len)
+{
+ int ret = 0;
+ const char *enc;
+
+ enc = find_header(headers, "Proc-Type");
+ if (enc) {
+ const char *dek;
+ char *type, *iv;
+ ssize_t ssize, size;
+ void *ivdata;
+ const EVP_CIPHER *cipher;
+ const struct _hx509_password *pw;
+ hx509_lock lock;
+ int i, decrypted = 0;
+
+ lock = _hx509_collector_get_lock(c);
+ if (lock == NULL) {
+ hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
+ "Failed to get password for "
+ "password protected file %s", fn);
+ return HX509_ALG_NOT_SUPP;
+ }
+
+ if (strcmp(enc, "4,ENCRYPTED") != 0) {
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "RSA key encrypted in unknown method %s "
+ "in file",
+ enc, fn);
+ hx509_clear_error_string(context);
+ return HX509_PARSING_KEY_FAILED;
+ }
+
+ dek = find_header(headers, "DEK-Info");
+ if (dek == NULL) {
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "Encrypted RSA missing DEK-Info");
+ return HX509_PARSING_KEY_FAILED;
+ }
+
+ type = strdup(dek);
+ if (type == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ iv = strchr(type, ',');
+ if (iv)
+ *iv++ = '\0';
+
+ size = strlen(iv);
+ ivdata = malloc(size);
+ if (ivdata == NULL) {
+ hx509_clear_error_string(context);
+ free(type);
+ return ENOMEM;
+ }
+
+ cipher = EVP_get_cipherbyname(type);
+ if (cipher == NULL) {
+ free(ivdata);
+ hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
+ "RSA key encrypted with "
+ "unsupported cipher: %s",
+ type);
+ free(type);
+ return HX509_ALG_NOT_SUPP;
+ }
+
+#define PKCS5_SALT_LEN 8
+
+ ssize = hex_decode(iv, ivdata, size);
+ free(type);
+ type = NULL;
+ iv = NULL;
+
+ if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) {
+ free(ivdata);
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "Salt have wrong length in RSA key file");
+ return HX509_PARSING_KEY_FAILED;
+ }
+
+ pw = _hx509_lock_get_passwords(lock);
+ if (pw != NULL) {
+ const void *password;
+ size_t passwordlen;
+
+ for (i = 0; i < pw->len; i++) {
+ password = pw->val[i];
+ passwordlen = strlen(password);
+
+ ret = try_decrypt(context, c, hx509_signature_rsa(),
+ cipher, ivdata, password, passwordlen,
+ data, len);
+ if (ret == 0) {
+ decrypted = 1;
+ break;
+ }
+ }
+ }
+ if (!decrypted) {
+ hx509_prompt prompt;
+ char password[128];
+
+ memset(&prompt, 0, sizeof(prompt));
+
+ prompt.prompt = "Password for keyfile: ";
+ prompt.type = HX509_PROMPT_TYPE_PASSWORD;
+ prompt.reply.data = password;
+ prompt.reply.length = sizeof(password);
+
+ ret = hx509_lock_prompt(lock, &prompt);
+ if (ret == 0)
+ ret = try_decrypt(context, c, hx509_signature_rsa(),
+ cipher, ivdata, password, strlen(password),
+ data, len);
+ /* XXX add password to lock password collection ? */
+ memset(password, 0, sizeof(password));
+ }
+ free(ivdata);
+
+ } else {
+ heim_octet_string keydata;
+
+ keydata.data = rk_UNCONST(data);
+ keydata.length = len;
+
+ ret = _hx509_collector_private_key_add(context,
+ c,
+ hx509_signature_rsa(),
+ NULL,
+ &keydata,
+ NULL);
+ }
+
+ return ret;
+}
+
+
+struct pem_formats {
+ const char *name;
+ int (*func)(hx509_context, const char *, struct hx509_collector *,
+ const struct header *, const void *, size_t);
+} formats[] = {
+ { "CERTIFICATE", parse_certificate },
+ { "RSA PRIVATE KEY", parse_rsa_private_key }
+};
+
+
+static int
+parse_pem_file(hx509_context context,
+ const char *fn,
+ struct hx509_collector *c,
+ int *found_data)
+{
+ struct header *headers = NULL;
+ char *type = NULL;
+ void *data = NULL;
+ size_t len = 0;
+ char buf[1024];
+ int ret;
+ FILE *f;
+
+
+ enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where;
+
+ where = BEFORE;
+ *found_data = 0;
+
+ if ((f = fopen(fn, "r")) == NULL) {
+ hx509_set_error_string(context, 0, ENOENT,
+ "Failed to open PEM file \"%s\": %s",
+ fn, strerror(errno));
+ return ENOENT;
+ }
+ ret = 0;
+
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ char *p;
+ int i;
+
+ i = strcspn(buf, "\n");
+ if (buf[i] == '\n') {
+ buf[i] = '\0';
+ if (i > 0)
+ i--;
+ }
+ if (buf[i] == '\r') {
+ buf[i] = '\0';
+ if (i > 0)
+ i--;
+ }
+
+ switch (where) {
+ case BEFORE:
+ if (strncmp("-----BEGIN ", buf, 11) == 0) {
+ type = strdup(buf + 11);
+ if (type == NULL)
+ break;
+ p = strchr(type, '-');
+ if (p)
+ *p = '\0';
+ *found_data = 1;
+ where = SEARCHHEADER;
+ }
+ break;
+ case SEARCHHEADER:
+ p = strchr(buf, ':');
+ if (p == NULL) {
+ where = INDATA;
+ goto indata;
+ }
+ /* FALLTHOUGH */
+ case INHEADER:
+ if (buf[0] == '\0') {
+ where = INDATA;
+ break;
+ }
+ p = strchr(buf, ':');
+ if (p) {
+ *p++ = '\0';
+ while (isspace((int)*p))
+ p++;
+ add_headers(&headers, buf, p);
+ }
+ break;
+ case INDATA:
+ indata:
+
+ if (strncmp("-----END ", buf, 9) == 0) {
+ where = DONE;
+ break;
+ }
+
+ p = emalloc(i);
+ i = base64_decode(buf, p);
+ if (i < 0) {
+ free(p);
+ goto out;
+ }
+
+ data = erealloc(data, len + i);
+ memcpy(((char *)data) + len, p, i);
+ free(p);
+ len += i;
+ break;
+ case DONE:
+ abort();
+ }
+
+ if (where == DONE) {
+ int j;
+
+ for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
+ const char *q = formats[j].name;
+ if (strcasecmp(type, q) == 0) {
+ ret = (*formats[j].func)(context, fn, c,
+ headers, data, len);
+ break;
+ }
+ }
+ if (j == sizeof(formats)/sizeof(formats[0])) {
+ ret = HX509_UNSUPPORTED_OPERATION;
+ hx509_set_error_string(context, 0, ret,
+ "Found no matching PEM format for %s",
+ type);
+ }
+ out:
+ free(data);
+ data = NULL;
+ len = 0;
+ free(type);
+ type = NULL;
+ where = BEFORE;
+ free_headers(headers);
+ headers = NULL;
+ if (ret)
+ break;
+ }
+ }
+
+ fclose(f);
+
+ if (where != BEFORE) {
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "File ends before end of PEM end tag");
+ ret = HX509_PARSING_KEY_FAILED;
+ }
+ if (data)
+ free(data);
+ if (type)
+ free(type);
+ if (headers)
+ free_headers(headers);
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+static int
+file_init(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
+{
+ char *p, *pnext;
+ struct ks_file *f = NULL;
+ struct hx509_collector *c = NULL;
+ hx509_private_key *keys = NULL;
+ int ret;
+
+ *data = NULL;
+
+ if (lock == NULL)
+ lock = _hx509_empty_lock;
+
+ f = calloc(1, sizeof(*f));
+ if (f == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ f->fn = strdup(residue);
+ if (f->fn == NULL) {
+ hx509_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /*
+ * XXX this is broken, the function should parse the file before
+ * overwriting it
+ */
+
+ if (flags & HX509_CERTS_CREATE) {
+ ret = hx509_certs_init(context, "MEMORY:ks-file-create",
+ 0, lock, &f->certs);
+ if (ret)
+ goto out;
+ *data = f;
+ return 0;
+ }
+
+ c = _hx509_collector_alloc(context, lock);
+ if (c == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ goto out;
+ }
+
+ for (p = f->fn; p != NULL; p = pnext) {
+ int found_data;
+
+ pnext = strchr(p, ',');
+ if (pnext)
+ *pnext++ = '\0';
+
+ ret = parse_pem_file(context, p, c, &found_data);
+ if (ret)
+ goto out;
+
+ if (!found_data) {
+ size_t length;
+ void *ptr;
+ int i;
+
+ ret = _hx509_map_file(p, &ptr, &length, NULL);
+ if (ret) {
+ hx509_clear_error_string(context);
+ goto out;
+ }
+
+ for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
+ ret = (*formats[i].func)(context, p, c, NULL, ptr, length);
+ if (ret == 0)
+ break;
+ }
+ _hx509_unmap_file(ptr, length);
+ if (ret)
+ goto out;
+ }
+ }
+
+ ret = _hx509_collector_collect_certs(context, c, &f->certs);
+ if (ret)
+ goto out;
+
+ ret = _hx509_collector_collect_private_keys(context, c, &keys);
+ if (ret == 0) {
+ int i;
+
+ for (i = 0; keys[i]; i++)
+ _hx509_certs_keys_add(context, f->certs, keys[i]);
+ _hx509_certs_keys_free(context, keys);
+ }
+
+out:
+ if (ret == 0)
+ *data = f;
+ else {
+ if (f->fn)
+ free(f->fn);
+ free(f);
+ }
+ if (c)
+ _hx509_collector_free(c);
+ return ret;
+}
+
+static int
+file_free(hx509_certs certs, void *data)
+{
+ struct ks_file *f = data;
+ hx509_certs_free(&f->certs);
+ free(f->fn);
+ free(f);
+ return 0;
+}
+
+static void
+pem_header(FILE *f, const char *type, const char *str)
+{
+ fprintf(f, "-----%s %s-----\n", type, str);
+}
+
+static int
+dump_pem_file(hx509_context context, const char *header,
+ FILE *f, const void *data, size_t size)
+{
+ const char *p = data;
+ size_t length;
+ char *line;
+
+#define ENCODE_LINE_LENGTH 54
+
+ pem_header(f, "BEGIN", header);
+
+ while (size > 0) {
+ ssize_t l;
+
+ length = size;
+ if (length > ENCODE_LINE_LENGTH)
+ length = ENCODE_LINE_LENGTH;
+
+ l = base64_encode(p, length, &line);
+ if (l < 0) {
+ hx509_set_error_string(context, 0, ENOMEM,
+ "malloc - out of memory");
+ return ENOMEM;
+ }
+ size -= length;
+ fprintf(f, "%s\n", line);
+ p += length;
+ free(line);
+ }
+
+ pem_header(f, "END", header);
+
+ return 0;
+}
+
+static int
+store_private_key(hx509_context context, FILE *f, hx509_private_key key)
+{
+ heim_octet_string data;
+ int ret;
+
+ ret = _hx509_private_key_export(context, key, &data);
+ if (ret == 0)
+ dump_pem_file(context, _hx509_private_pem_name(key), f,
+ data.data, data.length);
+ free(data.data);
+ return ret;
+}
+
+static int
+store_func(hx509_context context, void *ctx, hx509_cert c)
+{
+ FILE *f = (FILE *)ctx;
+ size_t size;
+ heim_octet_string data;
+ int ret;
+
+ ASN1_MALLOC_ENCODE(Certificate, data.data, data.length,
+ _hx509_get_cert(c), &size, ret);
+ if (ret)
+ return ret;
+ if (data.length != size)
+ _hx509_abort("internal ASN.1 encoder error");
+
+ dump_pem_file(context, "CERTIFICATE", f, data.data, data.length);
+ free(data.data);
+
+ if (_hx509_cert_private_key_exportable(c))
+ store_private_key(context, f, _hx509_cert_private_key(c));
+
+ return 0;
+}
+
+static int
+file_store(hx509_context context,
+ hx509_certs certs, void *data, int flags, hx509_lock lock)
+{
+ struct ks_file *f = data;
+ FILE *fh;
+ int ret;
+
+ fh = fopen(f->fn, "w");
+ if (fh == NULL) {
+ hx509_set_error_string(context, 0, ENOENT,
+ "Failed to open file %s for writing");
+ return ENOENT;
+ }
+
+ ret = hx509_certs_iter(context, f->certs, store_func, fh);
+ fclose(fh);
+ return ret;
+}
+
+static int
+file_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
+{
+ struct ks_file *f = data;
+ return hx509_certs_add(context, f->certs, c);
+}
+
+static int
+file_iter_start(hx509_context context,
+ hx509_certs certs, void *data, void **cursor)
+{
+ struct ks_file *f = data;
+ return hx509_certs_start_seq(context, f->certs, cursor);
+}
+
+static int
+file_iter(hx509_context context,
+ hx509_certs certs, void *data, void *iter, hx509_cert *cert)
+{
+ struct ks_file *f = data;
+ return hx509_certs_next_cert(context, f->certs, iter, cert);
+}
+
+static int
+file_iter_end(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void *cursor)
+{
+ struct ks_file *f = data;
+ return hx509_certs_end_seq(context, f->certs, cursor);
+}
+
+static int
+file_getkeys(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ hx509_private_key **keys)
+{
+ struct ks_file *f = data;
+ return _hx509_certs_keys_get(context, f->certs, keys);
+}
+
+static int
+file_addkey(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ hx509_private_key key)
+{
+ struct ks_file *f = data;
+ return _hx509_certs_keys_add(context, f->certs, key);
+}
+
+static struct hx509_keyset_ops keyset_file = {
+ "FILE",
+ 0,
+ file_init,
+ file_store,
+ file_free,
+ file_add,
+ NULL,
+ file_iter_start,
+ file_iter,
+ file_iter_end,
+ NULL,
+ file_getkeys,
+ file_addkey
+};
+
+void
+_hx509_ks_file_register(hx509_context context)
+{
+ _hx509_ks_register(context, &keyset_file);
+}
diff --git a/source4/heimdal/lib/hx509/ks_mem.c b/source4/heimdal/lib/hx509/ks_mem.c
new file mode 100644
index 00000000000..dd7b7166bc8
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ks_mem.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("Id$");
+
+/*
+ * Should use two hash/tree certificates intead of a array. Criteria
+ * should be subject and subjectKeyIdentifier since those two are
+ * commonly seached on in CMS and path building.
+ */
+
+struct mem_data {
+ char *name;
+ struct {
+ unsigned long len;
+ hx509_cert *val;
+ } certs;
+ hx509_private_key *keys;
+};
+
+static int
+mem_init(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
+{
+ struct mem_data *mem;
+ mem = calloc(1, sizeof(*mem));
+ if (mem == NULL)
+ return ENOMEM;
+ if (residue == NULL || residue[0] == '\0')
+ residue = "anonymous";
+ mem->name = strdup(residue);
+ if (mem->name == NULL) {
+ free(mem);
+ return ENOMEM;
+ }
+ *data = mem;
+ return 0;
+}
+
+static int
+mem_free(hx509_certs certs, void *data)
+{
+ struct mem_data *mem = data;
+ unsigned long i;
+
+ for (i = 0; i < mem->certs.len; i++)
+ hx509_cert_free(mem->certs.val[i]);
+ free(mem->certs.val);
+ for (i = 0; mem->keys && mem->keys[i]; i++)
+ _hx509_private_key_free(&mem->keys[i]);
+ free(mem->name);
+ free(mem);
+
+ return 0;
+}
+
+static int
+mem_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
+{
+ struct mem_data *mem = data;
+ hx509_cert *val;
+
+ val = realloc(mem->certs.val,
+ (mem->certs.len + 1) * sizeof(mem->certs.val[0]));
+ if (val == NULL)
+ return ENOMEM;
+
+ mem->certs.val = val;
+ mem->certs.val[mem->certs.len] = hx509_cert_ref(c);
+ mem->certs.len++;
+
+ return 0;
+}
+
+static int
+mem_iter_start(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void **cursor)
+{
+ unsigned long *iter = malloc(sizeof(*iter));
+
+ if (iter == NULL)
+ return ENOMEM;
+
+ *iter = 0;
+ *cursor = iter;
+
+ return 0;
+}
+
+static int
+mem_iter(hx509_context contexst,
+ hx509_certs certs,
+ void *data,
+ void *cursor,
+ hx509_cert *cert)
+{
+ unsigned long *iter = cursor;
+ struct mem_data *mem = data;
+
+ if (*iter >= mem->certs.len) {
+ *cert = NULL;
+ return 0;
+ }
+
+ *cert = hx509_cert_ref(mem->certs.val[*iter]);
+ (*iter)++;
+ return 0;
+}
+
+static int
+mem_iter_end(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void *cursor)
+{
+ free(cursor);
+ return 0;
+}
+
+static int
+mem_getkeys(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ hx509_private_key **keys)
+{
+ struct mem_data *mem = data;
+ int i;
+
+ for (i = 0; mem->keys && mem->keys[i]; i++)
+ ;
+ *keys = calloc(i, sizeof(**keys));
+ for (i = 0; mem->keys && mem->keys[i]; i++) {
+ (*keys)[i] = _hx509_private_key_ref(mem->keys[i]);
+ if ((*keys)[i] == NULL) {
+ while (--i >= 0)
+ _hx509_private_key_free(&(*keys)[i]);
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+ }
+ (*keys)[i] = NULL;
+ return 0;
+}
+
+static int
+mem_addkey(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ hx509_private_key key)
+{
+ struct mem_data *mem = data;
+ void *ptr;
+ int i;
+
+ for (i = 0; mem->keys && mem->keys[i]; i++)
+ ;
+ ptr = realloc(mem->keys, (i + 2) * sizeof(*mem->keys));
+ if (ptr == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+ mem->keys = ptr;
+ mem->keys[i++] = _hx509_private_key_ref(key);
+ mem->keys[i++] = NULL;
+ return 0;
+}
+
+
+static struct hx509_keyset_ops keyset_mem = {
+ "MEMORY",
+ 0,
+ mem_init,
+ NULL,
+ mem_free,
+ mem_add,
+ NULL,
+ mem_iter_start,
+ mem_iter,
+ mem_iter_end,
+ NULL,
+ mem_getkeys,
+ mem_addkey
+};
+
+void
+_hx509_ks_mem_register(hx509_context context)
+{
+ _hx509_ks_register(context, &keyset_mem);
+}
diff --git a/source4/heimdal/lib/hx509/ks_null.c b/source4/heimdal/lib/hx509/ks_null.c
new file mode 100644
index 00000000000..1e6c2ea3fb9
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ks_null.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: ks_null.c,v 1.5 2007/01/09 10:52:10 lha Exp $");
+
+
+static int
+null_init(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
+{
+ *data = NULL;
+ return 0;
+}
+
+static int
+null_free(hx509_certs certs, void *data)
+{
+ assert(data == NULL);
+ return 0;
+}
+
+static int
+null_iter_start(hx509_context context,
+ hx509_certs certs, void *data, void **cursor)
+{
+ *cursor = NULL;
+ return 0;
+}
+
+static int
+null_iter(hx509_context context,
+ hx509_certs certs, void *data, void *iter, hx509_cert *cert)
+{
+ *cert = NULL;
+ return ENOENT;
+}
+
+static int
+null_iter_end(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void *cursor)
+{
+ assert(cursor == NULL);
+ return 0;
+}
+
+
+struct hx509_keyset_ops keyset_null = {
+ "NULL",
+ 0,
+ null_init,
+ NULL,
+ null_free,
+ NULL,
+ NULL,
+ null_iter_start,
+ null_iter,
+ null_iter_end
+};
diff --git a/source4/heimdal/lib/hx509/ks_p11.c b/source4/heimdal/lib/hx509/ks_p11.c
new file mode 100644
index 00000000000..b103264b7a7
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ks_p11.c
@@ -0,0 +1,1183 @@
+/*
+ * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: ks_p11.c,v 1.45 2007/01/09 19:43:35 lha Exp $");
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifdef HAVE_DLOPEN
+
+#include "pkcs11.h"
+
+struct p11_slot {
+ int flags;
+#define P11_SESSION 1
+#define P11_SESSION_IN_USE 2
+#define P11_LOGIN_REQ 4
+#define P11_LOGIN_DONE 8
+#define P11_TOKEN_PRESENT 16
+ CK_SESSION_HANDLE session;
+ CK_SLOT_ID id;
+ CK_BBOOL token;
+ char *name;
+ hx509_certs certs;
+ char *pin;
+ struct {
+ CK_MECHANISM_TYPE_PTR list;
+ CK_ULONG num;
+ CK_MECHANISM_INFO_PTR *infos;
+ } mechs;
+};
+
+struct p11_module {
+ void *dl_handle;
+ CK_FUNCTION_LIST_PTR funcs;
+ CK_ULONG num_slots;
+ unsigned int refcount;
+ struct p11_slot *slot;
+};
+
+#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
+
+static int p11_get_session(hx509_context,
+ struct p11_module *,
+ struct p11_slot *,
+ hx509_lock,
+ CK_SESSION_HANDLE *);
+static int p11_put_session(struct p11_module *,
+ struct p11_slot *,
+ CK_SESSION_HANDLE);
+static void p11_release_module(struct p11_module *);
+
+static int p11_list_keys(hx509_context,
+ struct p11_module *,
+ struct p11_slot *,
+ CK_SESSION_HANDLE,
+ hx509_lock,
+ hx509_certs *);
+
+/*
+ *
+ */
+
+struct p11_rsa {
+ struct p11_module *p;
+ struct p11_slot *slot;
+ CK_OBJECT_HANDLE private_key;
+ CK_OBJECT_HANDLE public_key;
+};
+
+static int
+p11_rsa_public_encrypt(int flen,
+ const unsigned char *from,
+ unsigned char *to,
+ RSA *rsa,
+ int padding)
+{
+ return -1;
+}
+
+static int
+p11_rsa_public_decrypt(int flen,
+ const unsigned char *from,
+ unsigned char *to,
+ RSA *rsa,
+ int padding)
+{
+ return -1;
+}
+
+
+static int
+p11_rsa_private_encrypt(int flen,
+ const unsigned char *from,
+ unsigned char *to,
+ RSA *rsa,
+ int padding)
+{
+ struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
+ CK_OBJECT_HANDLE key = p11rsa->private_key;
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_ULONG ck_sigsize;
+ int ret;
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+
+ memset(&mechanism, 0, sizeof(mechanism));
+ mechanism.mechanism = CKM_RSA_PKCS;
+
+ ck_sigsize = RSA_size(rsa);
+
+ ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
+ if (ret)
+ return -1;
+
+ ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
+ if (ret != CKR_OK) {
+ p11_put_session(p11rsa->p, p11rsa->slot, session);
+ return -1;
+ }
+
+ ret = P11FUNC(p11rsa->p, Sign,
+ (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
+ p11_put_session(p11rsa->p, p11rsa->slot, session);
+ if (ret != CKR_OK)
+ return -1;
+
+ return ck_sigsize;
+}
+
+static int
+p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
+ RSA * rsa, int padding)
+{
+ struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
+ CK_OBJECT_HANDLE key = p11rsa->private_key;
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_ULONG ck_sigsize;
+ int ret;
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+
+ memset(&mechanism, 0, sizeof(mechanism));
+ mechanism.mechanism = CKM_RSA_PKCS;
+
+ ck_sigsize = RSA_size(rsa);
+
+ ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
+ if (ret)
+ return -1;
+
+ ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
+ if (ret != CKR_OK) {
+ p11_put_session(p11rsa->p, p11rsa->slot, session);
+ return -1;
+ }
+
+ ret = P11FUNC(p11rsa->p, Decrypt,
+ (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
+ p11_put_session(p11rsa->p, p11rsa->slot, session);
+ if (ret != CKR_OK)
+ return -1;
+
+ return ck_sigsize;
+}
+
+static int
+p11_rsa_init(RSA *rsa)
+{
+ return 1;
+}
+
+static int
+p11_rsa_finish(RSA *rsa)
+{
+ struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
+ p11_release_module(p11rsa->p);
+ free(p11rsa);
+ return 1;
+}
+
+static const RSA_METHOD rsa_pkcs1_method = {
+ "hx509 PKCS11 PKCS#1 RSA",
+ p11_rsa_public_encrypt,
+ p11_rsa_public_decrypt,
+ p11_rsa_private_encrypt,
+ p11_rsa_private_decrypt,
+ NULL,
+ NULL,
+ p11_rsa_init,
+ p11_rsa_finish,
+ 0,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ *
+ */
+
+static int
+p11_mech_info(hx509_context context,
+ struct p11_module *p,
+ struct p11_slot *slot,
+ int num)
+{
+ CK_ULONG i;
+ int ret;
+
+ ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
+ if (ret) {
+ hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
+ "Failed to get mech list count for slot %d",
+ num);
+ return HX509_PKCS11_NO_MECH;
+ }
+ if (i == 0) {
+ hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
+ "no mech supported for slot %d", num);
+ return HX509_PKCS11_NO_MECH;
+ }
+ slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
+ if (slot->mechs.list == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM,
+ "out of memory");
+ return ENOMEM;
+ }
+ slot->mechs.num = i;
+ ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
+ if (ret) {
+ hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
+ "Failed to get mech list for slot %d",
+ num);
+ return HX509_PKCS11_NO_MECH;
+ }
+ assert(i == slot->mechs.num);
+
+ slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
+ if (slot->mechs.list == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM,
+ "out of memory");
+ return ENOMEM;
+ }
+
+ for (i = 0; i < slot->mechs.num; i++) {
+ slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
+ if (slot->mechs.infos[i] == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM,
+ "out of memory");
+ return ENOMEM;
+ }
+ ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
+ slot->mechs.infos[i]));
+ if (ret) {
+ hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
+ "Failed to get mech info for slot %d",
+ num);
+ return HX509_PKCS11_NO_MECH;
+ }
+ }
+
+ return 0;
+}
+
+static int
+p11_init_slot(hx509_context context,
+ struct p11_module *p,
+ hx509_lock lock,
+ CK_SLOT_ID id,
+ int num,
+ struct p11_slot *slot)
+{
+ CK_SESSION_HANDLE session;
+ CK_SLOT_INFO slot_info;
+ CK_TOKEN_INFO token_info;
+ int ret, i;
+
+ slot->certs = NULL;
+ slot->id = id;
+
+ ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));
+ if (ret) {
+ hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
+ "Failed to init PKCS11 slot %d",
+ num);
+ return HX509_PKCS11_TOKEN_CONFUSED;
+ }
+
+ for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {
+ char c = slot_info.slotDescription[i];
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')
+ continue;
+ i++;
+ break;
+ }
+
+ asprintf(&slot->name, "%.*s",
+ i, slot_info.slotDescription);
+
+ if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)
+ return 0;
+
+ ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));
+ if (ret) {
+ hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,
+ "Failed to init PKCS11 slot %d "
+ "with error 0x08x",
+ num, ret);
+ return HX509_PKCS11_NO_TOKEN;
+ }
+ slot->flags |= P11_TOKEN_PRESENT;
+
+ if (token_info.flags & CKF_LOGIN_REQUIRED)
+ slot->flags |= P11_LOGIN_REQ;
+
+ ret = p11_get_session(context, p, slot, lock, &session);
+ if (ret)
+ return ret;
+
+ ret = p11_mech_info(context, p, slot, num);
+ if (ret)
+ goto out;
+
+ ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);
+ out:
+ p11_put_session(p, slot, session);
+
+ return ret;
+}
+
+static int
+p11_get_session(hx509_context context,
+ struct p11_module *p,
+ struct p11_slot *slot,
+ hx509_lock lock,
+ CK_SESSION_HANDLE *psession)
+{
+ CK_RV ret;
+
+ if (slot->flags & P11_SESSION_IN_USE)
+ _hx509_abort("slot already in session");
+
+ if (slot->flags & P11_SESSION) {
+ slot->flags |= P11_SESSION_IN_USE;
+ *psession = slot->session;
+ return 0;
+ }
+
+ ret = P11FUNC(p, OpenSession, (slot->id,
+ CKF_SERIAL_SESSION,
+ NULL,
+ NULL,
+ &slot->session));
+ if (ret != CKR_OK) {
+ if (context)
+ hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,
+ "Failed to OpenSession for slot id %d "
+ "with error: 0x%08x",
+ (int)slot->id, ret);
+ return HX509_PKCS11_OPEN_SESSION;
+ }
+
+ slot->flags |= P11_SESSION;
+
+ /*
+ * If we have have to login, and haven't tried before and have a
+ * prompter or known to work pin code.
+ *
+ * This code is very conversative and only uses the prompter in
+ * the hx509_lock, the reason is that its bad to try many
+ * passwords on a pkcs11 token, it might lock up and have to be
+ * unlocked by a administrator.
+ *
+ * XXX try harder to not use pin several times on the same card.
+ */
+
+ if ( (slot->flags & P11_LOGIN_REQ)
+ && (slot->flags & P11_LOGIN_DONE) == 0
+ && (lock || slot->pin))
+ {
+ hx509_prompt prompt;
+ char pin[20];
+ char *str;
+
+ slot->flags |= P11_LOGIN_DONE;
+
+ if (slot->pin == NULL) {
+
+ memset(&prompt, 0, sizeof(prompt));
+
+ asprintf(&str, "PIN code for %s: ", slot->name);
+ prompt.prompt = str;
+ prompt.type = HX509_PROMPT_TYPE_PASSWORD;
+ prompt.reply.data = pin;
+ prompt.reply.length = sizeof(pin);
+
+ ret = hx509_lock_prompt(lock, &prompt);
+ if (ret) {
+ free(str);
+ if (context)
+ hx509_set_error_string(context, 0, ret,
+ "Failed to get pin code for slot "
+ "id %d with error: %d",
+ (int)slot->id, ret);
+ return ret;
+ }
+ free(str);
+ } else {
+ strlcpy(pin, slot->pin, sizeof(pin));
+ }
+
+ ret = P11FUNC(p, Login, (slot->session, CKU_USER,
+ (unsigned char*)pin, strlen(pin)));
+ if (ret != CKR_OK) {
+ if (context)
+ hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,
+ "Failed to login on slot id %d "
+ "with error: 0x%08x",
+ (int)slot->id, ret);
+ p11_put_session(p, slot, slot->session);
+ return HX509_PKCS11_LOGIN;
+ }
+ if (slot->pin == NULL) {
+ slot->pin = strdup(pin);
+ if (slot->pin == NULL) {
+ if (context)
+ hx509_set_error_string(context, 0, ENOMEM,
+ "out of memory");
+ p11_put_session(p, slot, slot->session);
+ return ENOMEM;
+ }
+ }
+ } else
+ slot->flags |= P11_LOGIN_DONE;
+
+ slot->flags |= P11_SESSION_IN_USE;
+
+ *psession = slot->session;
+
+ return 0;
+}
+
+static int
+p11_put_session(struct p11_module *p,
+ struct p11_slot *slot,
+ CK_SESSION_HANDLE session)
+{
+ if ((slot->flags & P11_SESSION_IN_USE) == 0)
+ _hx509_abort("slot not in session");
+ slot->flags &= ~P11_SESSION_IN_USE;
+
+ return 0;
+}
+
+static int
+iterate_entries(hx509_context context,
+ struct p11_module *p, struct p11_slot *slot,
+ CK_SESSION_HANDLE session,
+ CK_ATTRIBUTE *search_data, int num_search_data,
+ CK_ATTRIBUTE *query, int num_query,
+ int (*func)(hx509_context,
+ struct p11_module *, struct p11_slot *,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ void *, CK_ATTRIBUTE *, int), void *ptr)
+{
+ CK_OBJECT_HANDLE object;
+ CK_ULONG object_count;
+ int ret, i;
+
+ ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));
+ if (ret != CKR_OK) {
+ return -1;
+ }
+ while (1) {
+ ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));
+ if (ret != CKR_OK) {
+ return -1;
+ }
+ if (object_count == 0)
+ break;
+
+ for (i = 0; i < num_query; i++)
+ query[i].pValue = NULL;
+
+ ret = P11FUNC(p, GetAttributeValue,
+ (session, object, query, num_query));
+ if (ret != CKR_OK) {
+ return -1;
+ }
+ for (i = 0; i < num_query; i++) {
+ query[i].pValue = malloc(query[i].ulValueLen);
+ if (query[i].pValue == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ }
+ ret = P11FUNC(p, GetAttributeValue,
+ (session, object, query, num_query));
+ if (ret != CKR_OK) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = (*func)(context, p, slot, session, object, ptr, query, num_query);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < num_query; i++) {
+ if (query[i].pValue)
+ free(query[i].pValue);
+ query[i].pValue = NULL;
+ }
+ }
+ out:
+
+ for (i = 0; i < num_query; i++) {
+ if (query[i].pValue)
+ free(query[i].pValue);
+ query[i].pValue = NULL;
+ }
+
+ ret = P11FUNC(p, FindObjectsFinal, (session));
+ if (ret != CKR_OK) {
+ return -2;
+ }
+
+
+ return 0;
+}
+
+static BIGNUM *
+getattr_bn(struct p11_module *p,
+ struct p11_slot *slot,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ unsigned int type)
+{
+ CK_ATTRIBUTE query;
+ BIGNUM *bn;
+ int ret;
+
+ query.type = type;
+ query.pValue = NULL;
+ query.ulValueLen = 0;
+
+ ret = P11FUNC(p, GetAttributeValue,
+ (session, object, &query, 1));
+ if (ret != CKR_OK)
+ return NULL;
+
+ query.pValue = malloc(query.ulValueLen);
+
+ ret = P11FUNC(p, GetAttributeValue,
+ (session, object, &query, 1));
+ if (ret != CKR_OK) {
+ free(query.pValue);
+ return NULL;
+ }
+ bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
+ free(query.pValue);
+
+ return bn;
+}
+
+static int
+collect_private_key(hx509_context context,
+ struct p11_module *p, struct p11_slot *slot,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ void *ptr, CK_ATTRIBUTE *query, int num_query)
+{
+ struct hx509_collector *collector = ptr;
+ hx509_private_key key;
+ heim_octet_string localKeyId;
+ int ret;
+ RSA *rsa;
+ struct p11_rsa *p11rsa;
+
+ localKeyId.data = query[0].pValue;
+ localKeyId.length = query[0].ulValueLen;
+
+ ret = _hx509_private_key_init(&key, NULL, NULL);
+ if (ret)
+ return ret;
+
+ rsa = RSA_new();
+ if (rsa == NULL)
+ _hx509_abort("out of memory");
+
+ /*
+ * The exponent and modulus should always be present according to
+ * the pkcs11 specification, but some smartcards leaves it out,
+ * let ignore any failure to fetch it.
+ */
+ rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
+ rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
+
+ p11rsa = calloc(1, sizeof(*p11rsa));
+ if (p11rsa == NULL)
+ _hx509_abort("out of memory");
+
+ p11rsa->p = p;
+ p11rsa->slot = slot;
+ p11rsa->private_key = object;
+
+ p->refcount++;
+ if (p->refcount == 0)
+ _hx509_abort("pkcs11 refcount to high");
+
+ RSA_set_method(rsa, &rsa_pkcs1_method);
+ ret = RSA_set_app_data(rsa, p11rsa);
+ if (ret != 1)
+ _hx509_abort("RSA_set_app_data");
+
+ _hx509_private_key_assign_rsa(key, rsa);
+
+ ret = _hx509_collector_private_key_add(context,
+ collector,
+ hx509_signature_rsa(),
+ key,
+ NULL,
+ &localKeyId);
+
+ if (ret) {
+ _hx509_private_key_free(&key);
+ return ret;
+ }
+ return 0;
+}
+
+static void
+p11_cert_release(hx509_cert cert, void *ctx)
+{
+ struct p11_module *p = ctx;
+ p11_release_module(p);
+}
+
+
+static int
+collect_cert(hx509_context context,
+ struct p11_module *p, struct p11_slot *slot,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ void *ptr, CK_ATTRIBUTE *query, int num_query)
+{
+ struct hx509_collector *collector = ptr;
+ hx509_cert cert;
+ Certificate t;
+ int ret;
+
+ if ((CK_LONG)query[0].ulValueLen == -1 ||
+ (CK_LONG)query[1].ulValueLen == -1)
+ {
+ return 0;
+ }
+
+
+ ret = decode_Certificate(query[1].pValue, query[1].ulValueLen,
+ &t, NULL);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return 0;
+ }
+
+ ret = hx509_cert_init(context, &t, &cert);
+ free_Certificate(&t);
+ if (ret)
+ return ret;
+
+ p->refcount++;
+ if (p->refcount == 0)
+ _hx509_abort("pkcs11 refcount to high");
+
+ _hx509_cert_set_release(cert, p11_cert_release, p);
+
+ {
+ heim_octet_string data;
+
+ data.data = query[0].pValue;
+ data.length = query[0].ulValueLen;
+
+ _hx509_set_cert_attribute(context,
+ cert,
+ oid_id_pkcs_9_at_localKeyId(),
+ &data);
+ }
+
+ if ((CK_LONG)query[2].ulValueLen != -1) {
+ char *str;
+
+ asprintf(&str, "%.*s",
+ (int)query[2].ulValueLen, (char *)query[2].pValue);
+ if (str) {
+ hx509_cert_set_friendly_name(cert, str);
+ free(str);
+ }
+ }
+
+ ret = _hx509_collector_certs_add(context, collector, cert);
+ hx509_cert_free(cert);
+
+ return ret;
+}
+
+
+static int
+p11_list_keys(hx509_context context,
+ struct p11_module *p,
+ struct p11_slot *slot,
+ CK_SESSION_HANDLE session,
+ hx509_lock lock,
+ hx509_certs *certs)
+{
+ struct hx509_collector *collector;
+ CK_OBJECT_CLASS key_class;
+ CK_ATTRIBUTE search_data[] = {
+ {CKA_CLASS, NULL, 0},
+ };
+ CK_ATTRIBUTE query_data[3] = {
+ {CKA_ID, NULL, 0},
+ {CKA_VALUE, NULL, 0},
+ {CKA_LABEL, NULL, 0}
+ };
+ int ret;
+
+ search_data[0].pValue = &key_class;
+ search_data[0].ulValueLen = sizeof(key_class);
+
+ if (lock == NULL)
+ lock = _hx509_empty_lock;
+
+ collector = _hx509_collector_alloc(context, lock);
+ if (collector == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+
+ key_class = CKO_PRIVATE_KEY;
+ ret = iterate_entries(context, p, slot, session,
+ search_data, 1,
+ query_data, 1,
+ collect_private_key, collector);
+ if (ret)
+ goto out;
+
+ key_class = CKO_CERTIFICATE;
+ ret = iterate_entries(context, p, slot, session,
+ search_data, 1,
+ query_data, 3,
+ collect_cert, collector);
+ if (ret)
+ goto out;
+
+ ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
+
+out:
+ _hx509_collector_free(collector);
+
+ return ret;
+}
+
+
+static int
+p11_init(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
+{
+ CK_C_GetFunctionList getFuncs;
+ struct p11_module *p;
+ char *list, *str;
+ int ret;
+
+ *data = NULL;
+
+ list = strdup(residue);
+ if (list == NULL)
+ return ENOMEM;
+
+ p = calloc(1, sizeof(*p));
+ if (p == NULL) {
+ free(list);
+ return ENOMEM;
+ }
+
+ p->refcount = 1;
+
+ str = strchr(list, ',');
+ if (str)
+ *str++ = '\0';
+ while (str) {
+ char *strnext;
+ strnext = strchr(str, ',');
+ if (strnext)
+ *strnext++ = '\0';
+#if 0
+ if (strncasecmp(str, "slot=", 5) == 0)
+ p->selected_slot = atoi(str + 5);
+#endif
+ str = strnext;
+ }
+
+ p->dl_handle = dlopen(list, RTLD_NOW);
+ free(list);
+ if (p->dl_handle == NULL) {
+ ret = HX509_PKCS11_LOAD;
+ hx509_set_error_string(context, 0, ret,
+ "Failed to open %s: %s", list, dlerror());
+ goto out;
+ }
+
+ getFuncs = dlsym(p->dl_handle, "C_GetFunctionList");
+ if (getFuncs == NULL) {
+ ret = HX509_PKCS11_LOAD;
+ hx509_set_error_string(context, 0, ret,
+ "C_GetFunctionList missing in %s: %s",
+ list, dlerror());
+ goto out;
+ }
+
+ ret = (*getFuncs)(&p->funcs);
+ if (ret) {
+ ret = HX509_PKCS11_LOAD;
+ hx509_set_error_string(context, 0, ret,
+ "C_GetFunctionList failed in %s", list);
+ goto out;
+ }
+
+ ret = P11FUNC(p, Initialize, (NULL_PTR));
+ if (ret != CKR_OK) {
+ ret = HX509_PKCS11_TOKEN_CONFUSED;
+ hx509_set_error_string(context, 0, ret,
+ "Failed initialize the PKCS11 module");
+ goto out;
+ }
+
+ ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
+ if (ret) {
+ ret = HX509_PKCS11_TOKEN_CONFUSED;
+ hx509_set_error_string(context, 0, ret,
+ "Failed to get number of PKCS11 slots");
+ goto out;
+ }
+
+ if (p->num_slots == 0) {
+ ret = HX509_PKCS11_NO_SLOT;
+ hx509_set_error_string(context, 0, ret,
+ "Selected PKCS11 module have no slots");
+ goto out;
+ }
+
+
+ {
+ CK_SLOT_ID_PTR slot_ids;
+ int i, num_tokens = 0;
+
+ slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
+ if (slot_ids == NULL) {
+ hx509_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
+ if (ret) {
+ free(slot_ids);
+ hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
+ "Failed getting slot-list from "
+ "PKCS11 module");
+ ret = HX509_PKCS11_TOKEN_CONFUSED;
+ goto out;
+ }
+
+ p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
+ if (p->slot == NULL) {
+ free(slot_ids);
+ hx509_set_error_string(context, 0, ENOMEM,
+ "Failed to get memory for slot-list");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < p->num_slots; i++) {
+ ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
+ if (ret)
+ break;
+ if (p->slot[i].flags & P11_TOKEN_PRESENT)
+ num_tokens++;
+ }
+ free(slot_ids);
+ if (ret)
+ goto out;
+ if (num_tokens == 0) {
+ ret = HX509_PKCS11_NO_TOKEN;
+ goto out;
+ }
+ }
+
+ *data = p;
+
+ return 0;
+ out:
+ p11_release_module(p);
+ return ret;
+}
+
+static void
+p11_release_module(struct p11_module *p)
+{
+ int i;
+
+ if (p->refcount == 0)
+ _hx509_abort("pkcs11 refcount to low");
+ if (--p->refcount > 0)
+ return;
+
+ for (i = 0; i < p->num_slots; i++) {
+ if (p->slot[i].flags & P11_SESSION_IN_USE)
+ _hx509_abort("pkcs11 module release while session in use");
+ if (p->slot[i].flags & P11_SESSION) {
+ int ret;
+
+ ret = P11FUNC(p, CloseSession, (p->slot[i].session));
+ if (ret != CKR_OK)
+ ;
+ }
+
+ if (p->slot[i].name)
+ free(p->slot[i].name);
+ if (p->slot[i].pin) {
+ memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
+ free(p->slot[i].pin);
+ }
+ if (p->slot[i].mechs.num) {
+ free(p->slot[i].mechs.list);
+
+ if (p->slot[i].mechs.infos) {
+ int j;
+
+ for (j = 0 ; j < p->slot[i].mechs.num ; j++)
+ free(p->slot[i].mechs.infos[j]);
+ free(p->slot[i].mechs.infos);
+ }
+ }
+ }
+ free(p->slot);
+
+ if (p->funcs)
+ P11FUNC(p, Finalize, (NULL));
+
+ if (p->dl_handle)
+ dlclose(p->dl_handle);
+
+ memset(p, 0, sizeof(*p));
+ free(p);
+}
+
+static int
+p11_free(hx509_certs certs, void *data)
+{
+ struct p11_module *p = data;
+ int i;
+
+ for (i = 0; i < p->num_slots; i++) {
+ if (p->slot[i].certs)
+ hx509_certs_free(&p->slot[i].certs);
+ }
+ p11_release_module(p);
+ return 0;
+}
+
+struct p11_cursor {
+ hx509_certs certs;
+ void *cursor;
+};
+
+static int
+p11_iter_start(hx509_context context,
+ hx509_certs certs, void *data, void **cursor)
+{
+ struct p11_module *p = data;
+ struct p11_cursor *c;
+ int ret, i;
+
+ c = malloc(sizeof(*c));
+ if (c == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+ ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
+ if (ret) {
+ free(c);
+ return ret;
+ }
+
+ for (i = 0 ; i < p->num_slots; i++) {
+ if (p->slot[i].certs == NULL)
+ continue;
+ ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
+ if (ret) {
+ hx509_certs_free(&c->certs);
+ free(c);
+ return ret;
+ }
+ }
+
+ ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
+ if (ret) {
+ hx509_certs_free(&c->certs);
+ free(c);
+ return 0;
+ }
+ *cursor = c;
+
+ return 0;
+}
+
+static int
+p11_iter(hx509_context context,
+ hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
+{
+ struct p11_cursor *c = cursor;
+ return hx509_certs_next_cert(context, c->certs, c->cursor, cert);
+}
+
+static int
+p11_iter_end(hx509_context context,
+ hx509_certs certs, void *data, void *cursor)
+{
+ struct p11_cursor *c = cursor;
+ int ret;
+ ret = hx509_certs_end_seq(context, c->certs, c->cursor);
+ hx509_certs_free(&c->certs);
+ free(c);
+ return ret;
+}
+
+#define MECHFLAG(x) { "unknown-flag-" #x, x }
+static struct units mechflags[] = {
+ MECHFLAG(0x80000000),
+ MECHFLAG(0x40000000),
+ MECHFLAG(0x20000000),
+ MECHFLAG(0x10000000),
+ MECHFLAG(0x08000000),
+ MECHFLAG(0x04000000),
+ {"ec-compress", 0x2000000 },
+ {"ec-uncompress", 0x1000000 },
+ {"ec-namedcurve", 0x0800000 },
+ {"ec-ecparameters", 0x0400000 },
+ {"ec-f-2m", 0x0200000 },
+ {"ec-f-p", 0x0100000 },
+ {"derive", 0x0080000 },
+ {"unwrap", 0x0040000 },
+ {"wrap", 0x0020000 },
+ {"genereate-key-pair", 0x0010000 },
+ {"generate", 0x0008000 },
+ {"verify-recover", 0x0004000 },
+ {"verify", 0x0002000 },
+ {"sign-recover", 0x0001000 },
+ {"sign", 0x0000800 },
+ {"digest", 0x0000400 },
+ {"decrypt", 0x0000200 },
+ {"encrypt", 0x0000100 },
+ MECHFLAG(0x00080),
+ MECHFLAG(0x00040),
+ MECHFLAG(0x00020),
+ MECHFLAG(0x00010),
+ MECHFLAG(0x00008),
+ MECHFLAG(0x00004),
+ MECHFLAG(0x00002),
+ {"hw", 0x0000001 },
+ { NULL, 0x0000000 }
+};
+#undef MECHFLAG
+
+static int
+p11_printinfo(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ int (*func)(void *, char *),
+ void *ctx)
+{
+ struct p11_module *p = data;
+ int i, j;
+
+ _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",
+ p->num_slots, p->num_slots > 1 ? "s" : "");
+
+ for (i = 0; i < p->num_slots; i++) {
+ struct p11_slot *s = &p->slot[i];
+
+ _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",
+ i, (int)s->id, s->name, s->flags);
+
+ _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",
+ (unsigned long)s->mechs.num);
+ for (j = 0; j < s->mechs.num; j++) {
+ const char *mechname = "unknown";
+ char flags[256], unknownname[40];
+#define MECHNAME(s,n) case s: mechname = n; break
+ switch(s->mechs.list[j]) {
+ MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");
+ MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");
+ MECHNAME(CKM_RSA_X_509, "rsa-x-509");
+ MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");
+ MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");
+ default:
+ snprintf(unknownname, sizeof(unknownname),
+ "unknown-mech-%lu",
+ (unsigned long)s->mechs.list[j]);
+ mechname = unknownname;
+ break;
+ }
+#undef MECHNAME
+ unparse_flags(s->mechs.infos[j]->flags, mechflags,
+ flags, sizeof(flags));
+
+ _hx509_pi_printf(func, ctx, " %s: %s", mechname, flags);
+ }
+ }
+
+ return 0;
+}
+
+static struct hx509_keyset_ops keyset_pkcs11 = {
+ "PKCS11",
+ 0,
+ p11_init,
+ NULL,
+ p11_free,
+ NULL,
+ NULL,
+ p11_iter_start,
+ p11_iter,
+ p11_iter_end,
+ p11_printinfo
+};
+
+#endif /* HAVE_DLOPEN */
+
+void
+_hx509_ks_pkcs11_register(hx509_context context)
+{
+#ifdef HAVE_DLOPEN
+ _hx509_ks_register(context, &keyset_pkcs11);
+#endif
+}
diff --git a/source4/heimdal/lib/hx509/ks_p12.c b/source4/heimdal/lib/hx509/ks_p12.c
new file mode 100644
index 00000000000..69dba802e5d
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ks_p12.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: ks_p12.c,v 1.18 2007/01/09 10:52:11 lha Exp $");
+
+struct ks_pkcs12 {
+ hx509_certs certs;
+ char *fn;
+};
+
+typedef int (*collector_func)(hx509_context,
+ struct hx509_collector *,
+ const void *, size_t,
+ const PKCS12_Attributes *);
+
+struct type {
+ const heim_oid * (*oid)(void);
+ collector_func func;
+};
+
+static void
+parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *,
+ const void *, size_t, const PKCS12_Attributes *);
+
+
+static const PKCS12_Attribute *
+find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
+{
+ int i;
+ if (attrs == NULL)
+ return NULL;
+ for (i = 0; i < attrs->len; i++)
+ if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)
+ return &attrs->val[i];
+ return NULL;
+}
+
+static int
+keyBag_parser(hx509_context context,
+ struct hx509_collector *c,
+ const void *data, size_t length,
+ const PKCS12_Attributes *attrs)
+{
+ const PKCS12_Attribute *attr;
+ PKCS8PrivateKeyInfo ki;
+ const heim_octet_string *os = NULL;
+ int ret;
+
+ attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId());
+ if (attr)
+ os = &attr->attrValues;
+
+ ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
+ if (ret)
+ return ret;
+
+ _hx509_collector_private_key_add(context,
+ c,
+ &ki.privateKeyAlgorithm,
+ NULL,
+ &ki.privateKey,
+ &attr->attrValues);
+ free_PKCS8PrivateKeyInfo(&ki);
+ return 0;
+}
+
+static int
+ShroudedKeyBag_parser(hx509_context context,
+ struct hx509_collector *c,
+ const void *data, size_t length,
+ const PKCS12_Attributes *attrs)
+{
+ PKCS8EncryptedPrivateKeyInfo pk;
+ heim_octet_string content;
+ int ret;
+
+ memset(&pk, 0, sizeof(pk));
+
+ ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);
+ if (ret)
+ return ret;
+
+ ret = _hx509_pbe_decrypt(context,
+ _hx509_collector_get_lock(c),
+ &pk.encryptionAlgorithm,
+ &pk.encryptedData,
+ &content);
+ free_PKCS8EncryptedPrivateKeyInfo(&pk);
+ if (ret)
+ return ret;
+
+ ret = keyBag_parser(context, c, content.data, content.length, attrs);
+ der_free_octet_string(&content);
+ return ret;
+}
+
+static int
+certBag_parser(hx509_context context,
+ struct hx509_collector *c,
+ const void *data, size_t length,
+ const PKCS12_Attributes *attrs)
+{
+ heim_octet_string os;
+ Certificate t;
+ hx509_cert cert;
+ PKCS12_CertBag cb;
+ int ret;
+
+ ret = decode_PKCS12_CertBag(data, length, &cb, NULL);
+ if (ret)
+ return ret;
+
+ if (der_heim_oid_cmp(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType)) {
+ free_PKCS12_CertBag(&cb);
+ return 0;
+ }
+
+ ret = decode_PKCS12_OctetString(cb.certValue.data,
+ cb.certValue.length,
+ &os,
+ NULL);
+ free_PKCS12_CertBag(&cb);
+ if (ret)
+ return ret;
+
+ ret = decode_Certificate(os.data, os.length, &t, NULL);
+ der_free_octet_string(&os);
+ if (ret)
+ return ret;
+
+ ret = hx509_cert_init(context, &t, &cert);
+ free_Certificate(&t);
+ if (ret)
+ return ret;
+
+ ret = _hx509_collector_certs_add(context, c, cert);
+ if (ret) {
+ hx509_cert_free(cert);
+ return ret;
+ }
+
+ {
+ const PKCS12_Attribute *attr;
+ const heim_oid * (*oids[])(void) = {
+ oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName
+ };
+ int i;
+
+ for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {
+ const heim_oid *oid = (*(oids[i]))();
+ attr = find_attribute(attrs, oid);
+ if (attr)
+ _hx509_set_cert_attribute(context, cert, oid,
+ &attr->attrValues);
+ }
+ }
+
+ hx509_cert_free(cert);
+
+ return 0;
+}
+
+static int
+parse_safe_content(hx509_context context,
+ struct hx509_collector *c,
+ const unsigned char *p, size_t len)
+{
+ PKCS12_SafeContents sc;
+ int ret, i;
+
+ memset(&sc, 0, sizeof(sc));
+
+ ret = decode_PKCS12_SafeContents(p, len, &sc, NULL);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < sc.len ; i++)
+ parse_pkcs12_type(context,
+ c,
+ &sc.val[i].bagId,
+ sc.val[i].bagValue.data,
+ sc.val[i].bagValue.length,
+ sc.val[i].bagAttributes);
+
+ free_PKCS12_SafeContents(&sc);
+ return 0;
+}
+
+static int
+safeContent_parser(hx509_context context,
+ struct hx509_collector *c,
+ const void *data, size_t length,
+ const PKCS12_Attributes *attrs)
+{
+ heim_octet_string os;
+ int ret;
+
+ ret = decode_PKCS12_OctetString(data, length, &os, NULL);
+ if (ret)
+ return ret;
+ ret = parse_safe_content(context, c, os.data, os.length);
+ der_free_octet_string(&os);
+ return ret;
+}
+
+static int
+encryptedData_parser(hx509_context context,
+ struct hx509_collector *c,
+ const void *data, size_t length,
+ const PKCS12_Attributes *attrs)
+{
+ heim_octet_string content;
+ heim_oid contentType;
+ int ret;
+
+ memset(&contentType, 0, sizeof(contentType));
+
+ ret = hx509_cms_decrypt_encrypted(context,
+ _hx509_collector_get_lock(c),
+ data, length,
+ &contentType,
+ &content);
+ if (ret)
+ return ret;
+
+ if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0)
+ ret = parse_safe_content(context, c, content.data, content.length);
+
+ der_free_octet_string(&content);
+ der_free_oid(&contentType);
+ return ret;
+}
+
+static int
+envelopedData_parser(hx509_context context,
+ struct hx509_collector *c,
+ const void *data, size_t length,
+ const PKCS12_Attributes *attrs)
+{
+ heim_octet_string content;
+ heim_oid contentType;
+ hx509_lock lock;
+ int ret;
+
+ memset(&contentType, 0, sizeof(contentType));
+
+ lock = _hx509_collector_get_lock(c);
+
+ ret = hx509_cms_unenvelope(context,
+ _hx509_lock_unlock_certs(lock),
+ 0,
+ data, length,
+ NULL,
+ &contentType,
+ &content);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "PKCS12 failed to unenvelope");
+ return ret;
+ }
+
+ if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0)
+ ret = parse_safe_content(context, c, content.data, content.length);
+
+ der_free_octet_string(&content);
+ der_free_oid(&contentType);
+
+ return ret;
+}
+
+
+struct type bagtypes[] = {
+ { oid_id_pkcs12_keyBag, keyBag_parser },
+ { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },
+ { oid_id_pkcs12_certBag, certBag_parser },
+ { oid_id_pkcs7_data, safeContent_parser },
+ { oid_id_pkcs7_encryptedData, encryptedData_parser },
+ { oid_id_pkcs7_envelopedData, envelopedData_parser }
+};
+
+static void
+parse_pkcs12_type(hx509_context context,
+ struct hx509_collector *c,
+ const heim_oid *oid,
+ const void *data, size_t length,
+ const PKCS12_Attributes *attrs)
+{
+ int i;
+
+ for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
+ if (der_heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0)
+ (*bagtypes[i].func)(context, c, data, length, attrs);
+}
+
+static int
+p12_init(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
+{
+ struct ks_pkcs12 *p12;
+ size_t len;
+ void *buf;
+ PKCS12_PFX pfx;
+ PKCS12_AuthenticatedSafe as;
+ int ret, i;
+ struct hx509_collector *c;
+
+ *data = NULL;
+
+ if (lock == NULL)
+ lock = _hx509_empty_lock;
+
+ c = _hx509_collector_alloc(context, lock);
+ if (c == NULL)
+ return ENOMEM;
+
+ p12 = calloc(1, sizeof(*p12));
+ if (p12 == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ p12->fn = strdup(residue);
+ if (p12->fn == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ if (flags & HX509_CERTS_CREATE) {
+ ret = hx509_certs_init(context, "MEMORY:ks-file-create",
+ 0, lock, &p12->certs);
+ if (ret)
+ goto out;
+ *data = p12;
+ return 0;
+ }
+
+ ret = _hx509_map_file(residue, &buf, &len, NULL);
+ if (ret)
+ goto out;
+
+ ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);
+ _hx509_unmap_file(buf, len);
+ if (ret)
+ goto out;
+
+ if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) {
+ free_PKCS12_PFX(&pfx);
+ ret = EINVAL;
+ hx509_set_error_string(context, 0, ret,
+ "PKCS PFX isn't a pkcs7-data container");
+ goto out;
+ }
+
+ if (pfx.authSafe.content == NULL) {
+ free_PKCS12_PFX(&pfx);
+ ret = EINVAL;
+ hx509_set_error_string(context, 0, ret,
+ "PKCS PFX missing data");
+ goto out;
+ }
+
+ {
+ heim_octet_string asdata;
+
+ ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,
+ pfx.authSafe.content->length,
+ &asdata,
+ NULL);
+ free_PKCS12_PFX(&pfx);
+ if (ret) {
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ ret = decode_PKCS12_AuthenticatedSafe(asdata.data,
+ asdata.length,
+ &as,
+ NULL);
+ der_free_octet_string(&asdata);
+ if (ret) {
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ }
+
+ for (i = 0; i < as.len; i++)
+ parse_pkcs12_type(context,
+ c,
+ &as.val[i].contentType,
+ as.val[i].content->data,
+ as.val[i].content->length,
+ NULL);
+
+ free_PKCS12_AuthenticatedSafe(&as);
+
+ ret = _hx509_collector_collect_certs(context, c, &p12->certs);
+ if (ret == 0)
+ *data = p12;
+
+out:
+ _hx509_collector_free(c);
+
+ if (ret) {
+ if (p12->certs)
+ hx509_certs_free(&p12->certs);
+ free(p12);
+ }
+
+ return ret;
+}
+
+static int
+addBag(hx509_context context,
+ PKCS12_AuthenticatedSafe *as,
+ const heim_oid *oid,
+ void *data,
+ size_t length)
+{
+ void *ptr;
+ int ret;
+
+ ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
+ if (ptr == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
+ return ENOMEM;
+ }
+ as->val = ptr;
+
+ ret = der_copy_oid(oid, &as->val[as->len].contentType);
+
+ as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
+ if (as->val[as->len].content == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
+ return ENOMEM;
+ }
+
+ as->val[as->len].content->data = data;
+ as->val[as->len].content->length = length;
+
+ as->len++;
+
+ return 0;
+}
+
+static int
+store_func(hx509_context context, void *ctx, hx509_cert c)
+{
+ PKCS12_AuthenticatedSafe *as = ctx;
+ PKCS12_OctetString os;
+ PKCS12_CertBag cb;
+ size_t size;
+ int ret;
+
+ memset(&os, 0, sizeof(os));
+ memset(&cb, 0, sizeof(cb));
+
+ os.data = NULL;
+ os.length = 0;
+
+ ASN1_MALLOC_ENCODE(Certificate, os.data, os.length,
+ _hx509_get_cert(c), &size, ret);
+ if (ret)
+ goto out;
+ ASN1_MALLOC_ENCODE(PKCS12_OctetString,
+ cb.certValue.data,cb.certValue.length,
+ &os, &size, ret);
+ free(os.data);
+ if (ret)
+ goto out;
+ ret = der_copy_oid(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType);
+ if (ret) {
+ free_PKCS12_CertBag(&cb);
+ goto out;
+ }
+ ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
+ &cb, &size, ret);
+ free(cb.certValue.data);
+ if (ret)
+ goto out;
+
+ ret = addBag(context, as, oid_id_pkcs12_certBag(), os.data, os.length);
+
+ if (_hx509_cert_private_key_exportable(c)) {
+ hx509_private_key key = _hx509_cert_private_key(c);
+ PKCS8PrivateKeyInfo pki;
+
+ memset(&pki, 0, sizeof(pki));
+
+ ret = der_parse_hex_heim_integer("00", &pki.version);
+ if (ret)
+ return ret;
+ ret = _hx509_private_key_oid(context, key,
+ &pki.privateKeyAlgorithm.algorithm);
+ if (ret) {
+ free_PKCS8PrivateKeyInfo(&pki);
+ return ret;
+ }
+ ret = _hx509_private_key_export(context,
+ _hx509_cert_private_key(c),
+ &pki.privateKey);
+ if (ret) {
+ free_PKCS8PrivateKeyInfo(&pki);
+ return ret;
+ }
+ /* set attribute, oid_id_pkcs_9_at_localKeyId() */
+
+ ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
+ &pki, &size, ret);
+ free_PKCS8PrivateKeyInfo(&pki);
+ if (ret)
+ return ret;
+
+ ret = addBag(context, as, oid_id_pkcs12_keyBag(), os.data, os.length);
+ if (ret)
+ return ret;
+ }
+
+out:
+ return ret;
+}
+
+static int
+p12_store(hx509_context context,
+ hx509_certs certs, void *data, int flags, hx509_lock lock)
+{
+ struct ks_pkcs12 *p12 = data;
+ PKCS12_PFX pfx;
+ PKCS12_AuthenticatedSafe as;
+ PKCS12_OctetString asdata;
+ size_t size;
+ int ret;
+
+ memset(&as, 0, sizeof(as));
+ memset(&pfx, 0, sizeof(pfx));
+
+ ret = hx509_certs_iter(context, p12->certs, store_func, &as);
+ if (ret)
+ goto out;
+
+ ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
+ &as, &size, ret);
+ free_PKCS12_AuthenticatedSafe(&as);
+ if (ret)
+ return ret;
+
+ ret = der_parse_hex_heim_integer("03", &pfx.version);
+ if (ret) {
+ free(asdata.data);
+ goto out;
+ }
+
+ pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));
+
+ ASN1_MALLOC_ENCODE(PKCS12_OctetString,
+ pfx.authSafe.content->data,
+ pfx.authSafe.content->length,
+ &asdata, &size, ret);
+ free(asdata.data);
+ if (ret)
+ goto out;
+
+ ret = der_copy_oid(oid_id_pkcs7_data(), &pfx.authSafe.contentType);
+ if (ret)
+ goto out;
+
+ ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
+ &pfx, &size, ret);
+ if (ret)
+ goto out;
+
+#if 0
+ const struct _hx509_password *pw;
+
+ pw = _hx509_lock_get_passwords(lock);
+ if (pw != NULL) {
+ pfx.macData = calloc(1, sizeof(*pfx.macData));
+ if (pfx.macData == NULL) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "malloc out of memory");
+ return ret;
+ }
+ if (pfx.macData == NULL) {
+ free(asdata.data);
+ goto out;
+ }
+ }
+ ret = calculate_hash(&aspath, pw, pfx.macData);
+#endif
+
+ rk_dumpdata(p12->fn, asdata.data, asdata.length);
+ free(asdata.data);
+
+out:
+ free_PKCS12_AuthenticatedSafe(&as);
+ free_PKCS12_PFX(&pfx);
+
+ return ret;
+}
+
+
+static int
+p12_free(hx509_certs certs, void *data)
+{
+ struct ks_pkcs12 *p12 = data;
+ hx509_certs_free(&p12->certs);
+ free(p12->fn);
+ free(p12);
+ return 0;
+}
+
+static int
+p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
+{
+ struct ks_pkcs12 *p12 = data;
+ return hx509_certs_add(context, p12->certs, c);
+}
+
+static int
+p12_iter_start(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void **cursor)
+{
+ struct ks_pkcs12 *p12 = data;
+ return hx509_certs_start_seq(context, p12->certs, cursor);
+}
+
+static int
+p12_iter(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void *cursor,
+ hx509_cert *cert)
+{
+ struct ks_pkcs12 *p12 = data;
+ return hx509_certs_next_cert(context, p12->certs, cursor, cert);
+}
+
+static int
+p12_iter_end(hx509_context context,
+ hx509_certs certs,
+ void *data,
+ void *cursor)
+{
+ struct ks_pkcs12 *p12 = data;
+ return hx509_certs_end_seq(context, p12->certs, cursor);
+}
+
+static struct hx509_keyset_ops keyset_pkcs12 = {
+ "PKCS12",
+ 0,
+ p12_init,
+ p12_store,
+ p12_free,
+ p12_add,
+ NULL,
+ p12_iter_start,
+ p12_iter,
+ p12_iter_end
+};
+
+void
+_hx509_ks_pkcs12_register(hx509_context context)
+{
+ _hx509_ks_register(context, &keyset_pkcs12);
+}
diff --git a/source4/heimdal/lib/hx509/lock.c b/source4/heimdal/lib/hx509/lock.c
new file mode 100644
index 00000000000..95fc0aa26da
--- /dev/null
+++ b/source4/heimdal/lib/hx509/lock.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: lock.c,v 1.13 2006/10/14 09:41:05 lha Exp $");
+
+struct hx509_lock_data {
+ struct _hx509_password password;
+ hx509_certs certs;
+ hx509_prompter_fct prompt;
+ void *prompt_data;
+};
+
+static struct hx509_lock_data empty_lock_data = {
+ { 0, NULL }
+};
+
+hx509_lock _hx509_empty_lock = &empty_lock_data;
+
+/*
+ *
+ */
+
+int
+hx509_lock_init(hx509_context context, hx509_lock *lock)
+{
+ hx509_lock l;
+ int ret;
+
+ *lock = NULL;
+
+ l = calloc(1, sizeof(*l));
+ if (l == NULL)
+ return ENOMEM;
+
+ ret = hx509_certs_init(context,
+ "MEMORY:locks-internal",
+ 0,
+ NULL,
+ &l->certs);
+ if (ret) {
+ free(l);
+ return ret;
+ }
+
+ *lock = l;
+
+ return 0;
+}
+
+int
+hx509_lock_add_password(hx509_lock lock, const char *password)
+{
+ void *d;
+ char *s;
+
+ s = strdup(password);
+ if (s == NULL)
+ return ENOMEM;
+
+ d = realloc(lock->password.val,
+ (lock->password.len + 1) * sizeof(lock->password.val[0]));
+ if (d == NULL) {
+ free(s);
+ return ENOMEM;
+ }
+ lock->password.val = d;
+ lock->password.val[lock->password.len] = s;
+ lock->password.len++;
+
+ return 0;
+}
+
+const struct _hx509_password *
+_hx509_lock_get_passwords(hx509_lock lock)
+{
+ return &lock->password;
+}
+
+hx509_certs
+_hx509_lock_unlock_certs(hx509_lock lock)
+{
+ return lock->certs;
+}
+
+void
+hx509_lock_reset_passwords(hx509_lock lock)
+{
+ int i;
+ for (i = 0; i < lock->password.len; i++)
+ free(lock->password.val[i]);
+ free(lock->password.val);
+ lock->password.val = NULL;
+ lock->password.len = 0;
+}
+
+int
+hx509_lock_add_cert(hx509_context context, hx509_lock lock, hx509_cert cert)
+{
+ return hx509_certs_add(context, lock->certs, cert);
+}
+
+int
+hx509_lock_add_certs(hx509_context context, hx509_lock lock, hx509_certs certs)
+{
+ return hx509_certs_merge(context, lock->certs, certs);
+}
+
+void
+hx509_lock_reset_certs(hx509_context context, hx509_lock lock)
+{
+ hx509_certs certs = lock->certs;
+ int ret;
+
+ ret = hx509_certs_init(context,
+ "MEMORY:locks-internal",
+ 0,
+ NULL,
+ &lock->certs);
+ if (ret == 0)
+ hx509_certs_free(&certs);
+ else
+ lock->certs = certs;
+}
+
+int
+_hx509_lock_find_cert(hx509_lock lock, const hx509_query *q, hx509_cert *c)
+{
+ *c = NULL;
+ return 0;
+}
+
+int
+hx509_lock_set_prompter(hx509_lock lock, hx509_prompter_fct prompt, void *data)
+{
+ lock->prompt = prompt;
+ lock->prompt_data = data;
+ return 0;
+}
+
+void
+hx509_lock_reset_promper(hx509_lock lock)
+{
+ lock->prompt = NULL;
+ lock->prompt_data = NULL;
+}
+
+static int
+default_prompter(void *data, const hx509_prompt *prompter)
+{
+ if (hx509_prompt_hidden(prompter->type)) {
+ if(UI_UTIL_read_pw_string(prompter->reply.data,
+ prompter->reply.length,
+ prompter->prompt,
+ 0))
+ return 1;
+ } else {
+ char *s = prompter->reply.data;
+
+ fputs (prompter->prompt, stdout);
+ fflush (stdout);
+ if(fgets(prompter->reply.data,
+ prompter->reply.length,
+ stdin) == NULL)
+ return 1;
+ s[strcspn(s, "\n")] = '\0';
+ }
+ return 0;
+}
+
+int
+hx509_lock_prompt(hx509_lock lock, hx509_prompt *prompt)
+{
+ if (lock->prompt == NULL)
+ return HX509_CRYPTO_NO_PROMPTER;
+ return (*lock->prompt)(lock->prompt_data, prompt);
+}
+
+void
+hx509_lock_free(hx509_lock lock)
+{
+ hx509_certs_free(&lock->certs);
+ hx509_lock_reset_passwords(lock);
+ memset(lock, 0, sizeof(*lock));
+ free(lock);
+}
+
+int
+hx509_prompt_hidden(hx509_prompt_type type)
+{
+ /* default to hidden if unknown */
+
+ switch (type) {
+ case HX509_PROMPT_TYPE_QUESTION:
+ case HX509_PROMPT_TYPE_INFO:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int
+hx509_lock_command_string(hx509_lock lock, const char *string)
+{
+ if (strncasecmp(string, "PASS:", 5) == 0) {
+ hx509_lock_add_password(lock, string + 5);
+ } else if (strcasecmp(string, "PROMPT") == 0) {
+ hx509_lock_set_prompter(lock, default_prompter, NULL);
+ } else
+ return HX509_UNKNOWN_LOCK_COMMAND;
+ return 0;
+}
diff --git a/source4/heimdal/lib/hx509/name.c b/source4/heimdal/lib/hx509/name.c
new file mode 100644
index 00000000000..92e9e6f974f
--- /dev/null
+++ b/source4/heimdal/lib/hx509/name.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: name.c,v 1.33 2006/12/30 23:04:11 lha Exp $");
+
+/*
+ * name parsing from rfc2253
+ * fix so parsing rfc1779 works too
+ * rfc3280
+ */
+
+static const struct {
+ char *n;
+ const heim_oid *(*o)(void);
+} no[] = {
+ { "C", oid_id_at_countryName },
+ { "CN", oid_id_at_commonName },
+ { "DC", oid_id_domainComponent },
+ { "L", oid_id_at_localityName },
+ { "O", oid_id_at_organizationName },
+ { "OU", oid_id_at_organizationalUnitName },
+ { "S", oid_id_at_stateOrProvinceName },
+ { "UID", oid_id_Userid },
+ { "emailAddress", oid_id_pkcs9_emailAddress },
+ { "serialNumber", oid_id_at_serialNumber }
+};
+
+static char *
+quote_string(const char *f, size_t len, size_t *rlen)
+{
+ size_t i, j, tolen;
+ const char *from = f;
+ char *to;
+
+ tolen = len * 3 + 1;
+ to = malloc(tolen);
+ if (to == NULL)
+ return NULL;
+
+ for (i = 0, j = 0; i < len; i++) {
+ if (from[i] == ' ' && i + 1 < len)
+ to[j++] = from[i];
+ else if (from[i] == ',' || from[i] == '=' || from[i] == '+' ||
+ from[i] == '<' || from[i] == '>' || from[i] == '#' ||
+ from[i] == ';' || from[i] == ' ')
+ {
+ to[j++] = '\\';
+ to[j++] = from[i];
+ } else if (((unsigned char)from[i]) >= 32 && ((unsigned char)from[i]) <= 127) {
+ to[j++] = from[i];
+ } else {
+ int l = snprintf(&to[j], tolen - j - 1,
+ "#%02x", (unsigned int)from[i]);
+ j += l;
+ }
+ }
+ to[j] = '\0';
+ *rlen = j;
+ return to;
+}
+
+
+static int
+append_string(char **str, size_t *total_len, char *ss, size_t len, int quote)
+{
+ char *s, *qs;
+
+ if (quote)
+ qs = quote_string(ss, len, &len);
+ else
+ qs = ss;
+
+ s = realloc(*str, len + *total_len + 1);
+ if (s == NULL)
+ _hx509_abort("allocation failure"); /* XXX */
+ memcpy(s + *total_len, qs, len);
+ if (qs != ss)
+ free(qs);
+ s[*total_len + len] = '\0';
+ *str = s;
+ *total_len += len;
+ return 0;
+}
+
+static char *
+oidtostring(const heim_oid *type)
+{
+ char *s;
+ size_t i;
+
+ for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
+ if (der_heim_oid_cmp((*no[i].o)(), type) == 0)
+ return strdup(no[i].n);
+ }
+ if (der_print_heim_oid(type, '.', &s) != 0)
+ return NULL;
+ return s;
+}
+
+static int
+stringtooid(const char *name, size_t len, heim_oid *oid)
+{
+ int i, ret;
+ char *s;
+
+ memset(oid, 0, sizeof(*oid));
+
+ for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
+ if (strncasecmp(no[i].n, name, len) == 0)
+ return der_copy_oid((*no[i].o)(), oid);
+ }
+ s = malloc(len + 1);
+ if (s == NULL)
+ return ENOMEM;
+ memcpy(s, name, len);
+ s[len] = '\0';
+ ret = der_parse_heim_oid(s, ".", oid);
+ free(s);
+ return ret;
+}
+
+int
+hx509_name_to_string(const hx509_name name, char **str)
+{
+ return _hx509_Name_to_string(&name->der_name, str);
+}
+
+int
+_hx509_Name_to_string(const Name *n, char **str)
+{
+ size_t total_len = 0;
+ int i, j;
+
+ *str = strdup("");
+ if (*str == NULL)
+ return ENOMEM;
+
+ for (i = n->u.rdnSequence.len - 1 ; i >= 0 ; i--) {
+ int len;
+
+ for (j = 0; j < n->u.rdnSequence.val[i].len; j++) {
+ DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value;
+ char *oidname;
+ char *ss;
+
+ oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type);
+
+ switch(ds->element) {
+ case choice_DirectoryString_ia5String:
+ ss = ds->u.ia5String;
+ break;
+ case choice_DirectoryString_printableString:
+ ss = ds->u.ia5String;
+ break;
+ case choice_DirectoryString_utf8String:
+ ss = ds->u.ia5String;
+ break;
+ case choice_DirectoryString_bmpString: {
+ uint16_t *bmp = ds->u.bmpString.data;
+ size_t bmplen = ds->u.bmpString.length;
+ size_t k;
+
+ ss = malloc(bmplen + 1);
+ if (ss == NULL)
+ _hx509_abort("allocation failure"); /* XXX */
+ for (k = 0; k < bmplen; k++)
+ ss[k] = bmp[k] & 0xff; /* XXX */
+ ss[k] = '\0';
+ break;
+ }
+ case choice_DirectoryString_teletexString:
+ ss = "teletex-string"; /* XXX */
+ break;
+ case choice_DirectoryString_universalString:
+ ss = "universalString"; /* XXX */
+ break;
+ default:
+ _hx509_abort("unknown directory type: %d", ds->element);
+ exit(1);
+ }
+ append_string(str, &total_len, oidname, strlen(oidname), 0);
+ free(oidname);
+ append_string(str, &total_len, "=", 1, 0);
+ len = strlen(ss);
+ append_string(str, &total_len, ss, len, 1);
+ if (ds->element == choice_DirectoryString_bmpString)
+ free(ss);
+ if (j + 1 < n->u.rdnSequence.val[i].len)
+ append_string(str, &total_len, "+", 1, 0);
+ }
+
+ if (i > 0)
+ append_string(str, &total_len, ",", 1, 0);
+ }
+ return 0;
+}
+
+/*
+ * XXX this function is broken, it needs to compare code points, not
+ * bytes.
+ */
+
+int
+_hx509_name_ds_cmp(const DirectoryString *ds1, const DirectoryString *ds2)
+{
+ int c;
+
+ c = ds1->element - ds2->element;
+ if (c)
+ return c;
+
+ switch(ds1->element) {
+ case choice_DirectoryString_ia5String:
+ c = strcmp(ds1->u.ia5String, ds2->u.ia5String);
+ break;
+ case choice_DirectoryString_teletexString:
+ c = der_heim_octet_string_cmp(&ds1->u.teletexString,
+ &ds2->u.teletexString);
+ break;
+ case choice_DirectoryString_printableString:
+ c = strcasecmp(ds1->u.printableString, ds2->u.printableString);
+ break;
+ case choice_DirectoryString_utf8String:
+ c = strcmp(ds1->u.utf8String, ds2->u.utf8String);
+ break;
+ case choice_DirectoryString_universalString:
+ c = der_heim_universal_string_cmp(&ds1->u.universalString,
+ &ds2->u.universalString);
+ break;
+ case choice_DirectoryString_bmpString:
+ c = der_heim_bmp_string_cmp(&ds1->u.bmpString,
+ &ds2->u.bmpString);
+ break;
+ default:
+ c = 1;
+ break;
+ }
+ return c;
+}
+
+int
+_hx509_name_cmp(const Name *n1, const Name *n2)
+{
+ int i, j, c;
+
+ c = n1->u.rdnSequence.len - n2->u.rdnSequence.len;
+ if (c)
+ return c;
+
+ for (i = 0 ; i < n1->u.rdnSequence.len; i++) {
+ c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len;
+ if (c)
+ return c;
+
+ for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) {
+ c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type,
+ &n1->u.rdnSequence.val[i].val[j].type);
+ if (c)
+ return c;
+
+ c = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value,
+ &n2->u.rdnSequence.val[i].val[j].value);
+ if (c)
+ return c;
+ }
+ }
+ return 0;
+}
+
+int
+_hx509_name_from_Name(const Name *n, hx509_name *name)
+{
+ int ret;
+ *name = calloc(1, sizeof(**name));
+ if (*name == NULL)
+ return ENOMEM;
+ ret = copy_Name(n, &(*name)->der_name);
+ if (ret) {
+ free(*name);
+ *name = NULL;
+ }
+ return ret;
+}
+
+static int
+hx509_der_parse_name(const void *data, size_t length, hx509_name *name)
+{
+ int ret;
+ Name n;
+
+ *name = NULL;
+ ret = decode_Name(data, length, &n, NULL);
+ if (ret)
+ return ret;
+ return _hx509_name_from_Name(&n, name);
+}
+
+int
+_hx509_name_modify(hx509_context context,
+ Name *name,
+ int append,
+ const heim_oid *oid,
+ const char *str)
+{
+ RelativeDistinguishedName *rdn;
+ int ret;
+ void *ptr;
+
+ ptr = realloc(name->u.rdnSequence.val,
+ sizeof(name->u.rdnSequence.val[0]) *
+ (name->u.rdnSequence.len + 1));
+ if (ptr == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
+ return ENOMEM;
+ }
+ name->u.rdnSequence.val = ptr;
+
+ if (append) {
+ rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len];
+ } else {
+ memmove(&name->u.rdnSequence.val[1],
+ &name->u.rdnSequence.val[0],
+ name->u.rdnSequence.len *
+ sizeof(name->u.rdnSequence.val[0]));
+
+ rdn = &name->u.rdnSequence.val[0];
+ }
+ rdn->val = malloc(sizeof(rdn->val[0]));
+ if (rdn->val == NULL)
+ return ENOMEM;
+ rdn->len = 1;
+ ret = der_copy_oid(oid, &rdn->val[0].type);
+ if (ret)
+ return ret;
+ rdn->val[0].value.element = choice_DirectoryString_utf8String;
+ rdn->val[0].value.u.utf8String = strdup(str);
+ if (rdn->val[0].value.u.utf8String == NULL)
+ return ENOMEM;
+ name->u.rdnSequence.len += 1;
+
+ return 0;
+}
+
+int
+hx509_parse_name(hx509_context context, const char *str, hx509_name *name)
+{
+ const char *p, *q;
+ size_t len;
+ hx509_name n;
+ int ret;
+
+ *name = NULL;
+
+ n = calloc(1, sizeof(*n));
+ if (n == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+
+ n->der_name.element = choice_Name_rdnSequence;
+
+ p = str;
+
+ while (p != NULL && *p != '\0') {
+ heim_oid oid;
+ int last;
+
+ q = strchr(p, ',');
+ if (q) {
+ len = (q - p);
+ last = 1;
+ } else {
+ len = strlen(p);
+ last = 0;
+ }
+
+ q = strchr(p, '=');
+ if (q == NULL) {
+ ret = HX509_PARSING_NAME_FAILED;
+ hx509_set_error_string(context, 0, ret, "missing = in %s", p);
+ goto out;
+ }
+ if (q == p) {
+ ret = HX509_PARSING_NAME_FAILED;
+ hx509_set_error_string(context, 0, ret,
+ "missing name before = in %s", p);
+ goto out;
+ }
+
+ if ((q - p) > len) {
+ ret = HX509_PARSING_NAME_FAILED;
+ hx509_set_error_string(context, 0, ret, " = after , in %s", p);
+ goto out;
+ }
+
+ ret = stringtooid(p, q - p, &oid);
+ if (ret) {
+ ret = HX509_PARSING_NAME_FAILED;
+ hx509_set_error_string(context, 0, ret,
+ "unknown type: %.*s", (int)(q - p), p);
+ goto out;
+ }
+
+ {
+ size_t pstr_len = len - (q - p) - 1;
+ const char *pstr = p + (q - p) + 1;
+ char *r;
+
+ r = malloc(pstr_len + 1);
+ if (r == NULL) {
+ der_free_oid(&oid);
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret, "out of memory");
+ goto out;
+ }
+ memcpy(r, pstr, pstr_len);
+ r[pstr_len] = '\0';
+
+ ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r);
+ free(r);
+ der_free_oid(&oid);
+ if(ret)
+ goto out;
+ }
+ p += len + last;
+ }
+
+ *name = n;
+
+ return 0;
+out:
+ hx509_name_free(&n);
+ return HX509_NAME_MALFORMED;
+}
+
+int
+hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to)
+{
+ int ret;
+
+ *to = calloc(1, sizeof(**to));
+ if (*to == NULL)
+ return ENOMEM;
+ ret = copy_Name(&from->der_name, &(*to)->der_name);
+ if (ret) {
+ free(*to);
+ *to = NULL;
+ return ENOMEM;
+ }
+ return 0;
+}
+
+int
+hx509_name_to_Name(const hx509_name from, Name *to)
+{
+ return copy_Name(&from->der_name, to);
+}
+
+
+void
+hx509_name_free(hx509_name *name)
+{
+ free_Name(&(*name)->der_name);
+ memset(*name, 0, sizeof(**name));
+ free(*name);
+ *name = NULL;
+}
+
+int
+hx509_unparse_der_name(const void *data, size_t length, char **str)
+{
+ hx509_name name;
+ int ret;
+
+ ret = hx509_der_parse_name(data, length, &name);
+ if (ret)
+ return ret;
+
+ ret = hx509_name_to_string(name, str);
+ hx509_name_free(&name);
+ return ret;
+}
+
+int
+hx509_name_to_der_name(const hx509_name name, void **data, size_t *length)
+{
+ size_t size;
+ int ret;
+
+ ASN1_MALLOC_ENCODE(Name, *data, *length, &name->der_name, &size, ret);
+ if (ret)
+ return ret;
+ if (*length != size)
+ _hx509_abort("internal ASN.1 encoder error");
+
+ return 0;
+}
+
+
+int
+_hx509_unparse_Name(const Name *aname, char **str)
+{
+ hx509_name name;
+ int ret;
+
+ ret = _hx509_name_from_Name(aname, &name);
+ if (ret)
+ return ret;
+
+ ret = hx509_name_to_string(name, str);
+ hx509_name_free(&name);
+ return ret;
+}
+
+int
+hx509_name_is_null_p(const hx509_name name)
+{
+ return name->der_name.u.rdnSequence.len == 0;
+}
diff --git a/source4/heimdal/lib/hx509/ocsp.asn1 b/source4/heimdal/lib/hx509/ocsp.asn1
new file mode 100644
index 00000000000..62a2750b96e
--- /dev/null
+++ b/source4/heimdal/lib/hx509/ocsp.asn1
@@ -0,0 +1,113 @@
+-- From rfc2560
+-- $Id: ocsp.asn1,v 1.4 2006/12/30 12:38:44 lha Exp $
+OCSP DEFINITIONS EXPLICIT TAGS::=
+
+BEGIN
+
+IMPORTS
+ Certificate, AlgorithmIdentifier, CRLReason,
+ Name, GeneralName, CertificateSerialNumber, Extensions
+ FROM rfc2459;
+
+OCSPVersion ::= INTEGER { ocsp-v1(0) }
+
+OCSPCertStatus ::= CHOICE {
+ good [0] IMPLICIT NULL,
+ revoked [1] IMPLICIT -- OCSPRevokedInfo -- SEQUENCE {
+ revocationTime GeneralizedTime,
+ revocationReason[0] EXPLICIT CRLReason OPTIONAL
+ },
+ unknown [2] IMPLICIT NULL }
+
+OCSPCertID ::= SEQUENCE {
+ hashAlgorithm AlgorithmIdentifier,
+ issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ serialNumber CertificateSerialNumber }
+
+OCSPSingleResponse ::= SEQUENCE {
+ certID OCSPCertID,
+ certStatus OCSPCertStatus,
+ thisUpdate GeneralizedTime,
+ nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+
+OCSPInnerRequest ::= SEQUENCE {
+ reqCert OCSPCertID,
+ singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+
+OCSPTBSRequest ::= SEQUENCE {
+ version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL,
+ requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ requestList SEQUENCE OF OCSPInnerRequest,
+ requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+
+OCSPSignature ::= SEQUENCE {
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING,
+ certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+
+OCSPRequest ::= SEQUENCE {
+ tbsRequest OCSPTBSRequest,
+ optionalSignature [0] EXPLICIT OCSPSignature OPTIONAL }
+
+OCSPResponseBytes ::= SEQUENCE {
+ responseType OBJECT IDENTIFIER,
+ response OCTET STRING }
+
+OCSPResponseStatus ::= ENUMERATED {
+ successful (0), --Response has valid confirmations
+ malformedRequest (1), --Illegal confirmation request
+ internalError (2), --Internal error in issuer
+ tryLater (3), --Try again later
+ --(4) is not used
+ sigRequired (5), --Must sign the request
+ unauthorized (6) --Request unauthorized
+}
+
+OCSPResponse ::= SEQUENCE {
+ responseStatus OCSPResponseStatus,
+ responseBytes [0] EXPLICIT OCSPResponseBytes OPTIONAL }
+
+OCSPKeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
+ --(excluding the tag and length fields)
+
+OCSPResponderID ::= CHOICE {
+ byName [1] Name,
+ byKey [2] OCSPKeyHash }
+
+OCSPResponseData ::= SEQUENCE {
+ version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL,
+ responderID OCSPResponderID,
+ producedAt GeneralizedTime,
+ responses SEQUENCE OF OCSPSingleResponse,
+ responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+
+OCSPBasicOCSPResponse ::= SEQUENCE {
+ tbsResponseData OCSPResponseData,
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING,
+ certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+
+-- ArchiveCutoff ::= GeneralizedTime
+
+-- AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER
+
+-- Object Identifiers
+
+id-pkix-ocsp OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) dod(6) internet(1)
+ security(5) mechanisms(5) pkix(7) pkix-ad(48) 1
+}
+
+id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
+id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 }
+-- id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 }
+-- id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 }
+-- id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 }
+-- id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 }
+-- id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 }
+
+
+END
+
diff --git a/source4/heimdal/lib/hx509/peer.c b/source4/heimdal/lib/hx509/peer.c
new file mode 100644
index 00000000000..f82f2877f6c
--- /dev/null
+++ b/source4/heimdal/lib/hx509/peer.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: peer.c,v 1.1 2006/11/26 15:49:01 lha Exp $");
+
+int
+hx509_peer_info_alloc(hx509_context context, hx509_peer_info *peer)
+{
+ *peer = calloc(1, sizeof(**peer));
+ if (*peer == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+ return 0;
+}
+
+
+static void
+free_cms_alg(hx509_peer_info peer)
+{
+ if (peer->val) {
+ size_t i;
+ for (i = 0; i < peer->len; i++)
+ free_AlgorithmIdentifier(&peer->val[i]);
+ free(peer->val);
+ peer->val = NULL;
+ peer->len = 0;
+ }
+}
+
+int
+hx509_peer_info_free(hx509_peer_info peer)
+{
+ if (peer->cert)
+ hx509_cert_free(peer->cert);
+ free_cms_alg(peer);
+ memset(peer, 0, sizeof(*peer));
+ return 0;
+}
+
+int
+hx509_peer_info_set_cert(hx509_peer_info peer,
+ hx509_cert cert)
+{
+ if (peer->cert)
+ hx509_cert_free(peer->cert);
+ peer->cert = hx509_cert_ref(cert);
+ return 0;
+}
+
+int
+hx509_peer_info_set_cms_algs(hx509_context context,
+ hx509_peer_info peer,
+ const AlgorithmIdentifier *val,
+ size_t len)
+{
+ size_t i;
+
+ free_cms_alg(peer);
+
+ peer->val = calloc(len, sizeof(*peer->val));
+ if (peer->val == NULL) {
+ peer->len = 0;
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+ peer->len = len;
+ for (i = 0; i < len; i++) {
+ int ret;
+ ret = copy_AlgorithmIdentifier(&val[i], &peer->val[i]);
+ if (ret) {
+ hx509_clear_error_string(context);
+ free_cms_alg(peer);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+#if 0
+
+/*
+ * S/MIME
+ */
+
+int
+hx509_peer_info_parse_smime(hx509_peer_info peer,
+ const heim_octet_string *data)
+{
+ return 0;
+}
+
+int
+hx509_peer_info_unparse_smime(hx509_peer_info peer,
+ heim_octet_string *data)
+{
+ return 0;
+}
+
+/*
+ * For storing hx509_peer_info to be able to cache them.
+ */
+
+int
+hx509_peer_info_parse(hx509_peer_info peer,
+ const heim_octet_string *data)
+{
+ return 0;
+}
+
+int
+hx509_peer_info_unparse(hx509_peer_info peer,
+ heim_octet_string *data)
+{
+ return 0;
+}
+#endif
diff --git a/source4/heimdal/lib/hx509/pkcs10.asn1 b/source4/heimdal/lib/hx509/pkcs10.asn1
new file mode 100644
index 00000000000..c33fd36cb2c
--- /dev/null
+++ b/source4/heimdal/lib/hx509/pkcs10.asn1
@@ -0,0 +1,25 @@
+-- $Id: pkcs10.asn1,v 1.1 2006/04/01 09:46:57 lha Exp $
+PKCS10 DEFINITIONS ::=
+
+BEGIN
+
+IMPORTS
+ Name, SubjectPublicKeyInfo, Attribute, AlgorithmIdentifier
+ FROM rfc2459;
+
+
+CertificationRequestInfo ::= SEQUENCE {
+ version INTEGER { pkcs10-v1(0) },
+ subject Name,
+ subjectPKInfo SubjectPublicKeyInfo,
+ attributes [0] IMPLICIT SET OF Attribute OPTIONAL
+}
+
+CertificationRequest ::= SEQUENCE {
+ certificationRequestInfo CertificationRequestInfo,
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING
+}
+
+END
+
diff --git a/source4/heimdal/lib/hx509/print.c b/source4/heimdal/lib/hx509/print.c
new file mode 100644
index 00000000000..802ac12b4e7
--- /dev/null
+++ b/source4/heimdal/lib/hx509/print.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: print.c,v 1.15 2006/12/07 20:37:57 lha Exp $");
+
+
+struct hx509_validate_ctx_data {
+ int flags;
+ hx509_vprint_func vprint_func;
+ void *ctx;
+};
+
+/*
+ *
+ */
+
+static int
+Time2string(const Time *T, char **str)
+{
+ time_t t;
+ char *s;
+ struct tm *tm;
+
+ *str = NULL;
+ t = _hx509_Time2time_t(T);
+ tm = gmtime (&t);
+ s = malloc(30);
+ if (s == NULL)
+ return ENOMEM;
+ strftime(s, 30, "%Y-%m-%d %H:%M:%S", tm);
+ *str = s;
+ return 0;
+}
+
+void
+hx509_print_stdout(void *ctx, const char *fmt, va_list va)
+{
+ FILE *f = ctx;
+ vfprintf(f, fmt, va);
+}
+
+void
+hx509_print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ (*func)(ctx, fmt, va);
+ va_end(va);
+}
+
+int
+hx509_oid_sprint(const heim_oid *oid, char **str)
+{
+ return der_print_heim_oid(oid, '.', str);
+}
+
+void
+hx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx)
+{
+ char *str;
+ hx509_oid_sprint(oid, &str);
+ hx509_print_func(func, ctx, "%s", str);
+ free(str);
+}
+
+void
+hx509_bitstring_print(const heim_bit_string *b,
+ hx509_vprint_func func, void *ctx)
+{
+ int i;
+ hx509_print_func(func, ctx, "\tlength: %d\n\t", b->length);
+ for (i = 0; i < (b->length + 7) / 8; i++)
+ hx509_print_func(func, ctx, "%02x%s%s",
+ ((unsigned char *)b->data)[i],
+ i < (b->length - 7) / 8
+ && (i == 0 || (i % 16) != 15) ? ":" : "",
+ i != 0 && (i % 16) == 15 ?
+ (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):"");
+}
+
+int
+hx509_cert_keyusage_print(hx509_context context, hx509_cert c, char **s)
+{
+ KeyUsage ku;
+ char buf[256];
+ int ret;
+
+ *s = NULL;
+
+ ret = _hx509_cert_get_keyusage(context, c, &ku);
+ if (ret)
+ return ret;
+ unparse_flags(KeyUsage2int(ku), asn1_KeyUsage_units(), buf, sizeof(buf));
+ *s = strdup(buf);
+ if (*s == NULL) {
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+static void
+validate_vprint(void *c, const char *fmt, va_list va)
+{
+ hx509_validate_ctx ctx = c;
+ if (ctx->vprint_func == NULL)
+ return;
+ (ctx->vprint_func)(ctx->ctx, fmt, va);
+}
+
+static void
+validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...)
+{
+ va_list va;
+ if ((ctx->flags & flags) == 0)
+ return;
+ va_start(va, fmt);
+ validate_vprint(ctx, fmt, va);
+ va_end(va);
+}
+
+enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C };
+
+static int
+check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e)
+{
+ switch(cf) {
+ case D_C:
+ break;
+ case S_C:
+ if (!e->critical)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "\tCritical not set on SHOULD\n");
+ break;
+ case S_N_C:
+ if (e->critical)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "\tCritical set on SHOULD NOT\n");
+ break;
+ case M_C:
+ if (!e->critical)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "\tCritical not set on MUST\n");
+ break;
+ case M_N_C:
+ if (e->critical)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "\tCritical set on MUST NOT\n");
+ break;
+ default:
+ _hx509_abort("internal check_Null state error");
+ }
+ return 0;
+}
+
+static int
+check_subjectKeyIdentifier(hx509_validate_ctx ctx,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ check_Null(ctx, cf, e);
+ return 0;
+}
+
+static int
+check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
+{
+ KRB5PrincipalName kn;
+ unsigned i;
+ size_t size;
+ int ret;
+
+ ret = decode_KRB5PrincipalName(a->data, a->length,
+ &kn, &size);
+ if (ret) {
+ printf("Decoding kerberos name in SAN failed: %d", ret);
+ return 1;
+ }
+
+ if (size != a->length) {
+ printf("Decoding kerberos name have extra bits on the end");
+ return 1;
+ }
+
+ /* print kerberos principal, add code to quote / within components */
+ for (i = 0; i < kn.principalName.name_string.len; i++) {
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s",
+ kn.principalName.name_string.val[i]);
+ if (i + 1 < kn.principalName.name_string.len)
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "/");
+ }
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "@");
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", kn.realm);
+
+ free_KRB5PrincipalName(&kn);
+ return 0;
+}
+
+static int
+check_dnssrv_san(hx509_validate_ctx ctx, heim_any *a)
+{
+ return 0;
+}
+
+struct {
+ const char *name;
+ const heim_oid *(*oid)(void);
+ int (*func)(hx509_validate_ctx, heim_any *);
+} check_altname[] = {
+ { "pk-init", oid_id_pkinit_san, check_pkinit_san },
+ { "dns-srv", oid_id_pkix_on_dnsSRV, check_dnssrv_san }
+};
+
+static int
+check_altName(hx509_validate_ctx ctx,
+ const char *name,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ GeneralNames gn;
+ size_t size;
+ int ret, i;
+
+ check_Null(ctx, cf, e);
+
+ if (e->extnValue.length == 0) {
+ printf("%sAltName empty, not allowed", name);
+ return 1;
+ }
+ ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length,
+ &gn, &size);
+ if (ret) {
+ printf("\tret = %d while decoding %s GeneralNames\n", ret, name);
+ return 1;
+ }
+ if (gn.len == 0) {
+ printf("%sAltName generalName empty, not allowed", name);
+ return 1;
+ }
+
+ for (i = 0; i < gn.len; i++) {
+ switch (gn.val[i].element) {
+ case choice_GeneralName_otherName: {
+ unsigned j;
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%sAltName otherName ", name);
+
+ for (j = 0; j < sizeof(check_altname)/sizeof(check_altname[0]); j++) {
+ if (der_heim_oid_cmp((*check_altname[j].oid)(),
+ &gn.val[i].u.otherName.type_id) != 0)
+ continue;
+
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ",
+ check_altname[j].name);
+ (*check_altname[j].func)(ctx, &gn.val[i].u.otherName.value);
+ break;
+ }
+ if (j == sizeof(check_altname)/sizeof(check_altname[0])) {
+ hx509_oid_print(&gn.val[i].u.otherName.type_id,
+ validate_vprint, ctx);
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown");
+ }
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n");
+ break;
+ }
+ case choice_GeneralName_rfc822Name:
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "rfc822Name: %s\n",
+ gn.val[i].u.rfc822Name);
+ break;
+ case choice_GeneralName_dNSName:
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "dNSName: %s\n",
+ gn.val[i].u.dNSName);
+ break;
+ case choice_GeneralName_directoryName: {
+ Name dir;
+ char *s;
+ dir.element = gn.val[i].u.directoryName.element;
+ dir.u.rdnSequence = gn.val[i].u.directoryName.u.rdnSequence;
+ ret = _hx509_unparse_Name(&dir, &s);
+ if (ret) {
+ printf("unable to parse %sAltName directoryName\n", name);
+ return 1;
+ }
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "directoryName: %s\n", s);
+ free(s);
+ break;
+ }
+ case choice_GeneralName_uniformResourceIdentifier:
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "uri: %s\n",
+ gn.val[i].u.uniformResourceIdentifier);
+ break;
+ case choice_GeneralName_iPAddress:
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "ip address\n");
+ break;
+ case choice_GeneralName_registeredID:
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "registered id: ");
+ hx509_oid_print(&gn.val[i].u.registeredID,
+ validate_vprint, ctx);
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n");
+ break;
+ }
+ }
+
+ free_GeneralNames(&gn);
+
+ return 0;
+}
+
+static int
+check_subjectAltName(hx509_validate_ctx ctx,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ return check_altName(ctx, "subject", cf, e);
+}
+
+static int
+check_issuerAltName(hx509_validate_ctx ctx,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ return check_altName(ctx, "issuer", cf, e);
+}
+
+
+static int
+check_basicConstraints(hx509_validate_ctx ctx,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ BasicConstraints b;
+ size_t size;
+ int ret;
+
+ check_Null(ctx, cf, e);
+
+ ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length,
+ &b, &size);
+ if (ret) {
+ printf("\tret = %d while decoding BasicConstraints\n", ret);
+ return 0;
+ }
+ if (size != e->extnValue.length)
+ printf("\tlength of der data isn't same as extension\n");
+
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT ");
+ if (b.pathLenConstraint)
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "\tpathLenConstraint: %d\n", *b.pathLenConstraint);
+
+ return 0;
+}
+
+struct {
+ const char *name;
+ const heim_oid *(*oid)(void);
+ int (*func)(hx509_validate_ctx ctx,
+ enum critical_flag cf,
+ const Extension *);
+ enum critical_flag cf;
+} check_extension[] = {
+#define ext(name, checkname) #name, &oid_id_x509_ce_##name, check_##checkname
+ { ext(subjectDirectoryAttributes, Null), M_N_C },
+ { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C },
+ { ext(keyUsage, Null), S_C },
+ { ext(subjectAltName, subjectAltName), M_N_C },
+ { ext(issuerAltName, issuerAltName), S_N_C },
+ { ext(basicConstraints, basicConstraints), M_C },
+ { ext(cRLNumber, Null), M_N_C },
+ { ext(cRLReason, Null), M_N_C },
+ { ext(holdInstructionCode, Null), M_N_C },
+ { ext(invalidityDate, Null), M_N_C },
+ { ext(deltaCRLIndicator, Null), M_C },
+ { ext(issuingDistributionPoint, Null), M_C },
+ { ext(certificateIssuer, Null), M_C },
+ { ext(nameConstraints, Null), M_C },
+ { ext(cRLDistributionPoints, Null), S_N_C },
+ { ext(certificatePolicies, Null) },
+ { ext(policyMappings, Null), M_N_C },
+ { ext(authorityKeyIdentifier, Null), M_N_C },
+ { ext(policyConstraints, Null), D_C },
+ { ext(extKeyUsage, Null), D_C },
+ { ext(freshestCRL, Null), M_N_C },
+ { ext(inhibitAnyPolicy, Null), M_C },
+ { NULL }
+};
+
+int
+hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx)
+{
+ *ctx = malloc(sizeof(**ctx));
+ if (*ctx == NULL)
+ return ENOMEM;
+ memset(*ctx, 0, sizeof(**ctx));
+ return 0;
+}
+
+void
+hx509_validate_ctx_set_print(hx509_validate_ctx ctx,
+ hx509_vprint_func func,
+ void *c)
+{
+ ctx->vprint_func = func;
+ ctx->ctx = c;
+}
+
+void
+hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags)
+{
+ ctx->flags |= flags;
+}
+
+void
+hx509_validate_ctx_free(hx509_validate_ctx ctx)
+{
+ free(ctx);
+}
+
+int
+hx509_validate_cert(hx509_context context,
+ hx509_validate_ctx ctx,
+ hx509_cert cert)
+{
+ Certificate *c = _hx509_get_cert(cert);
+ TBSCertificate *t = &c->tbsCertificate;
+ hx509_name name;
+ char *str;
+
+ if (_hx509_cert_get_version(c) != 3)
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "Not version 3 certificate\n");
+
+ if (t->version && *t->version < 2 && t->extensions)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Not version 3 certificate with extensions\n");
+
+ _hx509_name_from_Name(&t->subject, &name);
+ hx509_name_to_string(name, &str);
+ hx509_name_free(&name);
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "subject name: %s\n", str);
+ free(str);
+
+ _hx509_name_from_Name(&t->issuer, &name);
+ hx509_name_to_string(name, &str);
+ hx509_name_free(&name);
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "issuer name: %s\n", str);
+ free(str);
+
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "Validity:\n");
+
+ Time2string(&t->validity.notBefore, &str);
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str);
+ free(str);
+ Time2string(&t->validity.notAfter, &str);
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str);
+ free(str);
+
+ if (t->extensions) {
+ int i, j;
+
+ if (t->extensions->len == 0) {
+ validate_print(ctx,
+ HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE,
+ "The empty extensions list is not "
+ "allowed by PKIX\n");
+ }
+
+ for (i = 0; i < t->extensions->len; i++) {
+
+ for (j = 0; check_extension[j].name; j++)
+ if (der_heim_oid_cmp((*check_extension[j].oid)(),
+ &t->extensions->val[i].extnID) == 0)
+ break;
+ if (check_extension[j].name == NULL) {
+ int flags = HX509_VALIDATE_F_VERBOSE;
+ if (t->extensions->val[i].critical)
+ flags |= HX509_VALIDATE_F_VALIDATE;
+ validate_print(ctx, flags, "don't know what ");
+ if (t->extensions->val[i].critical)
+ validate_print(ctx, flags, "and is CRITICAL ");
+ if (ctx->flags & flags)
+ hx509_oid_print(&t->extensions->val[i].extnID,
+ validate_vprint, ctx);
+ validate_print(ctx, flags, " is\n");
+ continue;
+ }
+ validate_print(ctx,
+ HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE,
+ "checking extention: %s\n",
+ check_extension[j].name);
+ (*check_extension[j].func)(ctx,
+ check_extension[j].cf,
+ &t->extensions->val[i]);
+ }
+ } else
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n");
+
+ return 0;
+}
diff --git a/source4/heimdal/lib/hx509/req.c b/source4/heimdal/lib/hx509/req.c
new file mode 100644
index 00000000000..ca7baa514b6
--- /dev/null
+++ b/source4/heimdal/lib/hx509/req.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+#include <pkcs10_asn1.h>
+RCSID("$Id: req.c,v 1.7 2007/01/04 20:20:11 lha Exp $");
+
+struct hx509_request_data {
+ hx509_name name;
+ SubjectPublicKeyInfo key;
+ ExtKeyUsage eku;
+ GeneralNames san;
+};
+
+/*
+ *
+ */
+
+int
+_hx509_request_init(hx509_context context, hx509_request *req)
+{
+ *req = calloc(1, sizeof(**req));
+ if (*req == NULL)
+ return ENOMEM;
+
+ return 0;
+}
+
+void
+_hx509_request_free(hx509_request *req)
+{
+ if ((*req)->name)
+ hx509_name_free(&(*req)->name);
+ free_SubjectPublicKeyInfo(&(*req)->key);
+ free_ExtKeyUsage(&(*req)->eku);
+ free_GeneralNames(&(*req)->san);
+ memset(*req, 0, sizeof(**req));
+ free(*req);
+ *req = NULL;
+}
+
+int
+_hx509_request_set_name(hx509_context context,
+ hx509_request req,
+ hx509_name name)
+{
+ if (req->name)
+ hx509_name_free(&req->name);
+ if (name) {
+ int ret = hx509_name_copy(context, name, &req->name);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int
+_hx509_request_set_SubjectPublicKeyInfo(hx509_context context,
+ hx509_request req,
+ const SubjectPublicKeyInfo *key)
+{
+ free_SubjectPublicKeyInfo(&req->key);
+ return copy_SubjectPublicKeyInfo(key, &req->key);
+}
+
+int
+_hx509_request_add_eku(hx509_context context,
+ hx509_request req,
+ const heim_oid *oid)
+{
+ void *val;
+ int ret;
+
+ val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1));
+ if (val == NULL)
+ return ENOMEM;
+ req->eku.val = val;
+
+ ret = der_copy_oid(oid, &req->eku.val[req->eku.len]);
+ if (ret)
+ return ret;
+
+ req->eku.len += 1;
+
+ return 0;
+}
+
+int
+_hx509_request_add_dns_name(hx509_context context,
+ hx509_request req,
+ const char *hostname)
+{
+ GeneralName name;
+
+ memset(&name, 0, sizeof(name));
+ name.element = choice_GeneralName_dNSName;
+ name.u.dNSName = rk_UNCONST(hostname);
+
+ return add_GeneralNames(&req->san, &name);
+}
+
+int
+_hx509_request_add_email(hx509_context context,
+ hx509_request req,
+ const char *email)
+{
+ GeneralName name;
+
+ memset(&name, 0, sizeof(name));
+ name.element = choice_GeneralName_rfc822Name;
+ name.u.dNSName = rk_UNCONST(email);
+
+ return add_GeneralNames(&req->san, &name);
+}
+
+
+
+int
+_hx509_request_to_pkcs10(hx509_context context,
+ const hx509_request req,
+ const hx509_private_key signer,
+ heim_octet_string *request)
+{
+ CertificationRequest r;
+ heim_octet_string data, os;
+ int ret;
+ size_t size;
+
+ if (req->name == NULL) {
+ hx509_set_error_string(context, 0, EINVAL,
+ "PKCS10 needs to have a subject");
+ return EINVAL;
+ }
+
+ memset(&r, 0, sizeof(r));
+ memset(request, 0, sizeof(*request));
+
+ r.certificationRequestInfo.version = pkcs10_v1;
+
+ ret = copy_Name(&req->name->der_name,
+ &r.certificationRequestInfo.subject);
+ if (ret)
+ goto out;
+ ret = copy_SubjectPublicKeyInfo(&req->key,
+ &r.certificationRequestInfo.subjectPKInfo);
+ if (ret)
+ goto out;
+ r.certificationRequestInfo.attributes =
+ calloc(1, sizeof(*r.certificationRequestInfo.attributes));
+ if (r.certificationRequestInfo.attributes == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length,
+ &r.certificationRequestInfo, &size, ret);
+ if (ret)
+ goto out;
+ if (data.length != size)
+ abort();
+
+ ret = _hx509_create_signature(context,
+ signer,
+ hx509_signature_rsa_with_sha1(),
+ &data,
+ &r.signatureAlgorithm,
+ &os);
+ free(data.data);
+ if (ret)
+ goto out;
+ r.signature.data = os.data;
+ r.signature.length = os.length * 8;
+
+ ASN1_MALLOC_ENCODE(CertificationRequest, data.data, data.length,
+ &r, &size, ret);
+ if (ret)
+ goto out;
+ if (data.length != size)
+ abort();
+
+ *request = data;
+
+out:
+ free_CertificationRequest(&r);
+
+ return ret;
+}
diff --git a/source4/heimdal/lib/hx509/revoke.c b/source4/heimdal/lib/hx509/revoke.c
new file mode 100644
index 00000000000..8067b29c109
--- /dev/null
+++ b/source4/heimdal/lib/hx509/revoke.c
@@ -0,0 +1,1020 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: revoke.c,v 1.32 2006/12/30 17:09:06 lha Exp $");
+
+struct revoke_crl {
+ char *path;
+ time_t last_modfied;
+ CRLCertificateList crl;
+ int verified;
+};
+
+struct revoke_ocsp {
+ char *path;
+ time_t last_modfied;
+ OCSPBasicOCSPResponse ocsp;
+ hx509_certs certs;
+ hx509_cert signer;
+};
+
+
+struct hx509_revoke_ctx_data {
+ struct {
+ struct revoke_crl *val;
+ size_t len;
+ } crls;
+ struct {
+ struct revoke_ocsp *val;
+ size_t len;
+ } ocsps;
+};
+
+int
+hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
+{
+ *ctx = calloc(1, sizeof(**ctx));
+ if (*ctx == NULL)
+ return ENOMEM;
+
+ (*ctx)->crls.len = 0;
+ (*ctx)->crls.val = NULL;
+ (*ctx)->ocsps.len = 0;
+ (*ctx)->ocsps.val = NULL;
+
+ return 0;
+}
+
+static void
+free_ocsp(struct revoke_ocsp *ocsp)
+{
+ free(ocsp->path);
+ free_OCSPBasicOCSPResponse(&ocsp->ocsp);
+ hx509_certs_free(&ocsp->certs);
+ hx509_cert_free(ocsp->signer);
+}
+
+void
+hx509_revoke_free(hx509_revoke_ctx *ctx)
+{
+ size_t i ;
+
+ if (ctx == NULL || *ctx == NULL)
+ return;
+
+ for (i = 0; i < (*ctx)->crls.len; i++) {
+ free((*ctx)->crls.val[i].path);
+ free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
+ }
+
+ for (i = 0; i < (*ctx)->ocsps.len; i++)
+ free_ocsp(&(*ctx)->ocsps.val[i]);
+ free((*ctx)->ocsps.val);
+
+ free((*ctx)->crls.val);
+
+ memset(*ctx, 0, sizeof(**ctx));
+ free(*ctx);
+ *ctx = NULL;
+}
+
+static int
+verify_ocsp(hx509_context context,
+ struct revoke_ocsp *ocsp,
+ time_t time_now,
+ hx509_certs certs,
+ hx509_cert parent)
+{
+ hx509_cert signer = NULL;
+ hx509_query q;
+ int ret;
+
+ _hx509_query_clear(&q);
+
+ /*
+ * Need to match on issuer too in case there are two CA that have
+ * issued the same name to a certificate. One example of this is
+ * the www.openvalidation.org test's ocsp validator.
+ */
+
+ q.match = HX509_QUERY_MATCH_ISSUER_NAME;
+ q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
+
+ switch(ocsp->ocsp.tbsResponseData.responderID.element) {
+ case choice_OCSPResponderID_byName:
+ q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
+ q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
+ break;
+ case choice_OCSPResponderID_byKey:
+ q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
+ q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
+ break;
+ }
+
+ ret = hx509_certs_find(context, certs, &q, &signer);
+ if (ret && ocsp->certs)
+ ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
+ if (ret)
+ goto out;
+
+ /*
+ * If signer certificate isn't the CA certificate, lets check the
+ * its the CA that signed the signer certificate and the OCSP EKU
+ * is set.
+ */
+ if (hx509_cert_cmp(signer, parent) != 0) {
+ Certificate *p = _hx509_get_cert(parent);
+ Certificate *s = _hx509_get_cert(signer);
+
+ ret = _hx509_cert_is_parent_cmp(s, p, 0);
+ if (ret != 0) {
+ ret = HX509_PARENT_NOT_CA;
+ hx509_set_error_string(context, 0, ret, "Revoke OSCP signer is "
+ "doesn't have CA as signer certificate");
+ goto out;
+ }
+
+ ret = _hx509_verify_signature_bitstring(context,
+ p,
+ &s->signatureAlgorithm,
+ &s->tbsCertificate._save,
+ &s->signatureValue);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "OSCP signer signature invalid");
+ goto out;
+ }
+
+ ret = hx509_cert_check_eku(context, signer,
+ oid_id_pkix_kp_OCSPSigning(), 0);
+ if (ret)
+ goto out;
+ }
+
+ ret = _hx509_verify_signature_bitstring(context,
+ _hx509_get_cert(signer),
+ &ocsp->ocsp.signatureAlgorithm,
+ &ocsp->ocsp.tbsResponseData._save,
+ &ocsp->ocsp.signature);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "OSCP signature invalid");
+ goto out;
+ }
+
+ ocsp->signer = signer;
+ signer = NULL;
+out:
+ if (signer)
+ hx509_cert_free(signer);
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+static int
+parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
+{
+ OCSPResponse resp;
+ size_t size;
+ int ret;
+
+ memset(basic, 0, sizeof(*basic));
+
+ ret = decode_OCSPResponse(data, length, &resp, &size);
+ if (ret)
+ return ret;
+ if (length != size) {
+ free_OCSPResponse(&resp);
+ return ASN1_EXTRA_DATA;
+ }
+
+ switch (resp.responseStatus) {
+ case successful:
+ break;
+ default:
+ free_OCSPResponse(&resp);
+ return HX509_REVOKE_WRONG_DATA;
+ }
+
+ if (resp.responseBytes == NULL) {
+ free_OCSPResponse(&resp);
+ return EINVAL;
+ }
+
+ ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
+ oid_id_pkix_ocsp_basic());
+ if (ret != 0) {
+ free_OCSPResponse(&resp);
+ return HX509_REVOKE_WRONG_DATA;
+ }
+
+ ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
+ resp.responseBytes->response.length,
+ basic,
+ &size);
+ if (ret) {
+ free_OCSPResponse(&resp);
+ return ret;
+ }
+ if (size != resp.responseBytes->response.length) {
+ free_OCSPResponse(&resp);
+ free_OCSPBasicOCSPResponse(basic);
+ return ASN1_EXTRA_DATA;
+ }
+ free_OCSPResponse(&resp);
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+static int
+load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
+{
+ OCSPBasicOCSPResponse basic;
+ hx509_certs certs = NULL;
+ size_t length;
+ struct stat sb;
+ void *data;
+ int ret;
+
+ ret = _hx509_map_file(ocsp->path, &data, &length, &sb);
+ if (ret)
+ return ret;
+
+ ret = parse_ocsp_basic(data, length, &basic);
+ _hx509_unmap_file(data, length);
+ if (ret)
+ return ret;
+
+ if (basic.certs) {
+ int i;
+
+ ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
+ NULL, &certs);
+ if (ret) {
+ free_OCSPBasicOCSPResponse(&basic);
+ return ret;
+ }
+
+ for (i = 0; i < basic.certs->len; i++) {
+ hx509_cert c;
+
+ ret = hx509_cert_init(context, &basic.certs->val[i], &c);
+ if (ret)
+ continue;
+
+ ret = hx509_certs_add(context, certs, c);
+ hx509_cert_free(c);
+ if (ret)
+ continue;
+ }
+ }
+
+ ocsp->last_modfied = sb.st_mtime;
+
+ free_OCSPBasicOCSPResponse(&ocsp->ocsp);
+ hx509_certs_free(&ocsp->certs);
+ hx509_cert_free(ocsp->signer);
+
+ ocsp->ocsp = basic;
+ ocsp->certs = certs;
+ ocsp->signer = NULL;
+
+ return 0;
+}
+
+int
+hx509_revoke_add_ocsp(hx509_context context,
+ hx509_revoke_ctx ctx,
+ const char *path)
+{
+ void *data;
+ int ret;
+ size_t i;
+
+ if (strncmp(path, "FILE:", 5) != 0) {
+ hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
+ "unsupport type in %s", path);
+ return HX509_UNSUPPORTED_OPERATION;
+ }
+
+ path += 5;
+
+ for (i = 0; i < ctx->ocsps.len; i++) {
+ if (strcmp(ctx->ocsps.val[0].path, path) == 0)
+ return 0;
+ }
+
+ data = realloc(ctx->ocsps.val,
+ (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
+ if (data == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ ctx->ocsps.val = data;
+
+ memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
+ sizeof(ctx->ocsps.val[0]));
+
+ ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
+ if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
+ if (ret) {
+ free(ctx->ocsps.val[ctx->ocsps.len].path);
+ return ret;
+ }
+ ctx->ocsps.len++;
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+static int
+verify_crl(hx509_context context,
+ CRLCertificateList *crl,
+ time_t time_now,
+ hx509_certs certs,
+ hx509_cert parent)
+{
+ hx509_cert signer;
+ hx509_query q;
+ time_t t;
+ int ret;
+
+ t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
+ if (t > time_now)
+ return HX509_CRL_USED_BEFORE_TIME;
+
+ if (crl->tbsCertList.nextUpdate == NULL)
+ return HX509_CRL_INVALID_FORMAT;
+
+ t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
+ if (t < time_now)
+ return HX509_CRL_USED_AFTER_TIME;
+
+ _hx509_query_clear(&q);
+
+ q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
+ q.subject_name = &crl->tbsCertList.issuer;
+
+ ret = hx509_certs_find(context, certs, &q, &signer);
+ if (ret)
+ return ret;
+
+ /* verify is parent or CRLsigner */
+ if (hx509_cert_cmp(signer, parent) != 0) {
+ Certificate *p = _hx509_get_cert(parent);
+ Certificate *s = _hx509_get_cert(signer);
+
+ ret = _hx509_cert_is_parent_cmp(s, p, 0);
+ if (ret != 0) {
+ ret = HX509_PARENT_NOT_CA;
+ hx509_set_error_string(context, 0, ret, "Revoke CRL signer is "
+ "doesn't have CA as signer certificate");
+ goto out;
+ }
+
+ ret = _hx509_verify_signature_bitstring(context,
+ p,
+ &s->signatureAlgorithm,
+ &s->tbsCertificate._save,
+ &s->signatureValue);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
+ "CRL signer signature invalid");
+ goto out;
+ }
+
+ ret = _hx509_check_key_usage(context, signer, 1 << 6, TRUE); /* crl */
+ if (ret != 0)
+ goto out;
+ }
+
+ ret = _hx509_verify_signature_bitstring(context,
+ _hx509_get_cert(signer),
+ &crl->signatureAlgorithm,
+ &crl->tbsCertList._save,
+ &crl->signatureValue);
+ if (ret) {
+ hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "CRL signature invalid");
+ goto out;
+ }
+
+out:
+ hx509_cert_free(signer);
+
+ return ret;
+}
+
+static int
+load_crl(const char *path, time_t *t, CRLCertificateList *crl)
+{
+ size_t length, size;
+ struct stat sb;
+ void *data;
+ int ret;
+
+ memset(crl, 0, sizeof(*crl));
+
+ ret = _hx509_map_file(path, &data, &length, &sb);
+ if (ret)
+ return ret;
+
+ *t = sb.st_mtime;
+
+ ret = decode_CRLCertificateList(data, length, crl, &size);
+ _hx509_unmap_file(data, length);
+ if (ret)
+ return ret;
+
+ /* check signature is aligned */
+ if (crl->signatureValue.length & 7) {
+ free_CRLCertificateList(crl);
+ return HX509_CRYPTO_SIG_INVALID_FORMAT;
+ }
+ return 0;
+}
+
+int
+hx509_revoke_add_crl(hx509_context context,
+ hx509_revoke_ctx ctx,
+ const char *path)
+{
+ void *data;
+ size_t i;
+ int ret;
+
+ if (strncmp(path, "FILE:", 5) != 0) {
+ hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
+ "unsupport type in %s", path);
+ return HX509_UNSUPPORTED_OPERATION;
+ }
+
+
+ path += 5;
+
+ for (i = 0; i < ctx->crls.len; i++) {
+ if (strcmp(ctx->crls.val[0].path, path) == 0)
+ return 0;
+ }
+
+ data = realloc(ctx->crls.val,
+ (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
+ if (data == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+ ctx->crls.val = data;
+
+ memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
+
+ ctx->crls.val[ctx->crls.len].path = strdup(path);
+ if (ctx->crls.val[ctx->crls.len].path == NULL) {
+ hx509_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ ret = load_crl(path,
+ &ctx->crls.val[ctx->crls.len].last_modfied,
+ &ctx->crls.val[ctx->crls.len].crl);
+ if (ret) {
+ free(ctx->crls.val[ctx->crls.len].path);
+ return ret;
+ }
+
+ ctx->crls.len++;
+
+ return ret;
+}
+
+
+int
+hx509_revoke_verify(hx509_context context,
+ hx509_revoke_ctx ctx,
+ hx509_certs certs,
+ time_t now,
+ hx509_cert cert,
+ hx509_cert parent_cert)
+{
+ const Certificate *c = _hx509_get_cert(cert);
+ const Certificate *p = _hx509_get_cert(parent_cert);
+ unsigned long i, j, k;
+ int ret;
+
+ for (i = 0; i < ctx->ocsps.len; i++) {
+ struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
+ struct stat sb;
+
+ /* check this ocsp apply to this cert */
+
+ /* check if there is a newer version of the file */
+ ret = stat(ocsp->path, &sb);
+ if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
+ ret = load_ocsp(context, ocsp);
+ if (ret)
+ continue;
+ }
+
+ /* verify signature in ocsp if not already done */
+ if (ocsp->signer == NULL) {
+ ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
+ if (ret)
+ continue;
+ }
+
+ for (i = 0; i < ocsp->ocsp.tbsResponseData.responses.len; i++) {
+ heim_octet_string os;
+
+ ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[i].certID.serialNumber,
+ &c->tbsCertificate.serialNumber);
+ if (ret != 0)
+ continue;
+
+ /* verify issuer hashes hash */
+ ret = _hx509_verify_signature(context,
+ NULL,
+ &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
+ &c->tbsCertificate.issuer._save,
+ &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
+ if (ret != 0)
+ continue;
+
+ os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
+ os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
+
+ ret = _hx509_verify_signature(context,
+ NULL,
+ &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
+ &os,
+ &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerKeyHash);
+ if (ret != 0)
+ continue;
+
+ switch (ocsp->ocsp.tbsResponseData.responses.val[i].certStatus.element) {
+ case choice_OCSPCertStatus_good:
+ break;
+ case choice_OCSPCertStatus_revoked:
+ case choice_OCSPCertStatus_unknown:
+ continue;
+ }
+
+ /* don't allow the update to be in the future */
+ if (ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate >
+ now + context->ocsp_time_diff)
+ continue;
+
+ /* don't allow the next updte to be in the past */
+ if (ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate) {
+ if (*ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate < now)
+ continue;
+ } else
+ /* Should force a refetch, but can we ? */;
+
+ return 0;
+ }
+ }
+
+ for (i = 0; i < ctx->crls.len; i++) {
+ struct revoke_crl *crl = &ctx->crls.val[i];
+ struct stat sb;
+
+ /* check if cert.issuer == crls.val[i].crl.issuer */
+ ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
+ &crl->crl.tbsCertList.issuer);
+ if (ret)
+ continue;
+
+ ret = stat(crl->path, &sb);
+ if (ret == 0 && crl->last_modfied != sb.st_mtime) {
+ CRLCertificateList cl;
+
+ ret = load_crl(crl->path, &crl->last_modfied, &cl);
+ if (ret == 0) {
+ free_CRLCertificateList(&crl->crl);
+ crl->crl = cl;
+ crl->verified = 0;
+ }
+ }
+
+ /* verify signature in crl if not already done */
+ if (crl->verified == 0) {
+ ret = verify_crl(context, &crl->crl, now, certs, parent_cert);
+ if (ret)
+ return ret;
+ crl->verified = 1;
+ }
+
+ if (crl->crl.tbsCertList.crlExtensions)
+ for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++)
+ if (crl->crl.tbsCertList.crlExtensions->val[j].critical)
+ return HX509_CRL_UNKNOWN_EXTENSION;
+
+ if (crl->crl.tbsCertList.revokedCertificates == NULL)
+ return 0;
+
+ /* check if cert is in crl */
+ for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
+ time_t t;
+
+ ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
+ &c->tbsCertificate.serialNumber);
+ if (ret != 0)
+ continue;
+
+ t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
+ if (t > now)
+ continue;
+
+ if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
+ for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
+ if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
+ return HX509_CRL_UNKNOWN_EXTENSION;
+
+ return HX509_CRL_CERT_REVOKED;
+ }
+
+ return 0;
+ }
+
+
+ if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
+ return 0;
+ return HX509_REVOKE_STATUS_MISSING;
+}
+
+struct ocsp_add_ctx {
+ OCSPTBSRequest *req;
+ hx509_certs certs;
+ const AlgorithmIdentifier *digest;
+ hx509_cert parent;
+};
+
+static int
+add_to_req(hx509_context context, void *ptr, hx509_cert cert)
+{
+ struct ocsp_add_ctx *ctx = ptr;
+ OCSPInnerRequest *one;
+ hx509_cert parent = NULL;
+ Certificate *p, *c = _hx509_get_cert(cert);
+ heim_octet_string os;
+ int ret;
+ hx509_query q;
+ void *d;
+
+ d = realloc(ctx->req->requestList.val,
+ sizeof(ctx->req->requestList.val[0]) *
+ (ctx->req->requestList.len + 1));
+ if (d == NULL)
+ return ENOMEM;
+ ctx->req->requestList.val = d;
+
+ one = &ctx->req->requestList.val[ctx->req->requestList.len];
+ memset(one, 0, sizeof(*one));
+
+ _hx509_query_clear(&q);
+
+ q.match |= HX509_QUERY_FIND_ISSUER_CERT;
+ q.subject = c;
+
+ ret = hx509_certs_find(context, ctx->certs, &q, &parent);
+ if (ret)
+ goto out;
+
+ if (ctx->parent) {
+ if (hx509_cert_cmp(ctx->parent, parent) != 0) {
+ ret = HX509_REVOKE_NOT_SAME_PARENT;
+ hx509_set_error_string(context, 0, ret,
+ "Not same parent certifate as "
+ "last certificate in request");
+ goto out;
+ }
+ } else
+ ctx->parent = hx509_cert_ref(parent);
+
+ p = _hx509_get_cert(parent);
+
+ ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
+ if (ret)
+ goto out;
+
+ ret = _hx509_create_signature(context,
+ NULL,
+ &one->reqCert.hashAlgorithm,
+ &c->tbsCertificate.issuer._save,
+ NULL,
+ &one->reqCert.issuerNameHash);
+ if (ret)
+ goto out;
+
+ os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
+ os.length =
+ p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
+
+ ret = _hx509_create_signature(context,
+ NULL,
+ &one->reqCert.hashAlgorithm,
+ &os,
+ NULL,
+ &one->reqCert.issuerKeyHash);
+ if (ret)
+ goto out;
+
+ ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
+ &one->reqCert.serialNumber);
+ if (ret)
+ goto out;
+
+ ctx->req->requestList.len++;
+out:
+ hx509_cert_free(parent);
+ if (ret) {
+ free_OCSPInnerRequest(one);
+ memset(one, 0, sizeof(*one));
+ }
+
+ return ret;
+}
+
+
+int
+hx509_ocsp_request(hx509_context context,
+ hx509_certs reqcerts,
+ hx509_certs pool,
+ hx509_cert signer,
+ const AlgorithmIdentifier *digest,
+ heim_octet_string *request,
+ heim_octet_string *nonce)
+{
+ OCSPRequest req;
+ size_t size;
+ int ret;
+ struct ocsp_add_ctx ctx;
+ Extensions *es;
+
+ memset(&req, 0, sizeof(req));
+
+ if (digest == NULL)
+ digest = hx509_signature_sha1();
+
+ ctx.req = &req.tbsRequest;
+ ctx.certs = pool;
+ ctx.digest = digest;
+ ctx.parent = NULL;
+
+ ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx);
+ hx509_cert_free(ctx.parent);
+ if (ret) {
+ free_OCSPRequest(&req);
+ return ret;
+ }
+
+ if (nonce) {
+
+ req.tbsRequest.requestExtensions =
+ calloc(1, sizeof(*req.tbsRequest.requestExtensions));
+ if (req.tbsRequest.requestExtensions == NULL) {
+ free_OCSPRequest(&req);
+ return ENOMEM;
+ }
+
+ es = req.tbsRequest.requestExtensions;
+
+ es->len = 1;
+ es->val = calloc(es->len, sizeof(es->val[0]));
+
+ ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID);
+ if (ret)
+ abort();
+
+ es->val[0].extnValue.data = malloc(10);
+ if (es->val[0].extnValue.data == NULL) {
+ free_OCSPRequest(&req);
+ return ENOMEM;
+ }
+ es->val[0].extnValue.length = 10;
+
+ ret = RAND_bytes(es->val[0].extnValue.data,
+ es->val[0].extnValue.length);
+ if (ret != 1) {
+ free_OCSPRequest(&req);
+ return HX509_CRYPTO_INTERNAL_ERROR;
+ }
+ }
+
+ ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
+ &req, &size, ret);
+ free_OCSPRequest(&req);
+ if (ret)
+ return ret;
+ if (size != request->length)
+ _hx509_abort("internal ASN.1 encoder error");
+
+
+ return 0;
+}
+
+static char *
+printable_time(time_t t)
+{
+ static char s[128];
+ strlcpy(s, ctime(&t)+ 4, sizeof(s));
+ s[20] = 0;
+ return s;
+}
+
+int
+hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
+{
+ struct revoke_ocsp ocsp;
+ int ret, i;
+
+ if (out == NULL)
+ out = stdout;
+
+ memset(&ocsp, 0, sizeof(ocsp));
+
+ ocsp.path = strdup(path);
+ if (ocsp.path == NULL)
+ return ENOMEM;
+
+ ret = load_ocsp(context, &ocsp);
+ if (ret) {
+ free_ocsp(&ocsp);
+ return ret;
+ }
+
+ fprintf(out, "signer: ");
+
+ switch(ocsp.ocsp.tbsResponseData.responderID.element) {
+ case choice_OCSPResponderID_byName: {
+ hx509_name n;
+ char *s;
+ _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
+ hx509_name_to_string(n, &s);
+ hx509_name_free(&n);
+ fprintf(out, " byName: %s\n", s);
+ free(s);
+ break;
+ }
+ case choice_OCSPResponderID_byKey: {
+ char *s;
+ hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
+ ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
+ &s);
+ fprintf(out, " byKey: %s\n", s);
+ free(s);
+ break;
+ }
+ default:
+ _hx509_abort("choice_OCSPResponderID unknown");
+ break;
+ }
+
+ fprintf(out, "producedAt: %s\n",
+ printable_time(ocsp.ocsp.tbsResponseData.producedAt));
+
+ fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
+
+ for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
+ char *status;
+ switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
+ case choice_OCSPCertStatus_good:
+ status = "good";
+ break;
+ case choice_OCSPCertStatus_revoked:
+ status = "revoked";
+ break;
+ case choice_OCSPCertStatus_unknown:
+ status = "unknown";
+ break;
+ default:
+ status = "element unknown";
+ }
+
+ fprintf(out, "\t%d. status: %s\n", i, status);
+
+ fprintf(out, "\tthisUpdate: %s\n",
+ printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
+ if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
+ fprintf(out, "\tproducedAt: %s\n",
+ printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
+
+ }
+
+ fprintf(out, "appended certs:\n");
+ if (ocsp.certs)
+ ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out);
+
+ free_ocsp(&ocsp);
+ return ret;
+}
+
+int
+hx509_ocsp_verify(hx509_context context,
+ time_t now,
+ hx509_cert cert,
+ int flags,
+ const void *data, size_t length,
+ time_t *expiration)
+{
+ const Certificate *c = _hx509_get_cert(cert);
+ OCSPBasicOCSPResponse basic;
+ int ret, i;
+
+ *expiration = 0;
+
+ ret = parse_ocsp_basic(data, length, &basic);
+ if (ret)
+ return ret;
+
+
+ for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
+
+ ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
+ &c->tbsCertificate.serialNumber);
+ if (ret != 0)
+ continue;
+
+ /* verify issuer hashes hash */
+ ret = _hx509_verify_signature(context,
+ NULL,
+ &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
+ &c->tbsCertificate.issuer._save,
+ &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
+ if (ret != 0)
+ continue;
+
+ switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
+ case choice_OCSPCertStatus_good:
+ break;
+ case choice_OCSPCertStatus_revoked:
+ case choice_OCSPCertStatus_unknown:
+ continue;
+ }
+
+ /* don't allow the update to be in the future */
+ if (basic.tbsResponseData.responses.val[i].thisUpdate >
+ now + context->ocsp_time_diff)
+ continue;
+
+ /* don't allow the next updte to be in the past */
+ if (basic.tbsResponseData.responses.val[i].nextUpdate) {
+ if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
+ continue;
+ } else
+ continue;
+
+ *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
+
+ return 0;
+ }
+ free_OCSPBasicOCSPResponse(&basic);
+
+ return 0;
+}
diff --git a/source4/heimdal/lib/hx509/test_name.c b/source4/heimdal/lib/hx509/test_name.c
new file mode 100644
index 00000000000..9017e54ab1f
--- /dev/null
+++ b/source4/heimdal/lib/hx509/test_name.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hx_locl.h"
+RCSID("$Id: test_name.c,v 1.6 2006/12/30 23:04:54 lha Exp $");
+
+static int
+test_name(hx509_context context, const char *name)
+{
+ hx509_name n;
+ char *s;
+ int ret;
+
+ ret = hx509_parse_name(context, name, &n);
+ if (ret)
+ return 1;
+
+ ret = hx509_name_to_string(n, &s);
+ if (ret)
+ return 1;
+
+ if (strcmp(s, name) != 0)
+ return 1;
+
+ hx509_name_free(&n);
+ free(s);
+
+ return 0;
+}
+
+static int
+test_name_fail(hx509_context context, const char *name)
+{
+ hx509_name n;
+
+ if (hx509_parse_name(context, name, &n) == HX509_NAME_MALFORMED)
+ return 0;
+ hx509_name_free(&n);
+ return 1;
+}
+
+int
+main(int argc, char **argv)
+{
+ hx509_context context;
+ int ret = 0;
+
+ ret = hx509_context_init(&context);
+ if (ret)
+ errx(1, "hx509_context_init failed with %d", ret);
+
+ ret += test_name(context, "CN=foo,C=SE");
+ ret += test_name(context, "CN=foo,CN=kaka,CN=FOO,DC=ad1,C=SE");
+ ret += test_name(context, "1.2.3.4=foo,C=SE");
+ ret += test_name_fail(context, "=");
+ ret += test_name_fail(context, "CN=foo,=foo");
+ ret += test_name_fail(context, "CN=foo,really-unknown-type=foo");
+
+ hx509_context_free(&context);
+
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c
index 004926bc894..d20c24699be 100644
--- a/source4/heimdal/lib/krb5/acache.c
+++ b/source4/heimdal/lib/krb5/acache.c
@@ -37,7 +37,7 @@
#include <dlfcn.h>
#endif
-RCSID("$Id: acache.c,v 1.16 2006/10/19 11:41:38 lha Exp $");
+RCSID("$Id: acache.c,v 1.17 2007/01/08 15:31:01 lha Exp $");
/* XXX should we fetch these for each open ? */
static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER;
@@ -106,7 +106,12 @@ init_ccapi(krb5_context context)
}
#ifdef HAVE_DLOPEN
- cc_handle = dlopen(lib, 0);
+
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+
+ cc_handle = dlopen(lib, RTLD_LAZY);
if (cc_handle == NULL) {
HEIMDAL_MUTEX_unlock(&acc_mutex);
krb5_set_error_string(context, "Failed to load %s", lib);
diff --git a/source4/heimdal/lib/krb5/config_file.c b/source4/heimdal/lib/krb5/config_file.c
index 66051303ed8..bbd9cf4c781 100644
--- a/source4/heimdal/lib/krb5/config_file.c
+++ b/source4/heimdal/lib/krb5/config_file.c
@@ -32,7 +32,7 @@
*/
#include "krb5_locl.h"
-RCSID("$Id: config_file.c,v 1.54 2006/04/02 00:59:19 lha Exp $");
+RCSID("$Id: config_file.c,v 1.55 2006/12/04 23:35:54 lha Exp $");
#ifndef HAVE_NETINFO
@@ -158,8 +158,7 @@ parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent,
char *p;
++*lineno;
- if (buf[strlen(buf) - 1] == '\n')
- buf[strlen(buf) - 1] = '\0';
+ buf[strcspn(buf, "\r\n")] = '\0';
p = buf;
while(isspace((unsigned char)*p))
++p;
@@ -255,8 +254,7 @@ krb5_config_parse_debug (struct fileptr *f,
char *p;
++*lineno;
- if(buf[strlen(buf) - 1] == '\n')
- buf[strlen(buf) - 1] = '\0';
+ buf[strcspn(buf, "\r\n")] = '\0';
p = buf;
while(isspace((unsigned char)*p))
++p;
diff --git a/source4/heimdal/lib/krb5/context.c b/source4/heimdal/lib/krb5/context.c
index f3b0fad347a..d0317da3755 100644
--- a/source4/heimdal/lib/krb5/context.c
+++ b/source4/heimdal/lib/krb5/context.c
@@ -34,7 +34,7 @@
#include "krb5_locl.h"
#include <com_err.h>
-RCSID("$Id: context.c,v 1.111 2006/11/08 02:55:46 lha Exp $");
+RCSID("$Id: context.c,v 1.112 2006/11/24 14:24:33 lha Exp $");
#define INIT_FIELD(C, T, E, D, F) \
(C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \
@@ -180,7 +180,7 @@ init_context_from_config_file(krb5_context context)
/* prefer dns_lookup_kdc over srv_lookup. */
INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup");
INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc");
- INIT_FIELD(context, int, large_msg_size, 6000, "large_message_size");
+ INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size");
INIT_FIELD(context, bool, dns_canonicalize_hostname, TRUE, "dns_canonicalize_hostname");
context->default_cc_name = NULL;
return 0;
diff --git a/source4/heimdal/lib/krb5/crypto.c b/source4/heimdal/lib/krb5/crypto.c
index 9f6ef6b82b4..6d4a81baa8c 100644
--- a/source4/heimdal/lib/krb5/crypto.c
+++ b/source4/heimdal/lib/krb5/crypto.c
@@ -32,7 +32,7 @@
*/
#include "krb5_locl.h"
-RCSID("$Id: crypto.c,v 1.145 2006/10/22 07:32:40 lha Exp $");
+RCSID("$Id: crypto.c,v 1.146 2006/11/17 21:58:47 lha Exp $");
#undef CRYPTO_DEBUG
#ifdef CRYPTO_DEBUG
@@ -1076,6 +1076,21 @@ krb5_enctype_keysize(krb5_context context,
}
krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_keybits(krb5_context context,
+ krb5_enctype type,
+ size_t *keybits)
+{
+ struct encryption_type *et = _find_enctype(type);
+ if(et == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ type);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ *keybits = et->keytype->bits;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
krb5_generate_random_keyblock(krb5_context context,
krb5_enctype type,
krb5_keyblock *key)
diff --git a/source4/heimdal/lib/krb5/fcache.c b/source4/heimdal/lib/krb5/fcache.c
index 79b809d2a29..7441509e388 100644
--- a/source4/heimdal/lib/krb5/fcache.c
+++ b/source4/heimdal/lib/krb5/fcache.c
@@ -33,7 +33,7 @@
#include "krb5_locl.h"
-RCSID("$Id: fcache.c,v 1.52 2006/04/02 01:04:37 lha Exp $");
+RCSID("$Id: fcache.c,v 1.54 2006/12/15 21:35:52 lha Exp $");
typedef struct krb5_fcache{
char *filename;
@@ -699,6 +699,62 @@ fcc_get_version(krb5_context context,
return FCACHE(id)->version;
}
+struct fcache_iter {
+ int first;
+};
+
+static krb5_error_code
+fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
+{
+ struct fcache_iter *iter;
+
+ iter = calloc(1, sizeof(*iter));
+ if (iter == NULL) {
+ krb5_set_error_string(context, "malloc - out of memory");
+ return ENOMEM;
+ }
+ iter->first = 1;
+ *cursor = iter;
+ return 0;
+}
+
+static krb5_error_code
+fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
+{
+ struct fcache_iter *iter = cursor;
+ krb5_error_code ret;
+ const char *fn;
+ char *expandedfn = NULL;
+
+ if (!iter->first) {
+ krb5_clear_error_string(context);
+ return KRB5_CC_END;
+ }
+ iter->first = 0;
+
+ fn = krb5_cc_default_name(context);
+ if (strncasecmp(fn, "FILE:", 5) != 0) {
+ ret = _krb5_expand_default_cc_name(context,
+ KRB5_DEFAULT_CCNAME_FILE,
+ &expandedfn);
+ if (ret)
+ return ret;
+ }
+ ret = krb5_cc_resolve(context, fn, id);
+ if (expandedfn)
+ free(expandedfn);
+
+ return ret;
+}
+
+static krb5_error_code
+fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
+{
+ struct fcache_iter *iter = cursor;
+ free(iter);
+ return 0;
+}
+
const krb5_cc_ops krb5_fcc_ops = {
"FILE",
fcc_get_name,
@@ -715,5 +771,8 @@ const krb5_cc_ops krb5_fcc_ops = {
fcc_end_get,
fcc_remove_cred,
fcc_set_flags,
- fcc_get_version
+ fcc_get_version,
+ fcc_get_cache_first,
+ fcc_get_cache_next,
+ fcc_end_cache_get
};
diff --git a/source4/heimdal/lib/krb5/get_cred.c b/source4/heimdal/lib/krb5/get_cred.c
index b404c30f6e9..663b5e7f1b9 100644
--- a/source4/heimdal/lib/krb5/get_cred.c
+++ b/source4/heimdal/lib/krb5/get_cred.c
@@ -33,7 +33,7 @@
#include <krb5_locl.h>
-RCSID("$Id: get_cred.c,v 1.112 2006/06/06 21:22:54 lha Exp $");
+RCSID("$Id: get_cred.c,v 1.113 2006/11/21 05:14:01 lha Exp $");
/*
* Take the `body' and encode it into `padata' using the credentials
@@ -458,7 +458,7 @@ get_cred_kdc_usage(krb5_context context,
ret = krb5_create_checksum(context,
crypto,
- KRB5_KU_TGS_IMPERSONATE,
+ KRB5_KU_OTHER_CKSUM,
0,
data.data,
data.length,
diff --git a/source4/heimdal/lib/krb5/init_creds.c b/source4/heimdal/lib/krb5/init_creds.c
index 6dacb316d8c..a331524a7ed 100644
--- a/source4/heimdal/lib/krb5/init_creds.c
+++ b/source4/heimdal/lib/krb5/init_creds.c
@@ -33,7 +33,7 @@
#include "krb5_locl.h"
-RCSID("$Id: init_creds.c,v 1.28 2006/09/04 14:28:54 lha Exp $");
+RCSID("$Id: init_creds.c,v 1.30 2006/11/23 16:27:36 lha Exp $");
void KRB5_LIB_FUNCTION
krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
@@ -130,9 +130,10 @@ _krb5_get_init_creds_opt_set_krb5_error(krb5_context context,
void KRB5_LIB_FUNCTION
-krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opt)
+krb5_get_init_creds_opt_free(krb5_context context,
+ krb5_get_init_creds_opt *opt)
{
- if (opt->opt_private == NULL)
+ if (opt == NULL || opt->opt_private == NULL)
return;
if (opt->opt_private->refcount < 1) /* abort ? */
return;
diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c
index d43ae0ae6ff..f6f6eac7d5b 100644
--- a/source4/heimdal/lib/krb5/init_creds_pw.c
+++ b/source4/heimdal/lib/krb5/init_creds_pw.c
@@ -33,7 +33,7 @@
#include "krb5_locl.h"
-RCSID("$Id: init_creds_pw.c,v 1.101 2006/10/02 12:00:59 lha Exp $");
+RCSID("$Id: init_creds_pw.c,v 1.105 2007/01/09 10:44:59 lha Exp $");
typedef struct krb5_get_init_creds_ctx {
KDCOptions flags;
@@ -656,7 +656,7 @@ free_paid(krb5_context context, struct pa_info_data *ppaid)
{
krb5_free_salt(context, ppaid->salt);
if (ppaid->s2kparams)
- krb5_data_free(ppaid->s2kparams);
+ krb5_free_data(context, ppaid->s2kparams);
}
@@ -729,8 +729,8 @@ pa_etype_info2(krb5_context context,
if (e.val[i].salt == NULL)
krb5_free_salt(context, salt);
if (ret == 0) {
- free_ETYPE_INFO2(&e);
- return paid;
+ free_ETYPE_INFO2(&e);
+ return paid;
}
}
}
@@ -1092,23 +1092,31 @@ process_pa_data_to_md(krb5_context context,
(*out_md)->len = 0;
(*out_md)->val = NULL;
- if (in_md->len != 0) {
- struct pa_info_data paid, *ppaid;
+ /*
+ * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
+ * need to expose our password protecting our PKCS12 key.
+ */
- memset(&paid, 0, sizeof(paid));
+ if (ctx->pk_init_ctx) {
+
+ ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md);
+ if (ret)
+ return ret;
+ } else if (in_md->len != 0) {
+ struct pa_info_data paid, *ppaid;
+
+ memset(&paid, 0, sizeof(paid));
+
paid.etype = ENCTYPE_NULL;
ppaid = process_pa_info(context, creds->client, a, &paid, in_md);
-
+
pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
if (ppaid)
free_paid(context, ppaid);
}
pa_data_add_pac_request(context, ctx, *out_md);
- ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md);
- if (ret)
- return ret;
if ((*out_md)->len == 0) {
free(*out_md);
@@ -1503,7 +1511,7 @@ krb5_get_init_creds_password(krb5_context context,
free (q);
if (ret) {
memset (buf, 0, sizeof(buf));
- krb5_get_init_creds_opt_free(options);
+ krb5_get_init_creds_opt_free(context, options);
ret = KRB5_LIBOS_PWDINTR;
krb5_clear_error_string (context);
return ret;
@@ -1515,7 +1523,7 @@ krb5_get_init_creds_password(krb5_context context,
ret = krb5_get_init_creds_opt_set_pa_password(context, options,
password, NULL);
if (ret) {
- krb5_get_init_creds_opt_free(options);
+ krb5_get_init_creds_opt_free(context, options);
memset(buf, 0, sizeof(buf));
return ret;
}
@@ -1523,7 +1531,7 @@ krb5_get_init_creds_password(krb5_context context,
ret = krb5_get_init_creds(context, creds, client, prompter,
data, start_time, in_tkt_service, options);
- krb5_get_init_creds_opt_free(options);
+ krb5_get_init_creds_opt_free(context, options);
memset(buf, 0, sizeof(buf));
return ret;
}
diff --git a/source4/heimdal/lib/krb5/krb5-private.h b/source4/heimdal/lib/krb5/krb5-private.h
index ba2f75ad229..c3e57327539 100644
--- a/source4/heimdal/lib/krb5/krb5-private.h
+++ b/source4/heimdal/lib/krb5/krb5-private.h
@@ -73,15 +73,6 @@ _krb5_extract_ticket (
krb5_decrypt_proc /*decrypt_proc*/,
krb5_const_pointer /*decryptarg*/);
-int
-_krb5_find_type_in_ad (
- krb5_context /*context*/,
- int /*type*/,
- krb5_data */*data*/,
- krb5_boolean */*found*/,
- krb5_keyblock */*sessionkey*/,
- const AuthorizationData */*ad*/);
-
void
_krb5_free_krbhst_info (krb5_krbhst_info */*hi*/);
@@ -299,38 +290,17 @@ _krb5_oid_to_enctype (
const heim_oid */*oid*/,
krb5_enctype */*etype*/);
-void
-_krb5_pac_free (
- krb5_context /*context*/,
- struct krb5_pac */*pac*/);
-
-krb5_error_code
-_krb5_pac_parse (
- krb5_context /*context*/,
- const void */*ptr*/,
- size_t /*len*/,
- struct krb5_pac **/*pac*/);
-
krb5_error_code
_krb5_pac_sign (
krb5_context /*context*/,
struct krb5_pac */*p*/,
time_t /*authtime*/,
krb5_principal /*principal*/,
- krb5_keyblock */*server_key*/,
- krb5_keyblock */*priv_key*/,
+ const krb5_keyblock */*server_key*/,
+ const krb5_keyblock */*priv_key*/,
krb5_data */*data*/);
krb5_error_code
-_krb5_pac_verify (
- krb5_context /*context*/,
- struct krb5_pac */*pac*/,
- time_t /*authtime*/,
- krb5_principal /*principal*/,
- krb5_keyblock */*server*/,
- krb5_keyblock */*privsvr*/);
-
-krb5_error_code
_krb5_parse_moduli (
krb5_context /*context*/,
const char */*file*/,
diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h
index 8b61e8d7d25..9dfe487b0af 100644
--- a/source4/heimdal/lib/krb5/krb5-protos.h
+++ b/source4/heimdal/lib/krb5/krb5-protos.h
@@ -499,10 +499,11 @@ krb5_boolean KRB5_LIB_FUNCTION
krb5_c_is_keyed_cksum (krb5_cksumtype /*ctype*/);
krb5_error_code KRB5_LIB_FUNCTION
-krb5_c_keylength (
+krb5_c_keylengths (
krb5_context /*context*/,
krb5_enctype /*enctype*/,
- size_t */*len*/);
+ size_t */*ilen*/,
+ size_t */*keylen*/);
krb5_error_code KRB5_LIB_FUNCTION
krb5_c_make_checksum (
@@ -1520,6 +1521,12 @@ krb5_enctype_disable (
krb5_enctype /*enctype*/);
krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_keybits (
+ krb5_context /*context*/,
+ krb5_enctype /*type*/,
+ size_t */*keybits*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
krb5_enctype_keysize (
krb5_context /*context*/,
krb5_enctype /*type*/,
@@ -2021,7 +2028,9 @@ krb5_get_init_creds_opt_alloc (
krb5_get_init_creds_opt **/*opt*/);
void KRB5_LIB_FUNCTION
-krb5_get_init_creds_opt_free (krb5_get_init_creds_opt */*opt*/);
+krb5_get_init_creds_opt_free (
+ krb5_context /*context*/,
+ krb5_get_init_creds_opt */*opt*/);
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_init_creds_opt_get_error (
@@ -2189,6 +2198,9 @@ krb5_get_server_rcache (
krb5_boolean KRB5_LIB_FUNCTION
krb5_get_use_admin_kdc (krb5_context /*context*/);
+krb5_log_facility * KRB5_LIB_FUNCTION
+krb5_get_warn_dest (krb5_context /*context*/);
+
size_t
krb5_get_wrapped_length (
krb5_context /*context*/,
@@ -2609,12 +2621,172 @@ krb5_net_write_block (
size_t /*len*/,
time_t /*timeout*/);
+krb5_error_code
+krb5_ntlm_alloc (
+ krb5_context /*context*/,
+ krb5_ntlm */*ntlm*/);
+
+krb5_error_code
+krb5_ntlm_free (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/);
+
+krb5_error_code
+krb5_ntlm_init_get_challange (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ krb5_data */*challange*/);
+
+krb5_error_code
+krb5_ntlm_init_get_flags (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ uint32_t */*flags*/);
+
+krb5_error_code
+krb5_ntlm_init_get_opaque (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ krb5_data */*opaque*/);
+
+krb5_error_code
+krb5_ntlm_init_get_targetinfo (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ krb5_data */*data*/);
+
+krb5_error_code
+krb5_ntlm_init_get_targetname (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ char **/*name*/);
+
+krb5_error_code
+krb5_ntlm_init_request (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ krb5_realm /*realm*/,
+ krb5_ccache /*ccache*/,
+ uint32_t /*flags*/,
+ const char */*hostname*/,
+ const char */*domainname*/);
+
+krb5_error_code
+krb5_ntlm_rep_get_sessionkey (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ krb5_data */*data*/);
+
+krb5_boolean
+krb5_ntlm_rep_get_status (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/);
+
+krb5_error_code
+krb5_ntlm_req_set_flags (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ uint32_t /*flags*/);
+
+krb5_error_code
+krb5_ntlm_req_set_lm (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ void */*hash*/,
+ size_t /*len*/);
+
+krb5_error_code
+krb5_ntlm_req_set_ntlm (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ void */*hash*/,
+ size_t /*len*/);
+
+krb5_error_code
+krb5_ntlm_req_set_opaque (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ krb5_data */*opaque*/);
+
+krb5_error_code
+krb5_ntlm_req_set_session (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ void */*sessionkey*/,
+ size_t /*length*/);
+
+krb5_error_code
+krb5_ntlm_req_set_targetname (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ const char */*targetname*/);
+
+krb5_error_code
+krb5_ntlm_req_set_username (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ const char */*username*/);
+
+krb5_error_code
+krb5_ntlm_request (
+ krb5_context /*context*/,
+ krb5_ntlm /*ntlm*/,
+ krb5_realm /*realm*/,
+ krb5_ccache /*ccache*/);
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_openlog (
krb5_context /*context*/,
const char */*program*/,
krb5_log_facility **/*fac*/);
+krb5_error_code
+krb5_pac_add_buffer (
+ krb5_context /*context*/,
+ struct krb5_pac */*p*/,
+ uint32_t /*type*/,
+ const krb5_data */*data*/);
+
+void
+krb5_pac_free (
+ krb5_context /*context*/,
+ struct krb5_pac */*pac*/);
+
+krb5_error_code
+krb5_pac_get_buffer (
+ krb5_context /*context*/,
+ struct krb5_pac */*p*/,
+ uint32_t /*type*/,
+ krb5_data */*data*/);
+
+krb5_error_code
+krb5_pac_get_types (
+ krb5_context /*context*/,
+ struct krb5_pac */*p*/,
+ size_t */*len*/,
+ uint32_t **/*types*/);
+
+krb5_error_code
+krb5_pac_init (
+ krb5_context /*context*/,
+ struct krb5_pac **/*pac*/);
+
+krb5_error_code
+krb5_pac_parse (
+ krb5_context /*context*/,
+ const void */*ptr*/,
+ size_t /*len*/,
+ struct krb5_pac **/*pac*/);
+
+krb5_error_code
+krb5_pac_verify (
+ krb5_context /*context*/,
+ const struct krb5_pac */*pac*/,
+ time_t /*authtime*/,
+ krb5_const_principal /*principal*/,
+ const krb5_keyblock */*server*/,
+ const krb5_keyblock */*privsvr*/);
+
int KRB5_LIB_FUNCTION
krb5_padata_add (
krb5_context /*context*/,
@@ -2904,6 +3076,12 @@ krb5_rd_req_in_set_keytab (
krb5_rd_req_in_ctx /*in*/,
krb5_keytab /*keytab*/);
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req_in_set_pac_check (
+ krb5_context /*context*/,
+ krb5_rd_req_in_ctx /*in*/,
+ krb5_boolean /*flag*/);
+
void KRB5_LIB_FUNCTION
krb5_rd_req_out_ctx_free (
krb5_context /*context*/,
@@ -3515,6 +3693,11 @@ krb5_ticket_get_client (
const krb5_ticket */*ticket*/,
krb5_principal */*client*/);
+time_t KRB5_LIB_FUNCTION
+krb5_ticket_get_endtime (
+ krb5_context /*context*/,
+ const krb5_ticket */*ticket*/);
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_ticket_get_server (
krb5_context /*context*/,
diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h
index 1b26e8b3e77..55a83fb5335 100644
--- a/source4/heimdal/lib/krb5/krb5.h
+++ b/source4/heimdal/lib/krb5/krb5.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: krb5.h,v 1.255 2006/11/12 08:33:07 lha Exp $ */
+/* $Id: krb5.h,v 1.259 2007/01/03 18:51:52 lha Exp $ */
#ifndef __KRB5_H__
#define __KRB5_H__
@@ -77,8 +77,10 @@ typedef struct krb5_get_creds_opt_data *krb5_get_creds_opt;
struct krb5_digest;
typedef struct krb5_digest *krb5_digest;
+struct krb5_ntlm;
+typedef struct krb5_ntlm *krb5_ntlm;
-struct krb5_pac;
+typedef struct krb5_pac *krb5_pac;
typedef struct krb5_rd_req_in_ctx *krb5_rd_req_in_ctx;
typedef struct krb5_rd_req_out_ctx *krb5_rd_req_out_ctx;
@@ -216,8 +218,6 @@ typedef enum krb5_key_usage {
/* Keyusage for the server referral in a TGS req */
KRB5_KU_SAM_ENC_NONCE_SAD = 27,
/* Encryption of the SAM-NONCE-OR-SAD field */
- KRB5_KU_TGS_IMPERSONATE = -17,
- /* Checksum type used in the impersonate field */
KRB5_KU_DIGEST_ENCRYPT = -18,
/* Encryption key usage used in the digest encryption field */
KRB5_KU_DIGEST_OPAQUE = -19,
@@ -716,6 +716,7 @@ typedef struct krb5_krbhst_data *krb5_krbhst_handle;
#define KRB5_KRBHST_ADMIN 2
#define KRB5_KRBHST_CHANGEPW 3
#define KRB5_KRBHST_KRB524 4
+#define KRB5_KRBHST_KCA 5
typedef struct krb5_krbhst_info {
enum { KRB5_KRBHST_UDP,
diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h
index 3fb5461b3cd..35d046c8d9d 100644
--- a/source4/heimdal/lib/krb5/krb5_locl.h
+++ b/source4/heimdal/lib/krb5/krb5_locl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: krb5_locl.h,v 1.93 2006/10/20 18:13:31 lha Exp $ */
+/* $Id: krb5_locl.h,v 1.97 2006/12/15 16:46:51 lha Exp $ */
#ifndef __KRB5_LOCL_H__
#define __KRB5_LOCL_H__
@@ -239,20 +239,20 @@ typedef struct krb5_context_data {
int large_msg_size;
int dns_canonicalize_hostname;
struct send_to_kdc *send_to_kdc;
- void *mem_ctx; /* Some parts of Samba4 need a valid
- memory context (under the event
- context) to use */
} krb5_context_data;
+#define KRB5_DEFAULT_CCNAME_FILE "FILE:/tmp/krb5cc_%{uid}"
+#define KRB5_DEFAULT_CCNAME_API "API:"
+
/*
* Configurable options
*/
#ifndef KRB5_DEFAULT_CCNAME
#ifdef __APPLE__
-#define KRB5_DEFAULT_CCNAME "API:"
+#define KRB5_DEFAULT_CCNAME KRB5_DEFAULT_CCNAME_API
#else
-#define KRB5_DEFAULT_CCNAME "FILE:/tmp/krb5cc_%{uid}"
+#define KRB5_DEFAULT_CCNAME KRB5_DEFAULT_CCNAME_FILE
#endif
#endif
diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c
index f395f0d0c30..3e281e5c639 100644
--- a/source4/heimdal/lib/krb5/krbhst.c
+++ b/source4/heimdal/lib/krb5/krbhst.c
@@ -35,7 +35,7 @@
#include <resolve.h>
#include "locate_plugin.h"
-RCSID("$Id: krbhst.c,v 1.58 2006/11/12 20:05:20 lha Exp $");
+RCSID("$Id: krbhst.c,v 1.61 2006/11/30 17:23:08 lha Exp $");
static int
string_to_proto(const char *string)
@@ -493,7 +493,7 @@ add_locate(void *ctx, int type, struct sockaddr *addr)
if (ret != 0)
return 0;
- memset(&hints, 0, sizeof(hints));
+ make_hints(&hints, krbhst_get_default_proto(kd));
ret = getaddrinfo(host, port, &hints, &ai);
if (ret)
return 0;
@@ -521,7 +521,7 @@ plugin_get_hosts(krb5_context context,
struct krb5_krbhst_data *kd,
enum locate_service_type type)
{
- struct krb5_plugin *list, *e;
+ struct krb5_plugin *list = NULL, *e;
krb5_error_code ret;
ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "resolve", &list);
@@ -619,6 +619,13 @@ admin_get_next(krb5_context context,
{
krb5_error_code ret;
+ if ((kd->flags & KD_PLUGIN) == 0) {
+ plugin_get_hosts(context, kd, locate_service_kadmin);
+ kd->flags |= KD_PLUGIN;
+ if(get_next(kd, host))
+ return 0;
+ }
+
if((kd->flags & KD_CONFIG) == 0) {
config_get_hosts(context, kd, "admin_server");
kd->flags |= KD_CONFIG;
@@ -660,6 +667,13 @@ kpasswd_get_next(krb5_context context,
{
krb5_error_code ret;
+ if ((kd->flags & KD_PLUGIN) == 0) {
+ plugin_get_hosts(context, kd, locate_service_kpasswd);
+ kd->flags |= KD_PLUGIN;
+ if(get_next(kd, host))
+ return 0;
+ }
+
if((kd->flags & KD_CONFIG) == 0) {
config_get_hosts(context, kd, "kpasswd_server");
kd->flags |= KD_CONFIG;
@@ -705,6 +719,13 @@ krb524_get_next(krb5_context context,
struct krb5_krbhst_data *kd,
krb5_krbhst_info **host)
{
+ if ((kd->flags & KD_PLUGIN) == 0) {
+ plugin_get_hosts(context, kd, locate_service_krb524);
+ kd->flags |= KD_PLUGIN;
+ if(get_next(kd, host))
+ return 0;
+ }
+
if((kd->flags & KD_CONFIG) == 0) {
config_get_hosts(context, kd, "krb524_server");
if(get_next(kd, host))
diff --git a/source4/heimdal/lib/krb5/log.c b/source4/heimdal/lib/krb5/log.c
index e6fcb6bbb92..9523ca848c4 100644
--- a/source4/heimdal/lib/krb5/log.c
+++ b/source4/heimdal/lib/krb5/log.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "krb5_locl.h"
-RCSID("$Id: log.c,v 1.39 2006/04/24 15:09:27 lha Exp $");
+RCSID("$Id: log.c,v 1.40 2006/11/21 08:08:46 lha Exp $");
struct facility {
int min;
diff --git a/source4/heimdal/lib/krb5/mit_glue.c b/source4/heimdal/lib/krb5/mit_glue.c
index 493c4cd8453..c4d3ff53905 100755
--- a/source4/heimdal/lib/krb5/mit_glue.c
+++ b/source4/heimdal/lib/krb5/mit_glue.c
@@ -32,7 +32,7 @@
*/
#include "krb5_locl.h"
-RCSID("$Id: mit_glue.c,v 1.9 2006/11/09 21:24:16 lha Exp $");
+RCSID("$Id: mit_glue.c,v 1.12 2006/11/17 22:17:46 lha Exp $");
/*
* Glue for MIT API
@@ -327,9 +327,16 @@ krb5_c_make_random_key(krb5_context context,
}
krb5_error_code KRB5_LIB_FUNCTION
-krb5_c_keylength(krb5_context context,
- krb5_enctype enctype,
- size_t *len)
+krb5_c_keylengths(krb5_context context,
+ krb5_enctype enctype,
+ size_t *ilen,
+ size_t *keylen)
{
- return krb5_enctype_keysize(context, enctype, len);
+ krb5_error_code ret;
+
+ ret = krb5_enctype_keybits(context, enctype, ilen);
+ if (ret)
+ return ret;
+ *ilen = (*ilen + 7) / 8;
+ return krb5_enctype_keysize(context, enctype, keylen);
}
diff --git a/source4/heimdal/lib/krb5/mk_req_ext.c b/source4/heimdal/lib/krb5/mk_req_ext.c
index 18b0e3552fa..8646c4ebea6 100644
--- a/source4/heimdal/lib/krb5/mk_req_ext.c
+++ b/source4/heimdal/lib/krb5/mk_req_ext.c
@@ -33,7 +33,7 @@
#include <krb5_locl.h>
-RCSID("$Id: mk_req_ext.c,v 1.32 2006/03/19 20:33:13 lha Exp $");
+RCSID("$Id: mk_req_ext.c,v 1.33 2006/12/27 12:07:22 lha Exp $");
krb5_error_code
_krb5_mk_req_internal(krb5_context context,
@@ -91,7 +91,9 @@ _krb5_mk_req_internal(krb5_context context,
in_data->length,
&c);
} else if(ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5 ||
- ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56) {
+ ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56 ||
+ ac->keyblock->keytype == ETYPE_DES_CBC_MD4 ||
+ ac->keyblock->keytype == ETYPE_DES_CBC_MD5) {
/* this is to make MS kdc happy */
ret = krb5_create_checksum(context,
NULL,
diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c
new file mode 100644
index 00000000000..5bc72354597
--- /dev/null
+++ b/source4/heimdal/lib/krb5/pac.c
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "krb5_locl.h"
+
+RCSID("$Id: pac.c,v 1.13 2007/01/09 11:22:56 lha Exp $");
+
+struct PAC_INFO_BUFFER {
+ uint32_t type;
+ uint32_t buffersize;
+ uint32_t offset_hi;
+ uint32_t offset_lo;
+};
+
+struct PACTYPE {
+ uint32_t numbuffers;
+ uint32_t version;
+ struct PAC_INFO_BUFFER buffers[1];
+};
+
+struct krb5_pac {
+ struct PACTYPE *pac;
+ krb5_data data;
+ struct PAC_INFO_BUFFER *server_checksum;
+ struct PAC_INFO_BUFFER *privsvr_checksum;
+ struct PAC_INFO_BUFFER *logon_name;
+};
+
+#define PAC_ALIGNMENT 8
+
+#define PACTYPE_SIZE 8
+#define PAC_INFO_BUFFER_SIZE 16
+
+#define PAC_SERVER_CHECKSUM 6
+#define PAC_PRIVSVR_CHECKSUM 7
+#define PAC_LOGON_NAME 10
+
+#define CHECK(r,f,l) \
+ do { \
+ if (((r) = f ) != 0) { \
+ krb5_clear_error_string(context); \
+ goto l; \
+ } \
+ } while(0)
+
+static const char zeros[PAC_ALIGNMENT] = { 0 };
+
+/*
+ *
+ */
+
+krb5_error_code
+krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
+ struct krb5_pac **pac)
+{
+ krb5_error_code ret;
+ struct krb5_pac *p;
+ krb5_storage *sp = NULL;
+ uint32_t i, tmp, tmp2, header_end;
+
+ p = calloc(1, sizeof(*p));
+ if (p == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+
+ sp = krb5_storage_from_readonly_mem(ptr, len);
+ if (sp == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "out of memory");
+ goto out;
+ }
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(ret, krb5_ret_uint32(sp, &tmp), out);
+ CHECK(ret, krb5_ret_uint32(sp, &tmp2), out);
+ if (tmp < 1) {
+ krb5_set_error_string(context, "PAC have too few buffer");
+ ret = EINVAL; /* Too few buffers */
+ goto out;
+ }
+ if (tmp2 != 0) {
+ krb5_set_error_string(context, "PAC have wrong version");
+ ret = EINVAL; /* Wrong version */
+ goto out;
+ }
+
+ p->pac = calloc(1,
+ sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (tmp - 1)));
+ if (p->pac == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ p->pac->numbuffers = tmp;
+ p->pac->version = tmp2;
+
+ header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers);
+ if (header_end > len) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < p->pac->numbuffers; i++) {
+ CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].type), out);
+ CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize), out);
+ CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_lo), out);
+ CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_hi), out);
+
+ /* consistency checks */
+ if (p->pac->buffers[i].offset_lo & (PAC_ALIGNMENT - 1)) {
+ krb5_set_error_string(context, "PAC out of allignment");
+ ret = EINVAL;
+ goto out;
+ }
+ if (p->pac->buffers[i].offset_hi) {
+ krb5_set_error_string(context, "PAC high offset set");
+ ret = EINVAL;
+ goto out;
+ }
+ if (p->pac->buffers[i].offset_lo > len) {
+ krb5_set_error_string(context, "PAC offset off end");
+ ret = EINVAL;
+ goto out;
+ }
+ if (p->pac->buffers[i].offset_lo < header_end) {
+ krb5_set_error_string(context, "PAC offset inside header: %d %d",
+ p->pac->buffers[i].offset_lo, header_end);
+ ret = EINVAL;
+ goto out;
+ }
+ if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){
+ krb5_set_error_string(context, "PAC length off end");
+ ret = EINVAL;
+ goto out;
+ }
+
+ /* let save pointer to data we need later */
+ if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
+ if (p->server_checksum) {
+ krb5_set_error_string(context, "PAC have two server checksums");
+ ret = EINVAL;
+ goto out;
+ }
+ p->server_checksum = &p->pac->buffers[i];
+ } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
+ if (p->privsvr_checksum) {
+ krb5_set_error_string(context, "PAC have two KDC checksums");
+ ret = EINVAL;
+ goto out;
+ }
+ p->privsvr_checksum = &p->pac->buffers[i];
+ } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
+ if (p->logon_name) {
+ krb5_set_error_string(context, "PAC have two logon names");
+ ret = EINVAL;
+ goto out;
+ }
+ p->logon_name = &p->pac->buffers[i];
+ }
+ }
+
+ ret = krb5_data_copy(&p->data, ptr, len);
+ if (ret)
+ goto out;
+
+ krb5_storage_free(sp);
+
+ *pac = p;
+ return 0;
+
+out:
+ if (sp)
+ krb5_storage_free(sp);
+ if (p) {
+ if (p->pac)
+ free(p->pac);
+ free(p);
+ }
+ *pac = NULL;
+
+ return ret;
+}
+
+krb5_error_code
+krb5_pac_init(krb5_context context, struct krb5_pac **pac)
+{
+ krb5_error_code ret;
+ struct krb5_pac *p;
+
+ p = calloc(1, sizeof(*p));
+ if (p == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+
+ p->pac = calloc(1, sizeof(*p->pac));
+ if (p->pac == NULL) {
+ free(p);
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+
+ ret = krb5_data_alloc(&p->data, PACTYPE_SIZE);
+ if (ret) {
+ free (p->pac);
+ free(p);
+ krb5_set_error_string(context, "out of memory");
+ return ret;
+ }
+
+
+ *pac = p;
+ return 0;
+}
+
+krb5_error_code
+krb5_pac_add_buffer(krb5_context context, struct krb5_pac *p,
+ uint32_t type, const krb5_data *data)
+{
+ krb5_error_code ret;
+ void *ptr;
+ size_t len, offset, header_end;
+ uint32_t i;
+
+ len = p->pac->numbuffers + 1;
+ if (len < p->pac->numbuffers)
+ return EINVAL;
+
+ ptr = realloc(p->pac,
+ sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * len));
+ if (ptr == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ p->pac = ptr;
+
+ for (i = 0; i < len; i++)
+ p->pac->buffers[i].offset_lo += PAC_INFO_BUFFER_SIZE;
+
+ offset = p->data.length + PAC_INFO_BUFFER_SIZE;
+
+ p->pac->buffers[len - 1].type = type;
+ p->pac->buffers[len - 1].buffersize = data->length;
+ p->pac->buffers[len - 1].offset_lo = offset;
+ p->pac->buffers[len - 1].offset_hi = 0;
+
+ len = p->data.length + data->length + PAC_INFO_BUFFER_SIZE;
+ if (len < p->data.length) {
+ krb5_set_error_string(context, "integer overrun");
+ return EINVAL;
+ }
+
+ /* align to PAC_ALIGNMENT */
+ len = ((len + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT;
+
+ ret = krb5_data_realloc(&p->data, len);
+ if (ret) {
+ krb5_set_error_string(context, "out of memory");
+ return ret;
+ }
+
+ /* make place for PAC INFO BUFFER header */
+ header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers);
+ memmove((unsigned char *)p->data.data + header_end,
+ (unsigned char *)p->data.data + header_end + PAC_INFO_BUFFER_SIZE,
+ PAC_INFO_BUFFER_SIZE);
+
+ /*
+ *
+ */
+
+ memcpy((unsigned char *)p->data.data + offset,
+ data->data, data->length);
+ memset((unsigned char *)p->data.data + offset + data->length,
+ 0, p->data.length - offset - data->length);
+
+ p->pac->numbuffers += 1;
+
+ return 0;
+}
+
+krb5_error_code
+krb5_pac_get_buffer(krb5_context context, struct krb5_pac *p,
+ uint32_t type, krb5_data *data)
+{
+ krb5_error_code ret;
+ uint32_t i;
+
+ /*
+ * Hide the checksums from external consumers
+ */
+
+ if (type == PAC_PRIVSVR_CHECKSUM || type == PAC_SERVER_CHECKSUM) {
+ ret = krb5_data_alloc(data, 16);
+ if (ret) {
+ krb5_set_error_string(context, "out of memory");
+ return ret;
+ }
+ memset(data->data, 0, data->length);
+ return 0;
+ }
+
+ for (i = 0; i < p->pac->numbuffers; i++) {
+ size_t len = p->pac->buffers[i].buffersize;
+ size_t offset = p->pac->buffers[i].offset_lo;
+
+ if (p->pac->buffers[i].type != type)
+ continue;
+
+ ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
+ if (ret) {
+ krb5_set_error_string(context, "Out of memory");
+ return ret;
+ }
+ return 0;
+ }
+ krb5_set_error_string(context, "No PAC buffer of type %lu was found",
+ (unsigned long)type);
+ return ENOENT;
+}
+
+/*
+ *
+ */
+
+krb5_error_code
+krb5_pac_get_types(krb5_context context,
+ struct krb5_pac *p,
+ size_t *len,
+ uint32_t **types)
+{
+ size_t i;
+
+ *types = calloc(p->pac->numbuffers, sizeof(*types));
+ if (*types == NULL) {
+ *len = 0;
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ for (i = 0; i < p->pac->numbuffers; i++)
+ (*types)[i] = p->pac->buffers[i].type;
+ *len = p->pac->numbuffers;
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+void
+krb5_pac_free(krb5_context context, struct krb5_pac *pac)
+{
+ krb5_data_free(&pac->data);
+ free(pac->pac);
+ free(pac);
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+verify_checksum(krb5_context context,
+ const struct PAC_INFO_BUFFER *sig,
+ const krb5_data *data,
+ void *ptr, size_t len,
+ const krb5_keyblock *key)
+{
+ krb5_crypto crypto = NULL;
+ krb5_storage *sp = NULL;
+ uint32_t type;
+ krb5_error_code ret;
+ Checksum cksum;
+
+ sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo,
+ sig->buffersize);
+ if (sp == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(ret, krb5_ret_uint32(sp, &type), out);
+ cksum.cksumtype = type;
+ cksum.checksum.length =
+ sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR);
+ cksum.checksum.data = malloc(cksum.checksum.length);
+ if (cksum.checksum.data == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
+ if (ret != cksum.checksum.length) {
+ krb5_set_error_string(context, "PAC checksum missing checksum");
+ ret = EINVAL;
+ goto out;
+ }
+
+ if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) {
+ krb5_set_error_string (context, "Checksum type %d not keyed",
+ cksum.cksumtype);
+ ret = EINVAL;
+ goto out;
+ }
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ goto out;
+
+ ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM,
+ ptr, len, &cksum);
+ krb5_crypto_destroy(context, crypto);
+ krb5_storage_free(sp);
+
+ return ret;
+
+out:
+ if (sp)
+ krb5_storage_free(sp);
+ if (crypto)
+ krb5_crypto_destroy(context, crypto);
+ return ret;
+}
+
+static krb5_error_code
+create_checksum(krb5_context context,
+ const krb5_keyblock *key,
+ void *data, size_t datalen,
+ void *sig, size_t siglen)
+{
+ krb5_crypto crypto = NULL;
+ krb5_error_code ret;
+ Checksum cksum;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+
+ ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0,
+ data, datalen, &cksum);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ return ret;
+
+ if (cksum.checksum.length != siglen) {
+ krb5_set_error_string(context, "pac checksum wrong length");
+ free_Checksum(&cksum);
+ return EINVAL;
+ }
+
+ memcpy(sig, cksum.checksum.data, siglen);
+ free_Checksum(&cksum);
+
+ return 0;
+}
+
+
+/*
+ *
+ */
+
+#define NTTIME_EPOCH 0x019DB1DED53E8000LL
+
+static uint64_t
+unix2nttime(time_t unix_time)
+{
+ long long wt;
+ wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
+ return wt;
+}
+
+static krb5_error_code
+verify_logonname(krb5_context context,
+ const struct PAC_INFO_BUFFER *logon_name,
+ const krb5_data *data,
+ time_t authtime,
+ krb5_const_principal principal)
+{
+ krb5_error_code ret;
+ krb5_principal p2;
+ uint32_t time1, time2;
+ krb5_storage *sp;
+ uint16_t len;
+ char *s;
+
+ sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo,
+ logon_name->buffersize);
+ if (sp == NULL) {
+ krb5_set_error_string(context, "Out of memory");
+ return ENOMEM;
+ }
+
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(ret, krb5_ret_uint32(sp, &time1), out);
+ CHECK(ret, krb5_ret_uint32(sp, &time2), out);
+
+ {
+ uint64_t t1, t2;
+ t1 = unix2nttime(authtime);
+ t2 = ((uint64_t)time2 << 32) | time1;
+ if (t1 != t2) {
+ krb5_storage_free(sp);
+ krb5_set_error_string(context, "PAC timestamp mismatch");
+ return EINVAL;
+ }
+ }
+ CHECK(ret, krb5_ret_uint16(sp, &len), out);
+ if (len == 0) {
+ krb5_storage_free(sp);
+ krb5_set_error_string(context, "PAC logon name length missing");
+ return EINVAL;
+ }
+
+ s = malloc(len);
+ if (s == NULL) {
+ krb5_storage_free(sp);
+ krb5_set_error_string(context, "Out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_storage_read(sp, s, len);
+ if (ret != len) {
+ krb5_storage_free(sp);
+ krb5_set_error_string(context, "Failed to read pac logon name");
+ return EINVAL;
+ }
+ krb5_storage_free(sp);
+#if 1 /* cheat for now */
+ {
+ size_t i;
+
+ if (len & 1) {
+ krb5_set_error_string(context, "PAC logon name malformed");
+ return EINVAL;
+ }
+
+ for (i = 0; i < len / 2; i++) {
+ if (s[(i * 2) + 1]) {
+ krb5_set_error_string(context, "PAC logon name not ASCII");
+ return EINVAL;
+ }
+ s[i] = s[i * 2];
+ }
+ s[i] = '\0';
+ }
+#else
+ {
+ uint16_t *ucs2;
+ ssize_t ucs2len;
+ size_t u8len;
+
+ ucs2 = malloc(sizeof(ucs2[0]) * len / 2);
+ if (ucs2)
+ abort();
+ ucs2len = wind_ucs2read(s, len / 2, ucs2);
+ free(s);
+ if (len < 0)
+ return -1;
+ ret = wind_ucs2toutf8(ucs2, ucs2len, NULL, &u8len);
+ if (ret < 0)
+ abort();
+ s = malloc(u8len + 1);
+ if (s == NULL)
+ abort();
+ wind_ucs2toutf8(ucs2, ucs2len, s, &u8len);
+ free(ucs2);
+ }
+#endif
+ ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2);
+ free(s);
+ if (ret)
+ return ret;
+
+ if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) {
+ krb5_set_error_string(context, "PAC logon name mismatch");
+ ret = EINVAL;
+ }
+ krb5_free_principal(context, p2);
+ return ret;
+out:
+ return ret;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+build_logon_name(krb5_context context,
+ time_t authtime,
+ krb5_const_principal principal,
+ krb5_data *logon)
+{
+ krb5_error_code ret;
+ krb5_storage *sp;
+ uint64_t t;
+ char *s, *s2;
+ size_t i, len;
+
+ t = unix2nttime(authtime);
+
+ krb5_data_zero(logon);
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out);
+ CHECK(ret, krb5_store_uint32(sp, t >> 32), out);
+
+ ret = krb5_unparse_name_flags(context, principal,
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s);
+ if (ret)
+ goto out;
+
+ len = strlen(s);
+
+ CHECK(ret, krb5_store_uint16(sp, len * 2), out);
+
+#if 1 /* cheat for now */
+ s2 = malloc(len * 2);
+ if (s2 == NULL) {
+ ret = ENOMEM;
+ free(s);
+ goto out;
+ }
+ for (i = 0; i < len; i++) {
+ s2[i * 2] = s[i];
+ s2[i * 2 + 1] = 0;
+ }
+ free(s);
+#else
+ /* write libwind code here */
+#endif
+
+ ret = krb5_storage_write(sp, s2, len * 2);
+ free(s2);
+ if (ret != len * 2) {
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = krb5_storage_to_data(sp, logon);
+ if (ret)
+ goto out;
+ krb5_storage_free(sp);
+
+ return 0;
+out:
+ krb5_storage_free(sp);
+ return ret;
+}
+
+
+/*
+ *
+ */
+
+krb5_error_code
+krb5_pac_verify(krb5_context context,
+ const struct krb5_pac *pac,
+ time_t authtime,
+ krb5_const_principal principal,
+ const krb5_keyblock *server,
+ const krb5_keyblock *privsvr)
+{
+ krb5_error_code ret;
+
+ if (pac->server_checksum == NULL) {
+ krb5_set_error_string(context, "PAC missing server checksum");
+ return EINVAL;
+ }
+ if (pac->privsvr_checksum == NULL) {
+ krb5_set_error_string(context, "PAC missing kdc checksum");
+ return EINVAL;
+ }
+ if (pac->logon_name == NULL) {
+ krb5_set_error_string(context, "PAC missing logon name");
+ return EINVAL;
+ }
+
+ ret = verify_logonname(context,
+ pac->logon_name,
+ &pac->data,
+ authtime,
+ principal);
+ if (ret)
+ return ret;
+
+ /*
+ * in the service case, clean out data option of the privsvr and
+ * server checksum before checking the checksum.
+ */
+ {
+ krb5_data *copy;
+
+ ret = krb5_copy_data(context, &pac->data, &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;
+}
diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c
index f519b5ad086..4f8ed8fe075 100755
--- a/source4/heimdal/lib/krb5/pkinit.c
+++ b/source4/heimdal/lib/krb5/pkinit.c
@@ -33,7 +33,7 @@
#include "krb5_locl.h"
-RCSID("$Id: pkinit.c,v 1.110 2006/10/14 09:52:50 lha Exp $");
+RCSID("$Id: pkinit.c,v 1.120 2006/12/08 02:48:09 lha Exp $");
struct krb5_dh_moduli {
char *name;
@@ -81,12 +81,26 @@ struct krb5_pk_init_ctx_data {
DH *dh;
krb5_data *clientDHNonce;
struct krb5_dh_moduli **m;
+ hx509_peer_info peer;
+ int type;
int require_binding;
int require_eku;
int require_krbtgt_otherName;
int require_hostname_match;
};
+static void
+_krb5_pk_copy_error(krb5_context context,
+ hx509_context hx509ctx,
+ int hxret,
+ const char *fmt,
+ ...)
+ __attribute__ ((format (printf, 4, 5)));
+
+/*
+ *
+ */
+
void KRB5_LIB_FUNCTION
_krb5_pk_cert_free(struct krb5_pk_cert *cert)
{
@@ -130,6 +144,7 @@ _krb5_pk_create_sign(krb5_context context,
const heim_oid *eContentType,
krb5_data *eContent,
struct krb5_pk_identity *id,
+ hx509_peer_info peer,
krb5_data *sd_data)
{
hx509_cert cert;
@@ -137,16 +152,22 @@ _krb5_pk_create_sign(krb5_context context,
int ret;
ret = hx509_query_alloc(id->hx509ctx, &q);
- if (ret)
+ if (ret) {
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Allocate query to find signing certificate");
return ret;
+ }
hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
ret = hx509_certs_find(id->hx509ctx, id->certs, q, &cert);
hx509_query_free(id->hx509ctx, q);
- if (ret)
+ if (ret) {
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Find certificate to signed CMS data");
return ret;
+ }
ret = hx509_cms_create_signed_1(id->hx509ctx,
eContentType,
@@ -154,9 +175,12 @@ _krb5_pk_create_sign(krb5_context context,
eContent->length,
NULL,
cert,
+ peer,
NULL,
- NULL,
+ id->certs,
sd_data);
+ if (ret)
+ _krb5_pk_copy_error(context, id->hx509ctx, ret, "create CMS signedData");
hx509_cert_free(cert);
return ret;
@@ -402,6 +426,19 @@ build_auth_pack(krb5_context context,
a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
}
+ {
+ a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
+ if (a->supportedCMSTypes == NULL)
+ return ENOMEM;
+
+ ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL,
+ &a->supportedCMSTypes->val,
+ &a->supportedCMSTypes->len);
+ if (ret)
+ return ret;
+ }
+
+
return ret;
}
@@ -429,7 +466,6 @@ _krb5_pk_mk_ContentInfo(krb5_context context,
static krb5_error_code
pk_mk_padata(krb5_context context,
- int compat,
krb5_pk_init_ctx ctx,
const KDC_REQ_BODY *req_body,
unsigned nonce,
@@ -446,7 +482,7 @@ pk_mk_padata(krb5_context context,
krb5_data_zero(&sd_buf);
memset(&content_info, 0, sizeof(content_info));
- if (compat == COMPAT_WIN2K) {
+ if (ctx->type == COMPAT_WIN2K) {
AuthPack_Win2k ap;
krb5_timestamp sec;
int32_t usec;
@@ -483,7 +519,7 @@ pk_mk_padata(krb5_context context,
krb5_abortx(context, "internal ASN1 encoder error");
oid = oid_id_pkcs7_data();
- } else if (compat == COMPAT_IETF) {
+ } else if (ctx->type == COMPAT_IETF) {
AuthPack ap;
memset(&ap, 0, sizeof(ap));
@@ -510,7 +546,8 @@ pk_mk_padata(krb5_context context,
ret = _krb5_pk_create_sign(context,
oid,
&buf,
- ctx->id,
+ ctx->id,
+ ctx->peer,
&sd_buf);
krb5_data_free(&buf);
if (ret)
@@ -529,7 +566,7 @@ pk_mk_padata(krb5_context context,
if (buf.length != size)
krb5_abortx(context, "Internal ASN1 encoder error");
- if (compat == COMPAT_WIN2K) {
+ if (ctx->type == COMPAT_WIN2K) {
PA_PK_AS_REQ_Win2k winreq;
pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
@@ -542,7 +579,7 @@ pk_mk_padata(krb5_context context,
&winreq, &size, ret);
free_PA_PK_AS_REQ_Win2k(&winreq);
- } else if (compat == COMPAT_IETF) {
+ } else if (ctx->type == COMPAT_IETF) {
PA_PK_AS_REQ req;
pa_type = KRB5_PADATA_PK_AS_REQ;
@@ -583,7 +620,7 @@ pk_mk_padata(krb5_context context,
if (ret)
free(buf.data);
- if (ret == 0 && compat == COMPAT_WIN2K)
+ if (ret == 0 && ctx->type == COMPAT_WIN2K)
krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
out:
@@ -601,13 +638,13 @@ _krb5_pk_mk_padata(krb5_context context,
METHOD_DATA *md)
{
krb5_pk_init_ctx ctx = c;
- int win2k_compat, type;
+ int win2k_compat;
win2k_compat = krb5_config_get_bool_default(context, NULL,
FALSE,
"realms",
req_body->realm,
- "win2k_pkinit",
+ "pkinit_win2k",
NULL);
if (context->pkinit_flags & KRB5_PKINIT_WIN2K)
win2k_compat = 1;
@@ -618,11 +655,11 @@ _krb5_pk_mk_padata(krb5_context context,
FALSE,
"realms",
req_body->realm,
- "win2k_pkinit_require_binding",
+ "pkinit_win2k_require_binding",
NULL);
- type = COMPAT_WIN2K;
+ ctx->type = COMPAT_WIN2K;
} else
- type = COMPAT_IETF;
+ ctx->type = COMPAT_IETF;
ctx->require_eku =
krb5_config_get_bool_default(context, NULL,
@@ -647,7 +684,7 @@ _krb5_pk_mk_padata(krb5_context context,
"pkinit_require_hostname_match",
NULL);
- return pk_mk_padata(context, type, ctx, req_body, nonce, md);
+ return pk_mk_padata(context, ctx, req_body, nonce, md);
}
krb5_error_code KRB5_LIB_FUNCTION
@@ -673,13 +710,8 @@ _krb5_pk_verify_sign(krb5_context context,
content,
&signer_certs);
if (ret) {
- char *s = hx509_get_error_string(id->hx509ctx, ret);
- if (s) {
- krb5_set_error_string(context,
- "CMS verify signed failed with %s", s);
- free(s);
- } else
- krb5_clear_error_string(context);
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "CMS verify signed failed");
return ret;
}
@@ -692,7 +724,8 @@ _krb5_pk_verify_sign(krb5_context context,
ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert);
if (ret) {
- krb5_clear_error_string(context);
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed to get on of the signer certs");
goto out;
}
@@ -932,8 +965,11 @@ pk_rd_pa_reply_enckey(krb5_context context,
NULL,
&contentType,
&content);
- if (ret)
+ if (ret) {
+ _krb5_pk_copy_error(context, ctx->id->hx509ctx, ret,
+ "Failed to unenvelope CMS data in PK-INIT reply");
return ret;
+ }
p = content.data;
length = content.length;
@@ -1212,8 +1248,13 @@ _krb5_pk_rd_pa_reply(krb5_context context,
size_t size;
/* Check for IETF PK-INIT first */
- if (pa->padata_type == KRB5_PADATA_PK_AS_REP) {
+ if (ctx->type == COMPAT_IETF) {
PA_PK_AS_REP rep;
+
+ if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
+ krb5_set_error_string(context, "PKINIT: wrong padata recv");
+ return EINVAL;
+ }
memset(&rep, 0, sizeof(rep));
@@ -1269,14 +1310,19 @@ _krb5_pk_rd_pa_reply(krb5_context context,
ret = EINVAL;
break;
}
- if (ret == 0)
- return ret;
- }
- /* Check for Windows encoding of the AS-REP pa data */
- {
+ } else if (ctx->type == COMPAT_WIN2K) {
PA_PK_AS_REP_Win2k w2krep;
+ /* Check for Windows encoding of the AS-REP pa data */
+
+#if 0 /* should this be ? */
+ if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
+ krb5_set_error_string(context, "PKINIT: wrong padata recv");
+ return EINVAL;
+ }
+#endif
+
memset(&w2krep, 0, sizeof(w2krep));
ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
@@ -1317,6 +1363,9 @@ _krb5_pk_rd_pa_reply(krb5_context context,
break;
}
+ } else {
+ krb5_set_error_string(context, "PKINIT: unknown reply type");
+ ret = EINVAL;
}
return ret;
@@ -1428,25 +1477,34 @@ _krb5_pk_load_id(krb5_context context,
}
ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
- if (ret)
+ if (ret) {
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed to init cert certs");
goto out;
+ }
ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
- if (ret)
+ if (ret) {
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed to init anchors");
goto out;
+ }
ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain",
0, NULL, &id->certpool);
- if (ret)
+ if (ret) {
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed to init chain");
goto out;
+ }
while (chain_list && *chain_list) {
ret = hx509_certs_append(id->hx509ctx, id->certpool,
NULL, *chain_list);
if (ret) {
- krb5_set_error_string(context,
- "pkinit failed to load chain %s",
- *chain_list);
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed to laod chain %s",
+ *chain_list);
goto out;
}
chain_list++;
@@ -1455,7 +1513,8 @@ _krb5_pk_load_id(krb5_context context,
if (revoke_list) {
ret = hx509_revoke_init(id->hx509ctx, &id->revokectx);
if (ret) {
- krb5_set_error_string(context, "revoke failed to init");
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed init revoke list");
goto out;
}
@@ -1464,9 +1523,8 @@ _krb5_pk_load_id(krb5_context context,
id->revokectx,
*revoke_list);
if (ret) {
- krb5_set_error_string(context,
- "pkinit failed to load revoke %s",
- *revoke_list);
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed load revoke list");
goto out;
}
revoke_list++;
@@ -1475,8 +1533,11 @@ _krb5_pk_load_id(krb5_context context,
hx509_context_set_missing_revoke(id->hx509ctx, 1);
ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx);
- if (ret)
+ if (ret) {
+ _krb5_pk_copy_error(context, id->hx509ctx, ret,
+ "Failed init verify context");
goto out;
+ }
hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
@@ -1504,9 +1565,25 @@ select_dh_group(krb5_context context, DH *dh, unsigned long bits,
{
const struct krb5_dh_moduli *m;
- m = moduli[1]; /* XXX */
- if (m == NULL)
- m = moduli[0]; /* XXX */
+ if (bits == 0) {
+ m = moduli[1]; /* XXX */
+ if (m == NULL)
+ m = moduli[0]; /* XXX */
+ } else {
+ int i;
+ for (i = 0; moduli[i] != NULL; i++) {
+ if (bits < moduli[i]->bits)
+ break;
+ }
+ if (moduli[i] == NULL) {
+ krb5_set_error_string(context,
+ "Did not find a DH group parameter "
+ "matching requirement of %lu bits",
+ bits);
+ return EINVAL;
+ }
+ m = moduli[i];
+ }
dh->p = integer_to_BN(context, "p", &m->p);
if (dh->p == NULL)
@@ -1822,25 +1899,25 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context,
opt->opt_private->pk_init_ctx->require_binding = 0;
opt->opt_private->pk_init_ctx->require_eku = 1;
opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
-
+ opt->opt_private->pk_init_ctx->peer = NULL;
/* XXX implement krb5_appdefault_strings */
if (pool == NULL)
pool = krb5_config_get_strings(context, NULL,
"appdefaults",
- "pkinit-pool",
+ "pkinit_pool",
NULL);
if (pki_revoke == NULL)
pki_revoke = krb5_config_get_strings(context, NULL,
"appdefaults",
- "pkinit-revoke",
+ "pkinit_revoke",
NULL);
if (x509_anchors == NULL) {
krb5_appdefault_string(context, "kinit",
krb5_principal_get_realm(context, principal),
- "pkinit-anchors", NULL, &anchors);
+ "pkinit_anchors", NULL, &anchors);
x509_anchors = anchors;
}
@@ -1861,12 +1938,19 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context,
if ((flags & 2) == 0) {
const char *moduli_file;
+ unsigned long dh_min_bits;
moduli_file = krb5_config_get_string(context, NULL,
"libdefaults",
"moduli",
NULL);
+ dh_min_bits =
+ krb5_config_get_int_default(context, NULL, 0,
+ "libdefaults",
+ "pkinit_dh_min_bits",
+ NULL);
+
ret = _krb5_parse_moduli(context, moduli_file,
&opt->opt_private->pk_init_ctx->m);
if (ret) {
@@ -1881,7 +1965,8 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context,
return ENOMEM;
}
- ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, 0,
+ ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh,
+ dh_min_bits,
opt->opt_private->pk_init_ctx->m);
if (ret) {
_krb5_get_init_creds_opt_free_pkinit(opt);
@@ -1901,3 +1986,36 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context,
return EINVAL;
#endif
}
+
+/*
+ *
+ */
+
+static void
+_krb5_pk_copy_error(krb5_context context,
+ hx509_context hx509ctx,
+ int hxret,
+ const char *fmt,
+ ...)
+{
+ va_list va;
+ char *s, *f;
+
+ va_start(va, fmt);
+ vasprintf(&f, fmt, va);
+ va_end(va);
+ if (f == NULL) {
+ krb5_clear_error_string(context);
+ return;
+ }
+
+ s = hx509_get_error_string(hx509ctx, hxret);
+ if (s == NULL) {
+ krb5_clear_error_string(context);
+ free(f);
+ return;
+ }
+ krb5_set_error_string(context, "%s: %s", f, s);
+ free(s);
+ free(f);
+}
diff --git a/source4/heimdal/lib/krb5/plugin.c b/source4/heimdal/lib/krb5/plugin.c
index 294807faab1..ce7171dbf0a 100644
--- a/source4/heimdal/lib/krb5/plugin.c
+++ b/source4/heimdal/lib/krb5/plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -32,7 +32,7 @@
*/
#include "krb5_locl.h"
-RCSID("$Id: plugin.c,v 1.2 2006/11/12 21:39:43 lha Exp $");
+RCSID("$Id: plugin.c,v 1.4 2007/01/09 17:46:01 lha Exp $");
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
@@ -89,7 +89,11 @@ loadlib(krb5_context context,
return ENOMEM;
}
- (*e)->dsohandle = dlopen(lib, 0);
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+
+ (*e)->dsohandle = dlopen(lib, RTLD_LAZY);
if ((*e)->dsohandle == NULL) {
free(*e);
krb5_set_error_string(context, "Failed to load %s: %s",
diff --git a/source4/heimdal/lib/krb5/principal.c b/source4/heimdal/lib/krb5/principal.c
index 4d13e7db11f..57fcf63dcfa 100644
--- a/source4/heimdal/lib/krb5/principal.c
+++ b/source4/heimdal/lib/krb5/principal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -41,7 +41,7 @@
#include <fnmatch.h>
#include "resolve.h"
-RCSID("$Id: principal.c,v 1.99 2006/10/18 06:53:22 lha Exp $");
+RCSID("$Id: principal.c,v 1.100 2006/12/17 22:53:39 lha Exp $");
#define princ_num_comp(P) ((P)->name.name_string.len)
#define princ_type(P) ((P)->name.name_type)
diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c
index 3352334f657..b7dea2a3279 100644
--- a/source4/heimdal/lib/krb5/rd_req.c
+++ b/source4/heimdal/lib/krb5/rd_req.c
@@ -33,7 +33,7 @@
#include <krb5_locl.h>
-RCSID("$Id: rd_req.c,v 1.68 2006/11/07 17:11:31 lha Exp $");
+RCSID("$Id: rd_req.c,v 1.70 2007/01/04 11:27:20 lha Exp $");
static krb5_error_code
decrypt_tkt_enc_part (krb5_context context,
@@ -513,6 +513,7 @@ krb5_verify_ap_req2(krb5_context context,
struct krb5_rd_req_in_ctx {
krb5_keytab keytab;
krb5_keyblock *keyblock;
+ krb5_boolean no_pac_check;
};
struct krb5_rd_req_out_ctx {
@@ -546,6 +547,16 @@ krb5_rd_req_in_set_keytab(krb5_context context,
}
krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req_in_set_pac_check(krb5_context context,
+ krb5_rd_req_in_ctx in,
+ krb5_boolean flag)
+{
+ in->no_pac_check = !flag;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
krb5_rd_req_in_set_keyblock(krb5_context context,
krb5_rd_req_in_ctx in,
krb5_keyblock *keyblock)
@@ -822,6 +833,36 @@ krb5_rd_req_ctx(krb5_context context,
&o->ap_req_options,
&o->ticket);
+ if (ret)
+ goto out;
+
+ /* If there is a PAC, verify its server signature */
+ if (inctx->no_pac_check == FALSE) {
+ krb5_pac pac;
+ krb5_data data;
+
+ ret = krb5_ticket_get_authorization_data_type(context,
+ o->ticket,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ &data);
+ if (ret == 0) {
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ krb5_data_free(&data);
+ if (ret)
+ goto out;
+
+ ret = krb5_pac_verify(context,
+ pac,
+ o->ticket->ticket.authtime,
+ o->ticket->client,
+ o->keyblock,
+ NULL);
+ krb5_pac_free(context, pac);
+ if (ret)
+ goto out;
+ }
+ ret = 0;
+ }
out:
if (ret || outctx == NULL) {
krb5_rd_req_out_ctx_free(context, o);
diff --git a/source4/heimdal/lib/krb5/store.c b/source4/heimdal/lib/krb5/store.c
index e75f28ca5fa..5422c540b93 100644
--- a/source4/heimdal/lib/krb5/store.c
+++ b/source4/heimdal/lib/krb5/store.c
@@ -34,7 +34,7 @@
#include "krb5_locl.h"
#include "store-int.h"
-RCSID("$Id: store.c,v 1.59 2006/08/18 08:39:13 lha Exp $");
+RCSID("$Id: store.c,v 1.60 2006/12/17 22:49:37 lha Exp $");
#define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
#define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
@@ -577,6 +577,7 @@ krb5_ret_principal(krb5_storage *sp,
p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val));
if(p->name.name_string.val == NULL && ncomp != 0){
free(p->realm);
+ free(p);
return ENOMEM;
}
for(i = 0; i < ncomp; i++){
diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c
index fdc2a1b3a5d..81372c158e2 100644
--- a/source4/heimdal/lib/krb5/ticket.c
+++ b/source4/heimdal/lib/krb5/ticket.c
@@ -33,7 +33,7 @@
#include "krb5_locl.h"
-RCSID("$Id: ticket.c,v 1.15 2006/10/14 09:53:19 lha Exp $");
+RCSID("$Id: ticket.c,v 1.18 2006/12/28 20:49:18 lha Exp $");
krb5_error_code KRB5_LIB_FUNCTION
krb5_free_ticket(krb5_context context,
@@ -97,6 +97,13 @@ krb5_ticket_get_server(krb5_context context,
return krb5_copy_principal(context, ticket->server, server);
}
+time_t KRB5_LIB_FUNCTION
+krb5_ticket_get_endtime(krb5_context context,
+ const krb5_ticket *ticket)
+{
+ return ticket->ticket.endtime;
+}
+
static int
find_type_in_ad(krb5_context context,
int type,
@@ -107,10 +114,6 @@ find_type_in_ad(krb5_context context,
const AuthorizationData *ad,
int level)
{
- /* It is not an error if nothing in here, that is reported by *found */
- /* Setting a default error causes found to be set to FALSE, on
- * recursion to an second embedded authz data even if the first
- * element contains the required type */
krb5_error_code ret = 0;
int i;
@@ -148,8 +151,8 @@ find_type_in_ad(krb5_context context,
"IF_RELEVANT with %d", ret);
goto out;
}
- ret = find_type_in_ad(context, type, data, found, 0, sessionkey,
- &child, level + 1);
+ ret = find_type_in_ad(context, type, data, found, FALSE,
+ sessionkey, &child, level + 1);
free_AuthorizationData(&child);
if (ret)
goto out;
@@ -232,19 +235,6 @@ out:
return ret;
}
-int
-_krb5_find_type_in_ad(krb5_context context,
- int type,
- krb5_data *data,
- krb5_boolean *found,
- krb5_keyblock *sessionkey,
- const AuthorizationData *ad)
-{
- krb5_data_zero(data);
- return find_type_in_ad(context, type, data, found, TRUE, sessionkey, ad, 0);
-}
-
-
/*
* Extract the authorization data type of `type' from the
* 'ticket'. Store the field in `data'. This function is to use for
@@ -259,7 +249,9 @@ krb5_ticket_get_authorization_data_type(krb5_context context,
{
AuthorizationData *ad;
krb5_error_code ret;
- krb5_boolean found = 0;
+ krb5_boolean found = FALSE;
+
+ krb5_data_zero(data);
ad = ticket->ticket.authorization_data;
if (ticket->ticket.authorization_data == NULL) {
@@ -267,8 +259,8 @@ krb5_ticket_get_authorization_data_type(krb5_context context,
return ENOENT; /* XXX */
}
- ret = _krb5_find_type_in_ad(context, type, data, &found, &ticket->ticket.key,
- ticket->ticket.authorization_data);
+ ret = find_type_in_ad(context, type, data, &found, TRUE,
+ &ticket->ticket.key, ad, 0);
if (ret)
return ret;
if (!found) {
diff --git a/source4/heimdal/lib/krb5/warn.c b/source4/heimdal/lib/krb5/warn.c
index f9825914eee..42528653011 100644
--- a/source4/heimdal/lib/krb5/warn.c
+++ b/source4/heimdal/lib/krb5/warn.c
@@ -34,7 +34,7 @@
#include "krb5_locl.h"
#include <err.h>
-RCSID("$Id: warn.c,v 1.15 2004/05/25 21:46:26 lha Exp $");
+RCSID("$Id: warn.c,v 1.16 2006/11/21 08:06:40 lha Exp $");
static krb5_error_code _warnerr(krb5_context context, int do_errtext,
krb5_error_code code, int level, const char *fmt, va_list ap)
@@ -203,3 +203,9 @@ krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac)
context->warn_dest = fac;
return 0;
}
+
+krb5_log_facility * KRB5_LIB_FUNCTION
+krb5_get_warn_dest(krb5_context context)
+{
+ return context->warn_dest;
+}
diff --git a/source4/heimdal/lib/ntlm/heimntlm-protos.h b/source4/heimdal/lib/ntlm/heimntlm-protos.h
new file mode 100644
index 00000000000..e9e08370031
--- /dev/null
+++ b/source4/heimdal/lib/ntlm/heimntlm-protos.h
@@ -0,0 +1,120 @@
+/* This is a generated file */
+#ifndef __heimntlm_protos_h__
+#define __heimntlm_protos_h__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+heim_ntlm_build_ntlm1_master (
+ void */*key*/,
+ size_t /*len*/,
+ struct ntlm_buf */*session*/,
+ struct ntlm_buf */*master*/);
+
+int
+heim_ntlm_calculate_ntlm1 (
+ void */*key*/,
+ size_t /*len*/,
+ unsigned char challange[8],
+ struct ntlm_buf */*answer*/);
+
+int
+heim_ntlm_calculate_ntlm2 (
+ const void */*key*/,
+ size_t /*len*/,
+ const char */*username*/,
+ const char */*target*/,
+ const unsigned char serverchallange[8],
+ const struct ntlm_buf */*infotarget*/,
+ unsigned char ntlmv2[16],
+ struct ntlm_buf */*answer*/);
+
+int
+heim_ntlm_decode_targetinfo (
+ struct ntlm_buf */*data*/,
+ int /*ucs2*/,
+ struct ntlm_targetinfo */*ti*/);
+
+int
+heim_ntlm_decode_type1 (
+ const struct ntlm_buf */*buf*/,
+ struct ntlm_type1 */*data*/);
+
+int
+heim_ntlm_decode_type2 (
+ const struct ntlm_buf */*buf*/,
+ struct ntlm_type2 */*type2*/);
+
+int
+heim_ntlm_decode_type3 (
+ const struct ntlm_buf */*buf*/,
+ int /*ucs2*/,
+ struct ntlm_type3 */*type3*/);
+
+int
+heim_ntlm_encode_targetinfo (
+ struct ntlm_targetinfo */*ti*/,
+ int /*ucs2*/,
+ struct ntlm_buf */*data*/);
+
+int
+heim_ntlm_encode_type1 (
+ const struct ntlm_type1 */*type1*/,
+ struct ntlm_buf */*data*/);
+
+int
+heim_ntlm_encode_type2 (
+ struct ntlm_type2 */*type2*/,
+ struct ntlm_buf */*data*/);
+
+int
+heim_ntlm_encode_type3 (
+ struct ntlm_type3 */*type3*/,
+ struct ntlm_buf */*data*/);
+
+void
+heim_ntlm_free_targetinfo (struct ntlm_targetinfo */*ti*/);
+
+void
+heim_ntlm_free_type1 (struct ntlm_type1 */*data*/);
+
+void
+heim_ntlm_free_type2 (struct ntlm_type2 */*type2*/);
+
+void
+heim_ntlm_free_type3 (struct ntlm_type3 */*data*/);
+
+int
+heim_ntlm_nt_key (
+ const char */*password*/,
+ struct ntlm_buf */*key*/);
+
+void
+heim_ntlm_ntlmv2_key (
+ const void */*key*/,
+ size_t /*len*/,
+ const char */*username*/,
+ const char */*target*/,
+ unsigned char ntlmv2[16]);
+
+int
+heim_ntlm_verify_ntlm2 (
+ const void */*key*/,
+ size_t /*len*/,
+ const char */*username*/,
+ const char */*target*/,
+ time_t /*now*/,
+ const unsigned char serverchallange[8],
+ const struct ntlm_buf */*answer*/,
+ struct ntlm_buf */*infotarget*/,
+ unsigned char ntlmv2[16]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __heimntlm_protos_h__ */
diff --git a/source4/heimdal/lib/ntlm/heimntlm.h b/source4/heimdal/lib/ntlm/heimntlm.h
new file mode 100644
index 00000000000..1e38b2e400a
--- /dev/null
+++ b/source4/heimdal/lib/ntlm/heimntlm.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: heimntlm.h,v 1.4 2006/12/20 07:28:37 lha Exp $ */
+
+#ifndef HEIM_NTLM_H
+#define HEIM_NTLM_H
+
+struct ntlm_buf {
+ size_t length;
+ void *data;
+};
+
+#define NTLM_NEG_UNICODE 0x00000001
+#define NTLM_NEG_SIGN 0x00000010
+#define NTLM_NEG_SEAL 0x00000020
+#define NTLM_NEG_NTLM 0x00000200
+
+#define NTLM_SUPPLIED_DOMAIN 0x00001000
+#define NTLM_SUPPLIED_WORKSTAION 0x00002000
+
+#define NTLM_NEG_ALWAYS_SIGN 0x00008000
+#define NTLM_NEG_NTLM2_SESSION 0x00080000
+
+#define NTLM_NEG_TARGET_DOMAIN 0x00010000
+#define NTLM_ENC_128 0x20000000
+#define NTLM_NEG_KEYEX 0x40000000
+
+struct ntlm_targetinfo {
+ char *servername;
+ char *domainname;
+ char *dnsdomainname;
+ char *dnsservername;
+};
+
+struct ntlm_type1 {
+ uint32_t flags;
+ char *domain;
+ char *hostname;
+ uint32_t os[2];
+};
+
+struct ntlm_type2 {
+ uint32_t flags;
+ char *targetname;
+ struct ntlm_buf targetinfo;
+ unsigned char challange[8];
+ uint32_t context[2];
+ uint32_t os[2];
+};
+
+struct ntlm_type3 {
+ uint32_t flags;
+ char *username;
+ char *targetname;
+ struct ntlm_buf lm;
+ struct ntlm_buf ntlm;
+ struct ntlm_buf sessionkey;
+ char *ws;
+ uint32_t os[2];
+};
+
+#include <heimntlm-protos.h>
+
+#endif /* NTLM_NTLM_H */
diff --git a/source4/heimdal/lib/ntlm/ntlm.c b/source4/heimdal/lib/ntlm/ntlm.c
new file mode 100644
index 00000000000..430e80505ef
--- /dev/null
+++ b/source4/heimdal/lib/ntlm/ntlm.c
@@ -0,0 +1,1078 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+RCSID("$Id: ntlm.c,v 1.8 2006/12/26 00:25:17 lha Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <krb5.h>
+#include <roken.h>
+
+#include "krb5-types.h"
+#include "crypto-headers.h"
+
+#include <heimntlm.h>
+
+
+struct sec_buffer {
+ uint16_t length;
+ uint16_t allocated;
+ uint32_t offset;
+};
+
+static const unsigned char ntlmsigature[8] = "NTLMSSP\x00";
+
+/*
+ *
+ */
+
+#define CHECK(f, e) \
+ do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0)
+
+static void
+_ntlm_free_buf(struct ntlm_buf *p)
+{
+ if (p->data)
+ free(p->data);
+ p->data = NULL;
+ p->length = 0;
+}
+
+
+static int
+ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf)
+{
+ unsigned char *p;
+ size_t len, i;
+
+ len = strlen(string);
+ if (len / 2 > UINT_MAX)
+ return ERANGE;
+
+ buf->length = len * 2;
+ buf->data = malloc(buf->length);
+ if (buf->data == NULL && len != 0) {
+ _ntlm_free_buf(buf);
+ return ENOMEM;
+ }
+
+ p = buf->data;
+ for (i = 0; i < len; i++) {
+ unsigned char t = (unsigned char)string[i];
+ if (t & 0x80) {
+ _ntlm_free_buf(buf);
+ return EINVAL;
+ }
+ if (up)
+ t = toupper(t);
+ p[(i * 2) + 0] = t;
+ p[(i * 2) + 1] = 0;
+ }
+ return 0;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf)
+{
+ krb5_error_code ret;
+ CHECK(krb5_ret_uint16(sp, &buf->length), 0);
+ CHECK(krb5_ret_uint16(sp, &buf->allocated), 0);
+ CHECK(krb5_ret_uint32(sp, &buf->offset), 0);
+out:
+ return ret;
+}
+
+static krb5_error_code
+store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf)
+{
+ krb5_error_code ret;
+ CHECK(krb5_store_uint16(sp, buf->length), 0);
+ CHECK(krb5_store_uint16(sp, buf->allocated), 0);
+ CHECK(krb5_store_uint32(sp, buf->offset), 0);
+out:
+ return ret;
+}
+
+/*
+ * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
+ * wire, but using utf8 in memory.
+ */
+
+static krb5_error_code
+len_string(int ucs2, const char *s)
+{
+ size_t len = strlen(s);
+ if (ucs2)
+ len *= 2;
+ return len;
+}
+
+static krb5_error_code
+ret_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s)
+{
+ krb5_error_code ret;
+
+ *s = malloc(desc->length + 1);
+ CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
+ CHECK(krb5_storage_read(sp, *s, desc->length), desc->length);
+ (*s)[desc->length] = '\0';
+
+ if (ucs2) {
+ size_t i;
+ for (i = 0; i < desc->length / 2; i++) {
+ (*s)[i] = (*s)[i * 2];
+ if ((*s)[i * 2 + 1]) {
+ free(*s);
+ *s = NULL;
+ return EINVAL;
+ }
+ }
+ (*s)[i] = '\0';
+ }
+ ret = 0;
+out:
+ return ret;
+
+ return 0;
+}
+
+static krb5_error_code
+put_string(krb5_storage *sp, int ucs2, const char *s)
+{
+ krb5_error_code ret;
+ struct ntlm_buf buf;
+
+ if (ucs2) {
+ ret = ascii2ucs2le(s, 0, &buf);
+ if (ret)
+ return ret;
+ } else {
+ buf.data = rk_UNCONST(s);
+ buf.length = strlen(s);
+ }
+
+ CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length);
+ if (ucs2)
+ _ntlm_free_buf(&buf);
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf)
+{
+ krb5_error_code ret;
+
+ buf->data = malloc(desc->length);
+ buf->length = desc->length;
+ CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
+ CHECK(krb5_storage_read(sp, buf->data, buf->length), buf->length);
+ ret = 0;
+out:
+ return ret;
+}
+
+static krb5_error_code
+put_buf(krb5_storage *sp, struct ntlm_buf *buf)
+{
+ krb5_error_code ret;
+ CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length);
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ *
+ */
+
+void
+heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti)
+{
+ free(ti->servername);
+ free(ti->domainname);
+ free(ti->dnsdomainname);
+ free(ti->dnsservername);
+ memset(ti, 0, sizeof(*ti));
+}
+
+static int
+encode_ti_blob(krb5_storage *out, uint16_t type, int ucs2, char *s)
+{
+ krb5_error_code ret;
+ CHECK(krb5_store_uint16(out, type), 0);
+ CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0);
+ CHECK(put_string(out, ucs2, s), 0);
+out:
+ return ret;
+}
+
+int
+heim_ntlm_encode_targetinfo(struct ntlm_targetinfo *ti,
+ int ucs2,
+ struct ntlm_buf *data)
+{
+ krb5_error_code ret;
+ krb5_storage *out;
+
+ data->data = NULL;
+ data->length = 0;
+
+ out = krb5_storage_emem();
+ if (out == NULL)
+ return ENOMEM;
+
+ if (ti->servername)
+ CHECK(encode_ti_blob(out, 1, ucs2, ti->servername), 0);
+ if (ti->domainname)
+ CHECK(encode_ti_blob(out, 2, ucs2, ti->domainname), 0);
+ if (ti->dnsservername)
+ CHECK(encode_ti_blob(out, 3, ucs2, ti->dnsservername), 0);
+ if (ti->dnsdomainname)
+ CHECK(encode_ti_blob(out, 4, ucs2, ti->dnsdomainname), 0);
+
+ /* end tag */
+ CHECK(krb5_store_int16(out, 0), 0);
+ CHECK(krb5_store_int16(out, 0), 0);
+
+ {
+ krb5_data d;
+ ret = krb5_storage_to_data(out, &d);
+ data->data = d.data;
+ data->length = d.length;
+ }
+out:
+ krb5_storage_free(out);
+ return ret;
+}
+
+int
+heim_ntlm_decode_targetinfo(struct ntlm_buf *data, int ucs2,
+ struct ntlm_targetinfo *ti)
+{
+ memset(ti, 0, sizeof(*ti));
+ return 0;
+}
+
+/*
+ * encoder/decoder type1 messages
+ */
+
+void
+heim_ntlm_free_type1(struct ntlm_type1 *data)
+{
+ free(data->domain);
+ free(data->hostname);
+ memset(data, 0, sizeof(*data));
+}
+
+int
+heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data)
+{
+ krb5_error_code ret;
+ unsigned char sig[8];
+ uint32_t type;
+ struct sec_buffer domain, hostname;
+ krb5_storage *in;
+
+ memset(data, 0, sizeof(*data));
+
+ in = krb5_storage_from_readonly_mem(buf->data, buf->length);
+ if (in == NULL) {
+ ret = EINVAL;
+ goto out;
+ }
+ krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
+ CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
+ CHECK(krb5_ret_uint32(in, &type), 0);
+ CHECK(type, 1);
+ CHECK(krb5_ret_uint32(in, &data->flags), 0);
+ if (data->flags & NTLM_SUPPLIED_DOMAIN)
+ CHECK(ret_sec_buffer(in, &domain), 0);
+ if (data->flags & NTLM_SUPPLIED_WORKSTAION)
+ CHECK(ret_sec_buffer(in, &hostname), 0);
+#if 0
+ if (domain.offset > 32) {
+ CHECK(krb5_ret_uint32(in, &data->os[0]), 0);
+ CHECK(krb5_ret_uint32(in, &data->os[1]), 0);
+ }
+#endif
+ if (data->flags & NTLM_SUPPLIED_DOMAIN)
+ CHECK(ret_string(in, 0, &domain, &data->domain), 0);
+ if (data->flags & NTLM_SUPPLIED_WORKSTAION)
+ CHECK(ret_string(in, 0, &hostname, &data->hostname), 0);
+
+out:
+ krb5_storage_free(in);
+ if (ret)
+ heim_ntlm_free_type1(data);
+
+ return ret;
+}
+
+int
+heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data)
+{
+ krb5_error_code ret;
+ struct sec_buffer domain, hostname;
+ krb5_storage *out;
+ uint32_t base, flags;
+
+ flags = type1->flags;
+ base = 16;
+
+ if (type1->domain) {
+ base += 8;
+ flags |= NTLM_SUPPLIED_DOMAIN;
+ }
+ if (type1->hostname) {
+ base += 8;
+ flags |= NTLM_SUPPLIED_WORKSTAION;
+ }
+ if (type1->os[0])
+ base += 8;
+
+ if (type1->domain) {
+ domain.offset = base;
+ domain.length = len_string(0, type1->domain);
+ domain.allocated = domain.length;
+ }
+ if (type1->hostname) {
+ hostname.offset = domain.allocated + domain.offset;
+ hostname.length = len_string(0, type1->hostname);
+ hostname.allocated = hostname.length;
+ }
+
+ out = krb5_storage_emem();
+ if (out == NULL)
+ return ENOMEM;
+
+ krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
+ CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
+ sizeof(ntlmsigature));
+ CHECK(krb5_store_uint32(out, 1), 0);
+ CHECK(krb5_store_uint32(out, flags), 0);
+
+ if (type1->domain)
+ CHECK(store_sec_buffer(out, &domain), 0);
+ if (type1->hostname)
+ CHECK(store_sec_buffer(out, &hostname), 0);
+ if (type1->os[0]) {
+ CHECK(krb5_store_uint32(out, type1->os[0]), 0);
+ CHECK(krb5_store_uint32(out, type1->os[1]), 0);
+ }
+ if (type1->domain)
+ CHECK(put_string(out, 0, type1->domain), 0);
+ if (type1->hostname)
+ CHECK(put_string(out, 0, type1->hostname), 0);
+
+ {
+ krb5_data d;
+ ret = krb5_storage_to_data(out, &d);
+ data->data = d.data;
+ data->length = d.length;
+ }
+out:
+ krb5_storage_free(out);
+
+ return ret;
+}
+
+/*
+ * encoder/decoder type 2 messages
+ */
+
+void
+heim_ntlm_free_type2(struct ntlm_type2 *type2)
+{
+ memset(type2, 0, sizeof(*type2));
+}
+
+int
+heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2)
+{
+ krb5_error_code ret;
+ unsigned char sig[8];
+ uint32_t type, ctx[2];
+ struct sec_buffer targetname, targetinfo;
+ krb5_storage *in;
+ int ucs2 = 0;
+
+ memset(type2, 0, sizeof(*type2));
+
+ in = krb5_storage_from_readonly_mem(buf->data, buf->length);
+ if (in == NULL) {
+ ret = EINVAL;
+ goto out;
+ }
+ krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
+ CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
+ CHECK(krb5_ret_uint32(in, &type), 0);
+ CHECK(type, 2);
+
+ CHECK(ret_sec_buffer(in, &targetname), 0);
+ CHECK(krb5_ret_uint32(in, &type2->flags), 0);
+ if (type2->flags & NTLM_NEG_UNICODE)
+ ucs2 = 1;
+ CHECK(krb5_storage_read(in, type2->challange, sizeof(type2->challange)),
+ sizeof(type2->challange));
+ CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */
+ CHECK(krb5_ret_uint32(in, &ctx[1]), 0);
+ CHECK(ret_sec_buffer(in, &targetinfo), 0);
+ /* os version */
+#if 0
+ CHECK(krb5_ret_uint32(in, &type2->os[0]), 0);
+ CHECK(krb5_ret_uint32(in, &type2->os[1]), 0);
+#endif
+
+ CHECK(ret_string(in, ucs2, &targetname, &type2->targetname), 0);
+ CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0);
+ ret = 0;
+
+out:
+ krb5_storage_free(in);
+ if (ret)
+ heim_ntlm_free_type2(type2);
+
+ return ret;
+}
+
+int
+heim_ntlm_encode_type2(struct ntlm_type2 *type2, struct ntlm_buf *data)
+{
+ struct sec_buffer targetname, targetinfo;
+ krb5_error_code ret;
+ krb5_storage *out = NULL;
+ uint32_t base;
+ int ucs2 = 0;
+
+ if (type2->os[0])
+ base = 56;
+ else
+ base = 48;
+
+ if (type2->flags & NTLM_NEG_UNICODE)
+ ucs2 = 1;
+
+ targetname.offset = base;
+ targetname.length = len_string(ucs2, type2->targetname);
+ targetname.allocated = targetname.length;
+
+ targetinfo.offset = targetname.allocated + targetname.offset;
+ targetinfo.length = type2->targetinfo.length;
+ targetinfo.allocated = type2->targetinfo.length;
+
+ out = krb5_storage_emem();
+ if (out == NULL)
+ return ENOMEM;
+
+ krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
+ CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
+ sizeof(ntlmsigature));
+ CHECK(krb5_store_uint32(out, 2), 0);
+ CHECK(store_sec_buffer(out, &targetname), 0);
+ CHECK(krb5_store_uint32(out, type2->flags), 0);
+ CHECK(krb5_storage_write(out, type2->challange, sizeof(type2->challange)),
+ sizeof(type2->challange));
+ CHECK(krb5_store_uint32(out, 0), 0); /* context */
+ CHECK(krb5_store_uint32(out, 0), 0);
+ CHECK(store_sec_buffer(out, &targetinfo), 0);
+ /* os version */
+ if (type2->os[0]) {
+ CHECK(krb5_store_uint32(out, type2->os[0]), 0);
+ CHECK(krb5_store_uint32(out, type2->os[1]), 0);
+ }
+ CHECK(put_string(out, ucs2, type2->targetname), 0);
+ CHECK(krb5_storage_write(out, type2->targetinfo.data,
+ type2->targetinfo.length),
+ type2->targetinfo.length);
+
+ {
+ krb5_data d;
+ ret = krb5_storage_to_data(out, &d);
+ data->data = d.data;
+ data->length = d.length;
+ }
+
+out:
+ krb5_storage_free(out);
+
+ return ret;
+}
+
+/*
+ * encoder/decoder type 2 messages
+ */
+
+void
+heim_ntlm_free_type3(struct ntlm_type3 *data)
+{
+ memset(data, 0, sizeof(*data));
+}
+
+
+/*
+ *
+ */
+
+int
+heim_ntlm_decode_type3(const struct ntlm_buf *buf,
+ int ucs2,
+ struct ntlm_type3 *type3)
+{
+ krb5_error_code ret;
+ unsigned char sig[8];
+ uint32_t type;
+ krb5_storage *in;
+ struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
+
+ memset(type3, 0, sizeof(*type3));
+ memset(&sessionkey, 0, sizeof(sessionkey));
+
+ in = krb5_storage_from_readonly_mem(buf->data, buf->length);
+ if (in == NULL) {
+ ret = EINVAL;
+ goto out;
+ }
+ krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
+ CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
+ CHECK(krb5_ret_uint32(in, &type), 0);
+ CHECK(type, 3);
+ CHECK(ret_sec_buffer(in, &lm), 0);
+ CHECK(ret_sec_buffer(in, &ntlm), 0);
+ CHECK(ret_sec_buffer(in, &target), 0);
+ CHECK(ret_sec_buffer(in, &username), 0);
+ CHECK(ret_sec_buffer(in, &ws), 0);
+ if (lm.offset >= 60) {
+ CHECK(ret_sec_buffer(in, &sessionkey), 0);
+ }
+ if (lm.offset >= 64) {
+ CHECK(krb5_ret_uint32(in, &type3->flags), 0);
+ }
+ if (lm.offset >= 72) {
+ CHECK(krb5_ret_uint32(in, &type3->os[0]), 0);
+ CHECK(krb5_ret_uint32(in, &type3->os[1]), 0);
+ }
+ CHECK(ret_buf(in, &lm, &type3->lm), 0);
+ CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0);
+ CHECK(ret_string(in, ucs2, &target, &type3->targetname), 0);
+ CHECK(ret_string(in, ucs2, &username, &type3->username), 0);
+ CHECK(ret_string(in, ucs2, &username, &type3->ws), 0);
+ if (sessionkey.offset)
+ CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0);
+
+out:
+ krb5_storage_free(in);
+ if (ret)
+ heim_ntlm_free_type3(type3);
+
+ return ret;
+}
+
+int
+heim_ntlm_encode_type3(struct ntlm_type3 *type3, struct ntlm_buf *data)
+{
+ struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
+ krb5_error_code ret;
+ krb5_storage *out = NULL;
+ uint32_t base;
+ int ucs2 = 0;
+
+ memset(&lm, 0, sizeof(lm));
+ memset(&ntlm, 0, sizeof(ntlm));
+ memset(&target, 0, sizeof(target));
+ memset(&username, 0, sizeof(username));
+ memset(&ws, 0, sizeof(ws));
+ memset(&sessionkey, 0, sizeof(sessionkey));
+
+ base = 52;
+ if (type3->sessionkey.length) {
+ base += 8; /* sessionkey sec buf */
+ base += 4; /* flags */
+ }
+ if (type3->os[0]) {
+ base += 8;
+ }
+
+ if (type3->flags & NTLM_NEG_UNICODE)
+ ucs2 = 1;
+
+ lm.offset = base;
+ lm.length = type3->lm.length;
+ lm.allocated = type3->lm.length;
+
+ ntlm.offset = lm.offset + lm.allocated;
+ ntlm.length = type3->ntlm.length;
+ ntlm.allocated = ntlm.length;
+
+ target.offset = ntlm.offset + ntlm.allocated;
+ target.length = len_string(ucs2, type3->targetname);
+ target.allocated = target.length;
+
+ username.offset = target.offset + target.allocated;
+ username.length = len_string(ucs2, type3->username);
+ username.allocated = username.length;
+
+ ws.offset = username.offset + username.allocated;
+ ws.length = len_string(ucs2, type3->ws);
+ ws.allocated = ws.length;
+
+ sessionkey.offset = ws.offset + ws.allocated;
+ sessionkey.length = type3->sessionkey.length;
+ sessionkey.allocated = type3->sessionkey.length;
+
+ out = krb5_storage_emem();
+ if (out == NULL)
+ return ENOMEM;
+
+ krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
+ CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
+ sizeof(ntlmsigature));
+ CHECK(krb5_store_uint32(out, 3), 0);
+
+ CHECK(store_sec_buffer(out, &lm), 0);
+ CHECK(store_sec_buffer(out, &ntlm), 0);
+ CHECK(store_sec_buffer(out, &target), 0);
+ CHECK(store_sec_buffer(out, &username), 0);
+ CHECK(store_sec_buffer(out, &ws), 0);
+ /* optional */
+ if (type3->sessionkey.length) {
+ CHECK(store_sec_buffer(out, &sessionkey), 0);
+ CHECK(krb5_store_uint32(out, type3->flags), 0);
+ }
+#if 0
+ CHECK(krb5_store_uint32(out, 0), 0); /* os0 */
+ CHECK(krb5_store_uint32(out, 0), 0); /* os1 */
+#endif
+
+ CHECK(put_buf(out, &type3->lm), 0);
+ CHECK(put_buf(out, &type3->ntlm), 0);
+ CHECK(put_string(out, ucs2, type3->targetname), 0);
+ CHECK(put_string(out, ucs2, type3->username), 0);
+ CHECK(put_string(out, ucs2, type3->ws), 0);
+ CHECK(put_buf(out, &type3->sessionkey), 0);
+
+ {
+ krb5_data d;
+ ret = krb5_storage_to_data(out, &d);
+ data->data = d.data;
+ data->length = d.length;
+ }
+
+out:
+ krb5_storage_free(out);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+
+static void
+splitandenc(unsigned char *hash,
+ unsigned char *challange,
+ unsigned char *answer)
+{
+ DES_cblock key;
+ DES_key_schedule sched;
+
+ ((unsigned char*)key)[0] = hash[0];
+ ((unsigned char*)key)[1] = (hash[0] << 7) | (hash[1] >> 1);
+ ((unsigned char*)key)[2] = (hash[1] << 6) | (hash[2] >> 2);
+ ((unsigned char*)key)[3] = (hash[2] << 5) | (hash[3] >> 3);
+ ((unsigned char*)key)[4] = (hash[3] << 4) | (hash[4] >> 4);
+ ((unsigned char*)key)[5] = (hash[4] << 3) | (hash[5] >> 5);
+ ((unsigned char*)key)[6] = (hash[5] << 2) | (hash[6] >> 6);
+ ((unsigned char*)key)[7] = (hash[6] << 1);
+
+ DES_set_odd_parity(&key);
+ DES_set_key(&key, &sched);
+ DES_ecb_encrypt((DES_cblock *)challange, (DES_cblock *)answer, &sched, 1);
+ memset(&sched, 0, sizeof(sched));
+ memset(key, 0, sizeof(key));
+}
+
+int
+heim_ntlm_nt_key(const char *password, struct ntlm_buf *key)
+{
+ struct ntlm_buf buf;
+ MD4_CTX ctx;
+ int ret;
+
+ key->data = malloc(MD5_DIGEST_LENGTH);
+ if (key->data == NULL)
+ return ENOMEM;
+ key->length = MD5_DIGEST_LENGTH;
+
+ ret = ascii2ucs2le(password, 0, &buf);
+ if (ret) {
+ _ntlm_free_buf(key);
+ return ret;
+ }
+ MD4_Init(&ctx);
+ MD4_Update(&ctx, buf.data, buf.length);
+ MD4_Final(key->data, &ctx);
+ _ntlm_free_buf(&buf);
+ return 0;
+}
+
+int
+heim_ntlm_calculate_ntlm1(void *key, size_t len,
+ unsigned char challange[8],
+ struct ntlm_buf *answer)
+{
+ unsigned char res[21];
+
+ if (len != MD4_DIGEST_LENGTH)
+ return EINVAL;
+
+ memcpy(res, key, len);
+ memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH);
+
+ answer->data = malloc(24);
+ if (answer->data == NULL)
+ return ENOMEM;
+ answer->length = 24;
+
+ splitandenc(&res[0], challange, ((unsigned char *)answer->data) + 0);
+ splitandenc(&res[7], challange, ((unsigned char *)answer->data) + 8);
+ splitandenc(&res[14], challange, ((unsigned char *)answer->data) + 16);
+
+ return 0;
+}
+
+int
+heim_ntlm_build_ntlm1_master(void *key, size_t len,
+ struct ntlm_buf *session,
+ struct ntlm_buf *master)
+{
+ RC4_KEY rc4;
+
+ memset(master, 0, sizeof(*master));
+ memset(session, 0, sizeof(*session));
+
+ if (len != MD4_DIGEST_LENGTH)
+ return EINVAL;
+
+ session->length = MD4_DIGEST_LENGTH;
+ session->data = malloc(session->length);
+ if (session->data == NULL) {
+ session->length = 0;
+ return EINVAL;
+ }
+ master->length = MD4_DIGEST_LENGTH;
+ master->data = malloc(master->length);
+ if (master->data == NULL) {
+ _ntlm_free_buf(master);
+ _ntlm_free_buf(session);
+ return EINVAL;
+ }
+
+ {
+ unsigned char sessionkey[MD4_DIGEST_LENGTH];
+ MD4_CTX ctx;
+
+ MD4_Init(&ctx);
+ MD4_Update(&ctx, key, len);
+ MD4_Final(sessionkey, &ctx);
+
+ RC4_set_key(&rc4, sizeof(sessionkey), sessionkey);
+ }
+
+ if (RAND_bytes(session->data, session->length) != 1) {
+ _ntlm_free_buf(master);
+ _ntlm_free_buf(session);
+ return EINVAL;
+ }
+
+ RC4(&rc4, master->length, session->data, master->data);
+ memset(&rc4, 0, sizeof(rc4));
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+void
+heim_ntlm_ntlmv2_key(const void *key, size_t len,
+ const char *username,
+ const char *target,
+ unsigned char ntlmv2[16])
+{
+ unsigned int hmaclen;
+ HMAC_CTX c;
+
+ HMAC_CTX_init(&c);
+ HMAC_Init_ex(&c, key, len, EVP_md5(), NULL);
+ {
+ struct ntlm_buf buf;
+ /* uppercase username and turn it inte ucs2-le */
+ ascii2ucs2le(username, 1, &buf);
+ HMAC_Update(&c, buf.data, buf.length);
+ free(buf.data);
+ /* turn target into ucs2-le */
+ ascii2ucs2le(target, 0, &buf);
+ HMAC_Update(&c, buf.data, buf.length);
+ free(buf.data);
+ }
+ HMAC_Final(&c, ntlmv2, &hmaclen);
+ HMAC_CTX_cleanup(&c);
+
+}
+
+/*
+ *
+ */
+
+#define NTTIME_EPOCH 0x019DB1DED53E8000LL
+
+static uint64_t
+unix2nttime(time_t unix_time)
+{
+ long long wt;
+ wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
+ return wt;
+}
+
+static time_t
+nt2unixtime(uint64_t t)
+{
+ t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000);
+ if (t > (((time_t)(~(uint64_t)0)) >> 1))
+ return 0;
+ return (time_t)t;
+}
+
+
+int
+heim_ntlm_calculate_ntlm2(const void *key, size_t len,
+ const char *username,
+ const char *target,
+ const unsigned char serverchallange[8],
+ const struct ntlm_buf *infotarget,
+ unsigned char ntlmv2[16],
+ struct ntlm_buf *answer)
+{
+ krb5_error_code ret;
+ krb5_data data;
+ unsigned int hmaclen;
+ unsigned char ntlmv2answer[16];
+ krb5_storage *sp;
+ unsigned char clientchallange[8];
+ HMAC_CTX c;
+ uint64_t t;
+
+ t = unix2nttime(time(NULL));
+
+ if (RAND_bytes(clientchallange, sizeof(clientchallange)) != 1)
+ return EINVAL;
+
+ /* calculate ntlmv2 key */
+
+ heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
+
+ /* calculate and build ntlmv2 answer */
+
+ sp = krb5_storage_emem();
+ if (sp == NULL)
+ return ENOMEM;
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(krb5_store_uint32(sp, 0x01010000), 0);
+ CHECK(krb5_store_uint32(sp, 0), 0);
+ /* timestamp le 64 bit ts */
+ CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0);
+ CHECK(krb5_store_uint32(sp, t >> 32), 0);
+ CHECK(krb5_storage_write(sp, clientchallange, 8), 8);
+ CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length),
+ infotarget->length);
+ /* unknown */
+ /* CHECK(krb5_store_uint32(sp, 0), 0); */
+
+ CHECK(krb5_storage_to_data(sp, &data), 0);
+ krb5_storage_free(sp);
+ sp = NULL;
+
+ HMAC_CTX_init(&c);
+ HMAC_Init_ex(&c, ntlmv2, sizeof(ntlmv2), EVP_md5(), NULL);
+ HMAC_Update(&c, data.data, data.length);
+ HMAC_Update(&c, serverchallange, 8);
+ HMAC_Final(&c, ntlmv2answer, &hmaclen);
+ HMAC_CTX_cleanup(&c);
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_data_free(&data);
+ return ENOMEM;
+ }
+
+ CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16);
+ CHECK(krb5_storage_write(sp, data.data, data.length), data.length);
+ krb5_data_free(&data);
+
+ CHECK(krb5_storage_to_data(sp, &data), 0);
+ krb5_storage_free(sp);
+ sp = NULL;
+
+ answer->data = data.data;
+ answer->length = data.length;
+
+ return 0;
+out:
+ if (sp)
+ krb5_storage_free(sp);
+ return ret;
+}
+
+static const int authtimediff = 3600 * 2; /* 2 hours */
+
+int
+heim_ntlm_verify_ntlm2(const void *key, size_t len,
+ const char *username,
+ const char *target,
+ time_t now,
+ const unsigned char serverchallange[8],
+ const struct ntlm_buf *answer,
+ struct ntlm_buf *infotarget,
+ unsigned char ntlmv2[16])
+{
+ krb5_error_code ret;
+ unsigned int hmaclen;
+ unsigned char clientanswer[16];
+ unsigned char serveranswer[16];
+ krb5_storage *sp;
+ HMAC_CTX c;
+ uint64_t t;
+ time_t authtime;
+ uint32_t temp;
+
+ infotarget->length = 0;
+ infotarget->data = NULL;
+
+ if (answer->length < 16)
+ return EINVAL;
+
+ if (now == 0)
+ now = time(NULL);
+
+ /* calculate ntlmv2 key */
+
+ heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
+
+ /* calculate and build ntlmv2 answer */
+
+ sp = krb5_storage_from_readonly_mem(answer->data, answer->length);
+ if (sp == NULL)
+ return ENOMEM;
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ CHECK(krb5_storage_read(sp, clientanswer, 16), 16);
+
+ CHECK(krb5_ret_uint32(sp, &temp), 0);
+ CHECK(temp, 0x01010000);
+ CHECK(krb5_ret_uint32(sp, &temp), 0);
+ CHECK(temp, 0);
+ /* timestamp le 64 bit ts */
+ CHECK(krb5_ret_uint32(sp, &temp), 0);
+ t = temp;
+ CHECK(krb5_ret_uint32(sp, &temp), 0);
+ t |= ((uint64_t)temp)<< 32;
+
+ authtime = nt2unixtime(t);
+
+ if (abs((int)(authtime - now)) > authtimediff) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ /* client challange */
+ CHECK(krb5_storage_read(sp, serveranswer, 8), 8);
+
+ infotarget->length = answer->length - 40;
+ infotarget->data = malloc(infotarget->length);
+ if (infotarget->data == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length),
+ infotarget->length);
+ /* XXX remove the unknown uint32_t */
+ krb5_storage_free(sp);
+ sp = NULL;
+
+ HMAC_CTX_init(&c);
+ HMAC_Init_ex(&c, ntlmv2, sizeof(ntlmv2), EVP_md5(), NULL);
+ HMAC_Update(&c, ((char *)answer->data) + 16, answer->length - 16);
+ HMAC_Update(&c, serverchallange, 8);
+ HMAC_Final(&c, serveranswer, &hmaclen);
+ HMAC_CTX_cleanup(&c);
+
+ if (memcmp(serveranswer, clientanswer, 16) != 0) {
+ _ntlm_free_buf(infotarget);
+ return EINVAL;
+ }
+
+ return 0;
+out:
+ _ntlm_free_buf(infotarget);
+ if (sp)
+ krb5_storage_free(sp);
+ return ret;
+}
diff --git a/source4/heimdal/lib/roken/closefrom.c b/source4/heimdal/lib/roken/closefrom.c
new file mode 100644
index 00000000000..6b02f1ebca6
--- /dev/null
+++ b/source4/heimdal/lib/roken/closefrom.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: closefrom.c,v 1.2 2005/04/13 08:01:38 lha Exp $");
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <roken.h>
+
+int ROKEN_LIB_FUNCTION
+closefrom(int fd)
+{
+ int num = getdtablesize();
+
+ if (num < 0)
+ num = 1024; /* XXX */
+
+ for (; fd <= num; fd++)
+ close(fd);
+
+ return 0;
+}
diff --git a/source4/heimdal/lib/roken/dumpdata.c b/source4/heimdal/lib/roken/dumpdata.c
new file mode 100644
index 00000000000..402b4b1cb99
--- /dev/null
+++ b/source4/heimdal/lib/roken/dumpdata.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: dumpdata.c,v 1.1 2005/09/22 23:51:35 lha Exp $");
+#endif
+
+#include <unistd.h>
+
+#include <roken.h>
+
+/*
+ * Write datablob to a filename, don't care about errors.
+ */
+
+void ROKEN_LIB_FUNCTION
+rk_dumpdata (const char *filename, const void *buf, size_t size)
+{
+ int fd;
+
+ fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0640);
+ if (fd < 0)
+ return;
+ net_write(fd, buf, size);
+ close(fd);
+}
diff --git a/source4/heimdal/lib/roken/erealloc.c b/source4/heimdal/lib/roken/erealloc.c
new file mode 100644
index 00000000000..497b1e7ec2f
--- /dev/null
+++ b/source4/heimdal/lib/roken/erealloc.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: erealloc.c,v 1.6 2005/04/12 11:28:37 lha Exp $");
+#endif
+
+#include <stdlib.h>
+#include <err.h>
+
+#include <roken.h>
+
+/*
+ * Like realloc but never fails.
+ */
+
+void * ROKEN_LIB_FUNCTION
+erealloc (void *ptr, size_t sz)
+{
+ void *tmp = realloc (ptr, sz);
+
+ if (tmp == NULL && sz != 0)
+ errx (1, "realloc %lu failed", (unsigned long)sz);
+ return tmp;
+}
diff --git a/source4/heimdal/lib/roken/parse_bytes.h b/source4/heimdal/lib/roken/parse_bytes.h
new file mode 100644
index 00000000000..1537d16c33f
--- /dev/null
+++ b/source4/heimdal/lib/roken/parse_bytes.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: parse_bytes.h,v 1.4 2005/04/13 13:19:07 lha Exp $ */
+
+#ifndef __PARSE_BYTES_H__
+#define __PARSE_BYTES_H__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+int ROKEN_LIB_FUNCTION
+parse_bytes (const char *s, const char *def_unit);
+
+int ROKEN_LIB_FUNCTION
+unparse_bytes (int t, char *s, size_t len);
+
+int ROKEN_LIB_FUNCTION
+unparse_bytes_short (int t, char *s, size_t len);
+
+#endif /* __PARSE_BYTES_H__ */
diff --git a/source4/heimdal/lib/roken/resolve.c b/source4/heimdal/lib/roken/resolve.c
index 6a14547c62d..0f45bc57b22 100644
--- a/source4/heimdal/lib/roken/resolve.c
+++ b/source4/heimdal/lib/roken/resolve.c
@@ -504,7 +504,7 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type)
memset(&state, 0, sizeof(state));
if(res_ninit(&state))
return NULL; /* is this the best we can do? */
-#elif defined(HAVE__RES) && defined(HAVE_DECL__RES)
+#elif defined(HAVE__RES)
u_long old_options = 0;
#endif
@@ -520,7 +520,7 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type)
if (_resolve_debug) {
#ifdef HAVE_RES_NSEARCH
state.options |= RES_DEBUG;
-#elif defined(HAVE__RES) && defined(HAVE_DECL__RES)
+#elif defined(HAVE__RES)
old_options = _res.options;
_res.options |= RES_DEBUG;
#endif
@@ -540,7 +540,7 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type)
len = res_search(domain, rr_class, rr_type, reply, size);
#endif
if (_resolve_debug) {
-#if defined(HAVE__RES) && defined(HAVE_DECL__RES) && !defined(HAVE_RES_NSEARCH)
+#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
_res.options = old_options;
#endif
fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
diff --git a/source4/heimdal/lib/roken/simple_exec.c b/source4/heimdal/lib/roken/simple_exec.c
new file mode 100644
index 00000000000..048f2846ddf
--- /dev/null
+++ b/source4/heimdal/lib/roken/simple_exec.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: simple_exec.c,v 1.14 2005/04/13 11:39:00 lha Exp $");
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <roken.h>
+
+#define EX_NOEXEC 126
+#define EX_NOTFOUND 127
+
+/* return values:
+ -1 on `unspecified' system errors
+ -2 on fork failures
+ -3 on waitpid errors
+ -4 exec timeout
+ 0- is return value from subprocess
+ 126 if the program couldn't be executed
+ 127 if the program couldn't be found
+ 128- is 128 + signal that killed subprocess
+
+ possible values `func' can return:
+ ((time_t)-2) exit loop w/o killing child and return
+ `exec timeout'/-4 from simple_exec
+ ((time_t)-1) kill child with SIGTERM and wait for child to exit
+ 0 don't timeout again
+ n seconds to next timeout
+ */
+
+static int sig_alarm;
+
+static RETSIGTYPE
+sigtimeout(int sig)
+{
+ sig_alarm = 1;
+ SIGRETURN(0);
+}
+
+int ROKEN_LIB_FUNCTION
+wait_for_process_timed(pid_t pid, time_t (*func)(void *),
+ void *ptr, time_t timeout)
+{
+ RETSIGTYPE (*old_func)(int sig) = NULL;
+ unsigned int oldtime = 0;
+ int ret;
+
+ sig_alarm = 0;
+
+ if (func) {
+ old_func = signal(SIGALRM, sigtimeout);
+ oldtime = alarm(timeout);
+ }
+
+ while(1) {
+ int status;
+
+ while(waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR) {
+ ret = -3;
+ goto out;
+ }
+ if (func == NULL)
+ continue;
+ if (sig_alarm == 0)
+ continue;
+ timeout = (*func)(ptr);
+ if (timeout == (time_t)-1) {
+ kill(pid, SIGTERM);
+ continue;
+ } else if (timeout == (time_t)-2) {
+ ret = -4;
+ goto out;
+ }
+ alarm(timeout);
+ }
+ if(WIFSTOPPED(status))
+ continue;
+ if(WIFEXITED(status)) {
+ ret = WEXITSTATUS(status);
+ break;
+ }
+ if(WIFSIGNALED(status)) {
+ ret = WTERMSIG(status) + 128;
+ break;
+ }
+ }
+ out:
+ if (func) {
+ signal(SIGALRM, old_func);
+ alarm(oldtime);
+ }
+ return ret;
+}
+
+int ROKEN_LIB_FUNCTION
+wait_for_process(pid_t pid)
+{
+ return wait_for_process_timed(pid, NULL, NULL, 0);
+}
+
+int ROKEN_LIB_FUNCTION
+pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
+ const char *file, ...)
+{
+ int in_fd[2], out_fd[2], err_fd[2];
+ pid_t pid;
+ va_list ap;
+ char **argv;
+
+ if(stdin_fd != NULL)
+ pipe(in_fd);
+ if(stdout_fd != NULL)
+ pipe(out_fd);
+ if(stderr_fd != NULL)
+ pipe(err_fd);
+ pid = fork();
+ switch(pid) {
+ case 0:
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ va_end(ap);
+ if(argv == NULL)
+ exit(-1);
+
+ /* close pipes we're not interested in */
+ if(stdin_fd != NULL)
+ close(in_fd[1]);
+ if(stdout_fd != NULL)
+ close(out_fd[0]);
+ if(stderr_fd != NULL)
+ close(err_fd[0]);
+
+ /* pipe everything caller doesn't care about to /dev/null */
+ if(stdin_fd == NULL)
+ in_fd[0] = open(_PATH_DEVNULL, O_RDONLY);
+ if(stdout_fd == NULL)
+ out_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
+ if(stderr_fd == NULL)
+ err_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
+
+ /* move to proper descriptors */
+ if(in_fd[0] != STDIN_FILENO) {
+ dup2(in_fd[0], STDIN_FILENO);
+ close(in_fd[0]);
+ }
+ if(out_fd[1] != STDOUT_FILENO) {
+ dup2(out_fd[1], STDOUT_FILENO);
+ close(out_fd[1]);
+ }
+ if(err_fd[1] != STDERR_FILENO) {
+ dup2(err_fd[1], STDERR_FILENO);
+ close(err_fd[1]);
+ }
+
+ closefrom(3);
+
+ execv(file, argv);
+ exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
+ case -1:
+ if(stdin_fd != NULL) {
+ close(in_fd[0]);
+ close(in_fd[1]);
+ }
+ if(stdout_fd != NULL) {
+ close(out_fd[0]);
+ close(out_fd[1]);
+ }
+ if(stderr_fd != NULL) {
+ close(err_fd[0]);
+ close(err_fd[1]);
+ }
+ return -2;
+ default:
+ if(stdin_fd != NULL) {
+ close(in_fd[0]);
+ *stdin_fd = fdopen(in_fd[1], "w");
+ }
+ if(stdout_fd != NULL) {
+ close(out_fd[1]);
+ *stdout_fd = fdopen(out_fd[0], "r");
+ }
+ if(stderr_fd != NULL) {
+ close(err_fd[1]);
+ *stderr_fd = fdopen(err_fd[0], "r");
+ }
+ }
+ return pid;
+}
+
+int ROKEN_LIB_FUNCTION
+simple_execvp_timed(const char *file, char *const args[],
+ time_t (*func)(void *), void *ptr, time_t timeout)
+{
+ pid_t pid = fork();
+ switch(pid){
+ case -1:
+ return -2;
+ case 0:
+ execvp(file, args);
+ exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
+ default:
+ return wait_for_process_timed(pid, func, ptr, timeout);
+ }
+}
+
+int ROKEN_LIB_FUNCTION
+simple_execvp(const char *file, char *const args[])
+{
+ return simple_execvp_timed(file, args, NULL, NULL, 0);
+}
+
+/* gee, I'd like a execvpe */
+int ROKEN_LIB_FUNCTION
+simple_execve_timed(const char *file, char *const args[], char *const envp[],
+ time_t (*func)(void *), void *ptr, time_t timeout)
+{
+ pid_t pid = fork();
+ switch(pid){
+ case -1:
+ return -2;
+ case 0:
+ execve(file, args, envp);
+ exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
+ default:
+ return wait_for_process_timed(pid, func, ptr, timeout);
+ }
+}
+
+int ROKEN_LIB_FUNCTION
+simple_execve(const char *file, char *const args[], char *const envp[])
+{
+ return simple_execve_timed(file, args, envp, NULL, NULL, 0);
+}
+
+int ROKEN_LIB_FUNCTION
+simple_execlp(const char *file, ...)
+{
+ va_list ap;
+ char **argv;
+ int ret;
+
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ va_end(ap);
+ if(argv == NULL)
+ return -1;
+ ret = simple_execvp(file, argv);
+ free(argv);
+ return ret;
+}
+
+int ROKEN_LIB_FUNCTION
+simple_execle(const char *file, ... /* ,char *const envp[] */)
+{
+ va_list ap;
+ char **argv;
+ char *const* envp;
+ int ret;
+
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ envp = va_arg(ap, char **);
+ va_end(ap);
+ if(argv == NULL)
+ return -1;
+ ret = simple_execve(file, argv, envp);
+ free(argv);
+ return ret;
+}
+
+int ROKEN_LIB_FUNCTION
+simple_execl(const char *file, ...)
+{
+ va_list ap;
+ char **argv;
+ int ret;
+
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ va_end(ap);
+ if(argv == NULL)
+ return -1;
+ ret = simple_execve(file, argv, environ);
+ free(argv);
+ return ret;
+}
diff --git a/source4/heimdal/lib/roken/strcollect.c b/source4/heimdal/lib/roken/strcollect.c
new file mode 100644
index 00000000000..d6f30773481
--- /dev/null
+++ b/source4/heimdal/lib/roken/strcollect.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: strcollect.c,v 1.2 2005/04/12 11:29:07 lha Exp $");
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <roken.h>
+
+enum { initial = 10, increment = 5 };
+
+static char **
+sub (char **argv, int i, int argc, va_list *ap)
+{
+ do {
+ if(i == argc) {
+ /* realloc argv */
+ char **tmp = realloc(argv, (argc + increment) * sizeof(*argv));
+ if(tmp == NULL) {
+ free(argv);
+ errno = ENOMEM;
+ return NULL;
+ }
+ argv = tmp;
+ argc += increment;
+ }
+ argv[i++] = va_arg(*ap, char*);
+ } while(argv[i - 1] != NULL);
+ return argv;
+}
+
+/*
+ * return a malloced vector of pointers to the strings in `ap'
+ * terminated by NULL.
+ */
+
+char ** ROKEN_LIB_FUNCTION
+vstrcollect(va_list *ap)
+{
+ return sub (NULL, 0, 0, ap);
+}
+
+/*
+ *
+ */
+
+char ** ROKEN_LIB_FUNCTION
+strcollect(char *first, ...)
+{
+ va_list ap;
+ char **ret = malloc (initial * sizeof(char *));
+
+ if (ret == NULL)
+ return ret;
+
+ ret[0] = first;
+ va_start(ap, first);
+ ret = sub (ret, 1, initial, &ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/source4/heimdal/lib/roken/vis.c b/source4/heimdal/lib/roken/vis.c
index a4bde71e9b1..3e54f6d58a6 100644
--- a/source4/heimdal/lib/roken/vis.c
+++ b/source4/heimdal/lib/roken/vis.c
@@ -65,7 +65,7 @@
#if 1
#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id: vis.c,v 1.9 2005/04/12 11:29:15 lha Exp $");
+RCSID("$Id: vis.c,v 1.13 2006/12/15 11:49:22 lha Exp $");
#endif
#include <roken.h>
#ifndef _DIAGASSERT
@@ -108,6 +108,20 @@ __weak_alias(vis,_vis)
#define BELL '\007'
#endif
+char ROKEN_LIB_FUNCTION
+ *rk_vis (char *, int, int, int);
+char ROKEN_LIB_FUNCTION
+ *rk_svis (char *, int, int, int, const char *);
+int ROKEN_LIB_FUNCTION
+ rk_strvis (char *, const char *, int);
+int ROKEN_LIB_FUNCTION
+ rk_strsvis (char *, const char *, int, const char *);
+int ROKEN_LIB_FUNCTION
+ rk_strvisx (char *, const char *, size_t, int);
+int ROKEN_LIB_FUNCTION
+ rk_strsvisx (char *, const char *, size_t, int, const char *);
+
+
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
#define iswhite(c) (c == ' ' || c == '\t' || c == '\n')
#define issafe(c) (c == '\b' || c == BELL || c == '\r')
@@ -208,9 +222,9 @@ do { \
* svis - visually encode characters, also encoding the characters
* pointed to by `extra'
*/
-#ifndef HAVE_SVIS
+
char * ROKEN_LIB_FUNCTION
-svis(char *dst, int c, int flag, int nextc, const char *extra)
+rk_svis(char *dst, int c, int flag, int nextc, const char *extra)
{
_DIAGASSERT(dst != NULL);
_DIAGASSERT(extra != NULL);
@@ -219,7 +233,6 @@ svis(char *dst, int c, int flag, int nextc, const char *extra)
*dst = '\0';
return(dst);
}
-#endif
/*
@@ -237,9 +250,9 @@ svis(char *dst, int c, int flag, int nextc, const char *extra)
* Strsvisx encodes exactly len bytes from src into dst.
* This is useful for encoding a block of data.
*/
-#ifndef HAVE_STRSVIS
+
int ROKEN_LIB_FUNCTION
-strsvis(char *dst, const char *src, int flag, const char *extra)
+rk_strsvis(char *dst, const char *src, int flag, const char *extra)
{
char c;
char *start;
@@ -253,12 +266,10 @@ strsvis(char *dst, const char *src, int flag, const char *extra)
*dst = '\0';
return (dst - start);
}
-#endif
-#ifndef HAVE_STRVISX
int ROKEN_LIB_FUNCTION
-strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra)
+rk_strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra)
{
char c;
char *start;
@@ -274,15 +285,13 @@ strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra)
*dst = '\0';
return (dst - start);
}
-#endif
/*
* vis - visually encode characters
*/
-#ifndef HAVE_VIS
char * ROKEN_LIB_FUNCTION
-vis(char *dst, int c, int flag, int nextc)
+rk_vis(char *dst, int c, int flag, int nextc)
{
char extra[MAXEXTRAS];
@@ -293,7 +302,6 @@ vis(char *dst, int c, int flag, int nextc)
*dst = '\0';
return (dst);
}
-#endif
/*
@@ -306,25 +314,22 @@ vis(char *dst, int c, int flag, int nextc)
* Strvisx encodes exactly len bytes from src into dst.
* This is useful for encoding a block of data.
*/
-#ifndef HAVE_STRVIS
+
int ROKEN_LIB_FUNCTION
-strvis(char *dst, const char *src, int flag)
+rk_strvis(char *dst, const char *src, int flag)
{
char extra[MAXEXTRAS];
MAKEEXTRALIST(flag, extra);
- return (strsvis(dst, src, flag, extra));
+ return (rk_strsvis(dst, src, flag, extra));
}
-#endif
-#ifndef HAVE_STRVISX
int ROKEN_LIB_FUNCTION
-strvisx(char *dst, const char *src, size_t len, int flag)
+rk_strvisx(char *dst, const char *src, size_t len, int flag)
{
char extra[MAXEXTRAS];
MAKEEXTRALIST(flag, extra);
- return (strsvisx(dst, src, len, flag, extra));
+ return (rk_strsvisx(dst, src, len, flag, extra));
}
-#endif
diff --git a/source4/heimdal/lib/roken/vis.hin b/source4/heimdal/lib/roken/vis.hin
index 5b45c943629..b7a6f3ceff1 100644
--- a/source4/heimdal/lib/roken/vis.hin
+++ b/source4/heimdal/lib/roken/vis.hin
@@ -1,5 +1,5 @@
/* $NetBSD: vis.h,v 1.11 1999/11/25 16:55:50 wennmach Exp $ */
-/* $Id: vis.hin,v 1.3 2005/04/12 11:29:15 lha Exp $ */
+/* $Id: vis.hin,v 1.7 2006/12/15 11:53:09 lha Exp $ */
/*-
* Copyright (c) 1990, 1993
@@ -79,20 +79,37 @@
#define UNVIS_END 1 /* no more characters */
char ROKEN_LIB_FUNCTION
- *vis (char *, int, int, int);
+ *rk_vis (char *, int, int, int);
char ROKEN_LIB_FUNCTION
- *svis (char *, int, int, int, const char *);
+ *rk_svis (char *, int, int, int, const char *);
int ROKEN_LIB_FUNCTION
- strvis (char *, const char *, int);
+ rk_strvis (char *, const char *, int);
int ROKEN_LIB_FUNCTION
- strsvis (char *, const char *, int, const char *);
+ rk_strsvis (char *, const char *, int, const char *);
int ROKEN_LIB_FUNCTION
- strvisx (char *, const char *, size_t, int);
+ rk_strvisx (char *, const char *, size_t, int);
int ROKEN_LIB_FUNCTION
- strsvisx (char *, const char *, size_t, int, const char *);
+ rk_strsvisx (char *, const char *, size_t, int, const char *);
int ROKEN_LIB_FUNCTION
- strunvis (char *, const char *);
+ rk_strunvis (char *, const char *);
int ROKEN_LIB_FUNCTION
- unvis (char *, int, int *, int);
+ rk_unvis (char *, int, int *, int);
+
+#undef vis
+#define vis(a,b,c,d) rk_vis(a,b,c,d)
+#undef svis
+#define svis(a,b,c,d,e) rk_svis(a,b,c,d,e)
+#undef strvis
+#define strvis(a,b,c) rk_strvis(a,b,c)
+#undef strsvis
+#define strsvis(a,b,c,d) rk_strsvis(a,b,c,d)
+#undef strvisx
+#define strvisx(a,b,c,d) rk_strvisx(a,b,c,d)
+#undef strsvisx
+#define strsvisx(a,b,c,d,e) rk_strsvisx(a,b,c,d,e)
+#undef strunvis
+#define strunvis(a,b) rk_strunvis(a,b)
+#undef unvis
+#define unvis(a,b,c,d) rk_unvis(a,b,c,d)
#endif /* !_VIS_H_ */
diff --git a/source4/heimdal/lib/vers/print_version.c b/source4/heimdal/lib/vers/print_version.c
index 92c709b4944..5f5a2c4a4a4 100644
--- a/source4/heimdal/lib/vers/print_version.c
+++ b/source4/heimdal/lib/vers/print_version.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998 - 2004 Kungliga Tekniska Högskolan
+ * Copyright (c) 1998 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id: print_version.c,v 1.9 2005/01/01 14:27:47 lha Exp $");
+RCSID("$Id: print_version.c,v 1.10 2006/12/29 16:00:16 lha Exp $");
#endif
#include "roken.h"
@@ -50,6 +50,6 @@ print_version(const char *progname)
if(*package_list == '\0')
package_list = "no version information";
fprintf(stderr, "%s (%s)\n", progname, package_list);
- fprintf(stderr, "Copyright 1999-2005 Kungliga Tekniska Högskolan\n");
+ fprintf(stderr, "Copyright 1995-2007 Kungliga Tekniska Högskolan\n");
fprintf(stderr, "Send bug-reports to %s\n", PACKAGE_BUGREPORT);
}