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