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