1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3
* COPYRIGHT (C) 2006,2007
4
* THE REGENTS OF THE UNIVERSITY OF MICHIGAN
7
* Permission is granted to use, copy, create derivative works
8
* and redistribute this software and such derivative works
9
* for any purpose, so long as the name of The University of
10
* Michigan is not used in any advertising or publicity
11
* pertaining to the use of distribution of this software
12
* without specific, written prior authorization. If the
13
* above copyright notice or any other identification of the
14
* University of Michigan is included in any copy of any
15
* portion of this software, then the disclaimer below must
18
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
19
* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
20
* PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
21
* MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
22
* WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
23
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
24
* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
25
* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
26
* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
27
* OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
28
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
40
static krb5_error_code
41
pkinit_init_kdc_req_context(krb5_context, pkinit_kdc_req_context *blob);
44
pkinit_fini_kdc_req_context(krb5_context context, void *blob);
47
pkinit_server_plugin_fini_realm(krb5_context context,
48
pkinit_kdc_context plgctx);
51
pkinit_server_plugin_fini(krb5_context context,
52
krb5_kdcpreauth_moddata moddata);
54
static pkinit_kdc_context
55
pkinit_find_realm_context(krb5_context context,
56
krb5_kdcpreauth_moddata moddata,
57
krb5_principal princ);
59
static krb5_error_code
60
pkinit_create_edata(krb5_context context,
61
pkinit_plg_crypto_context plg_cryptoctx,
62
pkinit_req_crypto_context req_cryptoctx,
63
pkinit_identity_crypto_context id_cryptoctx,
64
pkinit_plg_opts *opts,
65
krb5_error_code err_code,
66
krb5_pa_data ***e_data_out)
68
krb5_error_code retval = KRB5KRB_ERR_GENERIC;
70
pkiDebug("pkinit_create_edata: creating edata for error %d (%s)\n",
71
err_code, error_message(err_code));
73
case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
74
retval = pkinit_create_td_trusted_certifiers(context,
75
plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data_out);
77
case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
78
retval = pkinit_create_td_dh_parameters(context, plg_cryptoctx,
79
req_cryptoctx, id_cryptoctx, opts, e_data_out);
81
case KRB5KDC_ERR_INVALID_CERTIFICATE:
82
case KRB5KDC_ERR_REVOKED_CERTIFICATE:
83
retval = pkinit_create_td_invalid_certificate(context,
84
plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data_out);
87
pkiDebug("no edata needed for error %d (%s)\n",
88
err_code, error_message(err_code));
99
pkinit_server_get_edata(krb5_context context,
100
krb5_kdc_req *request,
101
krb5_kdcpreauth_callbacks cb,
102
krb5_kdcpreauth_rock rock,
103
krb5_kdcpreauth_moddata moddata,
104
krb5_preauthtype pa_type,
105
krb5_kdcpreauth_edata_respond_fn respond,
108
krb5_error_code retval = 0;
109
pkinit_kdc_context plgctx = NULL;
111
pkiDebug("pkinit_server_get_edata: entered!\n");
115
* If we don't have a realm context for the given realm,
116
* don't tell the client that we support pkinit!
118
plgctx = pkinit_find_realm_context(context, moddata, request->server);
122
(*respond)(arg, retval, NULL);
125
static krb5_error_code
126
verify_client_san(krb5_context context,
127
pkinit_kdc_context plgctx,
128
pkinit_kdc_req_context reqctx,
129
krb5_principal client,
132
krb5_error_code retval;
133
krb5_principal *princs = NULL;
134
krb5_principal *upns = NULL;
136
#ifdef DEBUG_SAN_INFO
137
char *client_string = NULL, *san_string;
140
retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx,
141
reqctx->cryptoctx, plgctx->idctx,
143
plgctx->opts->allow_upn ? &upns : NULL,
146
pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
147
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
150
/* XXX Verify this is consistent with client side XXX */
152
retval = call_san_checking_plugins(context, plgctx, reqctx, princs,
153
upns, NULL, &plugin_decision, &ignore);
154
pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
157
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
160
pkiDebug("%s: call_san_checking_plugins() returned decision %d\n",
161
__FUNCTION__, plugin_decision);
162
if (plugin_decision != NO_DECISION) {
163
retval = plugin_decision;
168
#ifdef DEBUG_SAN_INFO
169
krb5_unparse_name(context, client, &client_string);
171
pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
172
for (i = 0; princs != NULL && princs[i] != NULL; i++) {
173
#ifdef DEBUG_SAN_INFO
174
krb5_unparse_name(context, princs[i], &san_string);
175
pkiDebug("%s: Comparing client '%s' to pkinit san value '%s'\n",
176
__FUNCTION__, client_string, san_string);
177
krb5_free_unparsed_name(context, san_string);
179
if (krb5_principal_compare(context, princs[i], client)) {
180
pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
186
pkiDebug("%s: no pkinit san match found\n", __FUNCTION__);
188
* XXX if cert has names but none match, should we
189
* be returning KRB5KDC_ERR_CLIENT_NAME_MISMATCH here?
193
pkiDebug("%s: no upn sans (or we wouldn't accept them anyway)\n",
195
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
199
pkiDebug("%s: Checking upn sans\n", __FUNCTION__);
200
for (i = 0; upns[i] != NULL; i++) {
201
#ifdef DEBUG_SAN_INFO
202
krb5_unparse_name(context, upns[i], &san_string);
203
pkiDebug("%s: Comparing client '%s' to upn san value '%s'\n",
204
__FUNCTION__, client_string, san_string);
205
krb5_free_unparsed_name(context, san_string);
207
if (krb5_principal_compare(context, upns[i], client)) {
208
pkiDebug("%s: upn san match found\n", __FUNCTION__);
214
pkiDebug("%s: no upn san match found\n", __FUNCTION__);
216
/* We found no match */
217
if (princs != NULL || upns != NULL) {
219
/* XXX ??? If there was one or more name in the cert, but
220
* none matched the client name, then return mismatch? */
221
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
226
if (princs != NULL) {
227
for (i = 0; princs[i] != NULL; i++)
228
krb5_free_principal(context, princs[i]);
232
for (i = 0; upns[i] != NULL; i++)
233
krb5_free_principal(context, upns[i]);
236
#ifdef DEBUG_SAN_INFO
237
if (client_string != NULL)
238
krb5_free_unparsed_name(context, client_string);
240
pkiDebug("%s: returning retval %d, valid_san %d\n",
241
__FUNCTION__, retval, *valid_san);
245
static krb5_error_code
246
verify_client_eku(krb5_context context,
247
pkinit_kdc_context plgctx,
248
pkinit_kdc_req_context reqctx,
251
krb5_error_code retval;
255
if (plgctx->opts->require_eku == 0) {
256
pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__);
262
retval = crypto_check_cert_eku(context, plgctx->cryptoctx,
263
reqctx->cryptoctx, plgctx->idctx,
265
plgctx->opts->accept_secondary_eku,
268
pkiDebug("%s: Error from crypto_check_cert_eku %d (%s)\n",
269
__FUNCTION__, retval, error_message(retval));
274
pkiDebug("%s: returning retval %d, eku_accepted %d\n",
275
__FUNCTION__, retval, *eku_accepted);
280
pkinit_server_verify_padata(krb5_context context,
282
krb5_kdc_req * request,
283
krb5_enc_tkt_part * enc_tkt_reply,
285
krb5_kdcpreauth_callbacks cb,
286
krb5_kdcpreauth_rock rock,
287
krb5_kdcpreauth_moddata moddata,
288
krb5_kdcpreauth_verify_respond_fn respond,
291
krb5_error_code retval = 0;
292
krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
293
krb5_pa_pk_as_req *reqp = NULL;
294
krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
295
krb5_auth_pack *auth_pack = NULL;
296
krb5_auth_pack_draft9 *auth_pack9 = NULL;
297
pkinit_kdc_context plgctx = NULL;
298
pkinit_kdc_req_context reqctx = NULL;
299
krb5_checksum cksum = {0, 0, 0, NULL};
300
krb5_data *der_req = NULL;
301
int valid_eku = 0, valid_san = 0;
302
krb5_kdc_req *tmp_as_req = NULL;
305
krb5_pa_data **e_data = NULL;
306
krb5_kdcpreauth_modreq modreq = NULL;
308
pkiDebug("pkinit_verify_padata: entered!\n");
309
if (data == NULL || data->length <= 0 || data->contents == NULL) {
310
(*respond)(arg, 0, NULL, NULL, NULL);
315
if (moddata == NULL) {
316
(*respond)(arg, EINVAL, NULL, NULL, NULL);
320
plgctx = pkinit_find_realm_context(context, moddata, request->server);
321
if (plgctx == NULL) {
322
(*respond)(arg, 0, NULL, NULL, NULL);
327
print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
329
/* create a per-request context */
330
retval = pkinit_init_kdc_req_context(context, &reqctx);
333
reqctx->pa_type = data->pa_type;
335
PADATA_TO_KRB5DATA(data, &k5data);
337
switch ((int)data->pa_type) {
338
case KRB5_PADATA_PK_AS_REQ:
339
pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
340
retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
342
pkiDebug("decode_krb5_pa_pk_as_req failed\n");
346
print_buffer_bin(reqp->signedAuthPack.data,
347
reqp->signedAuthPack.length,
348
"/tmp/kdc_signed_data");
350
retval = cms_signeddata_verify(context, plgctx->cryptoctx,
351
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_CLIENT,
352
plgctx->opts->require_crl_checking,
353
reqp->signedAuthPack.data, reqp->signedAuthPack.length,
354
&authp_data.data, &authp_data.length, &krb5_authz.data,
355
&krb5_authz.length, &is_signed);
357
case KRB5_PADATA_PK_AS_REP_OLD:
358
case KRB5_PADATA_PK_AS_REQ_OLD:
359
pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
360
retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
362
pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
366
print_buffer_bin(reqp9->signedAuthPack.data,
367
reqp9->signedAuthPack.length,
368
"/tmp/kdc_signed_data_draft9");
371
retval = cms_signeddata_verify(context, plgctx->cryptoctx,
372
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9,
373
plgctx->opts->require_crl_checking,
374
reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
375
&authp_data.data, &authp_data.length, &krb5_authz.data,
376
&krb5_authz.length, NULL);
379
pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
384
pkiDebug("pkcs7_signeddata_verify failed\n");
389
retval = verify_client_san(context, plgctx, reqctx, request->client,
394
pkiDebug("%s: did not find an acceptable SAN in user "
395
"certificate\n", __FUNCTION__);
396
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
399
retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
404
pkiDebug("%s: did not find an acceptable EKU in user "
405
"certificate\n", __FUNCTION__);
406
retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
409
} else { /* !is_signed */
410
if (!krb5_principal_compare(context, request->client,
411
krb5_anonymous_principal())) {
412
retval = KRB5KDC_ERR_PREAUTH_FAILED;
413
krb5_set_error_message(context, retval,
414
_("Pkinit request not signed, but client "
420
print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
423
OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
424
switch ((int)data->pa_type) {
425
case KRB5_PADATA_PK_AS_REQ:
426
retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
428
pkiDebug("failed to decode krb5_auth_pack\n");
432
/* check dh parameters */
433
if (auth_pack->clientPublicValue != NULL) {
434
retval = server_check_dh(context, plgctx->cryptoctx,
435
reqctx->cryptoctx, plgctx->idctx,
436
&auth_pack->clientPublicValue->algorithm.parameters,
437
plgctx->opts->dh_min_bits);
440
pkiDebug("bad dh parameters\n");
443
} else if (!is_signed) {
444
/*Anonymous pkinit requires DH*/
445
retval = KRB5KDC_ERR_PREAUTH_FAILED;
446
krb5_set_error_message(context, retval,
447
_("Anonymous pkinit without DH public "
448
"value not supported."));
451
der_req = cb->request_body(context, rock);
452
retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
455
pkiDebug("unable to calculate AS REQ checksum\n");
458
if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
459
memcmp(cksum.contents,
460
auth_pack->pkAuthenticator.paChecksum.contents,
462
pkiDebug("failed to match the checksum\n");
464
pkiDebug("calculating checksum on buf size (%d)\n",
466
print_buffer(req_pkt->data, req_pkt->length);
467
pkiDebug("received checksum type=%d size=%d ",
468
auth_pack->pkAuthenticator.paChecksum.checksum_type,
469
auth_pack->pkAuthenticator.paChecksum.length);
470
print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
471
auth_pack->pkAuthenticator.paChecksum.length);
472
pkiDebug("expected checksum type=%d size=%d ",
473
cksum.checksum_type, cksum.length);
474
print_buffer(cksum.contents, cksum.length);
477
retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
481
/* check if kdcPkId present and match KDC's subjectIdentifier */
482
if (reqp->kdcPkId.data != NULL) {
483
int valid_kdcPkId = 0;
484
retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
485
reqctx->cryptoctx, plgctx->idctx,
486
reqp->kdcPkId.data, reqp->kdcPkId.length, &valid_kdcPkId);
490
pkiDebug("kdcPkId in AS_REQ does not match KDC's cert"
491
"RFC says to ignore and proceed\n");
494
/* remember the decoded auth_pack for verify_padata routine */
495
reqctx->rcv_auth_pack = auth_pack;
498
case KRB5_PADATA_PK_AS_REP_OLD:
499
case KRB5_PADATA_PK_AS_REQ_OLD:
500
retval = k5int_decode_krb5_auth_pack_draft9(&k5data, &auth_pack9);
502
pkiDebug("failed to decode krb5_auth_pack_draft9\n");
505
if (auth_pack9->clientPublicValue != NULL) {
506
retval = server_check_dh(context, plgctx->cryptoctx,
507
reqctx->cryptoctx, plgctx->idctx,
508
&auth_pack9->clientPublicValue->algorithm.parameters,
509
plgctx->opts->dh_min_bits);
512
pkiDebug("bad dh parameters\n");
516
/* remember the decoded auth_pack for verify_padata routine */
517
reqctx->rcv_auth_pack9 = auth_pack9;
522
/* remember to set the PREAUTH flag in the reply */
523
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
524
modreq = (krb5_kdcpreauth_modreq)reqctx;
528
if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
529
pkiDebug("pkinit_verify_padata failed: creating e-data\n");
530
if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
531
plgctx->idctx, plgctx->opts, retval, &e_data))
532
pkiDebug("pkinit_create_edata failed\n");
535
switch ((int)data->pa_type) {
536
case KRB5_PADATA_PK_AS_REQ:
537
free_krb5_pa_pk_as_req(&reqp);
538
free(cksum.contents);
540
case KRB5_PADATA_PK_AS_REP_OLD:
541
case KRB5_PADATA_PK_AS_REQ_OLD:
542
free_krb5_pa_pk_as_req_draft9(&reqp9);
544
if (tmp_as_req != NULL)
545
k5int_krb5_free_kdc_req(context, tmp_as_req);
546
free(authp_data.data);
547
free(krb5_authz.data);
549
pkinit_fini_kdc_req_context(context, reqctx);
550
if (auth_pack != NULL)
551
free_krb5_auth_pack(&auth_pack);
552
if (auth_pack9 != NULL)
553
free_krb5_auth_pack_draft9(context, &auth_pack9);
555
(*respond)(arg, retval, modreq, e_data, NULL);
557
static krb5_error_code
558
return_pkinit_kx(krb5_context context, krb5_kdc_req *request,
559
krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
560
krb5_pa_data **out_padata)
562
krb5_error_code ret = 0;
563
krb5_keyblock *session = reply->ticket->enc_part2->session;
564
krb5_keyblock *new_session = NULL;
565
krb5_pa_data *pa = NULL;
567
krb5_data *scratch = NULL;
570
enc.ciphertext.data = NULL;
571
if (!krb5_principal_compare(context, request->client,
572
krb5_anonymous_principal()))
575
* The KDC contribution key needs to be a fresh key of an enctype supported
576
* by the client and server. The existing session key meets these
577
* requirements so we use it.
579
ret = krb5_c_fx_cf2_simple(context, session, "PKINIT",
580
encrypting_key, "KEYEXCHANGE",
584
ret = encode_krb5_encryption_key( session, &scratch);
587
ret = krb5_encrypt_helper(context, encrypting_key,
588
KRB5_KEYUSAGE_PA_PKINIT_KX, scratch, &enc);
591
memset(scratch->data, 0, scratch->length);
592
krb5_free_data(context, scratch);
594
ret = encode_krb5_enc_data(&enc, &scratch);
597
pa = malloc(sizeof(krb5_pa_data));
602
pa->pa_type = KRB5_PADATA_PKINIT_KX;
603
pa->length = scratch->length;
604
pa->contents = (krb5_octet *) scratch->data;
606
scratch->data = NULL;
607
memset(session->contents, 0, session->length);
608
krb5_free_keyblock_contents(context, session);
609
*session = *new_session;
610
new_session->contents = NULL;
612
krb5_free_data_contents(context, &enc.ciphertext);
613
krb5_free_keyblock(context, new_session);
614
krb5_free_data(context, scratch);
618
static krb5_error_code
619
pkinit_pick_kdf_alg(krb5_context context,
620
krb5_octet_data **kdf_list,
621
krb5_octet_data **alg_oid)
623
krb5_error_code retval = 0;
624
krb5_octet_data *req_oid = NULL;
625
const krb5_octet_data *supp_oid = NULL;
626
krb5_octet_data *tmp_oid = NULL;
629
/* if we don't find a match, return NULL value */
632
/* for each of the OIDs that the server supports... */
633
for (i = 0; NULL != (supp_oid = supported_kdf_alg_ids[i]); i++) {
634
/* if the requested OID is in the client's list, use it. */
635
for (j = 0; NULL != (req_oid = kdf_list[j]); j++) {
636
if ((req_oid->length == supp_oid->length) &&
637
(0 == memcmp(req_oid->data, supp_oid->data, req_oid->length))) {
638
tmp_oid = k5alloc(sizeof(krb5_octet_data), &retval);
641
tmp_oid->data = k5alloc(supp_oid->length, &retval);
644
tmp_oid->length = supp_oid->length;
645
memcpy(tmp_oid->data, supp_oid->data, tmp_oid->length);
647
/* don't free the OID in clean-up if we are returning it */
655
krb5_free_octet_data(context, tmp_oid);
659
static krb5_error_code
660
pkinit_server_return_padata(krb5_context context,
661
krb5_pa_data * padata,
663
krb5_kdc_req * request,
664
krb5_kdc_rep * reply,
665
krb5_keyblock * encrypting_key,
666
krb5_pa_data ** send_pa,
667
krb5_kdcpreauth_callbacks cb,
668
krb5_kdcpreauth_rock rock,
669
krb5_kdcpreauth_moddata moddata,
670
krb5_kdcpreauth_modreq modreq)
672
krb5_error_code retval = 0;
673
krb5_data scratch = {0, 0, NULL};
674
krb5_pa_pk_as_req *reqp = NULL;
675
krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
678
unsigned char *subjectPublicKey = NULL;
679
unsigned char *dh_pubkey = NULL, *server_key = NULL;
680
unsigned int subjectPublicKey_len = 0;
681
unsigned int server_key_len = 0, dh_pubkey_len = 0;
683
krb5_kdc_dh_key_info dhkey_info;
684
krb5_data *encoded_dhkey_info = NULL;
685
krb5_pa_pk_as_rep *rep = NULL;
686
krb5_pa_pk_as_rep_draft9 *rep9 = NULL;
687
krb5_data *out_data = NULL;
688
krb5_octet_data secret;
690
krb5_enctype enctype = -1;
692
krb5_reply_key_pack *key_pack = NULL;
693
krb5_reply_key_pack_draft9 *key_pack9 = NULL;
694
krb5_data *encoded_key_pack = NULL;
696
pkinit_kdc_context plgctx;
697
pkinit_kdc_req_context reqctx;
699
int fixed_keypack = 0;
702
if (padata->pa_type == KRB5_PADATA_PKINIT_KX) {
703
return return_pkinit_kx(context, request, reply,
704
encrypting_key, send_pa);
706
if (padata->length <= 0 || padata->contents == NULL)
709
if (modreq == NULL) {
710
pkiDebug("missing request context \n");
714
plgctx = pkinit_find_realm_context(context, moddata, request->server);
715
if (plgctx == NULL) {
716
pkiDebug("Unable to locate correct realm context\n");
720
pkiDebug("pkinit_return_padata: entered!\n");
721
reqctx = (pkinit_kdc_req_context)modreq;
723
if (encrypting_key->contents) {
724
free(encrypting_key->contents);
725
encrypting_key->length = 0;
726
encrypting_key->contents = NULL;
729
for(i = 0; i < request->nktypes; i++) {
730
enctype = request->ktype[i];
731
if (!krb5_c_valid_enctype(enctype))
734
pkiDebug("KDC picked etype = %d\n", enctype);
739
if (i == request->nktypes) {
740
retval = KRB5KDC_ERR_ETYPE_NOSUPP;
744
switch((int)reqctx->pa_type) {
745
case KRB5_PADATA_PK_AS_REQ:
746
init_krb5_pa_pk_as_rep(&rep);
751
/* let's assume it's RSA. we'll reset it to DH if needed */
752
rep->choice = choice_pa_pk_as_rep_encKeyPack;
754
case KRB5_PADATA_PK_AS_REP_OLD:
755
case KRB5_PADATA_PK_AS_REQ_OLD:
756
init_krb5_pa_pk_as_rep_draft9(&rep9);
761
rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
764
retval = KRB5KDC_ERR_PREAUTH_FAILED;
768
if (reqctx->rcv_auth_pack != NULL &&
769
reqctx->rcv_auth_pack->clientPublicValue != NULL) {
771
reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
772
subjectPublicKey_len =
773
reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
774
rep->choice = choice_pa_pk_as_rep_dhInfo;
775
} else if (reqctx->rcv_auth_pack9 != NULL &&
776
reqctx->rcv_auth_pack9->clientPublicValue != NULL) {
778
reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.data;
779
subjectPublicKey_len =
780
reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length;
781
rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
784
/* if this DH, then process finish computing DH key */
785
if (rep != NULL && (rep->choice == choice_pa_pk_as_rep_dhInfo ||
786
rep->choice == choice_pa_pk_as_rep_draft9_dhSignedData)) {
787
pkiDebug("received DH key delivery AS REQ\n");
788
retval = server_process_dh(context, plgctx->cryptoctx,
789
reqctx->cryptoctx, plgctx->idctx, subjectPublicKey,
790
subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len,
791
&server_key, &server_key_len);
793
pkiDebug("failed to process/create dh paramters\n");
798
rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
799
(rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
802
* This is DH, so don't generate the key until after we
803
* encode the reply, because the encoded reply is needed
804
* to generate the key in some cases.
807
dhkey_info.subjectPublicKey.length = dh_pubkey_len;
808
dhkey_info.subjectPublicKey.data = dh_pubkey;
809
dhkey_info.nonce = request->nonce;
810
dhkey_info.dhKeyExpiration = 0;
812
retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
813
&encoded_dhkey_info);
815
pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
819
print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
820
encoded_dhkey_info->length,
821
"/tmp/kdc_dh_key_info");
824
switch ((int)padata->pa_type) {
825
case KRB5_PADATA_PK_AS_REQ:
826
retval = cms_signeddata_create(context, plgctx->cryptoctx,
827
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1,
828
(unsigned char *)encoded_dhkey_info->data,
829
encoded_dhkey_info->length,
830
&rep->u.dh_Info.dhSignedData.data,
831
&rep->u.dh_Info.dhSignedData.length);
833
pkiDebug("failed to create pkcs7 signed data\n");
837
case KRB5_PADATA_PK_AS_REP_OLD:
838
case KRB5_PADATA_PK_AS_REQ_OLD:
839
retval = cms_signeddata_create(context, plgctx->cryptoctx,
840
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1,
841
(unsigned char *)encoded_dhkey_info->data,
842
encoded_dhkey_info->length,
843
&rep9->u.dhSignedData.data,
844
&rep9->u.dhSignedData.length);
846
pkiDebug("failed to create pkcs7 signed data\n");
853
pkiDebug("received RSA key delivery AS REQ\n");
855
retval = krb5_c_make_random_key(context, enctype, encrypting_key);
857
pkiDebug("unable to make a session key\n");
861
/* check if PA_TYPE of 132 is present which means the client is
862
* requesting that a checksum is send back instead of the nonce
864
for (i = 0; request->padata[i] != NULL; i++) {
865
pkiDebug("%s: Checking pa_type 0x%08x\n",
866
__FUNCTION__, request->padata[i]->pa_type);
867
if (request->padata[i]->pa_type == 132)
870
pkiDebug("%s: return checksum instead of nonce = %d\n",
871
__FUNCTION__, fixed_keypack);
873
/* if this is an RFC reply or draft9 client requested a checksum
874
* in the reply instead of the nonce, create an RFC-style keypack
876
if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) {
877
init_krb5_reply_key_pack(&key_pack);
878
if (key_pack == NULL) {
883
retval = krb5_c_make_checksum(context, 0,
884
encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
885
req_pkt, &key_pack->asChecksum);
887
pkiDebug("unable to calculate AS REQ checksum\n");
891
pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
892
print_buffer(req_pkt->data, req_pkt->length);
893
pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
894
print_buffer(key_pack->asChecksum.contents,
895
key_pack->asChecksum.length);
896
pkiDebug("encrypting key (%d)\n", encrypting_key->length);
897
print_buffer(encrypting_key->contents, encrypting_key->length);
900
krb5_copy_keyblock_contents(context, encrypting_key,
901
&key_pack->replyKey);
903
retval = k5int_encode_krb5_reply_key_pack(key_pack,
906
pkiDebug("failed to encode reply_key_pack\n");
911
switch ((int)padata->pa_type) {
912
case KRB5_PADATA_PK_AS_REQ:
913
rep->choice = choice_pa_pk_as_rep_encKeyPack;
914
retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
915
reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
916
(unsigned char *)encoded_key_pack->data,
917
encoded_key_pack->length,
918
&rep->u.encKeyPack.data, &rep->u.encKeyPack.length);
920
case KRB5_PADATA_PK_AS_REP_OLD:
921
case KRB5_PADATA_PK_AS_REQ_OLD:
922
/* if the request is from the broken draft9 client that
923
* expects back a nonce, create it now
925
if (!fixed_keypack) {
926
init_krb5_reply_key_pack_draft9(&key_pack9);
927
if (key_pack9 == NULL) {
931
key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce;
932
krb5_copy_keyblock_contents(context, encrypting_key,
933
&key_pack9->replyKey);
935
retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9,
938
pkiDebug("failed to encode reply_key_pack\n");
943
rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
944
retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
945
reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
946
(unsigned char *)encoded_key_pack->data,
947
encoded_key_pack->length,
948
&rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length);
952
pkiDebug("failed to create pkcs7 enveloped data: %s\n",
953
error_message(retval));
957
print_buffer_bin((unsigned char *)encoded_key_pack->data,
958
encoded_key_pack->length,
959
"/tmp/kdc_key_pack");
960
switch ((int)padata->pa_type) {
961
case KRB5_PADATA_PK_AS_REQ:
962
print_buffer_bin(rep->u.encKeyPack.data,
963
rep->u.encKeyPack.length,
964
"/tmp/kdc_enc_key_pack");
966
case KRB5_PADATA_PK_AS_REP_OLD:
967
case KRB5_PADATA_PK_AS_REQ_OLD:
968
print_buffer_bin(rep9->u.encKeyPack.data,
969
rep9->u.encKeyPack.length,
970
"/tmp/kdc_enc_key_pack");
976
if ((rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo) &&
977
((reqctx->rcv_auth_pack != NULL &&
978
reqctx->rcv_auth_pack->supportedKDFs != NULL))) {
980
/* If using the alg-agility KDF, put the algorithm in the reply
981
* before encoding it.
983
if (reqctx->rcv_auth_pack != NULL &&
984
reqctx->rcv_auth_pack->supportedKDFs != NULL) {
985
retval = pkinit_pick_kdf_alg(context, reqctx->rcv_auth_pack->supportedKDFs,
986
&(rep->u.dh_Info.kdfID));
988
pkiDebug("pkinit_pick_kdf_alg failed: %s\n",
989
error_message(retval));
995
switch ((int)padata->pa_type) {
996
case KRB5_PADATA_PK_AS_REQ:
997
retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
999
case KRB5_PADATA_PK_AS_REP_OLD:
1000
case KRB5_PADATA_PK_AS_REQ_OLD:
1001
retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
1005
pkiDebug("failed to encode AS_REP\n");
1009
if (out_data != NULL)
1010
print_buffer_bin((unsigned char *)out_data->data, out_data->length,
1014
/* If this is DH, we haven't computed the key yet, so do it now. */
1015
if ((rep9 != NULL &&
1016
rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
1017
(rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
1019
/* If mutually supported KDFs were found, use the alg agility KDF */
1020
if (rep->u.dh_Info.kdfID) {
1021
secret.data = server_key;
1022
secret.length = server_key_len;
1024
retval = pkinit_alg_agility_kdf(context, &secret,
1025
rep->u.dh_Info.kdfID,
1026
request->client, request->server,
1028
(krb5_octet_data *)req_pkt,
1029
(krb5_octet_data *)out_data,
1032
pkiDebug("pkinit_alg_agility_kdf failed: %s\n",
1033
error_message(retval));
1037
/* Otherwise, use the older octetstring2key() function */
1039
retval = pkinit_octetstring2key(context, enctype, server_key,
1040
server_key_len, encrypting_key);
1042
pkiDebug("pkinit_octetstring2key failed: %s\n",
1043
error_message(retval));
1049
*send_pa = malloc(sizeof(krb5_pa_data));
1050
if (*send_pa == NULL) {
1052
free(out_data->data);
1057
(*send_pa)->magic = KV5M_PA_DATA;
1058
switch ((int)padata->pa_type) {
1059
case KRB5_PADATA_PK_AS_REQ:
1060
(*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
1062
case KRB5_PADATA_PK_AS_REQ_OLD:
1063
case KRB5_PADATA_PK_AS_REP_OLD:
1064
(*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
1067
(*send_pa)->length = out_data->length;
1068
(*send_pa)->contents = (krb5_octet *) out_data->data;
1071
pkinit_fini_kdc_req_context(context, reqctx);
1074
if (encoded_dhkey_info != NULL)
1075
krb5_free_data(context, encoded_dhkey_info);
1076
if (encoded_key_pack != NULL)
1077
krb5_free_data(context, encoded_key_pack);
1081
switch ((int)padata->pa_type) {
1082
case KRB5_PADATA_PK_AS_REQ:
1083
free_krb5_pa_pk_as_req(&reqp);
1084
free_krb5_pa_pk_as_rep(&rep);
1085
free_krb5_reply_key_pack(&key_pack);
1087
case KRB5_PADATA_PK_AS_REP_OLD:
1088
case KRB5_PADATA_PK_AS_REQ_OLD:
1089
free_krb5_pa_pk_as_req_draft9(&reqp9);
1090
free_krb5_pa_pk_as_rep_draft9(&rep9);
1092
free_krb5_reply_key_pack_draft9(&key_pack9);
1094
free_krb5_reply_key_pack(&key_pack);
1099
pkiDebug("pkinit_verify_padata failure");
1105
pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
1107
if (patype == KRB5_PADATA_PKINIT_KX)
1109
return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA;
1112
static krb5_preauthtype supported_server_pa_types[] = {
1113
KRB5_PADATA_PK_AS_REQ,
1114
KRB5_PADATA_PK_AS_REQ_OLD,
1115
KRB5_PADATA_PK_AS_REP_OLD,
1116
KRB5_PADATA_PKINIT_KX,
1121
pkinit_fini_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1124
* There is nothing currently allocated by pkinit_init_kdc_profile()
1125
* which needs to be freed here.
1129
static krb5_error_code
1130
pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1132
krb5_error_code retval;
1133
char *eku_string = NULL;
1135
pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname);
1136
retval = pkinit_kdcdefault_string(context, plgctx->realmname,
1137
KRB5_CONF_PKINIT_IDENTITY,
1138
&plgctx->idopts->identity);
1139
if (retval != 0 || NULL == plgctx->idopts->identity) {
1141
krb5_set_error_message(context, retval,
1142
_("No pkinit_identity supplied for realm %s"),
1147
retval = pkinit_kdcdefault_strings(context, plgctx->realmname,
1148
KRB5_CONF_PKINIT_ANCHORS,
1149
&plgctx->idopts->anchors);
1150
if (retval != 0 || NULL == plgctx->idopts->anchors) {
1152
krb5_set_error_message(context, retval,
1153
_("No pkinit_anchors supplied for realm %s"),
1158
pkinit_kdcdefault_strings(context, plgctx->realmname,
1159
KRB5_CONF_PKINIT_POOL,
1160
&plgctx->idopts->intermediates);
1162
pkinit_kdcdefault_strings(context, plgctx->realmname,
1163
KRB5_CONF_PKINIT_REVOKE,
1164
&plgctx->idopts->crls);
1166
pkinit_kdcdefault_string(context, plgctx->realmname,
1167
KRB5_CONF_PKINIT_KDC_OCSP,
1168
&plgctx->idopts->ocsp);
1170
pkinit_kdcdefault_string(context, plgctx->realmname,
1171
KRB5_CONF_PKINIT_MAPPING_FILE,
1172
&plgctx->idopts->dn_mapping_file);
1174
pkinit_kdcdefault_integer(context, plgctx->realmname,
1175
KRB5_CONF_PKINIT_DH_MIN_BITS,
1176
PKINIT_DEFAULT_DH_MIN_BITS,
1177
&plgctx->opts->dh_min_bits);
1178
if (plgctx->opts->dh_min_bits < PKINIT_DEFAULT_DH_MIN_BITS) {
1179
pkiDebug("%s: invalid value (%d) for pkinit_dh_min_bits, "
1180
"using default value (%d) instead\n", __FUNCTION__,
1181
plgctx->opts->dh_min_bits, PKINIT_DEFAULT_DH_MIN_BITS);
1182
plgctx->opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
1185
pkinit_kdcdefault_boolean(context, plgctx->realmname,
1186
KRB5_CONF_PKINIT_ALLOW_UPN,
1187
0, &plgctx->opts->allow_upn);
1189
pkinit_kdcdefault_boolean(context, plgctx->realmname,
1190
KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING,
1191
0, &plgctx->opts->require_crl_checking);
1193
pkinit_kdcdefault_string(context, plgctx->realmname,
1194
KRB5_CONF_PKINIT_EKU_CHECKING,
1196
if (eku_string != NULL) {
1197
if (strcasecmp(eku_string, "kpClientAuth") == 0) {
1198
plgctx->opts->require_eku = 1;
1199
plgctx->opts->accept_secondary_eku = 0;
1200
} else if (strcasecmp(eku_string, "scLogin") == 0) {
1201
plgctx->opts->require_eku = 1;
1202
plgctx->opts->accept_secondary_eku = 1;
1203
} else if (strcasecmp(eku_string, "none") == 0) {
1204
plgctx->opts->require_eku = 0;
1205
plgctx->opts->accept_secondary_eku = 0;
1207
pkiDebug("%s: Invalid value for pkinit_eku_checking: '%s'\n",
1208
__FUNCTION__, eku_string);
1216
pkinit_fini_kdc_profile(context, plgctx);
1220
static pkinit_kdc_context
1221
pkinit_find_realm_context(krb5_context context,
1222
krb5_kdcpreauth_moddata moddata,
1223
krb5_principal princ)
1226
pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata;
1228
if (moddata == NULL)
1231
for (i = 0; realm_contexts[i] != NULL; i++) {
1232
pkinit_kdc_context p = realm_contexts[i];
1234
if ((p->realmname_len == princ->realm.length) &&
1235
(strncmp(p->realmname, princ->realm.data, p->realmname_len) == 0)) {
1236
pkiDebug("%s: returning context at %p for realm '%s'\n",
1237
__FUNCTION__, p, p->realmname);
1241
pkiDebug("%s: unable to find realm context for realm '%.*s'\n",
1242
__FUNCTION__, princ->realm.length, princ->realm.data);
1247
pkinit_server_plugin_init_realm(krb5_context context, const char *realmname,
1248
pkinit_kdc_context *pplgctx)
1250
krb5_error_code retval = ENOMEM;
1251
pkinit_kdc_context plgctx = NULL;
1255
plgctx = calloc(1, sizeof(*plgctx));
1259
pkiDebug("%s: initializing context at %p for realm '%s'\n",
1260
__FUNCTION__, plgctx, realmname);
1261
memset(plgctx, 0, sizeof(*plgctx));
1262
plgctx->magic = PKINIT_CTX_MAGIC;
1264
plgctx->realmname = strdup(realmname);
1265
if (plgctx->realmname == NULL)
1267
plgctx->realmname_len = strlen(plgctx->realmname);
1269
retval = pkinit_init_plg_crypto(&plgctx->cryptoctx);
1273
retval = pkinit_init_plg_opts(&plgctx->opts);
1277
retval = pkinit_init_identity_crypto(&plgctx->idctx);
1281
retval = pkinit_init_identity_opts(&plgctx->idopts);
1285
retval = pkinit_init_kdc_profile(context, plgctx);
1289
retval = pkinit_identity_initialize(context, plgctx->cryptoctx, NULL,
1290
plgctx->idopts, plgctx->idctx, 0, NULL);
1294
pkiDebug("%s: returning context at %p for realm '%s'\n",
1295
__FUNCTION__, plgctx, realmname);
1301
pkinit_server_plugin_fini_realm(context, plgctx);
1307
pkinit_server_plugin_init(krb5_context context,
1308
krb5_kdcpreauth_moddata *moddata_out,
1309
const char **realmnames)
1311
krb5_error_code retval = ENOMEM;
1312
pkinit_kdc_context plgctx, *realm_contexts = NULL;
1316
retval = pkinit_accessor_init();
1320
/* Determine how many realms we may need to support */
1321
for (i = 0; realmnames[i] != NULL; i++) {};
1324
realm_contexts = calloc(numrealms+1, sizeof(pkinit_kdc_context));
1325
if (realm_contexts == NULL)
1328
for (i = 0, j = 0; i < numrealms; i++) {
1329
pkiDebug("%s: processing realm '%s'\n", __FUNCTION__, realmnames[i]);
1330
retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx);
1331
if (retval == 0 && plgctx != NULL)
1332
realm_contexts[j++] = plgctx;
1337
krb5_set_error_message(context, retval,
1338
_("No realms configured correctly for pkinit "
1343
*moddata_out = (krb5_kdcpreauth_moddata)realm_contexts;
1345
pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts);
1349
pkinit_server_plugin_fini(context,
1350
(krb5_kdcpreauth_moddata)realm_contexts);
1357
pkinit_server_plugin_fini_realm(krb5_context context, pkinit_kdc_context plgctx)
1362
pkinit_fini_kdc_profile(context, plgctx);
1363
pkinit_fini_identity_opts(plgctx->idopts);
1364
pkinit_fini_identity_crypto(plgctx->idctx);
1365
pkinit_fini_plg_crypto(plgctx->cryptoctx);
1366
pkinit_fini_plg_opts(plgctx->opts);
1367
free(plgctx->realmname);
1372
pkinit_server_plugin_fini(krb5_context context,
1373
krb5_kdcpreauth_moddata moddata)
1375
pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata;
1378
if (realm_contexts == NULL)
1381
for (i = 0; realm_contexts[i] != NULL; i++) {
1382
pkinit_server_plugin_fini_realm(context, realm_contexts[i]);
1384
pkiDebug("%s: freeing context at %p\n", __FUNCTION__, realm_contexts);
1385
free(realm_contexts);
1388
static krb5_error_code
1389
pkinit_init_kdc_req_context(krb5_context context, pkinit_kdc_req_context *ctx)
1391
krb5_error_code retval = ENOMEM;
1392
pkinit_kdc_req_context reqctx = NULL;
1394
reqctx = malloc(sizeof(*reqctx));
1397
memset(reqctx, 0, sizeof(*reqctx));
1398
reqctx->magic = PKINIT_CTX_MAGIC;
1400
retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
1403
reqctx->rcv_auth_pack = NULL;
1404
reqctx->rcv_auth_pack9 = NULL;
1406
pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
1411
pkinit_fini_kdc_req_context(context, reqctx);
1417
pkinit_fini_kdc_req_context(krb5_context context, void *ctx)
1419
pkinit_kdc_req_context reqctx = (pkinit_kdc_req_context)ctx;
1421
if (reqctx == NULL || reqctx->magic != PKINIT_CTX_MAGIC) {
1422
pkiDebug("pkinit_fini_kdc_req_context: got bad reqctx (%p)!\n", reqctx);
1425
pkiDebug("%s: freeing reqctx at %p\n", __FUNCTION__, reqctx);
1427
pkinit_fini_req_crypto(reqctx->cryptoctx);
1428
if (reqctx->rcv_auth_pack != NULL)
1429
free_krb5_auth_pack(&reqctx->rcv_auth_pack);
1430
if (reqctx->rcv_auth_pack9 != NULL)
1431
free_krb5_auth_pack_draft9(context, &reqctx->rcv_auth_pack9);
1437
kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
1438
krb5_plugin_vtable vtable);
1441
kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
1442
krb5_plugin_vtable vtable)
1444
krb5_kdcpreauth_vtable vt;
1447
return KRB5_PLUGIN_VER_NOTSUPP;
1448
vt = (krb5_kdcpreauth_vtable)vtable;
1449
vt->name = "pkinit";
1450
vt->pa_type_list = supported_server_pa_types;
1451
vt->init = pkinit_server_plugin_init;
1452
vt->fini = pkinit_server_plugin_fini;
1453
vt->flags = pkinit_server_get_flags;
1454
vt->edata = pkinit_server_get_edata;
1455
vt->verify = pkinit_server_verify_padata;
1456
vt->return_padata = pkinit_server_return_padata;