source: branches/samba-3.5.x/source4/heimdal/lib/krb5/pkinit.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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