source: trunk/server/source4/heimdal/lib/krb5/pkinit.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

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