2
* COPYRIGHT (C) 2006,2007
3
* THE REGENTS OF THE UNIVERSITY OF MICHIGAN
6
* Permission is granted to use, copy, create derivative works
7
* and redistribute this software and such derivative works
8
* for any purpose, so long as the name of The University of
9
* Michigan is not used in any advertising or publicity
10
* pertaining to the use of distribution of this software
11
* without specific, written prior authorization. If the
12
* above copyright notice or any other identification of the
13
* University of Michigan is included in any copy of any
14
* portion of this software, then the disclaimer below must
17
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18
* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19
* PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20
* MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21
* WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23
* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24
* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25
* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26
* OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
38
static krb5_error_code
39
pkinit_server_get_edata(krb5_context context,
40
krb5_kdc_req * request,
41
struct _krb5_db_entry_new * client,
42
struct _krb5_db_entry_new * server,
43
preauth_get_entry_data_proc server_get_entry_data,
44
void *pa_plugin_context,
47
static krb5_error_code
48
pkinit_server_verify_padata(krb5_context context,
49
struct _krb5_db_entry_new * client,
51
krb5_kdc_req * request,
52
krb5_enc_tkt_part * enc_tkt_reply,
54
preauth_get_entry_data_proc server_get_entry_data,
55
void *pa_plugin_context,
56
void **pa_request_context,
58
krb5_authdata ***authz_data);
60
static krb5_error_code
61
pkinit_server_return_padata(krb5_context context,
62
krb5_pa_data * padata,
63
struct _krb5_db_entry_new * client,
65
krb5_kdc_req * request,
67
struct _krb5_key_data * client_key,
68
krb5_keyblock * encrypting_key,
69
krb5_pa_data ** send_pa,
70
preauth_get_entry_data_proc server_get_entry_data,
71
void *pa_plugin_context,
72
void **pa_request_context);
74
static int pkinit_server_get_flags
75
(krb5_context kcontext, krb5_preauthtype patype);
77
static krb5_error_code pkinit_init_kdc_req_context
78
(krb5_context, void **blob);
80
static void pkinit_fini_kdc_req_context
81
(krb5_context context, void *blob);
83
static int pkinit_server_plugin_init_realm
84
(krb5_context context, const char *realmname,
85
pkinit_kdc_context *pplgctx);
87
static void pkinit_server_plugin_fini_realm
88
(krb5_context context, pkinit_kdc_context plgctx);
90
static int pkinit_server_plugin_init
91
(krb5_context context, void **blob, const char **realmnames);
93
static void pkinit_server_plugin_fini
94
(krb5_context context, void *blob);
96
static pkinit_kdc_context pkinit_find_realm_context
97
(krb5_context context, void *pa_plugin_context, krb5_principal princ);
99
static krb5_error_code
100
pkinit_create_edata(krb5_context context,
101
pkinit_plg_crypto_context plg_cryptoctx,
102
pkinit_req_crypto_context req_cryptoctx,
103
pkinit_identity_crypto_context id_cryptoctx,
104
pkinit_plg_opts *opts,
105
krb5_error_code err_code,
108
krb5_error_code retval = KRB5KRB_ERR_GENERIC;
110
pkiDebug("pkinit_create_edata: creating edata for error %d (%s)\n",
111
err_code, error_message(err_code));
113
case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
114
retval = pkinit_create_td_trusted_certifiers(context,
115
plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data);
117
case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
118
retval = pkinit_create_td_dh_parameters(context, plg_cryptoctx,
119
req_cryptoctx, id_cryptoctx, opts, e_data);
121
case KRB5KDC_ERR_INVALID_CERTIFICATE:
122
case KRB5KDC_ERR_REVOKED_CERTIFICATE:
123
retval = pkinit_create_td_invalid_certificate(context,
124
plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data);
127
pkiDebug("no edata needed for error %d (%s)\n",
128
err_code, error_message(err_code));
138
static krb5_error_code
139
pkinit_server_get_edata(krb5_context context,
140
krb5_kdc_req * request,
141
struct _krb5_db_entry_new * client,
142
struct _krb5_db_entry_new * server,
143
preauth_get_entry_data_proc server_get_entry_data,
144
void *pa_plugin_context,
147
krb5_error_code retval = 0;
148
pkinit_kdc_context plgctx = NULL;
150
pkiDebug("pkinit_server_get_edata: entered!\n");
153
* If we don't have a realm context for the given realm,
154
* don't tell the client that we support pkinit!
156
plgctx = pkinit_find_realm_context(context, pa_plugin_context,
164
static krb5_error_code
165
verify_client_san(krb5_context context,
166
pkinit_kdc_context plgctx,
167
pkinit_kdc_req_context reqctx,
168
krb5_principal client,
171
krb5_error_code retval;
172
krb5_principal *princs = NULL;
173
krb5_principal *upns = NULL;
175
#ifdef DEBUG_SAN_INFO
176
char *client_string = NULL, *san_string;
179
retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx,
180
reqctx->cryptoctx, plgctx->idctx,
182
plgctx->opts->allow_upn ? &upns : NULL,
185
pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
186
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
189
/* XXX Verify this is consistent with client side XXX */
191
retval = call_san_checking_plugins(context, plgctx, reqctx, princs,
192
upns, NULL, &plugin_decision, &ignore);
193
pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
196
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
199
pkiDebug("%s: call_san_checking_plugins() returned decision %d\n",
200
__FUNCTION__, plugin_decision);
201
if (plugin_decision != NO_DECISION) {
202
retval = plugin_decision;
207
#ifdef DEBUG_SAN_INFO
208
krb5_unparse_name(context, client, &client_string);
210
pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
211
for (i = 0; princs != NULL && princs[i] != NULL; i++) {
212
#ifdef DEBUG_SAN_INFO
213
krb5_unparse_name(context, princs[i], &san_string);
214
pkiDebug("%s: Comparing client '%s' to pkinit san value '%s'\n",
215
__FUNCTION__, client_string, san_string);
216
krb5_free_unparsed_name(context, san_string);
218
if (krb5_principal_compare(context, princs[i], client)) {
219
pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
225
pkiDebug("%s: no pkinit san match found\n", __FUNCTION__);
227
* XXX if cert has names but none match, should we
228
* be returning KRB5KDC_ERR_CLIENT_NAME_MISMATCH here?
232
pkiDebug("%s: no upn sans (or we wouldn't accept them anyway)\n",
234
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
238
pkiDebug("%s: Checking upn sans\n", __FUNCTION__);
239
for (i = 0; upns[i] != NULL; i++) {
240
#ifdef DEBUG_SAN_INFO
241
krb5_unparse_name(context, upns[i], &san_string);
242
pkiDebug("%s: Comparing client '%s' to upn san value '%s'\n",
243
__FUNCTION__, client_string, san_string);
244
krb5_free_unparsed_name(context, san_string);
246
if (krb5_principal_compare(context, upns[i], client)) {
247
pkiDebug("%s: upn san match found\n", __FUNCTION__);
253
pkiDebug("%s: no upn san match found\n", __FUNCTION__);
255
/* We found no match */
256
if (princs != NULL || upns != NULL) {
258
/* XXX ??? If there was one or more name in the cert, but
259
* none matched the client name, then return mismatch? */
260
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
265
if (princs != NULL) {
266
for (i = 0; princs[i] != NULL; i++)
267
krb5_free_principal(context, princs[i]);
271
for (i = 0; upns[i] != NULL; i++)
272
krb5_free_principal(context, upns[i]);
275
#ifdef DEBUG_SAN_INFO
276
if (client_string != NULL)
277
krb5_free_unparsed_name(context, client_string);
279
pkiDebug("%s: returning retval %d, valid_san %d\n",
280
__FUNCTION__, retval, *valid_san);
284
static krb5_error_code
285
verify_client_eku(krb5_context context,
286
pkinit_kdc_context plgctx,
287
pkinit_kdc_req_context reqctx,
290
krb5_error_code retval;
294
if (plgctx->opts->require_eku == 0) {
295
pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__);
301
retval = crypto_check_cert_eku(context, plgctx->cryptoctx,
302
reqctx->cryptoctx, plgctx->idctx,
304
plgctx->opts->accept_secondary_eku,
307
pkiDebug("%s: Error from crypto_check_cert_eku %d (%s)\n",
308
__FUNCTION__, retval, error_message(retval));
313
pkiDebug("%s: returning retval %d, eku_accepted %d\n",
314
__FUNCTION__, retval, *eku_accepted);
318
static krb5_error_code
319
pkinit_server_verify_padata(krb5_context context,
320
struct _krb5_db_entry_new * client,
322
krb5_kdc_req * request,
323
krb5_enc_tkt_part * enc_tkt_reply,
325
preauth_get_entry_data_proc server_get_entry_data,
326
void *pa_plugin_context,
327
void **pa_request_context,
329
krb5_authdata ***authz_data)
331
krb5_error_code retval = 0;
332
krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
333
krb5_data *encoded_pkinit_authz_data = NULL;
334
krb5_pa_pk_as_req *reqp = NULL;
335
krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
336
krb5_auth_pack *auth_pack = NULL;
337
krb5_auth_pack_draft9 *auth_pack9 = NULL;
338
pkinit_kdc_context plgctx = NULL;
339
pkinit_kdc_req_context reqctx;
340
krb5_preauthtype pa_type;
341
krb5_checksum cksum = {0, 0, 0, NULL};
342
krb5_data *der_req = NULL;
343
int valid_eku = 0, valid_san = 0;
344
krb5_authdata **my_authz_data = NULL, *pkinit_authz_data = NULL;
345
krb5_kdc_req *tmp_as_req = NULL;
348
pkiDebug("pkinit_verify_padata: entered!\n");
349
if (data == NULL || data->length <= 0 || data->contents == NULL)
352
if (pa_plugin_context == NULL || e_data == NULL)
355
plgctx = pkinit_find_realm_context(context, pa_plugin_context,
361
print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
363
/* create a per-request context */
364
retval = pkinit_init_kdc_req_context(context, (void **)&reqctx);
367
reqctx->pa_type = data->pa_type;
369
PADATA_TO_KRB5DATA(data, &k5data);
371
switch ((int)data->pa_type) {
372
case KRB5_PADATA_PK_AS_REQ:
373
pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
374
pa_type = (int)data->pa_type;
375
retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
377
pkiDebug("decode_krb5_pa_pk_as_req failed\n");
381
print_buffer_bin(reqp->signedAuthPack.data,
382
reqp->signedAuthPack.length,
383
"/tmp/kdc_signed_data");
385
retval = cms_signeddata_verify(context, plgctx->cryptoctx,
386
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_CLIENT,
387
plgctx->opts->require_crl_checking,
388
reqp->signedAuthPack.data, reqp->signedAuthPack.length,
389
&authp_data.data, &authp_data.length, &krb5_authz.data,
392
case KRB5_PADATA_PK_AS_REP_OLD:
393
case KRB5_PADATA_PK_AS_REQ_OLD:
394
pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
395
pa_type = KRB5_PADATA_PK_AS_REQ_OLD;
396
retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
398
pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
402
print_buffer_bin(reqp9->signedAuthPack.data,
403
reqp9->signedAuthPack.length,
404
"/tmp/kdc_signed_data_draft9");
407
retval = cms_signeddata_verify(context, plgctx->cryptoctx,
408
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9,
409
plgctx->opts->require_crl_checking,
410
reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
411
&authp_data.data, &authp_data.length, &krb5_authz.data,
415
pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
420
pkiDebug("pkcs7_signeddata_verify failed\n");
424
retval = verify_client_san(context, plgctx, reqctx, request->client,
429
pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
431
retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
434
retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
439
pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
441
retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
446
print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
449
OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
450
switch ((int)data->pa_type) {
451
case KRB5_PADATA_PK_AS_REQ:
452
retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
454
pkiDebug("failed to decode krb5_auth_pack\n");
458
/* check dh parameters */
459
if (auth_pack->clientPublicValue != NULL) {
460
retval = server_check_dh(context, plgctx->cryptoctx,
461
reqctx->cryptoctx, plgctx->idctx,
462
&auth_pack->clientPublicValue->algorithm.parameters,
463
plgctx->opts->dh_min_bits);
466
pkiDebug("bad dh parameters\n");
471
* The KDC may have modified the request after decoding it.
472
* We need to compute the checksum on the data that
473
* came from the client. Therefore, we use the original
476
retval = k5int_decode_krb5_as_req(req_pkt, &tmp_as_req);
478
pkiDebug("decode_krb5_as_req returned %d\n", (int)retval);
482
retval = k5int_encode_krb5_kdc_req_body(tmp_as_req, &der_req);
484
pkiDebug("encode_krb5_kdc_req_body returned %d\n", (int) retval);
487
retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
490
pkiDebug("unable to calculate AS REQ checksum\n");
493
if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
494
memcmp(cksum.contents,
495
auth_pack->pkAuthenticator.paChecksum.contents,
497
pkiDebug("failed to match the checksum\n");
499
pkiDebug("calculating checksum on buf size (%d)\n",
501
print_buffer(req_pkt->data, req_pkt->length);
502
pkiDebug("received checksum type=%d size=%d ",
503
auth_pack->pkAuthenticator.paChecksum.checksum_type,
504
auth_pack->pkAuthenticator.paChecksum.length);
505
print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
506
auth_pack->pkAuthenticator.paChecksum.length);
507
pkiDebug("expected checksum type=%d size=%d ",
508
cksum.checksum_type, cksum.length);
509
print_buffer(cksum.contents, cksum.length);
512
retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
516
/* check if kdcPkId present and match KDC's subjectIdentifier */
517
if (reqp->kdcPkId.data != NULL) {
518
int valid_kdcPkId = 0;
519
retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
520
reqctx->cryptoctx, plgctx->idctx,
521
reqp->kdcPkId.data, reqp->kdcPkId.length, &valid_kdcPkId);
525
pkiDebug("kdcPkId in AS_REQ does not match KDC's cert"
526
"RFC says to ignore and proceed\n");
529
/* remember the decoded auth_pack for verify_padata routine */
530
reqctx->rcv_auth_pack = auth_pack;
533
case KRB5_PADATA_PK_AS_REP_OLD:
534
case KRB5_PADATA_PK_AS_REQ_OLD:
535
retval = k5int_decode_krb5_auth_pack_draft9(&k5data, &auth_pack9);
537
pkiDebug("failed to decode krb5_auth_pack_draft9\n");
540
if (auth_pack9->clientPublicValue != NULL) {
541
retval = server_check_dh(context, plgctx->cryptoctx,
542
reqctx->cryptoctx, plgctx->idctx,
543
&auth_pack9->clientPublicValue->algorithm.parameters,
544
plgctx->opts->dh_min_bits);
547
pkiDebug("bad dh parameters\n");
551
/* remember the decoded auth_pack for verify_padata routine */
552
reqctx->rcv_auth_pack9 = auth_pack9;
557
/* return authorization data to be included in the ticket */
558
switch ((int)data->pa_type) {
559
case KRB5_PADATA_PK_AS_REQ:
560
my_authz_data = malloc(2 * sizeof(*my_authz_data));
561
if (my_authz_data == NULL) {
563
pkiDebug("Couldn't allocate krb5_authdata ptr array\n");
566
my_authz_data[1] = NULL;
567
my_authz_data[0] = malloc(sizeof(krb5_authdata));
568
if (my_authz_data[0] == NULL) {
570
pkiDebug("Couldn't allocate krb5_authdata\n");
574
/* AD-INITIAL-VERIFIED-CAS must be wrapped in AD-IF-RELEVANT */
575
my_authz_data[0]->magic = KV5M_AUTHDATA;
576
my_authz_data[0]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
578
/* create an internal AD-INITIAL-VERIFIED-CAS data */
579
pkinit_authz_data = malloc(sizeof(krb5_authdata));
580
if (pkinit_authz_data == NULL) {
582
pkiDebug("Couldn't allocate krb5_authdata\n");
583
free(my_authz_data[0]);
587
pkinit_authz_data->ad_type = KRB5_AUTHDATA_INITIAL_VERIFIED_CAS;
588
/* content of this ad-type contains the certification
589
path with which the client certificate was validated
591
pkinit_authz_data->contents = krb5_authz.data;
592
pkinit_authz_data->length = krb5_authz.length;
593
retval = k5int_encode_krb5_authdata_elt(pkinit_authz_data,
594
&encoded_pkinit_authz_data);
596
print_buffer_bin((unsigned char *)encoded_pkinit_authz_data->data,
597
encoded_pkinit_authz_data->length,
598
"/tmp/kdc_pkinit_authz_data");
600
free(pkinit_authz_data);
602
pkiDebug("k5int_encode_krb5_authdata_elt failed\n");
603
free(my_authz_data[0]);
608
my_authz_data[0]->contents =
609
(krb5_octet *) encoded_pkinit_authz_data->data;
610
my_authz_data[0]->length = encoded_pkinit_authz_data->length;
611
*authz_data = my_authz_data;
612
pkiDebug("Returning %d bytes of authorization data\n",
614
encoded_pkinit_authz_data->data = NULL; /* Don't free during cleanup*/
615
free(encoded_pkinit_authz_data);
620
/* remember to set the PREAUTH flag in the reply */
621
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
622
*pa_request_context = reqctx;
626
if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
627
pkiDebug("pkinit_verify_padata failed: creating e-data\n");
628
if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
629
plgctx->idctx, plgctx->opts, retval, e_data))
630
pkiDebug("pkinit_create_edata failed\n");
633
switch ((int)data->pa_type) {
634
case KRB5_PADATA_PK_AS_REQ:
635
free_krb5_pa_pk_as_req(&reqp);
636
if (cksum.contents != NULL)
637
free(cksum.contents);
639
krb5_free_data(context, der_req);
641
case KRB5_PADATA_PK_AS_REP_OLD:
642
case KRB5_PADATA_PK_AS_REQ_OLD:
643
free_krb5_pa_pk_as_req_draft9(&reqp9);
645
if (tmp_as_req != NULL)
646
k5int_krb5_free_kdc_req(context, tmp_as_req);
647
if (authp_data.data != NULL)
648
free(authp_data.data);
649
if (krb5_authz.data != NULL)
650
free(krb5_authz.data);
652
pkinit_fini_kdc_req_context(context, reqctx);
653
if (auth_pack != NULL)
654
free_krb5_auth_pack(&auth_pack);
655
if (auth_pack9 != NULL)
656
free_krb5_auth_pack_draft9(context, &auth_pack9);
661
static krb5_error_code
662
pkinit_server_return_padata(krb5_context context,
663
krb5_pa_data * padata,
664
struct _krb5_db_entry_new * client,
666
krb5_kdc_req * request,
667
krb5_kdc_rep * reply,
668
struct _krb5_key_data * client_key,
669
krb5_keyblock * encrypting_key,
670
krb5_pa_data ** send_pa,
671
preauth_get_entry_data_proc server_get_entry_data,
672
void *pa_plugin_context,
673
void **pa_request_context)
675
krb5_error_code retval = 0;
676
krb5_data scratch = {0, 0, NULL};
677
krb5_pa_pk_as_req *reqp = NULL;
678
krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
681
unsigned char *subjectPublicKey = NULL;
682
unsigned char *dh_pubkey = NULL, *server_key = NULL;
683
unsigned int subjectPublicKey_len = 0;
684
unsigned int server_key_len = 0, dh_pubkey_len = 0;
686
krb5_kdc_dh_key_info dhkey_info;
687
krb5_data *encoded_dhkey_info = NULL;
688
krb5_pa_pk_as_rep *rep = NULL;
689
krb5_pa_pk_as_rep_draft9 *rep9 = NULL;
690
krb5_data *out_data = NULL;
692
krb5_enctype enctype = -1;
694
krb5_reply_key_pack *key_pack = NULL;
695
krb5_reply_key_pack_draft9 *key_pack9 = NULL;
696
krb5_data *encoded_key_pack = NULL;
697
unsigned int num_types;
698
krb5_cksumtype *cksum_types = NULL;
700
pkinit_kdc_context plgctx;
701
pkinit_kdc_req_context reqctx;
703
int fixed_keypack = 0;
706
if (padata == NULL || padata->length <= 0 || padata->contents == NULL)
709
if (pa_request_context == NULL || *pa_request_context == NULL) {
710
pkiDebug("missing request context \n");
714
plgctx = pkinit_find_realm_context(context, pa_plugin_context,
716
if (plgctx == NULL) {
717
pkiDebug("Unable to locate correct realm context\n");
721
pkiDebug("pkinit_return_padata: entered!\n");
722
reqctx = (pkinit_kdc_req_context)*pa_request_context;
724
if (encrypting_key->contents) {
725
free(encrypting_key->contents);
726
encrypting_key->length = 0;
727
encrypting_key->contents = NULL;
730
for(i = 0; i < request->nktypes; i++) {
731
enctype = request->ktype[i];
732
if (!krb5_c_valid_enctype(enctype))
735
pkiDebug("KDC picked etype = %d\n", enctype);
740
if (i == request->nktypes) {
741
retval = KRB5KDC_ERR_ETYPE_NOSUPP;
745
switch((int)reqctx->pa_type) {
746
case KRB5_PADATA_PK_AS_REQ:
747
init_krb5_pa_pk_as_rep(&rep);
752
/* let's assume it's RSA. we'll reset it to DH if needed */
753
rep->choice = choice_pa_pk_as_rep_encKeyPack;
755
case KRB5_PADATA_PK_AS_REP_OLD:
756
case KRB5_PADATA_PK_AS_REQ_OLD:
757
init_krb5_pa_pk_as_rep_draft9(&rep9);
762
rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
765
retval = KRB5KDC_ERR_PREAUTH_FAILED;
769
if (reqctx->rcv_auth_pack != NULL &&
770
reqctx->rcv_auth_pack->clientPublicValue != NULL) {
772
reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
773
subjectPublicKey_len =
774
reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
775
rep->choice = choice_pa_pk_as_rep_dhInfo;
776
} else if (reqctx->rcv_auth_pack9 != NULL &&
777
reqctx->rcv_auth_pack9->clientPublicValue != NULL) {
779
reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.data;
780
subjectPublicKey_len =
781
reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length;
782
rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
785
/* if this DH, then process finish computing DH key */
786
if (rep != NULL && (rep->choice == choice_pa_pk_as_rep_dhInfo ||
787
rep->choice == choice_pa_pk_as_rep_draft9_dhSignedData)) {
788
pkiDebug("received DH key delivery AS REQ\n");
789
retval = server_process_dh(context, plgctx->cryptoctx,
790
reqctx->cryptoctx, plgctx->idctx, subjectPublicKey,
791
subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len,
792
&server_key, &server_key_len);
794
pkiDebug("failed to process/create dh paramters\n");
800
rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
801
(rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
802
retval = pkinit_octetstring2key(context, enctype, server_key,
803
server_key_len, encrypting_key);
805
pkiDebug("pkinit_octetstring2key failed: %s\n",
806
error_message(retval));
810
dhkey_info.subjectPublicKey.length = dh_pubkey_len;
811
dhkey_info.subjectPublicKey.data = dh_pubkey;
812
dhkey_info.nonce = request->nonce;
813
dhkey_info.dhKeyExpiration = 0;
815
retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
816
&encoded_dhkey_info);
818
pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
822
print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
823
encoded_dhkey_info->length,
824
"/tmp/kdc_dh_key_info");
827
switch ((int)padata->pa_type) {
828
case KRB5_PADATA_PK_AS_REQ:
829
retval = cms_signeddata_create(context, plgctx->cryptoctx,
830
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1,
831
(unsigned char *)encoded_dhkey_info->data,
832
encoded_dhkey_info->length,
833
&rep->u.dh_Info.dhSignedData.data,
834
&rep->u.dh_Info.dhSignedData.length);
836
pkiDebug("failed to create pkcs7 signed data\n");
840
case KRB5_PADATA_PK_AS_REP_OLD:
841
case KRB5_PADATA_PK_AS_REQ_OLD:
842
retval = cms_signeddata_create(context, plgctx->cryptoctx,
843
reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1,
844
(unsigned char *)encoded_dhkey_info->data,
845
encoded_dhkey_info->length,
846
&rep9->u.dhSignedData.data,
847
&rep9->u.dhSignedData.length);
849
pkiDebug("failed to create pkcs7 signed data\n");
855
pkiDebug("received RSA key delivery AS REQ\n");
857
retval = krb5_c_make_random_key(context, enctype, encrypting_key);
859
pkiDebug("unable to make a session key\n");
863
/* check if PA_TYPE of 132 is present which means the client is
864
* requesting that a checksum is send back instead of the nonce
866
for (i = 0; request->padata[i] != NULL; i++) {
867
pkiDebug("%s: Checking pa_type 0x%08x\n",
868
__FUNCTION__, request->padata[i]->pa_type);
869
if (request->padata[i]->pa_type == 132)
872
pkiDebug("%s: return checksum instead of nonce = %d\n",
873
__FUNCTION__, fixed_keypack);
875
/* if this is an RFC reply or draft9 client requested a checksum
876
* in the reply instead of the nonce, create an RFC-style keypack
878
if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) {
879
init_krb5_reply_key_pack(&key_pack);
880
if (key_pack == NULL) {
884
/* retrieve checksums for a given enctype of the reply key */
885
retval = krb5_c_keyed_checksum_types(context,
886
encrypting_key->enctype, &num_types, &cksum_types);
890
/* pick the first of acceptable enctypes for the checksum */
891
retval = krb5_c_make_checksum(context, cksum_types[0],
892
encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
893
req_pkt, &key_pack->asChecksum);
895
pkiDebug("unable to calculate AS REQ checksum\n");
899
pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
900
print_buffer(req_pkt->data, req_pkt->length);
901
pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
902
print_buffer(key_pack->asChecksum.contents,
903
key_pack->asChecksum.length);
904
pkiDebug("encrypting key (%d)\n", encrypting_key->length);
905
print_buffer(encrypting_key->contents, encrypting_key->length);
908
krb5_copy_keyblock_contents(context, encrypting_key,
909
&key_pack->replyKey);
911
retval = k5int_encode_krb5_reply_key_pack(key_pack,
914
pkiDebug("failed to encode reply_key_pack\n");
919
switch ((int)padata->pa_type) {
920
case KRB5_PADATA_PK_AS_REQ:
921
rep->choice = choice_pa_pk_as_rep_encKeyPack;
922
retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
923
reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
924
(unsigned char *)encoded_key_pack->data,
925
encoded_key_pack->length,
926
&rep->u.encKeyPack.data, &rep->u.encKeyPack.length);
928
case KRB5_PADATA_PK_AS_REP_OLD:
929
case KRB5_PADATA_PK_AS_REQ_OLD:
930
/* if the request is from the broken draft9 client that
931
* expects back a nonce, create it now
933
if (!fixed_keypack) {
934
init_krb5_reply_key_pack_draft9(&key_pack9);
935
if (key_pack9 == NULL) {
939
key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce;
940
krb5_copy_keyblock_contents(context, encrypting_key,
941
&key_pack9->replyKey);
943
retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9,
946
pkiDebug("failed to encode reply_key_pack\n");
951
rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
952
retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
953
reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
954
(unsigned char *)encoded_key_pack->data,
955
encoded_key_pack->length,
956
&rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length);
960
pkiDebug("failed to create pkcs7 enveloped data: %s\n",
961
error_message(retval));
965
print_buffer_bin((unsigned char *)encoded_key_pack->data,
966
encoded_key_pack->length,
967
"/tmp/kdc_key_pack");
968
switch ((int)padata->pa_type) {
969
case KRB5_PADATA_PK_AS_REQ:
970
print_buffer_bin(rep->u.encKeyPack.data,
971
rep->u.encKeyPack.length,
972
"/tmp/kdc_enc_key_pack");
974
case KRB5_PADATA_PK_AS_REP_OLD:
975
case KRB5_PADATA_PK_AS_REQ_OLD:
976
print_buffer_bin(rep9->u.encKeyPack.data,
977
rep9->u.encKeyPack.length,
978
"/tmp/kdc_enc_key_pack");
984
switch ((int)padata->pa_type) {
985
case KRB5_PADATA_PK_AS_REQ:
986
retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
988
case KRB5_PADATA_PK_AS_REP_OLD:
989
case KRB5_PADATA_PK_AS_REQ_OLD:
990
retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
994
pkiDebug("failed to encode AS_REP\n");
998
if (out_data != NULL)
999
print_buffer_bin((unsigned char *)out_data->data, out_data->length,
1003
*send_pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
1004
if (*send_pa == NULL) {
1006
free(out_data->data);
1011
(*send_pa)->magic = KV5M_PA_DATA;
1012
switch ((int)padata->pa_type) {
1013
case KRB5_PADATA_PK_AS_REQ:
1014
(*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
1016
case KRB5_PADATA_PK_AS_REQ_OLD:
1017
case KRB5_PADATA_PK_AS_REP_OLD:
1018
(*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
1021
(*send_pa)->length = out_data->length;
1022
(*send_pa)->contents = (krb5_octet *) out_data->data;
1026
pkinit_fini_kdc_req_context(context, reqctx);
1027
if (scratch.data != NULL)
1029
if (out_data != NULL)
1031
if (encoded_dhkey_info != NULL)
1032
krb5_free_data(context, encoded_dhkey_info);
1033
if (encoded_key_pack != NULL)
1034
krb5_free_data(context, encoded_key_pack);
1035
if (dh_pubkey != NULL)
1037
if (server_key != NULL)
1039
if (cksum_types != NULL)
1042
switch ((int)padata->pa_type) {
1043
case KRB5_PADATA_PK_AS_REQ:
1044
free_krb5_pa_pk_as_req(&reqp);
1045
free_krb5_pa_pk_as_rep(&rep);
1046
free_krb5_reply_key_pack(&key_pack);
1048
case KRB5_PADATA_PK_AS_REP_OLD:
1049
case KRB5_PADATA_PK_AS_REQ_OLD:
1050
free_krb5_pa_pk_as_req_draft9(&reqp9);
1051
free_krb5_pa_pk_as_rep_draft9(&rep9);
1053
free_krb5_reply_key_pack_draft9(&key_pack9);
1055
free_krb5_reply_key_pack(&key_pack);
1060
pkiDebug("pkinit_verify_padata failure");
1066
pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
1068
return PA_SUFFICIENT | PA_REPLACES_KEY;
1071
static krb5_preauthtype supported_server_pa_types[] = {
1072
KRB5_PADATA_PK_AS_REQ,
1073
KRB5_PADATA_PK_AS_REQ_OLD,
1074
KRB5_PADATA_PK_AS_REP_OLD,
1079
pkinit_fini_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1082
* There is nothing currently allocated by pkinit_init_kdc_profile()
1083
* which needs to be freed here.
1087
static krb5_error_code
1088
pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1090
krb5_error_code retval;
1091
char *eku_string = NULL;
1093
pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname);
1094
retval = pkinit_kdcdefault_string(context, plgctx->realmname,
1096
&plgctx->idopts->identity);
1097
if (retval != 0 || NULL == plgctx->idopts->identity) {
1099
krb5_set_error_message(context, retval,
1100
"No pkinit_identity supplied for realm %s",
1105
retval = pkinit_kdcdefault_strings(context, plgctx->realmname,
1107
&plgctx->idopts->anchors);
1108
if (retval != 0 || NULL == plgctx->idopts->anchors) {
1110
krb5_set_error_message(context, retval,
1111
"No pkinit_anchors supplied for realm %s",
1116
pkinit_kdcdefault_strings(context, plgctx->realmname,
1118
&plgctx->idopts->intermediates);
1120
pkinit_kdcdefault_strings(context, plgctx->realmname,
1122
&plgctx->idopts->crls);
1124
pkinit_kdcdefault_string(context, plgctx->realmname,
1126
&plgctx->idopts->ocsp);
1128
pkinit_kdcdefault_string(context, plgctx->realmname,
1129
"pkinit_mappings_file",
1130
&plgctx->idopts->dn_mapping_file);
1132
pkinit_kdcdefault_integer(context, plgctx->realmname,
1133
"pkinit_dh_min_bits",
1134
PKINIT_DEFAULT_DH_MIN_BITS,
1135
&plgctx->opts->dh_min_bits);
1136
if (plgctx->opts->dh_min_bits < 1024) {
1137
pkiDebug("%s: invalid value (%d) for pkinit_dh_min_bits, "
1138
"using default value (%d) instead\n", __FUNCTION__,
1139
plgctx->opts->dh_min_bits, PKINIT_DEFAULT_DH_MIN_BITS);
1140
plgctx->opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
1143
pkinit_kdcdefault_boolean(context, plgctx->realmname,
1145
0, &plgctx->opts->allow_upn);
1147
pkinit_kdcdefault_boolean(context, plgctx->realmname,
1148
"pkinit_require_crl_checking",
1149
0, &plgctx->opts->require_crl_checking);
1151
pkinit_kdcdefault_string(context, plgctx->realmname,
1152
"pkinit_eku_checking",
1154
if (eku_string != NULL) {
1155
if (strcasecmp(eku_string, "kpClientAuth") == 0) {
1156
plgctx->opts->require_eku = 1;
1157
plgctx->opts->accept_secondary_eku = 0;
1158
} else if (strcasecmp(eku_string, "scLogin") == 0) {
1159
plgctx->opts->require_eku = 1;
1160
plgctx->opts->accept_secondary_eku = 1;
1161
} else if (strcasecmp(eku_string, "none") == 0) {
1162
plgctx->opts->require_eku = 0;
1163
plgctx->opts->accept_secondary_eku = 0;
1165
pkiDebug("%s: Invalid value for pkinit_eku_checking: '%s'\n",
1166
__FUNCTION__, eku_string);
1174
pkinit_fini_kdc_profile(context, plgctx);
1178
static pkinit_kdc_context
1179
pkinit_find_realm_context(krb5_context context, void *pa_plugin_context,
1180
krb5_principal princ)
1183
pkinit_kdc_context *realm_contexts = pa_plugin_context;
1185
if (pa_plugin_context == NULL)
1188
for (i = 0; realm_contexts[i] != NULL; i++) {
1189
pkinit_kdc_context p = realm_contexts[i];
1191
if ((p->realmname_len == princ->realm.length) &&
1192
(strncmp(p->realmname, princ->realm.data, p->realmname_len) == 0)) {
1193
pkiDebug("%s: returning context at %p for realm '%s'\n",
1194
__FUNCTION__, p, p->realmname);
1198
pkiDebug("%s: unable to find realm context for realm '%.*s'\n",
1199
__FUNCTION__, princ->realm.length, princ->realm.data);
1204
pkinit_server_plugin_init_realm(krb5_context context, const char *realmname,
1205
pkinit_kdc_context *pplgctx)
1207
krb5_error_code retval = ENOMEM;
1208
pkinit_kdc_context plgctx = NULL;
1212
plgctx = (pkinit_kdc_context) calloc(1, sizeof(*plgctx));
1216
pkiDebug("%s: initializing context at %p for realm '%s'\n",
1217
__FUNCTION__, plgctx, realmname);
1218
memset(plgctx, 0, sizeof(*plgctx));
1219
plgctx->magic = PKINIT_CTX_MAGIC;
1221
plgctx->realmname = strdup(realmname);
1222
if (plgctx->realmname == NULL)
1224
plgctx->realmname_len = strlen(plgctx->realmname);
1226
retval = pkinit_init_plg_crypto(&plgctx->cryptoctx);
1230
retval = pkinit_init_plg_opts(&plgctx->opts);
1234
retval = pkinit_init_identity_crypto(&plgctx->idctx);
1238
retval = pkinit_init_identity_opts(&plgctx->idopts);
1242
retval = pkinit_init_kdc_profile(context, plgctx);
1246
retval = pkinit_identity_initialize(context, plgctx->cryptoctx, NULL,
1247
plgctx->idopts, plgctx->idctx, 0, NULL);
1251
pkiDebug("%s: returning context at %p for realm '%s'\n",
1252
__FUNCTION__, plgctx, realmname);
1258
pkinit_server_plugin_fini_realm(context, plgctx);
1264
pkinit_server_plugin_init(krb5_context context, void **blob,
1265
const char **realmnames)
1267
krb5_error_code retval = ENOMEM;
1268
pkinit_kdc_context plgctx, *realm_contexts = NULL;
1272
retval = pkinit_accessor_init();
1276
/* Determine how many realms we may need to support */
1277
for (i = 0; realmnames[i] != NULL; i++) {};
1280
realm_contexts = (pkinit_kdc_context *)
1281
calloc(numrealms+1, sizeof(pkinit_kdc_context));
1282
if (realm_contexts == NULL)
1285
for (i = 0, j = 0; i < numrealms; i++) {
1286
pkiDebug("%s: processing realm '%s'\n", __FUNCTION__, realmnames[i]);
1287
retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx);
1288
if (retval == 0 && plgctx != NULL)
1289
realm_contexts[j++] = plgctx;
1294
krb5_set_error_message(context, retval, "No realms configured "
1295
"correctly for pkinit support");
1299
*blob = realm_contexts;
1301
pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts);
1305
pkinit_server_plugin_fini(context, realm_contexts);
1311
pkinit_server_plugin_fini_realm(krb5_context context, pkinit_kdc_context plgctx)
1316
pkinit_fini_kdc_profile(context, plgctx);
1317
pkinit_fini_identity_opts(plgctx->idopts);
1318
pkinit_fini_identity_crypto(plgctx->idctx);
1319
pkinit_fini_plg_crypto(plgctx->cryptoctx);
1320
pkinit_fini_plg_opts(plgctx->opts);
1321
free(plgctx->realmname);
1326
pkinit_server_plugin_fini(krb5_context context, void *blob)
1328
pkinit_kdc_context *realm_contexts = blob;
1331
if (realm_contexts == NULL)
1334
for (i = 0; realm_contexts[i] != NULL; i++) {
1335
pkinit_server_plugin_fini_realm(context, realm_contexts[i]);
1337
pkiDebug("%s: freeing context at %p\n", __FUNCTION__, realm_contexts);
1338
free(realm_contexts);
1341
static krb5_error_code
1342
pkinit_init_kdc_req_context(krb5_context context, void **ctx)
1344
krb5_error_code retval = ENOMEM;
1345
pkinit_kdc_req_context reqctx = NULL;
1347
reqctx = (pkinit_kdc_req_context)malloc(sizeof(*reqctx));
1350
memset(reqctx, 0, sizeof(*reqctx));
1351
reqctx->magic = PKINIT_CTX_MAGIC;
1353
retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
1356
reqctx->rcv_auth_pack = NULL;
1357
reqctx->rcv_auth_pack9 = NULL;
1359
pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
1364
pkinit_fini_kdc_req_context(context, reqctx);
1370
pkinit_fini_kdc_req_context(krb5_context context, void *ctx)
1372
pkinit_kdc_req_context reqctx = (pkinit_kdc_req_context)ctx;
1374
if (reqctx == NULL || reqctx->magic != PKINIT_CTX_MAGIC) {
1375
pkiDebug("pkinit_fini_kdc_req_context: got bad reqctx (%p)!\n", reqctx);
1378
pkiDebug("%s: freeing reqctx at %p\n", __FUNCTION__, reqctx);
1380
pkinit_fini_req_crypto(reqctx->cryptoctx);
1381
if (reqctx->rcv_auth_pack != NULL)
1382
free_krb5_auth_pack(&reqctx->rcv_auth_pack);
1383
if (reqctx->rcv_auth_pack9 != NULL)
1384
free_krb5_auth_pack_draft9(context, &reqctx->rcv_auth_pack9);
1389
struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
1390
"pkinit", /* name */
1391
supported_server_pa_types, /* pa_type_list */
1392
pkinit_server_plugin_init, /* (*init_proc) */
1393
pkinit_server_plugin_fini, /* (*fini_proc) */
1394
pkinit_server_get_flags, /* (*flags_proc) */
1395
pkinit_server_get_edata, /* (*edata_proc) */
1396
pkinit_server_verify_padata,/* (*verify_proc) */
1397
pkinit_server_return_padata,/* (*return_proc) */
1398
NULL, /* (*freepa_reqcontext_proc) */