diff options
| author | Sam Hartman <hartmans@mit.edu> | 2009-12-28 17:15:30 +0000 |
|---|---|---|
| committer | Sam Hartman <hartmans@mit.edu> | 2009-12-28 17:15:30 +0000 |
| commit | ec49e6e673ab229462ef18aa2986167eaa643643 (patch) | |
| tree | 625dba55e939a0073cf69f7b79c8c0010df991eb /src/plugins | |
| parent | c5479d0c5b29430a49cf3683513c1223a173ac4e (diff) | |
| download | krb5-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.h | 8 | ||||
| -rw-r--r-- | src/plugins/preauth/pkinit/pkinit_clnt.c | 37 | ||||
| -rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto.h | 15 | ||||
| -rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 191 | ||||
| -rw-r--r-- | src/plugins/preauth/pkinit/pkinit_identity.c | 108 | ||||
| -rw-r--r-- | src/plugins/preauth/pkinit/pkinit_lib.c | 4 | ||||
| -rw-r--r-- | src/plugins/preauth/pkinit/pkinit_srv.c | 189 |
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(); |
