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