/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- _krb5_pk_cert_free
- BN_to_integer
- integer_to_BN
- find_cert
- create_signature
- cert2epi
- build_edi
- build_auth_pack
- _krb5_pk_mk_ContentInfo
- pk_mk_padata
- _krb5_pk_mk_padata
- _krb5_pk_verify_sign
- get_reply_key_win
- get_reply_key
- pk_verify_host
- pk_rd_pa_reply_enckey
- pk_rd_pa_reply_dh
- _krb5_pk_rd_pa_reply
- hx_pass_prompter
- _krb5_pk_allow_proxy_certificate
- _krb5_pk_load_id
- select_dh_group
- pk_copy_error
- parse_integer
- _krb5_parse_moduli_line
- _krb5_free_moduli
- _krb5_parse_moduli
- _krb5_dh_group_ok
- _krb5_get_init_creds_opt_free_pkinit
- krb5_get_init_creds_opt_set_pkinit
1 /*
2 * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "krb5_locl.h"
35
36 RCSID("$Id$");
37
38 struct krb5_dh_moduli {
39 char *name;
40 unsigned long bits;
41 heim_integer p;
42 heim_integer g;
43 heim_integer q;
44 };
45
46 #ifdef PKINIT
47
48 #include <cms_asn1.h>
49 #include <pkcs8_asn1.h>
50 #include <pkcs9_asn1.h>
51 #include <pkcs12_asn1.h>
52 #include <pkinit_asn1.h>
53 #include <asn1_err.h>
54
55 #include <der.h>
56
57 struct krb5_pk_cert {
58 hx509_cert cert;
59 };
60
61 struct krb5_pk_init_ctx_data {
62 struct krb5_pk_identity *id;
63 DH *dh;
64 krb5_data *clientDHNonce;
65 struct krb5_dh_moduli **m;
66 hx509_peer_info peer;
67 enum krb5_pk_type type;
68 unsigned int require_binding:1;
69 unsigned int require_eku:1;
70 unsigned int require_krbtgt_otherName:1;
71 unsigned int require_hostname_match:1;
72 unsigned int trustedCertifiers:1;
73 };
74
75 static void
76 pk_copy_error(krb5_context context,
77 hx509_context hx509ctx,
78 int hxret,
79 const char *fmt,
80 ...)
81 __attribute__ ((format (printf, 4, 5)));
82
83 /*
84 *
85 */
86
87 void KRB5_LIB_FUNCTION
88 _krb5_pk_cert_free(struct krb5_pk_cert *cert)
/* [<][>][^][v][top][bottom][index][help] */
89 {
90 if (cert->cert) {
91 hx509_cert_free(cert->cert);
92 }
93 free(cert);
94 }
95
96 static krb5_error_code
97 BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
/* [<][>][^][v][top][bottom][index][help] */
98 {
99 integer->length = BN_num_bytes(bn);
100 integer->data = malloc(integer->length);
101 if (integer->data == NULL) {
102 krb5_clear_error_message(context);
103 return ENOMEM;
104 }
105 BN_bn2bin(bn, integer->data);
106 integer->negative = BN_is_negative(bn);
107 return 0;
108 }
109
110 static BIGNUM *
111 integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
/* [<][>][^][v][top][bottom][index][help] */
112 {
113 BIGNUM *bn;
114
115 bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
116 if (bn == NULL) {
117 krb5_set_error_message(context, ENOMEM,
118 N_("PKINIT: parsing BN failed %s", ""), field);
119 return NULL;
120 }
121 BN_set_negative(bn, f->negative);
122 return bn;
123 }
124
125 struct certfind {
126 const char *type;
127 const heim_oid *oid;
128 };
129
130 /*
131 * Try searchin the key by to use by first looking for for PK-INIT
132 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
133 */
134
135 static krb5_error_code
136 find_cert(krb5_context context, struct krb5_pk_identity *id,
/* [<][>][^][v][top][bottom][index][help] */
137 hx509_query *q, hx509_cert *cert)
138 {
139 struct certfind cf[3] = {
140 { "PKINIT EKU" },
141 { "MS EKU" },
142 { "no" }
143 };
144 int i, ret;
145
146 cf[0].oid = oid_id_pkekuoid();
147 cf[1].oid = oid_id_pkinit_ms_eku();
148 cf[2].oid = NULL;
149
150 for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) {
151 ret = hx509_query_match_eku(q, cf[i].oid);
152 if (ret) {
153 pk_copy_error(context, id->hx509ctx, ret,
154 "Failed setting %s OID", cf[i].type);
155 return ret;
156 }
157
158 ret = hx509_certs_find(id->hx509ctx, id->certs, q, cert);
159 if (ret == 0)
160 break;
161 pk_copy_error(context, id->hx509ctx, ret,
162 "Failed cert for finding %s OID", cf[i].type);
163 }
164 return ret;
165 }
166
167
168 static krb5_error_code
169 create_signature(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
170 const heim_oid *eContentType,
171 krb5_data *eContent,
172 struct krb5_pk_identity *id,
173 hx509_peer_info peer,
174 krb5_data *sd_data)
175 {
176 hx509_cert cert = NULL;
177 hx509_query *q = NULL;
178 int ret;
179
180 ret = hx509_query_alloc(id->hx509ctx, &q);
181 if (ret) {
182 pk_copy_error(context, id->hx509ctx, ret,
183 "Allocate query to find signing certificate");
184 return ret;
185 }
186
187 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
188 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
189
190 ret = find_cert(context, id, q, &cert);
191 hx509_query_free(id->hx509ctx, q);
192 if (ret)
193 return ret;
194
195 ret = hx509_cms_create_signed_1(id->hx509ctx,
196 0,
197 eContentType,
198 eContent->data,
199 eContent->length,
200 NULL,
201 cert,
202 peer,
203 NULL,
204 id->certs,
205 sd_data);
206 hx509_cert_free(cert);
207 if (ret) {
208 pk_copy_error(context, id->hx509ctx, ret,
209 "Create CMS signedData");
210 return ret;
211 }
212
213 return 0;
214 }
215
216 static int
217 cert2epi(hx509_context context, void *ctx, hx509_cert c)
/* [<][>][^][v][top][bottom][index][help] */
218 {
219 ExternalPrincipalIdentifiers *ids = ctx;
220 ExternalPrincipalIdentifier id;
221 hx509_name subject = NULL;
222 void *p;
223 int ret;
224
225 memset(&id, 0, sizeof(id));
226
227 ret = hx509_cert_get_subject(c, &subject);
228 if (ret)
229 return ret;
230
231 if (hx509_name_is_null_p(subject) != 0) {
232
233 id.subjectName = calloc(1, sizeof(*id.subjectName));
234 if (id.subjectName == NULL) {
235 hx509_name_free(&subject);
236 free_ExternalPrincipalIdentifier(&id);
237 return ENOMEM;
238 }
239
240 ret = hx509_name_binary(subject, id.subjectName);
241 if (ret) {
242 hx509_name_free(&subject);
243 free_ExternalPrincipalIdentifier(&id);
244 return ret;
245 }
246 }
247 hx509_name_free(&subject);
248
249
250 id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
251 if (id.issuerAndSerialNumber == NULL) {
252 free_ExternalPrincipalIdentifier(&id);
253 return ENOMEM;
254 }
255
256 {
257 IssuerAndSerialNumber iasn;
258 hx509_name issuer;
259 size_t size;
260
261 memset(&iasn, 0, sizeof(iasn));
262
263 ret = hx509_cert_get_issuer(c, &issuer);
264 if (ret) {
265 free_ExternalPrincipalIdentifier(&id);
266 return ret;
267 }
268
269 ret = hx509_name_to_Name(issuer, &iasn.issuer);
270 hx509_name_free(&issuer);
271 if (ret) {
272 free_ExternalPrincipalIdentifier(&id);
273 return ret;
274 }
275
276 ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
277 if (ret) {
278 free_IssuerAndSerialNumber(&iasn);
279 free_ExternalPrincipalIdentifier(&id);
280 return ret;
281 }
282
283 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
284 id.issuerAndSerialNumber->data,
285 id.issuerAndSerialNumber->length,
286 &iasn, &size, ret);
287 free_IssuerAndSerialNumber(&iasn);
288 if (ret)
289 return ret;
290 if (id.issuerAndSerialNumber->length != size)
291 abort();
292 }
293
294 id.subjectKeyIdentifier = NULL;
295
296 p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
297 if (p == NULL) {
298 free_ExternalPrincipalIdentifier(&id);
299 return ENOMEM;
300 }
301
302 ids->val = p;
303 ids->val[ids->len] = id;
304 ids->len++;
305
306 return 0;
307 }
308
309 static krb5_error_code
310 build_edi(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
311 hx509_context hx509ctx,
312 hx509_certs certs,
313 ExternalPrincipalIdentifiers *ids)
314 {
315 return hx509_certs_iter(hx509ctx, certs, cert2epi, ids);
316 }
317
318 static krb5_error_code
319 build_auth_pack(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
320 unsigned nonce,
321 krb5_pk_init_ctx ctx,
322 DH *dh,
323 const KDC_REQ_BODY *body,
324 AuthPack *a)
325 {
326 size_t buf_size, len;
327 krb5_error_code ret;
328 void *buf;
329 krb5_timestamp sec;
330 int32_t usec;
331 Checksum checksum;
332
333 krb5_clear_error_message(context);
334
335 memset(&checksum, 0, sizeof(checksum));
336
337 krb5_us_timeofday(context, &sec, &usec);
338 a->pkAuthenticator.ctime = sec;
339 a->pkAuthenticator.nonce = nonce;
340
341 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
342 if (ret)
343 return ret;
344 if (buf_size != len)
345 krb5_abortx(context, "internal error in ASN.1 encoder");
346
347 ret = krb5_create_checksum(context,
348 NULL,
349 0,
350 CKSUMTYPE_SHA1,
351 buf,
352 len,
353 &checksum);
354 free(buf);
355 if (ret)
356 return ret;
357
358 ALLOC(a->pkAuthenticator.paChecksum, 1);
359 if (a->pkAuthenticator.paChecksum == NULL) {
360 krb5_set_error_message(context, ENOMEM,
361 N_("malloc: out of memory", ""));
362 return ENOMEM;
363 }
364
365 ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
366 checksum.checksum.data, checksum.checksum.length);
367 free_Checksum(&checksum);
368 if (ret)
369 return ret;
370
371 if (dh) {
372 DomainParameters dp;
373 heim_integer dh_pub_key;
374 krb5_data dhbuf;
375 size_t size;
376
377 if (1 /* support_cached_dh */) {
378 ALLOC(a->clientDHNonce, 1);
379 if (a->clientDHNonce == NULL) {
380 krb5_clear_error_message(context);
381 return ENOMEM;
382 }
383 ret = krb5_data_alloc(a->clientDHNonce, 40);
384 if (a->clientDHNonce == NULL) {
385 krb5_clear_error_message(context);
386 return ret;
387 }
388 memset(a->clientDHNonce->data, 0, a->clientDHNonce->length);
389 ret = krb5_copy_data(context, a->clientDHNonce,
390 &ctx->clientDHNonce);
391 if (ret)
392 return ret;
393 }
394
395 ALLOC(a->clientPublicValue, 1);
396 if (a->clientPublicValue == NULL)
397 return ENOMEM;
398 ret = der_copy_oid(oid_id_dhpublicnumber(),
399 &a->clientPublicValue->algorithm.algorithm);
400 if (ret)
401 return ret;
402
403 memset(&dp, 0, sizeof(dp));
404
405 ret = BN_to_integer(context, dh->p, &dp.p);
406 if (ret) {
407 free_DomainParameters(&dp);
408 return ret;
409 }
410 ret = BN_to_integer(context, dh->g, &dp.g);
411 if (ret) {
412 free_DomainParameters(&dp);
413 return ret;
414 }
415 ret = BN_to_integer(context, dh->q, &dp.q);
416 if (ret) {
417 free_DomainParameters(&dp);
418 return ret;
419 }
420 dp.j = NULL;
421 dp.validationParms = NULL;
422
423 a->clientPublicValue->algorithm.parameters =
424 malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
425 if (a->clientPublicValue->algorithm.parameters == NULL) {
426 free_DomainParameters(&dp);
427 return ret;
428 }
429
430 ASN1_MALLOC_ENCODE(DomainParameters,
431 a->clientPublicValue->algorithm.parameters->data,
432 a->clientPublicValue->algorithm.parameters->length,
433 &dp, &size, ret);
434 free_DomainParameters(&dp);
435 if (ret)
436 return ret;
437 if (size != a->clientPublicValue->algorithm.parameters->length)
438 krb5_abortx(context, "Internal ASN1 encoder error");
439
440 ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
441 if (ret)
442 return ret;
443
444 ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
445 &dh_pub_key, &size, ret);
446 der_free_heim_integer(&dh_pub_key);
447 if (ret)
448 return ret;
449 if (size != dhbuf.length)
450 krb5_abortx(context, "asn1 internal error");
451
452 a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
453 a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
454 }
455
456 {
457 a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
458 if (a->supportedCMSTypes == NULL)
459 return ENOMEM;
460
461 ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL,
462 &a->supportedCMSTypes->val,
463 &a->supportedCMSTypes->len);
464 if (ret)
465 return ret;
466 }
467
468 return ret;
469 }
470
471 krb5_error_code KRB5_LIB_FUNCTION
472 _krb5_pk_mk_ContentInfo(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
473 const krb5_data *buf,
474 const heim_oid *oid,
475 struct ContentInfo *content_info)
476 {
477 krb5_error_code ret;
478
479 ret = der_copy_oid(oid, &content_info->contentType);
480 if (ret)
481 return ret;
482 ALLOC(content_info->content, 1);
483 if (content_info->content == NULL)
484 return ENOMEM;
485 content_info->content->data = malloc(buf->length);
486 if (content_info->content->data == NULL)
487 return ENOMEM;
488 memcpy(content_info->content->data, buf->data, buf->length);
489 content_info->content->length = buf->length;
490 return 0;
491 }
492
493 static krb5_error_code
494 pk_mk_padata(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
495 krb5_pk_init_ctx ctx,
496 const KDC_REQ_BODY *req_body,
497 unsigned nonce,
498 METHOD_DATA *md)
499 {
500 struct ContentInfo content_info;
501 krb5_error_code ret;
502 const heim_oid *oid;
503 size_t size;
504 krb5_data buf, sd_buf;
505 int pa_type;
506
507 krb5_data_zero(&buf);
508 krb5_data_zero(&sd_buf);
509 memset(&content_info, 0, sizeof(content_info));
510
511 if (ctx->type == PKINIT_WIN2K) {
512 AuthPack_Win2k ap;
513 krb5_timestamp sec;
514 int32_t usec;
515
516 memset(&ap, 0, sizeof(ap));
517
518 /* fill in PKAuthenticator */
519 ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
520 if (ret) {
521 free_AuthPack_Win2k(&ap);
522 krb5_clear_error_message(context);
523 goto out;
524 }
525 ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
526 if (ret) {
527 free_AuthPack_Win2k(&ap);
528 krb5_clear_error_message(context);
529 goto out;
530 }
531
532 krb5_us_timeofday(context, &sec, &usec);
533 ap.pkAuthenticator.ctime = sec;
534 ap.pkAuthenticator.cusec = usec;
535 ap.pkAuthenticator.nonce = nonce;
536
537 ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
538 &ap, &size, ret);
539 free_AuthPack_Win2k(&ap);
540 if (ret) {
541 krb5_set_error_message(context, ret,
542 N_("Failed encoding AuthPackWin: %d", ""),
543 (int)ret);
544 goto out;
545 }
546 if (buf.length != size)
547 krb5_abortx(context, "internal ASN1 encoder error");
548
549 oid = oid_id_pkcs7_data();
550 } else if (ctx->type == PKINIT_27) {
551 AuthPack ap;
552
553 memset(&ap, 0, sizeof(ap));
554
555 ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap);
556 if (ret) {
557 free_AuthPack(&ap);
558 goto out;
559 }
560
561 ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
562 free_AuthPack(&ap);
563 if (ret) {
564 krb5_set_error_message(context, ret,
565 N_("Failed encoding AuthPack: %d", ""),
566 (int)ret);
567 goto out;
568 }
569 if (buf.length != size)
570 krb5_abortx(context, "internal ASN1 encoder error");
571
572 oid = oid_id_pkauthdata();
573 } else
574 krb5_abortx(context, "internal pkinit error");
575
576 ret = create_signature(context, oid, &buf, ctx->id,
577 ctx->peer, &sd_buf);
578 krb5_data_free(&buf);
579 if (ret)
580 goto out;
581
582 ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf);
583 krb5_data_free(&sd_buf);
584 if (ret) {
585 krb5_set_error_message(context, ret,
586 N_("ContentInfo wrapping of signedData failed",""));
587 goto out;
588 }
589
590 if (ctx->type == PKINIT_WIN2K) {
591 PA_PK_AS_REQ_Win2k winreq;
592
593 pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
594
595 memset(&winreq, 0, sizeof(winreq));
596
597 winreq.signed_auth_pack = buf;
598
599 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
600 &winreq, &size, ret);
601 free_PA_PK_AS_REQ_Win2k(&winreq);
602
603 } else if (ctx->type == PKINIT_27) {
604 PA_PK_AS_REQ req;
605
606 pa_type = KRB5_PADATA_PK_AS_REQ;
607
608 memset(&req, 0, sizeof(req));
609 req.signedAuthPack = buf;
610
611 if (ctx->trustedCertifiers) {
612
613 req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
614 if (req.trustedCertifiers == NULL) {
615 ret = ENOMEM;
616 krb5_set_error_message(context, ret,
617 N_("malloc: out of memory", ""));
618 free_PA_PK_AS_REQ(&req);
619 goto out;
620 }
621 ret = build_edi(context, ctx->id->hx509ctx,
622 ctx->id->anchors, req.trustedCertifiers);
623 if (ret) {
624 krb5_set_error_message(context, ret,
625 N_("pk-init: failed to build "
626 "trustedCertifiers", ""));
627 free_PA_PK_AS_REQ(&req);
628 goto out;
629 }
630 }
631 req.kdcPkId = NULL;
632
633 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
634 &req, &size, ret);
635
636 free_PA_PK_AS_REQ(&req);
637
638 } else
639 krb5_abortx(context, "internal pkinit error");
640 if (ret) {
641 krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
642 goto out;
643 }
644 if (buf.length != size)
645 krb5_abortx(context, "Internal ASN1 encoder error");
646
647 ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
648 if (ret)
649 free(buf.data);
650
651 if (ret == 0 && ctx->type == PKINIT_WIN2K)
652 krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
653
654 out:
655 free_ContentInfo(&content_info);
656
657 return ret;
658 }
659
660
661 krb5_error_code KRB5_LIB_FUNCTION
662 _krb5_pk_mk_padata(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
663 void *c,
664 const KDC_REQ_BODY *req_body,
665 unsigned nonce,
666 METHOD_DATA *md)
667 {
668 krb5_pk_init_ctx ctx = c;
669 int win2k_compat;
670
671 win2k_compat = krb5_config_get_bool_default(context, NULL,
672 FALSE,
673 "realms",
674 req_body->realm,
675 "pkinit_win2k",
676 NULL);
677
678 if (win2k_compat) {
679 ctx->require_binding =
680 krb5_config_get_bool_default(context, NULL,
681 FALSE,
682 "realms",
683 req_body->realm,
684 "pkinit_win2k_require_binding",
685 NULL);
686 ctx->type = PKINIT_WIN2K;
687 } else
688 ctx->type = PKINIT_27;
689
690 ctx->require_eku =
691 krb5_config_get_bool_default(context, NULL,
692 TRUE,
693 "realms",
694 req_body->realm,
695 "pkinit_require_eku",
696 NULL);
697 ctx->require_krbtgt_otherName =
698 krb5_config_get_bool_default(context, NULL,
699 TRUE,
700 "realms",
701 req_body->realm,
702 "pkinit_require_krbtgt_otherName",
703 NULL);
704
705 ctx->require_hostname_match =
706 krb5_config_get_bool_default(context, NULL,
707 FALSE,
708 "realms",
709 req_body->realm,
710 "pkinit_require_hostname_match",
711 NULL);
712
713 ctx->trustedCertifiers =
714 krb5_config_get_bool_default(context, NULL,
715 TRUE,
716 "realms",
717 req_body->realm,
718 "pkinit_trustedCertifiers",
719 NULL);
720
721 return pk_mk_padata(context, ctx, req_body, nonce, md);
722 }
723
724 krb5_error_code KRB5_LIB_FUNCTION
725 _krb5_pk_verify_sign(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
726 const void *data,
727 size_t length,
728 struct krb5_pk_identity *id,
729 heim_oid *contentType,
730 krb5_data *content,
731 struct krb5_pk_cert **signer)
732 {
733 hx509_certs signer_certs;
734 int ret;
735
736 *signer = NULL;
737
738 ret = hx509_cms_verify_signed(id->hx509ctx,
739 id->verify_ctx,
740 data,
741 length,
742 NULL,
743 id->certpool,
744 contentType,
745 content,
746 &signer_certs);
747 if (ret) {
748 pk_copy_error(context, id->hx509ctx, ret,
749 "CMS verify signed failed");
750 return ret;
751 }
752
753 *signer = calloc(1, sizeof(**signer));
754 if (*signer == NULL) {
755 krb5_clear_error_message(context);
756 ret = ENOMEM;
757 goto out;
758 }
759
760 ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert);
761 if (ret) {
762 pk_copy_error(context, id->hx509ctx, ret,
763 "Failed to get on of the signer certs");
764 goto out;
765 }
766
767 out:
768 hx509_certs_free(&signer_certs);
769 if (ret) {
770 if (*signer) {
771 hx509_cert_free((*signer)->cert);
772 free(*signer);
773 *signer = NULL;
774 }
775 }
776
777 return ret;
778 }
779
780 static krb5_error_code
781 get_reply_key_win(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
782 const krb5_data *content,
783 unsigned nonce,
784 krb5_keyblock **key)
785 {
786 ReplyKeyPack_Win2k key_pack;
787 krb5_error_code ret;
788 size_t size;
789
790 ret = decode_ReplyKeyPack_Win2k(content->data,
791 content->length,
792 &key_pack,
793 &size);
794 if (ret) {
795 krb5_set_error_message(context, ret,
796 N_("PKINIT decoding reply key failed", ""));
797 free_ReplyKeyPack_Win2k(&key_pack);
798 return ret;
799 }
800
801 if (key_pack.nonce != nonce) {
802 krb5_set_error_message(context, ret,
803 N_("PKINIT enckey nonce is wrong", ""));
804 free_ReplyKeyPack_Win2k(&key_pack);
805 return KRB5KRB_AP_ERR_MODIFIED;
806 }
807
808 *key = malloc (sizeof (**key));
809 if (*key == NULL) {
810 free_ReplyKeyPack_Win2k(&key_pack);
811 krb5_set_error_message(context, ENOMEM,
812 N_("malloc: out of memory", ""));
813 return ENOMEM;
814 }
815
816 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
817 free_ReplyKeyPack_Win2k(&key_pack);
818 if (ret) {
819 krb5_set_error_message(context, ret,
820 N_("PKINIT failed copying reply key", ""));
821 free(*key);
822 *key = NULL;
823 }
824
825 return ret;
826 }
827
828 static krb5_error_code
829 get_reply_key(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
830 const krb5_data *content,
831 const krb5_data *req_buffer,
832 krb5_keyblock **key)
833 {
834 ReplyKeyPack key_pack;
835 krb5_error_code ret;
836 size_t size;
837
838 ret = decode_ReplyKeyPack(content->data,
839 content->length,
840 &key_pack,
841 &size);
842 if (ret) {
843 krb5_set_error_message(context, ret,
844 N_("PKINIT decoding reply key failed", ""));
845 free_ReplyKeyPack(&key_pack);
846 return ret;
847 }
848
849 {
850 krb5_crypto crypto;
851
852 /*
853 * XXX Verify kp.replyKey is a allowed enctype in the
854 * configuration file
855 */
856
857 ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
858 if (ret) {
859 free_ReplyKeyPack(&key_pack);
860 return ret;
861 }
862
863 ret = krb5_verify_checksum(context, crypto, 6,
864 req_buffer->data, req_buffer->length,
865 &key_pack.asChecksum);
866 krb5_crypto_destroy(context, crypto);
867 if (ret) {
868 free_ReplyKeyPack(&key_pack);
869 return ret;
870 }
871 }
872
873 *key = malloc (sizeof (**key));
874 if (*key == NULL) {
875 free_ReplyKeyPack(&key_pack);
876 krb5_set_error_message(context, ENOMEM,
877 N_("malloc: out of memory", ""));
878 return ENOMEM;
879 }
880
881 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
882 free_ReplyKeyPack(&key_pack);
883 if (ret) {
884 krb5_set_error_message(context, ret,
885 N_("PKINIT failed copying reply key", ""));
886 free(*key);
887 *key = NULL;
888 }
889
890 return ret;
891 }
892
893
894 static krb5_error_code
895 pk_verify_host(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
896 const char *realm,
897 const krb5_krbhst_info *hi,
898 struct krb5_pk_init_ctx_data *ctx,
899 struct krb5_pk_cert *host)
900 {
901 krb5_error_code ret = 0;
902
903 if (ctx->require_eku) {
904 ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert,
905 oid_id_pkkdcekuoid(), 0);
906 if (ret) {
907 krb5_set_error_message(context, ret,
908 N_("No PK-INIT KDC EKU in kdc certificate", ""));
909 return ret;
910 }
911 }
912 if (ctx->require_krbtgt_otherName) {
913 hx509_octet_string_list list;
914 int i;
915
916 ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx,
917 host->cert,
918 oid_id_pkinit_san(),
919 &list);
920 if (ret) {
921 krb5_set_error_message(context, ret,
922 N_("Failed to find the PK-INIT "
923 "subjectAltName in the KDC "
924 "certificate", ""));
925
926 return ret;
927 }
928
929 for (i = 0; i < list.len; i++) {
930 KRB5PrincipalName r;
931
932 ret = decode_KRB5PrincipalName(list.val[i].data,
933 list.val[i].length,
934 &r,
935 NULL);
936 if (ret) {
937 krb5_set_error_message(context, ret,
938 N_("Failed to decode the PK-INIT "
939 "subjectAltName in the "
940 "KDC certificate", ""));
941
942 break;
943 }
944
945 if (r.principalName.name_string.len != 2 ||
946 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
947 strcmp(r.principalName.name_string.val[1], realm) != 0 ||
948 strcmp(r.realm, realm) != 0)
949 {
950 ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
951 krb5_set_error_message(context, ret,
952 N_("KDC have wrong realm name in "
953 "the certificate", ""));
954 }
955
956 free_KRB5PrincipalName(&r);
957 if (ret)
958 break;
959 }
960 hx509_free_octet_string_list(&list);
961 }
962 if (ret)
963 return ret;
964
965 if (hi) {
966 ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert,
967 ctx->require_hostname_match,
968 HX509_HN_HOSTNAME,
969 hi->hostname,
970 hi->ai->ai_addr, hi->ai->ai_addrlen);
971
972 if (ret)
973 krb5_set_error_message(context, ret,
974 N_("Address mismatch in "
975 "the KDC certificate", ""));
976 }
977 return ret;
978 }
979
980 static krb5_error_code
981 pk_rd_pa_reply_enckey(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
982 int type,
983 const heim_octet_string *indata,
984 const heim_oid *dataType,
985 const char *realm,
986 krb5_pk_init_ctx ctx,
987 krb5_enctype etype,
988 const krb5_krbhst_info *hi,
989 unsigned nonce,
990 const krb5_data *req_buffer,
991 PA_DATA *pa,
992 krb5_keyblock **key)
993 {
994 krb5_error_code ret;
995 struct krb5_pk_cert *host = NULL;
996 krb5_data content;
997 heim_oid contentType = { 0, NULL };
998
999 if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) {
1000 krb5_set_error_message(context, EINVAL,
1001 N_("PKINIT: Invalid content type", ""));
1002 return EINVAL;
1003 }
1004
1005 ret = hx509_cms_unenvelope(ctx->id->hx509ctx,
1006 ctx->id->certs,
1007 HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT,
1008 indata->data,
1009 indata->length,
1010 NULL,
1011 0,
1012 &contentType,
1013 &content);
1014 if (ret) {
1015 pk_copy_error(context, ctx->id->hx509ctx, ret,
1016 "Failed to unenvelope CMS data in PK-INIT reply");
1017 return ret;
1018 }
1019 der_free_oid(&contentType);
1020
1021 #if 0 /* windows LH with interesting CMS packets, leaks memory */
1022 {
1023 size_t ph = 1 + der_length_len (length);
1024 unsigned char *ptr = malloc(length + ph);
1025 size_t l;
1026
1027 memcpy(ptr + ph, p, length);
1028
1029 ret = der_put_length_and_tag (ptr + ph - 1, ph, length,
1030 ASN1_C_UNIV, CONS, UT_Sequence, &l);
1031 if (ret)
1032 return ret;
1033 ptr += ph - l;
1034 length += l;
1035 p = ptr;
1036 }
1037 #endif
1038
1039 /* win2k uses ContentInfo */
1040 if (type == PKINIT_WIN2K) {
1041 heim_oid type;
1042 heim_octet_string out;
1043
1044 ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL);
1045 if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) {
1046 ret = EINVAL; /* XXX */
1047 krb5_set_error_message(context, ret,
1048 N_("PKINIT: Invalid content type", ""));
1049 der_free_oid(&type);
1050 der_free_octet_string(&out);
1051 goto out;
1052 }
1053 der_free_oid(&type);
1054 krb5_data_free(&content);
1055 ret = krb5_data_copy(&content, out.data, out.length);
1056 der_free_octet_string(&out);
1057 if (ret) {
1058 krb5_set_error_message(context, ret,
1059 N_("malloc: out of memory", ""));
1060 goto out;
1061 }
1062 }
1063
1064 ret = _krb5_pk_verify_sign(context,
1065 content.data,
1066 content.length,
1067 ctx->id,
1068 &contentType,
1069 &content,
1070 &host);
1071 if (ret)
1072 goto out;
1073
1074 /* make sure that it is the kdc's certificate */
1075 ret = pk_verify_host(context, realm, hi, ctx, host);
1076 if (ret) {
1077 goto out;
1078 }
1079
1080 #if 0
1081 if (type == PKINIT_WIN2K) {
1082 if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) {
1083 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1084 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1085 goto out;
1086 }
1087 } else {
1088 if (der_heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) {
1089 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1090 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1091 goto out;
1092 }
1093 }
1094 #endif
1095
1096 switch(type) {
1097 case PKINIT_WIN2K:
1098 ret = get_reply_key(context, &content, req_buffer, key);
1099 if (ret != 0 && ctx->require_binding == 0)
1100 ret = get_reply_key_win(context, &content, nonce, key);
1101 break;
1102 case PKINIT_27:
1103 ret = get_reply_key(context, &content, req_buffer, key);
1104 break;
1105 }
1106 if (ret)
1107 goto out;
1108
1109 /* XXX compare given etype with key->etype */
1110
1111 out:
1112 if (host)
1113 _krb5_pk_cert_free(host);
1114 der_free_oid(&contentType);
1115 krb5_data_free(&content);
1116
1117 return ret;
1118 }
1119
1120 static krb5_error_code
1121 pk_rd_pa_reply_dh(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1122 const heim_octet_string *indata,
1123 const heim_oid *dataType,
1124 const char *realm,
1125 krb5_pk_init_ctx ctx,
1126 krb5_enctype etype,
1127 const krb5_krbhst_info *hi,
1128 const DHNonce *c_n,
1129 const DHNonce *k_n,
1130 unsigned nonce,
1131 PA_DATA *pa,
1132 krb5_keyblock **key)
1133 {
1134 unsigned char *p, *dh_gen_key = NULL;
1135 struct krb5_pk_cert *host = NULL;
1136 BIGNUM *kdc_dh_pubkey = NULL;
1137 KDCDHKeyInfo kdc_dh_info;
1138 heim_oid contentType = { 0, NULL };
1139 krb5_data content;
1140 krb5_error_code ret;
1141 int dh_gen_keylen;
1142 size_t size;
1143
1144 krb5_data_zero(&content);
1145 memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1146
1147 if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) {
1148 krb5_set_error_message(context, EINVAL,
1149 N_("PKINIT: Invalid content type", ""));
1150 return EINVAL;
1151 }
1152
1153 ret = _krb5_pk_verify_sign(context,
1154 indata->data,
1155 indata->length,
1156 ctx->id,
1157 &contentType,
1158 &content,
1159 &host);
1160 if (ret)
1161 goto out;
1162
1163 /* make sure that it is the kdc's certificate */
1164 ret = pk_verify_host(context, realm, hi, ctx, host);
1165 if (ret)
1166 goto out;
1167
1168 if (der_heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) {
1169 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1170 krb5_set_error_message(context, ret,
1171 N_("pkinit - dh reply contains wrong oid", ""));
1172 goto out;
1173 }
1174
1175 ret = decode_KDCDHKeyInfo(content.data,
1176 content.length,
1177 &kdc_dh_info,
1178 &size);
1179
1180 if (ret) {
1181 krb5_set_error_message(context, ret,
1182 N_("pkinit - failed to decode "
1183 "KDC DH Key Info", ""));
1184 goto out;
1185 }
1186
1187 if (kdc_dh_info.nonce != nonce) {
1188 ret = KRB5KRB_AP_ERR_MODIFIED;
1189 krb5_set_error_message(context, ret,
1190 N_("PKINIT: DH nonce is wrong", ""));
1191 goto out;
1192 }
1193
1194 if (kdc_dh_info.dhKeyExpiration) {
1195 if (k_n == NULL) {
1196 ret = KRB5KRB_ERR_GENERIC;
1197 krb5_set_error_message(context, ret,
1198 N_("pkinit; got key expiration "
1199 "without server nonce", ""));
1200 goto out;
1201 }
1202 if (c_n == NULL) {
1203 ret = KRB5KRB_ERR_GENERIC;
1204 krb5_set_error_message(context, ret,
1205 N_("pkinit; got DH reuse but no "
1206 "client nonce", ""));
1207 goto out;
1208 }
1209 } else {
1210 if (k_n) {
1211 ret = KRB5KRB_ERR_GENERIC;
1212 krb5_set_error_message(context, ret,
1213 N_("pkinit: got server nonce "
1214 "without key expiration", ""));
1215 goto out;
1216 }
1217 c_n = NULL;
1218 }
1219
1220
1221 p = kdc_dh_info.subjectPublicKey.data;
1222 size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1223
1224 {
1225 DHPublicKey k;
1226 ret = decode_DHPublicKey(p, size, &k, NULL);
1227 if (ret) {
1228 krb5_set_error_message(context, ret,
1229 N_("pkinit: can't decode "
1230 "without key expiration", ""));
1231 goto out;
1232 }
1233
1234 kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1235 free_DHPublicKey(&k);
1236 if (kdc_dh_pubkey == NULL) {
1237 ret = ENOMEM;
1238 goto out;
1239 }
1240 }
1241
1242 dh_gen_keylen = DH_size(ctx->dh);
1243 size = BN_num_bytes(ctx->dh->p);
1244 if (size < dh_gen_keylen)
1245 size = dh_gen_keylen;
1246
1247 dh_gen_key = malloc(size);
1248 if (dh_gen_key == NULL) {
1249 ret = ENOMEM;
1250 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1251 goto out;
1252 }
1253 memset(dh_gen_key, 0, size - dh_gen_keylen);
1254
1255 dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
1256 kdc_dh_pubkey, ctx->dh);
1257 if (dh_gen_keylen == -1) {
1258 ret = KRB5KRB_ERR_GENERIC;
1259 krb5_set_error_message(context, ret,
1260 N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1261 goto out;
1262 }
1263
1264 *key = malloc (sizeof (**key));
1265 if (*key == NULL) {
1266 ret = ENOMEM;
1267 krb5_set_error_message(context, ret,
1268 N_("malloc: out of memory", ""));
1269 goto out;
1270 }
1271
1272 ret = _krb5_pk_octetstring2key(context,
1273 etype,
1274 dh_gen_key, dh_gen_keylen,
1275 c_n, k_n,
1276 *key);
1277 if (ret) {
1278 krb5_set_error_message(context, ret,
1279 N_("PKINIT: can't create key from DH key", ""));
1280 free(*key);
1281 *key = NULL;
1282 goto out;
1283 }
1284
1285 out:
1286 if (kdc_dh_pubkey)
1287 BN_free(kdc_dh_pubkey);
1288 if (dh_gen_key) {
1289 memset(dh_gen_key, 0, DH_size(ctx->dh));
1290 free(dh_gen_key);
1291 }
1292 if (host)
1293 _krb5_pk_cert_free(host);
1294 if (content.data)
1295 krb5_data_free(&content);
1296 der_free_oid(&contentType);
1297 free_KDCDHKeyInfo(&kdc_dh_info);
1298
1299 return ret;
1300 }
1301
1302 krb5_error_code KRB5_LIB_FUNCTION
1303 _krb5_pk_rd_pa_reply(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1304 const char *realm,
1305 void *c,
1306 krb5_enctype etype,
1307 const krb5_krbhst_info *hi,
1308 unsigned nonce,
1309 const krb5_data *req_buffer,
1310 PA_DATA *pa,
1311 krb5_keyblock **key)
1312 {
1313 krb5_pk_init_ctx ctx = c;
1314 krb5_error_code ret;
1315 size_t size;
1316
1317 /* Check for IETF PK-INIT first */
1318 if (ctx->type == PKINIT_27) {
1319 PA_PK_AS_REP rep;
1320 heim_octet_string os, data;
1321 heim_oid oid;
1322
1323 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1324 krb5_set_error_message(context, EINVAL,
1325 N_("PKINIT: wrong padata recv", ""));
1326 return EINVAL;
1327 }
1328
1329 ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1330 pa->padata_value.length,
1331 &rep,
1332 &size);
1333 if (ret) {
1334 krb5_set_error_message(context, ret,
1335 N_("Failed to decode pkinit AS rep", ""));
1336 return ret;
1337 }
1338
1339 switch (rep.element) {
1340 case choice_PA_PK_AS_REP_dhInfo:
1341 os = rep.u.dhInfo.dhSignedData;
1342 break;
1343 case choice_PA_PK_AS_REP_encKeyPack:
1344 os = rep.u.encKeyPack;
1345 break;
1346 default:
1347 free_PA_PK_AS_REP(&rep);
1348 krb5_set_error_message(context, EINVAL,
1349 N_("PKINIT: -27 reply "
1350 "invalid content type", ""));
1351 return EINVAL;
1352 }
1353
1354 ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1355 if (ret) {
1356 free_PA_PK_AS_REP(&rep);
1357 krb5_set_error_message(context, ret,
1358 N_("PKINIT: failed to unwrap CI", ""));
1359 return ret;
1360 }
1361
1362 switch (rep.element) {
1363 case choice_PA_PK_AS_REP_dhInfo:
1364 ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1365 ctx->clientDHNonce,
1366 rep.u.dhInfo.serverDHNonce,
1367 nonce, pa, key);
1368 break;
1369 case choice_PA_PK_AS_REP_encKeyPack:
1370 ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
1371 ctx, etype, hi, nonce, req_buffer, pa, key);
1372 break;
1373 default:
1374 krb5_abortx(context, "pk-init as-rep case not possible to happen");
1375 }
1376 der_free_octet_string(&data);
1377 der_free_oid(&oid);
1378 free_PA_PK_AS_REP(&rep);
1379
1380 } else if (ctx->type == PKINIT_WIN2K) {
1381 PA_PK_AS_REP_Win2k w2krep;
1382
1383 /* Check for Windows encoding of the AS-REP pa data */
1384
1385 #if 0 /* should this be ? */
1386 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1387 krb5_set_error_message(context, EINVAL,
1388 "PKINIT: wrong padata recv");
1389 return EINVAL;
1390 }
1391 #endif
1392
1393 memset(&w2krep, 0, sizeof(w2krep));
1394
1395 ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1396 pa->padata_value.length,
1397 &w2krep,
1398 &size);
1399 if (ret) {
1400 krb5_set_error_message(context, ret,
1401 N_("PKINIT: Failed decoding windows "
1402 "pkinit reply %d", ""), (int)ret);
1403 return ret;
1404 }
1405
1406 krb5_clear_error_message(context);
1407
1408 switch (w2krep.element) {
1409 case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1410 heim_octet_string data;
1411 heim_oid oid;
1412
1413 ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1414 &oid, &data, NULL);
1415 free_PA_PK_AS_REP_Win2k(&w2krep);
1416 if (ret) {
1417 krb5_set_error_message(context, ret,
1418 N_("PKINIT: failed to unwrap CI", ""));
1419 return ret;
1420 }
1421
1422 ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1423 ctx, etype, hi, nonce, req_buffer, pa, key);
1424 der_free_octet_string(&data);
1425 der_free_oid(&oid);
1426
1427 break;
1428 }
1429 default:
1430 free_PA_PK_AS_REP_Win2k(&w2krep);
1431 ret = EINVAL;
1432 krb5_set_error_message(context, ret,
1433 N_("PKINIT: win2k reply invalid "
1434 "content type", ""));
1435 break;
1436 }
1437
1438 } else {
1439 ret = EINVAL;
1440 krb5_set_error_message(context, ret,
1441 N_("PKINIT: unknown reply type", ""));
1442 }
1443
1444 return ret;
1445 }
1446
1447 struct prompter {
1448 krb5_context context;
1449 krb5_prompter_fct prompter;
1450 void *prompter_data;
1451 };
1452
1453 static int
1454 hx_pass_prompter(void *data, const hx509_prompt *prompter)
/* [<][>][^][v][top][bottom][index][help] */
1455 {
1456 krb5_error_code ret;
1457 krb5_prompt prompt;
1458 krb5_data password_data;
1459 struct prompter *p = data;
1460
1461 password_data.data = prompter->reply.data;
1462 password_data.length = prompter->reply.length;
1463
1464 prompt.prompt = prompter->prompt;
1465 prompt.hidden = hx509_prompt_hidden(prompter->type);
1466 prompt.reply = &password_data;
1467
1468 switch (prompter->type) {
1469 case HX509_PROMPT_TYPE_INFO:
1470 prompt.type = KRB5_PROMPT_TYPE_INFO;
1471 break;
1472 case HX509_PROMPT_TYPE_PASSWORD:
1473 case HX509_PROMPT_TYPE_QUESTION:
1474 default:
1475 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1476 break;
1477 }
1478
1479 ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1480 if (ret) {
1481 memset (prompter->reply.data, 0, prompter->reply.length);
1482 return 1;
1483 }
1484 return 0;
1485 }
1486
1487
1488 void KRB5_LIB_FUNCTION
1489 _krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id,
/* [<][>][^][v][top][bottom][index][help] */
1490 int boolean)
1491 {
1492 hx509_verify_set_proxy_certificate(id->verify_ctx, boolean);
1493 }
1494
1495
1496 krb5_error_code KRB5_LIB_FUNCTION
1497 _krb5_pk_load_id(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1498 struct krb5_pk_identity **ret_id,
1499 const char *user_id,
1500 const char *anchor_id,
1501 char * const *chain_list,
1502 char * const *revoke_list,
1503 krb5_prompter_fct prompter,
1504 void *prompter_data,
1505 char *password)
1506 {
1507 struct krb5_pk_identity *id = NULL;
1508 hx509_lock lock = NULL;
1509 struct prompter p;
1510 int ret;
1511
1512 *ret_id = NULL;
1513
1514 if (anchor_id == NULL) {
1515 krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
1516 N_("PKINIT: No anchor given", ""));
1517 return HEIM_PKINIT_NO_VALID_CA;
1518 }
1519
1520 if (user_id == NULL) {
1521 krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
1522 N_("PKINIT: No user certificate given", ""));
1523 return HEIM_PKINIT_NO_PRIVATE_KEY;
1524 }
1525
1526 /* load cert */
1527
1528 id = calloc(1, sizeof(*id));
1529 if (id == NULL) {
1530 krb5_set_error_message(context, ENOMEM,
1531 N_("malloc: out of memory", ""));
1532 return ENOMEM;
1533 }
1534
1535 ret = hx509_context_init(&id->hx509ctx);
1536 if (ret)
1537 goto out;
1538
1539 ret = hx509_lock_init(id->hx509ctx, &lock);
1540 if (password && password[0])
1541 hx509_lock_add_password(lock, password);
1542
1543 if (prompter) {
1544 p.context = context;
1545 p.prompter = prompter;
1546 p.prompter_data = prompter_data;
1547
1548 ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1549 if (ret)
1550 goto out;
1551 }
1552
1553 ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
1554 if (ret) {
1555 pk_copy_error(context, id->hx509ctx, ret,
1556 "Failed to init cert certs");
1557 goto out;
1558 }
1559
1560 ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1561 if (ret) {
1562 pk_copy_error(context, id->hx509ctx, ret,
1563 "Failed to init anchors");
1564 goto out;
1565 }
1566
1567 ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain",
1568 0, NULL, &id->certpool);
1569 if (ret) {
1570 pk_copy_error(context, id->hx509ctx, ret,
1571 "Failed to init chain");
1572 goto out;
1573 }
1574
1575 while (chain_list && *chain_list) {
1576 ret = hx509_certs_append(id->hx509ctx, id->certpool,
1577 NULL, *chain_list);
1578 if (ret) {
1579 pk_copy_error(context, id->hx509ctx, ret,
1580 "Failed to laod chain %s",
1581 *chain_list);
1582 goto out;
1583 }
1584 chain_list++;
1585 }
1586
1587 if (revoke_list) {
1588 ret = hx509_revoke_init(id->hx509ctx, &id->revokectx);
1589 if (ret) {
1590 pk_copy_error(context, id->hx509ctx, ret,
1591 "Failed init revoke list");
1592 goto out;
1593 }
1594
1595 while (*revoke_list) {
1596 ret = hx509_revoke_add_crl(id->hx509ctx,
1597 id->revokectx,
1598 *revoke_list);
1599 if (ret) {
1600 pk_copy_error(context, id->hx509ctx, ret,
1601 "Failed load revoke list");
1602 goto out;
1603 }
1604 revoke_list++;
1605 }
1606 } else
1607 hx509_context_set_missing_revoke(id->hx509ctx, 1);
1608
1609 ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx);
1610 if (ret) {
1611 pk_copy_error(context, id->hx509ctx, ret,
1612 "Failed init verify context");
1613 goto out;
1614 }
1615
1616 hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1617 hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1618
1619 out:
1620 if (ret) {
1621 hx509_verify_destroy_ctx(id->verify_ctx);
1622 hx509_certs_free(&id->certs);
1623 hx509_certs_free(&id->anchors);
1624 hx509_certs_free(&id->certpool);
1625 hx509_revoke_free(&id->revokectx);
1626 hx509_context_free(&id->hx509ctx);
1627 free(id);
1628 } else
1629 *ret_id = id;
1630
1631 hx509_lock_free(lock);
1632
1633 return ret;
1634 }
1635
1636 static krb5_error_code
1637 select_dh_group(krb5_context context, DH *dh, unsigned long bits,
/* [<][>][^][v][top][bottom][index][help] */
1638 struct krb5_dh_moduli **moduli)
1639 {
1640 const struct krb5_dh_moduli *m;
1641
1642 if (bits == 0) {
1643 m = moduli[1]; /* XXX */
1644 if (m == NULL)
1645 m = moduli[0]; /* XXX */
1646 } else {
1647 int i;
1648 for (i = 0; moduli[i] != NULL; i++) {
1649 if (bits < moduli[i]->bits)
1650 break;
1651 }
1652 if (moduli[i] == NULL) {
1653 krb5_set_error_message(context, EINVAL,
1654 N_("Did not find a DH group parameter "
1655 "matching requirement of %lu bits", ""),
1656 bits);
1657 return EINVAL;
1658 }
1659 m = moduli[i];
1660 }
1661
1662 dh->p = integer_to_BN(context, "p", &m->p);
1663 if (dh->p == NULL)
1664 return ENOMEM;
1665 dh->g = integer_to_BN(context, "g", &m->g);
1666 if (dh->g == NULL)
1667 return ENOMEM;
1668 dh->q = integer_to_BN(context, "q", &m->q);
1669 if (dh->q == NULL)
1670 return ENOMEM;
1671
1672 return 0;
1673 }
1674
1675 /*
1676 *
1677 */
1678
1679 static void
1680 pk_copy_error(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1681 hx509_context hx509ctx,
1682 int hxret,
1683 const char *fmt,
1684 ...)
1685 {
1686 va_list va;
1687 char *s, *f;
1688
1689 va_start(va, fmt);
1690 vasprintf(&f, fmt, va);
1691 va_end(va);
1692 if (f == NULL) {
1693 krb5_clear_error_message(context);
1694 return;
1695 }
1696
1697 s = hx509_get_error_string(hx509ctx, hxret);
1698 if (s == NULL) {
1699 krb5_clear_error_message(context);
1700 free(f);
1701 return;
1702 }
1703 krb5_set_error_message(context, hxret, "%s: %s", f, s);
1704 free(s);
1705 free(f);
1706 }
1707
1708 static int
1709 parse_integer(krb5_context context, char **p, const char *file, int lineno,
/* [<][>][^][v][top][bottom][index][help] */
1710 const char *name, heim_integer *integer)
1711 {
1712 int ret;
1713 char *p1;
1714 p1 = strsep(p, " \t");
1715 if (p1 == NULL) {
1716 krb5_set_error_message(context, EINVAL,
1717 N_("moduli file %s missing %s on line %d", ""),
1718 file, name, lineno);
1719 return EINVAL;
1720 }
1721 ret = der_parse_hex_heim_integer(p1, integer);
1722 if (ret) {
1723 krb5_set_error_message(context, ret,
1724 N_("moduli file %s failed parsing %s "
1725 "on line %d", ""),
1726 file, name, lineno);
1727 return ret;
1728 }
1729
1730 return 0;
1731 }
1732
1733 krb5_error_code
1734 _krb5_parse_moduli_line(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1735 const char *file,
1736 int lineno,
1737 char *p,
1738 struct krb5_dh_moduli **m)
1739 {
1740 struct krb5_dh_moduli *m1;
1741 char *p1;
1742 int ret;
1743
1744 *m = NULL;
1745
1746 m1 = calloc(1, sizeof(*m1));
1747 if (m1 == NULL) {
1748 krb5_set_error_message(context, ENOMEM,
1749 N_("malloc: out of memory", ""));
1750 return ENOMEM;
1751 }
1752
1753 while (isspace((unsigned char)*p))
1754 p++;
1755 if (*p == '#')
1756 return 0;
1757 ret = EINVAL;
1758
1759 p1 = strsep(&p, " \t");
1760 if (p1 == NULL) {
1761 krb5_set_error_message(context, ret,
1762 N_("moduli file %s missing name on line %d", ""),
1763 file, lineno);
1764 goto out;
1765 }
1766 m1->name = strdup(p1);
1767 if (p1 == NULL) {
1768 ret = ENOMEM;
1769 krb5_set_error_message(context, ret, N_("malloc: out of memeory", ""));
1770 goto out;
1771 }
1772
1773 p1 = strsep(&p, " \t");
1774 if (p1 == NULL) {
1775 krb5_set_error_message(context, ret,
1776 N_("moduli file %s missing bits on line %d", ""),
1777 file, lineno);
1778 goto out;
1779 }
1780
1781 m1->bits = atoi(p1);
1782 if (m1->bits == 0) {
1783 krb5_set_error_message(context, ret,
1784 N_("moduli file %s have un-parsable "
1785 "bits on line %d", ""), file, lineno);
1786 goto out;
1787 }
1788
1789 ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
1790 if (ret)
1791 goto out;
1792 ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
1793 if (ret)
1794 goto out;
1795 ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
1796 if (ret)
1797 goto out;
1798
1799 *m = m1;
1800
1801 return 0;
1802 out:
1803 free(m1->name);
1804 der_free_heim_integer(&m1->p);
1805 der_free_heim_integer(&m1->g);
1806 der_free_heim_integer(&m1->q);
1807 free(m1);
1808 return ret;
1809 }
1810
1811 void
1812 _krb5_free_moduli(struct krb5_dh_moduli **moduli)
/* [<][>][^][v][top][bottom][index][help] */
1813 {
1814 int i;
1815 for (i = 0; moduli[i] != NULL; i++) {
1816 free(moduli[i]->name);
1817 der_free_heim_integer(&moduli[i]->p);
1818 der_free_heim_integer(&moduli[i]->g);
1819 der_free_heim_integer(&moduli[i]->q);
1820 free(moduli[i]);
1821 }
1822 free(moduli);
1823 }
1824
1825 static const char *default_moduli_RFC2412_MODP_group2 =
1826 /* name */
1827 "RFC2412-MODP-group2 "
1828 /* bits */
1829 "1024 "
1830 /* p */
1831 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1832 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1833 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1834 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1835 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
1836 "FFFFFFFF" "FFFFFFFF "
1837 /* g */
1838 "02 "
1839 /* q */
1840 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1841 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1842 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1843 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1844 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
1845 "FFFFFFFF" "FFFFFFFF";
1846
1847 static const char *default_moduli_rfc3526_MODP_group14 =
1848 /* name */
1849 "rfc3526-MODP-group14 "
1850 /* bits */
1851 "1760 "
1852 /* p */
1853 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1854 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1855 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1856 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1857 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
1858 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
1859 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
1860 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
1861 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
1862 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
1863 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
1864 /* g */
1865 "02 "
1866 /* q */
1867 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1868 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1869 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1870 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1871 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
1872 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
1873 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
1874 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
1875 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
1876 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
1877 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
1878
1879 krb5_error_code
1880 _krb5_parse_moduli(krb5_context context, const char *file,
/* [<][>][^][v][top][bottom][index][help] */
1881 struct krb5_dh_moduli ***moduli)
1882 {
1883 /* name bits P G Q */
1884 krb5_error_code ret;
1885 struct krb5_dh_moduli **m = NULL, **m2;
1886 char buf[4096];
1887 FILE *f;
1888 int lineno = 0, n = 0;
1889
1890 *moduli = NULL;
1891
1892 m = calloc(1, sizeof(m[0]) * 3);
1893 if (m == NULL) {
1894 krb5_set_error_message(context, ENOMEM,
1895 N_("malloc: out of memory", ""));
1896 return ENOMEM;
1897 }
1898
1899 strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
1900 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]);
1901 if (ret) {
1902 _krb5_free_moduli(m);
1903 return ret;
1904 }
1905 n++;
1906
1907 strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
1908 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]);
1909 if (ret) {
1910 _krb5_free_moduli(m);
1911 return ret;
1912 }
1913 n++;
1914
1915
1916 if (file == NULL)
1917 file = MODULI_FILE;
1918
1919 f = fopen(file, "r");
1920 if (f == NULL) {
1921 *moduli = m;
1922 return 0;
1923 }
1924 rk_cloexec_file(f);
1925
1926 while(fgets(buf, sizeof(buf), f) != NULL) {
1927 struct krb5_dh_moduli *element;
1928
1929 buf[strcspn(buf, "\n")] = '\0';
1930 lineno++;
1931
1932 m2 = realloc(m, (n + 2) * sizeof(m[0]));
1933 if (m2 == NULL) {
1934 _krb5_free_moduli(m);
1935 krb5_set_error_message(context, ENOMEM,
1936 N_("malloc: out of memory", ""));
1937 return ENOMEM;
1938 }
1939 m = m2;
1940
1941 m[n] = NULL;
1942
1943 ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element);
1944 if (ret) {
1945 _krb5_free_moduli(m);
1946 return ret;
1947 }
1948 if (element == NULL)
1949 continue;
1950
1951 m[n] = element;
1952 m[n + 1] = NULL;
1953 n++;
1954 }
1955 *moduli = m;
1956 return 0;
1957 }
1958
1959 krb5_error_code
1960 _krb5_dh_group_ok(krb5_context context, unsigned long bits,
/* [<][>][^][v][top][bottom][index][help] */
1961 heim_integer *p, heim_integer *g, heim_integer *q,
1962 struct krb5_dh_moduli **moduli,
1963 char **name)
1964 {
1965 int i;
1966
1967 if (name)
1968 *name = NULL;
1969
1970 for (i = 0; moduli[i] != NULL; i++) {
1971 if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
1972 der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
1973 (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
1974 {
1975 if (bits && bits > moduli[i]->bits) {
1976 krb5_set_error_message(context,
1977 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
1978 N_("PKINIT: DH group parameter %s "
1979 "no accepted, not enough bits "
1980 "generated", ""),
1981 moduli[i]->name);
1982 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1983 }
1984 if (name)
1985 *name = strdup(moduli[i]->name);
1986 return 0;
1987 }
1988 }
1989 krb5_set_error_message(context,
1990 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
1991 N_("PKINIT: DH group parameter no ok", ""));
1992 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1993 }
1994 #endif /* PKINIT */
1995
1996 void KRB5_LIB_FUNCTION
1997 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
/* [<][>][^][v][top][bottom][index][help] */
1998 {
1999 #ifdef PKINIT
2000 krb5_pk_init_ctx ctx;
2001
2002 if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
2003 return;
2004 ctx = opt->opt_private->pk_init_ctx;
2005 if (ctx->dh)
2006 DH_free(ctx->dh);
2007 ctx->dh = NULL;
2008 if (ctx->id) {
2009 hx509_verify_destroy_ctx(ctx->id->verify_ctx);
2010 hx509_certs_free(&ctx->id->certs);
2011 hx509_certs_free(&ctx->id->anchors);
2012 hx509_certs_free(&ctx->id->certpool);
2013 hx509_context_free(&ctx->id->hx509ctx);
2014
2015 if (ctx->clientDHNonce) {
2016 krb5_free_data(NULL, ctx->clientDHNonce);
2017 ctx->clientDHNonce = NULL;
2018 }
2019 if (ctx->m)
2020 _krb5_free_moduli(ctx->m);
2021 free(ctx->id);
2022 ctx->id = NULL;
2023 }
2024 free(opt->opt_private->pk_init_ctx);
2025 opt->opt_private->pk_init_ctx = NULL;
2026 #endif
2027 }
2028
2029 krb5_error_code KRB5_LIB_FUNCTION
2030 krb5_get_init_creds_opt_set_pkinit(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
2031 krb5_get_init_creds_opt *opt,
2032 krb5_principal principal,
2033 const char *user_id,
2034 const char *x509_anchors,
2035 char * const * pool,
2036 char * const * pki_revoke,
2037 int flags,
2038 krb5_prompter_fct prompter,
2039 void *prompter_data,
2040 char *password)
2041 {
2042 #ifdef PKINIT
2043 krb5_error_code ret;
2044 char *anchors = NULL;
2045
2046 if (opt->opt_private == NULL) {
2047 krb5_set_error_message(context, EINVAL,
2048 N_("PKINIT: on non extendable opt", ""));
2049 return EINVAL;
2050 }
2051
2052 opt->opt_private->pk_init_ctx =
2053 calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
2054 if (opt->opt_private->pk_init_ctx == NULL) {
2055 krb5_set_error_message(context, ENOMEM,
2056 N_("malloc: out of memory", ""));
2057 return ENOMEM;
2058 }
2059 opt->opt_private->pk_init_ctx->dh = NULL;
2060 opt->opt_private->pk_init_ctx->id = NULL;
2061 opt->opt_private->pk_init_ctx->clientDHNonce = NULL;
2062 opt->opt_private->pk_init_ctx->require_binding = 0;
2063 opt->opt_private->pk_init_ctx->require_eku = 1;
2064 opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
2065 opt->opt_private->pk_init_ctx->peer = NULL;
2066
2067 /* XXX implement krb5_appdefault_strings */
2068 if (pool == NULL)
2069 pool = krb5_config_get_strings(context, NULL,
2070 "appdefaults",
2071 "pkinit_pool",
2072 NULL);
2073
2074 if (pki_revoke == NULL)
2075 pki_revoke = krb5_config_get_strings(context, NULL,
2076 "appdefaults",
2077 "pkinit_revoke",
2078 NULL);
2079
2080 if (x509_anchors == NULL) {
2081 krb5_appdefault_string(context, "kinit",
2082 krb5_principal_get_realm(context, principal),
2083 "pkinit_anchors", NULL, &anchors);
2084 x509_anchors = anchors;
2085 }
2086
2087 ret = _krb5_pk_load_id(context,
2088 &opt->opt_private->pk_init_ctx->id,
2089 user_id,
2090 x509_anchors,
2091 pool,
2092 pki_revoke,
2093 prompter,
2094 prompter_data,
2095 password);
2096 if (ret) {
2097 free(opt->opt_private->pk_init_ctx);
2098 opt->opt_private->pk_init_ctx = NULL;
2099 return ret;
2100 }
2101
2102 if ((flags & 2) == 0) {
2103 const char *moduli_file;
2104 unsigned long dh_min_bits;
2105
2106 moduli_file = krb5_config_get_string(context, NULL,
2107 "libdefaults",
2108 "moduli",
2109 NULL);
2110
2111 dh_min_bits =
2112 krb5_config_get_int_default(context, NULL, 0,
2113 "libdefaults",
2114 "pkinit_dh_min_bits",
2115 NULL);
2116
2117 ret = _krb5_parse_moduli(context, moduli_file,
2118 &opt->opt_private->pk_init_ctx->m);
2119 if (ret) {
2120 _krb5_get_init_creds_opt_free_pkinit(opt);
2121 return ret;
2122 }
2123
2124 opt->opt_private->pk_init_ctx->dh = DH_new();
2125 if (opt->opt_private->pk_init_ctx->dh == NULL) {
2126 _krb5_get_init_creds_opt_free_pkinit(opt);
2127 krb5_set_error_message(context, ENOMEM,
2128 N_("malloc: out of memory", ""));
2129 return ENOMEM;
2130 }
2131
2132 ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh,
2133 dh_min_bits,
2134 opt->opt_private->pk_init_ctx->m);
2135 if (ret) {
2136 _krb5_get_init_creds_opt_free_pkinit(opt);
2137 return ret;
2138 }
2139
2140 if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) {
2141 _krb5_get_init_creds_opt_free_pkinit(opt);
2142 krb5_set_error_message(context, ENOMEM,
2143 N_("pkinit: failed to generate DH key", ""));
2144 return ENOMEM;
2145 }
2146 }
2147
2148 return 0;
2149 #else
2150 krb5_set_error_message(context, EINVAL,
2151 N_("no support for PKINIT compiled in", ""));
2152 return EINVAL;
2153 #endif
2154 }