summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2009-12-28 17:15:30 +0000
committerSam Hartman <hartmans@mit.edu>2009-12-28 17:15:30 +0000
commitec49e6e673ab229462ef18aa2986167eaa643643 (patch)
tree625dba55e939a0073cf69f7b79c8c0010df991eb /src/plugins
parentc5479d0c5b29430a49cf3683513c1223a173ac4e (diff)
downloadkrb5-ec49e6e673ab229462ef18aa2986167eaa643643.tar.gz
krb5-ec49e6e673ab229462ef18aa2986167eaa643643.tar.xz
krb5-ec49e6e673ab229462ef18aa2986167eaa643643.zip
Anonymous support for Kerberos
This ticket implements Project/Anonymous pkinit from k5wiki. Provides support for completely anonymous principals and untested client support for realm-exposed anonymous authentication. * Introduce kinit -n * Introduce kadmin -n * krb5_get_init_creds_opt_set_out_ccache aliases the supplied ccache * No longer generate ad-initial-verified-cas in pkinit * Fix pkinit interactions with non-TGT authentication Merge remote branch 'anonymous' into trunk Conflicts: src/lib/krb5/krb/gic_opt.c ticket: 6607 Tags: enhancement git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23527 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/preauth/fast_factor.h8
-rw-r--r--src/plugins/preauth/pkinit/pkinit_clnt.c37
-rw-r--r--src/plugins/preauth/pkinit/pkinit_crypto.h15
-rw-r--r--src/plugins/preauth/pkinit/pkinit_crypto_openssl.c191
-rw-r--r--src/plugins/preauth/pkinit/pkinit_identity.c108
-rw-r--r--src/plugins/preauth/pkinit/pkinit_lib.c4
-rw-r--r--src/plugins/preauth/pkinit/pkinit_srv.c189
7 files changed, 358 insertions, 194 deletions
diff --git a/src/plugins/preauth/fast_factor.h b/src/plugins/preauth/fast_factor.h
index 0789c1ad18..52f4fa2e82 100644
--- a/src/plugins/preauth/fast_factor.h
+++ b/src/plugins/preauth/fast_factor.h
@@ -4,7 +4,7 @@
* Returns success with a null armor_key if FAST is available but not in use.
* Returns failure if the client library does not support FAST.
*/
-static krb5_error_code
+static inline krb5_error_code
fast_get_armor_key(krb5_context context, preauth_get_client_data_proc get_data,
struct _krb5_preauth_client_rock *rock,
krb5_keyblock **armor_key)
@@ -21,7 +21,7 @@ fast_get_armor_key(krb5_context context, preauth_get_client_data_proc get_data,
return retval;
}
-static krb5_error_code
+static inline krb5_error_code
fast_kdc_get_armor_key(krb5_context context,
preauth_get_entry_data_proc get_entry,
krb5_kdc_req *request,
@@ -43,7 +43,7 @@ fast_kdc_get_armor_key(krb5_context context,
-static krb5_error_code
+static inline krb5_error_code
fast_kdc_replace_reply_key(krb5_context context,
preauth_get_entry_data_proc get_data,
krb5_kdc_req *request)
@@ -51,7 +51,7 @@ fast_kdc_replace_reply_key(krb5_context context,
return 0;
}
-static krb5_error_code
+static inline krb5_error_code
fast_set_kdc_verified(krb5_context context,
preauth_get_client_data_proc get_data,
struct _krb5_preauth_client_rock *rock)
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index ba1e4344fe..8f17f7e4af 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -61,7 +61,8 @@ static krb5_error_code
pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
pkinit_req_context reqctx, krb5_timestamp ctsec,
krb5_int32 cusec, krb5_ui_4 nonce,
- const krb5_checksum *cksum, krb5_principal server,
+ const krb5_checksum *cksum,
+ krb5_principal client, krb5_principal server,
krb5_data **as_req);
static krb5_error_code
@@ -139,7 +140,7 @@ pa_pkinit_gen_req(krb5_context context,
nonce = request->nonce;
retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec,
- nonce, &cksum, request->server, &out_data);
+ nonce, &cksum, request->client, request->server, &out_data);
if (retval || !out_data->length) {
pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n",
(int) retval);
@@ -218,6 +219,7 @@ pkinit_as_req_create(krb5_context context,
krb5_int32 cusec,
krb5_ui_4 nonce,
const krb5_checksum * cksum,
+ krb5_principal client,
krb5_principal server,
krb5_data ** as_req)
{
@@ -344,10 +346,17 @@ pkinit_as_req_create(krb5_context context,
retval = ENOMEM;
goto cleanup;
}
- 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,
- &req->signedAuthPack.data, &req->signedAuthPack.length);
+ /*For the new protocol, we support anonymous*/
+ if (krb5_principal_compare_any_realm(context, client,
+ krb5_anonymous_principal()))
+ retval = cms_contentinfo_create(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT,
+ (unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
+ &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,
+ &req->signedAuthPack.data, &req->signedAuthPack.length);
#ifdef DEBUG_ASN1
print_buffer_bin((unsigned char *)req->signedAuthPack.data,
req->signedAuthPack.length,
@@ -640,6 +649,7 @@ pkinit_as_rep_parse(krb5_context context,
krb5_data *encoded_request)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_principal kdc_princ = NULL;
krb5_pa_pk_as_rep *kdc_reply = NULL;
krb5_kdc_dh_key_info *kdc_dh = NULL;
krb5_reply_key_pack *key_pack = NULL;
@@ -677,7 +687,7 @@ pkinit_as_rep_parse(krb5_context context,
reqctx->opts->require_crl_checking,
kdc_reply->u.dh_Info.dhSignedData.data,
kdc_reply->u.dh_Info.dhSignedData.length,
- &dh_data.data, &dh_data.length, NULL, NULL)) != 0) {
+ &dh_data.data, &dh_data.length, NULL, NULL, NULL)) != 0) {
pkiDebug("failed to verify pkcs7 signed data\n");
goto cleanup;
}
@@ -700,8 +710,16 @@ pkinit_as_rep_parse(krb5_context context,
retval = -1;
goto cleanup;
}
-
- retval = verify_kdc_san(context, plgctx, reqctx, request->server,
+ retval = krb5_build_principal_ext(context, &kdc_princ,
+ request->server->realm.length,
+ request->server->realm.data,
+ strlen(KRB5_TGS_NAME), KRB5_TGS_NAME,
+ request->server->realm.length,
+ request->server->realm.data,
+ 0);
+ if (retval)
+ goto cleanup;
+ retval = verify_kdc_san(context, plgctx, reqctx, kdc_princ,
&valid_san, &need_eku_checking);
if (retval)
goto cleanup;
@@ -850,6 +868,7 @@ pkinit_as_rep_parse(krb5_context context,
cleanup:
free(dh_data.data);
+ krb5_free_principal(context, kdc_princ);
free(client_key);
free_krb5_kdc_dh_key_info(&kdc_dh);
free_krb5_pa_pk_as_rep(&kdc_reply);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 83d2f1e19d..dedd8f9456 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -113,6 +113,16 @@ void pkinit_fini_req_crypto(pkinit_req_crypto_context);
krb5_error_code pkinit_init_identity_crypto(pkinit_identity_crypto_context *);
void pkinit_fini_identity_crypto(pkinit_identity_crypto_context);
+/**Create a pkinit ContentInfo*/
+krb5_error_code cms_contentinfo_create
+ (krb5_context context, /* IN */
+ pkinit_plg_crypto_context plg_cryptoctx, /* IN */
+ pkinit_req_crypto_context req_cryptoctx, /* IN */
+ pkinit_identity_crypto_context id_cryptoctx, /* IN */
+ int cms_msg_type,
+ unsigned char *in_data, unsigned int in_length,
+ unsigned char **out_data, unsigned int *out_data_len);
+
/*
* this function creates a CMS message where eContentType is SignedData
@@ -171,8 +181,9 @@ krb5_error_code cms_signeddata_verify
receives required authorization data that
contains the verified certificate chain
(only used by the KDC) */
- unsigned int *authz_data_len); /* OUT
- receives length of authz_data */
+ unsigned int *authz_data_len, /* OUT
+ receives length of authz_data */
+ int *is_signed /*out: is message signed*/);
/*
* this function creates a CMS message where eContentType is EnvelopedData
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 443b0f98cc..887ec06270 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -691,6 +691,102 @@ pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
return 0;
}
+/*helper function for creating pkinit ContentInfo*/
+static krb5_error_code create_contentinfo
+(krb5_context context, pkinit_plg_crypto_context plg_crypto_context,
+ ASN1_OBJECT *oid,
+ unsigned char *data, size_t data_len,
+ PKCS7 **out_p7)
+{
+ krb5_error_code retval = EINVAL;
+ PKCS7 *inner_p7;
+ ASN1_TYPE *pkinit_data = NULL;
+ *out_p7 = NULL;
+ if ((inner_p7 = PKCS7_new()) == NULL)
+ goto cleanup;
+ if ((pkinit_data = ASN1_TYPE_new()) == NULL)
+ goto cleanup;
+ pkinit_data->type = V_ASN1_OCTET_STRING;
+ if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
+ goto cleanup;
+ if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, (unsigned char *) data,
+ data_len)) {
+ unsigned long err = ERR_peek_error();
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "%s\n",
+ ERR_error_string(err, NULL));
+ pkiDebug("failed to add pkcs7 data\n");
+ goto cleanup;
+ }
+ if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
+ goto cleanup;
+ retval = 0;
+ *out_p7 = inner_p7;
+ inner_p7 = NULL;
+ pkinit_data = NULL;
+cleanup:
+ if (inner_p7)
+ PKCS7_free(inner_p7);
+ if (pkinit_data)
+ ASN1_TYPE_free(pkinit_data);
+ return retval;
+}
+
+krb5_error_code cms_contentinfo_create
+(krb5_context context, /* IN */
+ pkinit_plg_crypto_context plg_cryptoctx, /* IN */
+ pkinit_req_crypto_context req_cryptoctx, /* IN */
+ pkinit_identity_crypto_context id_cryptoctx, /* IN */
+ int cms_msg_type,
+ unsigned char *data, unsigned int data_len,
+ unsigned char **out_data, unsigned int *out_data_len)
+{
+ krb5_error_code retval = ENOMEM;
+ ASN1_OBJECT *oid = NULL;
+ PKCS7 *p7 = NULL;
+ unsigned char *p;
+ /* pick the correct oid for the eContentInfo */
+ oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
+ if (oid == NULL)
+ goto cleanup;
+ retval = create_contentinfo(context, plg_cryptoctx, oid,
+ data, data_len, &p7);
+ if (retval != 0)
+ goto cleanup;
+ *out_data_len = i2d_PKCS7(p7, NULL);
+ if (!(*out_data_len)) {
+ unsigned long err = ERR_peek_error();
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "%s\n",
+ ERR_error_string(err, NULL));
+ pkiDebug("failed to der encode pkcs7\n");
+ goto cleanup;
+ }
+ retval = ENOMEM;
+ if ((p = *out_data = malloc(*out_data_len)) == NULL)
+ goto cleanup;
+
+ /* DER encode PKCS7 data */
+ retval = i2d_PKCS7(p7, &p);
+ if (!retval) {
+ unsigned long err = ERR_peek_error();
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "%s\n",
+ ERR_error_string(err, NULL));
+ pkiDebug("failed to der encode pkcs7\n");
+ goto cleanup;
+ }
+ retval = 0;
+cleanup:
+ if (p7)
+ PKCS7_free(p7);
+ if (oid)
+ ASN1_OBJECT_free(oid);
+ return retval;
+}
+
+
+
krb5_error_code
cms_signeddata_create(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
@@ -708,7 +804,6 @@ cms_signeddata_create(krb5_context context,
PKCS7_SIGNED *p7s = NULL;
PKCS7_SIGNER_INFO *p7si = NULL;
unsigned char *p;
- ASN1_TYPE *pkinit_data = NULL;
STACK_OF(X509) * cert_stack = NULL;
ASN1_OCTET_STRING *digest_attr = NULL;
EVP_MD_CTX ctx, ctx2;
@@ -726,7 +821,11 @@ cms_signeddata_create(krb5_context context,
X509 *cert = NULL;
ASN1_OBJECT *oid = NULL;
- /* start creating PKCS7 data */
+ if (id_cryptoctx->my_certs == NULL) {
+ krb5_set_error_message(context, EINVAL, "cms_signdata_create called with no certificates");
+ return EINVAL;
+ }
+/* start creating PKCS7 data */
if ((p7 = PKCS7_new()) == NULL)
goto cleanup;
p7->type = OBJ_nid2obj(NID_pkcs7_signed);
@@ -751,7 +850,7 @@ cms_signeddata_create(krb5_context context,
X509_STORE_CTX certctx;
STACK_OF(X509) *certstack = NULL;
char buf[DN_BUF_LEN];
- int i = 0, size = 0;
+ unsigned int i = 0, size = 0;
if ((certstore = X509_STORE_new()) == NULL)
goto cleanup;
@@ -939,26 +1038,8 @@ cms_signeddata_create(krb5_context context,
goto cleanup2;
/* start on adding data to the pkcs7 signed */
- if ((inner_p7 = PKCS7_new()) == NULL)
- goto cleanup2;
- if ((pkinit_data = ASN1_TYPE_new()) == NULL)
- goto cleanup2;
- pkinit_data->type = V_ASN1_OCTET_STRING;
- if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
- goto cleanup2;
- if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
- (int)data_len)) {
- unsigned long err = ERR_peek_error();
- retval = KRB5KDC_ERR_PREAUTH_FAILED;
- krb5_set_error_message(context, retval, "%s\n",
- ERR_error_string(err, NULL));
- pkiDebug("failed to add pkcs7 data\n");
- goto cleanup2;
- }
-
- if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
- goto cleanup2;
-
+ retval = create_contentinfo(context, plg_cryptoctx, oid,
+ data, data_len, &inner_p7);
if (p7s->contents != NULL)
PKCS7_free(p7s->contents);
p7s->contents = inner_p7;
@@ -972,6 +1053,7 @@ cms_signeddata_create(krb5_context context,
pkiDebug("failed to der encode pkcs7\n");
goto cleanup2;
}
+ retval = ENOMEM;
if ((p = *signed_data = malloc(*signed_data_len)) == NULL)
goto cleanup2;
@@ -1038,12 +1120,14 @@ cms_signeddata_verify(krb5_context context,
unsigned char **data,
unsigned int *data_len,
unsigned char **authz_data,
- unsigned int *authz_data_len)
+ unsigned int *authz_data_len,
+ int *is_signed)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
PKCS7 *p7 = NULL;
BIO *out = NULL;
- int flags = PKCS7_NOVERIFY, i = 0;
+ int flags = PKCS7_NOVERIFY;
+ unsigned int i = 0;
unsigned int vflags = 0, size = 0;
const unsigned char *p = signed_data;
STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
@@ -1063,7 +1147,8 @@ cms_signeddata_verify(krb5_context context,
print_buffer_bin(signed_data, signed_data_len,
"/tmp/client_received_pkcs7_signeddata");
#endif
-
+ if (is_signed)
+ *is_signed = 1;
/* Do this early enough to create the shadow OID for pkcs7-data if needed */
oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
if (oid == NULL)
@@ -1079,13 +1164,33 @@ cms_signeddata_verify(krb5_context context,
goto cleanup;
}
- /* verify that the received message is PKCS7 SignedData message */
- if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
- pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
- OBJ_obj2nid(p7->type));
- krb5_set_error_message(context, retval, "wrong oid\n");
- goto cleanup;
- }
+/*Handle the case in pkinit anonymous where we get unsigned data.*/
+ if (is_signed && !OBJ_cmp( p7->type, oid)) {
+ unsigned char *d;
+ *is_signed = 0;
+ if (p7->d.other->type != V_ASN1_OCTET_STRING) {
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED, "Invalid pkinit packet: octet string expected");
+ goto cleanup;
+ }
+ *data_len = ASN1_STRING_length(p7->d.other->value.octet_string);
+ d = malloc(*data_len);
+ if (d == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ memcpy(d, ASN1_STRING_data(p7->d.other->value.octet_string),
+ *data_len);
+ *data = d;
+ goto out;
+ } else /* verify that the received message is PKCS7 SignedData message */
+ if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
+
+ pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
+ OBJ_obj2nid(p7->type));
+ krb5_set_error_message(context, retval, "wrong oid\n");
+ goto cleanup;
+ }
/* setup to verify X509 certificate used to sign PKCS7 message */
if (!(store = X509_STORE_new()))
@@ -1285,13 +1390,15 @@ cms_signeddata_verify(krb5_context context,
/* transfer the data from PKCS7 message into return buffer */
for (size = 0;;) {
+ int remain;
+ retval = ENOMEM;
if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
goto cleanup;
- i = BIO_read(out, &((*data)[size]), 1024 * 10);
- if (i <= 0)
+ remain = BIO_read(out, &((*data)[size]), 1024 * 10);
+ if (remain <= 0)
break;
else
- size += i;
+ size += remain;
}
*data_len = size;
@@ -1617,7 +1724,7 @@ cms_envelopeddata_verify(krb5_context context,
id_cryptoctx, msg_type,
require_crl_checking,
vfy_buf, vfy_buf_len,
- data, data_len, NULL, NULL);
+ data, data_len, NULL, NULL, NULL);
if (!retval)
pkiDebug("PKCS7 Verification Success\n");
@@ -1655,7 +1762,7 @@ crypto_retrieve_X509_sans(krb5_context context,
krb5_principal *princs = NULL;
krb5_principal *upns = NULL;
unsigned char **dnss = NULL;
- int i, num_found = 0;
+ unsigned int i, num_found = 0;
if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
@@ -3220,7 +3327,7 @@ static krb5_error_code
pkinit_open_session(krb5_context context,
pkinit_identity_crypto_context cctx)
{
- int i, r;
+ CK_ULONG i, r;
unsigned char *cp;
CK_ULONG count = 0;
CK_SLOT_ID_PTR slotlist;
@@ -3414,7 +3521,7 @@ pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
ulEncryptedDataLen, pData, pulDataLen);
if (rv == CKR_OK) {
- pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
+ pkiDebug("pData %x *pulDataLen %d\n", (unsigned int) pData, (int) *pulDataLen);
}
return rv;
}
@@ -4451,7 +4558,7 @@ X509_NAME_oneline_ex(X509_NAME * a,
out = BIO_new(BIO_s_mem ());
if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
- if (buf != NULL && *size > (int) BIO_number_written(out)) {
+ if (buf != NULL && (int)(*size) > BIO_number_written(out)) {
memset(buf, 0, *size);
BIO_read(out, buf, (int) BIO_number_written(out));
}
@@ -5459,7 +5566,7 @@ pkcs7_dataDecode(krb5_context context,
if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
goto cleanup;
- if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
+ if ((unsigned) jj != 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.
diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
index aef0393610..aecea2c787 100644
--- a/src/plugins/preauth/pkinit/pkinit_identity.c
+++ b/src/plugins/preauth/pkinit/pkinit_identity.c
@@ -505,65 +505,67 @@ pkinit_identity_initialize(krb5_context context,
int i;
pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
- if (idopts == NULL || id_cryptoctx == NULL)
- goto errout;
-
- /*
- * If identity was specified, use that. (For the kdc, this
- * is specified as pkinit_identity in the kdc.conf. For users,
- * this is specified on the command line via X509_user_identity.)
- * If a user did not specify identity on the command line,
- * then we will try alternatives which may have been specified
- * in the config file.
- */
- if (idopts->identity != NULL) {
- retval = process_option_identity(context, plg_cryptoctx, req_cryptoctx,
- idopts, id_cryptoctx,
- 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,
- idopts->identity_alt[i]);
- } else {
- 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);
- if (retval)
- goto errout;
+ if (!(princ && krb5_principal_compare_any_realm (context, princ, krb5_anonymous_principal()))) {
+ if (idopts == NULL || id_cryptoctx == NULL)
+ goto errout;
- if (do_matching) {
- retval = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx, princ);
- if (retval) {
- pkiDebug("%s: No matching certificate found\n", __FUNCTION__);
- crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx);
+ /*
+ * If identity was specified, use that. (For the kdc, this
+ * is specified as pkinit_identity in the kdc.conf. For users,
+ * this is specified on the command line via X509_user_identity.)
+ * If a user did not specify identity on the command line,
+ * then we will try alternatives which may have been specified
+ * in the config file.
+ */
+ if (idopts->identity != NULL) {
+ retval = process_option_identity(context, plg_cryptoctx, req_cryptoctx,
+ idopts, id_cryptoctx,
+ 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,
+ idopts->identity_alt[i]);
+ } else {
+ pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
goto errout;
}
- } else {
- /* Tell crypto code to use the "default" */
- retval = crypto_cert_select_default(context, plg_cryptoctx,
- req_cryptoctx, id_cryptoctx);
- if (retval) {
- pkiDebug("%s: Failed while selecting default certificate\n",
- __FUNCTION__);
- crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx);
+ if (retval)
+ goto errout;
+
+ retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
+ idopts, id_cryptoctx, princ);
+ if (retval)
goto errout;
+
+ if (do_matching) {
+ retval = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx, princ);
+ if (retval) {
+ pkiDebug("%s: No matching certificate found\n", __FUNCTION__);
+ crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx);
+ goto errout;
+ }
+ } else {
+ /* Tell crypto code to use the "default" */
+ retval = crypto_cert_select_default(context, plg_cryptoctx,
+ req_cryptoctx, id_cryptoctx);
+ if (retval) {
+ pkiDebug("%s: Failed while selecting default certificate\n",
+ __FUNCTION__);
+ crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx);
+ goto errout;
+ }
}
- }
- retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
- id_cryptoctx);
- if (retval)
- goto errout;
+ retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
+ id_cryptoctx);
+ if (retval)
+ goto errout;
+ } /*not anonymous principal*/
for (i = 0; idopts->anchors != NULL && idopts->anchors[i] != NULL; i++) {
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
index e665b6cb7a..a6d7762fbb 100644
--- a/src/plugins/preauth/pkinit/pkinit_lib.c
+++ b/src/plugins/preauth/pkinit/pkinit_lib.c
@@ -424,7 +424,7 @@ pkinit_copy_krb5_octet_data(krb5_octet_data *dst, const krb5_octet_data *src)
void
print_buffer(unsigned char *buf, unsigned int len)
{
- int i = 0;
+ unsigned i = 0;
if (len <= 0)
return;
@@ -437,7 +437,7 @@ void
print_buffer_bin(unsigned char *buf, unsigned int len, char *filename)
{
FILE *f = NULL;
- int i = 0;
+ unsigned int i = 0;
if (len <= 0 || filename == NULL)
return;
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index adfcb95930..34700ad18b 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -300,7 +300,6 @@ pkinit_server_verify_padata(krb5_context context,
{
krb5_error_code retval = 0;
krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
- krb5_data *encoded_pkinit_authz_data = NULL;
krb5_pa_pk_as_req *reqp = NULL;
krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
krb5_auth_pack *auth_pack = NULL;
@@ -311,9 +310,9 @@ pkinit_server_verify_padata(krb5_context context,
krb5_checksum cksum = {0, 0, 0, NULL};
krb5_data *der_req = NULL;
int valid_eku = 0, valid_san = 0;
- krb5_authdata **my_authz_data = NULL, *pkinit_authz_data = NULL;
krb5_kdc_req *tmp_as_req = NULL;
krb5_data k5data;
+ int is_signed = 1;
krb5_keyblock *armor_key;
pkiDebug("pkinit_verify_padata: entered!\n");
@@ -367,7 +366,7 @@ pkinit_server_verify_padata(krb5_context context,
plgctx->opts->require_crl_checking,
reqp->signedAuthPack.data, reqp->signedAuthPack.length,
&authp_data.data, &authp_data.length, &krb5_authz.data,
- &krb5_authz.length);
+ &krb5_authz.length, &is_signed);
break;
case KRB5_PADATA_PK_AS_REP_OLD:
case KRB5_PADATA_PK_AS_REQ_OLD:
@@ -389,7 +388,7 @@ pkinit_server_verify_padata(krb5_context context,
plgctx->opts->require_crl_checking,
reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
&authp_data.data, &authp_data.length, &krb5_authz.data,
- &krb5_authz.length);
+ &krb5_authz.length, NULL);
break;
default:
pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
@@ -400,28 +399,35 @@ pkinit_server_verify_padata(krb5_context context,
pkiDebug("pkcs7_signeddata_verify failed\n");
goto cleanup;
}
+ if (is_signed) {
- retval = verify_client_san(context, plgctx, reqctx, request->client,
- &valid_san);
- if (retval)
- goto cleanup;
- if (!valid_san) {
- pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
- __FUNCTION__);
- retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
- goto cleanup;
- }
- retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
- if (retval)
- goto cleanup;
+ retval = verify_client_san(context, plgctx, reqctx, request->client,
+ &valid_san);
+ if (retval)
+ goto cleanup;
+ if (!valid_san) {
+ pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
+ __FUNCTION__);
+ retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
+ goto cleanup;
+ }
+ retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
+ if (retval)
+ goto cleanup;
- if (!valid_eku) {
- pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
- __FUNCTION__);
- retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
- goto cleanup;
+ if (!valid_eku) {
+ pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
+ __FUNCTION__);
+ retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
+ goto cleanup;
+ }
+ } else { /*!is_signed*/
+ if (!krb5_principal_compare( context, request->client, krb5_anonymous_principal())) {
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ krb5_set_error_message(context, retval, "Pkinit request not signed, but client not anonymous.");
+ goto cleanup;
+ }
}
-
#ifdef DEBUG_ASN1
print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
#endif
@@ -446,6 +452,11 @@ pkinit_server_verify_padata(krb5_context context,
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;
}
/*
* The KDC may have modified the request after decoding it.
@@ -536,64 +547,11 @@ pkinit_server_verify_padata(krb5_context context,
/* return authorization data to be included in the ticket */
switch ((int)data->pa_type) {
- case KRB5_PADATA_PK_AS_REQ:
- my_authz_data = malloc(2 * sizeof(*my_authz_data));
- if (my_authz_data == NULL) {
- retval = ENOMEM;
- pkiDebug("Couldn't allocate krb5_authdata ptr array\n");
- goto cleanup;
- }
- my_authz_data[1] = NULL;
- my_authz_data[0] = malloc(sizeof(krb5_authdata));
- if (my_authz_data[0] == NULL) {
- retval = ENOMEM;
- pkiDebug("Couldn't allocate krb5_authdata\n");
- free(my_authz_data);
- goto cleanup;
- }
- /* AD-INITIAL-VERIFIED-CAS must be wrapped in AD-IF-RELEVANT */
- my_authz_data[0]->magic = KV5M_AUTHDATA;
- my_authz_data[0]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
-
- /* create an internal AD-INITIAL-VERIFIED-CAS data */
- pkinit_authz_data = malloc(sizeof(krb5_authdata));
- if (pkinit_authz_data == NULL) {
- retval = ENOMEM;
- pkiDebug("Couldn't allocate krb5_authdata\n");
- free(my_authz_data[0]);
- free(my_authz_data);
- goto cleanup;
- }
- pkinit_authz_data->ad_type = KRB5_AUTHDATA_INITIAL_VERIFIED_CAS;
- /* content of this ad-type contains the certification
- path with which the client certificate was validated
- */
- pkinit_authz_data->contents = krb5_authz.data;
- pkinit_authz_data->length = krb5_authz.length;
- retval = k5int_encode_krb5_authdata_elt(pkinit_authz_data,
- &encoded_pkinit_authz_data);
-#ifdef DEBUG_ASN1
- print_buffer_bin((unsigned char *)encoded_pkinit_authz_data->data,
- encoded_pkinit_authz_data->length,
- "/tmp/kdc_pkinit_authz_data");
-#endif
- free(pkinit_authz_data);
- if (retval) {
- pkiDebug("k5int_encode_krb5_authdata_elt failed\n");
- free(my_authz_data[0]);
- free(my_authz_data);
- goto cleanup;
- }
-
- my_authz_data[0]->contents =
- (krb5_octet *) encoded_pkinit_authz_data->data;
- my_authz_data[0]->length = encoded_pkinit_authz_data->length;
- *authz_data = my_authz_data;
- pkiDebug("Returning %d bytes of authorization data\n",
- krb5_authz.length);
- encoded_pkinit_authz_data->data = NULL; /* Don't free during cleanup*/
- free(encoded_pkinit_authz_data);
- break;
+/*
+ * This code used to generate ad-initial-verified-cas authorization data.
+ * However that has been removed until the ad-kdc-issued discussion can happen
+ * in the working group. Dec 2009
+ */
default:
*authz_data = NULL;
}
@@ -634,6 +592,67 @@ cleanup:
return retval;
}
+static krb5_error_code
+return_pkinit_kx( krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *reply,
+ krb5_keyblock *encrypting_key,
+ krb5_pa_data **out_padata)
+{
+ krb5_error_code ret = 0;
+ krb5_keyblock *session = reply->ticket->enc_part2->session;
+ krb5_keyblock *new_session = NULL;
+ krb5_pa_data *pa = NULL;
+ krb5_enc_data enc;
+ krb5_data *scratch = NULL;
+ *out_padata = NULL;
+ enc.ciphertext.data = NULL;
+ if (!krb5_principal_compare(context, request->client,
+ krb5_anonymous_principal()))
+ return 0;
+ /*
+ *The KDC contribution key needs to be a fresh key of an
+ *enctype supported by the client and server. The existing
+ *session key meets these requirements so we use itt.
+ */
+ ret = krb5_c_fx_cf2_simple(context, session, "PKINIT",
+ encrypting_key, "KEYEXCHANGE",
+ &new_session);
+ if (ret)
+ goto cleanup;
+ ret = encode_krb5_encryption_key( session, &scratch);
+ if (ret)
+ goto cleanup;
+ ret = krb5_encrypt_helper( context, encrypting_key, KRB5_KEYUSAGE_PA_PKINIT_KX,
+ scratch, &enc);
+ if (ret)
+ goto cleanup;
+ memset(scratch->data, 0, scratch->length);
+ krb5_free_data(context, scratch);
+ scratch = NULL;
+ ret = encode_krb5_enc_data(&enc, &scratch);
+ if (ret)
+ goto cleanup;
+ pa = malloc(sizeof(krb5_pa_data));
+ if (pa == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ if (ret)
+ goto cleanup;
+ pa->pa_type = KRB5_PADATA_PKINIT_KX;
+ pa->length = scratch->length;
+ pa->contents = (krb5_octet *) scratch->data;
+ *out_padata = pa;
+ scratch->data = NULL;
+ memset(session->contents, 0, session->length);
+ krb5_free_keyblock_contents(context, session);
+ *session = *new_session;
+ new_session->contents = NULL;
+cleanup:
+ krb5_free_data_contents(context, &enc.ciphertext);
+ krb5_free_keyblock(context, new_session);
+ krb5_free_data(context, scratch);
+ return ret;
+}
static krb5_error_code
pkinit_server_return_padata(krb5_context context,
@@ -680,6 +699,9 @@ pkinit_server_return_padata(krb5_context context,
int fixed_keypack = 0;
*send_pa = NULL;
+ if (padata->pa_type == KRB5_PADATA_PKINIT_KX)
+ return return_pkinit_kx(context, request, reply,
+ encrypting_key, send_pa);
if (padata == NULL || padata->length <= 0 || padata->contents == NULL)
return 0;
@@ -1037,6 +1059,8 @@ cleanup:
static int
pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
{
+ if (patype == KRB5_PADATA_PKINIT_KX)
+ return PA_PSEUDO;
return PA_SUFFICIENT | PA_REPLACES_KEY;
}
@@ -1044,6 +1068,7 @@ 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
};
@@ -1238,7 +1263,7 @@ pkinit_server_plugin_init(krb5_context context, void **blob,
{
krb5_error_code retval = ENOMEM;
pkinit_kdc_context plgctx, *realm_contexts = NULL;
- int i, j;
+ size_t i, j;
size_t numrealms;
retval = pkinit_accessor_init();