aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/preauth/pkinit
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2023-08-04 17:53:10 +0000
committerCy Schubert <cy@FreeBSD.org>2023-08-04 17:53:10 +0000
commit0320e0d5bb9fbb5da53478b3fd80ad79b110191d (patch)
treee1185f75bd2d3f87b0c17f787debc3ee8648214b /src/plugins/preauth/pkinit
parentb0e4d68d5124581ae353493d69bea352de4cff8a (diff)
Diffstat (limited to 'src/plugins/preauth/pkinit')
-rw-r--r--src/plugins/preauth/pkinit/Makefile.in6
-rw-r--r--src/plugins/preauth/pkinit/deps13
-rw-r--r--src/plugins/preauth/pkinit/pkcs11.h2
-rw-r--r--src/plugins/preauth/pkinit/pkinit.h17
-rw-r--r--src/plugins/preauth/pkinit/pkinit_accessor.c12
-rw-r--r--src/plugins/preauth/pkinit/pkinit_accessor.h6
-rw-r--r--src/plugins/preauth/pkinit/pkinit_clnt.c303
-rw-r--r--src/plugins/preauth/pkinit/pkinit_constants.c325
-rw-r--r--src/plugins/preauth/pkinit/pkinit_crypto.h66
-rw-r--r--src/plugins/preauth/pkinit/pkinit_crypto_openssl.c3120
-rw-r--r--src/plugins/preauth/pkinit/pkinit_crypto_openssl.h23
-rw-r--r--src/plugins/preauth/pkinit/pkinit_identity.c99
-rw-r--r--src/plugins/preauth/pkinit/pkinit_kdf_constants.c59
-rw-r--r--src/plugins/preauth/pkinit/pkinit_kdf_test.c22
-rw-r--r--src/plugins/preauth/pkinit/pkinit_lib.c95
-rw-r--r--src/plugins/preauth/pkinit/pkinit_matching.c60
-rw-r--r--src/plugins/preauth/pkinit/pkinit_srv.c701
-rw-r--r--src/plugins/preauth/pkinit/pkinit_trace.h66
18 files changed, 2310 insertions, 2685 deletions
diff --git a/src/plugins/preauth/pkinit/Makefile.in b/src/plugins/preauth/pkinit/Makefile.in
index d8b9398180ef..86f143d72d1c 100644
--- a/src/plugins/preauth/pkinit/Makefile.in
+++ b/src/plugins/preauth/pkinit/Makefile.in
@@ -10,14 +10,14 @@ RELDIR=../plugins/preauth/pkinit
SHLIB_EXPDEPS = \
$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
$(TOPLIBD)/libkrb5$(SHLIBEXT)
-SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto -lcrypto $(DL_LIB) $(SUPPORT_LIB) $(LIBS)
+SHLIB_EXPLIBS= -lkrb5 $(COM_ERR_LIB) -lk5crypto -lcrypto $(DL_LIB) $(SUPPORT_LIB) $(LIBS)
STLIBOBJS= \
pkinit_accessor.o \
pkinit_srv.o \
pkinit_lib.o \
pkinit_clnt.o \
- pkinit_kdf_constants.o \
+ pkinit_constants.o \
pkinit_profile.o \
pkinit_identity.o \
pkinit_matching.o \
@@ -28,7 +28,7 @@ SRCS= \
$(srcdir)/pkinit_srv.c \
$(srcdir)/pkinit_lib.c \
$(srcdir)/pkinit_kdf_test.c \
- $(srcdir)/pkinit_kdf_constants.c \
+ $(srcdir)/pkinit_constants.c \
$(srcdir)/pkinit_clnt.c \
$(srcdir)/pkinit_profile.c \
$(srcdir)/pkinit_identity.c \
diff --git a/src/plugins/preauth/pkinit/deps b/src/plugins/preauth/pkinit/deps
index 57116db1618c..58320aa80124 100644
--- a/src/plugins/preauth/pkinit/deps
+++ b/src/plugins/preauth/pkinit/deps
@@ -44,14 +44,14 @@ pkinit_kdf_test.so pkinit_kdf_test.po $(OUTPRE)pkinit_kdf_test.$(OBJEXT): \
$(top_srcdir)/include/krb5/preauth_plugin.h pkcs11.h \
pkinit.h pkinit_accessor.h pkinit_crypto.h pkinit_kdf_test.c \
pkinit_trace.h
-pkinit_kdf_constants.so pkinit_kdf_constants.po $(OUTPRE)pkinit_kdf_constants.$(OBJEXT): \
+pkinit_constants.so pkinit_constants.po $(OUTPRE)pkinit_constants.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
$(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-int-pkinit.h \
$(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
$(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5/clpreauth_plugin.h \
$(top_srcdir)/include/krb5/kdcpreauth_plugin.h $(top_srcdir)/include/krb5/plugin.h \
$(top_srcdir)/include/krb5/preauth_plugin.h pkcs11.h \
- pkinit.h pkinit_accessor.h pkinit_crypto.h pkinit_kdf_constants.c \
+ pkinit.h pkinit_accessor.h pkinit_constants.c pkinit_crypto.h \
pkinit_trace.h
pkinit_clnt.so pkinit_clnt.po $(OUTPRE)pkinit_clnt.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
@@ -101,10 +101,15 @@ pkinit_matching.so pkinit_matching.po $(OUTPRE)pkinit_matching.$(OBJEXT): \
pkinit_trace.h
pkinit_crypto_openssl.so pkinit_crypto_openssl.po $(OUTPRE)pkinit_crypto_openssl.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
- $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
- $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-platform.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-hex.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
$(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
$(top_srcdir)/include/krb5/clpreauth_plugin.h $(top_srcdir)/include/krb5/kdcpreauth_plugin.h \
$(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
pkcs11.h pkinit.h pkinit_accessor.h pkinit_crypto.h \
pkinit_crypto_openssl.c pkinit_crypto_openssl.h pkinit_trace.h
diff --git a/src/plugins/preauth/pkinit/pkcs11.h b/src/plugins/preauth/pkinit/pkcs11.h
index 28ded4a89f37..e3d2846315ad 100644
--- a/src/plugins/preauth/pkinit/pkcs11.h
+++ b/src/plugins/preauth/pkinit/pkcs11.h
@@ -12,7 +12,7 @@
PURPOSE. */
/* Please submit changes back to the Scute project at
- http://www.scute.org/ (or send them to marcus@g10code.com), so that
+ https://www.scute.org/ (or send them to marcus@g10code.com), so that
they can be picked up by other projects from there as well. */
/* This file is a modified implementation of the PKCS #11 standard by
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
index f3de9ad7a15d..66f92d8f03f5 100644
--- a/src/plugins/preauth/pkinit/pkinit.h
+++ b/src/plugins/preauth/pkinit/pkinit.h
@@ -42,7 +42,6 @@
#ifndef WITHOUT_PKCS11
#include "pkcs11.h"
-#define PKCS11_MODNAME "opensc-pkcs11.so"
#define PK_SIGLEN_GUESS 1000
#define PK_NOSLOT 999999
#endif
@@ -77,6 +76,7 @@
#define KRB5_CONF_PKINIT_KDC_OCSP "pkinit_kdc_ocsp"
#define KRB5_CONF_PKINIT_POOL "pkinit_pool"
#define KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING "pkinit_require_crl_checking"
+#define KRB5_CONF_PKINIT_REQUIRE_FRESHNESS "pkinit_require_freshness"
#define KRB5_CONF_PKINIT_REVOKE "pkinit_revoke"
/* Make pkiDebug(fmt,...) print, or not. */
@@ -148,6 +148,8 @@ typedef struct _pkinit_plg_opts {
int allow_upn; /* allow UPN-SAN instead of pkinit-SAN */
int dh_or_rsa; /* selects DH or RSA based pkinit */
int require_crl_checking; /* require CRL for a CA (default is false) */
+ int require_freshness; /* require freshness token (default is false) */
+ int disable_freshness; /* disable freshness token on client for testing */
int dh_min_bits; /* minimum DH modulus size allowed */
} pkinit_plg_opts;
@@ -162,6 +164,7 @@ typedef struct _pkinit_req_opts {
int require_crl_checking;
int dh_size; /* initial request DH modulus size (default=1024) */
int require_hostname_match;
+ int disable_freshness;
} pkinit_req_opts;
/*
@@ -209,11 +212,11 @@ struct _pkinit_req_context {
pkinit_identity_opts *idopts;
int do_identity_matching;
krb5_preauthtype pa_type;
- int rfc4556_kdc;
int rfc6112_kdc;
int identity_initialized;
int identity_prompted;
krb5_error_code identity_prompt_retval;
+ krb5_data *freshness_token;
};
typedef struct _pkinit_req_context *pkinit_req_context;
@@ -239,7 +242,6 @@ struct _pkinit_kdc_req_context {
int magic;
pkinit_req_crypto_context cryptoctx;
krb5_auth_pack *rcv_auth_pack;
- krb5_auth_pack_draft9 *rcv_auth_pack9;
krb5_preauthtype pa_type;
};
typedef struct _pkinit_kdc_req_context *pkinit_kdc_req_context;
@@ -324,27 +326,18 @@ void pkinit_free_deferred_ids(pkinit_deferred_id *identities);
* initialization and free functions
*/
void init_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in);
-void init_krb5_pa_pk_as_req_draft9(krb5_pa_pk_as_req_draft9 **in);
void init_krb5_reply_key_pack(krb5_reply_key_pack **in);
-void init_krb5_reply_key_pack_draft9(krb5_reply_key_pack_draft9 **in);
void init_krb5_pa_pk_as_rep(krb5_pa_pk_as_rep **in);
-void init_krb5_pa_pk_as_rep_draft9(krb5_pa_pk_as_rep_draft9 **in);
-void init_krb5_subject_pk_info(krb5_subject_pk_info **in);
void free_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in);
-void free_krb5_pa_pk_as_req_draft9(krb5_pa_pk_as_req_draft9 **in);
void free_krb5_reply_key_pack(krb5_reply_key_pack **in);
-void free_krb5_reply_key_pack_draft9(krb5_reply_key_pack_draft9 **in);
void free_krb5_auth_pack(krb5_auth_pack **in);
-void free_krb5_auth_pack_draft9(krb5_context, krb5_auth_pack_draft9 **in);
void free_krb5_pa_pk_as_rep(krb5_pa_pk_as_rep **in);
-void free_krb5_pa_pk_as_rep_draft9(krb5_pa_pk_as_rep_draft9 **in);
void free_krb5_external_principal_identifier(krb5_external_principal_identifier ***in);
void free_krb5_algorithm_identifiers(krb5_algorithm_identifier ***in);
void free_krb5_algorithm_identifier(krb5_algorithm_identifier *in);
void free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in);
-void free_krb5_subject_pk_info(krb5_subject_pk_info **in);
krb5_error_code pkinit_copy_krb5_data(krb5_data *dst, const krb5_data *src);
diff --git a/src/plugins/preauth/pkinit/pkinit_accessor.c b/src/plugins/preauth/pkinit/pkinit_accessor.c
index 6bae94969a87..0908f1b9bd89 100644
--- a/src/plugins/preauth/pkinit/pkinit_accessor.c
+++ b/src/plugins/preauth/pkinit/pkinit_accessor.c
@@ -41,23 +41,16 @@
krb5_error_code (*k5int_decode_##type)(const krb5_data *, type ***)
DEF_FUNC_PTRS(krb5_auth_pack);
-DEF_FUNC_PTRS(krb5_auth_pack_draft9);
DEF_FUNC_PTRS(krb5_kdc_dh_key_info);
DEF_FUNC_PTRS(krb5_pa_pk_as_rep);
DEF_FUNC_PTRS(krb5_pa_pk_as_req);
-DEF_FUNC_PTRS(krb5_pa_pk_as_req_draft9);
DEF_FUNC_PTRS(krb5_reply_key_pack);
-DEF_FUNC_PTRS(krb5_reply_key_pack_draft9);
/* special cases... */
krb5_error_code
(*k5int_decode_krb5_principal_name)(const krb5_data *, krb5_principal_data **);
krb5_error_code
-(*k5int_encode_krb5_pa_pk_as_rep_draft9)(const krb5_pa_pk_as_rep_draft9 *,
- krb5_data **code);
-
-krb5_error_code
(*k5int_encode_krb5_td_dh_parameters)(krb5_algorithm_identifier *const *,
krb5_data **code);
krb5_error_code
@@ -101,21 +94,16 @@ pkinit_accessor_init(void)
k5int_decode_##type = k5int.decode_##type;
SET_PTRS(krb5_auth_pack);
- SET_PTRS(krb5_auth_pack_draft9);
SET_PTRS(krb5_kdc_dh_key_info);
SET_PTRS(krb5_pa_pk_as_rep);
SET_PTRS(krb5_pa_pk_as_req);
- SET_PTRS(krb5_pa_pk_as_req_draft9);
SET_PTRS(krb5_reply_key_pack);
- SET_PTRS(krb5_reply_key_pack_draft9);
SET_PTRS(krb5_td_dh_parameters);
SET_PTRS(krb5_td_trusted_certifiers);
/* special cases... */
k5int_decode_krb5_principal_name = k5int.decode_krb5_principal_name;
k5int_encode_krb5_kdc_req_body = k5int.encode_krb5_kdc_req_body;
- k5int_encode_krb5_pa_pk_as_rep_draft9 = \
- k5int.encode_krb5_pa_pk_as_rep_draft9;
k5int_krb5_free_kdc_req = k5int.free_kdc_req;
k5int_set_prompt_types = k5int.set_prompt_types;
return 0;
diff --git a/src/plugins/preauth/pkinit/pkinit_accessor.h b/src/plugins/preauth/pkinit/pkinit_accessor.h
index dcee3db539e6..e510ab624ed4 100644
--- a/src/plugins/preauth/pkinit/pkinit_accessor.h
+++ b/src/plugins/preauth/pkinit/pkinit_accessor.h
@@ -45,21 +45,15 @@ extern krb5_error_code (*k5int_encode_##type)(const type **, krb5_data **); \
extern krb5_error_code (*k5int_decode_##type)(const krb5_data *, type ***)
DEF_EXT_FUNC_PTRS(krb5_auth_pack);
-DEF_EXT_FUNC_PTRS(krb5_auth_pack_draft9);
DEF_EXT_FUNC_PTRS(krb5_kdc_dh_key_info);
DEF_EXT_FUNC_PTRS(krb5_pa_pk_as_rep);
DEF_EXT_FUNC_PTRS(krb5_pa_pk_as_req);
-DEF_EXT_FUNC_PTRS(krb5_pa_pk_as_req_draft9);
DEF_EXT_FUNC_PTRS(krb5_reply_key_pack);
-DEF_EXT_FUNC_PTRS(krb5_reply_key_pack_draft9);
/* special cases... */
extern krb5_error_code (*k5int_decode_krb5_principal_name)
(const krb5_data *, krb5_principal_data **);
-extern krb5_error_code (*k5int_encode_krb5_pa_pk_as_rep_draft9)
- (const krb5_pa_pk_as_rep_draft9 *, krb5_data **code);
-
extern krb5_error_code (*k5int_encode_krb5_td_dh_parameters)
(krb5_algorithm_identifier *const *, krb5_data **code);
extern krb5_error_code (*k5int_decode_krb5_td_dh_parameters)
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index f1bc6b21dc47..725d5bc43863 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -34,7 +34,6 @@
#include "k5-json.h"
#include <unistd.h>
-#include <dlfcn.h>
#include <sys/stat.h>
/**
@@ -119,8 +118,8 @@ pa_pkinit_gen_req(krb5_context context,
goto cleanup;
}
- retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0,
- der_req, &cksum);
+ retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
+ &cksum);
if (retval)
goto cleanup;
TRACE_PKINIT_CLIENT_REQ_CHECKSUM(context, &cksum);
@@ -148,11 +147,7 @@ pa_pkinit_gen_req(krb5_context context,
goto cleanup;
}
- /*
- * The most we'll return is two pa_data, normally just one.
- * We need to make room for the NULL terminator.
- */
- return_pa_data = k5calloc(3, sizeof(*return_pa_data), &retval);
+ return_pa_data = k5calloc(2, sizeof(*return_pa_data), &retval);
if (return_pa_data == NULL)
goto cleanup;
@@ -162,23 +157,14 @@ pa_pkinit_gen_req(krb5_context context,
return_pa_data[0]->magic = KV5M_PA_DATA;
- if (pa_type == KRB5_PADATA_PK_AS_REQ_OLD)
- return_pa_data[0]->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
- else
- return_pa_data[0]->pa_type = pa_type;
+ return_pa_data[0]->pa_type = pa_type;
return_pa_data[0]->length = out_data->length;
return_pa_data[0]->contents = (krb5_octet *) out_data->data;
*out_data = empty_data();
- if (return_pa_data[0]->pa_type == KRB5_PADATA_PK_AS_REP_OLD) {
- return_pa_data[1] = k5alloc(sizeof(*return_pa_data[1]), &retval);
- if (return_pa_data[1] == NULL)
- goto cleanup;
- return_pa_data[1]->pa_type = KRB5_PADATA_AS_CHECKSUM;
- }
-
*out_padata = return_pa_data;
return_pa_data = NULL;
+ cb->disable_fallback(context, rock);
cleanup:
krb5_free_data(context, der_req);
@@ -201,84 +187,51 @@ pkinit_as_req_create(krb5_context context,
krb5_data ** as_req)
{
krb5_error_code retval = ENOMEM;
- krb5_subject_pk_info info;
- krb5_data *coded_auth_pack = NULL;
+ krb5_data spki = empty_data(), *coded_auth_pack = NULL;
krb5_auth_pack auth_pack;
krb5_pa_pk_as_req *req = NULL;
- krb5_auth_pack_draft9 auth_pack9;
- krb5_pa_pk_as_req_draft9 *req9 = NULL;
krb5_algorithm_identifier **cmstypes = NULL;
int protocol = reqctx->opts->dh_or_rsa;
- unsigned char *dh_params = NULL, *dh_pubkey = NULL;
- unsigned int dh_params_len, dh_pubkey_len;
pkiDebug("pkinit_as_req_create pa_type = %d\n", reqctx->pa_type);
/* Create the authpack */
- switch((int)reqctx->pa_type) {
- case KRB5_PADATA_PK_AS_REQ_OLD:
- protocol = RSA_PROTOCOL;
- memset(&auth_pack9, 0, sizeof(auth_pack9));
- auth_pack9.pkAuthenticator.ctime = ctsec;
- auth_pack9.pkAuthenticator.cusec = cusec;
- auth_pack9.pkAuthenticator.nonce = nonce;
- auth_pack9.pkAuthenticator.kdcName = server;
- break;
- case KRB5_PADATA_PK_AS_REQ:
- memset(&info, 0, sizeof(info));
- memset(&auth_pack, 0, sizeof(auth_pack));
- auth_pack.pkAuthenticator.ctime = ctsec;
- auth_pack.pkAuthenticator.cusec = cusec;
- auth_pack.pkAuthenticator.nonce = nonce;
- auth_pack.pkAuthenticator.paChecksum = *cksum;
- auth_pack.clientDHNonce.length = 0;
- auth_pack.clientPublicValue = &info;
- auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
+ memset(&auth_pack, 0, sizeof(auth_pack));
+ auth_pack.pkAuthenticator.ctime = ctsec;
+ auth_pack.pkAuthenticator.cusec = cusec;
+ auth_pack.pkAuthenticator.nonce = nonce;
+ auth_pack.pkAuthenticator.paChecksum = *cksum;
+ if (!reqctx->opts->disable_freshness)
+ auth_pack.pkAuthenticator.freshnessToken = reqctx->freshness_token;
+ auth_pack.clientDHNonce.length = 0;
+ auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
- /* add List of CMS algorithms */
- retval = create_krb5_supportedCMSTypes(context, plgctx->cryptoctx,
- reqctx->cryptoctx,
- reqctx->idctx, &cmstypes);
- auth_pack.supportedCMSTypes = cmstypes;
- if (retval)
- goto cleanup;
- break;
- default:
- pkiDebug("as_req: unrecognized pa_type = %d\n",
- (int)reqctx->pa_type);
- retval = -1;
+ /* add List of CMS algorithms */
+ retval = create_krb5_supportedCMSTypes(context, plgctx->cryptoctx,
+ reqctx->cryptoctx,
+ reqctx->idctx, &cmstypes);
+ auth_pack.supportedCMSTypes = cmstypes;
+ if (retval)
goto cleanup;
- }
switch(protocol) {
case DH_PROTOCOL:
TRACE_PKINIT_CLIENT_REQ_DH(context);
pkiDebug("as_req: DH key transport algorithm\n");
- info.algorithm.algorithm = dh_oid;
/* create client-side DH keys */
retval = client_create_dh(context, plgctx->cryptoctx,
reqctx->cryptoctx, reqctx->idctx,
- reqctx->opts->dh_size, &dh_params,
- &dh_params_len, &dh_pubkey, &dh_pubkey_len);
+ reqctx->opts->dh_size, &spki);
+ auth_pack.clientPublicValue = spki;
if (retval != 0) {
pkiDebug("failed to create dh parameters\n");
goto cleanup;
}
- info.algorithm.parameters = make_data(dh_params, dh_params_len);
- info.subjectPublicKey = make_data(dh_pubkey, dh_pubkey_len);
break;
case RSA_PROTOCOL:
TRACE_PKINIT_CLIENT_REQ_RSA(context);
pkiDebug("as_req: RSA key transport algorithm\n");
- switch((int)reqctx->pa_type) {
- case KRB5_PADATA_PK_AS_REQ_OLD:
- auth_pack9.clientPublicValue = NULL;
- break;
- case KRB5_PADATA_PK_AS_REQ:
- auth_pack.clientPublicValue = NULL;
- break;
- }
break;
default:
pkiDebug("as_req: unknown key transport protocol %d\n",
@@ -287,16 +240,7 @@ pkinit_as_req_create(krb5_context context,
goto cleanup;
}
- /* Encode the authpack */
- switch((int)reqctx->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- retval = k5int_encode_krb5_auth_pack(&auth_pack, &coded_auth_pack);
- break;
- case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = k5int_encode_krb5_auth_pack_draft9(&auth_pack9,
- &coded_auth_pack);
- break;
- }
+ retval = k5int_encode_krb5_auth_pack(&auth_pack, &coded_auth_pack);
if (retval) {
pkiDebug("failed to encode the AuthPack %d\n", retval);
goto cleanup;
@@ -308,60 +252,39 @@ pkinit_as_req_create(krb5_context context,
#endif
/* create PKCS7 object from authpack */
- switch((int)reqctx->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- init_krb5_pa_pk_as_req(&req);
- if (req == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- if (use_content_info(context, reqctx, client)) {
- retval = cms_contentinfo_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx,
- CMS_SIGN_CLIENT,
- (unsigned char *)
- coded_auth_pack->data,
- coded_auth_pack->length,
- (unsigned char **)
- &req->signedAuthPack.data,
- &req->signedAuthPack.length);
- } else {
- retval = cms_signeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx,
- CMS_SIGN_CLIENT, 1,
- (unsigned char *)
- coded_auth_pack->data,
- coded_auth_pack->length,
- (unsigned char **)
- &req->signedAuthPack.data,
- &req->signedAuthPack.length);
- }
-#ifdef DEBUG_ASN1
- print_buffer_bin((unsigned char *)req->signedAuthPack.data,
- req->signedAuthPack.length,
- "/tmp/client_signed_data");
-#endif
- break;
- case KRB5_PADATA_PK_AS_REQ_OLD:
- init_krb5_pa_pk_as_req_draft9(&req9);
- if (req9 == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
+ init_krb5_pa_pk_as_req(&req);
+ if (req == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ if (use_content_info(context, reqctx, client)) {
+ retval = cms_contentinfo_create(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx,
+ CMS_SIGN_CLIENT,
+ (unsigned char *)
+ coded_auth_pack->data,
+ coded_auth_pack->length,
+ (unsigned char **)
+ &req->signedAuthPack.data,
+ &req->signedAuthPack.length);
+ } else {
retval = cms_signeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_DRAFT9, 1,
- (unsigned char *)coded_auth_pack->data,
+ reqctx->cryptoctx, reqctx->idctx,
+ CMS_SIGN_CLIENT,
+ (unsigned char *)
+ coded_auth_pack->data,
coded_auth_pack->length,
(unsigned char **)
- &req9->signedAuthPack.data,
- &req9->signedAuthPack.length);
- break;
+ &req->signedAuthPack.data,
+ &req->signedAuthPack.length);
+ }
+
#ifdef DEBUG_ASN1
- print_buffer_bin((unsigned char *)req9->signedAuthPack.data,
- req9->signedAuthPack.length,
- "/tmp/client_signed_data_draft9");
+ print_buffer_bin((unsigned char *)req->signedAuthPack.data,
+ req->signedAuthPack.length,
+ "/tmp/client_signed_data");
#endif
- }
+
krb5_free_data(context, coded_auth_pack);
if (retval) {
pkiDebug("failed to create pkcs7 signed data\n");
@@ -369,33 +292,21 @@ pkinit_as_req_create(krb5_context context,
}
/* create a list of trusted CAs */
- switch((int)reqctx->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- retval = create_krb5_trustedCertifiers(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx, &req->trustedCertifiers);
- if (retval)
- goto cleanup;
- retval = create_issuerAndSerial(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx,
- (unsigned char **)&req->kdcPkId.data,
- &req->kdcPkId.length);
- if (retval)
- goto cleanup;
+ retval = create_krb5_trustedCertifiers(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx,
+ &req->trustedCertifiers);
+ if (retval)
+ goto cleanup;
+ retval = create_issuerAndSerial(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx,
+ (unsigned char **)&req->kdcPkId.data,
+ &req->kdcPkId.length);
+ if (retval)
+ goto cleanup;
+
+ /* Encode the as-req */
+ retval = k5int_encode_krb5_pa_pk_as_req(req, as_req);
- /* Encode the as-req */
- retval = k5int_encode_krb5_pa_pk_as_req(req, as_req);
- break;
- case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = create_issuerAndSerial(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx,
- (unsigned char **)&req9->kdcCert.data,
- &req9->kdcCert.length);
- if (retval)
- goto cleanup;
- /* Encode the as-req */
- retval = k5int_encode_krb5_pa_pk_as_req_draft9(req9, as_req);
- break;
- }
#ifdef DEBUG_ASN1
if (!retval)
print_buffer_bin((unsigned char *)(*as_req)->data, (*as_req)->length,
@@ -404,10 +315,8 @@ pkinit_as_req_create(krb5_context context,
cleanup:
free_krb5_algorithm_identifiers(&cmstypes);
- free(dh_params);
- free(dh_pubkey);
free_krb5_pa_pk_as_req(&req);
- free_krb5_pa_pk_as_req_draft9(&req9);
+ krb5_free_data_contents(context, &spki);
pkiDebug("pkinit_as_req_create retval=%d\n", (int) retval);
@@ -504,24 +413,6 @@ verify_kdc_san(krb5_context context,
for (hostptr = certhosts; *hostptr != NULL; hostptr++)
TRACE_PKINIT_CLIENT_SAN_KDCCERT_DNSNAME(context, *hostptr);
}
-#if 0
- retval = call_san_checking_plugins(context, plgctx, reqctx, idctx,
- princs, hosts, &plugin_decision,
- need_eku_checking);
- pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
- __FUNCTION__);
- if (retval) {
- retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
- goto out;
- }
- pkiDebug("%s: call_san_checking_plugins() returned decision %d and "
- "need_eku_checking %d\n",
- __FUNCTION__, plugin_decision, *need_eku_checking);
- if (plugin_decision != NO_DECISION) {
- retval = plugin_decision;
- goto out;
- }
-#endif
pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
for (i = 0; princs != NULL && princs[i] != NULL; i++) {
@@ -807,13 +698,6 @@ pkinit_as_rep_parse(krb5_context context,
pkiDebug("failed to decode reply_key_pack\n");
goto cleanup;
}
- /*
- * This is hack but Windows sends back SHA1 checksum
- * with checksum type of 14. There is currently no
- * checksum type of 14 defined.
- */
- if (key_pack->asChecksum.checksum_type == 14)
- key_pack->asChecksum.checksum_type = CKSUMTYPE_NIST_SHA;
retval = krb5_c_make_checksum(context,
key_pack->asChecksum.checksum_type,
&key_pack->replyKey,
@@ -856,7 +740,7 @@ pkinit_as_rep_parse(krb5_context context,
break;
default:
- pkiDebug("unknow as_rep type %d\n", kdc_reply->choice);
+ pkiDebug("unknown as_rep type %d\n", kdc_reply->choice);
goto cleanup;
}
@@ -1003,6 +887,11 @@ pkinit_client_prep_questions(krb5_context context,
k5_json_object jval = NULL;
k5_json_number jflag = NULL;
+ /* Don't ask questions for the informational padata items or when the
+ * ticket is issued. */
+ if (pa_data->pa_type != KRB5_PADATA_PK_AS_REQ)
+ return 0;
+
if (!reqctx->identity_initialized) {
pkinit_client_profile(context, plgctx, reqctx, cb, rock,
&request->server->realm);
@@ -1017,8 +906,6 @@ pkinit_client_prep_questions(krb5_context context,
}
reqctx->identity_initialized = TRUE;
- crypto_free_cert_info(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx);
if (retval != 0) {
pkiDebug("%s: not asking responder question\n", __FUNCTION__);
retval = 0;
@@ -1162,6 +1049,7 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
pkinit_context plgctx = (pkinit_context)moddata;
pkinit_req_context reqctx = (pkinit_req_context)modreq;
krb5_keyblock as_key;
+ krb5_data d;
pkiDebug("pkinit_client_process %p %p %p %p\n",
context, plgctx, reqctx, request);
@@ -1174,32 +1062,20 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
case KRB5_PADATA_PKINIT_KX:
reqctx->rfc6112_kdc = 1;
return 0;
+ case KRB5_PADATA_AS_FRESHNESS:
+ TRACE_PKINIT_CLIENT_FRESHNESS_TOKEN(context);
+ krb5_free_data(context, reqctx->freshness_token);
+ reqctx->freshness_token = NULL;
+ d = make_data(in_padata->contents, in_padata->length);
+ return krb5_copy_data(context, &d, &reqctx->freshness_token);
case KRB5_PADATA_PK_AS_REQ:
- reqctx->rfc4556_kdc = 1;
pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
processing_request = 1;
break;
case KRB5_PADATA_PK_AS_REP:
- reqctx->rfc4556_kdc = 1;
pkiDebug("processing KRB5_PADATA_PK_AS_REP\n");
break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- /* Don't fall back to draft9 code if the KDC supports RFC 4556. */
- if (reqctx->rfc4556_kdc) {
- TRACE_PKINIT_CLIENT_NO_DRAFT9(context);
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
- if (in_padata->length == 0) {
- pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
- in_padata->pa_type = KRB5_PADATA_PK_AS_REQ_OLD;
- processing_request = 1;
- } else {
- pkiDebug("processing KRB5_PADATA_PK_AS_REP_OLD\n");
- in_padata->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
- }
- break;
default:
pkiDebug("unrecognized patype = %d for PKINIT\n",
in_padata->pa_type);
@@ -1207,8 +1083,11 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
}
if (processing_request) {
- pkinit_client_profile(context, plgctx, reqctx, cb, rock,
- &request->server->realm);
+ if (reqctx->idopts->anchors == NULL) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ _("No pkinit_anchors supplied"));
+ return KRB5_PREAUTH_FAILED;
+ }
/* Pull in PINs and passwords for identities which we deferred
* loading earlier. */
retval = pkinit_client_parse_answers(context, moddata, modreq,
@@ -1359,7 +1238,7 @@ cleanup:
static int
pkinit_client_get_flags(krb5_context kcontext, krb5_preauthtype patype)
{
- if (patype == KRB5_PADATA_PKINIT_KX)
+ if (patype == KRB5_PADATA_PKINIT_KX || patype == KRB5_PADATA_AS_FRESHNESS)
return PA_INFO;
return PA_REAL;
}
@@ -1373,9 +1252,8 @@ pkinit_client_get_flags(krb5_context kcontext, krb5_preauthtype patype)
static krb5_preauthtype supported_client_pa_types[] = {
KRB5_PADATA_PK_AS_REP,
KRB5_PADATA_PK_AS_REQ,
- KRB5_PADATA_PK_AS_REP_OLD,
- KRB5_PADATA_PK_AS_REQ_OLD,
KRB5_PADATA_PKINIT_KX,
+ KRB5_PADATA_AS_FRESHNESS,
0
};
@@ -1400,6 +1278,7 @@ pkinit_client_req_init(krb5_context context,
reqctx->opts = NULL;
reqctx->idctx = NULL;
reqctx->idopts = NULL;
+ reqctx->freshness_token = NULL;
retval = pkinit_init_req_opts(&reqctx->opts);
if (retval)
@@ -1410,6 +1289,7 @@ pkinit_client_req_init(krb5_context context,
reqctx->opts->dh_or_rsa = plgctx->opts->dh_or_rsa;
reqctx->opts->allow_upn = plgctx->opts->allow_upn;
reqctx->opts->require_crl_checking = plgctx->opts->require_crl_checking;
+ reqctx->opts->disable_freshness = plgctx->opts->disable_freshness;
retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
if (retval)
@@ -1468,6 +1348,8 @@ pkinit_client_req_fini(krb5_context context, krb5_clpreauth_moddata moddata,
if (reqctx->idopts != NULL)
pkinit_fini_identity_opts(reqctx->idopts);
+ krb5_free_data(context, reqctx->freshness_token);
+
free(reqctx);
return;
}
@@ -1580,6 +1462,9 @@ handle_gic_opt(krb5_context context,
pkiDebug("Setting flag to use RSA_PROTOCOL\n");
plgctx->opts->dh_or_rsa = RSA_PROTOCOL;
}
+ } else if (strcmp(attr, "disable_freshness") == 0) {
+ if (strcmp(value, "yes") == 0)
+ plgctx->opts->disable_freshness = 1;
}
return 0;
}
diff --git a/src/plugins/preauth/pkinit/pkinit_constants.c b/src/plugins/preauth/pkinit/pkinit_constants.c
new file mode 100644
index 000000000000..1da482e0b4ab
--- /dev/null
+++ b/src/plugins/preauth/pkinit/pkinit_constants.c
@@ -0,0 +1,325 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* plugins/preauth/pkinit/pkinit_constants.c */
+/*
+ * Copyright (C) 2011,2021 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 "pkinit.h"
+
+/* RFC 8636 id-pkinit-kdf-ah-sha1: iso(1) identified-organization(3) dod(6)
+ * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha1(1) */
+static char sha1_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 };
+/* RFC 8636 id-pkinit-kdf-ah-sha256: iso(1) identified-organization(3) dod(6)
+ * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha256(2) */
+static char sha256_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 };
+/* RFC 8636 id-pkinit-kdf-ah-sha512: iso(1) identified-organization(3) dod(6)
+ * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha512(3) */
+static char sha512_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 };
+
+const krb5_data sha1_id = { KV5M_DATA, sizeof(sha1_oid), sha1_oid };
+const krb5_data sha256_id = { KV5M_DATA, sizeof(sha256_oid), sha256_oid };
+const krb5_data sha512_id = { KV5M_DATA, sizeof(sha512_oid), sha512_oid };
+
+krb5_data const * const supported_kdf_alg_ids[] = {
+ &sha256_id,
+ &sha1_id,
+ &sha512_id,
+ NULL
+};
+
+/* RFC 4055 sha256WithRSAEncryption: iso(1) member-body(2) us(840)
+ * rsadsi(113549) pkcs(1) 1 11 */
+static char sha256WithRSAEncr_oid[9] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
+};
+/* RFC 4055 sha256WithRSAEncryption: iso(1) member-body(2) us(840)
+ * rsadsi(113549) pkcs(1) 1 13 */
+static char sha512WithRSAEncr_oid[9] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d
+};
+
+const krb5_data sha256WithRSAEncr_id = {
+ KV5M_DATA, sizeof(sha256WithRSAEncr_oid), sha256WithRSAEncr_oid
+};
+const krb5_data sha512WithRSAEncr_id = {
+ KV5M_DATA, sizeof(sha512WithRSAEncr_oid), sha512WithRSAEncr_oid
+};
+
+krb5_data const * const supported_cms_algs[] = {
+ &sha512WithRSAEncr_id,
+ &sha256WithRSAEncr_id,
+ NULL
+};
+
+/* RFC 2412 section E.2 (well-known group 2) parameters, DER-encoded as
+ * DomainParameters (RFC 3279 section 2.3.3). */
+static const uint8_t o1024[] = {
+ 0x30, 0x82, 0x01, 0x0A, 0x02, 0x81, 0x81, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x02, 0x01, 0x02, 0x02, 0x81, 0x80, 0x7F, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x87,
+ 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, 0x62, 0x63,
+ 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, 0x94, 0x81,
+ 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, 0x01, 0x05,
+ 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, 0x28, 0xA5,
+ 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, 0xF7, 0xCA,
+ 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, 0x98, 0x15,
+ 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, 0xA7, 0xF0,
+ 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, 0xF2, 0x42,
+ 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, 0x7A, 0x26,
+ 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, 0x85, 0xFF,
+ 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, 0xF7, 0x1C,
+ 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, 0xD7, 0x4F,
+ 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, 0x24, 0x94,
+ 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526 section 3 (2048-bit MODP Group), RFC 3279 encoding */
+static const uint8_t o2048[] = {
+ 0x30, 0x82, 0x02, 0x0C, 0x02, 0x82, 0x01, 0x01,
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2,
+ 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C,
+ 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC,
+ 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B,
+ 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04,
+ 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43,
+ 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14,
+ 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2,
+ 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E,
+ 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED,
+ 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7,
+ 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F,
+ 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F,
+ 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B,
+ 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF,
+ 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3,
+ 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF,
+ 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD,
+ 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52,
+ 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96,
+ 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98,
+ 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21,
+ 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE,
+ 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86,
+ 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2,
+ 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52,
+ 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17,
+ 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A,
+ 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05,
+ 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA,
+ 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x02, 0x01, 0x02, 0x02, 0x82, 0x01, 0x00,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x56, 0x55, 0x34,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526 section 5 (4096-bit MODP Group), RFC 3279 encoding */
+static const uint8_t o4096[] = {
+ 0x30, 0x82, 0x04, 0x0C, 0x02, 0x82, 0x02, 0x01,
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2,
+ 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C,
+ 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC,
+ 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B,
+ 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04,
+ 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43,
+ 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14,
+ 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2,
+ 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E,
+ 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED,
+ 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7,
+ 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F,
+ 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F,
+ 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B,
+ 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF,
+ 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3,
+ 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF,
+ 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD,
+ 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52,
+ 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96,
+ 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98,
+ 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21,
+ 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE,
+ 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86,
+ 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2,
+ 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52,
+ 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17,
+ 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A,
+ 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05,
+ 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4,
+ 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A,
+ 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA,
+ 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF,
+ 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C,
+ 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4,
+ 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33,
+ 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61,
+ 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE,
+ 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08,
+ 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A,
+ 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20,
+ 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D,
+ 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46,
+ 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB,
+ 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10,
+ 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08,
+ 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6,
+ 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B,
+ 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2,
+ 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B,
+ 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C,
+ 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E,
+ 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA,
+ 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0,
+ 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3,
+ 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7,
+ 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7,
+ 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48,
+ 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A,
+ 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD,
+ 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0,
+ 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31,
+ 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x02, 0x01, 0x02, 0x02, 0x82, 0x02, 0x00,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+ 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+ 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+ 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+ 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+ 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+ 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+ 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+ 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+ 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+ 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+ 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+ 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+ 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+ 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+ 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+ 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x03, 0x18, 0xCC,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+const krb5_data oakley_1024 = { KV5M_DATA, sizeof(o1024), (char *)o1024 };
+const krb5_data oakley_2048 = { KV5M_DATA, sizeof(o2048), (char *)o2048 };
+const krb5_data oakley_4096 = { KV5M_DATA, sizeof(o4096), (char *)o4096 };
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 2d3733bbc8dd..e22798f668b6 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -46,7 +46,6 @@
*/
enum cms_msg_types {
CMS_SIGN_CLIENT,
- CMS_SIGN_DRAFT9,
CMS_SIGN_SERVER,
CMS_ENVEL_SERVER
};
@@ -97,8 +96,8 @@ typedef struct _pkinit_cert_matching_data {
char *issuer_dn; /* rfc2253-style issuer name string */
unsigned int ku_bits; /* key usage information */
unsigned int eku_bits; /* extended key usage information */
- krb5_principal *sans; /* Null-terminated array of subject alternative
- name info (pkinit and ms-upn) */
+ krb5_principal *sans; /* Null-terminated array of PKINIT SANs */
+ char **upns; /* Null-terimnated array of UPN SANs */
} pkinit_cert_matching_data;
/*
@@ -133,9 +132,6 @@ krb5_error_code cms_signeddata_create
int cms_msg_type, /* IN
specifies CMS_SIGN_CLIENT for client-side CMS message
and CMS_SIGN_SERVER for kdc-side */
- int include_certchain, /* IN
- specifies where certificates field in SignedData
- should contain certificate path */
unsigned char *auth_pack, /* IN
contains DER encoded AuthPack (CMS_SIGN_CLIENT)
or DER encoded DHRepInfo (CMS_SIGN_SERVER) */
@@ -193,9 +189,6 @@ krb5_error_code cms_envelopeddata_create
pkinit_req_crypto_context req_cryptoctx, /* IN */
pkinit_identity_crypto_context id_cryptoctx, /* IN */
krb5_preauthtype pa_type, /* IN */
- int include_certchain, /* IN
- specifies whether the certificates field in
- SignedData should contain certificate path */
unsigned char *key_pack, /* IN
contains DER encoded ReplyKeyPack */
unsigned int key_pack_len, /* IN
@@ -250,7 +243,7 @@ krb5_error_code crypto_retrieve_cert_sans
if non-NULL, a null-terminated array of
id-pkinit-san values found in the certificate
are returned */
- krb5_principal **upn_sans, /* OUT
+ char ***upn_sans, /* OUT
if non-NULL, a null-terminated array of
id-ms-upn-san values found in the certificate
are returned */
@@ -316,14 +309,8 @@ krb5_error_code client_create_dh
pkinit_identity_crypto_context id_cryptoctx, /* IN */
int dh_size, /* IN
specifies the DH modulous, eg 1024, 2048, or 4096 */
- unsigned char **dh_paramas, /* OUT
- contains DER encoded DH params */
- unsigned int *dh_params_len, /* OUT
- contains length of dh_parmas */
- unsigned char **dh_pubkey, /* OUT
- receives DER encoded DH pub key */
- unsigned int *dh_pubkey_len); /* OUT
- receives length of dh_pubkey */
+ krb5_data *spki_out); /* OUT
+ receives SubjectPublicKeyInfo encoding */
/*
* this function completes client's the DH protocol. client
@@ -339,10 +326,10 @@ krb5_error_code client_process_dh
contains client's DER encoded DH pub key */
unsigned int dh_pubkey_len, /* IN
contains length of dh_pubkey */
- unsigned char **dh_session_key, /* OUT
+ unsigned char **client_key_out, /* OUT
receives DH secret key */
- unsigned int *dh_session_key_len); /* OUT
- receives length of dh_session_key */
+ unsigned int *client_key_len_out); /* OUT
+ receives length of DH secret key */
/*
* this function implements the KDC first part of the DH protocol.
@@ -354,10 +341,10 @@ krb5_error_code server_check_dh
pkinit_plg_crypto_context plg_cryptoctx, /* IN */
pkinit_req_crypto_context req_cryptoctx, /* IN */
pkinit_identity_crypto_context id_cryptoctx, /* IN */
- krb5_data *dh_params, /* IN
- ???? */
+ const krb5_data *client_spki, /* IN
+ SubjectPublicKeyInfo encoding from client */
int minbits); /* IN
- the mininum number of key bits acceptable */
+ the minimum number of key bits acceptable */
/*
* this function completes the KDC's DH protocol. The KDC generates
@@ -368,18 +355,14 @@ krb5_error_code server_process_dh
pkinit_plg_crypto_context plg_cryptoctx, /* IN */
pkinit_req_crypto_context req_cryptoctx, /* IN */
pkinit_identity_crypto_context id_cryptoctx, /* IN */
- unsigned char *received_pubkey, /* IN
- contains client's DER encoded DH pub key */
- unsigned int received_pub_len, /* IN
- contains length of received_pubkey */
- unsigned char **dh_pubkey, /* OUT
+ unsigned char **dh_pubkey_out, /* OUT
receives KDC's DER encoded DH pub key */
- unsigned int *dh_pubkey_len, /* OUT
+ unsigned int *dh_pubkey_len_out, /* OUT
receives length of dh_pubkey */
- unsigned char **server_key, /* OUT
+ unsigned char **server_key_out, /* OUT
receives DH secret key */
- unsigned int *server_key_len); /* OUT
- receives length of server_key */
+ unsigned int *server_key_len_out); /* OUT
+ receives length of DH secret key */
/*
* this functions takes in crypto specific representation of
@@ -617,12 +600,13 @@ pkinit_alg_agility_kdf(krb5_context context,
krb5_data *pk_as_rep,
krb5_keyblock *key_block);
-extern const krb5_octet krb5_pkinit_sha1_oid[];
-extern const size_t krb5_pkinit_sha1_oid_len;
-extern const krb5_octet krb5_pkinit_sha256_oid[];
-extern const size_t krb5_pkinit_sha256_oid_len;
-extern const krb5_octet krb5_pkinit_sha512_oid[];
-extern const size_t krb5_pkinit_sha512_oid_len;
+extern const krb5_data sha1_id;
+extern const krb5_data sha256_id;
+extern const krb5_data sha512_id;
+extern const krb5_data oakley_1024;
+extern const krb5_data oakley_2048;
+extern const krb5_data oakley_4096;
+
/**
* An ordered set of OIDs, stored as krb5_data, of KDF algorithms
* supported by this implementation. The order of this array controls
@@ -630,6 +614,10 @@ extern const size_t krb5_pkinit_sha512_oid_len;
*/
extern krb5_data const * const supported_kdf_alg_ids[];
+/* CMS signature algorithms supported by this implementation, in order of
+ * decreasing preference. */
+extern krb5_data const * const supported_cms_algs[];
+
krb5_error_code
crypto_encode_der_cert(krb5_context context, pkinit_req_crypto_context reqctx,
uint8_t **der_out, size_t *der_len);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index ac107c2c1b67..f41328763ec6 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -29,13 +29,21 @@
* SUCH DAMAGES.
*/
+#include "k5-int.h"
#include "pkinit_crypto_openssl.h"
#include "k5-buf.h"
-#include <dlfcn.h>
+#include "k5-err.h"
+#include "k5-hex.h"
#include <unistd.h>
#include <dirent.h>
#include <arpa/inet.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#include <openssl/kdf.h>
+#include <openssl/params.h>
+#endif
+
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
@@ -48,11 +56,6 @@ static void pkinit_fini_certs(pkinit_identity_crypto_context ctx);
static krb5_error_code pkinit_init_pkcs11(pkinit_identity_crypto_context ctx);
static void pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx);
-static krb5_error_code pkinit_encode_dh_params
-(const BIGNUM *, const BIGNUM *, const BIGNUM *, uint8_t **, unsigned int *);
-static DH *decode_dh_params(const uint8_t *, unsigned int );
-static int pkinit_check_dh_params(DH *dh1, DH *dh2);
-
static krb5_error_code pkinit_sign_data
(krb5_context context, pkinit_identity_crypto_context cryptoctx,
unsigned char *data, unsigned int data_len,
@@ -79,12 +82,8 @@ static int openssl_callback (int, X509_STORE_CTX *);
static int openssl_callback_ignore_crls (int, X509_STORE_CTX *);
static int pkcs7_decrypt
-(krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
- PKCS7 *p7, BIO *bio);
-
-static BIO * pkcs7_dataDecode
-(krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
- PKCS7 *p7);
+(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7,
+ unsigned char **data_out, unsigned int *len_out);
static ASN1_OBJECT * pkinit_pkcs7type2oid
(pkinit_plg_crypto_context plg_cryptoctx, int pkcs7_type);
@@ -104,8 +103,6 @@ static krb5_error_code pkinit_login
CK_TOKEN_INFO *tip, const char *password);
static krb5_error_code pkinit_open_session
(krb5_context context, pkinit_identity_crypto_context id_cryptoctx);
-static void * pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p);
-static CK_RV pkinit_C_UnloadModule(void *handle);
#ifdef SILLYDECRYPT
CK_RV pkinit_C_Decrypt
(pkinit_identity_crypto_context id_cryptoctx,
@@ -146,46 +143,9 @@ static int
wrap_signeddata(unsigned char *data, unsigned int data_len,
unsigned char **out, unsigned int *out_len);
-static char *
-pkinit_pkcs11_code_to_text(int err);
-
+static const char *
+pkcs11err(int err);
-#ifdef HAVE_OPENSSL_CMS
-/* Use CMS support present in OpenSSL. */
-#include <openssl/cms.h>
-#define pkinit_CMS_get0_content_signed(_cms) CMS_get0_content(_cms)
-#define pkinit_CMS_get0_content_data(_cms) CMS_get0_content(_cms)
-#define pkinit_CMS_free1_crls(_sk_x509crl) \
- sk_X509_CRL_pop_free((_sk_x509crl), X509_CRL_free)
-#define pkinit_CMS_free1_certs(_sk_x509) \
- sk_X509_pop_free((_sk_x509), X509_free)
-#define pkinit_CMS_SignerInfo_get_cert(_cms,_si,_x509_pp) \
- CMS_SignerInfo_get0_algs(_si,NULL,_x509_pp,NULL,NULL)
-#else
-/* Fake up CMS support using PKCS7. */
-#define pkinit_CMS_free1_crls(_stack_of_x509crls) /* Don't free these */
-#define pkinit_CMS_free1_certs(_stack_of_x509certs) /* Don't free these */
-#define CMS_NO_SIGNER_CERT_VERIFY PKCS7_NOVERIFY
-#define CMS_NOATTR PKCS7_NOATTR
-#define CMS_ContentInfo PKCS7
-#define CMS_SignerInfo PKCS7_SIGNER_INFO
-#define d2i_CMS_ContentInfo d2i_PKCS7
-#define CMS_get0_type(_p7) ((_p7)->type)
-#define pkinit_CMS_get0_content_signed(_p7) (&((_p7)->d.sign->contents->d.other->value.octet_string))
-#define pkinit_CMS_get0_content_data(_p7) (&((_p7)->d.other->value.octet_string))
-#define CMS_set1_signers_certs(_p7,_stack_of_x509,_uint)
-#define CMS_get0_SignerInfos PKCS7_get_signer_info
-#define stack_st_CMS_SignerInfo stack_st_PKCS7_SIGNER_INFO
-#undef sk_CMS_SignerInfo_value
-#define sk_CMS_SignerInfo_value sk_PKCS7_SIGNER_INFO_value
-#define CMS_get0_eContentType(_p7) (_p7->d.sign->contents->type)
-#define CMS_verify PKCS7_verify
-#define CMS_get1_crls(_p7) (_p7->d.sign->crl)
-#define CMS_get1_certs(_p7) (_p7->d.sign->cert)
-#define CMS_ContentInfo_free(_p7) PKCS7_free(_p7)
-#define pkinit_CMS_SignerInfo_get_cert(_p7,_si,_x509_pp) \
- (*_x509_pp) = PKCS7_cert_from_signer_info(_p7,_si)
-#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -196,35 +156,34 @@ pkinit_pkcs11_code_to_text(int err);
#define EVP_MD_CTX_free EVP_MD_CTX_destroy
#define ASN1_STRING_get0_data ASN1_STRING_data
+/*
+ * 1.1 adds DHX support, which uses the RFC 3279 DomainParameters encoding we
+ * need for PKINIT. For 1.0 we must use the original DH type when creating
+ * EVP_PKEY objects.
+ */
+#define EVP_PKEY_DHX EVP_PKEY_DH
+
/* 1.1 makes many handle types opaque and adds accessors. Add compatibility
* versions of the new accessors we use for pre-1.1. */
#define OBJ_get0_data(o) ((o)->data)
#define OBJ_length(o) ((o)->length)
-#define DH_set0_pqg compat_dh_set0_pqg
-static int compat_dh_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+#define DH_set0_key compat_dh_set0_key
+static int
+compat_dh_set0_key(DH *dh, BIGNUM *pub, BIGNUM *priv)
{
- /* The real function frees the old values and does argument checking, but
- * our code doesn't need that. */
- dh->p = p;
- dh->q = q;
- dh->g = g;
+ if (pub != NULL) {
+ BN_clear_free(dh->pub_key);
+ dh->pub_key = pub;
+ }
+ if (priv != NULL) {
+ BN_clear_free(dh->priv_key);
+ dh->priv_key = priv;
+ }
return 1;
}
-#define DH_get0_pqg compat_dh_get0_pqg
-static void compat_dh_get0_pqg(const DH *dh, const BIGNUM **p,
- const BIGNUM **q, const BIGNUM **g)
-{
- if (p != NULL)
- *p = dh->p;
- if (q != NULL)
- *q = dh->q;
- if (g != NULL)
- *g = dh->g;
-}
-
#define DH_get0_key compat_dh_get0_key
static void compat_dh_get0_key(const DH *dh, const BIGNUM **pub,
const BIGNUM **priv)
@@ -235,6 +194,16 @@ static void compat_dh_get0_key(const DH *dh, const BIGNUM **pub,
*priv = dh->priv_key;
}
+#define EVP_PKEY_get0_DH compat_get0_DH
+static DH *
+compat_get0_DH(const EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_DH)
+ return NULL;
+ return pkey->pkey.dh;
+
+}
+
/* Return true if the cert c includes a key usage which doesn't include u.
* Define using direct member access for pre-1.1. */
#define ku_reject(c, u) \
@@ -247,6 +216,581 @@ static void compat_dh_get0_key(const DH *dh, const BIGNUM **pub,
#endif
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+/* OpenSSL 3.0 changes several preferred function names. */
+#define EVP_PKEY_parameters_eq EVP_PKEY_cmp_parameters
+#define EVP_MD_CTX_get0_md EVP_MD_CTX_md
+#define EVP_PKEY_get_size EVP_PKEY_size
+#define EVP_PKEY_get_bits EVP_PKEY_bits
+
+/*
+ * Convert *dh to an EVP_PKEY object, taking ownership of *dh and setting it to
+ * NULL. On error, return NULL and do not take ownership of or change *dh.
+ * OpenSSL 3.0 deprecates the low-level DH interfaces, so this helper will only
+ * be used with prior versions.
+ */
+static EVP_PKEY *
+dh_to_pkey(DH **dh)
+{
+ EVP_PKEY *pkey;
+
+ pkey = EVP_PKEY_new();
+ if (pkey == NULL)
+ return NULL;
+ if (!EVP_PKEY_assign(pkey, EVP_PKEY_DHX, *dh)) {
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ *dh = NULL;
+ return pkey;
+}
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
+/* Encode a bignum as an ASN.1 integer in DER. */
+static int
+encode_bn_der(const BIGNUM *bn, uint8_t **der_out, int *len_out)
+{
+ ASN1_INTEGER *intval;
+ int len;
+ uint8_t *der = NULL, *outptr;
+
+ intval = BN_to_ASN1_INTEGER(bn, NULL);
+ if (intval == NULL)
+ return 0;
+ len = i2d_ASN1_INTEGER(intval, NULL);
+ if (len > 0 && (outptr = der = malloc(len)) != NULL)
+ (void)i2d_ASN1_INTEGER(intval, &outptr);
+ ASN1_INTEGER_free(intval);
+ if (der == NULL)
+ return 0;
+ *der_out = der;
+ *len_out = len;
+ return 1;
+}
+
+/* Decode an ASN.1 integer, returning a bignum. */
+static BIGNUM *
+decode_bn_der(const uint8_t *der, size_t len)
+{
+ ASN1_INTEGER *intval;
+ BIGNUM *bn;
+
+ intval = d2i_ASN1_INTEGER(NULL, &der, len);
+ if (intval == NULL)
+ return NULL;
+ bn = ASN1_INTEGER_to_BN(intval, NULL);
+ ASN1_INTEGER_free(intval);
+ return bn;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+static int
+params_valid(EVP_PKEY *params)
+{
+ EVP_PKEY_CTX *ctx;
+ int result;
+
+ ctx = EVP_PKEY_CTX_new(params, NULL);
+ if (ctx == NULL)
+ return 0;
+ result = EVP_PKEY_param_check(ctx);
+ EVP_PKEY_CTX_free(ctx);
+ return result == 1;
+}
+#else
+static int
+params_valid(EVP_PKEY *params)
+{
+ DH *dh;
+ int codes;
+
+ dh = EVP_PKEY_get0_DH(params);
+ return (dh == NULL) ? 0 : (DH_check(dh, &codes) && codes == 0);
+}
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static EVP_PKEY *
+decode_dh_params(const krb5_data *params_der)
+{
+ EVP_PKEY *pkey = NULL;
+ const uint8_t *inptr = (uint8_t *)params_der->data;
+ size_t len = params_der->length;
+ OSSL_DECODER_CTX *dctx;
+ int ok;
+
+ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "type-specific", "DHX",
+ EVP_PKEY_KEY_PARAMETERS, NULL, NULL);
+ if (dctx == NULL)
+ return NULL;
+
+ ok = OSSL_DECODER_from_data(dctx, &inptr, &len);
+ OSSL_DECODER_CTX_free(dctx);
+ return ok ? pkey : NULL;
+}
+#else
+static EVP_PKEY *
+decode_dh_params(const krb5_data *params_der)
+{
+ const uint8_t *p = (uint8_t *)params_der->data;
+ DH *dh;
+ EVP_PKEY *pkey;
+
+ dh = d2i_DHxparams(NULL, &p, params_der->length);
+ pkey = dh_to_pkey(&dh);
+ DH_free(dh);
+ return pkey;
+}
+#endif
+
+static krb5_error_code
+encode_spki(EVP_PKEY *pkey, krb5_data *spki_out)
+{
+ krb5_error_code ret = ENOMEM;
+ int len;
+ uint8_t *outptr;
+
+ len = i2d_PUBKEY(pkey, NULL);
+ ret = alloc_data(spki_out, len);
+ if (ret)
+ goto cleanup;
+ outptr = (uint8_t *)spki_out->data;
+ (void)i2d_PUBKEY(pkey, &outptr);
+
+cleanup:
+ return ret;
+}
+
+static EVP_PKEY *
+decode_spki(const krb5_data *spki)
+{
+ const uint8_t *inptr = (uint8_t *)spki->data;
+
+ return d2i_PUBKEY(NULL, &inptr, spki->length);
+}
+
+#else /* OPENSSL_VERSION_NUMBER < 0x10100000L */
+
+/*
+ * OpenSSL 1.0 has no DHX support, so we need a custom decoder for RFC 3279
+ * DomainParameters, and we need to use X509_PUBKEY values to marshal
+ * SubjectPublicKeyInfo.
+ */
+
+typedef struct {
+ ASN1_BIT_STRING *seed;
+ BIGNUM *counter;
+} int_dhvparams;
+
+typedef struct {
+ BIGNUM *p;
+ BIGNUM *q;
+ BIGNUM *g;
+ BIGNUM *j;
+ int_dhvparams *vparams;
+} int_dhxparams;
+
+ASN1_SEQUENCE(int_dhvparams) = {
+ ASN1_SIMPLE(int_dhvparams, seed, ASN1_BIT_STRING),
+ ASN1_SIMPLE(int_dhvparams, counter, BIGNUM)
+} ASN1_SEQUENCE_END(int_dhvparams);
+
+ASN1_SEQUENCE(int_dhxparams) = {
+ ASN1_SIMPLE(int_dhxparams, p, BIGNUM),
+ ASN1_SIMPLE(int_dhxparams, g, BIGNUM),
+ ASN1_SIMPLE(int_dhxparams, q, BIGNUM),
+ ASN1_OPT(int_dhxparams, j, BIGNUM),
+ ASN1_OPT(int_dhxparams, vparams, int_dhvparams)
+} ASN1_SEQUENCE_END(int_dhxparams);
+
+static EVP_PKEY *
+decode_dh_params(const krb5_data *params_der)
+{
+ int_dhxparams *params;
+ DH *dh;
+ EVP_PKEY *pkey;
+ const uint8_t *p;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ p = (uint8_t *)params_der->data;
+ params = (int_dhxparams *)ASN1_item_d2i(NULL, &p, params_der->length,
+ ASN1_ITEM_rptr(int_dhxparams));
+ if (params == NULL) {
+ DH_free(dh);
+ return NULL;
+ }
+
+ /* Steal p, q, and g from dhparams for dh. Ignore j and vparams. */
+ dh->p = params->p;
+ dh->q = params->q;
+ dh->g = params->g;
+ params->p = params->q = params->g = NULL;
+ ASN1_item_free((ASN1_VALUE *)params, ASN1_ITEM_rptr(int_dhxparams));
+ pkey = dh_to_pkey(&dh);
+ DH_free(dh);
+ return pkey;
+}
+
+static krb5_error_code
+encode_spki(EVP_PKEY *pkey, krb5_data *spki_out)
+{
+ krb5_error_code ret = ENOMEM;
+ const DH *dh;
+ uint8_t *param_der = NULL, *pubkey_der = NULL, *outptr;
+ int param_der_len, pubkey_der_len, len;
+ X509_PUBKEY pubkey;
+ int_dhxparams dhxparams;
+ X509_ALGOR algor;
+ ASN1_OBJECT algorithm;
+ ASN1_TYPE parameter;
+ ASN1_STRING param_str, pubkey_str;
+
+ dh = EVP_PKEY_get0_DH(pkey);
+ if (dh == NULL)
+ goto cleanup;
+
+ dhxparams.p = dh->p;
+ dhxparams.q = dh->q;
+ dhxparams.g = dh->g;
+ dhxparams.j = NULL;
+ dhxparams.vparams = NULL;
+ param_der_len = ASN1_item_i2d((ASN1_VALUE *)&dhxparams, &param_der,
+ ASN1_ITEM_rptr(int_dhxparams));
+ if (param_der_len < 0)
+ goto cleanup;
+ param_str.length = param_der_len;
+ param_str.type = V_ASN1_SEQUENCE;
+ param_str.data = param_der;
+ param_str.flags = 0;
+ parameter.type = V_ASN1_SEQUENCE;
+ parameter.value.sequence = &param_str;
+
+ memset(&algorithm, 0, sizeof(algorithm));
+ algorithm.data = (uint8_t *)dh_oid.data;
+ algorithm.length = dh_oid.length;
+
+ algor.algorithm = &algorithm;
+ algor.parameter = &parameter;
+
+ if (!encode_bn_der(dh->pub_key, &pubkey_der, &pubkey_der_len))
+ goto cleanup;
+ pubkey_str.length = pubkey_der_len;
+ pubkey_str.type = V_ASN1_BIT_STRING;
+ pubkey_str.data = pubkey_der;
+ pubkey_str.flags = ASN1_STRING_FLAG_BITS_LEFT;
+
+ pubkey.algor = &algor;
+ pubkey.public_key = &pubkey_str;
+ len = i2d_X509_PUBKEY(&pubkey, NULL);
+ if (len < 0)
+ goto cleanup;
+ ret = alloc_data(spki_out, len);
+ if (ret)
+ goto cleanup;
+ outptr = (uint8_t *)spki_out->data;
+ i2d_X509_PUBKEY(&pubkey, &outptr);
+
+cleanup:
+ OPENSSL_free(param_der);
+ free(pubkey_der);
+ return ret;
+}
+
+static EVP_PKEY *
+decode_spki(const krb5_data *spki)
+{
+ X509_PUBKEY *pubkey = NULL;
+ const uint8_t *inptr;
+ DH *dh;
+ EVP_PKEY *pkey = NULL, *pkey_ret = NULL;
+ const ASN1_STRING *params;
+ const ASN1_BIT_STRING *public_key;
+ krb5_data d;
+
+ inptr = (uint8_t *)spki->data;
+ pubkey = d2i_X509_PUBKEY(NULL, &inptr, spki->length);
+ if (pubkey == NULL)
+ goto cleanup;
+
+ if (pubkey->algor->parameter->type != V_ASN1_SEQUENCE)
+ goto cleanup;
+ params = pubkey->algor->parameter->value.sequence;
+ d = make_data(params->data, params->length);
+ pkey = decode_dh_params(&d);
+ if (pkey == NULL)
+ goto cleanup;
+ dh = EVP_PKEY_get0_DH(pkey);
+ if (dh == NULL)
+ goto cleanup;
+ public_key = pubkey->public_key;
+ dh->pub_key = decode_bn_der(public_key->data, public_key->length);
+ if (dh->pub_key == NULL)
+ goto cleanup;
+
+ pkey_ret = pkey;
+ pkey = NULL;
+
+cleanup:
+ X509_PUBKEY_free(pubkey);
+ EVP_PKEY_free(pkey);
+ return pkey_ret;
+}
+
+#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
+
+/* Attempt to specify padded Diffie-Hellman result derivation. Don't error out
+ * if this fails since we also detect short results and adjust them. */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static void
+set_padded_derivation(EVP_PKEY_CTX *ctx)
+{
+ EVP_PKEY_CTX_set_dh_pad(ctx, 1);
+}
+#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
+static void
+set_padded_derivation(EVP_PKEY_CTX *ctx)
+{
+ /* We would use EVP_PKEY_CTX_set_dh_pad() but it doesn't work with DHX. */
+ EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
+ EVP_PKEY_CTRL_DH_PAD, 1, NULL);
+}
+#else
+static void
+set_padded_derivation(EVP_PKEY_CTX *ctx)
+{
+ /* There's no support for padded derivation in 1.0. */
+}
+#endif
+
+static int
+dh_result(EVP_PKEY *pkey, EVP_PKEY *peer,
+ uint8_t **result_out, unsigned int *len_out)
+{
+ EVP_PKEY_CTX *derive_ctx = NULL;
+ int ok = 0;
+ uint8_t *buf = NULL;
+ size_t len, dh_size = EVP_PKEY_get_size(pkey);
+
+ *result_out = NULL;
+ *len_out = 0;
+
+ derive_ctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (derive_ctx == NULL)
+ goto cleanup;
+ if (EVP_PKEY_derive_init(derive_ctx) <= 0)
+ goto cleanup;
+ set_padded_derivation(derive_ctx);
+ if (EVP_PKEY_derive_set_peer(derive_ctx, peer) <= 0)
+ goto cleanup;
+
+ buf = malloc(dh_size);
+ if (buf == NULL)
+ goto cleanup;
+ len = dh_size;
+ if (EVP_PKEY_derive(derive_ctx, buf, &len) <= 0)
+ goto cleanup;
+ if (len < dh_size) { /* only possible without padded derivation */
+ memmove(buf + (dh_size - len), buf, len);
+ memset(buf, 0, dh_size - len);
+ }
+
+ ok = 1;
+ *result_out = buf;
+ *len_out = dh_size;
+ buf = NULL;
+
+cleanup:
+ EVP_PKEY_CTX_free(derive_ctx);
+ free(buf);
+ return ok;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static int
+dh_pubkey_der(EVP_PKEY *pkey, uint8_t **pubkey_out, unsigned int *len_out)
+{
+ BIGNUM *pubkey_bn = NULL;
+ int len, ok;
+ uint8_t *buf;
+
+ if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pubkey_bn))
+ return 0;
+ ok = encode_bn_der(pubkey_bn, &buf, &len);
+ BN_free(pubkey_bn);
+ if (ok) {
+ *pubkey_out = buf;
+ *len_out = len;
+ }
+ return ok;
+}
+#else
+static int
+dh_pubkey_der(EVP_PKEY *pkey, uint8_t **pubkey_out, unsigned int *len_out)
+{
+ const DH *dh;
+ const BIGNUM *pubkey_bn;
+ uint8_t *buf;
+ int len;
+
+ dh = EVP_PKEY_get0_DH(pkey);
+ if (dh == NULL)
+ return 0;
+ DH_get0_key(dh, &pubkey_bn, NULL);
+ if (!encode_bn_der(pubkey_bn, &buf, &len))
+ return 0;
+ *pubkey_out = buf;
+ *len_out = len;
+ return 1;
+}
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+/* OpenSSL 1.1 and later will copy the q parameter when generating keys. */
+static int
+copy_q_openssl10(EVP_PKEY *src, EVP_PKEY *dest)
+{
+ return 1;
+}
+#else
+/* OpenSSL 1.0 won't copy the q parameter, so we have to do it. */
+static int
+copy_q_openssl10(EVP_PKEY *src, EVP_PKEY *dest)
+{
+ DH *dhsrc = EVP_PKEY_get0_DH(src), *dhdest = EVP_PKEY_get0_DH(dest);
+
+ if (dhsrc == NULL || dhsrc->q == NULL || dhdest == NULL)
+ return 0;
+ if (dhdest->q != NULL)
+ return 1;
+ dhdest->q = BN_dup(dhsrc->q);
+ return dhdest->q != NULL;
+}
+#endif
+
+static EVP_PKEY *
+generate_dh_pkey(EVP_PKEY *params)
+{
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ ctx = EVP_PKEY_CTX_new(params, NULL);
+ if (ctx == NULL)
+ goto cleanup;
+ if (EVP_PKEY_keygen_init(ctx) <= 0)
+ goto cleanup;
+ if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
+ goto cleanup;
+ if (!copy_q_openssl10(params, pkey)) {
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+
+cleanup:
+ EVP_PKEY_CTX_free(ctx);
+ return pkey;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+static EVP_PKEY *
+compose_dh_pkey(EVP_PKEY *params, const uint8_t *pubkey_der, size_t der_len)
+{
+ EVP_PKEY *pkey = NULL, *pkey_ret = NULL;
+ BIGNUM *pubkey_bn = NULL;
+ uint8_t *pubkey_bin = NULL;
+ int binlen;
+
+ pkey = EVP_PKEY_dup(params);
+ if (pkey == NULL)
+ goto cleanup;
+
+ pubkey_bn = decode_bn_der(pubkey_der, der_len);
+ if (pubkey_bn == NULL)
+ goto cleanup;
+ binlen = EVP_PKEY_get_size(pkey);
+ pubkey_bin = malloc(binlen);
+ if (pubkey_bin == NULL)
+ goto cleanup;
+ if (BN_bn2binpad(pubkey_bn, pubkey_bin, binlen) != binlen)
+ goto cleanup;
+ if (EVP_PKEY_set1_encoded_public_key(pkey, pubkey_bin, binlen) != 1)
+ goto cleanup;
+
+ pkey_ret = pkey;
+ pkey = NULL;
+
+cleanup:
+ EVP_PKEY_free(pkey);
+ BN_free(pubkey_bn);
+ free(pubkey_bin);
+ return pkey_ret;
+}
+
+#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+static DH *
+dup_dh_params(DH *src)
+{
+ return DHparams_dup(src);
+}
+#else
+/* DHparams_dup() won't copy q in OpenSSL 1.0. */
+static DH *
+dup_dh_params(DH *src)
+{
+ DH *dh;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+ dh->p = BN_dup(src->p);
+ dh->q = BN_dup(src->q);
+ dh->g = BN_dup(src->g);
+ if (dh->p == NULL || dh->q == NULL || dh->g == NULL) {
+ DH_free(dh);
+ return NULL;
+ }
+ return dh;
+}
+#endif
+
+static EVP_PKEY *
+compose_dh_pkey(EVP_PKEY *params, const uint8_t *pubkey_der, size_t der_len)
+{
+ DH *dhparams, *dh = NULL;
+ EVP_PKEY *pkey = NULL;
+ BIGNUM *pubkey_bn = NULL;
+
+ pubkey_bn = decode_bn_der(pubkey_der, der_len);
+ if (pubkey_bn == NULL)
+ goto cleanup;
+
+ dhparams = EVP_PKEY_get0_DH(params);
+ if (dhparams == NULL)
+ goto cleanup;
+ dh = dup_dh_params(dhparams);
+ if (dh == NULL)
+ goto cleanup;
+ if (!DH_set0_key(dh, pubkey_bn, NULL))
+ goto cleanup;
+ pubkey_bn = NULL;
+
+ pkey = dh_to_pkey(&dh);
+
+cleanup:
+ BN_free(pubkey_bn);
+ DH_free(dh);
+ return pkey;
+}
+
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
static struct pkcs11_errstrings {
short code;
char *text;
@@ -339,128 +883,6 @@ static struct pkcs11_errstrings {
{ -1, NULL }
};
-/* DH parameters */
-static uint8_t oakley_1024[128] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
- 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
- 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
- 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
- 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
- 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
- 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
- 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
- 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
- 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
- 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
- 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
- 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
- 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-static uint8_t oakley_2048[2048/8] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
- 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
- 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
- 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
- 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
- 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
- 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
- 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
- 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
- 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
- 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
- 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
- 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
- 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
- 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
- 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
- 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
- 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
- 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
- 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
- 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
- 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
- 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
- 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
- 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
- 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
- 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
- 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
- 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
- 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-static uint8_t oakley_4096[4096/8] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
- 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
- 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
- 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
- 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
- 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
- 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
- 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
- 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
- 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
- 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
- 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
- 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
- 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
- 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
- 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
- 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
- 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
- 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
- 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
- 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
- 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
- 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
- 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
- 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
- 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
- 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
- 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
- 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
- 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
- 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
- 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
- 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
- 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
- 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
- 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
- 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
- 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
- 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
- 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
- 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
- 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
- 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
- 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
- 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
- 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
- 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
- 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
- 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
- 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
- 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
- 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
- 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
- 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
- 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
- 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
- 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
- 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
- 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
- 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
- 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
- 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
MAKE_INIT_FUNCTION(pkinit_openssl_init);
static krb5_error_code oerr(krb5_context context, krb5_error_code code,
@@ -631,7 +1053,8 @@ pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
goto out;
memset(ctx, 0, sizeof(*ctx));
- ctx->dh = NULL;
+ ctx->client_pkey = NULL;
+ ctx->received_params = NULL;
ctx->received_cert = NULL;
*cryptoctx = ctx;
@@ -652,10 +1075,9 @@ pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
return;
pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, req_cryptoctx);
- if (req_cryptoctx->dh != NULL)
- DH_free(req_cryptoctx->dh);
- if (req_cryptoctx->received_cert != NULL)
- X509_free(req_cryptoctx->received_cert);
+ EVP_PKEY_free(req_cryptoctx->client_pkey);
+ EVP_PKEY_free(req_cryptoctx->received_params);
+ X509_free(req_cryptoctx->received_cert);
free(req_cryptoctx);
}
@@ -856,54 +1278,20 @@ pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
ASN1_OBJECT_free(ctx->id_kp_serverAuth);
}
-/* Construct an OpenSSL DH object for an Oakley group. */
-static DH *
-make_oakley_dh(uint8_t *prime, size_t len)
-{
- DH *dh = NULL;
- BIGNUM *p = NULL, *q = NULL, *g = NULL;
-
- p = BN_bin2bn(prime, len, NULL);
- if (p == NULL)
- goto cleanup;
- q = BN_new();
- if (q == NULL)
- goto cleanup;
- if (!BN_rshift1(q, p))
- goto cleanup;
- g = BN_new();
- if (g == NULL)
- goto cleanup;
- if (!BN_set_word(g, DH_GENERATOR_2))
- goto cleanup;
-
- dh = DH_new();
- if (dh == NULL)
- goto cleanup;
- DH_set0_pqg(dh, p, q, g);
- p = g = q = NULL;
-
-cleanup:
- BN_free(p);
- BN_free(q);
- BN_free(g);
- return dh;
-}
-
static krb5_error_code
pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
{
krb5_error_code retval = ENOMEM;
- plgctx->dh_1024 = make_oakley_dh(oakley_1024, sizeof(oakley_1024));
+ plgctx->dh_1024 = decode_dh_params(&oakley_1024);
if (plgctx->dh_1024 == NULL)
goto cleanup;
- plgctx->dh_2048 = make_oakley_dh(oakley_2048, sizeof(oakley_2048));
+ plgctx->dh_2048 = decode_dh_params(&oakley_2048);
if (plgctx->dh_2048 == NULL)
goto cleanup;
- plgctx->dh_4096 = make_oakley_dh(oakley_4096, sizeof(oakley_4096));
+ plgctx->dh_4096 = decode_dh_params(&oakley_4096);
if (plgctx->dh_4096 == NULL)
goto cleanup;
@@ -919,13 +1307,9 @@ cleanup:
static void
pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
{
- if (plgctx->dh_1024 != NULL)
- DH_free(plgctx->dh_1024);
- if (plgctx->dh_2048 != NULL)
- DH_free(plgctx->dh_2048);
- if (plgctx->dh_4096 != NULL)
- DH_free(plgctx->dh_4096);
-
+ EVP_PKEY_free(plgctx->dh_1024);
+ EVP_PKEY_free(plgctx->dh_2048);
+ EVP_PKEY_free(plgctx->dh_4096);
plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
}
@@ -1008,7 +1392,7 @@ pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
ctx->p11 = NULL;
}
if (ctx->p11_module != NULL) {
- pkinit_C_UnloadModule(ctx->p11_module);
+ krb5int_close_plugin(ctx->p11_module);
ctx->p11_module = NULL;
}
free(ctx->p11_module_name);
@@ -1052,17 +1436,11 @@ create_contentinfo(krb5_context context, ASN1_OBJECT *oid,
if (p7->type == NULL)
goto oom;
- if (OBJ_obj2nid(oid) == NID_pkcs7_data) {
- /* Draft 9 uses id-pkcs7-data for signed data. For this type OpenSSL
- * expects an octet string in d.data. */
- p7->d.data = ostr;
- } else {
- p7->d.other = ASN1_TYPE_new();
- if (p7->d.other == NULL)
- goto oom;
- p7->d.other->type = V_ASN1_OCTET_STRING;
- p7->d.other->value.octet_string = ostr;
- }
+ p7->d.other = ASN1_TYPE_new();
+ if (p7->d.other == NULL)
+ goto oom;
+ p7->d.other->type = V_ASN1_OCTET_STRING;
+ p7->d.other->value.octet_string = ostr;
*p7_out = p7;
return 0;
@@ -1126,7 +1504,6 @@ cms_signeddata_create(krb5_context context,
pkinit_req_crypto_context req_cryptoctx,
pkinit_identity_crypto_context id_cryptoctx,
int cms_msg_type,
- int include_certchain,
unsigned char *data,
unsigned int data_len,
unsigned char **signed_data,
@@ -1171,50 +1548,46 @@ cms_signeddata_create(krb5_context context,
goto cleanup;
if (id_cryptoctx->my_certs != NULL) {
- /* create a cert chain that has at least the signer's certificate */
+ X509_STORE *certstore = NULL;
+ X509_STORE_CTX *certctx;
+ STACK_OF(X509) *certstack = NULL;
+ char buf[DN_BUF_LEN];
+ unsigned int i = 0, size = 0;
+
+ /* create a cert chain */
if ((cert_stack = sk_X509_new_null()) == NULL)
goto cleanup;
cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
- if (!include_certchain) {
- pkiDebug("only including signer's certificate\n");
- sk_X509_push(cert_stack, X509_dup(cert));
- } else {
- /* create a cert chain */
- X509_STORE *certstore = NULL;
- X509_STORE_CTX *certctx;
- STACK_OF(X509) *certstack = NULL;
- char buf[DN_BUF_LEN];
- unsigned int i = 0, size = 0;
- if ((certstore = X509_STORE_new()) == NULL)
- goto cleanup;
- pkiDebug("building certificate chain\n");
- X509_STORE_set_verify_cb(certstore, openssl_callback);
- certctx = X509_STORE_CTX_new();
- if (certctx == NULL)
- goto cleanup;
- X509_STORE_CTX_init(certctx, certstore, cert,
- id_cryptoctx->intermediateCAs);
- X509_STORE_CTX_trusted_stack(certctx, id_cryptoctx->trustedCAs);
- if (!X509_verify_cert(certctx)) {
- retval = oerr_cert(context, 0, certctx,
- _("Failed to verify own certificate"));
- goto cleanup;
- }
- certstack = X509_STORE_CTX_get1_chain(certctx);
- size = sk_X509_num(certstack);
- pkiDebug("size of certificate chain = %d\n", size);
- for(i = 0; i < size - 1; i++) {
- X509 *x = sk_X509_value(certstack, i);
- X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
- pkiDebug("cert #%d: %s\n", i, buf);
- sk_X509_push(cert_stack, X509_dup(x));
- }
- X509_STORE_CTX_free(certctx);
- X509_STORE_free(certstore);
- sk_X509_pop_free(certstack, X509_free);
+ certstore = X509_STORE_new();
+ if (certstore == NULL)
+ goto cleanup;
+ pkiDebug("building certificate chain\n");
+ X509_STORE_set_verify_cb(certstore, openssl_callback);
+ certctx = X509_STORE_CTX_new();
+ if (certctx == NULL)
+ goto cleanup;
+ X509_STORE_CTX_init(certctx, certstore, cert,
+ id_cryptoctx->intermediateCAs);
+ X509_STORE_CTX_trusted_stack(certctx, id_cryptoctx->trustedCAs);
+ if (!X509_verify_cert(certctx)) {
+ retval = oerr_cert(context, 0, certctx,
+ _("Failed to verify own certificate"));
+ goto cleanup;
}
+ certstack = X509_STORE_CTX_get1_chain(certctx);
+ size = sk_X509_num(certstack);
+ for (i = 0; i < size - 1; i++) {
+ X509 *x = sk_X509_value(certstack, i);
+ X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
+ TRACE_PKINIT_CERT_CHAIN_NAME(context, (int)i, buf);
+ sk_X509_push(cert_stack, X509_dup(x));
+ }
+ X509_STORE_CTX_free(certctx);
+ X509_STORE_free(certstore);
+ sk_X509_pop_free(certstack, X509_free);
+
p7s->cert = cert_stack;
/* fill-in PKCS7_SIGNER_INFO */
@@ -1235,7 +1608,7 @@ cms_signeddata_create(krb5_context context,
/* will not fill-out EVP_PKEY because it's on the smartcard */
/* Set digest algs */
- p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
+ p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha256);
if (p7si->digest_alg->parameter != NULL)
ASN1_TYPE_free(p7si->digest_alg->parameter);
@@ -1246,56 +1619,53 @@ cms_signeddata_create(krb5_context context,
/* Set sig algs */
if (p7si->digest_enc_alg->parameter != NULL)
ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
- p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
+ p7si->digest_enc_alg->algorithm =
+ OBJ_nid2obj(NID_sha256WithRSAEncryption);
if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
goto cleanup;
p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
- if (cms_msg_type == CMS_SIGN_DRAFT9){
- /* don't include signed attributes for pa-type 15 request */
- abuf = data;
- alen = data_len;
- } else {
- /* add signed attributes */
- /* compute sha1 digest over the EncapsulatedContentInfo */
- ctx = EVP_MD_CTX_new();
- if (ctx == NULL)
- goto cleanup;
- EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
- EVP_DigestUpdate(ctx, data, data_len);
- md_tmp = EVP_MD_CTX_md(ctx);
- EVP_DigestFinal_ex(ctx, md_data, &md_len);
- EVP_MD_CTX_free(ctx);
+ /* add signed attributes */
+ /* compute sha256 digest over the EncapsulatedContentInfo */
+ ctx = EVP_MD_CTX_new();
+ if (ctx == NULL)
+ goto cleanup;
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
+ EVP_DigestUpdate(ctx, data, data_len);
+ md_tmp = EVP_MD_CTX_get0_md(ctx);
+ EVP_DigestFinal_ex(ctx, md_data, &md_len);
+ EVP_MD_CTX_free(ctx);
- /* create a message digest attr */
- digest_attr = ASN1_OCTET_STRING_new();
- ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
- PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
- V_ASN1_OCTET_STRING, (char *) digest_attr);
+ /* create a message digest attr */
+ digest_attr = ASN1_OCTET_STRING_new();
+ ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
+ PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
+ V_ASN1_OCTET_STRING, (char *)digest_attr);
- /* create a content-type attr */
- oid_copy = OBJ_dup(oid);
- if (oid_copy == NULL)
- goto cleanup2;
- PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
- V_ASN1_OBJECT, oid_copy);
+ /* create a content-type attr */
+ oid_copy = OBJ_dup(oid);
+ if (oid_copy == NULL)
+ goto cleanup2;
+ PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
+ V_ASN1_OBJECT, oid_copy);
- /* create the signature over signed attributes. get DER encoded value */
- /* This is the place where smartcard signature needs to be calculated */
- sk = p7si->auth_attr;
- alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
- ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
- if (abuf == NULL)
- goto cleanup2;
- } /* signed attributes */
+ /* create the signature over signed attributes. get DER encoded value */
+ /* This is the place where smartcard signature needs to be calculated */
+ sk = p7si->auth_attr;
+ alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
+ ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
+ if (abuf == NULL)
+ goto cleanup2;
#ifndef WITHOUT_PKCS11
- /* Some tokens can only do RSAEncryption without sha1 hash */
- /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
- * function and the hash value into an ASN.1 value of type DigestInfo
- * DigestInfo::=SEQUENCE {
- * digestAlgorithm AlgorithmIdentifier,
- * digest OCTET STRING }
+ /*
+ * Some tokens can only do RSAEncryption without a hash. To compute
+ * sha256WithRSAEncryption, encode the algorithm ID for the hash
+ * function and the hash value into an ASN.1 value of type DigestInfo:
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING
+ * }
*/
if (id_cryptoctx->pkcs11_method == 1 &&
id_cryptoctx->mech == CKM_RSA_PKCS) {
@@ -1303,11 +1673,7 @@ cms_signeddata_create(krb5_context context,
ctx = EVP_MD_CTX_new();
if (ctx == NULL)
goto cleanup;
- /* if this is not draft9 request, include digest signed attribute */
- if (cms_msg_type != CMS_SIGN_DRAFT9)
- EVP_DigestInit_ex(ctx, md_tmp, NULL);
- else
- EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
+ EVP_DigestInit_ex(ctx, md_tmp, NULL);
EVP_DigestUpdate(ctx, abuf, alen);
EVP_DigestFinal_ex(ctx, md_data2, &md_len2);
EVP_MD_CTX_free(ctx);
@@ -1315,7 +1681,7 @@ cms_signeddata_create(krb5_context context,
alg = X509_ALGOR_new();
if (alg == NULL)
goto cleanup2;
- X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha1), V_ASN1_NULL, NULL);
+ X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, NULL);
alg_len = i2d_X509_ALGOR(alg, NULL);
digest = ASN1_OCTET_STRING_new();
@@ -1344,15 +1710,14 @@ cms_signeddata_create(krb5_context context,
#endif
{
pkiDebug("mech = %s\n",
- id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
+ id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA256_RSA_PKCS" : "FS");
retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
&sig, &sig_len);
}
#ifdef DEBUG_SIG
print_buffer(sig, sig_len);
#endif
- if (cms_msg_type != CMS_SIGN_DRAFT9 )
- free(abuf);
+ free(abuf);
if (retval)
goto cleanup2;
@@ -1395,19 +1760,13 @@ cms_signeddata_create(krb5_context context,
print_buffer_bin(*signed_data, *signed_data_len,
"/tmp/client_pkcs7_signeddata");
} else {
- if (cms_msg_type == CMS_SIGN_SERVER) {
- print_buffer_bin(*signed_data, *signed_data_len,
- "/tmp/kdc_pkcs7_signeddata");
- } else {
- print_buffer_bin(*signed_data, *signed_data_len,
- "/tmp/draft9_pkcs7_signeddata");
- }
+ print_buffer_bin(*signed_data, *signed_data_len,
+ "/tmp/kdc_pkcs7_signeddata");
}
#endif
cleanup2:
if (p7si) {
- if (cms_msg_type != CMS_SIGN_DRAFT9)
#ifndef WITHOUT_PKCS11
if (id_cryptoctx->pkcs11_method == 1 &&
id_cryptoctx->mech == CKM_RSA_PKCS) {
@@ -1501,7 +1860,7 @@ cms_signeddata_verify(krb5_context context,
if (is_signed && !OBJ_cmp(type, oid)) {
unsigned char *d;
*is_signed = 0;
- octets = pkinit_CMS_get0_content_data(cms);
+ octets = CMS_get0_content(cms);
if (!octets || ((*octets)->type != V_ASN1_OCTET_STRING)) {
retval = KRB5KDC_ERR_PREAUTH_FAILED;
krb5_set_error_message(context, retval,
@@ -1556,13 +1915,13 @@ cms_signeddata_verify(krb5_context context,
goto cleanup;
*is_signed = 0;
/* We cannot use CMS_dataInit because there may be no digest */
- octets = pkinit_CMS_get0_content_signed(cms);
+ octets = CMS_get0_content(cms);
if (octets)
out = BIO_new_mem_buf((*octets)->data, (*octets)->length);
if (out == NULL)
goto cleanup;
} else {
- pkinit_CMS_SignerInfo_get_cert(cms, si, &x);
+ CMS_SignerInfo_get0_algs(si, NULL, &x, NULL, NULL);
if (x == NULL)
goto cleanup;
@@ -1694,46 +2053,24 @@ cms_signeddata_verify(krb5_context context,
#endif
} else {
/* retrieve verified certificate chain */
- if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9)
+ if (cms_msg_type == CMS_SIGN_CLIENT)
verified_chain = X509_STORE_CTX_get1_chain(cert_ctx);
}
X509_STORE_CTX_free(cert_ctx);
if (i <= 0)
goto cleanup;
out = BIO_new(BIO_s_mem());
- if (cms_msg_type == CMS_SIGN_DRAFT9)
- flags |= CMS_NOATTR;
if (CMS_verify(cms, NULL, store, NULL, out, flags) == 0) {
- unsigned long err = ERR_peek_error();
- switch(ERR_GET_REASON(err)) {
- case PKCS7_R_DIGEST_FAILURE:
- retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
- break;
- case PKCS7_R_SIGNATURE_FAILURE:
- default:
+ if (ERR_peek_last_error() == CMS_R_VERIFICATION_FAILURE)
retval = KRB5KDC_ERR_INVALID_SIG;
- }
+ else
+ retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
(void)oerr(context, retval, _("Failed to verify CMS message"));
goto cleanup;
}
} /* message was signed */
if (!OBJ_cmp(etype, oid))
valid_oid = 1;
- else if (cms_msg_type == CMS_SIGN_DRAFT9) {
- /*
- * Various implementations of the pa-type 15 request use
- * different OIDS. We check that the returned object
- * has any of the acceptable OIDs
- */
- ASN1_OBJECT *client_oid = NULL, *server_oid = NULL, *rsa_oid = NULL;
- client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
- server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
- rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
- if (!OBJ_cmp(etype, client_oid) ||
- !OBJ_cmp(etype, server_oid) ||
- !OBJ_cmp(etype, rsa_oid))
- valid_oid = 1;
- }
if (valid_oid)
pkiDebug("CMS Verification successful\n");
@@ -1763,7 +2100,7 @@ cms_signeddata_verify(krb5_context context,
reqctx->received_cert = X509_dup(x);
/* generate authorization data */
- if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) {
+ if (cms_msg_type == CMS_SIGN_CLIENT) {
if (authz_data == NULL || authz_data_len == NULL)
goto out;
@@ -1804,11 +2141,11 @@ cleanup:
X509_STORE_free(store);
if (cms != NULL) {
if (signerCerts != NULL)
- pkinit_CMS_free1_certs(signerCerts);
+ sk_X509_pop_free(signerCerts, X509_free);
if (idctx->intermediateCAs != NULL && signerCerts)
sk_X509_free(intermediateCAs);
if (signerRevoked != NULL)
- pkinit_CMS_free1_crls(signerRevoked);
+ sk_X509_CRL_pop_free(signerRevoked, X509_CRL_free);
if (idctx->revoked != NULL && signerRevoked)
sk_X509_CRL_free(revoked);
CMS_ContentInfo_free(cms);
@@ -1829,7 +2166,6 @@ cms_envelopeddata_create(krb5_context context,
pkinit_req_crypto_context reqctx,
pkinit_identity_crypto_context idctx,
krb5_preauthtype pa_type,
- int include_certchain,
unsigned char *key_pack,
unsigned int key_pack_len,
unsigned char **out,
@@ -1843,24 +2179,11 @@ cms_envelopeddata_create(krb5_context context,
int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
STACK_OF(X509) *encerts = NULL;
const EVP_CIPHER *cipher = NULL;
- int cms_msg_type;
-
- /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
- switch ((int)pa_type) {
- case KRB5_PADATA_PK_AS_REQ_OLD:
- case KRB5_PADATA_PK_AS_REP_OLD:
- cms_msg_type = CMS_SIGN_DRAFT9;
- break;
- case KRB5_PADATA_PK_AS_REQ:
- cms_msg_type = CMS_ENVEL_SERVER;
- break;
- default:
- goto cleanup;
- }
retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
- cms_msg_type, include_certchain, key_pack, key_pack_len,
- &signed_data, (unsigned int *)&signed_data_len);
+ CMS_ENVEL_SERVER, key_pack, key_pack_len,
+ &signed_data,
+ (unsigned int *)&signed_data_len);
if (retval) {
pkiDebug("failed to create pkcs7 signed data\n");
goto cleanup;
@@ -1876,26 +2199,11 @@ cms_envelopeddata_create(krb5_context context,
cipher = EVP_des_ede3_cbc();
in = BIO_new(BIO_s_mem());
- switch (pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- prepare_enc_data(signed_data, signed_data_len, &enc_data,
- &enc_data_len);
- retval = BIO_write(in, enc_data, enc_data_len);
- if (retval != enc_data_len) {
- pkiDebug("BIO_write only wrote %d\n", retval);
- goto cleanup;
- }
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = BIO_write(in, signed_data, signed_data_len);
- if (retval != signed_data_len) {
- pkiDebug("BIO_write only wrote %d\n", retval);
- goto cleanup;
- }
- break;
- default:
- retval = -1;
+ prepare_enc_data(signed_data, signed_data_len, &enc_data,
+ &enc_data_len);
+ retval = BIO_write(in, enc_data, enc_data_len);
+ if (retval != enc_data_len) {
+ pkiDebug("BIO_write only wrote %d\n", retval);
goto cleanup;
}
@@ -1904,20 +2212,7 @@ cms_envelopeddata_create(krb5_context context,
retval = oerr(context, 0, _("Failed to encrypt PKCS7 object"));
goto cleanup;
}
- switch (pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- p7->d.enveloped->enc_data->content_type =
- OBJ_nid2obj(NID_pkcs7_signed);
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- p7->d.enveloped->enc_data->content_type =
- OBJ_nid2obj(NID_pkcs7_data);
- break;
- break;
- break;
- break;
- }
+ p7->d.enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_signed);
*out_len = i2d_PKCS7(p7, NULL);
if (!*out_len || (p = *out = malloc(*out_len)) == NULL) {
@@ -1962,13 +2257,9 @@ cms_envelopeddata_verify(krb5_context context,
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
PKCS7 *p7 = NULL;
- BIO *out = NULL;
- int i = 0;
- unsigned int size = 0;
const unsigned char *p = enveloped_data;
unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
- int msg_type = 0;
#ifdef DEBUG_ASN1
print_buffer_bin(enveloped_data, enveloped_data_len,
@@ -1989,70 +2280,32 @@ cms_envelopeddata_verify(krb5_context context,
}
/* decrypt received PKCS7 message */
- out = BIO_new(BIO_s_mem());
- if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) {
+ if (pkcs7_decrypt(context, id_cryptoctx, p7, &tmp_buf, &tmp_buf_len)) {
pkiDebug("PKCS7 decryption successful\n");
} else {
retval = oerr(context, 0, _("Failed to decrypt PKCS7 message"));
goto cleanup;
}
- /* transfer the decoded PKCS7 SignedData message into a separate buffer */
- for (;;) {
- if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL)
- goto cleanup;
- i = BIO_read(out, &(tmp_buf[size]), 1024 * 10);
- if (i <= 0)
- break;
- else
- size += i;
- }
- tmp_buf_len = size;
-
#ifdef DEBUG_ASN1
print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
#endif
/* verify PKCS7 SignedData message */
- switch (pa_type) {
- case KRB5_PADATA_PK_AS_REP:
- msg_type = CMS_ENVEL_SERVER;
-
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- msg_type = CMS_SIGN_DRAFT9;
- break;
- default:
- pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type);
- retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ /* Wrap the signed data to make decoding easier in the verify routine. */
+ retval = wrap_signeddata(tmp_buf, tmp_buf_len, &tmp_buf2, &tmp_buf2_len);
+ if (retval) {
+ pkiDebug("failed to encode signeddata\n");
goto cleanup;
}
- /*
- * If this is the RFC style, wrap the signed data to make
- * decoding easier in the verify routine.
- * For draft9-compatible, we don't do anything because it
- * is already wrapped.
- */
- if (msg_type == CMS_ENVEL_SERVER) {
- retval = wrap_signeddata(tmp_buf, tmp_buf_len,
- &tmp_buf2, &tmp_buf2_len);
- if (retval) {
- pkiDebug("failed to encode signeddata\n");
- goto cleanup;
- }
- vfy_buf = tmp_buf2;
- vfy_buf_len = tmp_buf2_len;
-
- } else {
- vfy_buf = tmp_buf;
- vfy_buf_len = tmp_buf_len;
- }
+ vfy_buf = tmp_buf2;
+ vfy_buf_len = tmp_buf2_len;
#ifdef DEBUG_ASN1
print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
#endif
retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx, msg_type,
+ id_cryptoctx, CMS_ENVEL_SERVER,
require_crl_checking,
vfy_buf, vfy_buf_len,
data, data_len, NULL, NULL, NULL);
@@ -2070,8 +2323,6 @@ cleanup:
if (p7 != NULL)
PKCS7_free(p7);
- if (out != NULL)
- BIO_free(out);
free(tmp_buf);
free(tmp_buf2);
@@ -2083,17 +2334,16 @@ crypto_retrieve_X509_sans(krb5_context context,
pkinit_plg_crypto_context plgctx,
pkinit_req_crypto_context reqctx,
X509 *cert,
- krb5_principal **princs_ret,
- krb5_principal **upn_ret,
+ krb5_principal **princs_ret, char ***upn_ret,
unsigned char ***dns_ret)
{
krb5_error_code retval = EINVAL;
char buf[DN_BUF_LEN];
int p = 0, u = 0, d = 0, ret = 0, l;
krb5_principal *princs = NULL;
- krb5_principal *upns = NULL;
+ char **upns = NULL;
unsigned char **dnss = NULL;
- unsigned int i, num_found = 0, num_sans = 0;
+ unsigned int i, num_sans = 0;
X509_EXTENSION *ext = NULL;
GENERAL_NAMES *ialt = NULL;
GENERAL_NAME *gen = NULL;
@@ -2117,21 +2367,17 @@ crypto_retrieve_X509_sans(krb5_context context,
X509_NAME_oneline(X509_get_subject_name(cert),
buf, sizeof(buf));
- pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf);
l = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
if (l < 0)
return 0;
if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) {
- pkiDebug("%s: found no subject alt name extensions\n", __FUNCTION__);
+ TRACE_PKINIT_SAN_CERT_NONE(context, buf);
goto cleanup;
}
num_sans = sk_GENERAL_NAME_num(ialt);
- pkiDebug("%s: found %d subject alt name extension(s)\n", __FUNCTION__,
- num_sans);
-
/* OK, we're likely returning something. Allocate return values */
if (princs_ret != NULL) {
princs = calloc(num_sans + 1, sizeof(krb5_principal));
@@ -2141,7 +2387,7 @@ crypto_retrieve_X509_sans(krb5_context context,
}
}
if (upn_ret != NULL) {
- upns = calloc(num_sans + 1, sizeof(krb5_principal));
+ upns = calloc(num_sans + 1, sizeof(*upns));
if (upns == NULL) {
retval = ENOMEM;
goto cleanup;
@@ -2176,7 +2422,6 @@ crypto_retrieve_X509_sans(krb5_context context,
__FUNCTION__);
} else {
p++;
- num_found++;
}
} else if (upns != NULL &&
OBJ_cmp(plgctx->id_ms_san_upn,
@@ -2184,16 +2429,10 @@ crypto_retrieve_X509_sans(krb5_context context,
/* Prevent abuse of embedded null characters. */
if (memchr(name.data, '\0', name.length))
break;
- ret = krb5_parse_name_flags(context, name.data,
- KRB5_PRINCIPAL_PARSE_ENTERPRISE,
- &upns[u]);
- if (ret) {
- pkiDebug("%s: failed parsing ms-upn san value\n",
- __FUNCTION__);
- } else {
- u++;
- num_found++;
- }
+ upns[u] = k5memdup0(name.data, name.length, &ret);
+ if (upns[u] == NULL)
+ goto cleanup;
+ u++;
} else {
pkiDebug("%s: unrecognized othername oid in SAN\n",
__FUNCTION__);
@@ -2215,7 +2454,6 @@ crypto_retrieve_X509_sans(krb5_context context,
__FUNCTION__);
} else {
d++;
- num_found++;
}
}
break;
@@ -2226,6 +2464,8 @@ crypto_retrieve_X509_sans(krb5_context context,
}
sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
+ TRACE_PKINIT_SAN_CERT_COUNT(context, (int)num_sans, p, u, d, buf);
+
retval = 0;
if (princs != NULL && *princs != NULL) {
*princs_ret = princs;
@@ -2245,7 +2485,7 @@ cleanup:
krb5_free_principal(context, princs[i]);
free(princs);
for (i = 0; upns != NULL && upns[i] != NULL; i++)
- krb5_free_principal(context, upns[i]);
+ free(upns[i]);
free(upns);
for (i = 0; dnss != NULL && dnss[i] != NULL; i++)
free(dnss[i]);
@@ -2269,8 +2509,7 @@ crypto_retrieve_cert_sans(krb5_context context,
pkinit_plg_crypto_context plgctx,
pkinit_req_crypto_context reqctx,
pkinit_identity_crypto_context idctx,
- krb5_principal **princs_ret,
- krb5_principal **upn_ret,
+ krb5_principal **princs_ret, char ***upn_ret,
unsigned char ***dns_ret)
{
krb5_error_code retval = EINVAL;
@@ -2374,22 +2613,28 @@ pkinit_octetstring2key(krb5_context context,
unsigned char counter;
size_t keybytes, keylength, offset;
krb5_data random_data;
+ EVP_MD_CTX *sha1_ctx = NULL;
- if ((buf = malloc(dh_key_len)) == NULL) {
- retval = ENOMEM;
+ buf = k5alloc(dh_key_len, &retval);
+ if (buf == NULL)
+ goto cleanup;
+
+ sha1_ctx = EVP_MD_CTX_new();
+ if (sha1_ctx == NULL) {
+ retval = KRB5_CRYPTO_INTERNAL;
goto cleanup;
}
- memset(buf, 0, dh_key_len);
counter = 0;
offset = 0;
do {
- SHA_CTX c;
-
- SHA1_Init(&c);
- SHA1_Update(&c, &counter, 1);
- SHA1_Update(&c, key, dh_key_len);
- SHA1_Final(md, &c);
+ if (!EVP_DigestInit(sha1_ctx, EVP_sha1()) ||
+ !EVP_DigestUpdate(sha1_ctx, &counter, 1) ||
+ !EVP_DigestUpdate(sha1_ctx, key, dh_key_len) ||
+ !EVP_DigestFinal(sha1_ctx, md, NULL)) {
+ retval = KRB5_CRYPTO_INTERNAL;
+ goto cleanup;
+ }
if (dh_key_len - offset < sizeof(md))
memcpy(buf + offset, md, dh_key_len - offset);
@@ -2408,11 +2653,9 @@ pkinit_octetstring2key(krb5_context context,
goto cleanup;
key_block->length = keylength;
- key_block->contents = malloc(keylength);
- if (key_block->contents == NULL) {
- retval = ENOMEM;
+ key_block->contents = k5alloc(keylength, &retval);
+ if (key_block->contents == NULL)
goto cleanup;
- }
random_data.length = keybytes;
random_data.data = (char *)buf;
@@ -2420,6 +2663,7 @@ pkinit_octetstring2key(krb5_context context,
retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
cleanup:
+ EVP_MD_CTX_free(sha1_ctx);
free(buf);
/* If this is an error return, free the allocated keyblock, if any */
if (retval) {
@@ -2430,231 +2674,217 @@ cleanup:
}
-/**
- * Given an algorithm_identifier, this function returns the hash length
- * and EVP function associated with that algorithm.
- */
-static krb5_error_code
-pkinit_alg_values(krb5_context context,
- const krb5_data *alg_id,
- size_t *hash_bytes,
- const EVP_MD *(**func)(void))
+/* Return the OpenSSL descriptor for the given RFC 5652 OID specified in RFC
+ * 8636. RFC 8636 defines a SHA384 variant, but we don't use it. */
+static const EVP_MD *
+algid_to_md(const krb5_data *alg_id)
{
- *hash_bytes = 0;
- *func = NULL;
- if ((alg_id->length == krb5_pkinit_sha1_oid_len) &&
- (0 == memcmp(alg_id->data, &krb5_pkinit_sha1_oid,
- krb5_pkinit_sha1_oid_len))) {
- *hash_bytes = 20;
- *func = &EVP_sha1;
- return 0;
- } else if ((alg_id->length == krb5_pkinit_sha256_oid_len) &&
- (0 == memcmp(alg_id->data, krb5_pkinit_sha256_oid,
- krb5_pkinit_sha256_oid_len))) {
- *hash_bytes = 32;
- *func = &EVP_sha256;
- return 0;
- } else if ((alg_id->length == krb5_pkinit_sha512_oid_len) &&
- (0 == memcmp(alg_id->data, krb5_pkinit_sha512_oid,
- krb5_pkinit_sha512_oid_len))) {
- *hash_bytes = 64;
- *func = &EVP_sha512;
- return 0;
- } else {
- krb5_set_error_message(context, KRB5_ERR_BAD_S2K_PARAMS,
- "Bad algorithm ID passed to PK-INIT KDF.");
- return KRB5_ERR_BAD_S2K_PARAMS;
- }
-} /* pkinit_alg_values() */
+ if (data_eq(*alg_id, sha1_id))
+ return EVP_sha1();
+ if (data_eq(*alg_id, sha256_id))
+ return EVP_sha256();
+ if (data_eq(*alg_id, sha512_id))
+ return EVP_sha512();
+ return NULL;
+}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-/* pkinit_alg_agility_kdf() --
- * This function generates a key using the KDF described in
- * draft_ietf_krb_wg_pkinit_alg_agility-04.txt. The algorithm is
- * described as follows:
- *
- * 1. reps = keydatalen (K) / hash length (H)
- *
- * 2. Initialize a 32-bit, big-endian bit string counter as 1.
- *
- * 3. For i = 1 to reps by 1, do the following:
- *
- * - Compute Hashi = H(counter || Z || OtherInfo).
- *
- * - Increment counter (modulo 2^32)
- *
- * 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes.
- */
-krb5_error_code
-pkinit_alg_agility_kdf(krb5_context context,
- krb5_data *secret,
- krb5_data *alg_oid,
- krb5_const_principal party_u_info,
- krb5_const_principal party_v_info,
- krb5_enctype enctype,
- krb5_data *as_req,
- krb5_data *pk_as_rep,
- krb5_keyblock *key_block)
+#define sskdf openssl_sskdf
+static krb5_error_code
+openssl_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
+ krb5_data *info, size_t len, krb5_data *out)
{
- krb5_error_code retval = 0;
-
- unsigned int reps = 0;
- uint32_t counter = 1; /* Does this type work on Windows? */
- size_t offset = 0;
- size_t hash_len = 0;
- size_t rand_len = 0;
- size_t key_len = 0;
- krb5_data random_data;
- krb5_sp80056a_other_info other_info_fields;
- krb5_pkinit_supp_pub_info supp_pub_info_fields;
- krb5_data *other_info = NULL;
- krb5_data *supp_pub_info = NULL;
- krb5_algorithm_identifier alg_id;
- EVP_MD_CTX *ctx = NULL;
- const EVP_MD *(*EVP_func)(void);
+ krb5_error_code ret;
+ EVP_KDF *kdf = NULL;
+ EVP_KDF_CTX *kctx = NULL;
+ OSSL_PARAM params[4], *p = params;
- /* initialize random_data here to make clean-up safe */
- random_data.length = 0;
- random_data.data = NULL;
+ ret = alloc_data(out, len);
+ if (ret)
+ goto cleanup;
- /* allocate and initialize the key block */
- key_block->magic = 0;
- key_block->enctype = enctype;
- if (0 != (retval = krb5_c_keylengths(context, enctype, &rand_len,
- &key_len)))
+ kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
+ if (kdf == NULL) {
+ ret = oerr(context, KRB5_CRYPTO_INTERNAL, _("Failed to fetch SSKDF"));
goto cleanup;
+ }
- random_data.length = rand_len;
- key_block->length = key_len;
+ kctx = EVP_KDF_CTX_new(kdf);
+ if (!kctx) {
+ ret = oerr(context, KRB5_CRYPTO_INTERNAL,
+ _("Failed to instantiate SSKDF"));
+ goto cleanup;
+ }
- if (NULL == (key_block->contents = malloc(key_block->length))) {
- retval = ENOMEM;
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
+ (char *)EVP_MD_get0_name(md), 0);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
+ key->data, key->length);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
+ info->data, info->length);
+ *p = OSSL_PARAM_construct_end();
+ if (EVP_KDF_derive(kctx, (uint8_t *)out->data, len, params) <= 0) {
+ ret = oerr(context, KRB5_CRYPTO_INTERNAL,
+ _("Failed to derive key using SSKDF"));
goto cleanup;
}
- memset (key_block->contents, 0, key_block->length);
+ ret = 0;
- /* If this is anonymous pkinit, use the anonymous principle for party_u_info */
- if (party_u_info && krb5_principal_compare_any_realm(context, party_u_info,
- krb5_anonymous_principal()))
- party_u_info = (krb5_principal)krb5_anonymous_principal();
+cleanup:
+ EVP_KDF_free(kdf);
+ EVP_KDF_CTX_free(kctx);
+ return ret;
+}
- if (0 != (retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func)))
- goto cleanup;
+#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
+#define sskdf builtin_sskdf
+static krb5_error_code
+builtin_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
+ krb5_data *info, size_t len, krb5_data *out)
+{
+ krb5_error_code ret;
+ uint32_t counter = 1, reps;
+ uint8_t be_counter[4], *outptr;
+ EVP_MD_CTX *ctx = NULL;
+ unsigned int s, hash_len;
- /* 1. reps = keydatalen (K) / hash length (H) */
- reps = key_block->length/hash_len;
+ hash_len = EVP_MD_size(md);
- /* ... and round up, if necessary */
- if (key_block->length > (reps * hash_len))
- reps++;
+ /* 1. reps = keydatalen (K) / hash length (H) rounded up. */
+ reps = (len + hash_len - 1) / hash_len;
/* Allocate enough space in the random data buffer to hash directly into
* it, even if the last hash will make it bigger than the key length. */
- if (NULL == (random_data.data = malloc(reps * hash_len))) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- /* Encode the ASN.1 octet string for "SuppPubInfo" */
- supp_pub_info_fields.enctype = enctype;
- supp_pub_info_fields.as_req = *as_req;
- supp_pub_info_fields.pk_as_rep = *pk_as_rep;
- if (0 != ((retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
- &supp_pub_info))))
- goto cleanup;
-
- /* Now encode the ASN.1 octet string for "OtherInfo" */
- memset(&alg_id, 0, sizeof alg_id);
- alg_id.algorithm = *alg_oid; /*alias*/
-
- other_info_fields.algorithm_identifier = alg_id;
- other_info_fields.party_u_info = (krb5_principal) party_u_info;
- other_info_fields.party_v_info = (krb5_principal) party_v_info;
- other_info_fields.supp_pub_info = *supp_pub_info;
- if (0 != (retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info)))
+ ret = alloc_data(out, reps * hash_len);
+ if (ret)
goto cleanup;
+ out->length = len;
- /* 2. Initialize a 32-bit, big-endian bit string counter as 1.
+ /*
+ * 2. Initialize a 32-bit, big-endian bit string counter as 1.
* 3. For i = 1 to reps by 1, do the following:
* - Compute Hashi = H(counter || Z || OtherInfo).
* - Increment counter (modulo 2^32)
+ * 4. Set key = Hash1 || Hash2 || ... so that length of key is K
+ * bytes.
*/
+ outptr = (uint8_t *)out->data;
for (counter = 1; counter <= reps; counter++) {
- uint s = 0;
- uint32_t be_counter = htonl(counter);
+ store_32_be(counter, be_counter);
ctx = EVP_MD_CTX_new();
if (ctx == NULL) {
- retval = KRB5_CRYPTO_INTERNAL;
+ ret = KRB5_CRYPTO_INTERNAL;
goto cleanup;
}
/* - Compute Hashi = H(counter || Z || OtherInfo). */
- if (!EVP_DigestInit(ctx, EVP_func())) {
- krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
- "Call to OpenSSL EVP_DigestInit() returned an error.");
- retval = KRB5_CRYPTO_INTERNAL;
+ if (!EVP_DigestInit(ctx, md) ||
+ !EVP_DigestUpdate(ctx, be_counter, 4) ||
+ !EVP_DigestUpdate(ctx, key->data, key->length) ||
+ !EVP_DigestUpdate(ctx, info->data, info->length) ||
+ !EVP_DigestFinal(ctx, outptr, &s)) {
+ ret = oerr(context, KRB5_CRYPTO_INTERNAL,
+ _("Failed to compute digest"));
goto cleanup;
}
- if (!EVP_DigestUpdate(ctx, &be_counter, 4) ||
- !EVP_DigestUpdate(ctx, secret->data, secret->length) ||
- !EVP_DigestUpdate(ctx, other_info->data, other_info->length)) {
- krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
- "Call to OpenSSL EVP_DigestUpdate() returned an error.");
- retval = KRB5_CRYPTO_INTERNAL;
- goto cleanup;
- }
-
- /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. */
- if (!EVP_DigestFinal(ctx, (uint8_t *)random_data.data + offset, &s)) {
- krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
- "Call to OpenSSL EVP_DigestUpdate() returned an error.");
- retval = KRB5_CRYPTO_INTERNAL;
- goto cleanup;
- }
- offset += s;
assert(s == hash_len);
+ outptr += s;
EVP_MD_CTX_free(ctx);
ctx = NULL;
}
- retval = krb5_c_random_to_key(context, enctype, &random_data,
- key_block);
-
cleanup:
EVP_MD_CTX_free(ctx);
+ return ret;
+}
- /* If this has been an error, free the allocated key_block, if any */
- if (retval) {
- krb5_free_keyblock_contents(context, key_block);
- }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
- /* free other allocated resources, either way */
- if (random_data.data)
- free(random_data.data);
- krb5_free_data(context, other_info);
- krb5_free_data(context, supp_pub_info);
+/* id-pkinit-kdf family, as specified by RFC 8636. */
+krb5_error_code
+pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
+ krb5_data *alg_oid, krb5_const_principal party_u_info,
+ krb5_const_principal party_v_info,
+ krb5_enctype enctype, krb5_data *as_req,
+ krb5_data *pk_as_rep, krb5_keyblock *key_block)
+{
+ krb5_error_code ret;
+ size_t rand_len = 0, key_len = 0;
+ const EVP_MD *md;
+ krb5_sp80056a_other_info other_info_fields;
+ krb5_pkinit_supp_pub_info supp_pub_info_fields;
+ krb5_data *other_info = NULL, *supp_pub_info = NULL;
+ krb5_data random_data = empty_data();
+ krb5_algorithm_identifier alg_id;
+ char *hash_name = NULL;
- return retval;
-} /*pkinit_alg_agility_kdf() */
+ ret = krb5_c_keylengths(context, enctype, &rand_len, &key_len);
+ if (ret)
+ goto cleanup;
-/* Call DH_compute_key() and ensure that we left-pad short results instead of
- * leaving junk bytes at the end of the buffer. */
-static void
-compute_dh(unsigned char *buf, int size, BIGNUM *server_pub_key, DH *dh)
-{
- int len, pad;
+ /* Allocate and initialize the key block. */
+ key_block->magic = 0;
+ key_block->enctype = enctype;
+ key_block->length = key_len;
+ key_block->contents = k5calloc(key_block->length, 1, &ret);
+ if (key_block->contents == NULL)
+ goto cleanup;
+
+ /* If this is anonymous pkinit, use the anonymous principle for
+ * party_u_info. */
+ if (party_u_info &&
+ krb5_principal_compare_any_realm(context, party_u_info,
+ krb5_anonymous_principal())) {
+ party_u_info = (krb5_principal)krb5_anonymous_principal();
+ }
- len = DH_compute_key(buf, server_pub_key, dh);
- assert(len >= 0 && len <= size);
- if (len < size) {
- pad = size - len;
- memmove(buf + pad, buf, len);
- memset(buf, 0, pad);
+ md = algid_to_md(alg_oid);
+ if (md == NULL) {
+ krb5_set_error_message(context, KRB5_ERR_BAD_S2K_PARAMS,
+ "Bad algorithm ID passed to PK-INIT KDF.");
+ return KRB5_ERR_BAD_S2K_PARAMS;
}
+
+ /* Encode the ASN.1 octet string for "SuppPubInfo". */
+ supp_pub_info_fields.enctype = enctype;
+ supp_pub_info_fields.as_req = *as_req;
+ supp_pub_info_fields.pk_as_rep = *pk_as_rep;
+ ret = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
+ &supp_pub_info);
+ if (ret)
+ goto cleanup;
+
+ /* Now encode the ASN.1 octet string for "OtherInfo". */
+ memset(&alg_id, 0, sizeof(alg_id));
+ alg_id.algorithm = *alg_oid;
+ other_info_fields.algorithm_identifier = alg_id;
+ other_info_fields.party_u_info = (krb5_principal)party_u_info;
+ other_info_fields.party_v_info = (krb5_principal)party_v_info;
+ other_info_fields.supp_pub_info = *supp_pub_info;
+ ret = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info);
+ if (ret)
+ goto cleanup;
+
+ ret = sskdf(context, md, secret, other_info, rand_len, &random_data);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5_c_random_to_key(context, enctype, &random_data, key_block);
+
+cleanup:
+ if (ret)
+ krb5_free_keyblock_contents(context, key_block);
+ free(hash_name);
+ zapfree(random_data.data, random_data.length);
+ krb5_free_data(context, other_info);
+ krb5_free_data(context, supp_pub_info);
+ return ret;
}
krb5_error_code
@@ -2662,99 +2892,38 @@ client_create_dh(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
pkinit_req_crypto_context cryptoctx,
pkinit_identity_crypto_context id_cryptoctx,
- int dh_size,
- unsigned char **dh_params,
- unsigned int *dh_params_len,
- unsigned char **dh_pubkey,
- unsigned int *dh_pubkey_len)
+ int dh_size, krb5_data *spki_out)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
- unsigned char *buf = NULL;
- int dh_err = 0;
- ASN1_INTEGER *pub_key = NULL;
- const BIGNUM *pubkey_bn, *p, *q, *g;
-
- if (cryptoctx->dh == NULL) {
- if (dh_size == 1024)
- cryptoctx->dh = make_oakley_dh(oakley_1024, sizeof(oakley_1024));
- else if (dh_size == 2048)
- cryptoctx->dh = make_oakley_dh(oakley_2048, sizeof(oakley_2048));
- else if (dh_size == 4096)
- cryptoctx->dh = make_oakley_dh(oakley_4096, sizeof(oakley_4096));
- if (cryptoctx->dh == NULL)
- goto cleanup;
- }
-
- DH_generate_key(cryptoctx->dh);
- DH_get0_key(cryptoctx->dh, &pubkey_bn, NULL);
+ EVP_PKEY *params = NULL, *pkey = NULL;
- DH_check(cryptoctx->dh, &dh_err);
- if (dh_err != 0) {
- pkiDebug("Warning: dh_check failed with %d\n", dh_err);
- if (dh_err & DH_CHECK_P_NOT_PRIME)
- pkiDebug("p value is not prime\n");
- if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
- pkiDebug("p value is not a safe prime\n");
- if (dh_err & DH_UNABLE_TO_CHECK_GENERATOR)
- pkiDebug("unable to check the generator value\n");
- if (dh_err & DH_NOT_SUITABLE_GENERATOR)
- pkiDebug("the g value is not a generator\n");
- }
-#ifdef DEBUG_DH
- print_dh(cryptoctx->dh, "client's DH params\n");
- print_pubkey(cryptoctx->dh->pub_key, "client's pub_key=");
-#endif
+ *spki_out = empty_data();
- DH_check_pub_key(cryptoctx->dh, pubkey_bn, &dh_err);
- if (dh_err != 0) {
- pkiDebug("dh_check_pub_key failed with %d\n", dh_err);
+ if (cryptoctx->received_params != NULL)
+ params = cryptoctx->received_params;
+ else if (dh_size == 1024)
+ params = plg_cryptoctx->dh_1024;
+ else if (dh_size == 2048)
+ params = plg_cryptoctx->dh_2048;
+ else if (dh_size == 4096)
+ params = plg_cryptoctx->dh_4096;
+ else
goto cleanup;
- }
- /* pack DHparams */
- /* aglo: usually we could just call i2d_DHparams to encode DH params
- * however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
- */
- DH_get0_pqg(cryptoctx->dh, &p, &q, &g);
- retval = pkinit_encode_dh_params(p, g, q, dh_params, dh_params_len);
- if (retval)
+ pkey = generate_dh_pkey(params);
+ if (pkey == NULL)
goto cleanup;
- /* pack DH public key */
- /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
- * encoding shall be used as the contents (the value) of the
- * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
- * data element
- */
- pub_key = BN_to_ASN1_INTEGER(pubkey_bn, NULL);
- if (pub_key == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
- if ((buf = *dh_pubkey = malloc(*dh_pubkey_len)) == NULL) {
- retval = ENOMEM;
+ retval = encode_spki(pkey, spki_out);
+ if (retval)
goto cleanup;
- }
- i2d_ASN1_INTEGER(pub_key, &buf);
- if (pub_key != NULL)
- ASN1_INTEGER_free(pub_key);
-
- retval = 0;
- return retval;
+ EVP_PKEY_free(cryptoctx->client_pkey);
+ cryptoctx->client_pkey = pkey;
+ pkey = NULL;
cleanup:
- if (cryptoctx->dh != NULL)
- DH_free(cryptoctx->dh);
- cryptoctx->dh = NULL;
- free(*dh_params);
- *dh_params = NULL;
- free(*dh_pubkey);
- *dh_pubkey = NULL;
- if (pub_key != NULL)
- ASN1_INTEGER_free(pub_key);
-
+ EVP_PKEY_free(pkey);
return retval;
}
@@ -2765,77 +2934,56 @@ client_process_dh(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
unsigned char *subjectPublicKey_data,
unsigned int subjectPublicKey_length,
- unsigned char **client_key,
- unsigned int *client_key_len)
+ unsigned char **client_key_out,
+ unsigned int *client_key_len_out)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
- BIGNUM *server_pub_key = NULL;
- ASN1_INTEGER *pub_key = NULL;
- const unsigned char *p = NULL;
+ EVP_PKEY *server_pkey = NULL;
+ uint8_t *client_key = NULL;
+ unsigned int client_key_len;
- *client_key_len = DH_size(cryptoctx->dh);
- if ((*client_key = malloc(*client_key_len)) == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- p = subjectPublicKey_data;
- pub_key = d2i_ASN1_INTEGER(NULL, &p, (long)subjectPublicKey_length);
- if (pub_key == NULL)
+ *client_key_out = NULL;
+ *client_key_len_out = 0;
+
+ server_pkey = compose_dh_pkey(cryptoctx->client_pkey,
+ subjectPublicKey_data,
+ subjectPublicKey_length);
+ if (server_pkey == NULL)
goto cleanup;
- if ((server_pub_key = ASN1_INTEGER_to_BN(pub_key, NULL)) == NULL)
+
+ if (!dh_result(cryptoctx->client_pkey, server_pkey,
+ &client_key, &client_key_len))
goto cleanup;
- compute_dh(*client_key, *client_key_len, server_pub_key, cryptoctx->dh);
#ifdef DEBUG_DH
print_pubkey(server_pub_key, "server's pub_key=");
- pkiDebug("client computed key (%d)= ", *client_key_len);
- print_buffer(*client_key, *client_key_len);
+ pkiDebug("client computed key (%d)= ", client_key_len);
+ print_buffer(client_key, client_key_len);
#endif
- retval = 0;
- if (server_pub_key != NULL)
- BN_free(server_pub_key);
- if (pub_key != NULL)
- ASN1_INTEGER_free(pub_key);
+ *client_key_out = client_key;
+ *client_key_len_out = client_key_len;
+ client_key = NULL;
- return retval;
+ retval = 0;
cleanup:
- free(*client_key);
- *client_key = NULL;
- if (pub_key != NULL)
- ASN1_INTEGER_free(pub_key);
-
+ EVP_PKEY_free(server_pkey);
+ free(client_key);
return retval;
}
/* Return 1 if dh is a permitted well-known group, otherwise return 0. */
static int
-check_dh_wellknown(pkinit_plg_crypto_context cryptoctx, DH *dh, int nbits)
+check_dh_wellknown(pkinit_plg_crypto_context cryptoctx, EVP_PKEY *pkey,
+ int nbits)
{
-
- switch (nbits) {
- case 1024:
- /* Oakley MODP group 2 */
- if (pkinit_check_dh_params(cryptoctx->dh_1024, dh) == 0)
- return 1;
- break;
-
- case 2048:
- /* Oakley MODP group 14 */
- if (pkinit_check_dh_params(cryptoctx->dh_2048, dh) == 0)
- return 1;
- break;
-
- case 4096:
- /* Oakley MODP group 16 */
- if (pkinit_check_dh_params(cryptoctx->dh_4096, dh) == 0)
- return 1;
- break;
-
- default:
- break;
- }
+ if (nbits == 1024)
+ return EVP_PKEY_parameters_eq(cryptoctx->dh_1024, pkey) == 1;
+ else if (nbits == 2048)
+ return EVP_PKEY_parameters_eq(cryptoctx->dh_2048, pkey) == 1;
+ else if (nbits == 4096)
+ return EVP_PKEY_parameters_eq(cryptoctx->dh_4096, pkey) == 1;
return 0;
}
@@ -2844,150 +2992,82 @@ server_check_dh(krb5_context context,
pkinit_plg_crypto_context cryptoctx,
pkinit_req_crypto_context req_cryptoctx,
pkinit_identity_crypto_context id_cryptoctx,
- krb5_data *dh_params,
+ const krb5_data *client_spki,
int minbits)
{
- DH *dh = NULL;
- const BIGNUM *p;
+ EVP_PKEY *client_pkey = NULL;
int dh_prime_bits;
krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
- dh = decode_dh_params((uint8_t *)dh_params->data, dh_params->length);
- if (dh == NULL) {
+ client_pkey = decode_spki(client_spki);
+ if (client_pkey == NULL) {
pkiDebug("failed to decode dhparams\n");
goto cleanup;
}
/* KDC SHOULD check to see if the key parameters satisfy its policy */
- DH_get0_pqg(dh, &p, NULL, NULL);
- dh_prime_bits = BN_num_bits(p);
+ dh_prime_bits = EVP_PKEY_get_bits(client_pkey);
if (minbits && dh_prime_bits < minbits) {
pkiDebug("client sent dh params with %d bits, we require %d\n",
dh_prime_bits, minbits);
goto cleanup;
}
- if (check_dh_wellknown(cryptoctx, dh, dh_prime_bits))
+ if (check_dh_wellknown(cryptoctx, client_pkey, dh_prime_bits))
retval = 0;
cleanup:
if (retval == 0)
- req_cryptoctx->dh = dh;
+ req_cryptoctx->client_pkey = client_pkey;
else
- DH_free(dh);
+ EVP_PKEY_free(client_pkey);
return retval;
}
-/* Duplicate a DH handle (parameters only, not public or private key). */
-static DH *
-dup_dh_params(const DH *src)
-{
- const BIGNUM *oldp, *oldq, *oldg;
- BIGNUM *p = NULL, *q = NULL, *g = NULL;
- DH *dh;
-
- DH_get0_pqg(src, &oldp, &oldq, &oldg);
- p = BN_dup(oldp);
- q = BN_dup(oldq);
- g = BN_dup(oldg);
- dh = DH_new();
- if (p == NULL || q == NULL || g == NULL || dh == NULL) {
- BN_free(p);
- BN_free(q);
- BN_free(g);
- DH_free(dh);
- return NULL;
- }
- DH_set0_pqg(dh, p, q, g);
- return dh;
-}
-
/* kdc's dh function */
krb5_error_code
server_process_dh(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
pkinit_req_crypto_context cryptoctx,
pkinit_identity_crypto_context id_cryptoctx,
- unsigned char *data,
- unsigned int data_len,
- unsigned char **dh_pubkey,
- unsigned int *dh_pubkey_len,
- unsigned char **server_key,
- unsigned int *server_key_len)
+ unsigned char **dh_pubkey_out,
+ unsigned int *dh_pubkey_len_out,
+ unsigned char **server_key_out,
+ unsigned int *server_key_len_out)
{
krb5_error_code retval = ENOMEM;
- DH *dh = NULL, *dh_server = NULL;
- unsigned char *p = NULL;
- ASN1_INTEGER *pub_key = NULL;
- BIGNUM *client_pubkey = NULL;
- const BIGNUM *server_pubkey;
-
- *dh_pubkey = *server_key = NULL;
- *dh_pubkey_len = *server_key_len = 0;
+ EVP_PKEY *server_pkey = NULL;
+ unsigned char *dh_pubkey = NULL, *server_key = NULL;
+ unsigned int dh_pubkey_len = 0, server_key_len = 0;
- /* get client's received DH parameters that we saved in server_check_dh */
- dh = cryptoctx->dh;
- dh_server = dup_dh_params(dh);
- if (dh_server == NULL)
- goto cleanup;
+ *dh_pubkey_out = *server_key_out = NULL;
+ *dh_pubkey_len_out = *server_key_len_out = 0;
- /* decode client's public key */
- p = data;
- pub_key = d2i_ASN1_INTEGER(NULL, (const unsigned char **)&p, (int)data_len);
- if (pub_key == NULL)
- goto cleanup;
- client_pubkey = ASN1_INTEGER_to_BN(pub_key, NULL);
- if (client_pubkey == NULL)
+ /* Generate a server DH key with the same parameters as the client key. */
+ server_pkey = generate_dh_pkey(cryptoctx->client_pkey);
+ if (server_pkey == NULL)
goto cleanup;
- ASN1_INTEGER_free(pub_key);
- if (!DH_generate_key(dh_server))
+ if (!dh_result(server_pkey, cryptoctx->client_pkey, &server_key,
+ &server_key_len))
goto cleanup;
- DH_get0_key(dh_server, &server_pubkey, NULL);
- /* generate DH session key */
- *server_key_len = DH_size(dh_server);
- if ((*server_key = malloc(*server_key_len)) == NULL)
+ if (!dh_pubkey_der(server_pkey, &dh_pubkey, &dh_pubkey_len))
goto cleanup;
- compute_dh(*server_key, *server_key_len, client_pubkey, dh_server);
-
-#ifdef DEBUG_DH
- print_dh(dh_server, "client&server's DH params\n");
- print_pubkey(client_pubkey, "client's pub_key=");
- print_pubkey(server_pubkey, "server's pub_key=");
- pkiDebug("server computed key=");
- print_buffer(*server_key, *server_key_len);
-#endif
- /* KDC reply */
- /* pack DH public key */
- /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
- * encoding shall be used as the contents (the value) of the
- * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
- * data element
- */
- pub_key = BN_to_ASN1_INTEGER(server_pubkey, NULL);
- if (pub_key == NULL)
- goto cleanup;
- *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
- if ((p = *dh_pubkey = malloc(*dh_pubkey_len)) == NULL)
- goto cleanup;
- i2d_ASN1_INTEGER(pub_key, &p);
- if (pub_key != NULL)
- ASN1_INTEGER_free(pub_key);
+ *dh_pubkey_out = dh_pubkey;
+ *dh_pubkey_len_out = dh_pubkey_len;
+ *server_key_out = server_key;
+ *server_key_len_out = server_key_len;
+ dh_pubkey = server_key = NULL;
retval = 0;
- if (dh_server != NULL)
- DH_free(dh_server);
- return retval;
-
cleanup:
- BN_free(client_pubkey);
- DH_free(dh_server);
- free(*dh_pubkey);
- free(*server_key);
+ EVP_PKEY_free(server_pkey);
+ free(dh_pubkey);
+ free(server_key);
return retval;
}
@@ -3002,191 +3082,6 @@ pkinit_openssl_init()
}
static krb5_error_code
-pkinit_encode_dh_params(const BIGNUM *p, const BIGNUM *g, const BIGNUM *q,
- uint8_t **buf, unsigned int *buf_len)
-{
- krb5_error_code retval = ENOMEM;
- int bufsize = 0, r = 0;
- unsigned char *tmp = NULL;
- ASN1_INTEGER *ap = NULL, *ag = NULL, *aq = NULL;
-
- if ((ap = BN_to_ASN1_INTEGER(p, NULL)) == NULL)
- goto cleanup;
- if ((ag = BN_to_ASN1_INTEGER(g, NULL)) == NULL)
- goto cleanup;
- if ((aq = BN_to_ASN1_INTEGER(q, NULL)) == NULL)
- goto cleanup;
- bufsize = i2d_ASN1_INTEGER(ap, NULL);
- bufsize += i2d_ASN1_INTEGER(ag, NULL);
- bufsize += i2d_ASN1_INTEGER(aq, NULL);
-
- r = ASN1_object_size(1, bufsize, V_ASN1_SEQUENCE);
-
- tmp = *buf = malloc((size_t) r);
- if (tmp == NULL)
- goto cleanup;
-
- ASN1_put_object(&tmp, 1, bufsize, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
-
- i2d_ASN1_INTEGER(ap, &tmp);
- i2d_ASN1_INTEGER(ag, &tmp);
- i2d_ASN1_INTEGER(aq, &tmp);
-
- *buf_len = r;
-
- retval = 0;
-
-cleanup:
- if (ap != NULL)
- ASN1_INTEGER_free(ap);
- if (ag != NULL)
- ASN1_INTEGER_free(ag);
- if (aq != NULL)
- ASN1_INTEGER_free(aq);
-
- return retval;
-}
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-
-/*
- * We need to decode DomainParameters from RFC 3279 section 2.3.3. We would
- * like to just call d2i_DHxparams(), but Microsoft's implementation may omit
- * the q value in violation of the RFC. Instead we must copy the internal
- * structures and sequence declarations from dh_asn1.c, modified to make the q
- * field optional.
- */
-
-typedef struct {
- ASN1_BIT_STRING *seed;
- BIGNUM *counter;
-} int_dhvparams;
-
-typedef struct {
- BIGNUM *p;
- BIGNUM *q;
- BIGNUM *g;
- BIGNUM *j;
- int_dhvparams *vparams;
-} int_dhx942_dh;
-
-ASN1_SEQUENCE(DHvparams) = {
- ASN1_SIMPLE(int_dhvparams, seed, ASN1_BIT_STRING),
- ASN1_SIMPLE(int_dhvparams, counter, BIGNUM)
-} static_ASN1_SEQUENCE_END_name(int_dhvparams, DHvparams)
-
-ASN1_SEQUENCE(DHxparams) = {
- ASN1_SIMPLE(int_dhx942_dh, p, BIGNUM),
- ASN1_SIMPLE(int_dhx942_dh, g, BIGNUM),
- ASN1_OPT(int_dhx942_dh, q, BIGNUM),
- ASN1_OPT(int_dhx942_dh, j, BIGNUM),
- ASN1_OPT(int_dhx942_dh, vparams, DHvparams),
-} static_ASN1_SEQUENCE_END_name(int_dhx942_dh, DHxparams)
-
-static DH *
-decode_dh_params(const uint8_t *p, unsigned int len)
-{
- int_dhx942_dh *params;
- DH *dh;
-
- dh = DH_new();
- if (dh == NULL)
- return NULL;
-
- params = (int_dhx942_dh *)ASN1_item_d2i(NULL, &p, len,
- ASN1_ITEM_rptr(DHxparams));
- if (params == NULL) {
- DH_free(dh);
- return NULL;
- }
-
- /* Steal the p, q, and g values from dhparams for dh. Ignore j and
- * vparams. */
- DH_set0_pqg(dh, params->p, params->q, params->g);
- params->p = params->q = params->g = NULL;
- ASN1_item_free((ASN1_VALUE *)params, ASN1_ITEM_rptr(DHxparams));
- return dh;
-}
-
-#else /* OPENSSL_VERSION_NUMBER < 0x10100000L */
-
-/*
- * Do the same decoding (except without decoding j and vparams or checking the
- * sequence length) using the pre-OpenSSL-1.1 asn1_mac.h. Define an internal
- * function in the form demanded by the macros, then wrap it for caller
- * convenience.
- */
-
-static DH *
-decode_dh_params_int(DH ** a, uint8_t **pp, unsigned int len)
-{
- ASN1_INTEGER ai, *aip = NULL;
- long length = (long) len;
-
- M_ASN1_D2I_vars(a, DH *, DH_new);
-
- M_ASN1_D2I_Init();
- M_ASN1_D2I_start_sequence();
- aip = &ai;
- ai.data = NULL;
- ai.length = 0;
- M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
- if (aip == NULL)
- return NULL;
- else {
- ret->p = ASN1_INTEGER_to_BN(aip, NULL);
- if (ret->p == NULL)
- return NULL;
- if (ai.data != NULL) {
- OPENSSL_free(ai.data);
- ai.data = NULL;
- ai.length = 0;
- }
- }
- M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
- if (aip == NULL)
- return NULL;
- else {
- ret->g = ASN1_INTEGER_to_BN(aip, NULL);
- if (ret->g == NULL)
- return NULL;
- if (ai.data != NULL) {
- OPENSSL_free(ai.data);
- ai.data = NULL;
- ai.length = 0;
- }
-
- }
- M_ASN1_D2I_get_opt(aip, d2i_ASN1_INTEGER, V_ASN1_INTEGER);
- if (aip == NULL || ai.data == NULL)
- ret->q = NULL;
- else {
- ret->q = ASN1_INTEGER_to_BN(aip, NULL);
- if (ret->q == NULL)
- return NULL;
- if (ai.data != NULL) {
- OPENSSL_free(ai.data);
- ai.data = NULL;
- ai.length = 0;
- }
-
- }
- M_ASN1_D2I_end_sequence();
- M_ASN1_D2I_Finish(a, DH_free, 0);
-
-}
-
-static DH *
-decode_dh_params(const uint8_t *p, unsigned int len)
-{
- uint8_t *ptr = (uint8_t *)p;
-
- return decode_dh_params_int(NULL, &ptr, len);
-}
-
-#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
-
-static krb5_error_code
pkinit_create_sequence_of_principal_identifiers(
krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
@@ -3297,151 +3192,50 @@ pkinit_create_td_dh_parameters(krb5_context context,
pkinit_plg_opts *opts,
krb5_pa_data ***e_data_out)
{
- krb5_error_code retval = ENOMEM;
- unsigned int buf1_len = 0, buf2_len = 0, buf3_len = 0, i = 0;
- unsigned char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
+ krb5_error_code ret;
+ int i;
krb5_pa_data **pa_data = NULL;
- krb5_data *encoded_algId = NULL;
- krb5_algorithm_identifier **algId = NULL;
- const BIGNUM *p, *q, *g;
+ krb5_data *der_alglist = NULL;
+ krb5_algorithm_identifier alg_1024 = { dh_oid, oakley_1024 };
+ krb5_algorithm_identifier alg_2048 = { dh_oid, oakley_2048 };
+ krb5_algorithm_identifier alg_4096 = { dh_oid, oakley_4096 };
+ krb5_algorithm_identifier *alglist[4];
- if (opts->dh_min_bits > 4096)
+ if (opts->dh_min_bits > 4096) {
+ ret = KRB5KRB_ERR_GENERIC;
goto cleanup;
-
- if (opts->dh_min_bits <= 1024) {
- DH_get0_pqg(plg_cryptoctx->dh_1024, &p, &q, &g);
- retval = pkinit_encode_dh_params(p, g, q, &buf1, &buf1_len);
- if (retval)
- goto cleanup;
- }
- if (opts->dh_min_bits <= 2048) {
- DH_get0_pqg(plg_cryptoctx->dh_2048, &p, &q, &g);
- retval = pkinit_encode_dh_params(p, g, q, &buf2, &buf2_len);
- if (retval)
- goto cleanup;
}
- DH_get0_pqg(plg_cryptoctx->dh_4096, &p, &q, &g);
- retval = pkinit_encode_dh_params(p, g, q, &buf3, &buf3_len);
- if (retval)
- goto cleanup;
- if (opts->dh_min_bits <= 1024) {
- algId = malloc(4 * sizeof(krb5_algorithm_identifier *));
- if (algId == NULL)
- goto cleanup;
- algId[3] = NULL;
- algId[0] = malloc(sizeof(krb5_algorithm_identifier));
- if (algId[0] == NULL)
- goto cleanup;
- algId[0]->parameters.data = malloc(buf2_len);
- if (algId[0]->parameters.data == NULL)
- goto cleanup;
- memcpy(algId[0]->parameters.data, buf2, buf2_len);
- algId[0]->parameters.length = buf2_len;
- algId[0]->algorithm = dh_oid;
-
- algId[1] = malloc(sizeof(krb5_algorithm_identifier));
- if (algId[1] == NULL)
- goto cleanup;
- algId[1]->parameters.data = malloc(buf3_len);
- if (algId[1]->parameters.data == NULL)
- goto cleanup;
- memcpy(algId[1]->parameters.data, buf3, buf3_len);
- algId[1]->parameters.length = buf3_len;
- algId[1]->algorithm = dh_oid;
+ i = 0;
+ if (opts->dh_min_bits <= 2048)
+ alglist[i++] = &alg_2048;
+ alglist[i++] = &alg_4096;
+ if (opts->dh_min_bits <= 1024)
+ alglist[i++] = &alg_1024;
+ alglist[i] = NULL;
- algId[2] = malloc(sizeof(krb5_algorithm_identifier));
- if (algId[2] == NULL)
- goto cleanup;
- algId[2]->parameters.data = malloc(buf1_len);
- if (algId[2]->parameters.data == NULL)
- goto cleanup;
- memcpy(algId[2]->parameters.data, buf1, buf1_len);
- algId[2]->parameters.length = buf1_len;
- algId[2]->algorithm = dh_oid;
-
- } else if (opts->dh_min_bits <= 2048) {
- algId = malloc(3 * sizeof(krb5_algorithm_identifier *));
- if (algId == NULL)
- goto cleanup;
- algId[2] = NULL;
- algId[0] = malloc(sizeof(krb5_algorithm_identifier));
- if (algId[0] == NULL)
- goto cleanup;
- algId[0]->parameters.data = malloc(buf2_len);
- if (algId[0]->parameters.data == NULL)
- goto cleanup;
- memcpy(algId[0]->parameters.data, buf2, buf2_len);
- algId[0]->parameters.length = buf2_len;
- algId[0]->algorithm = dh_oid;
-
- algId[1] = malloc(sizeof(krb5_algorithm_identifier));
- if (algId[1] == NULL)
- goto cleanup;
- algId[1]->parameters.data = malloc(buf3_len);
- if (algId[1]->parameters.data == NULL)
- goto cleanup;
- memcpy(algId[1]->parameters.data, buf3, buf3_len);
- algId[1]->parameters.length = buf3_len;
- algId[1]->algorithm = dh_oid;
-
- } else if (opts->dh_min_bits <= 4096) {
- algId = malloc(2 * sizeof(krb5_algorithm_identifier *));
- if (algId == NULL)
- goto cleanup;
- algId[1] = NULL;
- algId[0] = malloc(sizeof(krb5_algorithm_identifier));
- if (algId[0] == NULL)
- goto cleanup;
- algId[0]->parameters.data = malloc(buf3_len);
- if (algId[0]->parameters.data == NULL)
- goto cleanup;
- memcpy(algId[0]->parameters.data, buf3, buf3_len);
- algId[0]->parameters.length = buf3_len;
- algId[0]->algorithm = dh_oid;
-
- }
- retval = k5int_encode_krb5_td_dh_parameters((krb5_algorithm_identifier *const *)algId, &encoded_algId);
- if (retval)
+ ret = k5int_encode_krb5_td_dh_parameters(alglist, &der_alglist);
+ if (ret)
goto cleanup;
-#ifdef DEBUG_ASN1
- print_buffer_bin((unsigned char *)encoded_algId->data,
- encoded_algId->length, "/tmp/kdc_td_dh_params");
-#endif
- pa_data = malloc(2 * sizeof(krb5_pa_data *));
- if (pa_data == NULL) {
- retval = ENOMEM;
+
+ pa_data = k5calloc(2, sizeof(*pa_data), &ret);
+ if (pa_data == NULL)
goto cleanup;
- }
pa_data[1] = NULL;
- pa_data[0] = malloc(sizeof(krb5_pa_data));
+ pa_data[0] = k5alloc(sizeof(*pa_data[0]), &ret);
if (pa_data[0] == NULL) {
free(pa_data);
- retval = ENOMEM;
goto cleanup;
}
pa_data[0]->pa_type = TD_DH_PARAMETERS;
- pa_data[0]->length = encoded_algId->length;
- pa_data[0]->contents = (krb5_octet *)encoded_algId->data;
+ pa_data[0]->length = der_alglist->length;
+ pa_data[0]->contents = (krb5_octet *)der_alglist->data;
+ der_alglist->data = NULL;
*e_data_out = pa_data;
- retval = 0;
-cleanup:
-
- free(buf1);
- free(buf2);
- free(buf3);
- free(encoded_algId);
-
- if (algId != NULL) {
- while(algId[i] != NULL) {
- free(algId[i]->parameters.data);
- free(algId[i]);
- i++;
- }
- free(algId);
- }
- return retval;
+cleanup:
+ krb5_free_data(context, der_alglist);
+ return ret;
}
krb5_error_code
@@ -3478,26 +3272,6 @@ pkinit_check_kdc_pkid(krb5_context context,
return 0;
}
-/* Check parameters against a well-known DH group. */
-static int
-pkinit_check_dh_params(DH *dh1, DH *dh2)
-{
- const BIGNUM *p1, *p2, *g1, *g2;
-
- DH_get0_pqg(dh1, &p1, NULL, &g1);
- DH_get0_pqg(dh2, &p2, NULL, &g2);
- if (BN_cmp(p1, p2) != 0) {
- pkiDebug("p is not well-known group dhparameter\n");
- return -1;
- }
- if (BN_cmp(g1, g2) != 0) {
- pkiDebug("bad g dhparameter\n");
- return -1;
- }
- pkiDebug("good %d dhparams\n", BN_num_bits(p1));
- return 0;
-}
-
krb5_error_code
pkinit_process_td_dh_params(krb5_context context,
pkinit_plg_crypto_context cryptoctx,
@@ -3507,60 +3281,55 @@ pkinit_process_td_dh_params(krb5_context context,
int *new_dh_size)
{
krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
- int i = 0, use_sent_dh = 0, ok = 0;
+ EVP_PKEY *params = NULL;
+ int i, dh_prime_bits, old_dh_size;
pkiDebug("dh parameters\n");
- while (algId[i] != NULL) {
- DH *dh = NULL;
- const BIGNUM *p;
- int dh_prime_bits = 0;
+ EVP_PKEY_free(req_cryptoctx->received_params);
+ req_cryptoctx->received_params = NULL;
+
+ old_dh_size = *new_dh_size;
+ for (i = 0; algId[i] != NULL; i++) {
+ /* Free any parameters from the previous iteration. */
+ EVP_PKEY_free(params);
+ params = NULL;
+
+ /* Skip any parameters for algorithms other than DH. */
if (algId[i]->algorithm.length != dh_oid.length ||
memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
- goto cleanup;
+ continue;
- dh = decode_dh_params((uint8_t *)algId[i]->parameters.data,
- algId[i]->parameters.length);
- if (dh == NULL)
- goto cleanup;
- DH_get0_pqg(dh, &p, NULL, NULL);
- dh_prime_bits = BN_num_bits(p);
+ params = decode_dh_params(&algId[i]->parameters);
+ if (params == NULL)
+ continue;
+ dh_prime_bits = EVP_PKEY_get_bits(params);
+ /* Skip any parameters shorter than the previous size. */
+ if (dh_prime_bits < old_dh_size)
+ continue;
pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
*new_dh_size, dh_prime_bits);
- ok = check_dh_wellknown(cryptoctx, dh, dh_prime_bits);
- if (ok) {
+
+ /* If this is one of our well-known groups, just save the new size; we
+ * will use our own copy of the parameters. */
+ if (check_dh_wellknown(cryptoctx, params, dh_prime_bits)) {
*new_dh_size = dh_prime_bits;
+ retval = 0;
+ goto cleanup;
}
- if (!ok) {
- DH_check(dh, &retval);
- if (retval != 0) {
- pkiDebug("DH parameters provided by server are unacceptable\n");
- retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
- }
- else {
- use_sent_dh = 1;
- ok = 1;
- }
- }
- if (!use_sent_dh)
- DH_free(dh);
- if (ok) {
- if (req_cryptoctx->dh != NULL) {
- DH_free(req_cryptoctx->dh);
- req_cryptoctx->dh = NULL;
- }
- if (use_sent_dh)
- req_cryptoctx->dh = dh;
- break;
+
+ /* If the parameters aren't well-known but check out, save them. */
+ if (params_valid(params)) {
+ req_cryptoctx->received_params = params;
+ params = NULL;
+ retval = 0;
+ goto cleanup;
}
- i++;
}
- if (ok)
- retval = 0;
-
cleanup:
+ EVP_PKEY_free(params);
return retval;
}
@@ -3596,8 +3365,6 @@ pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
switch (pkcs7_type) {
case CMS_SIGN_CLIENT:
return cryptoctx->id_pkinit_authData;
- case CMS_SIGN_DRAFT9:
- return OBJ_nid2obj(NID_pkcs7_data);
case CMS_SIGN_SERVER:
return cryptoctx->id_pkinit_DHKeyData;
case CMS_ENVEL_SERVER:
@@ -3673,33 +3440,48 @@ prepare_enc_data(const uint8_t *indata, int indata_len, uint8_t **outdata,
}
#ifndef WITHOUT_PKCS11
-static void *
-pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
+static struct plugin_file_handle *
+load_pkcs11_module(krb5_context context, const char *modname,
+ CK_FUNCTION_LIST_PTR_PTR p11p)
{
- void *handle;
+ struct plugin_file_handle *handle = NULL;
CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
+ struct errinfo einfo = EMPTY_ERRINFO;
+ const char *errmsg = NULL;
+ void (*sym)();
+ long err;
+ CK_RV rv;
- pkiDebug("loading module \"%s\"... ", modname);
- handle = dlopen(modname, RTLD_NOW);
- if (handle == NULL) {
- pkiDebug("not found\n");
- return NULL;
+ TRACE_PKINIT_PKCS11_OPEN(context, modname);
+ err = krb5int_open_plugin(modname, &handle, &einfo);
+ if (err) {
+ errmsg = k5_get_error(&einfo, err);
+ TRACE_PKINIT_PKCS11_OPEN_FAILED(context, errmsg);
+ goto error;
}
- getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
- if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
- dlclose(handle);
- pkiDebug("failed\n");
- return NULL;
+
+ err = krb5int_get_plugin_func(handle, "C_GetFunctionList", &sym, &einfo);
+ if (err) {
+ errmsg = k5_get_error(&einfo, err);
+ TRACE_PKINIT_PKCS11_GETSYM_FAILED(context, errmsg);
+ goto error;
+ }
+
+ getflist = (CK_RV (*)())sym;
+ rv = (*getflist)(p11p);
+ if (rv != CKR_OK) {
+ TRACE_PKINIT_PKCS11_GETFLIST_FAILED(context, pkcs11err(rv));
+ goto error;
}
- pkiDebug("ok\n");
+
return handle;
-}
-static CK_RV
-pkinit_C_UnloadModule(void *handle)
-{
- dlclose(handle);
- return CKR_OK;
+error:
+ k5_free_error(&einfo, errmsg);
+ k5_clear_error(&einfo);
+ if (handle != NULL)
+ krb5int_close_plugin(handle);
+ return NULL;
}
static krb5_error_code
@@ -3756,7 +3538,7 @@ pkinit_login(krb5_context context,
(u_char *) rdat.data, rdat.length);
if (r != CKR_OK) {
- pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
+ TRACE_PKINIT_PKCS11_LOGIN_FAILED(context, pkcs11err(r));
r = KRB5KDC_ERR_PREAUTH_FAILED;
}
}
@@ -3769,40 +3551,46 @@ static krb5_error_code
pkinit_open_session(krb5_context context,
pkinit_identity_crypto_context cctx)
{
- CK_ULONG i, r;
+ CK_ULONG i, pret;
unsigned char *cp;
size_t label_len;
CK_ULONG count = 0;
- CK_SLOT_ID_PTR slotlist;
+ CK_SLOT_ID_PTR slotlist = NULL;
CK_TOKEN_INFO tinfo;
- char *p11name;
+ char *p11name = NULL;
const char *password;
+ krb5_error_code ret;
if (cctx->p11_module != NULL)
return 0; /* session already open */
/* Load module */
- cctx->p11_module =
- pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
+ cctx->p11_module = load_pkcs11_module(context, cctx->p11_module_name,
+ &cctx->p11);
if (cctx->p11_module == NULL)
return KRB5KDC_ERR_PREAUTH_FAILED;
/* Init */
- if ((r = cctx->p11->C_Initialize(NULL)) != CKR_OK) {
- pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
+ pret = cctx->p11->C_Initialize(NULL);
+ if (pret != CKR_OK) {
+ pkiDebug("C_Initialize: %s\n", pkcs11err(pret));
return KRB5KDC_ERR_PREAUTH_FAILED;
}
/* Get the list of available slots */
if (cctx->p11->C_GetSlotList(TRUE, NULL, &count) != CKR_OK)
return KRB5KDC_ERR_PREAUTH_FAILED;
- if (count == 0)
+ if (count == 0) {
+ TRACE_PKINIT_PKCS11_NO_TOKEN(context);
return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
slotlist = calloc(count, sizeof(CK_SLOT_ID));
if (slotlist == NULL)
return ENOMEM;
- if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK)
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
+ }
/* Look for the given token label, or if none given take the first one */
for (i = 0; i < count; i++) {
@@ -3811,16 +3599,20 @@ pkinit_open_session(krb5_context context,
continue;
/* Open session */
- if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
- NULL, NULL, &cctx->session)) != CKR_OK) {
- pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ pret = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
+ NULL, NULL, &cctx->session);
+ if (pret != CKR_OK) {
+ pkiDebug("C_OpenSession: %s\n", pkcs11err(pret));
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
}
/* Get token info */
- if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
- pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ pret = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo);
+ if (pret != CKR_OK) {
+ pkiDebug("C_GetTokenInfo: %s\n", pkcs11err(pret));
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
}
/* tinfo.label is zero-filled but not necessarily zero-terminated.
@@ -3831,8 +3623,8 @@ pkinit_open_session(krb5_context context,
}
label_len = cp - tinfo.label;
- pkiDebug("open_session: slotid %d token \"%.*s\"\n",
- (int)slotlist[i], (int)label_len, tinfo.label);
+ TRACE_PKINIT_PKCS11_SLOT(context, (int)slotlist[i], (int)label_len,
+ tinfo.label);
if (cctx->token_label == NULL ||
(strlen(cctx->token_label) == label_len &&
memcmp(cctx->token_label, tinfo.label, label_len) == 0))
@@ -3840,12 +3632,11 @@ pkinit_open_session(krb5_context context,
cctx->p11->C_CloseSession(cctx->session);
}
if (i >= count) {
- free(slotlist);
- pkiDebug("open_session: no matching token found\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ TRACE_PKINIT_PKCS11_NO_MATCH_TOKEN(context);
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
}
cctx->slotid = slotlist[i];
- free(slotlist);
pkiDebug("open_session: slotid %d (%lu of %d)\n", (int)cctx->slotid,
i + 1, (int) count);
@@ -3865,23 +3656,26 @@ pkinit_open_session(krb5_context context,
(int)label_len, tinfo.label) < 0)
p11name = NULL;
}
- } else {
- p11name = NULL;
}
if (cctx->defer_id_prompt) {
/* Supply the identity name to be passed to the responder. */
pkinit_set_deferred_id(&cctx->deferred_ids,
p11name, tinfo.flags, NULL);
- free(p11name);
- return KRB5KRB_ERR_GENERIC;
+ ret = 0;
+ goto cleanup;
}
/* Look up a responder-supplied password for the token. */
password = pkinit_find_deferred_id(cctx->deferred_ids, p11name);
- free(p11name);
- r = pkinit_login(context, cctx, &tinfo, password);
+ ret = pkinit_login(context, cctx, &tinfo, password);
+ if (ret)
+ goto cleanup;
}
- return r;
+ ret = 0;
+cleanup:
+ free(slotlist);
+ free(p11name);
+ return ret;
}
/*
@@ -3950,13 +3744,13 @@ pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
if (r != CKR_OK) {
pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
- pkinit_pkcs11_code_to_text(r));
+ pkcs11err(r));
return KRB5KDC_ERR_PREAUTH_FAILED;
}
r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
- pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
+ pkiDebug("found %d private keys (%s)\n", (int)count, pkcs11err(r));
if (r != CKR_OK || count < 1)
return KRB5KDC_ERR_PREAUTH_FAILED;
return 0;
@@ -3972,8 +3766,10 @@ pkinit_decode_data_fs(krb5_context context,
X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
id_cryptoctx->cert_index);
EVP_PKEY *pkey = id_cryptoctx->my_key;
- uint8_t *buf;
- int buf_len, decrypt_len;
+ EVP_PKEY_CTX *ctx = NULL;
+ uint8_t *buf = NULL;
+ size_t buf_len = 0;
+ int ok;
*decoded_data = NULL;
*decoded_data_len = 0;
@@ -3983,21 +3779,40 @@ pkinit_decode_data_fs(krb5_context context,
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- buf_len = EVP_PKEY_size(pkey);
- buf = malloc(buf_len + 10);
- if (buf == NULL)
+ ctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (ctx == NULL)
return KRB5KDC_ERR_PREAUTH_FAILED;
- decrypt_len = EVP_PKEY_decrypt_old(buf, data, data_len, pkey);
- if (decrypt_len <= 0) {
- pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
- free(buf);
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ ok = EVP_PKEY_decrypt_init(ctx);
+ if (!ok)
+ goto cleanup;
+
+ /* Get the length of the eventual output. */
+ ok = EVP_PKEY_decrypt(ctx, NULL, &buf_len, data, data_len);
+ if (!ok) {
+ pkiDebug("unable to decrypt received data\n");
+ goto cleanup;
+ }
+
+ buf = malloc(buf_len);
+ if (buf == NULL) {
+ ok = 0;
+ goto cleanup;
+ }
+
+ ok = EVP_PKEY_decrypt(ctx, buf, &buf_len, data, data_len);
+ if (!ok) {
+ pkiDebug("unable to decrypt received data\n");
+ goto cleanup;
}
*decoded_data = buf;
- *decoded_data_len = decrypt_len;
- return 0;
+ *decoded_data_len = buf_len;
+ buf = NULL;
+cleanup:
+ zapfree(buf, buf_len);
+ EVP_PKEY_CTX_free(ctx);
+ return ok ? 0 : KRB5KDC_ERR_PREAUTH_FAILED;
}
#ifndef WITHOUT_PKCS11
@@ -4069,7 +3884,7 @@ pkinit_decode_data_pkcs11(krb5_context context,
r = pkinit_C_Decrypt(id_cryptoctx, (CK_BYTE_PTR) data, (CK_ULONG) data_len,
cp, &len);
if (r != CKR_OK) {
- pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
+ pkiDebug("C_Decrypt: %s\n", pkcs11err(r));
if (r == CKR_BUFFER_TOO_SMALL)
pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
return KRB5KDC_ERR_PREAUTH_FAILED;
@@ -4149,7 +3964,7 @@ pkinit_sign_data_pkcs11(krb5_context context,
if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
obj)) != CKR_OK) {
- pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
+ pkiDebug("C_SignInit: %s\n", pkcs11err(r));
return KRB5KDC_ERR_PREAUTH_FAILED;
}
@@ -4172,7 +3987,7 @@ pkinit_sign_data_pkcs11(krb5_context context,
(CK_ULONG) data_len, cp, &len);
}
if (r != CKR_OK) {
- pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
+ pkiDebug("C_Sign: %s\n", pkcs11err(r));
return KRB5KDC_ERR_PREAUTH_FAILED;
}
pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
@@ -4219,7 +4034,7 @@ create_signature(unsigned char **sig, unsigned int *sig_len,
ctx = EVP_MD_CTX_new();
if (ctx == NULL)
return ENOMEM;
- EVP_SignInit(ctx, EVP_sha1());
+ EVP_SignInit(ctx, EVP_sha256());
EVP_SignUpdate(ctx, data, data_len);
*sig_len = EVP_PKEY_size(pkey);
if ((*sig = malloc(*sig_len)) == NULL)
@@ -4434,17 +4249,18 @@ pkinit_load_fs_cert_and_key(krb5_context context,
/* Load the certificate. */
retval = get_cert(certname, &x);
- if (retval != 0 || x == NULL) {
- retval = oerr(context, 0, _("Cannot read certificate file '%s'"),
+ if (retval) {
+ retval = oerr(context, retval, _("Cannot read certificate file '%s'"),
certname);
- goto cleanup;
}
+ if (retval || x == NULL)
+ goto cleanup;
/* Load the key. */
retval = get_key(context, id_cryptoctx, keyname, fsname, &y, password);
- if (retval != 0 || y == NULL) {
- retval = oerr(context, 0, _("Cannot read key file '%s'"), fsname);
+ if (retval)
+ retval = oerr(context, retval, _("Cannot read key file '%s'"), fsname);
+ if (retval || y == NULL)
goto cleanup;
- }
id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
if (id_cryptoctx->creds[cindex] == NULL) {
@@ -4590,7 +4406,6 @@ reassemble_pkcs11_name(pkinit_identity_opts *idopts)
{
struct k5buf buf;
int n = 0;
- char *ret;
k5_buf_init_dynamic(&buf);
k5_buf_add(&buf, "PKCS11:");
@@ -4615,11 +4430,89 @@ reassemble_pkcs11_name(pkinit_identity_opts *idopts)
k5_buf_add_fmt(&buf, "%sslotid=%ld", n++ ? ":" : "",
(long)idopts->slotid);
}
- if (k5_buf_status(&buf) == 0)
- ret = strdup(buf.data);
- else
- ret = NULL;
- k5_buf_free(&buf);
+ return k5_buf_cstring(&buf);
+}
+
+static krb5_error_code
+load_one_cert(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE session,
+ pkinit_identity_opts *idopts, pkinit_cred_info *cred_out)
+{
+ krb5_error_code ret;
+ CK_ATTRIBUTE attrs[2];
+ CK_BYTE_PTR cert = NULL, cert_id = NULL;
+ CK_RV pret;
+ const unsigned char *cp;
+ CK_OBJECT_HANDLE obj;
+ CK_ULONG count;
+ X509 *x = NULL;
+ pkinit_cred_info cred;
+
+ *cred_out = NULL;
+
+ /* Look for X.509 cert. */
+ pret = p11->C_FindObjects(session, &obj, 1, &count);
+ if (pret != CKR_OK || count <= 0)
+ return 0;
+
+ /* Get cert and id len. */
+ attrs[0].type = CKA_VALUE;
+ attrs[0].pValue = NULL;
+ attrs[0].ulValueLen = 0;
+ attrs[1].type = CKA_ID;
+ attrs[1].pValue = NULL;
+ attrs[1].ulValueLen = 0;
+ pret = p11->C_GetAttributeValue(session, obj, attrs, 2);
+ if (pret != CKR_OK && pret != CKR_BUFFER_TOO_SMALL) {
+ pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(pret));
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
+ }
+
+ /* Allocate buffers and read the cert and id. */
+ cert = k5alloc(attrs[0].ulValueLen + 1, &ret);
+ if (cert == NULL)
+ goto cleanup;
+ cert_id = k5alloc(attrs[1].ulValueLen + 1, &ret);
+ if (cert_id == NULL)
+ goto cleanup;
+ attrs[0].type = CKA_VALUE;
+ attrs[0].pValue = cert;
+ attrs[1].type = CKA_ID;
+ attrs[1].pValue = cert_id;
+ pret = p11->C_GetAttributeValue(session, obj, attrs, 2);
+ if (pret != CKR_OK) {
+ pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(pret));
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
+ }
+
+ pkiDebug("cert: size %d, id %d, idlen %d\n", (int)attrs[0].ulValueLen,
+ (int)cert_id[0], (int)attrs[1].ulValueLen);
+
+ cp = (unsigned char *)cert;
+ x = d2i_X509(NULL, &cp, (int)attrs[0].ulValueLen);
+ if (x == NULL) {
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
+ }
+
+ cred = k5alloc(sizeof(struct _pkinit_cred_info), &ret);
+ if (cred == NULL)
+ goto cleanup;
+
+ cred->name = reassemble_pkcs11_name(idopts);
+ cred->cert = x;
+ cred->key = NULL;
+ cred->cert_id = cert_id;
+ cred->cert_id_len = attrs[1].ulValueLen;
+
+ *cred_out = cred;
+ cert_id = NULL;
+ ret = 0;
+
+cleanup:
+ free(cert);
+ free(cert_id);
return ret;
}
@@ -4631,20 +4524,13 @@ pkinit_get_certs_pkcs11(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
krb5_principal princ)
{
-#ifdef PKINIT_USE_MECH_LIST
- CK_MECHANISM_TYPE_PTR mechp;
- CK_MECHANISM_INFO info;
-#endif
CK_OBJECT_CLASS cls;
- CK_OBJECT_HANDLE obj;
CK_ATTRIBUTE attrs[4];
- CK_ULONG count;
CK_CERTIFICATE_TYPE certtype;
- CK_BYTE_PTR cert = NULL, cert_id;
- const unsigned char *cp;
- int i, r;
+ int i;
unsigned int nattrs;
- X509 *x = NULL;
+ krb5_error_code ret;
+ CK_RV pret;
/* Copy stuff from idopts -> id_cryptoctx */
if (idopts->p11_module_name != NULL) {
@@ -4665,27 +4551,20 @@ pkinit_get_certs_pkcs11(krb5_context context,
}
/* Convert the ascii cert_id string into a binary blob */
if (idopts->cert_id_string != NULL) {
- BIGNUM *bn = NULL;
- BN_hex2bn(&bn, idopts->cert_id_string);
- if (bn == NULL)
- return ENOMEM;
- id_cryptoctx->cert_id_len = BN_num_bytes(bn);
- id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
- if (id_cryptoctx->cert_id == NULL) {
- BN_free(bn);
- return ENOMEM;
+ ret = k5_hex_decode(idopts->cert_id_string, &id_cryptoctx->cert_id,
+ &id_cryptoctx->cert_id_len);
+ if (ret) {
+ pkiDebug("Failed to convert certid string [%s]\n",
+ idopts->cert_id_string);
+ return ret;
}
- BN_bn2bin(bn, id_cryptoctx->cert_id);
- BN_free(bn);
}
id_cryptoctx->slotid = idopts->slotid;
id_cryptoctx->pkcs11_method = 1;
- if (pkinit_open_session(context, id_cryptoctx)) {
- pkiDebug("can't open pkcs11 session\n");
- if (!id_cryptoctx->defer_id_prompt)
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
+ ret = pkinit_open_session(context, id_cryptoctx);
+ if (ret)
+ return ret;
if (id_cryptoctx->defer_id_prompt) {
/*
* We need to reset all of the PKCS#11 state, so that the next time we
@@ -4697,56 +4576,24 @@ pkinit_get_certs_pkcs11(krb5_context context,
return 0;
}
-#ifndef PKINIT_USE_MECH_LIST
/*
- * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
- * many cards seems to be confused about whether they are capable of
- * this or not. The safe thing seems to be to ignore the mechanism list,
- * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
+ * We'd like to use CKM_SHA256_RSA_PKCS for signing if it's available, but
+ * historically many cards seem to be confused about whether they are
+ * capable of mechanisms or not. The safe thing seems to be to ignore the
+ * mechanism list, always use CKM_RSA_PKCS and calculate the sha256 digest
+ * ourselves.
*/
-
id_cryptoctx->mech = CKM_RSA_PKCS;
-#else
- if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
- &count)) != CKR_OK || count <= 0) {
- pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
- mechp = malloc(count * sizeof (CK_MECHANISM_TYPE));
- if (mechp == NULL)
- return ENOMEM;
- if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
- mechp, &count)) != CKR_OK)
- return KRB5KDC_ERR_PREAUTH_FAILED;
- for (i = 0; i < count; i++) {
- if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
- mechp[i], &info)) != CKR_OK)
- return KRB5KDC_ERR_PREAUTH_FAILED;
-#ifdef DEBUG_MECHINFO
- pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
- if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
- pkiDebug(" this mech is good for sign & decrypt\n");
-#endif
- if (mechp[i] == CKM_RSA_PKCS) {
- /* This seems backwards... */
- id_cryptoctx->mech =
- (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
- }
- }
- free(mechp);
-
- pkiDebug("got %d mechs from card\n", (int) count);
-#endif
cls = CKO_CERTIFICATE;
attrs[0].type = CKA_CLASS;
attrs[0].pValue = &cls;
- attrs[0].ulValueLen = sizeof cls;
+ attrs[0].ulValueLen = sizeof(cls);
certtype = CKC_X_509;
attrs[1].type = CKA_CERTIFICATE_TYPE;
attrs[1].pValue = &certtype;
- attrs[1].ulValueLen = sizeof certtype;
+ attrs[1].ulValueLen = sizeof(certtype);
nattrs = 2;
@@ -4764,80 +4611,33 @@ pkinit_get_certs_pkcs11(krb5_context context,
nattrs++;
}
- r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
- if (r != CKR_OK) {
- pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
+ pret = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs,
+ nattrs);
+ if (pret != CKR_OK) {
+ pkiDebug("C_FindObjectsInit: %s\n", pkcs11err(pret));
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- for (i = 0; ; i++) {
- if (i >= MAX_CREDS_ALLOWED)
- return KRB5KDC_ERR_PREAUTH_FAILED;
-
- /* Look for x.509 cert */
- if ((r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session,
- &obj, 1, &count)) != CKR_OK || count <= 0) {
- id_cryptoctx->creds[i] = NULL;
- break;
- }
-
- /* Get cert and id len */
- attrs[0].type = CKA_VALUE;
- attrs[0].pValue = NULL;
- attrs[0].ulValueLen = 0;
-
- attrs[1].type = CKA_ID;
- attrs[1].pValue = NULL;
- attrs[1].ulValueLen = 0;
-
- if ((r = id_cryptoctx->p11->C_GetAttributeValue(id_cryptoctx->session,
- obj, attrs, 2)) != CKR_OK && r != CKR_BUFFER_TOO_SMALL) {
- pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
- cert = (CK_BYTE_PTR) malloc((size_t) attrs[0].ulValueLen + 1);
- cert_id = (CK_BYTE_PTR) malloc((size_t) attrs[1].ulValueLen + 1);
- if (cert == NULL || cert_id == NULL)
- return ENOMEM;
-
- /* Read the cert and id off the card */
-
- attrs[0].type = CKA_VALUE;
- attrs[0].pValue = cert;
-
- attrs[1].type = CKA_ID;
- attrs[1].pValue = cert_id;
-
- if ((r = id_cryptoctx->p11->C_GetAttributeValue(id_cryptoctx->session,
- obj, attrs, 2)) != CKR_OK) {
- pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
-
- pkiDebug("cert %d size %d id %d idlen %d\n", i,
- (int) attrs[0].ulValueLen, (int) cert_id[0],
- (int) attrs[1].ulValueLen);
-
- cp = (unsigned char *) cert;
- x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
- if (x == NULL)
- return KRB5KDC_ERR_PREAUTH_FAILED;
- id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
+ for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
+ ret = load_one_cert(id_cryptoctx->p11, id_cryptoctx->session, idopts,
+ &id_cryptoctx->creds[i]);
+ if (ret)
+ return ret;
if (id_cryptoctx->creds[i] == NULL)
- return KRB5KDC_ERR_PREAUTH_FAILED;
- id_cryptoctx->creds[i]->name = reassemble_pkcs11_name(idopts);
- id_cryptoctx->creds[i]->cert = x;
- id_cryptoctx->creds[i]->key = NULL;
- id_cryptoctx->creds[i]->cert_id = cert_id;
- id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
- free(cert);
+ break;
}
+ if (i == MAX_CREDS_ALLOWED)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+
id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
- if (cert == NULL)
+
+ /* Check if we found no certs. */
+ if (id_cryptoctx->creds[0] == NULL)
return KRB5KDC_ERR_PREAUTH_FAILED;
return 0;
}
-#endif
+
+#endif /* !WITHOUT_PKCS11 */
static void
@@ -5060,6 +4860,9 @@ crypto_cert_free_matching_data(krb5_context context,
for (i = 0; md->sans != NULL && md->sans[i] != NULL; i++)
krb5_free_principal(context, md->sans[i]);
free(md->sans);
+ for (i = 0; md->upns != NULL && md->upns[i] != NULL; i++)
+ free(md->upns[i]);
+ free(md->upns);
free(md);
}
@@ -5088,8 +4891,6 @@ get_matching_data(krb5_context context,
{
krb5_error_code ret = ENOMEM;
pkinit_cert_matching_data *md = NULL;
- krb5_principal *pkinit_sans = NULL, *upn_sans = NULL;
- size_t i, j;
*md_out = NULL;
@@ -5106,40 +4907,10 @@ get_matching_data(krb5_context context,
/* Get the SAN data. */
ret = crypto_retrieve_X509_sans(context, plg_cryptoctx, req_cryptoctx,
- cert, &pkinit_sans, &upn_sans, NULL);
+ cert, &md->sans, &md->upns, NULL);
if (ret)
goto cleanup;
- j = 0;
- if (pkinit_sans != NULL) {
- for (i = 0; pkinit_sans[i] != NULL; i++)
- j++;
- }
- if (upn_sans != NULL) {
- for (i = 0; upn_sans[i] != NULL; i++)
- j++;
- }
- if (j != 0) {
- md->sans = calloc((size_t)j+1, sizeof(*md->sans));
- if (md->sans == NULL) {
- ret = ENOMEM;
- goto cleanup;
- }
- j = 0;
- if (pkinit_sans != NULL) {
- for (i = 0; pkinit_sans[i] != NULL; i++)
- md->sans[j++] = pkinit_sans[i];
- free(pkinit_sans);
- }
- if (upn_sans != NULL) {
- for (i = 0; upn_sans[i] != NULL; i++)
- md->sans[j++] = upn_sans[i];
- free(upn_sans);
- }
- md->sans[j] = NULL;
- } else
- md->sans = NULL;
-
/* Get the KU and EKU data. */
ret = crypto_retrieve_X509_key_usage(context, plg_cryptoctx,
req_cryptoctx, cert, &md->ku_bits,
@@ -5508,12 +5279,12 @@ crypto_load_cas_and_crls(krb5_context context,
{
switch (idtype) {
case IDTYPE_FILE:
- TRACE_PKINIT_LOAD_FROM_FILE(context);
+ TRACE_PKINIT_LOAD_FROM_FILE(context, id);
return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
id_cryptoctx, catype, id);
break;
case IDTYPE_DIR:
- TRACE_PKINIT_LOAD_FROM_DIR(context);
+ TRACE_PKINIT_LOAD_FROM_DIR(context, id);
return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
id_cryptoctx, catype, id);
break;
@@ -5651,37 +5422,38 @@ create_krb5_supportedCMSTypes(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
pkinit_req_crypto_context req_cryptoctx,
pkinit_identity_crypto_context id_cryptoctx,
- krb5_algorithm_identifier ***oids)
+ krb5_algorithm_identifier ***algs_out)
{
+ krb5_error_code ret;
+ krb5_algorithm_identifier **algs = NULL;
+ size_t i, count;
- krb5_error_code retval = ENOMEM;
- krb5_algorithm_identifier **loids = NULL;
- krb5_data des3oid = {0, 8, "\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
+ *algs_out = NULL;
- *oids = NULL;
- loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
- if (loids == NULL)
- goto cleanup;
- loids[1] = NULL;
- loids[0] = malloc(sizeof(krb5_algorithm_identifier));
- if (loids[0] == NULL) {
- free(loids);
- goto cleanup;
- }
- retval = pkinit_copy_krb5_data(&loids[0]->algorithm, &des3oid);
- if (retval) {
- free(loids[0]);
- free(loids);
+ /* Count supported OIDs and allocate list (including null terminator). */
+ for (count = 0; supported_cms_algs[count] != NULL; count++);
+ algs = k5calloc(count + 1, sizeof(*algs), &ret);
+ if (algs == NULL)
goto cleanup;
+
+ /* Add an algorithm identifier for each OID, with no parameters. */
+ for (i = 0; i < count; i++) {
+ algs[i] = k5alloc(sizeof(*algs[i]), &ret);
+ if (algs[i] == NULL)
+ goto cleanup;
+ ret = krb5int_copy_data_contents(context, supported_cms_algs[i],
+ &algs[i]->algorithm);
+ if (ret)
+ goto cleanup;
+ algs[i]->parameters = empty_data();
}
- loids[0]->parameters.length = 0;
- loids[0]->parameters.data = NULL;
- *oids = loids;
- retval = 0;
-cleanup:
+ *algs_out = algs;
+ algs = NULL;
- return retval;
+cleanup:
+ free_krb5_algorithm_identifiers(&algs);
+ return ret;
}
krb5_error_code
@@ -5742,39 +5514,6 @@ cleanup:
return retval;
}
-static int
-pkcs7_decrypt(krb5_context context,
- pkinit_identity_crypto_context id_cryptoctx,
- PKCS7 *p7,
- BIO *data)
-{
- BIO *tmpmem = NULL;
- int retval = 0, i = 0;
- char buf[4096];
-
- if(p7 == NULL)
- return 0;
-
- if(!PKCS7_type_is_enveloped(p7)) {
- pkiDebug("wrong pkcs7 content type\n");
- return 0;
- }
-
- if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
- pkiDebug("unable to decrypt pkcs7 object\n");
- return 0;
- }
-
- for(;;) {
- i = BIO_read(tmpmem, buf, sizeof(buf));
- if (i <= 0) break;
- BIO_write(data, buf, i);
- BIO_free_all(tmpmem);
- return 1;
- }
- return retval;
-}
-
krb5_error_code
pkinit_process_td_trusted_certifiers(
krb5_context context,
@@ -5855,118 +5594,86 @@ cleanup:
return retval;
}
-static BIO *
-pkcs7_dataDecode(krb5_context context,
- pkinit_identity_crypto_context id_cryptoctx,
- PKCS7 *p7)
+/* Originally based on OpenSSL's PKCS7_dataDecode(), now modified to remove the
+ * use of BIO objects and to fit the PKINIT internal interfaces. */
+static int
+pkcs7_decrypt(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7,
+ unsigned char **data_out, unsigned int *len_out)
{
- unsigned int eklen=0, tkeylen=0;
- BIO *out=NULL,*etmp=NULL,*bio=NULL;
- unsigned char *ek=NULL, *tkey=NULL;
- ASN1_OCTET_STRING *data_body=NULL;
- const EVP_CIPHER *evp_cipher=NULL;
- EVP_CIPHER_CTX *evp_ctx=NULL;
- X509_ALGOR *enc_alg=NULL;
- STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
- PKCS7_RECIP_INFO *ri=NULL;
+ krb5_error_code ret;
+ int ok = 0, plaintext_len = 0, final_len;
+ unsigned int keylen = 0, eklen = 0, blocksize;
+ unsigned char *ek = NULL, *tkey = NULL, *plaintext = NULL, *use_key;
+ ASN1_OCTET_STRING *data_body = p7->d.enveloped->enc_data->enc_data;
+ const EVP_CIPHER *evp_cipher;
+ EVP_CIPHER_CTX *evp_ctx = NULL;
+ X509_ALGOR *enc_alg = p7->d.enveloped->enc_data->algorithm;
+ STACK_OF(PKCS7_RECIP_INFO) *rsk = p7->d.enveloped->recipientinfo;
+ PKCS7_RECIP_INFO *ri = NULL;
- p7->state=PKCS7_S_HEADER;
+ *data_out = NULL;
+ *len_out = 0;
- rsk=p7->d.enveloped->recipientinfo;
- enc_alg=p7->d.enveloped->enc_data->algorithm;
- data_body=p7->d.enveloped->enc_data->enc_data;
- evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
- if (evp_cipher == NULL) {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
- goto cleanup;
- }
-
- if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
- PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
- goto cleanup;
- }
-
- /* It was encrypted, we need to decrypt the secret key
- * with the private key */
+ p7->state = PKCS7_S_HEADER;
/* RFC 4556 section 3.2.3.2 requires that there be exactly one
* recipientInfo. */
if (sk_PKCS7_RECIP_INFO_num(rsk) != 1) {
pkiDebug("invalid number of EnvelopedData RecipientInfos\n");
- goto cleanup;
+ return 0;
}
-
ri = sk_PKCS7_RECIP_INFO_value(rsk, 0);
- (void)pkinit_decode_data(context, id_cryptoctx,
- ASN1_STRING_get0_data(ri->enc_key),
- ASN1_STRING_length(ri->enc_key), &ek, &eklen);
- evp_ctx=NULL;
- BIO_get_cipher_ctx(etmp,&evp_ctx);
- if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
+ evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
+ if (evp_cipher == NULL)
+ goto cleanup;
+ keylen = EVP_CIPHER_key_length(evp_cipher);
+ blocksize = EVP_CIPHER_block_size(evp_cipher);
+
+ evp_ctx = EVP_CIPHER_CTX_new();
+ if (evp_ctx == NULL)
goto cleanup;
- if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
+ if (!EVP_DecryptInit(evp_ctx, evp_cipher, NULL, NULL) ||
+ EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) <= 0)
goto cleanup;
/* Generate a random symmetric key to avoid exposing timing data if RSA
* decryption fails the padding check. */
- tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
- tkey = OPENSSL_malloc(tkeylen);
- if (tkey == NULL)
- goto cleanup;
- if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
+ tkey = malloc(keylen);
+ if (tkey == NULL || !EVP_CIPHER_CTX_rand_key(evp_ctx, tkey))
goto cleanup;
- if (ek == NULL) {
- ek = tkey;
- eklen = tkeylen;
- tkey = NULL;
- }
- if (eklen != (unsigned)EVP_CIPHER_CTX_key_length(evp_ctx)) {
- /* Some S/MIME clients don't use the same key
- * and effective key length. The key length is
- * determined by the size of the decrypted RSA key.
- */
- if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)eklen)) {
- ek = tkey;
- eklen = tkeylen;
- tkey = NULL;
- }
- }
- if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0)
- goto cleanup;
+ /* Decrypt the secret key with the private key. */
+ ret = pkinit_decode_data(context, id_cryptoctx,
+ ASN1_STRING_get0_data(ri->enc_key),
+ ASN1_STRING_length(ri->enc_key), &ek, &eklen);
+ use_key = (ret || eklen != keylen) ? tkey : ek;
- if (out == NULL)
- out=etmp;
- else
- BIO_push(out,etmp);
- etmp=NULL;
+ /* Allocate a plaintext buffer and decrypt data_body into it. */
+ plaintext = malloc(data_body->length + blocksize);
+ if (plaintext == NULL)
+ goto cleanup;
+ if (!EVP_DecryptInit(evp_ctx, NULL, use_key, NULL))
+ goto cleanup;
+ if (!EVP_DecryptUpdate(evp_ctx, plaintext, &plaintext_len,
+ data_body->data, data_body->length))
+ goto cleanup;
+ if (!EVP_DecryptFinal(evp_ctx, plaintext + plaintext_len, &final_len))
+ goto cleanup;
+ plaintext_len += final_len;
- if (data_body->length > 0)
- bio = BIO_new_mem_buf(data_body->data, data_body->length);
- else {
- bio=BIO_new(BIO_s_mem());
- BIO_set_mem_eof_return(bio,0);
- }
- BIO_push(out,bio);
- bio=NULL;
+ *len_out = plaintext_len;
+ *data_out = plaintext;
+ plaintext = NULL;
+ ok = 1;
- if (0) {
- cleanup:
- if (out != NULL) BIO_free_all(out);
- if (etmp != NULL) BIO_free_all(etmp);
- if (bio != NULL) BIO_free_all(bio);
- out=NULL;
- }
- if (ek != NULL) {
- OPENSSL_cleanse(ek, eklen);
- OPENSSL_free(ek);
- }
- if (tkey != NULL) {
- OPENSSL_cleanse(tkey, tkeylen);
- OPENSSL_free(tkey);
- }
- return(out);
+cleanup:
+ EVP_CIPHER_CTX_free(evp_ctx);
+ zapfree(plaintext, plaintext_len);
+ zapfree(ek, eklen);
+ zapfree(tkey, keylen);
+ return ok;
}
#ifdef DEBUG_DH
@@ -6009,19 +5716,18 @@ print_pubkey(BIGNUM * key, char *msg)
}
#endif
-static char *
-pkinit_pkcs11_code_to_text(int err)
+static const char *
+pkcs11err(int err)
{
int i;
- static char uc[32];
for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
if (pkcs11_errstrings[i].code == err)
break;
if (pkcs11_errstrings[i].text != NULL)
return (pkcs11_errstrings[i].text);
- snprintf(uc, sizeof(uc), _("unknown code 0x%x"), err);
- return (uc);
+
+ return "unknown PKCS11 error";
}
/*
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
index 7411348fab8c..c807f044ac48 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
@@ -45,11 +45,11 @@
#include <openssl/sha.h>
#include <openssl/asn1.h>
#include <openssl/pem.h>
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
#include <openssl/asn1t.h>
-#else
-#include <openssl/asn1_mac.h>
+#include <openssl/cms.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#include <openssl/decoder.h>
#endif
#define DN_BUF_LEN 256
@@ -84,11 +84,11 @@ struct _pkinit_identity_crypto_context {
char *token_label;
char *cert_label;
/* These are crypto-specific */
- void *p11_module;
+ struct plugin_file_handle *p11_module;
CK_SESSION_HANDLE session;
CK_FUNCTION_LIST_PTR p11;
- CK_BYTE_PTR cert_id;
- int cert_id_len;
+ uint8_t *cert_id;
+ size_t cert_id_len;
CK_MECHANISM_TYPE mech;
#endif
krb5_boolean defer_id_prompt;
@@ -96,9 +96,9 @@ struct _pkinit_identity_crypto_context {
};
struct _pkinit_plg_crypto_context {
- DH *dh_1024;
- DH *dh_2048;
- DH *dh_4096;
+ EVP_PKEY *dh_1024;
+ EVP_PKEY *dh_2048;
+ EVP_PKEY *dh_4096;
ASN1_OBJECT *id_pkinit_authData;
ASN1_OBJECT *id_pkinit_DHKeyData;
ASN1_OBJECT *id_pkinit_rkeyData;
@@ -112,7 +112,8 @@ struct _pkinit_plg_crypto_context {
struct _pkinit_req_crypto_context {
X509 *received_cert;
- DH *dh;
+ EVP_PKEY *client_pkey;
+ EVP_PKEY *received_params;
};
#endif /* _PKINIT_CRYPTO_OPENSSL_H */
diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
index e8997c9351a8..a5a979f279aa 100644
--- a/src/plugins/preauth/pkinit/pkinit_identity.c
+++ b/src/plugins/preauth/pkinit/pkinit_identity.c
@@ -29,15 +29,8 @@
* SUCH DAMAGES.
*/
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <unistd.h>
-#include <dirent.h>
-
#include "pkinit.h"
+#include <dirent.h>
static void
free_list(char **list)
@@ -317,29 +310,40 @@ parse_fs_options(krb5_context context,
const char *residual)
{
char *certname, *keyname, *save;
+ char *copy = NULL, *cert_filename = NULL, *key_filename = NULL;
krb5_error_code retval = ENOMEM;
- if (residual == NULL || residual[0] == '\0')
- return 0;
+ if (residual == NULL || residual[0] == '\0' || residual[0] == ',')
+ return EINVAL;
- certname = strdup(residual);
- if (certname == NULL)
+ copy = strdup(residual);
+ if (copy == NULL)
goto cleanup;
- certname = strtok_r(certname, ",", &save);
+ certname = strtok_r(copy, ",", &save);
+ if (certname == NULL)
+ goto cleanup;
keyname = strtok_r(NULL, ",", &save);
- idopts->cert_filename = strdup(certname);
- if (idopts->cert_filename == NULL)
+ cert_filename = strdup(certname);
+ if (cert_filename == NULL)
goto cleanup;
- idopts->key_filename = strdup(keyname ? keyname : certname);
- if (idopts->key_filename == NULL)
+ key_filename = strdup((keyname != NULL) ? keyname : certname);
+ if (key_filename == NULL)
goto cleanup;
+ free(idopts->cert_filename);
+ free(idopts->key_filename);
+ idopts->cert_filename = cert_filename;
+ idopts->key_filename = key_filename;
+ cert_filename = key_filename = NULL;
retval = 0;
+
cleanup:
- free(certname);
+ free(copy);
+ free(cert_filename);
+ free(key_filename);
return retval;
}
@@ -353,10 +357,12 @@ parse_pkcs12_options(krb5_context context,
if (residual == NULL || residual[0] == '\0')
return 0;
+ free(idopts->cert_filename);
idopts->cert_filename = strdup(residual);
if (idopts->cert_filename == NULL)
goto cleanup;
+ free(idopts->key_filename);
idopts->key_filename = strdup(residual);
if (idopts->key_filename == NULL)
goto cleanup;
@@ -375,14 +381,13 @@ process_option_identity(krb5_context context,
pkinit_req_crypto_context req_cryptoctx,
pkinit_identity_opts *idopts,
pkinit_identity_crypto_context id_cryptoctx,
- const char *value)
+ krb5_principal princ, const char *value)
{
const char *residual;
int idtype;
krb5_error_code retval = 0;
- pkiDebug("%s: processing value '%s'\n",
- __FUNCTION__, value ? value : "NULL");
+ TRACE_PKINIT_IDENTITY_OPTION(context, value);
if (value == NULL)
return EINVAL;
@@ -421,7 +426,8 @@ process_option_identity(krb5_context context,
switch (idtype) {
case IDTYPE_ENVVAR:
return process_option_identity(context, plg_cryptoctx, req_cryptoctx,
- idopts, id_cryptoctx, getenv(residual));
+ idopts, id_cryptoctx, princ,
+ secure_getenv(residual));
break;
case IDTYPE_FILE:
retval = parse_fs_options(context, idopts, residual);
@@ -435,6 +441,7 @@ process_option_identity(krb5_context context,
break;
#endif
case IDTYPE_DIR:
+ free(idopts->cert_filename);
idopts->cert_filename = strdup(residual);
if (idopts->cert_filename == NULL)
retval = ENOMEM;
@@ -446,7 +453,16 @@ process_option_identity(krb5_context context,
retval = EINVAL;
break;
}
- return retval;
+ if (retval)
+ return retval;
+
+ retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx, idopts,
+ id_cryptoctx, princ, TRUE);
+ if (retval)
+ return retval;
+
+ crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx, id_cryptoctx);
+ return 0;
}
static krb5_error_code
@@ -521,12 +537,13 @@ pkinit_identity_initialize(krb5_context context,
if (idopts->identity != NULL) {
retval = process_option_identity(context, plg_cryptoctx,
req_cryptoctx, idopts,
- id_cryptoctx, idopts->identity);
+ id_cryptoctx, princ,
+ idopts->identity);
} else if (idopts->identity_alt != NULL) {
for (i = 0; retval != 0 && idopts->identity_alt[i] != NULL; i++) {
retval = process_option_identity(context, plg_cryptoctx,
req_cryptoctx, idopts,
- id_cryptoctx,
+ id_cryptoctx, princ,
idopts->identity_alt[i]);
}
} else {
@@ -536,13 +553,6 @@ pkinit_identity_initialize(krb5_context context,
pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
goto errout;
}
- if (retval)
- goto errout;
-
- retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
- idopts, id_cryptoctx, princ, TRUE);
- if (retval)
- goto errout;
} else {
/* We're the anonymous principal. */
retval = 0;
@@ -569,8 +579,9 @@ pkinit_identity_prompt(krb5_context context,
int do_matching,
krb5_principal princ)
{
- krb5_error_code retval = EINVAL;
+ krb5_error_code retval = 0;
const char *signer_identity;
+ krb5_boolean valid;
int i;
pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
@@ -623,22 +634,36 @@ pkinit_identity_prompt(krb5_context context,
goto errout;
} /* Not anonymous principal */
+ /* Require at least one successful anchor if any are specified. */
+ valid = FALSE;
for (i = 0; idopts->anchors != NULL && idopts->anchors[i] != NULL; i++) {
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
idopts, id_cryptoctx,
idopts->anchors[i], CATYPE_ANCHORS);
- if (retval)
- goto errout;
+ if (!retval)
+ valid = TRUE;
}
+ if (retval && !valid)
+ goto errout;
+ krb5_clear_error_message(context);
+ retval = 0;
+
+ /* Require at least one successful intermediate if any are specified. */
+ valid = FALSE;
for (i = 0; idopts->intermediates != NULL
&& idopts->intermediates[i] != NULL; i++) {
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
idopts, id_cryptoctx,
idopts->intermediates[i],
CATYPE_INTERMEDIATES);
- if (retval)
- goto errout;
+ if (!retval)
+ valid = TRUE;
}
+ if (retval && !valid)
+ goto errout;
+ krb5_clear_error_message(context);
+ retval = 0;
+
for (i = 0; idopts->crls != NULL && idopts->crls[i] != NULL; i++) {
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
idopts, id_cryptoctx, idopts->crls[i],
diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_constants.c b/src/plugins/preauth/pkinit/pkinit_kdf_constants.c
deleted file mode 100644
index 1604f1670ac7..000000000000
--- a/src/plugins/preauth/pkinit/pkinit_kdf_constants.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* plugins/preauth/pkinit/pkinit_kdf_constants.c */
-/*
- * Copyright (C) 2011 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * pkinit_kdf_test.c -- Structures and constants for implementation of
- * pkinit algorithm agility. Includes definitions of algorithm identifiers
- * for SHA-1, SHA-256 and SHA-512.
- */
-
-#include "pkinit.h"
-
-/* statically declare OID constants for all three algorithms */
-const krb5_octet krb5_pkinit_sha1_oid[8] =
-{0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x01};
-const size_t krb5_pkinit_sha1_oid_len = 8;
-const krb5_octet krb5_pkinit_sha256_oid[8] =
-{0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x02};
-const size_t krb5_pkinit_sha256_oid_len = 8;
-const krb5_octet krb5_pkinit_sha512_oid [8] =
-{0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x03};
-const size_t krb5_pkinit_sha512_oid_len = 8;
-
-#define oid_as_data(var, oid_base) \
- const krb5_data var = \
- {0, sizeof oid_base, (char *)oid_base}
-oid_as_data(sha1_id, krb5_pkinit_sha1_oid);
-oid_as_data(sha256_id, krb5_pkinit_sha256_oid);
-oid_as_data(sha512_id, krb5_pkinit_sha512_oid);
-#undef oid_as_data
-
-krb5_data const * const supported_kdf_alg_ids[] = {
- &sha256_id,
- &sha1_id,
- &sha512_id,
- NULL
-};
diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_test.c b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
index 7acbd0d2875f..7f38e84910aa 100644
--- a/src/plugins/preauth/pkinit/pkinit_kdf_test.c
+++ b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
@@ -112,6 +112,10 @@ main(int argc, char **argv)
goto cleanup;
}
+ /* The test vectors in RFC 8636 implicitly use NT-PRINCIPAL names. */
+ u_principal->type = KRB5_NT_PRINCIPAL;
+ v_principal->type = KRB5_NT_PRINCIPAL;
+
/* set-up the as_req and and pk_as_rep data */
memset(twenty_as, 0xaa, sizeof(twenty_as));
memset(eighteen_bs, 0xbb, sizeof(eighteen_bs));
@@ -123,8 +127,7 @@ main(int argc, char **argv)
/* TEST 1: SHA-1/AES */
/* set up algorithm id */
- alg_id.algorithm.data = (char *)krb5_pkinit_sha1_oid;
- alg_id.algorithm.length = krb5_pkinit_sha1_oid_len;
+ alg_id.algorithm = sha1_id;
enctype = enctype_aes;
@@ -134,7 +137,7 @@ main(int argc, char **argv)
u_principal, v_principal,
enctype, &as_req, &pk_as_rep,
&key_block))) {
- printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d",
+ printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d\n",
retval);
goto cleanup;
}
@@ -155,8 +158,7 @@ main(int argc, char **argv)
/* TEST 2: SHA-256/AES */
/* set up algorithm id */
- alg_id.algorithm.data = (char *)krb5_pkinit_sha256_oid;
- alg_id.algorithm.length = krb5_pkinit_sha256_oid_len;
+ alg_id.algorithm = sha256_id;
enctype = enctype_aes;
@@ -166,7 +168,7 @@ main(int argc, char **argv)
u_principal, v_principal,
enctype, &as_req, &pk_as_rep,
&key_block))) {
- printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d",
+ printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d\n",
retval);
goto cleanup;
}
@@ -187,8 +189,7 @@ main(int argc, char **argv)
/* TEST 3: SHA-512/DES3 */
/* set up algorithm id */
- alg_id.algorithm.data = (char *)krb5_pkinit_sha512_oid;
- alg_id.algorithm.length = krb5_pkinit_sha512_oid_len;
+ alg_id.algorithm = sha512_id;
enctype = enctype_des3;
@@ -198,7 +199,7 @@ main(int argc, char **argv)
u_principal, v_principal,
enctype, &as_req, &pk_as_rep,
&key_block))) {
- printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d",
+ printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d\n",
retval);
goto cleanup;
}
@@ -221,5 +222,6 @@ cleanup:
krb5_free_principal(context, u_principal);
krb5_free_principal(context, v_principal);
krb5_free_keyblock_contents(context, &key_block);
- exit(retval);
+ krb5_free_context(context);
+ return retval ? 1 : 0;
}
diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
index 2f88545da841..4c3d46bf5ade 100644
--- a/src/plugins/preauth/pkinit/pkinit_lib.c
+++ b/src/plugins/preauth/pkinit/pkinit_lib.c
@@ -82,6 +82,8 @@ pkinit_init_plg_opts(pkinit_plg_opts **plgopts)
opts->dh_or_rsa = DH_PROTOCOL;
opts->allow_upn = 0;
opts->require_crl_checking = 0;
+ opts->require_freshness = 0;
+ opts->disable_freshness = 0;
opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
@@ -109,15 +111,6 @@ free_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in)
}
void
-free_krb5_pa_pk_as_req_draft9(krb5_pa_pk_as_req_draft9 **in)
-{
- if (*in == NULL) return;
- free((*in)->signedAuthPack.data);
- free((*in)->kdcCert.data);
- free(*in);
-}
-
-void
free_krb5_reply_key_pack(krb5_reply_key_pack **in)
{
if (*in == NULL) return;
@@ -127,24 +120,12 @@ free_krb5_reply_key_pack(krb5_reply_key_pack **in)
}
void
-free_krb5_reply_key_pack_draft9(krb5_reply_key_pack_draft9 **in)
-{
- if (*in == NULL) return;
- free((*in)->replyKey.contents);
- free(*in);
-}
-
-void
free_krb5_auth_pack(krb5_auth_pack **in)
{
if ((*in) == NULL) return;
- if ((*in)->clientPublicValue != NULL) {
- free((*in)->clientPublicValue->algorithm.algorithm.data);
- free((*in)->clientPublicValue->algorithm.parameters.data);
- free((*in)->clientPublicValue->subjectPublicKey.data);
- free((*in)->clientPublicValue);
- }
+ krb5_free_data_contents(NULL, &(*in)->clientPublicValue);
free((*in)->pkAuthenticator.paChecksum.contents);
+ krb5_free_data(NULL, (*in)->pkAuthenticator.freshnessToken);
if ((*in)->supportedCMSTypes != NULL)
free_krb5_algorithm_identifiers(&((*in)->supportedCMSTypes));
if ((*in)->supportedKDFs) {
@@ -158,15 +139,6 @@ free_krb5_auth_pack(krb5_auth_pack **in)
}
void
-free_krb5_auth_pack_draft9(krb5_context context,
- krb5_auth_pack_draft9 **in)
-{
- if ((*in) == NULL) return;
- krb5_free_principal(context, (*in)->pkAuthenticator.kdcName);
- free(*in);
-}
-
-void
free_krb5_pa_pk_as_rep(krb5_pa_pk_as_rep **in)
{
if (*in == NULL) return;
@@ -185,14 +157,6 @@ free_krb5_pa_pk_as_rep(krb5_pa_pk_as_rep **in)
}
void
-free_krb5_pa_pk_as_rep_draft9(krb5_pa_pk_as_rep_draft9 **in)
-{
- if (*in == NULL) return;
- free((*in)->u.encKeyPack.data);
- free(*in);
-}
-
-void
free_krb5_external_principal_identifier(krb5_external_principal_identifier ***in)
{
int i = 0;
@@ -230,15 +194,6 @@ free_krb5_algorithm_identifiers(krb5_algorithm_identifier ***in)
}
void
-free_krb5_subject_pk_info(krb5_subject_pk_info **in)
-{
- if ((*in) == NULL) return;
- free((*in)->algorithm.parameters.data);
- free((*in)->subjectPublicKey.data);
- free(*in);
-}
-
-void
free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in)
{
if (*in == NULL) return;
@@ -259,17 +214,6 @@ init_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in)
}
void
-init_krb5_pa_pk_as_req_draft9(krb5_pa_pk_as_req_draft9 **in)
-{
- (*in) = malloc(sizeof(krb5_pa_pk_as_req_draft9));
- if ((*in) == NULL) return;
- (*in)->signedAuthPack.data = NULL;
- (*in)->signedAuthPack.length = 0;
- (*in)->kdcCert.data = NULL;
- (*in)->kdcCert.length = 0;
-}
-
-void
init_krb5_reply_key_pack(krb5_reply_key_pack **in)
{
(*in) = malloc(sizeof(krb5_reply_key_pack));
@@ -281,15 +225,6 @@ init_krb5_reply_key_pack(krb5_reply_key_pack **in)
}
void
-init_krb5_reply_key_pack_draft9(krb5_reply_key_pack_draft9 **in)
-{
- (*in) = malloc(sizeof(krb5_reply_key_pack_draft9));
- if ((*in) == NULL) return;
- (*in)->replyKey.contents = NULL;
- (*in)->replyKey.length = 0;
-}
-
-void
init_krb5_pa_pk_as_rep(krb5_pa_pk_as_rep **in)
{
(*in) = malloc(sizeof(krb5_pa_pk_as_rep));
@@ -303,28 +238,6 @@ init_krb5_pa_pk_as_rep(krb5_pa_pk_as_rep **in)
(*in)->u.dh_Info.kdfID = NULL;
}
-void
-init_krb5_pa_pk_as_rep_draft9(krb5_pa_pk_as_rep_draft9 **in)
-{
- (*in) = malloc(sizeof(krb5_pa_pk_as_rep_draft9));
- if ((*in) == NULL) return;
- (*in)->u.dhSignedData.length = 0;
- (*in)->u.dhSignedData.data = NULL;
- (*in)->u.encKeyPack.length = 0;
- (*in)->u.encKeyPack.data = NULL;
-}
-
-void
-init_krb5_subject_pk_info(krb5_subject_pk_info **in)
-{
- (*in) = malloc(sizeof(krb5_subject_pk_info));
- if ((*in) == NULL) return;
- (*in)->algorithm.parameters.data = NULL;
- (*in)->algorithm.parameters.length = 0;
- (*in)->subjectPublicKey.data = NULL;
- (*in)->subjectPublicKey.length = 0;
-}
-
krb5_error_code
pkinit_copy_krb5_data(krb5_data *dst, const krb5_data *src)
{
diff --git a/src/plugins/preauth/pkinit/pkinit_matching.c b/src/plugins/preauth/pkinit/pkinit_matching.c
index c1ce84b82641..b42485a50a79 100644
--- a/src/plugins/preauth/pkinit/pkinit_matching.c
+++ b/src/plugins/preauth/pkinit/pkinit_matching.c
@@ -296,7 +296,7 @@ parse_rule_component(krb5_context context,
rc->kwval_type = kwval_type;
/*
- * Before procesing the value for this keyword,
+ * Before processing the value for this keyword,
* (compiling the regular expression or processing the list)
* we need to find the end of it. That means parsing for the
* beginning of the next keyword (or the end of the rule).
@@ -448,50 +448,53 @@ cleanup:
}
static int
-regexp_match(krb5_context context, rule_component *rc, char *value)
+regexp_match(krb5_context context, rule_component *rc, char *value, int idx)
{
int code;
- pkiDebug("%s: checking %s rule '%s' with value '%s'\n",
- __FUNCTION__, keyword2string(rc->kw_type), rc->regsrc, value);
-
code = regexec(&rc->regexp, value, 0, NULL, 0);
- pkiDebug("%s: the result is%s a match\n", __FUNCTION__,
- code == REG_NOMATCH ? " NOT" : "");
+ if (code == 0) {
+ TRACE_PKINIT_REGEXP_MATCH(context, keyword2string(rc->kw_type),
+ rc->regsrc, value, idx);
+ } else {
+ TRACE_PKINIT_REGEXP_NOMATCH(context, keyword2string(rc->kw_type),
+ rc->regsrc, value, idx);
+ }
return (code == 0 ? 1: 0);
}
static int
-component_match(krb5_context context,
- rule_component *rc,
- pkinit_cert_matching_data *md)
+component_match(krb5_context context, rule_component *rc,
+ pkinit_cert_matching_data *md, int idx)
{
int match = 0;
int i;
- krb5_principal p;
char *princ_string;
switch (rc->kwval_type) {
case kwvaltype_regexp:
switch (rc->kw_type) {
case kw_subject:
- match = regexp_match(context, rc, md->subject_dn);
+ match = regexp_match(context, rc, md->subject_dn, idx);
break;
case kw_issuer:
- match = regexp_match(context, rc, md->issuer_dn);
+ match = regexp_match(context, rc, md->issuer_dn, idx);
break;
case kw_san:
- if (md->sans == NULL)
- break;
- for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i]) {
- krb5_unparse_name(context, p, &princ_string);
- match = regexp_match(context, rc, princ_string);
+ for (i = 0; md->sans != NULL && md->sans[i] != NULL; i++) {
+ krb5_unparse_name(context, md->sans[i], &princ_string);
+ match = regexp_match(context, rc, princ_string, idx);
krb5_free_unparsed_name(context, princ_string);
if (match)
break;
}
+ for (i = 0; md->upns != NULL && md->upns[i] != NULL; i++) {
+ match = regexp_match(context, rc, md->upns[i], idx);
+ if (match)
+ break;
+ }
break;
default:
pkiDebug("%s: keyword %s, keyword value %s mismatch\n",
@@ -570,18 +573,9 @@ check_all_certs(krb5_context context,
*/
for (i = 0, md = matchdata[i]; md != NULL; md = matchdata[++i]) {
pkiDebug("%s: subject: '%s'\n", __FUNCTION__, md->subject_dn);
-#if 0
- pkiDebug("%s: issuer: '%s'\n", __FUNCTION__, md->subject_dn);
- for (j = 0, p = md->sans[j]; p != NULL; p = md->sans[++j]) {
- char *san_string;
- krb5_unparse_name(context, p, &san_string);
- pkiDebug("%s: san: '%s'\n", __FUNCTION__, san_string);
- krb5_free_unparsed_name(context, san_string);
- }
-#endif
certs_checked++;
for (rc = rs->crs; rc != NULL; rc = rc->next) {
- comp_match = component_match(context, rc, md);
+ comp_match = component_match(context, rc, md, i);
if (comp_match) {
pkiDebug("%s: match for keyword type %s\n",
__FUNCTION__, keyword2string(rc->kw_type));
@@ -607,8 +601,7 @@ check_all_certs(krb5_context context,
nextcert:
continue;
}
- pkiDebug("%s: After checking %d certs, we found %d matches\n",
- __FUNCTION__, certs_checked, total_cert_matches);
+ TRACE_PKINIT_CERT_NUM_MATCHING(context, certs_checked, total_cert_matches);
if (total_cert_matches == 1) {
*match_found = 1;
*match_index = save_index;
@@ -649,7 +642,7 @@ pkinit_cert_matching(krb5_context context,
/* parse each rule line one at a time and check all the certs against it */
for (x = 0; rules[x] != NULL; x++) {
- pkiDebug("%s: Processing rule '%s'\n", __FUNCTION__, rules[x]);
+ TRACE_PKINIT_CERT_RULE(context, rules[x]);
/* Free rules from previous time through... */
if (rs != NULL) {
@@ -659,8 +652,7 @@ pkinit_cert_matching(krb5_context context,
retval = parse_rule_set(context, rules[x], &rs);
if (retval) {
if (retval == EINVAL) {
- pkiDebug("%s: Ignoring invalid rule pkinit_cert_match = '%s'\n",
- __FUNCTION__, rules[x]);
+ TRACE_PKINIT_CERT_RULE_INVALID(context, rules[x]);
continue;
}
goto cleanup;
@@ -744,7 +736,7 @@ pkinit_client_cert_match(krb5_context context,
goto cleanup;
for (rc = rs->crs; rc != NULL; rc = rc->next) {
- comp_match = component_match(context, rc, md);
+ comp_match = component_match(context, rc, md, 0);
if ((comp_match && rs->relation == relation_or) ||
(!comp_match && rs->relation == relation_and)) {
break;
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index 4e9685885f80..1b3bf6d4d0ee 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -161,6 +161,10 @@ pkinit_server_get_edata(krb5_context context,
if (plgctx == NULL)
retval = EINVAL;
+ /* Send a freshness token if the client requested one. */
+ if (!retval)
+ cb->send_freshness_token(context, rock);
+
(*respond)(arg, retval, NULL);
}
@@ -174,8 +178,9 @@ verify_client_san(krb5_context context,
int *valid_san)
{
krb5_error_code retval;
- krb5_principal *princs = NULL;
- krb5_principal *upns = NULL;
+ krb5_principal *princs = NULL, upn;
+ krb5_boolean match;
+ char **upns = NULL;
int i;
#ifdef DEBUG_SAN_INFO
char *client_string = NULL, *san_string;
@@ -199,24 +204,6 @@ verify_client_san(krb5_context context,
goto out;
}
- /* XXX Verify this is consistent with client side XXX */
-#if 0
- retval = call_san_checking_plugins(context, plgctx, reqctx, princs,
- upns, NULL, &plugin_decision, &ignore);
- pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
- __FUNCTION__);
- if (retval) {
- retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
- goto cleanup;
- }
- pkiDebug("%s: call_san_checking_plugins() returned decision %d\n",
- __FUNCTION__, plugin_decision);
- if (plugin_decision != NO_DECISION) {
- retval = plugin_decision;
- goto out;
- }
-#endif
-
#ifdef DEBUG_SAN_INFO
krb5_unparse_name(context, client, &client_string);
#endif
@@ -251,12 +238,18 @@ verify_client_san(krb5_context context,
pkiDebug("%s: Checking upn sans\n", __FUNCTION__);
for (i = 0; upns[i] != NULL; i++) {
#ifdef DEBUG_SAN_INFO
- krb5_unparse_name(context, upns[i], &san_string);
pkiDebug("%s: Comparing client '%s' to upn san value '%s'\n",
- __FUNCTION__, client_string, san_string);
- krb5_free_unparsed_name(context, san_string);
+ __FUNCTION__, client_string, upns[i]);
#endif
- if (cb->match_client(context, rock, upns[i])) {
+ retval = krb5_parse_name_flags(context, upns[i],
+ KRB5_PRINCIPAL_PARSE_ENTERPRISE, &upn);
+ if (retval) {
+ TRACE_PKINIT_SERVER_UPN_PARSE_FAIL(context, upns[i], retval);
+ continue;
+ }
+ match = cb->match_client(context, rock, upn);
+ krb5_free_principal(context, upn);
+ if (match) {
TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(context);
*valid_san = 1;
retval = 0;
@@ -265,15 +258,7 @@ verify_client_san(krb5_context context,
}
pkiDebug("%s: no upn san match found\n", __FUNCTION__);
- /* We found no match */
- if (princs != NULL || upns != NULL) {
- *valid_san = 0;
- /* XXX ??? If there was one or more name in the cert, but
- * none matched the client name, then return mismatch? */
- retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
- }
retval = 0;
-
out:
if (princs != NULL) {
for (i = 0; princs[i] != NULL; i++)
@@ -282,7 +267,7 @@ out:
}
if (upns != NULL) {
for (i = 0; upns[i] != NULL; i++)
- krb5_free_principal(context, upns[i]);
+ free(upns[i]);
free(upns);
}
#ifdef DEBUG_SAN_INFO
@@ -335,12 +320,12 @@ static krb5_error_code
authorize_cert(krb5_context context, certauth_handle *certauth_modules,
pkinit_kdc_context plgctx, pkinit_kdc_req_context reqctx,
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
- krb5_principal client)
+ krb5_principal client, krb5_boolean *hwauth_out)
{
krb5_error_code ret;
certauth_handle h;
struct certauth_req_opts opts;
- krb5_boolean accepted = FALSE;
+ krb5_boolean accepted = FALSE, hwauth = FALSE;
uint8_t *cert;
size_t i, cert_len;
void *db_ent = NULL;
@@ -362,9 +347,10 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
/*
* Check the certificate against each certauth module. For the certificate
- * to be authorized at least one module must return 0, and no module can an
- * error code other than KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from
- * modules that return 0 or pass.
+ * to be authorized at least one module must return 0 or
+ * KRB5_CERTAUTH_HWAUTH, and no module can return an error code other than
+ * KRB5_PLUGIN_NO_HANDLE (pass) or KRB5_CERTAUTH_HWAUTH_PASS (pass but
+ * set hw-authent). Add indicators from all modules.
*/
ret = KRB5_PLUGIN_NO_HANDLE;
for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) {
@@ -374,6 +360,10 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
&opts, db_ent, &ais);
if (ret == 0)
accepted = TRUE;
+ else if (ret == KRB5_CERTAUTH_HWAUTH)
+ accepted = hwauth = TRUE;
+ else if (ret == KRB5_CERTAUTH_HWAUTH_PASS)
+ hwauth = TRUE;
else if (ret != KRB5_PLUGIN_NO_HANDLE)
goto cleanup;
@@ -389,6 +379,7 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
}
}
+ *hwauth_out = hwauth;
ret = accepted ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
cleanup:
@@ -396,6 +387,31 @@ cleanup:
return ret;
}
+/* Return an error if freshness tokens are required and one was not received.
+ * Log an appropriate message indicating whether a valid token was received. */
+static krb5_error_code
+check_log_freshness(krb5_context context, pkinit_kdc_context plgctx,
+ krb5_kdc_req *request, krb5_boolean valid_freshness_token)
+{
+ krb5_error_code ret;
+ char *name = NULL;
+
+ ret = krb5_unparse_name(context, request->client, &name);
+ if (ret)
+ return ret;
+ if (plgctx->opts->require_freshness && !valid_freshness_token) {
+ com_err("", 0, _("PKINIT: no freshness token, rejecting auth from %s"),
+ name);
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ } else if (valid_freshness_token) {
+ com_err("", 0, _("PKINIT: freshness token received from %s"), name);
+ } else {
+ com_err("", 0, _("PKINIT: no freshness token received from %s"), name);
+ }
+ krb5_free_unparsed_name(context, name);
+ return ret;
+}
+
static void
pkinit_server_verify_padata(krb5_context context,
krb5_data *req_pkt,
@@ -411,17 +427,16 @@ pkinit_server_verify_padata(krb5_context context,
krb5_error_code retval = 0;
krb5_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
krb5_pa_pk_as_req *reqp = NULL;
- krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
krb5_auth_pack *auth_pack = NULL;
- krb5_auth_pack_draft9 *auth_pack9 = NULL;
pkinit_kdc_context plgctx = NULL;
pkinit_kdc_req_context reqctx = NULL;
krb5_checksum cksum = {0, 0, 0, NULL};
krb5_data *der_req = NULL;
- krb5_data k5data;
+ krb5_data k5data, *ftoken;
int is_signed = 1;
krb5_pa_data **e_data = NULL;
krb5_kdcpreauth_modreq modreq = NULL;
+ krb5_boolean valid_freshness_token = FALSE, hwauth = FALSE;
char **sp;
pkiDebug("pkinit_verify_padata: entered!\n");
@@ -453,65 +468,39 @@ pkinit_server_verify_padata(krb5_context context,
PADATA_TO_KRB5DATA(data, &k5data);
- switch ((int)data->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- TRACE_PKINIT_SERVER_PADATA_VERIFY(context);
- retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
- if (retval) {
- pkiDebug("decode_krb5_pa_pk_as_req failed\n");
- goto cleanup;
- }
-#ifdef DEBUG_ASN1
- print_buffer_bin(reqp->signedAuthPack.data,
- reqp->signedAuthPack.length,
- "/tmp/kdc_signed_data");
-#endif
- retval = cms_signeddata_verify(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_CLIENT,
- plgctx->opts->require_crl_checking,
- (unsigned char *)
- reqp->signedAuthPack.data, reqp->signedAuthPack.length,
- (unsigned char **)&authp_data.data,
- &authp_data.length,
- (unsigned char **)&krb5_authz.data,
- &krb5_authz.length, &is_signed);
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- TRACE_PKINIT_SERVER_PADATA_VERIFY_OLD(context);
- retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
- if (retval) {
- pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
- goto cleanup;
- }
-#ifdef DEBUG_ASN1
- print_buffer_bin(reqp9->signedAuthPack.data,
- reqp9->signedAuthPack.length,
- "/tmp/kdc_signed_data_draft9");
-#endif
-
- retval = cms_signeddata_verify(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9,
- plgctx->opts->require_crl_checking,
- (unsigned char *)
- reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
- (unsigned char **)&authp_data.data,
- &authp_data.length,
- (unsigned char **)&krb5_authz.data,
- &krb5_authz.length, NULL);
- break;
- default:
+ if (data->pa_type != KRB5_PADATA_PK_AS_REQ) {
pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
retval = EINVAL;
goto cleanup;
}
+
+ TRACE_PKINIT_SERVER_PADATA_VERIFY(context);
+ retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
+ if (retval) {
+ pkiDebug("decode_krb5_pa_pk_as_req failed\n");
+ goto cleanup;
+ }
+#ifdef DEBUG_ASN1
+ print_buffer_bin(reqp->signedAuthPack.data, reqp->signedAuthPack.length,
+ "/tmp/kdc_signed_data");
+#endif
+ retval = cms_signeddata_verify(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, plgctx->idctx,
+ CMS_SIGN_CLIENT,
+ plgctx->opts->require_crl_checking,
+ (unsigned char *)reqp->signedAuthPack.data,
+ reqp->signedAuthPack.length,
+ (unsigned char **)&authp_data.data,
+ &authp_data.length,
+ (unsigned char **)&krb5_authz.data,
+ &krb5_authz.length, &is_signed);
if (retval) {
TRACE_PKINIT_SERVER_PADATA_VERIFY_FAIL(context);
goto cleanup;
}
if (is_signed) {
retval = authorize_cert(context, moddata->certauth_modules, plgctx,
- reqctx, cb, rock, request->client);
+ reqctx, cb, rock, request->client, &hwauth);
if (retval)
goto cleanup;
@@ -530,108 +519,93 @@ pkinit_server_verify_padata(krb5_context context,
#endif
OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
- switch ((int)data->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
- if (retval) {
- pkiDebug("failed to decode krb5_auth_pack\n");
- goto cleanup;
- }
-
- retval = krb5_check_clockskew(context,
- auth_pack->pkAuthenticator.ctime);
- if (retval)
- goto cleanup;
+ retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
+ if (retval) {
+ pkiDebug("failed to decode krb5_auth_pack\n");
+ goto cleanup;
+ }
- /* check dh parameters */
- if (auth_pack->clientPublicValue != NULL) {
- retval = server_check_dh(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx,
- &auth_pack->clientPublicValue->algorithm.parameters,
- plgctx->opts->dh_min_bits);
+ retval = krb5_check_clockskew(context, auth_pack->pkAuthenticator.ctime);
+ if (retval)
+ goto cleanup;
- if (retval) {
- pkiDebug("bad dh parameters\n");
- goto cleanup;
- }
- } else if (!is_signed) {
- /*Anonymous pkinit requires DH*/
- retval = KRB5KDC_ERR_PREAUTH_FAILED;
- krb5_set_error_message(context, retval,
- _("Anonymous pkinit without DH public "
- "value not supported."));
- goto cleanup;
- }
- der_req = cb->request_body(context, rock);
- retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
- 0, der_req, &cksum);
+ /* check dh parameters */
+ if (auth_pack->clientPublicValue.length > 0) {
+ retval = server_check_dh(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, plgctx->idctx,
+ &auth_pack->clientPublicValue,
+ plgctx->opts->dh_min_bits);
if (retval) {
- pkiDebug("unable to calculate AS REQ checksum\n");
+ pkiDebug("bad dh parameters\n");
goto cleanup;
}
- if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
- k5_bcmp(cksum.contents,
- auth_pack->pkAuthenticator.paChecksum.contents,
- cksum.length) != 0) {
- pkiDebug("failed to match the checksum\n");
+ } else if (!is_signed) {
+ /*Anonymous pkinit requires DH*/
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval,
+ _("Anonymous pkinit without DH public "
+ "value not supported."));
+ goto cleanup;
+ }
+ der_req = cb->request_body(context, rock);
+ retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
+ &cksum);
+ if (retval) {
+ pkiDebug("unable to calculate AS REQ checksum\n");
+ goto cleanup;
+ }
+ if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
+ k5_bcmp(cksum.contents, auth_pack->pkAuthenticator.paChecksum.contents,
+ cksum.length) != 0) {
+ pkiDebug("failed to match the checksum\n");
#ifdef DEBUG_CKSUM
- pkiDebug("calculating checksum on buf size (%d)\n",
- req_pkt->length);
- print_buffer(req_pkt->data, req_pkt->length);
- pkiDebug("received checksum type=%d size=%d ",
- auth_pack->pkAuthenticator.paChecksum.checksum_type,
+ pkiDebug("calculating checksum on buf size (%d)\n", req_pkt->length);
+ print_buffer(req_pkt->data, req_pkt->length);
+ pkiDebug("received checksum type=%d size=%d ",
+ auth_pack->pkAuthenticator.paChecksum.checksum_type,
+ auth_pack->pkAuthenticator.paChecksum.length);
+ print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
auth_pack->pkAuthenticator.paChecksum.length);
- print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
- auth_pack->pkAuthenticator.paChecksum.length);
- pkiDebug("expected checksum type=%d size=%d ",
- cksum.checksum_type, cksum.length);
- print_buffer(cksum.contents, cksum.length);
+ pkiDebug("expected checksum type=%d size=%d ",
+ cksum.checksum_type, cksum.length);
+ print_buffer(cksum.contents, cksum.length);
#endif
- retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
- goto cleanup;
- }
+ retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
+ goto cleanup;
+ }
- /* check if kdcPkId present and match KDC's subjectIdentifier */
- if (reqp->kdcPkId.data != NULL) {
- int valid_kdcPkId = 0;
- retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx,
- (unsigned char *)reqp->kdcPkId.data,
- reqp->kdcPkId.length, &valid_kdcPkId);
- if (retval)
- goto cleanup;
- if (!valid_kdcPkId)
- pkiDebug("kdcPkId in AS_REQ does not match KDC's cert"
- "RFC says to ignore and proceed\n");
+ ftoken = auth_pack->pkAuthenticator.freshnessToken;
+ if (ftoken != NULL) {
+ retval = cb->check_freshness_token(context, rock, ftoken);
+ if (retval)
+ goto cleanup;
+ valid_freshness_token = TRUE;
+ }
- }
- /* remember the decoded auth_pack for verify_padata routine */
- reqctx->rcv_auth_pack = auth_pack;
- auth_pack = NULL;
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = k5int_decode_krb5_auth_pack_draft9(&k5data, &auth_pack9);
- if (retval) {
- pkiDebug("failed to decode krb5_auth_pack_draft9\n");
+ /* check if kdcPkId present and match KDC's subjectIdentifier */
+ if (reqp->kdcPkId.data != NULL) {
+ int valid_kdcPkId = 0;
+ retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, plgctx->idctx,
+ (unsigned char *)reqp->kdcPkId.data,
+ reqp->kdcPkId.length, &valid_kdcPkId);
+ if (retval)
goto cleanup;
+ if (!valid_kdcPkId) {
+ pkiDebug("kdcPkId in AS_REQ does not match KDC's cert; "
+ "RFC says to ignore and proceed\n");
}
- if (auth_pack9->clientPublicValue != NULL) {
- retval = server_check_dh(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx,
- &auth_pack9->clientPublicValue->algorithm.parameters,
- plgctx->opts->dh_min_bits);
+ }
+ /* remember the decoded auth_pack for verify_padata routine */
+ reqctx->rcv_auth_pack = auth_pack;
+ auth_pack = NULL;
- if (retval) {
- pkiDebug("bad dh parameters\n");
- goto cleanup;
- }
- }
- /* remember the decoded auth_pack for verify_padata routine */
- reqctx->rcv_auth_pack9 = auth_pack9;
- auth_pack9 = NULL;
- break;
+ if (is_signed) {
+ retval = check_log_freshness(context, plgctx, request,
+ valid_freshness_token);
+ if (retval)
+ goto cleanup;
}
if (is_signed && plgctx->auth_indicators != NULL) {
@@ -645,6 +619,8 @@ pkinit_server_verify_padata(krb5_context context,
/* remember to set the PREAUTH flag in the reply */
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
+ if (hwauth)
+ enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
modreq = (krb5_kdcpreauth_modreq)reqctx;
reqctx = NULL;
@@ -656,21 +632,13 @@ cleanup:
pkiDebug("pkinit_create_edata failed\n");
}
- switch ((int)data->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- free_krb5_pa_pk_as_req(&reqp);
- free(cksum.contents);
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- free_krb5_pa_pk_as_req_draft9(&reqp9);
- }
+ free_krb5_pa_pk_as_req(&reqp);
+ free(cksum.contents);
free(authp_data.data);
free(krb5_authz.data);
if (reqctx != NULL)
pkinit_fini_kdc_req_context(context, reqctx);
free_krb5_auth_pack(&auth_pack);
- free_krb5_auth_pack_draft9(context, &auth_pack9);
(*respond)(arg, retval, modreq, e_data, NULL);
}
@@ -791,32 +759,26 @@ pkinit_server_return_padata(krb5_context context,
krb5_error_code retval = 0;
krb5_data scratch = {0, 0, NULL};
krb5_pa_pk_as_req *reqp = NULL;
- krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
int i = 0;
- unsigned char *subjectPublicKey = NULL;
unsigned char *dh_pubkey = NULL, *server_key = NULL;
- unsigned int subjectPublicKey_len = 0;
unsigned int server_key_len = 0, dh_pubkey_len = 0;
+ krb5_keyblock reply_key = { 0 };
krb5_kdc_dh_key_info dhkey_info;
krb5_data *encoded_dhkey_info = NULL;
krb5_pa_pk_as_rep *rep = NULL;
- krb5_pa_pk_as_rep_draft9 *rep9 = NULL;
krb5_data *out_data = NULL;
krb5_data secret;
krb5_enctype enctype = -1;
krb5_reply_key_pack *key_pack = NULL;
- krb5_reply_key_pack_draft9 *key_pack9 = NULL;
krb5_data *encoded_key_pack = NULL;
pkinit_kdc_context plgctx;
pkinit_kdc_req_context reqctx;
- int fixed_keypack = 0;
-
*send_pa = NULL;
if (padata->pa_type == KRB5_PADATA_PKINIT_KX) {
return return_pkinit_kx(context, request, reply,
@@ -839,12 +801,6 @@ pkinit_server_return_padata(krb5_context context,
TRACE_PKINIT_SERVER_RETURN_PADATA(context);
reqctx = (pkinit_kdc_req_context)modreq;
- if (encrypting_key->contents) {
- free(encrypting_key->contents);
- encrypting_key->length = 0;
- encrypting_key->contents = NULL;
- }
-
for(i = 0; i < request->nktypes; i++) {
enctype = request->ktype[i];
if (!krb5_c_valid_enctype(enctype))
@@ -860,62 +816,27 @@ pkinit_server_return_padata(krb5_context context,
goto cleanup;
}
- switch((int)reqctx->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- init_krb5_pa_pk_as_rep(&rep);
- if (rep == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- /* let's assume it's RSA. we'll reset it to DH if needed */
- rep->choice = choice_pa_pk_as_rep_encKeyPack;
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- init_krb5_pa_pk_as_rep_draft9(&rep9);
- if (rep9 == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
- break;
- default:
- retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ init_krb5_pa_pk_as_rep(&rep);
+ if (rep == NULL) {
+ retval = ENOMEM;
goto cleanup;
}
+ /* let's assume it's RSA. we'll reset it to DH if needed */
+ rep->choice = choice_pa_pk_as_rep_encKeyPack;
if (reqctx->rcv_auth_pack != NULL &&
- reqctx->rcv_auth_pack->clientPublicValue != NULL) {
- subjectPublicKey = (unsigned char *)
- reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
- subjectPublicKey_len =
- reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
+ reqctx->rcv_auth_pack->clientPublicValue.length > 0) {
rep->choice = choice_pa_pk_as_rep_dhInfo;
- } else if (reqctx->rcv_auth_pack9 != NULL &&
- reqctx->rcv_auth_pack9->clientPublicValue != NULL) {
- subjectPublicKey = (unsigned char *)
- reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.data;
- subjectPublicKey_len =
- reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length;
- rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
- }
- /* if this DH, then process finish computing DH key */
- if (rep != NULL && (rep->choice == choice_pa_pk_as_rep_dhInfo ||
- rep->choice == choice_pa_pk_as_rep_draft9_dhSignedData)) {
pkiDebug("received DH key delivery AS REQ\n");
retval = server_process_dh(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx, subjectPublicKey,
- subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len,
+ reqctx->cryptoctx, plgctx->idctx,
+ &dh_pubkey, &dh_pubkey_len,
&server_key, &server_key_len);
if (retval) {
- pkiDebug("failed to process/create dh paramters\n");
+ pkiDebug("failed to process/create dh parameters\n");
goto cleanup;
}
- }
- if ((rep9 != NULL &&
- rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
- (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
/*
* This is DH, so don't generate the key until after we
@@ -940,143 +861,69 @@ pkinit_server_return_padata(krb5_context context,
"/tmp/kdc_dh_key_info");
#endif
- switch ((int)padata->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- retval = cms_signeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1,
- (unsigned char *)
- encoded_dhkey_info->data,
- encoded_dhkey_info->length,
- (unsigned char **)
- &rep->u.dh_Info.dhSignedData.data,
- &rep->u.dh_Info.dhSignedData.length);
- if (retval) {
- pkiDebug("failed to create pkcs7 signed data\n");
- goto cleanup;
- }
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = cms_signeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1,
- (unsigned char *)
- encoded_dhkey_info->data,
- encoded_dhkey_info->length,
- (unsigned char **)
- &rep9->u.dhSignedData.data,
- &rep9->u.dhSignedData.length);
- if (retval) {
- pkiDebug("failed to create pkcs7 signed data\n");
- goto cleanup;
- }
- break;
+ retval = cms_signeddata_create(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, plgctx->idctx,
+ CMS_SIGN_SERVER,
+ (unsigned char *)
+ encoded_dhkey_info->data,
+ encoded_dhkey_info->length,
+ (unsigned char **)
+ &rep->u.dh_Info.dhSignedData.data,
+ &rep->u.dh_Info.dhSignedData.length);
+ if (retval) {
+ pkiDebug("failed to create pkcs7 signed data\n");
+ goto cleanup;
}
} else {
pkiDebug("received RSA key delivery AS REQ\n");
- retval = krb5_c_make_random_key(context, enctype, encrypting_key);
+ init_krb5_reply_key_pack(&key_pack);
+ if (key_pack == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+
+ retval = krb5_c_make_random_key(context, enctype, &key_pack->replyKey);
if (retval) {
pkiDebug("unable to make a session key\n");
goto cleanup;
}
- /* check if PA_TYPE of KRB5_PADATA_AS_CHECKSUM (132) is present which
- * means the client is requesting that a checksum is send back instead
- * of the nonce.
- */
- for (i = 0; request->padata[i] != NULL; i++) {
- pkiDebug("%s: Checking pa_type 0x%08x\n",
- __FUNCTION__, request->padata[i]->pa_type);
- if (request->padata[i]->pa_type == KRB5_PADATA_AS_CHECKSUM)
- fixed_keypack = 1;
+ retval = krb5_c_make_checksum(context, 0, &key_pack->replyKey,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
+ req_pkt, &key_pack->asChecksum);
+ if (retval) {
+ pkiDebug("unable to calculate AS REQ checksum\n");
+ goto cleanup;
}
- pkiDebug("%s: return checksum instead of nonce = %d\n",
- __FUNCTION__, fixed_keypack);
-
- /* if this is an RFC reply or draft9 client requested a checksum
- * in the reply instead of the nonce, create an RFC-style keypack
- */
- if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) {
- init_krb5_reply_key_pack(&key_pack);
- if (key_pack == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- retval = krb5_c_make_checksum(context, 0,
- encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
- req_pkt, &key_pack->asChecksum);
- if (retval) {
- pkiDebug("unable to calculate AS REQ checksum\n");
- goto cleanup;
- }
#ifdef DEBUG_CKSUM
- pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
- print_buffer(req_pkt->data, req_pkt->length);
- pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
- print_buffer(key_pack->asChecksum.contents,
- key_pack->asChecksum.length);
- pkiDebug("encrypting key (%d)\n", encrypting_key->length);
- print_buffer(encrypting_key->contents, encrypting_key->length);
+ pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
+ print_buffer(req_pkt->data, req_pkt->length);
+ pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
+ print_buffer(key_pack->asChecksum.contents,
+ key_pack->asChecksum.length);
+ pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length);
+ print_buffer(key_pack->replyKey.contents, key_pack->replyKey.length);
#endif
- krb5_copy_keyblock_contents(context, encrypting_key,
- &key_pack->replyKey);
-
- retval = k5int_encode_krb5_reply_key_pack(key_pack,
- &encoded_key_pack);
- if (retval) {
- pkiDebug("failed to encode reply_key_pack\n");
- goto cleanup;
- }
+ retval = k5int_encode_krb5_reply_key_pack(key_pack,
+ &encoded_key_pack);
+ if (retval) {
+ pkiDebug("failed to encode reply_key_pack\n");
+ goto cleanup;
}
- switch ((int)padata->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- rep->choice = choice_pa_pk_as_rep_encKeyPack;
- retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
- (unsigned char *)
- encoded_key_pack->data,
- encoded_key_pack->length,
- (unsigned char **)
- &rep->u.encKeyPack.data,
- &rep->u.encKeyPack.length);
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- /* if the request is from the broken draft9 client that
- * expects back a nonce, create it now
- */
- if (!fixed_keypack) {
- init_krb5_reply_key_pack_draft9(&key_pack9);
- if (key_pack9 == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce;
- krb5_copy_keyblock_contents(context, encrypting_key,
- &key_pack9->replyKey);
-
- retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9,
- &encoded_key_pack);
- if (retval) {
- pkiDebug("failed to encode reply_key_pack\n");
- goto cleanup;
- }
- }
-
- rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
- retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
- (unsigned char *)
- encoded_key_pack->data,
- encoded_key_pack->length,
- (unsigned char **)
- &rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length);
- break;
- }
+ rep->choice = choice_pa_pk_as_rep_encKeyPack;
+ retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, plgctx->idctx,
+ padata->pa_type,
+ (unsigned char *)
+ encoded_key_pack->data,
+ encoded_key_pack->length,
+ (unsigned char **)
+ &rep->u.encKeyPack.data,
+ &rep->u.encKeyPack.length);
if (retval) {
pkiDebug("failed to create pkcs7 enveloped data: %s\n",
error_message(retval));
@@ -1086,23 +933,17 @@ pkinit_server_return_padata(krb5_context context,
print_buffer_bin((unsigned char *)encoded_key_pack->data,
encoded_key_pack->length,
"/tmp/kdc_key_pack");
- switch ((int)padata->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- print_buffer_bin(rep->u.encKeyPack.data,
- rep->u.encKeyPack.length,
- "/tmp/kdc_enc_key_pack");
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- print_buffer_bin(rep9->u.encKeyPack.data,
- rep9->u.encKeyPack.length,
- "/tmp/kdc_enc_key_pack");
- break;
- }
+ print_buffer_bin(rep->u.encKeyPack.data, rep->u.encKeyPack.length,
+ "/tmp/kdc_enc_key_pack");
#endif
+
+ retval = cb->replace_reply_key(context, rock, &key_pack->replyKey,
+ FALSE);
+ if (retval)
+ goto cleanup;
}
- if ((rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo) &&
+ if (rep->choice == choice_pa_pk_as_rep_dhInfo &&
((reqctx->rcv_auth_pack != NULL &&
reqctx->rcv_auth_pack->supportedKDFs != NULL))) {
@@ -1121,15 +962,7 @@ pkinit_server_return_padata(krb5_context context,
}
}
- switch ((int)padata->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
- break;
- }
+ retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
if (retval) {
pkiDebug("failed to encode AS_REP\n");
goto cleanup;
@@ -1141,13 +974,11 @@ pkinit_server_return_padata(krb5_context context,
#endif
/* If this is DH, we haven't computed the key yet, so do it now. */
- if ((rep9 != NULL &&
- rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
- (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
+ if (rep->choice == choice_pa_pk_as_rep_dhInfo) {
- /* If we're not doing draft 9, and mutually supported KDFs were found,
- * use the algorithm agility KDF. */
- if (rep != NULL && rep->u.dh_Info.kdfID) {
+ /* If mutually supported KDFs were found, use the algorithm agility
+ * KDF. */
+ if (rep->u.dh_Info.kdfID) {
secret.data = (char *)server_key;
secret.length = server_key_len;
@@ -1155,7 +986,7 @@ pkinit_server_return_padata(krb5_context context,
rep->u.dh_Info.kdfID,
request->client, request->server,
enctype, req_pkt, out_data,
- encrypting_key);
+ &reply_key);
if (retval) {
pkiDebug("pkinit_alg_agility_kdf failed: %s\n",
error_message(retval));
@@ -1165,13 +996,16 @@ pkinit_server_return_padata(krb5_context context,
/* Otherwise, use the older octetstring2key() function */
} else {
retval = pkinit_octetstring2key(context, enctype, server_key,
- server_key_len, encrypting_key);
+ server_key_len, &reply_key);
if (retval) {
pkiDebug("pkinit_octetstring2key failed: %s\n",
error_message(retval));
goto cleanup;
}
}
+ retval = cb->replace_reply_key(context, rock, &reply_key, FALSE);
+ if (retval)
+ goto cleanup;
}
*send_pa = malloc(sizeof(krb5_pa_data));
@@ -1183,20 +1017,11 @@ pkinit_server_return_padata(krb5_context context,
goto cleanup;
}
(*send_pa)->magic = KV5M_PA_DATA;
- switch ((int)padata->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
- break;
- case KRB5_PADATA_PK_AS_REQ_OLD:
- case KRB5_PADATA_PK_AS_REP_OLD:
- (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
- break;
- }
+ (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
(*send_pa)->length = out_data->length;
(*send_pa)->contents = (krb5_octet *) out_data->data;
cleanup:
- pkinit_fini_kdc_req_context(context, reqctx);
free(scratch.data);
free(out_data);
if (encoded_dhkey_info != NULL)
@@ -1205,23 +1030,10 @@ cleanup:
krb5_free_data(context, encoded_key_pack);
free(dh_pubkey);
free(server_key);
-
- switch ((int)padata->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- free_krb5_pa_pk_as_req(&reqp);
- free_krb5_pa_pk_as_rep(&rep);
- free_krb5_reply_key_pack(&key_pack);
- break;
- case KRB5_PADATA_PK_AS_REP_OLD:
- case KRB5_PADATA_PK_AS_REQ_OLD:
- free_krb5_pa_pk_as_req_draft9(&reqp9);
- free_krb5_pa_pk_as_rep_draft9(&rep9);
- if (!fixed_keypack)
- free_krb5_reply_key_pack_draft9(&key_pack9);
- else
- free_krb5_reply_key_pack(&key_pack);
- break;
- }
+ free_krb5_pa_pk_as_req(&reqp);
+ free_krb5_pa_pk_as_rep(&rep);
+ free_krb5_reply_key_pack(&key_pack);
+ krb5_free_keyblock_contents(context, &reply_key);
if (retval)
pkiDebug("pkinit_verify_padata failure");
@@ -1234,13 +1046,13 @@ pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
{
if (patype == KRB5_PADATA_PKINIT_KX)
return PA_INFO;
- return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA;
+ /* PKINIT does not normally set the hw-authent ticket flag, but a
+ * certauth module can cause it to do so. */
+ return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA | PA_HARDWARE;
}
static krb5_preauthtype supported_server_pa_types[] = {
KRB5_PADATA_PK_AS_REQ,
- KRB5_PADATA_PK_AS_REQ_OLD,
- KRB5_PADATA_PK_AS_REP_OLD,
KRB5_PADATA_PKINIT_KX,
0
};
@@ -1323,6 +1135,10 @@ pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING,
0, &plgctx->opts->require_crl_checking);
+ pkinit_kdcdefault_boolean(context, plgctx->realmname,
+ KRB5_CONF_PKINIT_REQUIRE_FRESHNESS,
+ 0, &plgctx->opts->require_freshness);
+
pkinit_kdcdefault_string(context, plgctx->realmname,
KRB5_CONF_PKINIT_EKU_CHECKING,
&eku_string);
@@ -1584,7 +1400,8 @@ certauth_dbmatch_initvt(krb5_context context, int maj_ver, int min_ver,
}
static krb5_error_code
-load_certauth_plugins(krb5_context context, certauth_handle **handle_out)
+load_certauth_plugins(krb5_context context, const char *const *realmnames,
+ certauth_handle **handle_out)
{
krb5_error_code ret;
krb5_plugin_initvt_fn *modules = NULL, *mod;
@@ -1624,20 +1441,21 @@ load_certauth_plugins(krb5_context context, certauth_handle **handle_out)
if (h == NULL)
goto cleanup;
- ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt);
+ ret = (*mod)(context, 1, 2, (krb5_plugin_vtable)&h->vt);
if (ret) {
TRACE_CERTAUTH_VTINIT_FAIL(context, ret);
free(h);
continue;
}
h->moddata = NULL;
- if (h->vt.init != NULL) {
+ if (h->vt.init_ex != NULL)
+ ret = h->vt.init_ex(context, realmnames, &h->moddata);
+ else if (h->vt.init != NULL)
ret = h->vt.init(context, &h->moddata);
- if (ret) {
- TRACE_CERTAUTH_INIT_FAIL(context, h->vt.name, ret);
- free(h);
- continue;
- }
+ if (ret) {
+ TRACE_CERTAUTH_INIT_FAIL(context, h->vt.name, ret);
+ free(h);
+ continue;
}
list[count++] = h;
list[count] = NULL;
@@ -1700,7 +1518,7 @@ pkinit_server_plugin_init(krb5_context context,
goto errout;
}
- retval = load_certauth_plugins(context, &certauth_modules);
+ retval = load_certauth_plugins(context, realmnames, &certauth_modules);
if (retval)
goto errout;
@@ -1766,7 +1584,6 @@ pkinit_init_kdc_req_context(krb5_context context, pkinit_kdc_req_context *ctx)
if (retval)
goto cleanup;
reqctx->rcv_auth_pack = NULL;
- reqctx->rcv_auth_pack9 = NULL;
pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
*ctx = reqctx;
@@ -1792,12 +1609,17 @@ pkinit_fini_kdc_req_context(krb5_context context, void *ctx)
pkinit_fini_req_crypto(reqctx->cryptoctx);
if (reqctx->rcv_auth_pack != NULL)
free_krb5_auth_pack(&reqctx->rcv_auth_pack);
- if (reqctx->rcv_auth_pack9 != NULL)
- free_krb5_auth_pack_draft9(context, &reqctx->rcv_auth_pack9);
free(reqctx);
}
+static void
+pkinit_free_modreq(krb5_context context, krb5_kdcpreauth_moddata moddata,
+ krb5_kdcpreauth_modreq modreq)
+{
+ pkinit_fini_kdc_req_context(context, modreq);
+}
+
krb5_error_code
kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable);
@@ -1819,5 +1641,6 @@ kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
vt->edata = pkinit_server_get_edata;
vt->verify = pkinit_server_verify_padata;
vt->return_padata = pkinit_server_return_padata;
+ vt->free_modreq = pkinit_free_modreq;
return 0;
}
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
index d4eb39d88b95..259e95c6c2c2 100644
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
@@ -41,14 +41,14 @@
TRACE(c, "PKINIT client found no acceptable EKU in KDC cert")
#define TRACE_PKINIT_CLIENT_EKU_SKIP(c) \
TRACE(c, "PKINIT client skipping EKU check due to configuration")
+#define TRACE_PKINIT_CLIENT_FRESHNESS_TOKEN(c) \
+ TRACE(c, "PKINIT client received freshness token from KDC")
#define TRACE_PKINIT_CLIENT_KDF_ALG(c, kdf, keyblock) \
TRACE(c, "PKINIT client used KDF {hexdata} to compute reply key " \
"{keyblock}", kdf, keyblock)
#define TRACE_PKINIT_CLIENT_KDF_OS2K(c, keyblock) \
TRACE(c, "PKINIT client used octetstring2key to compute reply key " \
"{keyblock}", keyblock)
-#define TRACE_PKINIT_CLIENT_NO_DRAFT9(c) \
- TRACE(c, "PKINIT client ignoring draft 9 offer from RFC 4556 KDC")
#define TRACE_PKINIT_CLIENT_NO_IDENTITY(c) \
TRACE(c, "PKINIT client has no configured identity; giving up")
#define TRACE_PKINIT_CLIENT_REP_CHECKSUM_FAIL(c, expected, received) \
@@ -72,9 +72,9 @@
#define TRACE_PKINIT_CLIENT_REQ_RSA(c) \
TRACE(c, "PKINIT client making RSA request")
#define TRACE_PKINIT_CLIENT_SAN_CONFIG_DNSNAME(c, host) \
- TRACE(c, "PKINIT client config accepts KDC dNSName SAN {string}", host)
+ TRACE(c, "PKINIT client config accepts KDC dNSName SAN {str}", host)
#define TRACE_PKINIT_CLIENT_SAN_MATCH_DNSNAME(c, host) \
- TRACE(c, "PKINIT client matched KDC hostname {string} against " \
+ TRACE(c, "PKINIT client matched KDC hostname {str} against " \
"dNSName SAN; EKU check still required", host)
#define TRACE_PKINIT_CLIENT_SAN_MATCH_NONE(c) \
TRACE(c, "PKINIT client found no acceptable SAN in KDC cert")
@@ -84,7 +84,7 @@
#define TRACE_PKINIT_CLIENT_SAN_ERR(c) \
TRACE(c, "PKINIT client failed to decode SANs in KDC cert")
#define TRACE_PKINIT_CLIENT_SAN_KDCCERT_DNSNAME(c, host) \
- TRACE(c, "PKINIT client found dNSName SAN in KDC cert: {string}", host)
+ TRACE(c, "PKINIT client found dNSName SAN in KDC cert: {str}", host)
#define TRACE_PKINIT_CLIENT_SAN_KDCCERT_PRINC(c, princ) \
TRACE(c, "PKINIT client found id-pkinit-san in KDC cert: {princ}", princ)
#define TRACE_PKINIT_CLIENT_TRYAGAIN(c) \
@@ -93,6 +93,25 @@
#define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \
TRACE(c, "PKINIT OpenSSL error: {str}", msg)
+#define TRACE_PKINIT_PKCS11_GETFLIST_FAILED(c, errstr) \
+ TRACE(c, "PKINIT PKCS11 C_GetFunctionList failed: {str}", errstr)
+#define TRACE_PKINIT_PKCS11_GETSYM_FAILED(c, errstr) \
+ TRACE(c, "PKINIT unable to find PKCS11 plugin symbol " \
+ "C_GetFunctionList: {str}", errstr)
+#define TRACE_PKINIT_PKCS11_LOGIN_FAILED(c, errstr) \
+ TRACE(c, "PKINIT PKCS11 C_Login failed: {str}", errstr)
+#define TRACE_PKINIT_PKCS11_NO_MATCH_TOKEN(c) \
+ TRACE(c, "PKINIT PKCS#11 module has no matching tokens")
+#define TRACE_PKINIT_PKCS11_NO_TOKEN(c) \
+ TRACE(c, "PKINIT PKCS#11 module shows no slots with tokens")
+#define TRACE_PKINIT_PKCS11_OPEN(c, name) \
+ TRACE(c, "PKINIT opening PKCS#11 module \"{str}\"", name)
+#define TRACE_PKINIT_PKCS11_OPEN_FAILED(c, errstr) \
+ TRACE(c, "PKINIT PKCS#11 module open failed: {str}", errstr)
+#define TRACE_PKINIT_PKCS11_SLOT(c, slot, len, label) \
+ TRACE(c, "PKINIT PKCS#11 slotid {int} token {lenstr}", \
+ slot, len, label)
+
#define TRACE_PKINIT_SERVER_CERT_AUTH(c, modname) \
TRACE(c, "PKINIT server authorizing cert with module {str}", \
modname)
@@ -113,25 +132,38 @@
TRACE(c, "PKINIT server found no SAN in client cert")
#define TRACE_PKINIT_SERVER_PADATA_VERIFY(c) \
TRACE(c, "PKINIT server verifying KRB5_PADATA_PK_AS_REQ")
-#define TRACE_PKINIT_SERVER_PADATA_VERIFY_OLD(c) \
- TRACE(c, "PKINIT server verifying KRB5_PADATA_PK_AS_REQ_OLD")
#define TRACE_PKINIT_SERVER_PADATA_VERIFY_FAIL(c) \
TRACE(c, "PKINIT server failed to verify PA data")
#define TRACE_PKINIT_SERVER_RETURN_PADATA(c) \
TRACE(c, "PKINIT server returning PA data")
#define TRACE_PKINIT_SERVER_SAN_REJECT(c) \
TRACE(c, "PKINIT server found no acceptable SAN in client cert")
+#define TRACE_PKINIT_SERVER_UPN_PARSE_FAIL(c, upn, ret) \
+ TRACE(c, "PKINIT server could not parse UPN \"{str}\": {kerr}", \
+ upn, ret)
+
+#define TRACE_PKINIT_CERT_CHAIN_NAME(c, index, name) \
+ TRACE(c, "PKINIT chain cert #{int}: {str}", index, name)
+#define TRACE_PKINIT_CERT_NUM_MATCHING(c, total, nummatch) \
+ TRACE(c, "PKINIT client checked {int} certs, found {int} matches", \
+ total, nummatch)
+#define TRACE_PKINIT_CERT_RULE(c, rule) \
+ TRACE(c, "PKINIT client matching rule '{str}' against certificates", rule)
+#define TRACE_PKINIT_CERT_RULE_INVALID(c, rule) \
+ TRACE(c, "PKINIT client ignoring invalid rule '{str}'", rule)
#define TRACE_PKINIT_EKU(c) \
TRACE(c, "PKINIT found acceptable EKU and digitalSignature KU")
#define TRACE_PKINIT_EKU_NO_KU(c) \
TRACE(c, "PKINIT found acceptable EKU but no digitalSignature KU")
+#define TRACE_PKINIT_IDENTITY_OPTION(c, name) \
+ TRACE(c, "PKINIT loading identity {str}", name)
#define TRACE_PKINIT_LOADED_CERT(c, name) \
TRACE(c, "PKINIT loaded cert and key for {str}", name)
-#define TRACE_PKINIT_LOAD_FROM_FILE(c) \
- TRACE(c, "PKINIT loading CA certs and CRLs from FILE")
-#define TRACE_PKINIT_LOAD_FROM_DIR(c) \
- TRACE(c, "PKINIT loading CA certs and CRLs from DIR")
+#define TRACE_PKINIT_LOAD_FROM_FILE(c, name) \
+ TRACE(c, "PKINIT loading CA certs and CRLs from FILE {str}", name)
+#define TRACE_PKINIT_LOAD_FROM_DIR(c, name) \
+ TRACE(c, "PKINIT loading CA certs and CRLs from DIR {str}", name)
#define TRACE_PKINIT_NO_CA_ANCHOR(c, file) \
TRACE(c, "PKINIT no anchor CA in file {str}", file)
#define TRACE_PKINIT_NO_CA_INTERMEDIATE(c, file) \
@@ -161,6 +193,18 @@
TRACE(c, "PKINIT second PKCS12_parse with password failed")
#define TRACE_PKINIT_PKCS_PROMPT_FAIL(c) \
TRACE(c, "PKINIT failed to prompt for PKCS12 password")
+#define TRACE_PKINIT_REGEXP_MATCH(c, keyword, comp, value, idx) \
+ TRACE(c, "PKINIT matched {str} rule '{str}' with " \
+ "value '{str}' in cert #{int}", keyword, comp, value, (idx) + 1)
+#define TRACE_PKINIT_REGEXP_NOMATCH(c, keyword, comp, value, idx) \
+ TRACE(c, "PKINIT didn't match {str} rule '{str}' with " \
+ "value '{str}' in cert #{int}", keyword, comp, value, (idx) + 1)
+#define TRACE_PKINIT_SAN_CERT_COUNT(c, count, princ, upns, dns, cert) \
+ TRACE(c, "PKINIT client found {int} SANs ({int} princs, {int} " \
+ "UPNs, {int} DNS names) in certificate {str}", count, princ, \
+ upns, dns, cert)
+#define TRACE_PKINIT_SAN_CERT_NONE(c, cert) \
+ TRACE(c, "PKINIT client found no SANs in certificate {str}", cert)
#define TRACE_CERTAUTH_VTINIT_FAIL(c, ret) \
TRACE(c, "certauth module failed to init vtable: {kerr}", ret)