xref: /illumos-gate/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_clnt.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
1159d09a2SMark Phalan /*
2159d09a2SMark Phalan  * COPYRIGHT (C) 2006,2007
3159d09a2SMark Phalan  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
4159d09a2SMark Phalan  * ALL RIGHTS RESERVED
5159d09a2SMark Phalan  *
6159d09a2SMark Phalan  * Permission is granted to use, copy, create derivative works
7159d09a2SMark Phalan  * and redistribute this software and such derivative works
8159d09a2SMark Phalan  * for any purpose, so long as the name of The University of
9159d09a2SMark Phalan  * Michigan is not used in any advertising or publicity
10159d09a2SMark Phalan  * pertaining to the use of distribution of this software
11159d09a2SMark Phalan  * without specific, written prior authorization.  If the
12159d09a2SMark Phalan  * above copyright notice or any other identification of the
13159d09a2SMark Phalan  * University of Michigan is included in any copy of any
14159d09a2SMark Phalan  * portion of this software, then the disclaimer below must
15159d09a2SMark Phalan  * also be included.
16159d09a2SMark Phalan  *
17159d09a2SMark Phalan  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18159d09a2SMark Phalan  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19159d09a2SMark Phalan  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20159d09a2SMark Phalan  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21159d09a2SMark Phalan  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22159d09a2SMark Phalan  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23159d09a2SMark Phalan  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24159d09a2SMark Phalan  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25159d09a2SMark Phalan  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26159d09a2SMark Phalan  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27159d09a2SMark Phalan  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
28159d09a2SMark Phalan  * SUCH DAMAGES.
29159d09a2SMark Phalan  */
30159d09a2SMark Phalan 
31*488060a6SWill Fiveash /*
32*488060a6SWill Fiveash  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
33*488060a6SWill Fiveash  */
34*488060a6SWill Fiveash 
35159d09a2SMark Phalan #include <stdio.h>
36159d09a2SMark Phalan #include <stdlib.h>
37159d09a2SMark Phalan #include <errno.h>
38159d09a2SMark Phalan #include <unistd.h>
39159d09a2SMark Phalan #include <string.h>
40159d09a2SMark Phalan #include <ctype.h>
41159d09a2SMark Phalan #include <assert.h>
42159d09a2SMark Phalan #include <dlfcn.h>
43159d09a2SMark Phalan #include <sys/stat.h>
44159d09a2SMark Phalan 
45159d09a2SMark Phalan #include "pkinit.h"
46159d09a2SMark Phalan 
47159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
48159d09a2SMark Phalan /*
49159d09a2SMark Phalan  * It is anticipated that all the special checks currently
50159d09a2SMark Phalan  * required when talking to a Longhorn server will go away
51159d09a2SMark Phalan  * by the time it is officially released and all references
52159d09a2SMark Phalan  * to the longhorn global can be removed and any code
53159d09a2SMark Phalan  * #ifdef'd with LONGHORN_BETA_COMPAT can be removed.
54159d09a2SMark Phalan  *
55159d09a2SMark Phalan  * Current testing (20070620) is against a patched Beta 3
56159d09a2SMark Phalan  * version of Longhorn.  Most, if not all, problems should
57159d09a2SMark Phalan  * be fixed in SP1 of Longhorn.
58159d09a2SMark Phalan  */
59159d09a2SMark Phalan int longhorn = 0;	/* Talking to a Longhorn server? */
60159d09a2SMark Phalan #endif
61159d09a2SMark Phalan 
62159d09a2SMark Phalan krb5_error_code pkinit_client_process
63159d09a2SMark Phalan 	(krb5_context context, void *plugin_context, void *request_context,
64159d09a2SMark Phalan 		krb5_get_init_creds_opt *gic_opt,
65159d09a2SMark Phalan 		preauth_get_client_data_proc get_data_proc,
66159d09a2SMark Phalan 		struct _krb5_preauth_client_rock *rock,
67159d09a2SMark Phalan 		krb5_kdc_req * request, krb5_data *encoded_request_body,
68159d09a2SMark Phalan 		krb5_data *encoded_previous_request, krb5_pa_data *in_padata,
69159d09a2SMark Phalan 		krb5_prompter_fct prompter, void *prompter_data,
70159d09a2SMark Phalan 		preauth_get_as_key_proc gak_fct, void *gak_data,
71159d09a2SMark Phalan 		krb5_data * salt, krb5_data * s2kparams,
72159d09a2SMark Phalan 		krb5_keyblock * as_key, krb5_pa_data *** out_padata);
73159d09a2SMark Phalan 
74159d09a2SMark Phalan krb5_error_code pkinit_client_tryagain
75159d09a2SMark Phalan 	(krb5_context context, void *plugin_context, void *request_context,
76159d09a2SMark Phalan 		krb5_get_init_creds_opt *gic_opt,
77159d09a2SMark Phalan 		preauth_get_client_data_proc get_data_proc,
78159d09a2SMark Phalan 		struct _krb5_preauth_client_rock *rock,
79159d09a2SMark Phalan 		krb5_kdc_req * request, krb5_data *encoded_request_body,
80159d09a2SMark Phalan 		krb5_data *encoded_previous_request,
81159d09a2SMark Phalan 		krb5_pa_data *in_padata, krb5_error *err_reply,
82159d09a2SMark Phalan 		krb5_prompter_fct prompter, void *prompter_data,
83159d09a2SMark Phalan 		preauth_get_as_key_proc gak_fct, void *gak_data,
84159d09a2SMark Phalan 		krb5_data * salt, krb5_data * s2kparams,
85159d09a2SMark Phalan 		krb5_keyblock * as_key, krb5_pa_data *** out_padata);
86159d09a2SMark Phalan 
87159d09a2SMark Phalan void pkinit_client_req_init
88159d09a2SMark Phalan 	(krb5_context contex, void *plugin_context, void **request_context);
89159d09a2SMark Phalan 
90159d09a2SMark Phalan void pkinit_client_req_fini
91159d09a2SMark Phalan 	(krb5_context context, void *plugin_context, void *request_context);
92159d09a2SMark Phalan 
93159d09a2SMark Phalan krb5_error_code pa_pkinit_gen_req
94159d09a2SMark Phalan 	(krb5_context context, pkinit_context plgctx,
95159d09a2SMark Phalan 		pkinit_req_context reqctx, krb5_kdc_req * request,
96159d09a2SMark Phalan 		krb5_pa_data * in_padata, krb5_pa_data *** out_padata,
97159d09a2SMark Phalan 		krb5_prompter_fct prompter, void *prompter_data,
98159d09a2SMark Phalan 		krb5_get_init_creds_opt *gic_opt);
99159d09a2SMark Phalan 
100159d09a2SMark Phalan krb5_error_code pkinit_as_req_create
101159d09a2SMark Phalan 	(krb5_context context, pkinit_context plgctx,
102159d09a2SMark Phalan 		pkinit_req_context reqctx, krb5_timestamp ctsec,
103159d09a2SMark Phalan 		krb5_int32 cusec, krb5_ui_4 nonce,
104159d09a2SMark Phalan 		const krb5_checksum * cksum, krb5_principal server,
105159d09a2SMark Phalan 		krb5_data ** as_req);
106159d09a2SMark Phalan 
107159d09a2SMark Phalan krb5_error_code pkinit_as_rep_parse
108159d09a2SMark Phalan 	(krb5_context context, pkinit_context plgctx,
109159d09a2SMark Phalan 		pkinit_req_context reqctx, krb5_preauthtype pa_type,
110159d09a2SMark Phalan 		krb5_kdc_req * request, const krb5_data * as_rep,
111159d09a2SMark Phalan 		krb5_keyblock * key_block, krb5_enctype etype, krb5_data *);
112159d09a2SMark Phalan 
113159d09a2SMark Phalan krb5_error_code pa_pkinit_parse_rep
114159d09a2SMark Phalan 	(krb5_context context, pkinit_context plgctx,
115159d09a2SMark Phalan 		pkinit_req_context reqcxt, krb5_kdc_req * request,
116159d09a2SMark Phalan 		krb5_pa_data * in_padata, krb5_enctype etype,
117159d09a2SMark Phalan 		krb5_keyblock * as_key, krb5_data *);
118159d09a2SMark Phalan 
119159d09a2SMark Phalan static int pkinit_client_plugin_init(krb5_context context, void **blob);
120159d09a2SMark Phalan static void pkinit_client_plugin_fini(krb5_context context, void *blob);
121159d09a2SMark Phalan 
122159d09a2SMark Phalan /* ARGSUSED */
123159d09a2SMark Phalan krb5_error_code
pa_pkinit_gen_req(krb5_context context,pkinit_context plgctx,pkinit_req_context reqctx,krb5_kdc_req * request,krb5_pa_data * in_padata,krb5_pa_data *** out_padata,krb5_prompter_fct prompter,void * prompter_data,krb5_get_init_creds_opt * gic_opt)124159d09a2SMark Phalan pa_pkinit_gen_req(krb5_context context,
125159d09a2SMark Phalan 		  pkinit_context plgctx,
126159d09a2SMark Phalan 		  pkinit_req_context reqctx,
127159d09a2SMark Phalan 		  krb5_kdc_req * request,
128159d09a2SMark Phalan 		  krb5_pa_data * in_padata,
129159d09a2SMark Phalan 		  krb5_pa_data *** out_padata,
130159d09a2SMark Phalan 		  krb5_prompter_fct prompter,
131159d09a2SMark Phalan 		  void *prompter_data,
132159d09a2SMark Phalan 		  krb5_get_init_creds_opt *gic_opt)
133159d09a2SMark Phalan {
134159d09a2SMark Phalan 
135159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
136159d09a2SMark Phalan     krb5_data *out_data = NULL;
137159d09a2SMark Phalan     krb5_timestamp ctsec = 0;
138159d09a2SMark Phalan     krb5_int32 cusec = 0;
139159d09a2SMark Phalan     krb5_ui_4 nonce = 0;
140159d09a2SMark Phalan     krb5_checksum cksum;
141159d09a2SMark Phalan     krb5_data *der_req = NULL;
142159d09a2SMark Phalan     krb5_pa_data **return_pa_data = NULL;
143159d09a2SMark Phalan 
144159d09a2SMark Phalan     cksum.contents = NULL;
145159d09a2SMark Phalan     reqctx->pa_type = in_padata->pa_type;
146159d09a2SMark Phalan 
147159d09a2SMark Phalan     pkiDebug("kdc_options = 0x%x  till = %d\n",
148159d09a2SMark Phalan 	     request->kdc_options, request->till);
149159d09a2SMark Phalan     /* If we don't have a client, we're done */
150159d09a2SMark Phalan     if (request->client == NULL) {
151159d09a2SMark Phalan 	pkiDebug("No request->client; aborting PKINIT\n");
152159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
153159d09a2SMark Phalan     }
154159d09a2SMark Phalan 
155159d09a2SMark Phalan     retval = pkinit_get_kdc_cert(context, plgctx->cryptoctx, reqctx->cryptoctx,
156159d09a2SMark Phalan 				 reqctx->idctx, request->server);
157159d09a2SMark Phalan     if (retval) {
158159d09a2SMark Phalan 	pkiDebug("pkinit_get_kdc_cert returned %d\n", retval);
159159d09a2SMark Phalan 	goto cleanup;
160159d09a2SMark Phalan     }
161159d09a2SMark Phalan 
162159d09a2SMark Phalan     /* checksum of the encoded KDC-REQ-BODY */
163159d09a2SMark Phalan     retval = k5int_encode_krb5_kdc_req_body(request, &der_req);
164159d09a2SMark Phalan     if (retval) {
165159d09a2SMark Phalan 	pkiDebug("encode_krb5_kdc_req_body returned %d\n", (int) retval);
166159d09a2SMark Phalan 	goto cleanup;
167159d09a2SMark Phalan     }
168159d09a2SMark Phalan 
169159d09a2SMark Phalan     retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0,
170159d09a2SMark Phalan 				  der_req, &cksum);
171159d09a2SMark Phalan     if (retval)
172159d09a2SMark Phalan 	goto cleanup;
173159d09a2SMark Phalan #ifdef DEBUG_CKSUM
174159d09a2SMark Phalan     pkiDebug("calculating checksum on buf size (%d)\n", der_req->length);
175159d09a2SMark Phalan     print_buffer(der_req->data, der_req->length);
176159d09a2SMark Phalan #endif
177159d09a2SMark Phalan 
178159d09a2SMark Phalan     retval = krb5_us_timeofday(context, &ctsec, &cusec);
179159d09a2SMark Phalan     if (retval)
180159d09a2SMark Phalan 	goto cleanup;
181159d09a2SMark Phalan 
182159d09a2SMark Phalan     /* XXX PKINIT RFC says that nonce in PKAuthenticator doesn't have be the
183159d09a2SMark Phalan      * same as in the AS_REQ. However, if we pick a different nonce, then we
184159d09a2SMark Phalan      * need to remember that info when AS_REP is returned. I'm choosing to
185159d09a2SMark Phalan      * reuse the AS_REQ nonce.
186159d09a2SMark Phalan      */
187159d09a2SMark Phalan     nonce = request->nonce;
188159d09a2SMark Phalan 
189159d09a2SMark Phalan     retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec,
190159d09a2SMark Phalan 				  nonce, &cksum, request->server, &out_data);
191159d09a2SMark Phalan     if (retval || !out_data->length) {
192159d09a2SMark Phalan 	pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n",
193159d09a2SMark Phalan 		 (int) retval);
194159d09a2SMark Phalan 	goto cleanup;
195159d09a2SMark Phalan     }
196159d09a2SMark Phalan     retval = ENOMEM;
197159d09a2SMark Phalan     /*
198159d09a2SMark Phalan      * The most we'll return is two pa_data, normally just one.
199159d09a2SMark Phalan      * We need to make room for the NULL terminator.
200159d09a2SMark Phalan      */
201159d09a2SMark Phalan     return_pa_data = (krb5_pa_data **) malloc(3 * sizeof(krb5_pa_data *));
202159d09a2SMark Phalan     if (return_pa_data == NULL)
203159d09a2SMark Phalan 	goto cleanup;
204159d09a2SMark Phalan 
205159d09a2SMark Phalan     return_pa_data[1] = NULL;	/* in case of an early trip to cleanup */
206159d09a2SMark Phalan     return_pa_data[2] = NULL;	/* Terminate the list */
207159d09a2SMark Phalan 
208159d09a2SMark Phalan     return_pa_data[0] = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
209159d09a2SMark Phalan     if (return_pa_data[0] == NULL)
210159d09a2SMark Phalan 	goto cleanup;
211159d09a2SMark Phalan 
212159d09a2SMark Phalan     return_pa_data[1] = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
213159d09a2SMark Phalan     if (return_pa_data[1] == NULL)
214159d09a2SMark Phalan 	goto cleanup;
215159d09a2SMark Phalan 
216159d09a2SMark Phalan     return_pa_data[0]->magic = KV5M_PA_DATA;
217159d09a2SMark Phalan 
218159d09a2SMark Phalan     if (in_padata->pa_type == KRB5_PADATA_PK_AS_REQ_OLD)
219159d09a2SMark Phalan 	return_pa_data[0]->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
220159d09a2SMark Phalan     else
221159d09a2SMark Phalan 	return_pa_data[0]->pa_type = in_padata->pa_type;
222159d09a2SMark Phalan     return_pa_data[0]->length = out_data->length;
223159d09a2SMark Phalan     return_pa_data[0]->contents = (krb5_octet *) out_data->data;
224159d09a2SMark Phalan 
225159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
226159d09a2SMark Phalan     /*
227159d09a2SMark Phalan      * LH Beta 3 requires the extra pa-data, even for RFC requests,
228159d09a2SMark Phalan      * in order to get the Checksum rather than a Nonce in the reply.
229159d09a2SMark Phalan      * This can be removed when LH SP1 is released.
230159d09a2SMark Phalan      */
231159d09a2SMark Phalan     if ((return_pa_data[0]->pa_type == KRB5_PADATA_PK_AS_REP_OLD
232159d09a2SMark Phalan 	&& reqctx->opts->win2k_require_cksum) || (longhorn == 1)) {
233159d09a2SMark Phalan #else
234159d09a2SMark Phalan     if ((return_pa_data[0]->pa_type == KRB5_PADATA_PK_AS_REP_OLD
235159d09a2SMark Phalan 	&& reqctx->opts->win2k_require_cksum)) {
236159d09a2SMark Phalan #endif
237159d09a2SMark Phalan 	return_pa_data[1]->pa_type = 132;
238159d09a2SMark Phalan 	return_pa_data[1]->length = 0;
239159d09a2SMark Phalan 	return_pa_data[1]->contents = NULL;
240159d09a2SMark Phalan     } else {
241159d09a2SMark Phalan 	free(return_pa_data[1]);
242159d09a2SMark Phalan 	return_pa_data[1] = NULL;   /* Move the list terminator */
243159d09a2SMark Phalan     }
244159d09a2SMark Phalan     *out_padata = return_pa_data;
245159d09a2SMark Phalan     retval = 0;
246159d09a2SMark Phalan 
247159d09a2SMark Phalan   cleanup:
248159d09a2SMark Phalan     if (der_req != NULL)
249159d09a2SMark Phalan 	krb5_free_data(context, der_req);
250159d09a2SMark Phalan 
251159d09a2SMark Phalan     if (out_data != NULL)
252159d09a2SMark Phalan 	free(out_data);
253159d09a2SMark Phalan 
254159d09a2SMark Phalan     if (retval) {
255159d09a2SMark Phalan 	if (return_pa_data) {
256159d09a2SMark Phalan 	    if (return_pa_data[0] != NULL)
257159d09a2SMark Phalan 		free(return_pa_data[0]);
258159d09a2SMark Phalan 	    if (return_pa_data[1] != NULL)
259159d09a2SMark Phalan 		free(return_pa_data[1]);
260159d09a2SMark Phalan 	    free(return_pa_data);
261159d09a2SMark Phalan 	}
262159d09a2SMark Phalan 	if (out_data) {
263159d09a2SMark Phalan 	    free(out_data->data);
264159d09a2SMark Phalan 	    free(out_data);
265159d09a2SMark Phalan 	}
266159d09a2SMark Phalan     }
267159d09a2SMark Phalan     return retval;
268159d09a2SMark Phalan }
269159d09a2SMark Phalan 
270159d09a2SMark Phalan krb5_error_code
271159d09a2SMark Phalan pkinit_as_req_create(krb5_context context,
272159d09a2SMark Phalan 		     pkinit_context plgctx,
273159d09a2SMark Phalan 		     pkinit_req_context reqctx,
274159d09a2SMark Phalan 		     krb5_timestamp ctsec,
275159d09a2SMark Phalan 		     krb5_int32 cusec,
276159d09a2SMark Phalan 		     krb5_ui_4 nonce,
277159d09a2SMark Phalan 		     const krb5_checksum * cksum,
278159d09a2SMark Phalan 		     krb5_principal server,
279159d09a2SMark Phalan 		     krb5_data ** as_req)
280159d09a2SMark Phalan {
281159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
282159d09a2SMark Phalan     krb5_subject_pk_info *info = NULL;
283159d09a2SMark Phalan     krb5_data *coded_auth_pack = NULL;
284159d09a2SMark Phalan     krb5_auth_pack *auth_pack = NULL;
285159d09a2SMark Phalan     krb5_pa_pk_as_req *req = NULL;
286159d09a2SMark Phalan     krb5_auth_pack_draft9 *auth_pack9 = NULL;
287159d09a2SMark Phalan     krb5_pa_pk_as_req_draft9 *req9 = NULL;
288159d09a2SMark Phalan     int protocol = reqctx->opts->dh_or_rsa;
289159d09a2SMark Phalan 
290159d09a2SMark Phalan     pkiDebug("pkinit_as_req_create pa_type = %d\n", reqctx->pa_type);
291159d09a2SMark Phalan 
292159d09a2SMark Phalan     /* Create the authpack */
293159d09a2SMark Phalan     switch((int)reqctx->pa_type) {
294159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
295159d09a2SMark Phalan 	    protocol = RSA_PROTOCOL;
296159d09a2SMark Phalan 	    init_krb5_auth_pack_draft9(&auth_pack9);
297159d09a2SMark Phalan 	    if (auth_pack9 == NULL)
298159d09a2SMark Phalan 		goto cleanup;
299159d09a2SMark Phalan 	    auth_pack9->pkAuthenticator.ctime = ctsec;
300159d09a2SMark Phalan 	    auth_pack9->pkAuthenticator.cusec = cusec;
301159d09a2SMark Phalan 	    auth_pack9->pkAuthenticator.nonce = nonce;
302159d09a2SMark Phalan 	    auth_pack9->pkAuthenticator.kdcName = server;
303159d09a2SMark Phalan 	    auth_pack9->pkAuthenticator.kdcRealm.magic = 0;
304159d09a2SMark Phalan 	    auth_pack9->pkAuthenticator.kdcRealm.data =
305159d09a2SMark Phalan 					(unsigned char *)server->realm.data;
306159d09a2SMark Phalan 	    auth_pack9->pkAuthenticator.kdcRealm.length = server->realm.length;
307159d09a2SMark Phalan 	    free(cksum->contents);
308159d09a2SMark Phalan 	    break;
309159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
310159d09a2SMark Phalan 	    init_krb5_subject_pk_info(&info);
311159d09a2SMark Phalan 	    if (info == NULL)
312159d09a2SMark Phalan 		goto cleanup;
313159d09a2SMark Phalan 	    init_krb5_auth_pack(&auth_pack);
314159d09a2SMark Phalan 	    if (auth_pack == NULL)
315159d09a2SMark Phalan 		goto cleanup;
316159d09a2SMark Phalan 	    auth_pack->pkAuthenticator.ctime = ctsec;
317159d09a2SMark Phalan 	    auth_pack->pkAuthenticator.cusec = cusec;
318159d09a2SMark Phalan 	    auth_pack->pkAuthenticator.nonce = nonce;
319159d09a2SMark Phalan 	    auth_pack->pkAuthenticator.paChecksum = *cksum;
320159d09a2SMark Phalan 	    auth_pack->clientDHNonce.length = 0;
321159d09a2SMark Phalan 	    auth_pack->clientPublicValue = info;
322159d09a2SMark Phalan 
323159d09a2SMark Phalan 	    /* add List of CMS algorithms */
324159d09a2SMark Phalan 	    retval = create_krb5_supportedCMSTypes(context, plgctx->cryptoctx,
325159d09a2SMark Phalan 			reqctx->cryptoctx, reqctx->idctx,
326159d09a2SMark Phalan 			&auth_pack->supportedCMSTypes);
327159d09a2SMark Phalan 	    if (retval)
328159d09a2SMark Phalan 		goto cleanup;
329159d09a2SMark Phalan 	    break;
330159d09a2SMark Phalan 	default:
331159d09a2SMark Phalan 	    pkiDebug("as_req: unrecognized pa_type = %d\n",
332159d09a2SMark Phalan 		    (int)reqctx->pa_type);
333159d09a2SMark Phalan 	    retval = -1;
334159d09a2SMark Phalan 	    goto cleanup;
335159d09a2SMark Phalan     }
336159d09a2SMark Phalan 
337159d09a2SMark Phalan     switch(protocol) {
338159d09a2SMark Phalan 	case DH_PROTOCOL:
339159d09a2SMark Phalan 	    pkiDebug("as_req: DH key transport algorithm\n");
340159d09a2SMark Phalan 	    retval = pkinit_copy_krb5_octet_data(&info->algorithm.algorithm, &dh_oid);
341159d09a2SMark Phalan 	    if (retval) {
342159d09a2SMark Phalan 		pkiDebug("failed to copy dh_oid\n");
343159d09a2SMark Phalan 		goto cleanup;
344159d09a2SMark Phalan 	    }
345159d09a2SMark Phalan 
346159d09a2SMark Phalan 	    /* create client-side DH keys */
347159d09a2SMark Phalan 	    if ((retval = client_create_dh(context, plgctx->cryptoctx,
348159d09a2SMark Phalan 		    reqctx->cryptoctx, reqctx->idctx, reqctx->opts->dh_size,
349159d09a2SMark Phalan 		    &info->algorithm.parameters.data,
350159d09a2SMark Phalan 		    &info->algorithm.parameters.length,
351159d09a2SMark Phalan 		    &info->subjectPublicKey.data,
352159d09a2SMark Phalan 		    &info->subjectPublicKey.length)) != 0) {
353159d09a2SMark Phalan 		pkiDebug("failed to create dh parameters\n");
354159d09a2SMark Phalan 		goto cleanup;
355159d09a2SMark Phalan 	    }
356159d09a2SMark Phalan 	    break;
357159d09a2SMark Phalan 	case RSA_PROTOCOL:
358159d09a2SMark Phalan 	    pkiDebug("as_req: RSA key transport algorithm\n");
359159d09a2SMark Phalan 	    switch((int)reqctx->pa_type) {
360159d09a2SMark Phalan 		case KRB5_PADATA_PK_AS_REQ_OLD:
361159d09a2SMark Phalan 		    auth_pack9->clientPublicValue = NULL;
362159d09a2SMark Phalan 		    break;
363159d09a2SMark Phalan 		case KRB5_PADATA_PK_AS_REQ:
364159d09a2SMark Phalan 		    free_krb5_subject_pk_info(&info);
365159d09a2SMark Phalan 		    auth_pack->clientPublicValue = NULL;
366159d09a2SMark Phalan 		    break;
367159d09a2SMark Phalan 	    }
368159d09a2SMark Phalan 	    break;
369159d09a2SMark Phalan 	default:
370159d09a2SMark Phalan 	    pkiDebug("as_req: unknown key transport protocol %d\n",
371159d09a2SMark Phalan 		    protocol);
372159d09a2SMark Phalan 	    retval = -1;
373159d09a2SMark Phalan 	    goto cleanup;
374159d09a2SMark Phalan     }
375159d09a2SMark Phalan 
376159d09a2SMark Phalan     /* Encode the authpack */
377159d09a2SMark Phalan     switch((int)reqctx->pa_type) {
378159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
379159d09a2SMark Phalan 	    retval = k5int_encode_krb5_auth_pack(auth_pack, &coded_auth_pack);
380159d09a2SMark Phalan 	    break;
381159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
382159d09a2SMark Phalan 	    retval = k5int_encode_krb5_auth_pack_draft9(auth_pack9,
383159d09a2SMark Phalan 							&coded_auth_pack);
384159d09a2SMark Phalan 	    break;
385159d09a2SMark Phalan     }
386159d09a2SMark Phalan     if (retval) {
387159d09a2SMark Phalan 	pkiDebug("failed to encode the AuthPack %d\n", retval);
388159d09a2SMark Phalan 	goto cleanup;
389159d09a2SMark Phalan     }
390159d09a2SMark Phalan #ifdef DEBUG_ASN1
391159d09a2SMark Phalan     print_buffer_bin((unsigned char *)coded_auth_pack->data,
392159d09a2SMark Phalan 		     coded_auth_pack->length,
393159d09a2SMark Phalan 		     "/tmp/client_auth_pack");
394159d09a2SMark Phalan #endif
395159d09a2SMark Phalan 
396159d09a2SMark Phalan     /* create PKCS7 object from authpack */
397159d09a2SMark Phalan     switch((int)reqctx->pa_type) {
398159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
399159d09a2SMark Phalan 	    init_krb5_pa_pk_as_req(&req);
400159d09a2SMark Phalan 	    if (req == NULL) {
401159d09a2SMark Phalan 		retval = ENOMEM;
402159d09a2SMark Phalan 		goto cleanup;
403159d09a2SMark Phalan 	    }
404159d09a2SMark Phalan 	    retval = cms_signeddata_create(context, plgctx->cryptoctx,
405159d09a2SMark Phalan 		reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT, 1,
406159d09a2SMark Phalan 		(unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
407159d09a2SMark Phalan 		&req->signedAuthPack.data, &req->signedAuthPack.length);
408159d09a2SMark Phalan #ifdef DEBUG_ASN1
409159d09a2SMark Phalan 	    print_buffer_bin((unsigned char *)req->signedAuthPack.data,
410159d09a2SMark Phalan 			     req->signedAuthPack.length,
411159d09a2SMark Phalan 			     "/tmp/client_signed_data");
412159d09a2SMark Phalan #endif
413159d09a2SMark Phalan 	    break;
414159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
415159d09a2SMark Phalan 	    init_krb5_pa_pk_as_req_draft9(&req9);
416159d09a2SMark Phalan 	    if (req9 == NULL) {
417159d09a2SMark Phalan 		retval = ENOMEM;
418159d09a2SMark Phalan 		goto cleanup;
419159d09a2SMark Phalan 	    }
420159d09a2SMark Phalan 	    retval = cms_signeddata_create(context, plgctx->cryptoctx,
421159d09a2SMark Phalan 		reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_DRAFT9, 1,
422159d09a2SMark Phalan 		(unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
423159d09a2SMark Phalan 		&req9->signedAuthPack.data, &req9->signedAuthPack.length);
424159d09a2SMark Phalan 	    break;
425159d09a2SMark Phalan #ifdef DEBUG_ASN1
426159d09a2SMark Phalan 	    print_buffer_bin((unsigned char *)req9->signedAuthPack.data,
427159d09a2SMark Phalan 			     req9->signedAuthPack.length,
428159d09a2SMark Phalan 			     "/tmp/client_signed_data_draft9");
429159d09a2SMark Phalan #endif
430159d09a2SMark Phalan     }
431159d09a2SMark Phalan     krb5_free_data(context, coded_auth_pack);
432159d09a2SMark Phalan     if (retval) {
433159d09a2SMark Phalan 	pkiDebug("failed to create pkcs7 signed data\n");
434159d09a2SMark Phalan 	goto cleanup;
435159d09a2SMark Phalan     }
436159d09a2SMark Phalan 
437159d09a2SMark Phalan     /* create a list of trusted CAs */
438159d09a2SMark Phalan     switch((int)reqctx->pa_type) {
439159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
440159d09a2SMark Phalan 	    retval = create_krb5_trustedCertifiers(context, plgctx->cryptoctx,
441159d09a2SMark Phalan 		reqctx->cryptoctx, reqctx->idctx, &req->trustedCertifiers);
442159d09a2SMark Phalan 	    if (retval)
443159d09a2SMark Phalan 		goto cleanup;
444159d09a2SMark Phalan 	    retval = create_issuerAndSerial(context, plgctx->cryptoctx,
445159d09a2SMark Phalan 		reqctx->cryptoctx, reqctx->idctx, &req->kdcPkId.data,
446159d09a2SMark Phalan 		&req->kdcPkId.length);
447159d09a2SMark Phalan 	    if (retval)
448159d09a2SMark Phalan 		goto cleanup;
449159d09a2SMark Phalan 
450159d09a2SMark Phalan 	    /* Encode the as-req */
451159d09a2SMark Phalan 	    retval = k5int_encode_krb5_pa_pk_as_req(req, as_req);
452159d09a2SMark Phalan 	    break;
453159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
454159d09a2SMark Phalan #if 0
455159d09a2SMark Phalan 	    /* W2K3 KDC doesn't like this */
456159d09a2SMark Phalan 	    retval = create_krb5_trustedCas(context, plgctx->cryptoctx,
457159d09a2SMark Phalan 		reqctx->cryptoctx, reqctx->idctx, 1, &req9->trustedCertifiers);
458159d09a2SMark Phalan 	    if (retval)
459159d09a2SMark Phalan 		goto cleanup;
460159d09a2SMark Phalan 
461159d09a2SMark Phalan #endif
462159d09a2SMark Phalan 	    retval = create_issuerAndSerial(context, plgctx->cryptoctx,
463159d09a2SMark Phalan 		reqctx->cryptoctx, reqctx->idctx, &req9->kdcCert.data,
464159d09a2SMark Phalan 		&req9->kdcCert.length);
465159d09a2SMark Phalan 	    if (retval)
466159d09a2SMark Phalan 		goto cleanup;
467159d09a2SMark Phalan 	    /* Encode the as-req */
468159d09a2SMark Phalan 	    retval = k5int_encode_krb5_pa_pk_as_req_draft9(req9, as_req);
469159d09a2SMark Phalan 	    break;
470159d09a2SMark Phalan     }
471159d09a2SMark Phalan #ifdef DEBUG_ASN1
472159d09a2SMark Phalan     if (!retval)
473159d09a2SMark Phalan 	print_buffer_bin((unsigned char *)(*as_req)->data, (*as_req)->length,
474159d09a2SMark Phalan 			 "/tmp/client_as_req");
475159d09a2SMark Phalan #endif
476159d09a2SMark Phalan 
477159d09a2SMark Phalan cleanup:
478159d09a2SMark Phalan     switch((int)reqctx->pa_type) {
479159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
480159d09a2SMark Phalan 	    free_krb5_auth_pack(&auth_pack);
481159d09a2SMark Phalan 	    free_krb5_pa_pk_as_req(&req);
482159d09a2SMark Phalan 	    break;
483159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
484159d09a2SMark Phalan 	    free_krb5_pa_pk_as_req_draft9(&req9);
485159d09a2SMark Phalan 	    free(auth_pack9);
486159d09a2SMark Phalan 	    break;
487159d09a2SMark Phalan     }
488159d09a2SMark Phalan 
489159d09a2SMark Phalan 
490159d09a2SMark Phalan     pkiDebug("pkinit_as_req_create retval=%d\n", (int) retval);
491159d09a2SMark Phalan 
492159d09a2SMark Phalan     return retval;
493159d09a2SMark Phalan }
494159d09a2SMark Phalan 
495159d09a2SMark Phalan krb5_error_code
496159d09a2SMark Phalan pa_pkinit_parse_rep(krb5_context context,
497159d09a2SMark Phalan 		    pkinit_context plgctx,
498159d09a2SMark Phalan 		    pkinit_req_context reqctx,
499159d09a2SMark Phalan 		    krb5_kdc_req * request,
500159d09a2SMark Phalan 		    krb5_pa_data * in_padata,
501159d09a2SMark Phalan 		    krb5_enctype etype,
502159d09a2SMark Phalan 		    krb5_keyblock * as_key,
503159d09a2SMark Phalan 		    krb5_data *encoded_request)
504159d09a2SMark Phalan {
505159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
506159d09a2SMark Phalan     krb5_data asRep = { 0, 0, NULL};
507159d09a2SMark Phalan 
508159d09a2SMark Phalan     /*
509159d09a2SMark Phalan      * One way or the other - success or failure - no other PA systems can
510159d09a2SMark Phalan      * work if the server sent us a PKINIT reply, since only we know how to
511159d09a2SMark Phalan      * decrypt the key.
512159d09a2SMark Phalan      */
513159d09a2SMark Phalan     if ((in_padata == NULL) || (in_padata->length == 0)) {
514159d09a2SMark Phalan 	pkiDebug("pa_pkinit_parse_rep: no in_padata\n");
515159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
516159d09a2SMark Phalan     }
517159d09a2SMark Phalan 
518159d09a2SMark Phalan     asRep.data = (char *) in_padata->contents;
519159d09a2SMark Phalan     asRep.length = in_padata->length;
520159d09a2SMark Phalan 
521159d09a2SMark Phalan     retval =
522159d09a2SMark Phalan 	pkinit_as_rep_parse(context, plgctx, reqctx, in_padata->pa_type,
523159d09a2SMark Phalan 			    request, &asRep, as_key, etype, encoded_request);
524159d09a2SMark Phalan     if (retval) {
525159d09a2SMark Phalan 	pkiDebug("pkinit_as_rep_parse returned %d (%s)\n",
526159d09a2SMark Phalan 		 retval, error_message(retval));
527159d09a2SMark Phalan 	goto cleanup;
528159d09a2SMark Phalan     }
529159d09a2SMark Phalan 
530159d09a2SMark Phalan     retval = 0;
531159d09a2SMark Phalan 
532159d09a2SMark Phalan cleanup:
533159d09a2SMark Phalan 
534159d09a2SMark Phalan     return retval;
535159d09a2SMark Phalan }
536159d09a2SMark Phalan 
537159d09a2SMark Phalan static krb5_error_code
538159d09a2SMark Phalan verify_kdc_san(krb5_context context,
539159d09a2SMark Phalan 	       pkinit_context plgctx,
540159d09a2SMark Phalan 	       pkinit_req_context reqctx,
541159d09a2SMark Phalan 	       krb5_principal kdcprinc,
542159d09a2SMark Phalan 	       int *valid_san,
543159d09a2SMark Phalan 	       int *need_eku_checking)
544159d09a2SMark Phalan {
545159d09a2SMark Phalan     krb5_error_code retval;
546159d09a2SMark Phalan     char **certhosts = NULL, **cfghosts = NULL;
547159d09a2SMark Phalan     krb5_principal *princs = NULL;
548159d09a2SMark Phalan     unsigned char ***get_dns;
549159d09a2SMark Phalan     int i, j;
550159d09a2SMark Phalan 
551159d09a2SMark Phalan     *valid_san = 0;
552159d09a2SMark Phalan     *need_eku_checking = 1;
553159d09a2SMark Phalan 
554159d09a2SMark Phalan     retval = pkinit_libdefault_strings(context,
555159d09a2SMark Phalan 				       krb5_princ_realm(context, kdcprinc),
556159d09a2SMark Phalan 				       "pkinit_kdc_hostname",
557159d09a2SMark Phalan 				       &cfghosts);
558159d09a2SMark Phalan     if (retval || cfghosts == NULL) {
559159d09a2SMark Phalan 	pkiDebug("%s: No pkinit_kdc_hostname values found in config file\n",
560159d09a2SMark Phalan 		 __FUNCTION__);
561159d09a2SMark Phalan 	get_dns = NULL;
562159d09a2SMark Phalan     } else {
563159d09a2SMark Phalan 	pkiDebug("%s: pkinit_kdc_hostname values found in config file\n",
564159d09a2SMark Phalan 		 __FUNCTION__);
565159d09a2SMark Phalan 	get_dns = (unsigned char ***)&certhosts;
566159d09a2SMark Phalan     }
567159d09a2SMark Phalan 
568159d09a2SMark Phalan     retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx,
569159d09a2SMark Phalan 				       reqctx->cryptoctx, reqctx->idctx,
570159d09a2SMark Phalan 				       &princs, NULL, get_dns);
571159d09a2SMark Phalan     if (retval) {
572159d09a2SMark Phalan 	pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
573159d09a2SMark Phalan 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
574159d09a2SMark Phalan 	goto out;
575159d09a2SMark Phalan     }
576159d09a2SMark Phalan #if 0
577159d09a2SMark Phalan     retval = call_san_checking_plugins(context, plgctx, reqctx, idctx,
578159d09a2SMark Phalan 				       princs, hosts, &plugin_decision,
579159d09a2SMark Phalan 				       need_eku_checking);
580159d09a2SMark Phalan     pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
581159d09a2SMark Phalan 	     __FUNCTION__);
582159d09a2SMark Phalan     if (retval) {
583159d09a2SMark Phalan 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
584159d09a2SMark Phalan 	goto out;
585159d09a2SMark Phalan     }
586159d09a2SMark Phalan     pkiDebug("%s: call_san_checking_plugins() returned decision %d and "
587159d09a2SMark Phalan 	     "need_eku_checking %d\n",
588159d09a2SMark Phalan 	     __FUNCTION__, plugin_decision, *need_eku_checking);
589159d09a2SMark Phalan     if (plugin_decision != NO_DECISION) {
590159d09a2SMark Phalan 	retval = plugin_decision;
591159d09a2SMark Phalan 	goto out;
592159d09a2SMark Phalan     }
593159d09a2SMark Phalan #endif
594159d09a2SMark Phalan 
595159d09a2SMark Phalan     pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
596159d09a2SMark Phalan     for (i = 0; princs != NULL && princs[i] != NULL; i++) {
597159d09a2SMark Phalan 	if (krb5_principal_compare(context, princs[i], kdcprinc)) {
598159d09a2SMark Phalan 	    pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
599159d09a2SMark Phalan 	    *valid_san = 1;
600159d09a2SMark Phalan 	    *need_eku_checking = 0;
601159d09a2SMark Phalan 	    retval = 0;
602159d09a2SMark Phalan 	    goto out;
603159d09a2SMark Phalan 	}
604159d09a2SMark Phalan     }
605159d09a2SMark Phalan     pkiDebug("%s: no pkinit san match found\n", __FUNCTION__);
606159d09a2SMark Phalan 
607159d09a2SMark Phalan     if (certhosts == NULL) {
608159d09a2SMark Phalan 	pkiDebug("%s: no certhosts (or we wouldn't accept them anyway)\n",
609159d09a2SMark Phalan 		 __FUNCTION__);
610159d09a2SMark Phalan 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
611159d09a2SMark Phalan 	goto out;
612159d09a2SMark Phalan     }
613159d09a2SMark Phalan 
614159d09a2SMark Phalan     for (i = 0; certhosts[i] != NULL; i++) {
615159d09a2SMark Phalan 	for (j = 0; cfghosts != NULL && cfghosts[j] != NULL; j++) {
616159d09a2SMark Phalan 	    pkiDebug("%s: comparing cert name '%s' with config name '%s'\n",
617159d09a2SMark Phalan 		     __FUNCTION__, certhosts[i], cfghosts[j]);
618159d09a2SMark Phalan 	    if (strcmp(certhosts[i], cfghosts[j]) == 0) {
619159d09a2SMark Phalan 		pkiDebug("%s: we have a dnsName match\n", __FUNCTION__);
620159d09a2SMark Phalan 		*valid_san = 1;
621159d09a2SMark Phalan 		retval = 0;
622159d09a2SMark Phalan 		goto out;
623159d09a2SMark Phalan 	    }
624159d09a2SMark Phalan 	}
625159d09a2SMark Phalan     }
626159d09a2SMark Phalan     pkiDebug("%s: no dnsName san match found\n", __FUNCTION__);
627159d09a2SMark Phalan 
628159d09a2SMark Phalan     /* We found no match */
629159d09a2SMark Phalan     retval = 0;
630159d09a2SMark Phalan 
631159d09a2SMark Phalan out:
632159d09a2SMark Phalan     if (princs != NULL) {
633159d09a2SMark Phalan 	for (i = 0; princs[i] != NULL; i++)
634159d09a2SMark Phalan 	    krb5_free_principal(context, princs[i]);
635159d09a2SMark Phalan 	free(princs);
636159d09a2SMark Phalan     }
637159d09a2SMark Phalan     if (certhosts != NULL) {
638159d09a2SMark Phalan 	for (i = 0; certhosts[i] != NULL; i++)
639159d09a2SMark Phalan 	    free(certhosts[i]);
640159d09a2SMark Phalan 	free(certhosts);
641159d09a2SMark Phalan     }
642159d09a2SMark Phalan     if (cfghosts != NULL)
643159d09a2SMark Phalan 	profile_free_list(cfghosts);
644159d09a2SMark Phalan 
645159d09a2SMark Phalan     pkiDebug("%s: returning retval %d, valid_san %d, need_eku_checking %d\n",
646159d09a2SMark Phalan 	     __FUNCTION__, retval, *valid_san, *need_eku_checking);
647159d09a2SMark Phalan     return retval;
648159d09a2SMark Phalan }
649159d09a2SMark Phalan 
650159d09a2SMark Phalan static krb5_error_code
651159d09a2SMark Phalan verify_kdc_eku(krb5_context context,
652159d09a2SMark Phalan 	       pkinit_context plgctx,
653159d09a2SMark Phalan 	       pkinit_req_context reqctx,
654159d09a2SMark Phalan 	       int *eku_accepted)
655159d09a2SMark Phalan {
656159d09a2SMark Phalan     krb5_error_code retval;
657159d09a2SMark Phalan 
658159d09a2SMark Phalan     *eku_accepted = 0;
659159d09a2SMark Phalan 
660159d09a2SMark Phalan     if (reqctx->opts->require_eku == 0) {
661159d09a2SMark Phalan 	pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__);
662159d09a2SMark Phalan 	*eku_accepted = 1;
663159d09a2SMark Phalan 	retval = 0;
664159d09a2SMark Phalan 	goto out;
665159d09a2SMark Phalan     }
666159d09a2SMark Phalan     retval = crypto_check_cert_eku(context, plgctx->cryptoctx,
667159d09a2SMark Phalan 				   reqctx->cryptoctx, reqctx->idctx,
668159d09a2SMark Phalan 				   1, /* kdc cert */
669159d09a2SMark Phalan 				   reqctx->opts->accept_secondary_eku,
670159d09a2SMark Phalan 				   eku_accepted);
671159d09a2SMark Phalan     if (retval) {
672159d09a2SMark Phalan 	pkiDebug("%s: Error from crypto_check_cert_eku %d (%s)\n",
673159d09a2SMark Phalan 		 __FUNCTION__, retval, error_message(retval));
674159d09a2SMark Phalan 	goto out;
675159d09a2SMark Phalan     }
676159d09a2SMark Phalan 
677159d09a2SMark Phalan out:
678159d09a2SMark Phalan     pkiDebug("%s: returning retval %d, eku_accepted %d\n",
679159d09a2SMark Phalan 	     __FUNCTION__, retval, *eku_accepted);
680159d09a2SMark Phalan     return retval;
681159d09a2SMark Phalan }
682159d09a2SMark Phalan 
683159d09a2SMark Phalan /*
684159d09a2SMark Phalan  * Parse PA-PK-AS-REP message. Optionally evaluates the message's
685159d09a2SMark Phalan  * certificate chain.
686159d09a2SMark Phalan  * Optionally returns various components.
687159d09a2SMark Phalan  */
688159d09a2SMark Phalan krb5_error_code
689159d09a2SMark Phalan pkinit_as_rep_parse(krb5_context context,
690159d09a2SMark Phalan 		    pkinit_context plgctx,
691159d09a2SMark Phalan   		    pkinit_req_context reqctx,
692159d09a2SMark Phalan 		    krb5_preauthtype pa_type,
693159d09a2SMark Phalan 		    krb5_kdc_req *request,
694159d09a2SMark Phalan 		    const krb5_data *as_rep,
695159d09a2SMark Phalan 		    krb5_keyblock *key_block,
696159d09a2SMark Phalan 		    krb5_enctype etype,
697159d09a2SMark Phalan 		    krb5_data *encoded_request)
698159d09a2SMark Phalan {
699159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
700159d09a2SMark Phalan     krb5_pa_pk_as_rep *kdc_reply = NULL;
701159d09a2SMark Phalan     krb5_kdc_dh_key_info *kdc_dh = NULL;
702159d09a2SMark Phalan     krb5_reply_key_pack *key_pack = NULL;
703159d09a2SMark Phalan     krb5_reply_key_pack_draft9 *key_pack9 = NULL;
704159d09a2SMark Phalan     krb5_octet_data dh_data = { 0, 0, NULL };
705159d09a2SMark Phalan     unsigned char *client_key = NULL, *kdc_hostname = NULL;
706159d09a2SMark Phalan     unsigned int client_key_len = 0;
707159d09a2SMark Phalan     krb5_checksum cksum = {0, 0, 0, NULL};
708159d09a2SMark Phalan     krb5_data k5data;
709159d09a2SMark Phalan     int valid_san = 0;
710159d09a2SMark Phalan     int valid_eku = 0;
711159d09a2SMark Phalan     int need_eku_checking = 1;
712159d09a2SMark Phalan 
713159d09a2SMark Phalan     assert((as_rep != NULL) && (key_block != NULL));
714159d09a2SMark Phalan 
715159d09a2SMark Phalan #ifdef DEBUG_ASN1
716159d09a2SMark Phalan     print_buffer_bin((unsigned char *)as_rep->data, as_rep->length,
717159d09a2SMark Phalan 		     "/tmp/client_as_rep");
718159d09a2SMark Phalan #endif
719159d09a2SMark Phalan 
720159d09a2SMark Phalan     if ((retval = k5int_decode_krb5_pa_pk_as_rep(as_rep, &kdc_reply))) {
721159d09a2SMark Phalan 	pkiDebug("decode_krb5_as_rep failed %d\n", retval);
722159d09a2SMark Phalan 	return retval;
723159d09a2SMark Phalan     }
724159d09a2SMark Phalan 
725159d09a2SMark Phalan     switch(kdc_reply->choice) {
726159d09a2SMark Phalan 	case choice_pa_pk_as_rep_dhInfo:
727159d09a2SMark Phalan 	    pkiDebug("as_rep: DH key transport algorithm\n");
728159d09a2SMark Phalan #ifdef DEBUG_ASN1
729159d09a2SMark Phalan     print_buffer_bin(kdc_reply->u.dh_Info.dhSignedData.data,
730159d09a2SMark Phalan 	kdc_reply->u.dh_Info.dhSignedData.length, "/tmp/client_kdc_signeddata");
731159d09a2SMark Phalan #endif
732159d09a2SMark Phalan 	    if ((retval = cms_signeddata_verify(context, plgctx->cryptoctx,
733159d09a2SMark Phalan 		    reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_SERVER,
734159d09a2SMark Phalan 		    reqctx->opts->require_crl_checking,
735159d09a2SMark Phalan 		    kdc_reply->u.dh_Info.dhSignedData.data,
736159d09a2SMark Phalan 		    kdc_reply->u.dh_Info.dhSignedData.length,
737159d09a2SMark Phalan 		    &dh_data.data, &dh_data.length, NULL, NULL)) != 0) {
738159d09a2SMark Phalan 		pkiDebug("failed to verify pkcs7 signed data\n");
739159d09a2SMark Phalan 		goto cleanup;
740159d09a2SMark Phalan 	    }
741159d09a2SMark Phalan 
742159d09a2SMark Phalan 	    break;
743159d09a2SMark Phalan 	case choice_pa_pk_as_rep_encKeyPack:
744159d09a2SMark Phalan 	    pkiDebug("as_rep: RSA key transport algorithm\n");
745159d09a2SMark Phalan 	    if ((retval = cms_envelopeddata_verify(context, plgctx->cryptoctx,
746159d09a2SMark Phalan 		    reqctx->cryptoctx, reqctx->idctx, pa_type,
747159d09a2SMark Phalan 		    reqctx->opts->require_crl_checking,
748159d09a2SMark Phalan 		    kdc_reply->u.encKeyPack.data,
749159d09a2SMark Phalan 		    kdc_reply->u.encKeyPack.length,
750159d09a2SMark Phalan 		    &dh_data.data, &dh_data.length)) != 0) {
751159d09a2SMark Phalan 		pkiDebug("failed to verify pkcs7 enveloped data\n");
752159d09a2SMark Phalan 		goto cleanup;
753159d09a2SMark Phalan 	    }
754159d09a2SMark Phalan 	    break;
755159d09a2SMark Phalan 	default:
756159d09a2SMark Phalan 	    pkiDebug("unknown as_rep type %d\n", kdc_reply->choice);
757159d09a2SMark Phalan 	    retval = -1;
758159d09a2SMark Phalan 	    goto cleanup;
759159d09a2SMark Phalan     }
760159d09a2SMark Phalan 
761159d09a2SMark Phalan     retval = verify_kdc_san(context, plgctx, reqctx, request->server,
762159d09a2SMark Phalan 			    &valid_san, &need_eku_checking);
763159d09a2SMark Phalan     if (retval)
764159d09a2SMark Phalan 	    goto cleanup;
765159d09a2SMark Phalan     if (!valid_san) {
766159d09a2SMark Phalan 	pkiDebug("%s: did not find an acceptable SAN in KDC certificate\n",
767159d09a2SMark Phalan 		 __FUNCTION__);
768159d09a2SMark Phalan 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
769159d09a2SMark Phalan 	goto cleanup;
770159d09a2SMark Phalan     }
771159d09a2SMark Phalan 
772159d09a2SMark Phalan     if (need_eku_checking) {
773159d09a2SMark Phalan 	retval = verify_kdc_eku(context, plgctx, reqctx,
774159d09a2SMark Phalan 				&valid_eku);
775159d09a2SMark Phalan 	if (retval)
776159d09a2SMark Phalan 	    goto cleanup;
777159d09a2SMark Phalan 	if (!valid_eku) {
778159d09a2SMark Phalan 	    pkiDebug("%s: did not find an acceptable EKU in KDC certificate\n",
779159d09a2SMark Phalan 		     __FUNCTION__);
780159d09a2SMark Phalan 	    retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
781159d09a2SMark Phalan 	    goto cleanup;
782159d09a2SMark Phalan 	}
783159d09a2SMark Phalan     } else
784159d09a2SMark Phalan 	pkiDebug("%s: skipping EKU check\n", __FUNCTION__);
785159d09a2SMark Phalan 
786159d09a2SMark Phalan     OCTETDATA_TO_KRB5DATA(&dh_data, &k5data);
787159d09a2SMark Phalan 
788159d09a2SMark Phalan     switch(kdc_reply->choice) {
789159d09a2SMark Phalan 	case choice_pa_pk_as_rep_dhInfo:
790159d09a2SMark Phalan #ifdef DEBUG_ASN1
791159d09a2SMark Phalan 	    print_buffer_bin(dh_data.data, dh_data.length,
792159d09a2SMark Phalan 			     "/tmp/client_dh_key");
793159d09a2SMark Phalan #endif
794159d09a2SMark Phalan 	    if ((retval = k5int_decode_krb5_kdc_dh_key_info(&k5data,
795159d09a2SMark Phalan 		    &kdc_dh)) != 0) {
796159d09a2SMark Phalan 		pkiDebug("failed to decode kdc_dh_key_info\n");
797159d09a2SMark Phalan 		goto cleanup;
798159d09a2SMark Phalan 	    }
799159d09a2SMark Phalan 
800159d09a2SMark Phalan 	    /* client after KDC reply */
801159d09a2SMark Phalan 	    if ((retval = client_process_dh(context, plgctx->cryptoctx,
802159d09a2SMark Phalan 		    reqctx->cryptoctx, reqctx->idctx,
803159d09a2SMark Phalan 		    kdc_dh->subjectPublicKey.data,
804159d09a2SMark Phalan 		    kdc_dh->subjectPublicKey.length,
805159d09a2SMark Phalan 		    &client_key, &client_key_len)) != 0) {
806159d09a2SMark Phalan 		pkiDebug("failed to process dh params\n");
807159d09a2SMark Phalan 		goto cleanup;
808159d09a2SMark Phalan 	    }
809159d09a2SMark Phalan 
810159d09a2SMark Phalan 	    retval = pkinit_octetstring2key(context, etype, client_key,
811159d09a2SMark Phalan 					  client_key_len, key_block);
812159d09a2SMark Phalan 	    if (retval) {
813159d09a2SMark Phalan 		pkiDebug("failed to create key pkinit_octetstring2key %s\n",
814159d09a2SMark Phalan 			 error_message(retval));
815159d09a2SMark Phalan 		goto cleanup;
816159d09a2SMark Phalan 	    }
817159d09a2SMark Phalan 
818159d09a2SMark Phalan 	    break;
819159d09a2SMark Phalan 	case choice_pa_pk_as_rep_encKeyPack:
820159d09a2SMark Phalan #ifdef DEBUG_ASN1
821159d09a2SMark Phalan 	    print_buffer_bin(dh_data.data, dh_data.length,
822159d09a2SMark Phalan 			     "/tmp/client_key_pack");
823159d09a2SMark Phalan #endif
824159d09a2SMark Phalan 	    if ((retval = k5int_decode_krb5_reply_key_pack(&k5data,
825159d09a2SMark Phalan 		    &key_pack)) != 0) {
826159d09a2SMark Phalan 		pkiDebug("failed to decode reply_key_pack\n");
827159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
828159d09a2SMark Phalan     /*
829159d09a2SMark Phalan      * LH Beta 3 requires the extra pa-data, even for RFC requests,
830159d09a2SMark Phalan      * in order to get the Checksum rather than a Nonce in the reply.
831159d09a2SMark Phalan      * This can be removed when LH SP1 is released.
832159d09a2SMark Phalan      */
833159d09a2SMark Phalan 		if (pa_type == KRB5_PADATA_PK_AS_REP && longhorn == 0)
834159d09a2SMark Phalan #else
835159d09a2SMark Phalan 		if (pa_type == KRB5_PADATA_PK_AS_REP)
836159d09a2SMark Phalan #endif
837159d09a2SMark Phalan 		    goto cleanup;
838159d09a2SMark Phalan 		else {
839159d09a2SMark Phalan 		    if ((retval =
840159d09a2SMark Phalan 			k5int_decode_krb5_reply_key_pack_draft9(&k5data,
841159d09a2SMark Phalan 							  &key_pack9)) != 0) {
842159d09a2SMark Phalan 			pkiDebug("failed to decode reply_key_pack_draft9\n");
843159d09a2SMark Phalan 			goto cleanup;
844159d09a2SMark Phalan 		    }
845159d09a2SMark Phalan 		    pkiDebug("decode reply_key_pack_draft9\n");
846159d09a2SMark Phalan 		    if (key_pack9->nonce != request->nonce) {
847159d09a2SMark Phalan 			pkiDebug("nonce in AS_REP=%d doesn't match AS_REQ=%d\n",				 key_pack9->nonce, request->nonce);
848159d09a2SMark Phalan 			retval = -1;
849159d09a2SMark Phalan 			goto cleanup;
850159d09a2SMark Phalan 		    }
851159d09a2SMark Phalan 		    krb5_copy_keyblock_contents(context, &key_pack9->replyKey,
852159d09a2SMark Phalan 						key_block);
853159d09a2SMark Phalan 		    break;
854159d09a2SMark Phalan 		}
855159d09a2SMark Phalan 	    }
856159d09a2SMark Phalan 	    /*
857159d09a2SMark Phalan 	     * This is hack but Windows sends back SHA1 checksum
858159d09a2SMark Phalan 	     * with checksum type of 14. There is currently no
859159d09a2SMark Phalan 	     * checksum type of 14 defined.
860159d09a2SMark Phalan 	     */
861159d09a2SMark Phalan 	    if (key_pack->asChecksum.checksum_type == 14)
862159d09a2SMark Phalan 		key_pack->asChecksum.checksum_type = CKSUMTYPE_NIST_SHA;
863159d09a2SMark Phalan 	    retval = krb5_c_make_checksum(context,
864159d09a2SMark Phalan 					  key_pack->asChecksum.checksum_type,
865159d09a2SMark Phalan 					  &key_pack->replyKey,
866159d09a2SMark Phalan 					  KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
867159d09a2SMark Phalan 					  encoded_request, &cksum);
868159d09a2SMark Phalan 	    if (retval) {
869159d09a2SMark Phalan 		pkiDebug("failed to make a checksum\n");
870159d09a2SMark Phalan 		goto cleanup;
871159d09a2SMark Phalan 	    }
872159d09a2SMark Phalan 
873159d09a2SMark Phalan 	    if ((cksum.length != key_pack->asChecksum.length) ||
874159d09a2SMark Phalan 		memcmp(cksum.contents, key_pack->asChecksum.contents,
875159d09a2SMark Phalan 			cksum.length)) {
876159d09a2SMark Phalan 		pkiDebug("failed to match the checksums\n");
877159d09a2SMark Phalan #ifdef DEBUG_CKSUM
878159d09a2SMark Phalan 	    pkiDebug("calculating checksum on buf size (%d)\n",
879159d09a2SMark Phalan 		     encoded_request->length);
880159d09a2SMark Phalan 	    print_buffer(encoded_request->data, encoded_request->length);
881159d09a2SMark Phalan 	    pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length);
882159d09a2SMark Phalan 	    print_buffer(key_pack->replyKey.contents,
883159d09a2SMark Phalan 			 key_pack->replyKey.length);
884159d09a2SMark Phalan 	    pkiDebug("received checksum type=%d size=%d ",
885159d09a2SMark Phalan 		     key_pack->asChecksum.checksum_type,
886159d09a2SMark Phalan 		     key_pack->asChecksum.length);
887159d09a2SMark Phalan 	    print_buffer(key_pack->asChecksum.contents,
888159d09a2SMark Phalan 			 key_pack->asChecksum.length);
889159d09a2SMark Phalan 	    pkiDebug("expected checksum type=%d size=%d ",
890159d09a2SMark Phalan 		     cksum.checksum_type, cksum.length);
891159d09a2SMark Phalan 	    print_buffer(cksum.contents, cksum.length);
892159d09a2SMark Phalan #endif
893159d09a2SMark Phalan 		goto cleanup;
894159d09a2SMark Phalan 	    } else
895159d09a2SMark Phalan 		pkiDebug("checksums match\n");
896159d09a2SMark Phalan 
897159d09a2SMark Phalan 	    krb5_copy_keyblock_contents(context, &key_pack->replyKey,
898159d09a2SMark Phalan 					key_block);
899159d09a2SMark Phalan 
900159d09a2SMark Phalan 	    break;
901159d09a2SMark Phalan 	default:
902159d09a2SMark Phalan 	    pkiDebug("unknow as_rep type %d\n", kdc_reply->choice);
903159d09a2SMark Phalan 	    goto cleanup;
904159d09a2SMark Phalan     }
905159d09a2SMark Phalan 
906159d09a2SMark Phalan     retval = 0;
907159d09a2SMark Phalan 
908159d09a2SMark Phalan cleanup:
909159d09a2SMark Phalan     if (dh_data.data != NULL)
910159d09a2SMark Phalan 	free(dh_data.data);
911159d09a2SMark Phalan     if (client_key != NULL)
912159d09a2SMark Phalan 	free(client_key);
913159d09a2SMark Phalan     free_krb5_kdc_dh_key_info(&kdc_dh);
914159d09a2SMark Phalan     free_krb5_pa_pk_as_rep(&kdc_reply);
915159d09a2SMark Phalan 
916159d09a2SMark Phalan     if (key_pack != NULL) {
917159d09a2SMark Phalan 	free_krb5_reply_key_pack(&key_pack);
918159d09a2SMark Phalan 	if (cksum.contents != NULL)
919159d09a2SMark Phalan 	    free(cksum.contents);
920159d09a2SMark Phalan     }
921159d09a2SMark Phalan     if (key_pack9 != NULL)
922159d09a2SMark Phalan 	free_krb5_reply_key_pack_draft9(&key_pack9);
923159d09a2SMark Phalan 
924159d09a2SMark Phalan     if (kdc_hostname != NULL)
925159d09a2SMark Phalan 	free(kdc_hostname);
926159d09a2SMark Phalan 
927159d09a2SMark Phalan     pkiDebug("pkinit_as_rep_parse returning %d (%s)\n",
928159d09a2SMark Phalan 	     retval, error_message(retval));
929159d09a2SMark Phalan     return retval;
930159d09a2SMark Phalan }
931159d09a2SMark Phalan 
932159d09a2SMark Phalan static void
933159d09a2SMark Phalan pkinit_client_profile(krb5_context context,
934159d09a2SMark Phalan 		      pkinit_context plgctx,
935159d09a2SMark Phalan 		      pkinit_req_context reqctx,
936159d09a2SMark Phalan 		      krb5_kdc_req *request)
937159d09a2SMark Phalan {
938159d09a2SMark Phalan     char *eku_string = NULL;
939159d09a2SMark Phalan 
940159d09a2SMark Phalan     pkiDebug("pkinit_client_profile %p %p %p %p\n",
941159d09a2SMark Phalan 	     context, plgctx, reqctx, request);
942159d09a2SMark Phalan 
943159d09a2SMark Phalan     (void) pkinit_libdefault_boolean(context, &request->server->realm,
944159d09a2SMark Phalan 			      "pkinit_win2k",
945159d09a2SMark Phalan 			      reqctx->opts->win2k_target,
946159d09a2SMark Phalan 			      &reqctx->opts->win2k_target);
947159d09a2SMark Phalan     (void) pkinit_libdefault_boolean(context, &request->server->realm,
948159d09a2SMark Phalan 			      "pkinit_win2k_require_binding",
949159d09a2SMark Phalan 			      reqctx->opts->win2k_require_cksum,
950159d09a2SMark Phalan 			      &reqctx->opts->win2k_require_cksum);
951159d09a2SMark Phalan     (void) pkinit_libdefault_boolean(context, &request->server->realm,
952159d09a2SMark Phalan 			      "pkinit_require_crl_checking",
953159d09a2SMark Phalan 			      reqctx->opts->require_crl_checking,
954159d09a2SMark Phalan 			      &reqctx->opts->require_crl_checking);
955159d09a2SMark Phalan     (void) pkinit_libdefault_integer(context, &request->server->realm,
956159d09a2SMark Phalan 			      "pkinit_dh_min_bits",
957159d09a2SMark Phalan 			      reqctx->opts->dh_size,
958159d09a2SMark Phalan 			      &reqctx->opts->dh_size);
959159d09a2SMark Phalan     if (reqctx->opts->dh_size != 1024 && reqctx->opts->dh_size != 2048
960159d09a2SMark Phalan         && reqctx->opts->dh_size != 4096) {
961159d09a2SMark Phalan 	pkiDebug("%s: invalid value (%d) for pkinit_dh_min_bits, "
962159d09a2SMark Phalan 		 "using default value (%d) instead\n", __FUNCTION__,
963159d09a2SMark Phalan 		 reqctx->opts->dh_size, PKINIT_DEFAULT_DH_MIN_BITS);
964159d09a2SMark Phalan 	reqctx->opts->dh_size = PKINIT_DEFAULT_DH_MIN_BITS;
965159d09a2SMark Phalan     }
966159d09a2SMark Phalan     (void) pkinit_libdefault_string(context, &request->server->realm,
967159d09a2SMark Phalan 			     "pkinit_eku_checking",
968159d09a2SMark Phalan 			     &eku_string);
969159d09a2SMark Phalan     if (eku_string != NULL) {
970159d09a2SMark Phalan 	if (strcasecmp(eku_string, "kpKDC") == 0) {
971159d09a2SMark Phalan 	    reqctx->opts->require_eku = 1;
972159d09a2SMark Phalan 	    reqctx->opts->accept_secondary_eku = 0;
973159d09a2SMark Phalan 	} else if (strcasecmp(eku_string, "kpServerAuth") == 0) {
974159d09a2SMark Phalan 	    reqctx->opts->require_eku = 1;
975159d09a2SMark Phalan 	    reqctx->opts->accept_secondary_eku = 1;
976159d09a2SMark Phalan 	} else if (strcasecmp(eku_string, "none") == 0) {
977159d09a2SMark Phalan 	    reqctx->opts->require_eku = 0;
978159d09a2SMark Phalan 	    reqctx->opts->accept_secondary_eku = 0;
979159d09a2SMark Phalan 	} else {
980159d09a2SMark Phalan 	    pkiDebug("%s: Invalid value for pkinit_eku_checking: '%s'\n",
981159d09a2SMark Phalan 		     __FUNCTION__, eku_string);
982159d09a2SMark Phalan 	}
983159d09a2SMark Phalan 	free(eku_string);
984159d09a2SMark Phalan     }
985159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
986159d09a2SMark Phalan     /* Temporarily just set global flag from config file */
987159d09a2SMark Phalan     (void) pkinit_libdefault_boolean(context, &request->server->realm,
988159d09a2SMark Phalan 			      "pkinit_longhorn",
989159d09a2SMark Phalan 			      0,
990159d09a2SMark Phalan 			      &longhorn);
991159d09a2SMark Phalan #endif
992159d09a2SMark Phalan 
993159d09a2SMark Phalan     /* Only process anchors here if they were not specified on command line */
994159d09a2SMark Phalan     if (reqctx->idopts->anchors == NULL)
995159d09a2SMark Phalan 	(void) pkinit_libdefault_strings(context, &request->server->realm,
996159d09a2SMark Phalan 				  "pkinit_anchors",
997159d09a2SMark Phalan 				  &reqctx->idopts->anchors);
998159d09a2SMark Phalan     /* Solaris Kerberos */
999159d09a2SMark Phalan     (void) pkinit_libdefault_strings(context, &request->server->realm,
1000159d09a2SMark Phalan 			      "pkinit_pool",
1001159d09a2SMark Phalan 			      &reqctx->idopts->intermediates);
1002159d09a2SMark Phalan     (void) pkinit_libdefault_strings(context, &request->server->realm,
1003159d09a2SMark Phalan 			      "pkinit_revoke",
1004159d09a2SMark Phalan 			      &reqctx->idopts->crls);
1005159d09a2SMark Phalan     (void) pkinit_libdefault_strings(context, &request->server->realm,
1006159d09a2SMark Phalan 			      "pkinit_identities",
1007159d09a2SMark Phalan 			      &reqctx->idopts->identity_alt);
1008159d09a2SMark Phalan }
1009159d09a2SMark Phalan 
1010159d09a2SMark Phalan /* ARGSUSED */
1011159d09a2SMark Phalan krb5_error_code
1012159d09a2SMark Phalan pkinit_client_process(krb5_context context,
1013159d09a2SMark Phalan 		      void *plugin_context,
1014159d09a2SMark Phalan 		      void *request_context,
1015159d09a2SMark Phalan 		      krb5_get_init_creds_opt *gic_opt,
1016159d09a2SMark Phalan 		      preauth_get_client_data_proc get_data_proc,
1017159d09a2SMark Phalan 		      struct _krb5_preauth_client_rock *rock,
1018159d09a2SMark Phalan 		      krb5_kdc_req *request,
1019159d09a2SMark Phalan 		      krb5_data *encoded_request_body,
1020159d09a2SMark Phalan 		      krb5_data *encoded_previous_request,
1021159d09a2SMark Phalan 		      krb5_pa_data *in_padata,
1022159d09a2SMark Phalan 		      krb5_prompter_fct prompter,
1023159d09a2SMark Phalan 		      void *prompter_data,
1024159d09a2SMark Phalan 		      preauth_get_as_key_proc gak_fct,
1025159d09a2SMark Phalan 		      void *gak_data,
1026159d09a2SMark Phalan 		      krb5_data *salt,
1027159d09a2SMark Phalan 		      krb5_data *s2kparams,
1028159d09a2SMark Phalan 		      krb5_keyblock *as_key,
1029159d09a2SMark Phalan 		      krb5_pa_data ***out_padata)
1030159d09a2SMark Phalan {
1031159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1032159d09a2SMark Phalan     krb5_enctype enctype = -1;
1033159d09a2SMark Phalan     krb5_data *cdata = NULL;
1034159d09a2SMark Phalan     int processing_request = 0;
1035159d09a2SMark Phalan     pkinit_context plgctx = (pkinit_context)plugin_context;
1036159d09a2SMark Phalan     pkinit_req_context reqctx = (pkinit_req_context)request_context;
1037159d09a2SMark Phalan 
1038159d09a2SMark Phalan     pkiDebug("pkinit_client_process %p %p %p %p\n",
1039159d09a2SMark Phalan 	     context, plgctx, reqctx, request);
1040159d09a2SMark Phalan 
1041159d09a2SMark Phalan     if (plgctx == NULL || reqctx == NULL)
1042159d09a2SMark Phalan 	return EINVAL;
1043159d09a2SMark Phalan 
1044159d09a2SMark Phalan     switch ((int) in_padata->pa_type) {
1045159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
1046159d09a2SMark Phalan 	    pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
1047159d09a2SMark Phalan 	    processing_request = 1;
1048159d09a2SMark Phalan 	    break;
1049159d09a2SMark Phalan 
1050159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP:
1051159d09a2SMark Phalan 	    pkiDebug("processing KRB5_PADATA_PK_AS_REP\n");
1052159d09a2SMark Phalan 	    break;
1053159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
1054159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
1055159d09a2SMark Phalan 	    if (in_padata->length == 0) {
1056159d09a2SMark Phalan 		pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
1057159d09a2SMark Phalan 		in_padata->pa_type = KRB5_PADATA_PK_AS_REQ_OLD;
1058159d09a2SMark Phalan 		processing_request = 1;
1059159d09a2SMark Phalan 	    } else {
1060159d09a2SMark Phalan 		pkiDebug("processing KRB5_PADATA_PK_AS_REP_OLD\n");
1061159d09a2SMark Phalan 		in_padata->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
1062159d09a2SMark Phalan 	    }
1063159d09a2SMark Phalan 	    break;
1064159d09a2SMark Phalan 	default:
1065159d09a2SMark Phalan 	    pkiDebug("unrecognized patype = %d for PKINIT\n",
1066159d09a2SMark Phalan 		    in_padata->pa_type);
1067159d09a2SMark Phalan 	    return EINVAL;
1068159d09a2SMark Phalan     }
1069159d09a2SMark Phalan 
1070159d09a2SMark Phalan     if (processing_request) {
1071159d09a2SMark Phalan 	pkinit_client_profile(context, plgctx, reqctx, request);
1072159d09a2SMark Phalan 	/* Solaris Kerberos */
1073159d09a2SMark Phalan 	retval = pkinit_identity_set_prompter(reqctx->idctx, prompter, prompter_data);
1074159d09a2SMark Phalan 	if (retval) {
1075159d09a2SMark Phalan 	    pkiDebug("pkinit_identity_set_prompter returned %d (%s)\n",
1076159d09a2SMark Phalan 		     retval, error_message(retval));
1077159d09a2SMark Phalan 	    return retval;
1078159d09a2SMark Phalan 	}
1079159d09a2SMark Phalan 
1080159d09a2SMark Phalan 	retval = pkinit_identity_initialize(context, plgctx->cryptoctx,
1081159d09a2SMark Phalan 					    reqctx->cryptoctx, reqctx->idopts,
1082159d09a2SMark Phalan 					    reqctx->idctx, 1, request->client);
1083159d09a2SMark Phalan 	if (retval) {
1084159d09a2SMark Phalan 	    pkiDebug("pkinit_identity_initialize returned %d (%s)\n",
1085159d09a2SMark Phalan 		     retval, error_message(retval));
1086159d09a2SMark Phalan 	    return retval;
1087159d09a2SMark Phalan 	}
1088159d09a2SMark Phalan 	retval = pa_pkinit_gen_req(context, plgctx, reqctx, request,
1089159d09a2SMark Phalan 				   in_padata, out_padata, prompter,
1090159d09a2SMark Phalan 				   prompter_data, gic_opt);
1091159d09a2SMark Phalan     } else {
1092159d09a2SMark Phalan 	/*
1093159d09a2SMark Phalan 	 * Get the enctype of the reply.
1094159d09a2SMark Phalan 	 */
1095159d09a2SMark Phalan 	retval = (*get_data_proc)(context, rock,
1096159d09a2SMark Phalan 				krb5plugin_preauth_client_get_etype, &cdata);
1097159d09a2SMark Phalan 	if (retval) {
1098159d09a2SMark Phalan 	    pkiDebug("get_data_proc returned %d (%s)\n",
1099159d09a2SMark Phalan 		     retval, error_message(retval));
1100159d09a2SMark Phalan 	    return retval;
1101159d09a2SMark Phalan 	}
1102159d09a2SMark Phalan 	enctype = *((krb5_enctype *)cdata->data);
1103159d09a2SMark Phalan 	(*get_data_proc)(context, rock,
1104159d09a2SMark Phalan 			 krb5plugin_preauth_client_free_etype, &cdata);
1105159d09a2SMark Phalan 	retval = pa_pkinit_parse_rep(context, plgctx, reqctx, request,
1106159d09a2SMark Phalan 				     in_padata, enctype, as_key,
1107159d09a2SMark Phalan 				     encoded_previous_request);
1108159d09a2SMark Phalan     }
1109159d09a2SMark Phalan 
1110159d09a2SMark Phalan     pkiDebug("pkinit_client_process: returning %d (%s)\n",
1111159d09a2SMark Phalan 	     retval, error_message(retval));
1112159d09a2SMark Phalan     return retval;
1113159d09a2SMark Phalan }
1114159d09a2SMark Phalan 
1115159d09a2SMark Phalan /* ARGSUSED */
1116159d09a2SMark Phalan krb5_error_code
1117159d09a2SMark Phalan pkinit_client_tryagain(krb5_context context,
1118159d09a2SMark Phalan 		       void *plugin_context,
1119159d09a2SMark Phalan 		       void *request_context,
1120159d09a2SMark Phalan 		       krb5_get_init_creds_opt *gic_opt,
1121159d09a2SMark Phalan 		       preauth_get_client_data_proc get_data_proc,
1122159d09a2SMark Phalan 		       struct _krb5_preauth_client_rock *rock,
1123159d09a2SMark Phalan 		       krb5_kdc_req *request,
1124159d09a2SMark Phalan 		       krb5_data *encoded_request_body,
1125159d09a2SMark Phalan 		       krb5_data *encoded_previous_request,
1126159d09a2SMark Phalan 		       krb5_pa_data *in_padata,
1127159d09a2SMark Phalan 		       krb5_error *err_reply,
1128159d09a2SMark Phalan 		       krb5_prompter_fct prompter,
1129159d09a2SMark Phalan 		       void *prompter_data,
1130159d09a2SMark Phalan 		       preauth_get_as_key_proc gak_fct,
1131159d09a2SMark Phalan 		       void *gak_data,
1132159d09a2SMark Phalan 		       krb5_data *salt,
1133159d09a2SMark Phalan 		       krb5_data *s2kparams,
1134159d09a2SMark Phalan 		       krb5_keyblock *as_key,
1135159d09a2SMark Phalan 		       krb5_pa_data ***out_padata)
1136159d09a2SMark Phalan {
1137159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1138159d09a2SMark Phalan     pkinit_context plgctx = (pkinit_context)plugin_context;
1139159d09a2SMark Phalan     pkinit_req_context reqctx = (pkinit_req_context)request_context;
1140159d09a2SMark Phalan     krb5_typed_data **typed_data = NULL;
1141159d09a2SMark Phalan     krb5_data scratch;
1142159d09a2SMark Phalan     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
1143159d09a2SMark Phalan     krb5_algorithm_identifier **algId = NULL;
1144159d09a2SMark Phalan     int do_again = 0;
1145159d09a2SMark Phalan 
1146159d09a2SMark Phalan     pkiDebug("pkinit_client_tryagain %p %p %p %p\n",
1147159d09a2SMark Phalan 	     context, plgctx, reqctx, request);
1148159d09a2SMark Phalan 
1149159d09a2SMark Phalan     if (reqctx->pa_type != in_padata->pa_type)
1150159d09a2SMark Phalan 	return retval;
1151159d09a2SMark Phalan 
1152159d09a2SMark Phalan #ifdef DEBUG_ASN1
1153159d09a2SMark Phalan     print_buffer_bin((unsigned char *)err_reply->e_data.data,
1154159d09a2SMark Phalan 		     err_reply->e_data.length, "/tmp/client_edata");
1155159d09a2SMark Phalan #endif
1156159d09a2SMark Phalan     retval = k5int_decode_krb5_typed_data(&err_reply->e_data, &typed_data);
1157159d09a2SMark Phalan     if (retval) {
1158159d09a2SMark Phalan 	pkiDebug("decode_krb5_typed_data failed\n");
1159159d09a2SMark Phalan 	goto cleanup;
1160159d09a2SMark Phalan     }
1161159d09a2SMark Phalan #ifdef DEBUG_ASN1
1162159d09a2SMark Phalan     print_buffer_bin(typed_data[0]->data, typed_data[0]->length,
1163159d09a2SMark Phalan 		     "/tmp/client_typed_data");
1164159d09a2SMark Phalan #endif
1165159d09a2SMark Phalan     OCTETDATA_TO_KRB5DATA(typed_data[0], &scratch);
1166159d09a2SMark Phalan 
1167159d09a2SMark Phalan     switch(typed_data[0]->type) {
1168159d09a2SMark Phalan 	case TD_TRUSTED_CERTIFIERS:
1169159d09a2SMark Phalan 	case TD_INVALID_CERTIFICATES:
1170159d09a2SMark Phalan 	    retval = k5int_decode_krb5_td_trusted_certifiers(&scratch,
1171159d09a2SMark Phalan 		&krb5_trusted_certifiers);
1172159d09a2SMark Phalan 	    if (retval) {
1173159d09a2SMark Phalan 		pkiDebug("failed to decode sequence of trusted certifiers\n");
1174159d09a2SMark Phalan 		goto cleanup;
1175159d09a2SMark Phalan 	    }
1176159d09a2SMark Phalan 	    retval = pkinit_process_td_trusted_certifiers(context,
1177159d09a2SMark Phalan 		    plgctx->cryptoctx, reqctx->cryptoctx, reqctx->idctx,
1178159d09a2SMark Phalan 		    krb5_trusted_certifiers, typed_data[0]->type);
1179159d09a2SMark Phalan 	    if (!retval)
1180159d09a2SMark Phalan 		do_again = 1;
1181159d09a2SMark Phalan 	    break;
1182159d09a2SMark Phalan 	case TD_DH_PARAMETERS:
1183159d09a2SMark Phalan 	    retval = k5int_decode_krb5_td_dh_parameters(&scratch, &algId);
1184159d09a2SMark Phalan 	    if (retval) {
1185159d09a2SMark Phalan 		pkiDebug("failed to decode td_dh_parameters\n");
1186159d09a2SMark Phalan 		goto cleanup;
1187159d09a2SMark Phalan 	    }
1188159d09a2SMark Phalan 	    retval = pkinit_process_td_dh_params(context, plgctx->cryptoctx,
1189159d09a2SMark Phalan 		reqctx->cryptoctx, reqctx->idctx, algId,
1190159d09a2SMark Phalan 		&reqctx->opts->dh_size);
1191159d09a2SMark Phalan 	    if (!retval)
1192159d09a2SMark Phalan 		do_again = 1;
1193159d09a2SMark Phalan 	    break;
1194159d09a2SMark Phalan 	default:
1195159d09a2SMark Phalan 	    break;
1196159d09a2SMark Phalan     }
1197159d09a2SMark Phalan 
1198159d09a2SMark Phalan     if (do_again) {
1199159d09a2SMark Phalan 	retval = pa_pkinit_gen_req(context, plgctx, reqctx, request, in_padata,
1200159d09a2SMark Phalan 				   out_padata, prompter, prompter_data, gic_opt);
1201159d09a2SMark Phalan 	if (retval)
1202159d09a2SMark Phalan 	    goto cleanup;
1203159d09a2SMark Phalan     }
1204159d09a2SMark Phalan 
1205159d09a2SMark Phalan     retval = 0;
1206159d09a2SMark Phalan cleanup:
1207159d09a2SMark Phalan     if (krb5_trusted_certifiers != NULL)
1208159d09a2SMark Phalan 	free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
1209159d09a2SMark Phalan 
1210159d09a2SMark Phalan     if (typed_data != NULL)
1211159d09a2SMark Phalan 	free_krb5_typed_data(&typed_data);
1212159d09a2SMark Phalan 
1213159d09a2SMark Phalan     if (algId != NULL)
1214159d09a2SMark Phalan 	free_krb5_algorithm_identifiers(&algId);
1215159d09a2SMark Phalan 
1216159d09a2SMark Phalan     pkiDebug("pkinit_client_tryagain: returning %d (%s)\n",
1217159d09a2SMark Phalan 	     retval, error_message(retval));
1218159d09a2SMark Phalan     return retval;
1219159d09a2SMark Phalan }
1220159d09a2SMark Phalan 
1221159d09a2SMark Phalan /* ARGSUSED */
1222159d09a2SMark Phalan static int
1223159d09a2SMark Phalan pkinit_client_get_flags(krb5_context kcontext, krb5_preauthtype patype)
1224159d09a2SMark Phalan {
1225159d09a2SMark Phalan     return PA_REAL;
1226159d09a2SMark Phalan }
1227159d09a2SMark Phalan 
1228159d09a2SMark Phalan static krb5_preauthtype supported_client_pa_types[] = {
1229159d09a2SMark Phalan     KRB5_PADATA_PK_AS_REP,
1230159d09a2SMark Phalan     KRB5_PADATA_PK_AS_REQ,
1231159d09a2SMark Phalan     KRB5_PADATA_PK_AS_REP_OLD,
1232159d09a2SMark Phalan     KRB5_PADATA_PK_AS_REQ_OLD,
1233159d09a2SMark Phalan     0
1234159d09a2SMark Phalan };
1235159d09a2SMark Phalan 
1236159d09a2SMark Phalan /* ARGSUSED */
1237159d09a2SMark Phalan void
1238159d09a2SMark Phalan pkinit_client_req_init(krb5_context context,
1239159d09a2SMark Phalan 		       void *plugin_context,
1240159d09a2SMark Phalan 		       void **request_context)
1241159d09a2SMark Phalan {
1242159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
1243159d09a2SMark Phalan     struct _pkinit_req_context *reqctx = NULL;
1244159d09a2SMark Phalan     struct _pkinit_context *plgctx = (struct _pkinit_context *)plugin_context;
1245159d09a2SMark Phalan 
1246159d09a2SMark Phalan     *request_context = NULL;
1247159d09a2SMark Phalan 
1248159d09a2SMark Phalan     reqctx = (struct _pkinit_req_context *) malloc(sizeof(*reqctx));
1249159d09a2SMark Phalan     if (reqctx == NULL)
1250159d09a2SMark Phalan 	return;
1251159d09a2SMark Phalan     (void) memset(reqctx, 0, sizeof(*reqctx));
1252159d09a2SMark Phalan 
1253159d09a2SMark Phalan     reqctx->magic = PKINIT_REQ_CTX_MAGIC;
1254159d09a2SMark Phalan     reqctx->cryptoctx = NULL;
1255159d09a2SMark Phalan     reqctx->opts = NULL;
1256159d09a2SMark Phalan     reqctx->idctx = NULL;
1257159d09a2SMark Phalan     reqctx->idopts = NULL;
1258159d09a2SMark Phalan 
1259159d09a2SMark Phalan     retval = pkinit_init_req_opts(&reqctx->opts);
1260159d09a2SMark Phalan     if (retval)
1261159d09a2SMark Phalan 	goto cleanup;
1262159d09a2SMark Phalan 
1263159d09a2SMark Phalan     reqctx->opts->require_eku = plgctx->opts->require_eku;
1264159d09a2SMark Phalan     reqctx->opts->accept_secondary_eku = plgctx->opts->accept_secondary_eku;
1265159d09a2SMark Phalan     reqctx->opts->dh_or_rsa = plgctx->opts->dh_or_rsa;
1266159d09a2SMark Phalan     reqctx->opts->allow_upn = plgctx->opts->allow_upn;
1267159d09a2SMark Phalan     reqctx->opts->require_crl_checking = plgctx->opts->require_crl_checking;
1268159d09a2SMark Phalan 
1269159d09a2SMark Phalan     retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
1270159d09a2SMark Phalan     if (retval)
1271159d09a2SMark Phalan 	goto cleanup;
1272159d09a2SMark Phalan 
1273159d09a2SMark Phalan     retval = pkinit_init_identity_crypto(&reqctx->idctx);
1274159d09a2SMark Phalan     if (retval)
1275159d09a2SMark Phalan 	goto cleanup;
1276159d09a2SMark Phalan 
1277159d09a2SMark Phalan     retval = pkinit_dup_identity_opts(plgctx->idopts, &reqctx->idopts);
1278159d09a2SMark Phalan     if (retval)
1279159d09a2SMark Phalan 	goto cleanup;
1280159d09a2SMark Phalan 
1281159d09a2SMark Phalan     *request_context = (void *) reqctx;
1282159d09a2SMark Phalan     pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
1283159d09a2SMark Phalan 
1284159d09a2SMark Phalan cleanup:
1285159d09a2SMark Phalan     if (retval) {
1286159d09a2SMark Phalan 	if (reqctx->idctx != NULL)
1287159d09a2SMark Phalan 	    pkinit_fini_identity_crypto(reqctx->idctx);
1288159d09a2SMark Phalan 	if (reqctx->cryptoctx != NULL)
1289159d09a2SMark Phalan 	    pkinit_fini_req_crypto(reqctx->cryptoctx);
1290159d09a2SMark Phalan 	if (reqctx->opts != NULL)
1291159d09a2SMark Phalan 	    pkinit_fini_req_opts(reqctx->opts);
1292159d09a2SMark Phalan 	if (reqctx->idopts != NULL)
1293159d09a2SMark Phalan 	    pkinit_fini_identity_opts(reqctx->idopts);
1294159d09a2SMark Phalan 	free(reqctx);
1295159d09a2SMark Phalan     }
1296159d09a2SMark Phalan 
1297159d09a2SMark Phalan     return;
1298159d09a2SMark Phalan }
1299159d09a2SMark Phalan 
1300159d09a2SMark Phalan /* ARGSUSED */
1301159d09a2SMark Phalan void
1302159d09a2SMark Phalan pkinit_client_req_fini(krb5_context context,
1303159d09a2SMark Phalan 		      void *plugin_context,
1304159d09a2SMark Phalan 		      void *request_context)
1305159d09a2SMark Phalan {
1306159d09a2SMark Phalan     struct _pkinit_req_context *reqctx =
1307159d09a2SMark Phalan 	(struct _pkinit_req_context *)request_context;
1308159d09a2SMark Phalan 
1309159d09a2SMark Phalan     pkiDebug("%s: received reqctx at %p\n", __FUNCTION__, reqctx);
1310159d09a2SMark Phalan     if (reqctx == NULL)
1311159d09a2SMark Phalan 	return;
1312159d09a2SMark Phalan     if (reqctx->magic != PKINIT_REQ_CTX_MAGIC) {
1313159d09a2SMark Phalan 	pkiDebug("%s: Bad magic value (%x) in req ctx\n",
1314159d09a2SMark Phalan 		 __FUNCTION__, reqctx->magic);
1315159d09a2SMark Phalan 	return;
1316159d09a2SMark Phalan     }
1317159d09a2SMark Phalan     if (reqctx->opts != NULL)
1318159d09a2SMark Phalan 	pkinit_fini_req_opts(reqctx->opts);
1319159d09a2SMark Phalan 
1320159d09a2SMark Phalan     if (reqctx->cryptoctx != NULL)
1321159d09a2SMark Phalan 	pkinit_fini_req_crypto(reqctx->cryptoctx);
1322159d09a2SMark Phalan 
1323159d09a2SMark Phalan     if (reqctx->idctx != NULL)
1324159d09a2SMark Phalan 	pkinit_fini_identity_crypto(reqctx->idctx);
1325159d09a2SMark Phalan 
1326159d09a2SMark Phalan     if (reqctx->idopts != NULL)
1327159d09a2SMark Phalan 	pkinit_fini_identity_opts(reqctx->idopts);
1328159d09a2SMark Phalan 
1329159d09a2SMark Phalan     free(reqctx);
1330159d09a2SMark Phalan     return;
1331159d09a2SMark Phalan }
1332159d09a2SMark Phalan 
1333159d09a2SMark Phalan /* ARGSUSED */
1334159d09a2SMark Phalan static void
1335159d09a2SMark Phalan pkinit_fini_client_profile(krb5_context context, pkinit_context plgctx)
1336159d09a2SMark Phalan {
1337159d09a2SMark Phalan     /* This should clean up anything allocated in pkinit_init_client_profile */
1338159d09a2SMark Phalan }
1339159d09a2SMark Phalan 
1340159d09a2SMark Phalan /* ARGSUSED */
1341159d09a2SMark Phalan static krb5_error_code
1342159d09a2SMark Phalan pkinit_init_client_profile(krb5_context context, pkinit_context plgctx)
1343159d09a2SMark Phalan {
1344159d09a2SMark Phalan     return 0;
1345159d09a2SMark Phalan }
1346159d09a2SMark Phalan 
1347159d09a2SMark Phalan static int
1348159d09a2SMark Phalan pkinit_client_plugin_init(krb5_context context, void **blob)
1349159d09a2SMark Phalan {
1350159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
1351159d09a2SMark Phalan     struct _pkinit_context *ctx = NULL;
1352159d09a2SMark Phalan 
1353159d09a2SMark Phalan     ctx = (struct _pkinit_context *)calloc(1, sizeof(*ctx));
1354159d09a2SMark Phalan     if (ctx == NULL)
1355159d09a2SMark Phalan 	return ENOMEM;
1356159d09a2SMark Phalan     (void) memset(ctx, 0, sizeof(*ctx));
1357159d09a2SMark Phalan     ctx->magic = PKINIT_CTX_MAGIC;
1358159d09a2SMark Phalan     ctx->opts = NULL;
1359159d09a2SMark Phalan     ctx->cryptoctx = NULL;
1360159d09a2SMark Phalan     ctx->idopts = NULL;
1361159d09a2SMark Phalan 
1362159d09a2SMark Phalan     retval = pkinit_accessor_init();
1363159d09a2SMark Phalan     if (retval)
1364159d09a2SMark Phalan 	goto errout;
1365159d09a2SMark Phalan 
1366159d09a2SMark Phalan     retval = pkinit_init_plg_opts(&ctx->opts);
1367159d09a2SMark Phalan     if (retval)
1368159d09a2SMark Phalan 	goto errout;
1369159d09a2SMark Phalan 
1370159d09a2SMark Phalan     retval = pkinit_init_plg_crypto(&ctx->cryptoctx);
1371159d09a2SMark Phalan     if (retval)
1372159d09a2SMark Phalan 	goto errout;
1373159d09a2SMark Phalan 
1374159d09a2SMark Phalan     retval = pkinit_init_identity_opts(&ctx->idopts);
1375159d09a2SMark Phalan     if (retval)
1376159d09a2SMark Phalan 	goto errout;
1377159d09a2SMark Phalan 
1378159d09a2SMark Phalan     retval = pkinit_init_client_profile(context, ctx);
1379159d09a2SMark Phalan     if (retval)
1380159d09a2SMark Phalan 	goto errout;
1381159d09a2SMark Phalan 
1382159d09a2SMark Phalan     *blob = ctx;
1383159d09a2SMark Phalan 
1384159d09a2SMark Phalan     pkiDebug("%s: returning plgctx at %p\n", __FUNCTION__, ctx);
1385159d09a2SMark Phalan 
1386159d09a2SMark Phalan errout:
1387159d09a2SMark Phalan     if (retval)
1388159d09a2SMark Phalan 	pkinit_client_plugin_fini(context, ctx);
1389159d09a2SMark Phalan 
1390159d09a2SMark Phalan     return retval;
1391159d09a2SMark Phalan }
1392159d09a2SMark Phalan 
1393159d09a2SMark Phalan static void
1394159d09a2SMark Phalan pkinit_client_plugin_fini(krb5_context context, void *blob)
1395159d09a2SMark Phalan {
1396159d09a2SMark Phalan     struct _pkinit_context *ctx = (struct _pkinit_context *)blob;
1397159d09a2SMark Phalan 
1398159d09a2SMark Phalan     if (ctx == NULL || ctx->magic != PKINIT_CTX_MAGIC) {
1399159d09a2SMark Phalan 	pkiDebug("pkinit_lib_fini: got bad plgctx (%p)!\n", ctx);
1400159d09a2SMark Phalan 	return;
1401159d09a2SMark Phalan     }
1402159d09a2SMark Phalan     pkiDebug("%s: got plgctx at %p\n", __FUNCTION__, ctx);
1403159d09a2SMark Phalan 
1404159d09a2SMark Phalan     pkinit_fini_client_profile(context, ctx);
1405159d09a2SMark Phalan     pkinit_fini_identity_opts(ctx->idopts);
1406159d09a2SMark Phalan     pkinit_fini_plg_crypto(ctx->cryptoctx);
1407159d09a2SMark Phalan     pkinit_fini_plg_opts(ctx->opts);
1408159d09a2SMark Phalan     free(ctx);
1409159d09a2SMark Phalan 
1410159d09a2SMark Phalan }
1411159d09a2SMark Phalan 
1412159d09a2SMark Phalan /* ARGSUSED */
1413159d09a2SMark Phalan static krb5_error_code
1414159d09a2SMark Phalan add_string_to_array(krb5_context context, char ***array, const char *addition)
1415159d09a2SMark Phalan {
1416159d09a2SMark Phalan     char **out = NULL;
1417159d09a2SMark Phalan 
1418159d09a2SMark Phalan     if (*array == NULL) {
1419159d09a2SMark Phalan 	out = malloc(2 * sizeof(char *));
1420159d09a2SMark Phalan 	if (out == NULL)
1421159d09a2SMark Phalan 	    return ENOMEM;
1422159d09a2SMark Phalan 	out[1] = NULL;
1423159d09a2SMark Phalan 	out[0] = strdup(addition);
1424159d09a2SMark Phalan 	if (out[0] == NULL) {
1425159d09a2SMark Phalan 	    free(out);
1426159d09a2SMark Phalan 	    return ENOMEM;
1427159d09a2SMark Phalan 	}
1428159d09a2SMark Phalan     } else {
1429159d09a2SMark Phalan 	int i;
1430159d09a2SMark Phalan 	char **a = *array;
1431159d09a2SMark Phalan 	for (i = 0; a[i] != NULL; i++);
1432159d09a2SMark Phalan 	out = malloc( (i + 2) * sizeof(char *));
1433159d09a2SMark Phalan 	if (out == NULL)
1434159d09a2SMark Phalan 	    return ENOMEM;
1435159d09a2SMark Phalan 	for (i = 0; a[i] != NULL; i++) {
1436159d09a2SMark Phalan 	    out[i] = a[i];
1437159d09a2SMark Phalan 	}
1438159d09a2SMark Phalan 	out[i++] = strdup(addition);
1439159d09a2SMark Phalan 	if (out == NULL) {
1440159d09a2SMark Phalan 	    free(out);
1441159d09a2SMark Phalan 	    return ENOMEM;
1442159d09a2SMark Phalan 	}
1443159d09a2SMark Phalan 	out[i] = NULL;
1444159d09a2SMark Phalan 	free(*array);
1445159d09a2SMark Phalan     }
1446159d09a2SMark Phalan     *array = out;
1447159d09a2SMark Phalan 
1448159d09a2SMark Phalan     return 0;
1449159d09a2SMark Phalan }
1450159d09a2SMark Phalan static krb5_error_code
1451159d09a2SMark Phalan handle_gic_opt(krb5_context context,
1452159d09a2SMark Phalan 	       struct _pkinit_context *plgctx,
1453159d09a2SMark Phalan 	       const char *attr,
1454159d09a2SMark Phalan 	       const char *value)
1455159d09a2SMark Phalan {
1456159d09a2SMark Phalan     krb5_error_code retval;
1457159d09a2SMark Phalan 
1458159d09a2SMark Phalan     if (strcmp(attr, "X509_user_identity") == 0) {
1459159d09a2SMark Phalan 	if (plgctx->idopts->identity != NULL) {
1460159d09a2SMark Phalan 	    krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
1461159d09a2SMark Phalan 		"X509_user_identity can not be given twice\n");
1462159d09a2SMark Phalan 	    return KRB5_PREAUTH_FAILED;
1463159d09a2SMark Phalan 	}
1464159d09a2SMark Phalan 	plgctx->idopts->identity = strdup(value);
1465159d09a2SMark Phalan 	if (plgctx->idopts->identity == NULL) {
1466159d09a2SMark Phalan 	    krb5_set_error_message(context, ENOMEM,
1467159d09a2SMark Phalan 		"Could not duplicate X509_user_identity value\n");
1468159d09a2SMark Phalan 	    return ENOMEM;
1469159d09a2SMark Phalan 	}
1470159d09a2SMark Phalan     } else if (strcmp(attr, "X509_anchors") == 0) {
1471159d09a2SMark Phalan 	retval = add_string_to_array(context, &plgctx->idopts->anchors, value);
1472159d09a2SMark Phalan 	if (retval)
1473159d09a2SMark Phalan 	    return retval;
1474159d09a2SMark Phalan     } else if (strcmp(attr, "flag_RSA_PROTOCOL") == 0) {
1475159d09a2SMark Phalan 	if (strcmp(value, "yes") == 0) {
1476159d09a2SMark Phalan 	    pkiDebug("Setting flag to use RSA_PROTOCOL\n");
1477159d09a2SMark Phalan 	    plgctx->opts->dh_or_rsa = RSA_PROTOCOL;
1478159d09a2SMark Phalan 	}
1479*488060a6SWill Fiveash     } else if (strcmp(attr, "PIN") == 0) {
1480*488060a6SWill Fiveash 	/* Solaris Kerberos: handle our PIN attr */
1481*488060a6SWill Fiveash 	plgctx->idopts->PIN = strdup(value);
1482*488060a6SWill Fiveash 	if (plgctx->idopts->PIN == NULL)
1483*488060a6SWill Fiveash 	    return ENOMEM;
1484159d09a2SMark Phalan     }
1485159d09a2SMark Phalan     return 0;
1486159d09a2SMark Phalan }
1487159d09a2SMark Phalan 
1488159d09a2SMark Phalan /* ARGSUSED */
1489159d09a2SMark Phalan static krb5_error_code
1490159d09a2SMark Phalan pkinit_client_gic_opt(krb5_context context,
1491159d09a2SMark Phalan 		      void *plugin_context,
1492159d09a2SMark Phalan 		      krb5_get_init_creds_opt *gic_opt,
1493159d09a2SMark Phalan 		      const char *attr,
1494159d09a2SMark Phalan 		      const char *value)
1495159d09a2SMark Phalan {
1496159d09a2SMark Phalan     krb5_error_code retval;
1497159d09a2SMark Phalan     struct _pkinit_context *plgctx = (struct _pkinit_context *)plugin_context;
1498159d09a2SMark Phalan 
1499159d09a2SMark Phalan     pkiDebug("(pkinit) received '%s' = '%s'\n", attr, value);
1500159d09a2SMark Phalan     retval = handle_gic_opt(context, plgctx, attr, value);
1501159d09a2SMark Phalan     if (retval)
1502159d09a2SMark Phalan 	return retval;
1503159d09a2SMark Phalan 
1504159d09a2SMark Phalan     return 0;
1505159d09a2SMark Phalan }
1506159d09a2SMark Phalan 
1507159d09a2SMark Phalan struct krb5plugin_preauth_client_ftable_v1 preauthentication_client_1 = {
1508159d09a2SMark Phalan     "pkinit",			/* name */
1509159d09a2SMark Phalan     supported_client_pa_types,	/* pa_type_list */
1510159d09a2SMark Phalan     NULL,			/* enctype_list */
1511159d09a2SMark Phalan     pkinit_client_plugin_init,	/* (*init) */
1512159d09a2SMark Phalan     pkinit_client_plugin_fini,	/* (*fini) */
1513159d09a2SMark Phalan     pkinit_client_get_flags,	/* (*flags) */
1514159d09a2SMark Phalan     pkinit_client_req_init,     /* (*client_req_init) */
1515159d09a2SMark Phalan     pkinit_client_req_fini,     /* (*client_req_fini) */
1516159d09a2SMark Phalan     pkinit_client_process,	/* (*process) */
1517159d09a2SMark Phalan     pkinit_client_tryagain,	/* (*tryagain) */
1518159d09a2SMark Phalan     pkinit_client_gic_opt	/* (*gic_opt) */
1519159d09a2SMark Phalan };
1520