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