[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
PKINIT
Hi all,
a pre-beta version of the pkinit implementation for Heimdal is enclosed. You
can have a look at it but remember it's still under development.
Unfortunatelly I'm out of my office until end of this week so I assume I'll
continue in this work (and post a version of the patch) at the end of the
next week.
regards
--
Dan
Index: heimdal/kdc/Makefile.am
diff -u heimdal/kdc/Makefile.am:1.1.1.1 heimdal/kdc/Makefile.am:1.1.1.1.2.1
--- heimdal/kdc/Makefile.am:1.1.1.1 Tue Feb 26 15:42:03 2002
+++ heimdal/kdc/Makefile.am Fri May 10 14:45:00 2002
@@ -33,6 +33,7 @@
log.c \
main.c \
misc.c \
+ pkinit.c \
$(krb4_sources)
Index: heimdal/kdc/Makefile.in
diff -u heimdal/kdc/Makefile.in:1.1.1.1 heimdal/kdc/Makefile.in:1.2.2.1
--- heimdal/kdc/Makefile.in:1.1.1.1 Tue Feb 26 15:42:03 2002
+++ heimdal/kdc/Makefile.in Fri May 10 14:45:00 2002
@@ -224,6 +224,7 @@
log.c \
main.c \
misc.c \
+ pkinit.c \
$(krb4_sources)
@@ -289,11 +290,11 @@
hpropd_LDFLAGS =
@KRB4_FALSE@am_kdc_OBJECTS = config.$(OBJEXT) connect.$(OBJEXT) \
@KRB4_FALSE@kerberos5.$(OBJEXT) log.$(OBJEXT) main.$(OBJEXT) \
-@KRB4_FALSE@misc.$(OBJEXT)
+@KRB4_FALSE@misc.$(OBJEXT) pkinit.$(OBJEXT)
@KRB4_TRUE@am_kdc_OBJECTS = config.$(OBJEXT) connect.$(OBJEXT) \
@KRB4_TRUE@kerberos5.$(OBJEXT) log.$(OBJEXT) main.$(OBJEXT) \
@KRB4_TRUE@misc.$(OBJEXT) 524.$(OBJEXT) kerberos4.$(OBJEXT) \
-@KRB4_TRUE@kaserver.$(OBJEXT)
+@KRB4_TRUE@kaserver.$(OBJEXT) pkinit.$(OBJEXT)
kdc_OBJECTS = $(am_kdc_OBJECTS)
kdc_DEPENDENCIES = $(top_builddir)/lib/hdb/libhdb.la \
$(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/asn1/libasn1.la
Index: heimdal/kdc/config.c
diff -u heimdal/kdc/config.c:1.1.1.1 heimdal/kdc/config.c:1.2.2.5
--- heimdal/kdc/config.c:1.1.1.1 Tue Feb 26 15:42:03 2002
+++ heimdal/kdc/config.c Wed May 15 14:21:55 2002
@@ -68,6 +68,12 @@
static struct getarg_strings addresses_str; /* addresses to listen on */
krb5_addresses explicit_addresses;
+#ifdef PKINIT
+STACK_OF(X509) *pk_certificate = NULL; /* whole certification chain */
+STACK_OF(X509) *pk_trusted_certs = NULL;
+EVP_PKEY *pk_private_key = NULL;
+#endif
+
#ifdef KRB4
char *v4_realm;
int enable_v4 = -1;
@@ -297,6 +425,26 @@
}
}
+#ifdef PKINIT
+ {
+ const char *cert_file = NULL;
+ const char *key_file = NULL;
+ const char *ca_dir = NULL;
+
+ cert_file =
+ krb5_config_get_string(context, cf,
+ "kdc", "pk-certificate", NULL);
+ key_file =
+ krb5_config_get_string(context, cf,
+ "kdc", "pk-private-key", NULL);
+ ca_dir =
+ krb5_config_get_string(context, cf,
+ "kdc", "pk-ca-dir", NULL);
+ pk_load_config(context, cert_file, key_file, ca_dir,
+ &pk_certificate, &pk_private_key, &pk_trusted_certs);
+ }
+#endif
+
#ifdef KRB4
if(enable_v4 == -1)
enable_v4 = krb5_config_get_bool_default(context, cf, TRUE, "kdc",
Index: heimdal/kdc/headers.h
diff -u heimdal/kdc/headers.h:1.1.1.1 heimdal/kdc/headers.h:1.1.1.1.2.1
--- heimdal/kdc/headers.h:1.1.1.1 Tue Feb 26 15:42:03 2002
+++ heimdal/kdc/headers.h Fri May 10 14:45:00 2002
@@ -87,6 +87,10 @@
#include <parse_units.h>
#ifdef HAVE_OPENSSL
#include <openssl/des.h>
+#ifdef PKINIT
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#endif
#else
#include <des.h>
#endif
Index: heimdal/kdc/kdc_locl.h
diff -u heimdal/kdc/kdc_locl.h:1.1.1.1 heimdal/kdc/kdc_locl.h:1.2.2.2
--- heimdal/kdc/kdc_locl.h:1.1.1.1 Tue Feb 26 15:42:03 2002
+++ heimdal/kdc/kdc_locl.h Tue May 14 14:30:59 2002
@@ -70,6 +73,12 @@
extern krb5_boolean enable_kaserver;
#endif
+#ifdef PKINIT
+extern STACK_OF(X509) *pk_certificate;
+extern STACK_OF(X509) *pk_trusted_certs;
+extern EVP_PKEY *pk_private_key;
+#endif
+
#define _PATH_KDC_CONF HDB_DB_DIR "/kdc.conf"
#define DEFAULT_LOG_DEST "0-1/FILE:" HDB_DB_DIR "/kdc.log"
@@ -115,6 +124,22 @@
#ifdef HAVE_OPENSSL
#define des_new_random_key des_random_key
+#endif
+
+#ifdef PKINIT
+krb5_error_code
+pk_mk_pa_reply(krb5_context context,
+ unsigned pk_nonce,
+ krb5_keyblock *reply_key,
+ X509 *user_cert,
+ PA_DATA *pa);
+
+krb5_error_code
+pk_rd_padata(krb5_context context,
+ KDC_REQ *req,
+ PA_DATA *pa,
+ unsigned *pk_nonce,
+ X509 **user_cert);
#endif
#endif /* __KDC_LOCL_H__ */
Index: heimdal/kdc/kerberos5.c
diff -u heimdal/kdc/kerberos5.c:1.1.1.1 heimdal/kdc/kerberos5.c:1.2.2.5
--- heimdal/kdc/kerberos5.c:1.1.1.1 Tue Feb 26 15:42:03 2002
+++ heimdal/kdc/kerberos5.c Wed May 15 14:05:36 2002
@@ -60,6 +60,18 @@
}
}
+#ifdef PKINIT
+static void
+set_pk_padata(METHOD_DATA **m, PA_DATA *pa)
+{
+ ALLOC(*m);
+ (*m)->len = 1;
+ ALLOC((*m)->val);
+ (*m)->val->padata_type = pa->padata_type;
+ copy_octet_string(&pa->padata_value, &(*m)->val->padata_value);
+}
+#endif /* PKINIT */
+
static PA_DATA*
find_padata(KDC_REQ *req, int *start, int type)
{
@@ -443,6 +455,15 @@
const char *e_text = NULL;
krb5_crypto crypto;
Key *ckey, *skey;
+#ifdef PKINIT
+ EncryptionKey reply_key;
+ PA_DATA pk_pa;
+ X509 *user_cert = NULL;
+ unsigned pk_nonce;
+
+ memset(&reply_key, 0, sizeof(reply_key));
+ memset(&pk_pa, 0, sizeof(pk_pa));
+#endif
memset(&rep, 0, sizeof(rep));
@@ -497,13 +518,40 @@
PA_DATA *pa;
int found_pa = 0;
kdc_log(5, "Looking for pa-data -- %s", client_name);
- while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
+#ifdef PKINIT
+ /* XXX write better find_padata() */
+ while((pa = find_padata(req, &i,
+ (pk_certificate == NULL) ? KRB5_PADATA_ENC_TIMESTAMP :
+ KRB5_PADATA_PK_AS_REQ)))
+#else
+ while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP)))
+#endif
+ {
krb5_data ts_data;
PA_ENC_TS_ENC p;
time_t patime;
size_t len;
EncryptedData enc_data;
Key *pa_key;
+#ifdef PKINIT
+ if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
+ found_pa = 1;
+ ret = pk_rd_padata(context, req, pa, &pk_nonce, &user_cert);
+ if (ret) {
+ goto out;
+ }
+ et.flags.pre_authent = 1;
+ kdc_log(2, "PKINIT pre-authentication succeded -- %s", client_name);
+
+ krb5_generate_random_keyblock(context, KEYTYPE_DES3, &reply_key);
+
+ ret = pk_mk_pa_reply(context, pk_nonce, &reply_key, user_cert, &pk_pa);
+ if (ret) {
+ goto out;
+ }
+ } else
+#endif
+ {
found_pa = 1;
@@ -582,6 +630,7 @@
et.flags.pre_authent = 1;
kdc_log(2, "Pre-authentication succeded -- %s", client_name);
break;
+ }
}
if(found_pa == 0 && require_preauth)
goto use_pa;
@@ -849,9 +898,20 @@
copy_HostAddresses(et.caddr, ek.caddr);
}
- set_salt_padata (&rep.padata, ckey->salt);
+#ifdef PKINIT
+ if (reply_key.keytype != 0) /* XXX better check */
+ set_pk_padata(&rep.padata, &pk_pa);
+ else
+ set_salt_padata (&rep.padata, ckey->salt);
+
+ ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
+ client->kvno, /* XXX */
+ (reply_key.keytype == 0) ? &ckey->key : &reply_key,
+ reply);
+#else
ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
client->kvno, &ckey->key, reply);
+#endif
free_EncTicketPart(&et);
free_EncKDCRepPart(&ek);
free_AS_REP(&rep);
@@ -877,6 +937,9 @@
free_ent(client);
if(server)
free_ent(server);
+#ifdef PKINIT
+ /* XXX free reply_key, pk_pa */
+#endif
return ret;
}
Index: heimdal/kdc/pkinit.c
diff -u /dev/null heimdal/kdc/pkinit.c:1.1.2.4
--- /dev/null Wed May 15 15:07:04 2002
+++ heimdal/kdc/pkinit.c Wed May 15 14:05:36 2002
@@ -0,0 +1,223 @@
+#ifdef PKINIT
+#include "kdc_locl.h"
+#include "pkinit_asn1.h"
+
+RCSID("$Id$");
+
+static krb5_error_code
+pk_check_pkauthenticator(krb5_context context,
+ PKAuthenticator *a,
+ KDC_REQ *req,
+ unsigned *pk_nonce)
+{
+ u_char buf[1024];
+ krb5_error_code ret;
+ size_t len;
+
+ memset(buf, 0, sizeof(buf));
+
+ /* XXX check the times */
+ ret = encode_KDC_REQ_BODY(buf + sizeof(buf) - 1, sizeof(buf), &req->req_body,
+ &len);
+ if (ret)
+ goto out;
+
+ ret = krb5_verify_checksum(context,
+ NULL,
+ 0,
+ buf + sizeof(buf) - len,
+ len,
+ &a->pachecksum);
+ if (ret)
+ goto out;
+
+out:
+ return ret;
+}
+
+static krb5_error_code
+pk_encrypt_key(krb5_context context,
+ krb5_keyblock *key,
+ EVP_PKEY *public_key,
+ krb5_data *encrypted_key)
+{
+ krb5_error_code ret;
+ u_char buf[1024];
+ size_t len;
+
+ ret = encode_EncryptionKey(buf + sizeof(buf) - 1, sizeof(buf), key, &len);
+ if (ret)
+ return ret;
+
+ encrypted_key->length = EVP_PKEY_size(public_key);
+ encrypted_key->data = malloc(encrypted_key->length);
+ if (encrypted_key->data == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ ret = EVP_PKEY_encrypt(encrypted_key->data,
+ buf + sizeof(buf) - len,
+ len,
+ public_key);
+ if (ret < 0) {
+ free(encrypted_key->data);
+ ret = -1; /* XXX */
+ }
+
+ return 0;
+}
+
+krb5_error_code
+pk_rd_padata(krb5_context context,
+ KDC_REQ *req,
+ PA_DATA *pa,
+ unsigned *pk_nonce,
+ X509 **user_cert)
+{
+ krb5_error_code ret;
+ size_t len;
+ PA_PK_AS_REQ r;
+ AuthPack a;
+ int i;
+
+ memset(&a, 0, sizeof(a));
+ memset(&r, 0, sizeof(r));
+ if (pa->padata_type != KRB5_PADATA_PK_AS_REQ)
+ return -1; /* XXX */
+
+ ret = decode_PA_PK_AS_REQ(pa->padata_value.data, pa->padata_value.length,
+ &r, &len);
+ if (ret)
+ return ret;
+
+ ret = pk_verify_sign(context, &r.signed_data, pk_trusted_certs, user_cert);
+ if (ret)
+ goto end;
+
+ /* XXX use something like g_OID_equal() */
+ if (strcmp(r.signed_data.econtent_info.type, OID_PKAUTHDATA)) {
+ ret = -1; /* XXX */
+ goto end;
+ }
+ ret = decode_AuthPack(r.signed_data.econtent_info.content.data,
+ r.signed_data.econtent_info.content.length,
+ &a, &len);
+ if (ret)
+ goto end;
+
+ ret = pk_check_pkauthenticator(context, &a.pkAuthenticator, req, pk_nonce);
+ if (ret)
+ goto end;
+
+ if (r.trusted_certifiers != NULL && sk_X509_NAME_num(r.trusted_certifiers) > 0) {
+#if 0
+ X509_NAME *name;
+ X509 *kdc_cert = sk_X509_value(pk_certificate, 0);
+ X509_NAME *kdc_issuer = X509_get_issuer_name(kdc_cert);
+
+ ret = -1; /* ca not found */
+ /* nebude fungovat pro heirarchicke CA */
+ /* also serial_number should be compared */
+ for (i = 0; i < sk_X509_NAME_num(r.trusted_certifiers); i++) {
+ name = sk_X509_NAME_value(r.trusted_certifiers, i);
+ if (X509_NAME_cmp(name, kdc_issuer) == 0) {
+ ret = 0;
+ break;
+ }
+ }
+#else
+ ret = 0;
+#endif
+ if (ret)
+ goto end;
+ }
+
+end:
+ free_PA_PK_AS_REQ(&r);
+ free_AuthPack(&a);
+ return ret;
+}
+
+krb5_error_code
+pk_mk_pa_reply(krb5_context context,
+ unsigned pk_nonce,
+ krb5_keyblock *reply_key,
+ X509 *user_cert,
+ PA_DATA *pa)
+{
+ PA_PK_AS_REP rep;
+ SignedData sd;
+ ReplyKeyPack kp;
+ size_t len;
+ u_char buf[8192];
+ krb5_keyblock tmp_key;
+ krb5_error_code ret;
+ krb5_crypto crypto;
+
+ memset(&sd, 0, sizeof(sd));
+ memset(&kp, 0, sizeof(kp));
+
+ /* Prepare signed Data (containg signed reply key and nonce from request) */
+ copy_EncryptionKey(reply_key, &kp.replyKey);
+ kp.nonce = pk_nonce;
+ encode_ReplyKeyPack(buf + sizeof(buf) - 1, sizeof(buf), &kp, &len);
+ free_ReplyKeyPack(&kp);
+
+ sd.econtent_info.type = strdup(OID_PKRKEYDATA);
+ krb5_data_copy(&sd.econtent_info.content, buf + sizeof(buf) - len , len);
+ ret = pk_create_sign(context, pk_certificate, pk_private_key, &sd);
+ if (ret)
+ goto end;
+
+ /* Create KDC PA reply (containing the SignedData built above)
+ The PA reply is encrypted with a tmp key, which is encrypted with
+ client's public key and stored within the reply.
+ The DH variant is not implemented. */
+
+ ret = krb5_generate_random_keyblock(context, KEYTYPE_DES3, &tmp_key);
+ if (ret)
+ goto end;
+
+ rep.recipient_info.rid.issuer =
+ X509_NAME_dup(X509_get_issuer_name(user_cert));
+ rep.recipient_info.rid.serial =
+ ASN1_INTEGER_dup(X509_get_serialNumber(user_cert));
+ rep.recipient_info.etype = ETYPE_ENCRYPT_RSA_PUB; /* XXX */
+ ret = pk_encrypt_key(context, &tmp_key, X509_get_pubkey(user_cert),
+ &rep.recipient_info.encrypted_key);
+ if (ret)
+ goto end;
+
+ rep.econtent_info.type = strdup(OID_ID_SIGNEDDATA);
+ rep.econtent_info.etype = tmp_key.keytype; /* XXX */
+
+ ret = encode_SignedData(buf + sizeof(buf) - 1, sizeof(buf), &sd, &len);
+ if (ret)
+ goto end;
+
+ ret = krb5_crypto_init(context, &tmp_key, 0, &crypto);
+ if (ret)
+ goto end;
+ ret = krb5_encrypt(context, crypto, 0,
+ buf + sizeof(buf) - len, len,
+ &rep.econtent_info.content);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ goto end;
+
+ ret = encode_PA_PK_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len);
+ if (ret)
+ goto end;
+
+ pa->padata_type = KRB5_PADATA_PK_AS_REP;
+ krb5_data_copy(&pa->padata_value, buf + sizeof(buf) - len, len);
+
+end:
+ memset(&tmp_key, 0, sizeof(tmp_key));
+ free_SignedData(&sd);
+ free_PA_PK_AS_REP(&rep);
+
+ return ret;
+}
+#endif /* PKINIT */
Index: heimdal/kuser/kinit.c
diff -u heimdal/kuser/kinit.c:1.1.1.1 heimdal/kuser/kinit.c:1.2.2.1
--- heimdal/kuser/kinit.c:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/kuser/kinit.c Tue May 14 14:30:59 2002
@@ -57,6 +58,11 @@
int convert_524;
#endif
int fcache_version;
+#ifdef PKINIT
+char *pk_cert_file = NULL;
+char *pk_key_file = NULL;
+char *pk_ca_dir = NULL;
+#endif
static struct getargs args[] = {
#ifdef KRB4
@@ -117,6 +123,17 @@
{ "anonymous", 0, arg_flag, &anonymous_flag,
"request an anonymous ticket" },
+#ifdef PKINIT
+ { "certificate", 'C', arg_string, &pk_cert_file,
+ "principal's public key certificate", "filename"},
+
+ { "private-key", 'K', arg_string, &pk_key_file,
+ "principal's private key", "filename" },
+
+ { "ca-dir", 'D', arg_string, &pk_ca_dir,
+ "directory with CA certificates", "directory" },
+#endif
+
{ "version", 0, arg_flag, &version_flag },
{ "help", 0, arg_flag, &help_flag }
};
@@ -456,6 +475,19 @@
etype_str.num_strings);
}
+#ifdef PKINIT
+ if(pk_cert_file) {
+ ret = krb5_get_init_creds_pkinit(context,
+ &cred,
+ principal,
+ pk_cert_file,
+ pk_key_file,
+ pk_ca_dir,
+ start_time,
+ server,
+ &opt);
+ } else
+#endif
if(use_keytab || keytab_str) {
krb5_keytab kt;
if(keytab_str)
@@ -566,6 +602,13 @@
argc -= optind;
argv += optind;
+
+#ifdef PKINIT
+ if ((pk_cert_file && !pk_key_file) ||
+ (!pk_cert_file && pk_key_file))
+ krb5_err (context, 1, -1,
+ "Both certificate and private key must be given");
+#endif
if (argv[0]) {
ret = krb5_parse_name (context, argv[0], &principal);
Index: heimdal/lib/asn1/Makefile.am
diff -u heimdal/lib/asn1/Makefile.am:1.1.1.1 heimdal/lib/asn1/Makefile.am:1.1.1.1.2.2
--- heimdal/lib/asn1/Makefile.am:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/asn1/Makefile.am Mon May 6 16:51:40 2002
@@ -2,6 +2,8 @@
include $(top_srcdir)/Makefile.am.common
+INCLUDES += $(INCLUDE_des)
+
YFLAGS = -d
lib_LTLIBRARIES = libasn1.la
@@ -65,6 +67,9 @@
asn1_Ticket.x \
asn1_TicketFlags.x \
asn1_TransitedEncoding.x \
+ asn1_PKAuthenticator.x \
+ asn1_AuthPack.x \
+ asn1_ReplyKeyPack.x \
asn1_UNSIGNED.x
@@ -93,6 +98,7 @@
der_length.c \
der_copy.c \
timegm.c \
+ pkinit_asn1.c \
$(BUILT_SOURCES)
asn1_compile_LDADD = \
@@ -107,7 +113,7 @@
CLEANFILES = lex.c parse.c parse.h krb5_asn1.h $(BUILT_SOURCES) \
$(gen_files) asn1_files
-include_HEADERS = krb5_asn1.h asn1_err.h der.h
+include_HEADERS = krb5_asn1.h asn1_err.h der.h pkinit_asn1.h
$(asn1_compile_OBJECTS): parse.h parse.c
Index: heimdal/lib/asn1/Makefile.in
diff -u heimdal/lib/asn1/Makefile.in:1.1.1.1 heimdal/lib/asn1/Makefile.in:1.2.2.2
--- heimdal/lib/asn1/Makefile.in:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/asn1/Makefile.in Mon May 6 16:51:40 2002
@@ -137,7 +137,7 @@
SUFFIXES = .et .h .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8 .x
-INCLUDES = -I$(top_builddir)/include $(INCLUDES_roken)
+INCLUDES = -I$(top_builddir)/include $(INCLUDES_roken) $(INCLUDE_des)
AM_CFLAGS = $(WFLAGS)
@@ -263,6 +263,9 @@
asn1_Ticket.x \
asn1_TicketFlags.x \
asn1_TransitedEncoding.x \
+ asn1_PKAuthenticator.x \
+ asn1_AuthPack.x \
+ asn1_ReplyKeyPack.x \
asn1_UNSIGNED.x
@@ -292,6 +295,7 @@
der_length.c \
der_copy.c \
timegm.c \
+ pkinit_asn1.c \
$(BUILT_SOURCES)
@@ -306,11 +310,11 @@
asn1_print_LDADD = $(check_der_LDADD)
-CLEANFILES = lex.c parse.c parse.h krb5_asn1.h $(BUILT_SOURCES) \
+CLEANFILES = lex.c parse.c parse.h krb5_asn1.h pkinit_asn1.h $(BUILT_SOURCES) \
$(gen_files) asn1_files
-include_HEADERS = krb5_asn1.h asn1_err.h der.h
+include_HEADERS = krb5_asn1.h asn1_err.h der.h pkinit_asn1.h
EXTRA_DIST = asn1_err.et
subdir = lib/asn1
@@ -329,7 +333,7 @@
X_PRE_LIBS = @X_PRE_LIBS@
libasn1_la_DEPENDENCIES =
am_libasn1_la_OBJECTS = der_get.lo der_put.lo der_free.lo der_length.lo \
-der_copy.lo timegm.lo asn1_APOptions.lo asn1_AP_REP.lo asn1_AP_REQ.lo \
+der_copy.lo timegm.lo pkinit_asn1.lo asn1_APOptions.lo asn1_AP_REP.lo asn1_AP_REQ.lo \
asn1_AS_REP.lo asn1_AS_REQ.lo asn1_Authenticator.lo \
asn1_AuthorizationData.lo asn1_CKSUMTYPE.lo asn1_Checksum.lo \
asn1_ENCTYPE.lo asn1_ETYPE_INFO.lo asn1_ETYPE_INFO_ENTRY.lo \
@@ -345,6 +349,7 @@
asn1_PA_DATA.lo asn1_PA_ENC_TS_ENC.lo asn1_Principal.lo \
asn1_PrincipalName.lo asn1_Realm.lo asn1_TGS_REP.lo asn1_TGS_REQ.lo \
asn1_Ticket.lo asn1_TicketFlags.lo asn1_TransitedEncoding.lo \
+asn1_PKAuthenticator.lo asn1_AuthPack.lo asn1_ReplyKeyPack.lo \
asn1_UNSIGNED.lo asn1_err.lo
libasn1_la_OBJECTS = $(am_libasn1_la_OBJECTS)
check_PROGRAMS = check-der$(EXEEXT)
Index: heimdal/lib/asn1/k5.asn1
diff -u heimdal/lib/asn1/k5.asn1:1.1.1.1 heimdal/lib/asn1/k5.asn1:1.1.1.1.2.1
--- heimdal/lib/asn1/k5.asn1:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/asn1/k5.asn1 Tue Apr 30 11:00:53 2002
@@ -443,6 +443,45 @@
DOMAIN-X500-COMPRESS INTEGER ::= 1
+--
+-- PKINIT
+PKAuthenticator ::= SEQUENCE {
+ cusec[0] INTEGER,
+ -- for replay prevention as in RFC 1510bis
+ ctime[1] KerberosTime,
+ -- for replay prevention as in RFC 1510bis
+ nonce[2] INTEGER,
+ -- zero only if client will accept
+ -- cached DH parameters from KDC;
+ -- must be non-zero otherwise
+ pachecksum[3] Checksum
+ -- Checksum over KDC-REQ-BODY
+ -- Defined by Kerberos spec;
+ -- must be unkeyed, e.g. sha1 or rsa-md5
+}
+
+AuthPack ::= SEQUENCE {
+ pkAuthenticator[0] PKAuthenticator
+-- DK: DH is not supported since SubjectPublicKeyInfo is not defined
+-- clientPublicValue[1] SubjectPublicKeyInfo OPTIONAL
+ -- if client is using Diffie-Hellman
+ -- (ephemeral-ephemeral only)
+}
+
+ReplyKeyPack ::= SEQUENCE {
+ -- not used for Diffie-Hellman
+ replyKey[0] EncryptionKey,
+ -- from RFC 1510bis
+ -- used to encrypt main reply
+ -- ENCTYPE is at least as strong as
+ -- ENCTYPE of session key
+ nonce[1] INTEGER
+ -- binds response to the request
+ -- must be same as the nonce
+ -- passed in the PKAuthenticator
+}
+
+
END
-- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1
Index: heimdal/lib/asn1/pkinit_asn1.c
diff -u /dev/null heimdal/lib/asn1/pkinit_asn1.c:1.1.2.6
--- /dev/null Wed May 15 15:07:04 2002
+++ heimdal/lib/asn1/pkinit_asn1.c Wed May 15 14:04:02 2002
@@ -0,0 +1,477 @@
+/* Generated by hand :-) */
+/* Feel free to edit */
+
+#include "libasn1.h"
+#include "pkinit_asn1.h"
+
+#define BACK if (e) return e; p -= l; len -= l; ret += l
+#define FORW if(e) goto fail; p += l; len -= l; ret += l
+
+/* All the i2d_TYPE_bio() functions return 1 on success, 0 otherwise.
+ Unfortunatelly this is different from simple i2d_TYPE() functions, which
+ return number of bytes. */
+
+static int
+i2d_X509_NAME_bio(BIO *bio, X509_NAME *data)
+{
+ return ASN1_i2d_bio(i2d_X509_NAME, bio, (unsigned char *)data);
+}
+
+static int
+i2d_ASN1_INTEGER_bio(BIO *bio, ASN1_INTEGER *data)
+{
+ return ASN1_i2d_bio(i2d_ASN1_INTEGER, bio, (unsigned char *)data);
+}
+
+#if 0
+static X509_NAME *
+d2i_X509_NAME_bio(BIO *bio, X509_NAME **data)
+{
+ return (X509_NAME *) ASN1_d2i_bio((char *(*)()) X509_NAME_new,
+ (char *(*)()) d2i_X509_NAME,
+ bio,
+ (unsigned char **) data);
+}
+
+static ASN1_INTEGER *
+d2i_ASN1_INTEGER_bio(BIO *bio, ASN1_INTEGER **data)
+{
+ return (ASN1_INTEGER *) ASN1_d2i_bio((char *(*)()) ASN1_INTEGER_new,
+ (char *(*)()) d2i_ASN1_INTEGER,
+ bio,
+ (unsigned char **) data);
+}
+#endif
+
+
+static int
+bio_to_buffer(BIO *bio, unsigned char *p, size_t len, size_t *size)
+{
+ size_t bio_len;
+ int e;
+
+ bio_len = BIO_pending(bio);
+ if (bio_len > len)
+ return ASN1_OVERFLOW; /* XXX */
+
+ e = BIO_read(bio, p - bio_len + 1, bio_len);
+ if (e == 0)
+ return -1; /* XXX */
+
+ *size = bio_len;
+ return 0;
+}
+
+#if 0
+static int
+buffer_to_bio(const unsigned char *p, size_t len, BIO **bio)
+{
+ BIO *ret_bio = NULL;
+ int e;
+
+ ret_bio = BIO_new(BIO_s_mem());
+ if (ret_bio == NULL)
+ return -1; /* XXX */
+
+ e = BIO_write(ret_bio, (unsigned char *) p, len);
+ if (e == 0) {
+ BIO_free(ret_bio);
+ return -1; /* XXX */
+ }
+
+ *bio = ret_bio;
+ return 0;
+}
+#endif
+
+/*
+ * IssuerAndSerialNumber
+ */
+int
+encode_IssuerAndSerialNumber(unsigned char *p, size_t len, const IssuerAndSerialNumber *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+ BIO *bio = NULL;
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ return -1; /* XXX */
+
+ e = i2d_X509_NAME_bio(bio, data->issuer);
+ if (e != 1) {
+ BIO_free(bio);
+ return -1; /* XXX */
+ }
+
+ e = i2d_ASN1_INTEGER_bio(bio, data->serial);
+ if (e != 1) {
+ BIO_free(bio);
+ return -1; /* XXX */
+ }
+
+ e = bio_to_buffer(bio, p, len, &l);
+ BACK;
+
+ *size = ret;
+ return 0;
+}
+
+int
+decode_IssuerAndSerialNumber(const unsigned char *p, size_t len, IssuerAndSerialNumber *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+
+ memset(data, 0, sizeof(*data));
+ {
+ unsigned char *begin;
+
+ begin = (unsigned char *)p;
+ data->issuer = d2i_X509_NAME(NULL, (unsigned char **)&p, len);
+ if (data->issuer == NULL) {
+ e = -1; /* XXX */
+ goto fail;
+ }
+ l = p - begin;
+ len -= l;
+ ret += l;
+
+ begin = (unsigned char *)p;
+ data->serial = d2i_ASN1_INTEGER(NULL, (unsigned char **)&p, len);
+ if (data->issuer == NULL) {
+ e = -1; /* XXX */
+ goto fail;
+ }
+ l = p - begin;
+ len -= l;
+ ret += l;
+ }
+
+ if (size) *size = ret;
+ return 0;
+
+fail:
+ free_IssuerAndSerialNumber(data);
+ return e;
+}
+
+void
+free_IssuerAndSerialNumber(IssuerAndSerialNumber *data)
+{
+ if (data->issuer)
+ X509_NAME_free(data->issuer);
+ if (data->serial)
+ ASN1_INTEGER_free(data->serial);
+}
+
+/*
+ * SignedData
+ */
+int
+encode_SignedData(unsigned char *p, size_t len, const SignedData *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+
+ e = encode_general_string(p, len, &data->econtent_info.type, &l);
+ BACK;
+ e = encode_octet_string(p, len, &data->econtent_info.content, &l);
+ BACK;
+
+ {
+ unsigned num;
+ int i;
+ BIO *bio = NULL;
+
+ num = sk_X509_num(data->chain);
+ if (num < 0)
+ return -1; /* XXX */
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ return -1; /* XXX */
+
+ for (i = 0; i < num; i++) {
+ e = i2d_X509_bio(bio, sk_X509_value(data->chain, i));
+ if (e != 1) {
+ BIO_free(bio);
+ return -1;
+ }
+ }
+ e = bio_to_buffer(bio, p, len, &l);
+ BIO_free(bio);
+ BACK;
+
+ e = encode_unsigned(p, len, &num, &l);
+ BACK;
+ }
+
+ e = encode_IssuerAndSerialNumber(p, len, &data->signer_info.sid, &l);
+ BACK;
+ e = encode_CKSUMTYPE(p, len, &data->signer_info.digest_type, &l);
+ BACK;
+ e = encode_ENCTYPE(p, len, &data->signer_info.signature_type, &l);
+ BACK;
+ e = encode_octet_string(p, len, &data->econtent_info.content, &l);
+ BACK;
+
+ *size = ret;
+ return 0;
+}
+
+int
+decode_SignedData(const unsigned char *p, size_t len, SignedData *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+
+ memset(data, 0, sizeof(*data));
+
+ e = decode_octet_string(p, len, &data->econtent_info.content, &l);
+ FORW;
+ e = decode_ENCTYPE(p, len, &data->signer_info.signature_type, &l);
+ FORW;
+ e = decode_CKSUMTYPE(p, len, &data->signer_info.digest_type, &l);
+ FORW;
+ e = decode_IssuerAndSerialNumber(p, len, &data->signer_info.sid, &l);
+ FORW;
+
+ {
+ unsigned num;
+ X509 *cert;
+ int i;
+ unsigned char *begin;
+
+ e = decode_unsigned(p, len, &num, &l);
+ FORW;
+
+ data->chain = sk_X509_new_null();
+ for (i = 0; i < num; i++) {
+ begin = (unsigned char *)p;
+ cert = d2i_X509(NULL, (unsigned char **)&p, len);
+ if (cert == NULL) {
+ e = -1; /* XXX */
+ goto fail;
+ }
+ sk_X509_push(data->chain, cert);
+ l = p - begin;
+ len -= l;
+ ret += l;
+ }
+
+ }
+
+ e = decode_octet_string(p, len, &data->econtent_info.content, &l);
+ FORW;
+ e = decode_general_string(p, len, &data->econtent_info.type, &l);
+ FORW;
+
+ if (size) *size = ret;
+ return 0;
+
+fail:
+ free_SignedData(data);
+ return e;
+}
+
+void
+free_SignedData(SignedData *data)
+{
+ if (data->econtent_info.type)
+ free_general_string(&data->econtent_info.type);
+ if (data->econtent_info.content.length)
+ free_octet_string(&data->econtent_info.content);
+
+ if (data->chain)
+ sk_X509_pop_free(data->chain, X509_free);
+
+ free_IssuerAndSerialNumber(&data->signer_info.sid);
+ free_CKSUMTYPE(&data->signer_info.digest_type);
+ free_ENCTYPE(&data->signer_info.signature_type);
+ if (data->signer_info.signature.length)
+ free_octet_string(&data->signer_info.signature);
+}
+
+/*
+ * PA_PK_AS_REQ
+ */
+int
+encode_PA_PK_AS_REQ(unsigned char *p, size_t len, const PA_PK_AS_REQ *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+
+ e = encode_SignedData(p, len, &data->signed_data, &l);
+ BACK;
+
+ {
+ unsigned num;
+ int i;
+ BIO *bio = NULL;
+
+ num = sk_X509_NAME_num(data->trusted_certifiers);
+ if (num < 0)
+ return -1; /* XXX */
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ return -1; /* XXX */
+
+ for (i = 0; i < num; i++) {
+ /* pozor na ssleay.doc:650 ! */
+ e = i2d_X509_NAME_bio(bio, sk_X509_NAME_value(data->trusted_certifiers, i));
+ if (e != 1) {
+ BIO_free(bio);
+ return -1;
+ }
+ }
+ e = bio_to_buffer(bio, p, len, &l);
+ BIO_free(bio);
+ BACK;
+
+ e = encode_unsigned(p, len, &num, &l);
+ BACK;
+ }
+
+ *size = ret;
+ return 0;
+}
+
+int
+decode_PA_PK_AS_REQ(const unsigned char *p, size_t len, PA_PK_AS_REQ *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+
+ memset(data, 0, sizeof(*data));
+ {
+ unsigned certs_num;
+ X509_NAME *name = NULL;
+ unsigned char *begin;
+ int i;
+
+ e = decode_unsigned(p, len, &certs_num, &l);
+ FORW;
+
+ if (certs_num > 0) {
+ data->trusted_certifiers = sk_X509_NAME_new_null();
+ for (i = 0; i < certs_num; i++) {
+ begin = (unsigned char *)p;
+ name = d2i_X509_NAME(NULL, (unsigned char **)&p, len);
+ if (name == NULL) {
+ e = -1; /* XXX */
+ goto fail;
+ }
+ sk_X509_NAME_push(data->trusted_certifiers, name);
+ l = p - begin;
+ len -= l;
+ ret += l;
+ }
+ }
+ }
+
+ e = decode_SignedData(p, len, &data->signed_data, &l);
+ FORW;
+
+ if (size) *size = ret;
+ return 0;
+
+fail:
+ free_PA_PK_AS_REQ(data);
+ return e;
+}
+
+void
+free_PA_PK_AS_REQ(PA_PK_AS_REQ *data)
+{
+ free_SignedData(&data->signed_data);
+ if (data->trusted_certifiers)
+ sk_X509_NAME_pop_free(data->trusted_certifiers, X509_NAME_free);
+}
+
+
+/*
+ * PA_PK_AS_REP
+ */
+int
+encode_PA_PK_AS_REP(unsigned char *p, size_t len, const PA_PK_AS_REP *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+
+ /* recipient_info */
+ e = encode_IssuerAndSerialNumber(p, len, &data->recipient_info.rid, &l);
+ BACK;
+ e = encode_ENCTYPE(p, len, &data->recipient_info.etype, &l);
+ BACK;
+ e = encode_octet_string(p, len, &data->recipient_info.encrypted_key, &l);
+ BACK;
+
+ /* econtent_info */
+ e = encode_general_string(p, len, &data->econtent_info.type, &l);
+ BACK;
+ e = encode_ENCTYPE(p, len, &data->econtent_info.etype, &l);
+ BACK;
+ e = encode_octet_string(p, len, &data->econtent_info.content, &l);
+ BACK;
+
+ *size = ret;
+ return 0;
+}
+
+
+int
+decode_PA_PK_AS_REP(const unsigned char *p, size_t len, PA_PK_AS_REP *data, size_t *size)
+{
+ size_t ret = 0;
+ size_t l;
+ int e;
+
+ memset(data, 0, sizeof(*data));
+
+ /* econtent_info */
+ e = decode_octet_string(p, len, &data->econtent_info.content, &l);
+ FORW;
+ e = decode_ENCTYPE(p, len, &data->econtent_info.etype, &l);
+ FORW;
+ e = decode_general_string(p, len, &data->econtent_info.type, &l);
+ FORW;
+
+ /* recipient_info */
+ e = decode_octet_string(p, len, &data->recipient_info.encrypted_key, &l);
+ FORW;
+ e = decode_ENCTYPE(p, len, &data->recipient_info.etype, &l);
+ FORW;
+ e = decode_IssuerAndSerialNumber(p, len, &data->recipient_info.rid, &l);
+ FORW;
+
+ if (size) *size = ret;
+ return 0;
+
+fail:
+ free_PA_PK_AS_REP(data);
+ return e;
+}
+
+void
+free_PA_PK_AS_REP(PA_PK_AS_REP *data)
+{
+ free_IssuerAndSerialNumber(&data->recipient_info.rid);
+ free_ENCTYPE(&data->recipient_info.etype);
+ if (data->recipient_info.encrypted_key.length)
+ free_octet_string(&data->recipient_info.encrypted_key);
+
+ if (data->econtent_info.type)
+ free_general_string(&data->econtent_info.type);
+ free_ENCTYPE(&data->econtent_info.etype);
+ if (data->econtent_info.content.length)
+ free_octet_string(&data->econtent_info.content);
+}
Index: heimdal/lib/asn1/pkinit_asn1.h
diff -u /dev/null heimdal/lib/asn1/pkinit_asn1.h:1.1.2.4
--- /dev/null Wed May 15 15:07:04 2002
+++ heimdal/lib/asn1/pkinit_asn1.h Fri May 10 14:45:00 2002
@@ -0,0 +1,89 @@
+#ifndef __PKINIT_ASN1_H__
+#define __PKINIT_ASN1_H__
+
+#ifdef PKINIT
+#include "krb5_asn1.h"
+#include <openssl/x509.h>
+#include <openssl/bio.h>
+
+#include <openssl/pem.h>
+#include <openssl/err.h>
+/* XXX ^^^ snad jen docasne */
+
+/* For encoding OIDs see rfc2743 section 3.1, item 5. */
+
+/* pkauthdata (in client's as-req):
+ iso (1) org (3) dod (6) internet (1)
+ security (5) kerberosv5 (2) pkinit (3) pkauthdata (1) */
+#define OID_PKAUTHDATA "\x2b\x06\x01\x05\x02\x03\x01"
+
+/* id-signedData (in KDC's reply):
+ iso (1) member-body (2) us (840)
+ rsadsi (113549) pkcs (1) pkcs7 (7) signedData (2) */
+#define OID_ID_SIGNEDDATA "\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02"
+
+/* pkrkeydata (in KDC's reply):
+ iso (1) org (3) dod (6) internet (1)
+ security (5) kerberosv5 (2) pkinit (3) pkrkeydata (3) */
+#define OID_PKRKEYDATA "\x2b\x06\x01\x05\x02\x03\x03"
+
+typedef struct IssuerAndSerialNumber{
+ X509_NAME *issuer;
+ ASN1_INTEGER *serial;
+} IssuerAndSerialNumber;
+
+int encode_IssuerAndSerialNumber(unsigned char *, size_t, const IssuerAndSerialNumber *, size_t *);
+int decode_IssuerAndSerialNumber(const unsigned char *, size_t, IssuerAndSerialNumber *, size_t *);
+void free_IssuerAndSerialNumber(IssuerAndSerialNumber *);
+
+typedef struct SignedData {
+ struct {
+ general_string type;
+ octet_string content;
+ } econtent_info;
+ STACK_OF(X509) *chain;
+ struct {
+ IssuerAndSerialNumber sid; /* SignerIdentifier */
+ CKSUMTYPE digest_type;
+ ENCTYPE signature_type; /* XXX ? X509_ALGOR */
+ octet_string signature;
+ } signer_info;
+} SignedData;
+
+int encode_SignedData(unsigned char *, size_t, const SignedData *, size_t *);
+int decode_SignedData(const unsigned char *, size_t, SignedData *, size_t *);
+void free_SignedData(SignedData *);
+
+typedef struct PA_PK_AS_REQ {
+ SignedData signed_data;
+ STACK_OF(X509_NAME) *trusted_certifiers;
+} PA_PK_AS_REQ;
+
+int encode_PA_PK_AS_REQ(unsigned char *, size_t, const PA_PK_AS_REQ *, size_t *);
+int decode_PA_PK_AS_REQ(const unsigned char *, size_t, PA_PK_AS_REQ *, size_t *);
+void free_PA_PK_AS_REQ(PA_PK_AS_REQ *);
+
+typedef struct EnvelopedData {
+ struct {
+ IssuerAndSerialNumber rid;
+ ENCTYPE etype; /* XXX ? X509_ALGOR */
+ octet_string encrypted_key;
+ } recipient_info;
+ struct {
+ general_string type;
+ ENCTYPE etype; /* XXX ? X509_ALGOR */
+ octet_string content;
+ } econtent_info;
+} EnvelopedData;
+
+typedef EnvelopedData PA_PK_AS_REP;
+
+int encode_PA_PK_AS_REP(unsigned char *, size_t, const PA_PK_AS_REP *, size_t *);
+int decode_PA_PK_AS_REP(const unsigned char *, size_t, PA_PK_AS_REP *, size_t *);
+void free_PA_PK_AS_REP(PA_PK_AS_REP *);
+
+
+
+#endif /* PKINIT */
+
+#endif /* __PKINIT_ASN1_H__ */
Index: heimdal/lib/krb5/Makefile.am
diff -u heimdal/lib/krb5/Makefile.am:1.1.1.1 heimdal/lib/krb5/Makefile.am:1.1.1.1.2.1
--- heimdal/lib/krb5/Makefile.am:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/krb5/Makefile.am Sun May 5 19:43:04 2002
@@ -120,6 +120,7 @@
version.c \
warn.c \
write_message.c \
+ pkinit.c \
$(ERR_FILES)
libkrb5_la_LDFLAGS = -version-info 18:2:1
Index: heimdal/lib/krb5/Makefile.in
diff -u heimdal/lib/krb5/Makefile.in:1.1.1.1 heimdal/lib/krb5/Makefile.in:1.2.2.1
--- heimdal/lib/krb5/Makefile.in:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/krb5/Makefile.in Sun May 5 19:43:04 2002
@@ -317,6 +317,7 @@
version.c \
warn.c \
write_message.c \
+ pkinit.c \
$(ERR_FILES)
@@ -391,7 +392,7 @@
read_message.lo recvauth.lo replay.lo send_to_kdc.lo sendauth.lo \
set_default_realm.lo sock_principal.lo store.lo store_emem.lo \
store_fd.lo store_mem.lo ticket.lo time.lo transited.lo verify_init.lo \
-verify_user.lo version.lo warn.lo write_message.lo krb5_err.lo \
+verify_user.lo version.lo warn.lo write_message.lo pkinit.lo krb5_err.lo \
heim_err.lo k524_err.lo
libkrb5_la_OBJECTS = $(am_libkrb5_la_OBJECTS)
bin_PROGRAMS = verify_krb5_conf$(EXEEXT)
Index: heimdal/lib/krb5/get_in_tkt.c
diff -u heimdal/lib/krb5/get_in_tkt.c:1.1.1.1 heimdal/lib/krb5/get_in_tkt.c:1.1.1.1.2.5
--- heimdal/lib/krb5/get_in_tkt.c:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/krb5/get_in_tkt.c Wed May 15 14:08:33 2002
@@ -427,6 +427,12 @@
krb5_key_proc key_proc,
krb5_const_pointer keyseed,
unsigned nonce,
+#ifdef PKINIT
+ STACK_OF(X509) *cert,
+ EVP_PKEY *private_key,
+ STACK_OF(X509) *trusted_certs,
+ unsigned pk_nonce,
+#endif
AS_REQ *a)
{
krb5_error_code ret;
@@ -585,7 +591,27 @@
add_padata(context, a->padata, creds->client,
key_proc, keyseed, a->req_body.etype.val,
a->req_body.etype.len, &salt);
- } else {
+ }
+#ifdef PKINIT
+ else if (*ptypes == KRB5_PADATA_PK_AS_REQ) {
+ ALLOC(a->padata, 1);
+ if (a->padata == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ a->padata->len = 0;
+ a->padata->val = NULL;
+ ret = pk_mk_padata(context,
+ cert, private_key, trusted_certs,
+ &a->req_body,
+ pk_nonce,
+ a->padata);
+ if (ret)
+ goto fail;
+ }
+#endif /* PKINIT */
+ else {
krb5_set_error_string (context, "pre-auth type %d not supported",
*ptypes);
ret = KRB5_PREAUTH_BAD_TYPE;
@@ -640,18 +666,23 @@
}
krb5_error_code
-krb5_get_in_cred(krb5_context context,
- krb5_flags options,
- const krb5_addresses *addrs,
- const krb5_enctype *etypes,
- const krb5_preauthtype *ptypes,
- const krb5_preauthdata *preauth,
- krb5_key_proc key_proc,
- krb5_const_pointer keyseed,
- krb5_decrypt_proc decrypt_proc,
- krb5_const_pointer decryptarg,
- krb5_creds *creds,
- krb5_kdc_rep *ret_as_reply)
+krb5_get_in_cred_ext(krb5_context context,
+ krb5_flags options,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ const krb5_preauthtype *ptypes,
+ const krb5_preauthdata *preauth,
+ krb5_key_proc key_proc,
+ krb5_const_pointer keyseed,
+ krb5_decrypt_proc decrypt_proc,
+ krb5_const_pointer decryptarg,
+#ifdef PKINIT
+ void *p_cert, /* STACK_OF(X509) */
+ void *p_private_key, /* EVP_PKEY */
+ void *p_trusted_certs, /* STACK_OF(X509) */
+#endif
+ krb5_creds *creds,
+ krb5_kdc_rep *ret_as_reply)
{
krb5_error_code ret;
AS_REQ a;
@@ -666,12 +697,21 @@
krb5_enctype etype;
krb5_preauthdata *my_preauth = NULL;
unsigned nonce;
+#ifdef PKINIT
+ unsigned pk_nonce;
+ X509 *user_cert;
+ STACK_OF(X509) *cert = (STACK_OF(X509) *) p_cert;
+ EVP_PKEY *private_key = (EVP_PKEY *) p_private_key;
+ STACK_OF(X509) *trusted_certs = (STACK_OF(X509) *) p_trusted_certs;
+#endif
int done;
opts.i = options;
krb5_generate_random_block (&nonce, sizeof(nonce));
nonce &= 0xffffffff;
+ krb5_generate_random_block (&pk_nonce, sizeof(pk_nonce));
+ pk_nonce &= 0xffffffff;
do {
done = 1;
@@ -685,6 +725,12 @@
key_proc,
keyseed,
nonce,
+#ifdef PKINIT
+ cert,
+ private_key,
+ trusted_certs,
+ pk_nonce,
+#endif
&a);
if (my_preauth) {
free_ETYPE_INFO(&my_preauth->val[0].info);
@@ -757,12 +803,34 @@
rep.kdc_rep.padata->len,
KRB5_PADATA_AFS3_SALT, &index);
}
+#ifdef PKINIT
+ if (pa == NULL && *ptypes == KRB5_PADATA_PK_AS_REQ) {
+ index = 0;
+ pa = krb5_find_padata(rep.kdc_rep.padata->val,
+ rep.kdc_rep.padata->len,
+ KRB5_PADATA_PK_AS_REP, &index);
+ }
+#endif
}
if(pa) {
- salt.salttype = pa->padata_type;
- salt.saltvalue = pa->padata_value;
+#ifdef PKINIT
+ if (pa->padata_type == KRB5_PADATA_PK_AS_REP) {
+ user_cert = sk_X509_value(cert, 0);
+ ret = pk_rd_pa_reply(context,
+ user_cert,
+ private_key,
+ trusted_certs,
+ pk_nonce,
+ pa,
+ &key);
+ } else
+#endif
+ {
+ salt.salttype = pa->padata_type;
+ salt.saltvalue = pa->padata_value;
- ret = (*key_proc)(context, etype, salt, keyseed, &key);
+ ret = (*key_proc)(context, etype, salt, keyseed, &key);
+ }
} else {
/* make a v5 salted pa-data */
ret = krb5_get_pw_salt (context, creds->client, &salt);
@@ -798,6 +866,40 @@
krb5_free_kdc_rep (context, &rep);
return ret;
}
+
+krb5_error_code
+krb5_get_in_cred(krb5_context context,
+ krb5_flags options,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ const krb5_preauthtype *ptypes,
+ const krb5_preauthdata *preauth,
+ krb5_key_proc key_proc,
+ krb5_const_pointer keyseed,
+ krb5_decrypt_proc decrypt_proc,
+ krb5_const_pointer decryptarg,
+ krb5_creds *creds,
+ krb5_kdc_rep *ret_as_reply)
+{
+ return krb5_get_in_cred_ext(context,
+ options,
+ addrs,
+ etypes,
+ ptypes,
+ preauth,
+ key_proc,
+ keyseed,
+ decrypt_proc,
+ decryptarg,
+#ifdef PKINIT
+ NULL,
+ NULL,
+ NULL,
+#endif
+ creds,
+ ret_as_reply);
+}
+
krb5_error_code
krb5_get_in_tkt(krb5_context context,
Index: heimdal/lib/krb5/init_creds_pw.c
diff -u heimdal/lib/krb5/init_creds_pw.c:1.1.1.1 heimdal/lib/krb5/init_creds_pw.c:1.1.1.1.2.2
--- heimdal/lib/krb5/init_creds_pw.c:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/krb5/init_creds_pw.c Wed May 15 14:08:33 2002
@@ -542,3 +542,80 @@
krb5_free_creds_contents (context, &this_cred);
return ret;
}
+
+#ifdef PKINIT
+krb5_error_code
+krb5_get_init_creds_pkinit(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ char *pk_cert_file,
+ char *pk_key_file,
+ char *pk_ca_dir,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
+{
+ krb5_error_code ret;
+ krb5_kdc_flags flags;
+ krb5_addresses *addrs = NULL;
+ krb5_enctype *etypes = NULL;
+ krb5_preauthtype *pre_auth_types = NULL;
+ krb5_preauthtype pk_pre_auth_types[2] = {KRB5_PADATA_PK_AS_REQ, KRB5_PADATA_NONE};
+ krb5_creds this_cred;
+ krb5_keytab_key_proc_args *a;
+ STACK_OF(X509) *user_cert = NULL;
+ EVP_PKEY *user_key = NULL;
+ STACK_OF(X509) *trusted_certs = NULL;
+
+ ret = get_init_creds_common(context, creds, client, start_time,
+ in_tkt_service, options,
+ &addrs, &etypes, &this_cred, &pre_auth_types,
+ &flags);
+ if(ret)
+ goto out;
+
+ a = malloc (sizeof(*a));
+ if (a == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ a->principal = this_cred.client;
+
+ ret = pk_load_config(context, pk_cert_file, pk_key_file, pk_ca_dir,
+ &user_cert, &user_key, &trusted_certs);
+ if (ret)
+ goto out;
+
+ ret = krb5_get_in_cred_ext (context,
+ flags.i,
+ addrs,
+ etypes,
+ pk_pre_auth_types,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ user_cert,
+ user_key,
+ trusted_certs,
+ &this_cred,
+ NULL);
+ if (ret)
+ goto out;
+ free (pre_auth_types);
+ free (etypes);
+ if (creds)
+ *creds = this_cred;
+ else
+ krb5_free_creds_contents (context, &this_cred);
+ return 0;
+
+out:
+ free (pre_auth_types);
+ free (etypes);
+ krb5_free_creds_contents (context, &this_cred);
+ return ret;
+}
+#endif /* PKINIT */
Index: heimdal/lib/krb5/krb5-protos.h
diff -u heimdal/lib/krb5/krb5-protos.h:1.1.1.1 heimdal/lib/krb5/krb5-protos.h:1.1.1.1.2.3
--- heimdal/lib/krb5/krb5-protos.h:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/krb5/krb5-protos.h Wed May 15 14:08:33 2002
@@ -1380,6 +1380,24 @@
krb5_kdc_rep *ret_as_reply));
krb5_error_code
+krb5_get_in_cred_ext __P((
+ krb5_context context,
+ krb5_flags options,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ const krb5_preauthtype *ptypes,
+ const krb5_preauthdata *preauth,
+ krb5_key_proc key_proc,
+ krb5_const_pointer keyseed,
+ krb5_decrypt_proc decrypt_proc,
+ krb5_const_pointer decryptarg,
+ void *p_cert,
+ void *p_private_key,
+ void *p_trusted_certs,
+ krb5_creds *creds,
+ krb5_kdc_rep *ret_as_reply));
+
+krb5_error_code
krb5_get_in_tkt __P((
krb5_context context,
krb5_flags options,
@@ -2842,6 +2860,26 @@
krb5_error_code
krb5_xfree __P((void *ptr));
+
+krb5_error_code
+pk_mk_padata __P((
+ krb5_context context,
+ void *p_chain,
+ void *p_private_key,
+ void *p_trusted_certs,
+ KDC_REQ_BODY *req_body,
+ unsigned nonce,
+ METHOD_DATA *md));
+
+krb5_error_code
+pk_rd_pa_reply __P((
+ krb5_context context,
+ void *p_cert,
+ void *p_priv_key,
+ void *p_trusted_certs,
+ unsigned nonce,
+ PA_DATA *pa,
+ krb5_keyblock **key));
krb5_error_code
principalname2krb5_principal __P((
Index: heimdal/lib/krb5/krb5_locl.h
diff -u heimdal/lib/krb5/krb5_locl.h:1.1.1.1 heimdal/lib/krb5/krb5_locl.h:1.1.1.1.2.1
--- heimdal/lib/krb5/krb5_locl.h:1.1.1.1 Tue Feb 26 15:42:04 2002
+++ heimdal/lib/krb5/krb5_locl.h Mon May 6 16:00:49 2002
@@ -115,6 +115,12 @@
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/rc4.h>
+#ifdef PKINIT
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/evp.h>
+#endif
#else
#include <des.h>
#include <md4.h>
Index: heimdal/lib/krb5/pkinit.c
diff -u /dev/null heimdal/lib/krb5/pkinit.c:1.1.2.6
--- /dev/null Wed May 15 15:07:04 2002
+++ heimdal/lib/krb5/pkinit.c Wed May 15 14:08:33 2002
@@ -0,0 +1,548 @@
+#include "krb5_locl.h"
+
+RCSID("$Id$");
+
+#ifdef PKINIT
+#include "pkinit_asn1.h"
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+static krb5_error_code
+build_auth_pack(krb5_context context,
+ unsigned nonce,
+ KDC_REQ_BODY *body,
+ AuthPack *a)
+{
+ u_char buf[1024];
+ size_t len;
+ krb5_error_code ret;
+ int32_t sec, usec;
+
+ memset(a, 0, sizeof(*a));
+
+ /* fill in PKAuthenticator */
+ krb5_us_timeofday (context, &sec, &usec);
+ a->pkAuthenticator.cusec = usec;
+ a->pkAuthenticator.ctime = sec;
+
+ a->pkAuthenticator.nonce = nonce;
+
+ ret = encode_KDC_REQ_BODY(buf + sizeof(buf) - 1, sizeof(buf), body, &len);
+ if (ret)
+ return ret;
+
+ ret = krb5_create_checksum(context,
+ NULL,
+ 0,
+ CKSUMTYPE_SHA1, /* default type from context ?? */
+ buf + sizeof(buf) - len,
+ len,
+ &a->pkAuthenticator.pachecksum);
+ return ret;
+}
+
+krb5_error_code
+pk_load_config(krb5_context context,
+ char *cert_file,
+ char *key_file,
+ char *ca_dir,
+ STACK_OF(X509) **user_cert,
+ EVP_PKEY **user_key,
+ STACK_OF(X509) **trusted_certs)
+{
+ X509 *cert = NULL;
+ FILE *fp = NULL;
+ DIR *dir = NULL;
+ char dirname[MAXPATHLEN];
+ char filename[MAXPATHLEN];
+ struct dirent *file;
+ STACK_OF(X509) *tmp_certificate = NULL;
+ EVP_PKEY *tmp_key = NULL;
+ STACK_OF(X509) *tmp_certs = NULL;
+ krb5_error_code ret;
+
+ fp = fopen(cert_file, "r");
+ if (fp == NULL) {
+ /* krb5_set_error_string() ??? */
+ return -1; /* XXX */
+ }
+ tmp_certificate = sk_X509_new_null();
+ while (1) {
+ /* see http://www.openssl.org/docs/crypto/pem.html section BUGS */
+ cert = PEM_read_X509(fp, NULL, NULL, NULL);
+ if (cert == NULL) {
+ if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) {
+ /* End of file reached. no error */
+ ERR_clear_error();
+ break;
+ }
+ ret = -1; /* XXX */
+ goto fail;
+ }
+ sk_X509_push(tmp_certificate, cert);
+ }
+ fclose(fp);
+ fp = NULL;
+
+ fp = fopen(key_file, "r");
+ if (fp == NULL) {
+ }
+ tmp_key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
+ if (tmp_key == NULL) {
+ /* XXX Pozor, pokud je klic zasifrovany vyvola se interni callback,
+ ktery ceka na zadani hesla */
+ ret = -1; /* XXX */
+ goto fail;
+ }
+ fclose(fp);
+ fp = NULL;
+
+ dir = opendir(ca_dir);
+ if (dir == NULL) {
+ ret = -1; /* XXX */
+ goto fail;
+ }
+ memset(dirname, 0, sizeof(dirname));
+ strncpy(dirname, ca_dir, sizeof(dirname) - 1);
+ if (dirname[strlen(dirname) - 1] != '/')
+ dirname[strlen(dirname)] = '/';
+
+ tmp_certs = sk_X509_new_null();
+ while ((file = readdir(dir))) {
+ /* suppose the certificate filenames constist of hashed subject name
+ followed by suffix ".0" */
+ if (strlen(file->d_name) == 10 &&
+ file->d_name[8] == '.' &&
+ file->d_name[9] == '0') {
+ snprintf(filename, sizeof(filename), "%s%s", dirname, file->d_name);
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ ret = -1;
+ goto fail;
+ }
+ cert = PEM_read_X509(fp, NULL, NULL, NULL);
+ if (cert == NULL) {
+ ret = -1;
+ goto fail;
+ }
+ fclose(fp);
+ fp = NULL;
+ sk_X509_push(tmp_certs, cert);
+ }
+ }
+ closedir(dir);
+
+ *user_cert = tmp_certificate;
+ *user_key = tmp_key;
+ *trusted_certs = tmp_certs;
+
+ return 0;
+
+fail:
+ if (dir)
+ closedir(dir);
+ if (fp)
+ fclose(fp);
+ if (tmp_certificate)
+ sk_X509_pop_free(tmp_certificate, X509_free);
+ if (tmp_key)
+ EVP_PKEY_free(tmp_key);
+ if (tmp_certs)
+ sk_X509_pop_free(tmp_certs, X509_free);
+
+ return ret;
+}
+
+krb5_boolean
+pk_peer_compare(krb5_context context,
+ IssuerAndSerialNumber *peer1,
+ X509 *peer2)
+{
+#if 0
+ if (ASN1_INTEGER_cmp(peer1->serial,
+ X509_get_serialNumber(peer2)) != 0)
+ return FALSE;
+ if (X509_NAME_cmp(peer1->issuer,
+ X509_get_issuer_name(peer2)) != 0)
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+/* the user's certificate is supposed to be first in the chain */
+krb5_error_code
+pk_create_sign(krb5_context context,
+ STACK_OF(X509) *cert_chain,
+ EVP_PKEY *private_key,
+ SignedData *sd)
+{
+ X509 *user_cert;
+ EVP_MD_CTX md;
+ unsigned char *buf = NULL;
+ unsigned len;
+ int ret;
+
+ if (cert_chain == NULL || private_key == NULL) {
+ return -1; /* XXX error code */
+ }
+
+ if (sk_X509_num(cert_chain) == 0) {
+ return -1; /* XXX error code */
+ }
+
+ user_cert = sk_X509_value(cert_chain, 0);
+ sd->chain = sk_dup(cert_chain);
+
+ sd->signer_info.sid.issuer = X509_NAME_dup(X509_get_issuer_name(user_cert));
+ sd->signer_info.sid.serial = ASN1_INTEGER_dup(X509_get_serialNumber(user_cert));
+ /* sd->signer_info.sid.serial = ASN1_INTEGER_get(serial); */
+
+ sd->signer_info.digest_type = CKSUMTYPE_SHA1;
+ sd->signer_info.signature_type = ETYPE_ENCRYPT_RSA_PRIV;
+
+ /* suppose that econtent_info is already filled in by the caller */
+ buf = malloc(EVP_PKEY_size(private_key));
+ if (buf == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto fail;
+ }
+ EVP_SignInit(&md, EVP_sha1());
+ EVP_SignUpdate(&md,
+ sd->econtent_info.content.data,
+ sd->econtent_info.content.length);
+ ret = EVP_SignFinal(&md, buf, &len, private_key);
+ if (ret == 0) {
+ /* krb5_set_error_string -- check Openssl error */
+ return -1; /* XXX */
+ goto fail;
+ }
+
+ ret = krb5_data_copy(&sd->signer_info.signature, buf, len);
+ if (ret)
+ goto fail;
+
+ free(buf);
+
+ return 0;
+
+fail:
+ if (buf)
+ free(buf);
+ free_SignedData(sd);
+
+ return ret;
+}
+
+krb5_error_code
+pk_mk_padata(krb5_context context,
+ void *p_chain, /* STACK_OF(X509)* */
+ void *p_private_key, /* EVP_PKEY* */
+ void *p_trusted_certs, /* STACK_OF(X509)* */
+ KDC_REQ_BODY *req_body,
+ unsigned nonce,
+ METHOD_DATA *md)
+{
+ STACK_OF(X509) *chain = (STACK_OF(X509) *) p_chain;
+ EVP_PKEY *private_key = (EVP_PKEY *) p_private_key;
+ STACK_OF(X509) *trusted_certs = (STACK_OF(X509) *) p_trusted_certs ;
+ AuthPack ap;
+ PA_PK_AS_REQ req;
+ PA_DATA *pa;
+ SignedData *sd;
+ size_t len;
+ u_char buf[8096];
+ krb5_error_code problem;
+ int num, i;
+
+ memset(&req, sizeof(req), 0);
+ memset(&ap, sizeof(ap), 0);
+
+ /* first fill in SignedData, ie. create AuthPack and sign it with client's
+ private key. */
+ problem = build_auth_pack(context, nonce, req_body, &ap);
+ if (problem)
+ return problem;
+ encode_AuthPack(buf + sizeof(buf) - 1, sizeof(buf), &ap, &len);
+ free_AuthPack(&ap);
+
+ sd = &req.signed_data;
+ krb5_data_copy(&sd->econtent_info.content, buf + sizeof(buf) - len , len);
+ sd->econtent_info.type = strdup(OID_PKAUTHDATA);
+ problem = pk_create_sign(context, chain, private_key, sd);
+ if (problem)
+ goto end;
+
+ num = sk_X509_num(trusted_certs);
+ if (num > 0) {
+ req.trusted_certifiers = sk_X509_NAME_new_null();
+ if (req.trusted_certifiers == NULL) {
+ problem = ENOMEM; /* XXX */
+ goto end;
+ }
+
+ for (i = 0; i < num; i++) {
+ X509_NAME *name;
+
+ name = X509_NAME_dup(X509_get_issuer_name(sk_X509_value(trusted_certs, i)));
+ sk_X509_NAME_push(req.trusted_certifiers, name);
+ }
+ }
+
+ /* Add Signed Data to PADATA */
+
+ pa = realloc (md->val, (md->len + 1) * sizeof(*md->val));
+ if (pa == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ problem = ENOMEM;
+ goto end;
+ }
+ md->val = pa;
+
+ problem = encode_PA_PK_AS_REQ(buf + sizeof(buf) - 1, sizeof(buf), &req, &len);
+ if (problem)
+ goto end;
+ pa = &md->val[md->len]; /* XXX ??? &md */
+ pa->padata_type = KRB5_PADATA_PK_AS_REQ;
+ krb5_data_copy(&pa->padata_value,
+ buf + sizeof(buf) - len,
+ len);
+ ++md->len;
+
+end:
+ free_PA_PK_AS_REQ(&req);
+
+ return problem;
+}
+
+krb5_error_code
+pk_verify_sign(krb5_context context,
+ SignedData *sd,
+ STACK_OF(X509) *trusted_certs,
+ X509 **signer)
+{
+ X509_STORE *cert_store = NULL;
+ X509_STORE_CTX *store_ctx = NULL;
+ EVP_PKEY *public_key = NULL;
+ X509 *cert = NULL;
+ krb5_error_code ret;
+ EVP_MD_CTX md;
+ int i;
+
+ ret = -1; /* cert not found */
+ for (i = 0; i < sk_X509_num(sd->chain); i++) {
+ cert = sk_X509_value(sd->chain, i);
+ if (pk_peer_compare(context, &sd->signer_info.sid, cert) == TRUE) {
+ ret = 0;
+ break;
+ }
+ }
+ if (ret)
+ return ret;
+
+ cert_store = X509_STORE_new();
+ if (cert_store == NULL) {
+ return -1; /* XXX */
+ }
+
+ /* ERR_load_crypto_strings(); */ /* ??? */
+
+ store_ctx = X509_STORE_CTX_new();
+ if (store_ctx == NULL) {
+ ret = -1; /* XXX */
+ goto end;
+ }
+
+ X509_STORE_CTX_init(store_ctx, cert_store, cert, sd->chain);
+ X509_STORE_CTX_trusted_stack(store_ctx, trusted_certs);
+ ret = X509_verify_cert(store_ctx);
+
+ public_key = X509_get_pubkey(cert);
+
+ EVP_VerifyInit(&md, EVP_sha1());
+ EVP_VerifyUpdate(&md,
+ sd->econtent_info.content.data,
+ sd->econtent_info.content.length);
+ ret = EVP_VerifyFinal(&md,
+ sd->signer_info.signature.data,
+ sd->signer_info.signature.length,
+ public_key);
+
+ if (signer && cert)
+ *signer = X509_dup(cert);
+
+end:
+ if (store_ctx)
+ X509_STORE_CTX_free(store_ctx);
+
+ return ret;
+}
+
+static krb5_error_code
+pk_decrypt_key(krb5_context context,
+ krb5_data *encrypted_key,
+ EVP_PKEY *priv_key,
+ krb5_keyblock *key)
+{
+ int ret;
+ unsigned char *buf;
+ size_t len;
+
+ buf = malloc(EVP_PKEY_size(priv_key));
+ if (buf == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = EVP_PKEY_decrypt(buf,
+ encrypted_key->data,
+ encrypted_key->length,
+ priv_key);
+ if (ret <= 0) {
+ free(buf);
+ return -1; /* XXX */
+ }
+
+ ret = decode_EncryptionKey(buf, EVP_PKEY_size(priv_key), key, &len);
+ free(buf);
+ return ret;
+}
+
+static krb5_error_code
+get_reply_key(krb5_context context,
+ krb5_data *raw,
+ unsigned nonce,
+ krb5_keyblock **key)
+{
+ ReplyKeyPack key_pack;
+ size_t len;
+ krb5_error_code problem;
+
+ memset(&key_pack, 0, sizeof(key_pack));
+
+ problem = decode_ReplyKeyPack(raw->data,
+ raw->length,
+ &key_pack,
+ &len);
+ if (problem)
+ goto end;
+
+#if 0
+ if (key_pack.nonce != nonce) {
+ problem = -1; /* XXX */
+ goto end;
+ }
+#endif
+
+ *key = malloc (sizeof (**key));
+ if (*key == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ problem = krb5_copy_keyblock(context, &key_pack.replyKey, key);
+
+end:
+ free_ReplyKeyPack(&key_pack);
+ if (problem)
+ free(*key);
+ return problem;
+}
+
+
+krb5_error_code
+pk_rd_pa_reply(krb5_context context,
+ void *p_cert, /* X509* */
+ void *p_priv_key, /* EVP_PKEY* */
+ void *p_trusted_certs, /* STACK_OF(X509)* */
+ unsigned nonce,
+ PA_DATA *pa,
+ krb5_keyblock **key)
+{
+ X509 *cert = (X509 *) p_cert;
+ EVP_PKEY *priv_key = (EVP_PKEY *) p_priv_key;
+ STACK_OF(X509) *trusted_certs = (STACK_OF(X509) *) p_trusted_certs;
+ krb5_error_code problem;
+ PA_PK_AS_REP rep;
+ SignedData sd;
+ size_t len;
+ krb5_keyblock tmp_key;
+ krb5_crypto crypto;
+ krb5_data plain;
+
+ memset(&rep, 0, sizeof(rep));
+ memset(&sd, 0, sizeof(sd));
+ memset(&tmp_key, 0, sizeof(tmp_key));
+ krb5_data_zero(&plain);
+
+ problem = decode_PA_PK_AS_REP(pa->padata_value.data, pa->padata_value.length,
+ &rep, &len);
+ if (problem)
+ return problem;
+
+ /* check the message is really for us */
+ problem = pk_peer_compare(context, &rep.recipient_info.rid, cert);
+ if (!problem) {
+ problem = -1; /* XXX */
+ goto end;
+ }
+
+ if (rep.recipient_info.etype != ETYPE_ENCRYPT_RSA_PUB) {
+ problem = KRB5_WRONG_ETYPE; /* XXX */
+ goto end;
+ }
+
+ problem = pk_decrypt_key(context,
+ &rep.recipient_info.encrypted_key,
+ priv_key,
+ &tmp_key);
+ if (problem)
+ goto end;
+
+ /* XXX use something like g_OID_equal() */
+ if (strcmp(rep.econtent_info.type, OID_ID_SIGNEDDATA)) {
+ problem = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto end;
+ }
+
+ /* decrypt signed data with tmp_key) */
+ problem = krb5_crypto_init(context, &tmp_key, 0, &crypto);
+ if (problem)
+ goto end;
+ problem = krb5_decrypt(context, crypto,
+ 0,
+ rep.econtent_info.content.data,
+ rep.econtent_info.content.length,
+ &plain);
+ krb5_crypto_destroy(context, crypto);
+ if (problem)
+ goto end;
+
+ problem = decode_SignedData(plain.data, plain.length, &sd, &len);
+ if (problem)
+ goto end;
+
+ problem = pk_verify_sign(context, &sd, trusted_certs, NULL);
+ if (problem)
+ goto end;
+
+ /* XXX use something like g_OID_equal() */
+ if (strcmp(sd.econtent_info.type, OID_PKRKEYDATA)) {
+ problem = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
+ goto end;
+ }
+
+ problem = get_reply_key(context, &sd.econtent_info.content, nonce, key);
+ if (problem)
+ goto end;
+
+end:
+ krb5_free_keyblock_contents(context, &tmp_key);
+ krb5_data_free(&plain);
+ free_PA_PK_AS_REP(&rep);
+ free_SignedData(&sd);
+
+ return problem;
+}
+#endif /* PKINIT */
- Follow-Ups:
- Re: PKINIT
- From: Christopher James <cjames@berkeley.innomedia.com>
- Re: PKINIT
- From: Christopher James <cjames@berkeley.innomedia.com>