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 
31159d09a2SMark Phalan #include <stdio.h>
32159d09a2SMark Phalan #include <stdlib.h>
33159d09a2SMark Phalan #include <errno.h>
34159d09a2SMark Phalan #include <string.h>
35159d09a2SMark Phalan 
36159d09a2SMark Phalan #include "pkinit.h"
37159d09a2SMark Phalan 
38159d09a2SMark Phalan static krb5_error_code
39159d09a2SMark Phalan pkinit_server_get_edata(krb5_context context,
40159d09a2SMark Phalan 			krb5_kdc_req * request,
41159d09a2SMark Phalan 			struct _krb5_db_entry_new * client,
42159d09a2SMark Phalan 			struct _krb5_db_entry_new * server,
43159d09a2SMark Phalan 			preauth_get_entry_data_proc server_get_entry_data,
44159d09a2SMark Phalan 			void *pa_plugin_context,
45159d09a2SMark Phalan 			krb5_pa_data * data);
46159d09a2SMark Phalan 
47159d09a2SMark Phalan static krb5_error_code
48159d09a2SMark Phalan pkinit_server_verify_padata(krb5_context context,
49159d09a2SMark Phalan 			    struct _krb5_db_entry_new * client,
50159d09a2SMark Phalan 			    krb5_data *req_pkt,
51159d09a2SMark Phalan 			    krb5_kdc_req * request,
52159d09a2SMark Phalan 			    krb5_enc_tkt_part * enc_tkt_reply,
53159d09a2SMark Phalan 			    krb5_pa_data * data,
54159d09a2SMark Phalan 			    preauth_get_entry_data_proc server_get_entry_data,
55159d09a2SMark Phalan 			    void *pa_plugin_context,
56159d09a2SMark Phalan 			    void **pa_request_context,
57159d09a2SMark Phalan 			    krb5_data **e_data,
58159d09a2SMark Phalan 			    krb5_authdata ***authz_data);
59159d09a2SMark Phalan 
60159d09a2SMark Phalan static krb5_error_code
61159d09a2SMark Phalan pkinit_server_return_padata(krb5_context context,
62159d09a2SMark Phalan 			    krb5_pa_data * padata,
63159d09a2SMark Phalan 			    struct _krb5_db_entry_new * client,
64159d09a2SMark Phalan 			    krb5_data *req_pkt,
65159d09a2SMark Phalan 			    krb5_kdc_req * request,
66159d09a2SMark Phalan 			    krb5_kdc_rep * reply,
67159d09a2SMark Phalan 			    struct _krb5_key_data * client_key,
68159d09a2SMark Phalan 			    krb5_keyblock * encrypting_key,
69159d09a2SMark Phalan 			    krb5_pa_data ** send_pa,
70159d09a2SMark Phalan 			    preauth_get_entry_data_proc server_get_entry_data,
71159d09a2SMark Phalan 			    void *pa_plugin_context,
72159d09a2SMark Phalan 			    void **pa_request_context);
73159d09a2SMark Phalan 
74159d09a2SMark Phalan static int pkinit_server_get_flags
75159d09a2SMark Phalan 	(krb5_context kcontext, krb5_preauthtype patype);
76159d09a2SMark Phalan 
77159d09a2SMark Phalan static krb5_error_code pkinit_init_kdc_req_context
78159d09a2SMark Phalan 	(krb5_context, void **blob);
79159d09a2SMark Phalan 
80159d09a2SMark Phalan static void pkinit_fini_kdc_req_context
81159d09a2SMark Phalan 	(krb5_context context, void *blob);
82159d09a2SMark Phalan 
83159d09a2SMark Phalan static int pkinit_server_plugin_init_realm
84159d09a2SMark Phalan 	(krb5_context context, const char *realmname,
85159d09a2SMark Phalan 	 pkinit_kdc_context *pplgctx);
86159d09a2SMark Phalan 
87159d09a2SMark Phalan static void pkinit_server_plugin_fini_realm
88159d09a2SMark Phalan 	(krb5_context context, pkinit_kdc_context plgctx);
89159d09a2SMark Phalan 
90159d09a2SMark Phalan static int pkinit_server_plugin_init
91159d09a2SMark Phalan 	(krb5_context context, void **blob, const char **realmnames);
92159d09a2SMark Phalan 
93159d09a2SMark Phalan static void pkinit_server_plugin_fini
94159d09a2SMark Phalan 	(krb5_context context, void *blob);
95159d09a2SMark Phalan 
96159d09a2SMark Phalan static pkinit_kdc_context pkinit_find_realm_context
97159d09a2SMark Phalan 	(krb5_context context, void *pa_plugin_context, krb5_principal princ);
98159d09a2SMark Phalan 
99159d09a2SMark Phalan static krb5_error_code
pkinit_create_edata(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,pkinit_plg_opts * opts,krb5_error_code err_code,krb5_data ** e_data)100159d09a2SMark Phalan pkinit_create_edata(krb5_context context,
101159d09a2SMark Phalan 		    pkinit_plg_crypto_context plg_cryptoctx,
102159d09a2SMark Phalan 		    pkinit_req_crypto_context req_cryptoctx,
103159d09a2SMark Phalan 		    pkinit_identity_crypto_context id_cryptoctx,
104159d09a2SMark Phalan 		    pkinit_plg_opts *opts,
105159d09a2SMark Phalan 		    krb5_error_code err_code,
106159d09a2SMark Phalan 		    krb5_data **e_data)
107159d09a2SMark Phalan {
108159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
109159d09a2SMark Phalan 
110159d09a2SMark Phalan     pkiDebug("pkinit_create_edata: creating edata for error %d (%s)\n",
111159d09a2SMark Phalan 	     err_code, error_message(err_code));
112159d09a2SMark Phalan     switch(err_code) {
113159d09a2SMark Phalan 	case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
114159d09a2SMark Phalan 	    retval = pkinit_create_td_trusted_certifiers(context,
115159d09a2SMark Phalan 		plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data);
116159d09a2SMark Phalan 	    break;
117159d09a2SMark Phalan 	case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
118159d09a2SMark Phalan 	    retval = pkinit_create_td_dh_parameters(context, plg_cryptoctx,
119159d09a2SMark Phalan 		req_cryptoctx, id_cryptoctx, opts, e_data);
120159d09a2SMark Phalan 	    break;
121159d09a2SMark Phalan 	case KRB5KDC_ERR_INVALID_CERTIFICATE:
122159d09a2SMark Phalan 	case KRB5KDC_ERR_REVOKED_CERTIFICATE:
123159d09a2SMark Phalan 	    retval = pkinit_create_td_invalid_certificate(context,
124159d09a2SMark Phalan 		plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data);
125159d09a2SMark Phalan 	    break;
126159d09a2SMark Phalan 	default:
127159d09a2SMark Phalan 	    pkiDebug("no edata needed for error %d (%s)\n",
128159d09a2SMark Phalan 		     err_code, error_message(err_code));
129159d09a2SMark Phalan 	    retval = 0;
130159d09a2SMark Phalan 	    goto cleanup;
131159d09a2SMark Phalan     }
132159d09a2SMark Phalan 
133159d09a2SMark Phalan cleanup:
134159d09a2SMark Phalan 
135159d09a2SMark Phalan     return retval;
136159d09a2SMark Phalan }
137159d09a2SMark Phalan 
138159d09a2SMark Phalan /* ARGSUSED */
139159d09a2SMark Phalan static krb5_error_code
pkinit_server_get_edata(krb5_context context,krb5_kdc_req * request,struct _krb5_db_entry_new * client,struct _krb5_db_entry_new * server,preauth_get_entry_data_proc server_get_entry_data,void * pa_plugin_context,krb5_pa_data * data)140159d09a2SMark Phalan pkinit_server_get_edata(krb5_context context,
141159d09a2SMark Phalan 			krb5_kdc_req * request,
142159d09a2SMark Phalan 			struct _krb5_db_entry_new * client,
143159d09a2SMark Phalan 			struct _krb5_db_entry_new * server,
144159d09a2SMark Phalan 			preauth_get_entry_data_proc server_get_entry_data,
145159d09a2SMark Phalan 			void *pa_plugin_context,
146159d09a2SMark Phalan 			krb5_pa_data * data)
147159d09a2SMark Phalan {
148159d09a2SMark Phalan     krb5_error_code retval = 0;
149159d09a2SMark Phalan     pkinit_kdc_context plgctx = NULL;
150159d09a2SMark Phalan 
151159d09a2SMark Phalan     pkiDebug("pkinit_server_get_edata: entered!\n");
152159d09a2SMark Phalan 
153159d09a2SMark Phalan     /*
154159d09a2SMark Phalan      * If we don't have a realm context for the given realm,
155*55fea89dSDan Cross      * don't tell the client that we support pkinit!
156159d09a2SMark Phalan      */
157159d09a2SMark Phalan     plgctx = pkinit_find_realm_context(context, pa_plugin_context,
158159d09a2SMark Phalan 				       request->server);
159159d09a2SMark Phalan     if (plgctx == NULL)
160159d09a2SMark Phalan 	retval = EINVAL;
161159d09a2SMark Phalan 
162159d09a2SMark Phalan     return retval;
163159d09a2SMark Phalan }
164159d09a2SMark Phalan 
165159d09a2SMark Phalan static krb5_error_code
verify_client_san(krb5_context context,pkinit_kdc_context plgctx,pkinit_kdc_req_context reqctx,krb5_principal client,int * valid_san)166159d09a2SMark Phalan verify_client_san(krb5_context context,
167159d09a2SMark Phalan 		  pkinit_kdc_context plgctx,
168159d09a2SMark Phalan 		  pkinit_kdc_req_context reqctx,
169159d09a2SMark Phalan 		  krb5_principal client,
170159d09a2SMark Phalan 		  int *valid_san)
171159d09a2SMark Phalan {
172159d09a2SMark Phalan     krb5_error_code retval;
173159d09a2SMark Phalan     krb5_principal *princs = NULL;
174159d09a2SMark Phalan     krb5_principal *upns = NULL;
175159d09a2SMark Phalan     int i;
176159d09a2SMark Phalan #ifdef DEBUG_SAN_INFO
177159d09a2SMark Phalan     char *client_string = NULL, *san_string;
178159d09a2SMark Phalan #endif
179*55fea89dSDan Cross 
180159d09a2SMark Phalan     retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx,
181159d09a2SMark Phalan 				       reqctx->cryptoctx, plgctx->idctx,
182159d09a2SMark Phalan 				       &princs,
183159d09a2SMark Phalan 				       plgctx->opts->allow_upn ? &upns : NULL,
184159d09a2SMark Phalan 				       NULL);
185159d09a2SMark Phalan     if (retval) {
186159d09a2SMark Phalan 	pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
187159d09a2SMark Phalan 	retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
188159d09a2SMark Phalan 	goto out;
189159d09a2SMark Phalan     }
190159d09a2SMark Phalan     /* XXX Verify this is consistent with client side XXX */
191159d09a2SMark Phalan #if 0
192159d09a2SMark Phalan     retval = call_san_checking_plugins(context, plgctx, reqctx, princs,
193159d09a2SMark Phalan 				       upns, NULL, &plugin_decision, &ignore);
194159d09a2SMark Phalan     pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
195159d09a2SMark Phalan 	     __FUNCTION__);
196159d09a2SMark Phalan     if (retval) {
197159d09a2SMark Phalan 	retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
198159d09a2SMark Phalan 	goto cleanup;
199159d09a2SMark Phalan     }
200159d09a2SMark Phalan     pkiDebug("%s: call_san_checking_plugins() returned decision %d\n",
201159d09a2SMark Phalan 	     __FUNCTION__, plugin_decision);
202159d09a2SMark Phalan     if (plugin_decision != NO_DECISION) {
203159d09a2SMark Phalan 	retval = plugin_decision;
204159d09a2SMark Phalan 	goto out;
205159d09a2SMark Phalan     }
206159d09a2SMark Phalan #endif
207159d09a2SMark Phalan 
208159d09a2SMark Phalan #ifdef DEBUG_SAN_INFO
209159d09a2SMark Phalan     krb5_unparse_name(context, client, &client_string);
210159d09a2SMark Phalan #endif
211159d09a2SMark Phalan     pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
212159d09a2SMark Phalan     for (i = 0; princs != NULL && princs[i] != NULL; i++) {
213159d09a2SMark Phalan #ifdef DEBUG_SAN_INFO
214159d09a2SMark Phalan 	krb5_unparse_name(context, princs[i], &san_string);
215159d09a2SMark Phalan 	pkiDebug("%s: Comparing client '%s' to pkinit san value '%s'\n",
216159d09a2SMark Phalan 		 __FUNCTION__, client_string, san_string);
217159d09a2SMark Phalan 	krb5_free_unparsed_name(context, san_string);
218159d09a2SMark Phalan #endif
219159d09a2SMark Phalan 	if (krb5_principal_compare(context, princs[i], client)) {
220159d09a2SMark Phalan 	    pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
221159d09a2SMark Phalan 	    *valid_san = 1;
222159d09a2SMark Phalan 	    retval = 0;
223159d09a2SMark Phalan 	    goto out;
224159d09a2SMark Phalan 	}
225159d09a2SMark Phalan     }
226159d09a2SMark Phalan     pkiDebug("%s: no pkinit san match found\n", __FUNCTION__);
227159d09a2SMark Phalan     /*
228159d09a2SMark Phalan      * XXX if cert has names but none match, should we
229159d09a2SMark Phalan      * be returning KRB5KDC_ERR_CLIENT_NAME_MISMATCH here?
230159d09a2SMark Phalan      */
231159d09a2SMark Phalan 
232159d09a2SMark Phalan     if (upns == NULL) {
233159d09a2SMark Phalan 	pkiDebug("%s: no upn sans (or we wouldn't accept them anyway)\n",
234159d09a2SMark Phalan 		 __FUNCTION__);
235159d09a2SMark Phalan 	retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
236159d09a2SMark Phalan 	goto out;
237159d09a2SMark Phalan     }
238159d09a2SMark Phalan 
239159d09a2SMark Phalan     pkiDebug("%s: Checking upn sans\n", __FUNCTION__);
240159d09a2SMark Phalan     for (i = 0; upns[i] != NULL; i++) {
241159d09a2SMark Phalan #ifdef DEBUG_SAN_INFO
242159d09a2SMark Phalan 	krb5_unparse_name(context, upns[i], &san_string);
243159d09a2SMark Phalan 	pkiDebug("%s: Comparing client '%s' to upn san value '%s'\n",
244159d09a2SMark Phalan 		 __FUNCTION__, client_string, san_string);
245159d09a2SMark Phalan 	krb5_free_unparsed_name(context, san_string);
246159d09a2SMark Phalan #endif
247159d09a2SMark Phalan 	if (krb5_principal_compare(context, upns[i], client)) {
248159d09a2SMark Phalan 	    pkiDebug("%s: upn san match found\n", __FUNCTION__);
249159d09a2SMark Phalan 	    *valid_san = 1;
250159d09a2SMark Phalan 	    retval = 0;
251159d09a2SMark Phalan 	    goto out;
252159d09a2SMark Phalan 	}
253159d09a2SMark Phalan     }
254159d09a2SMark Phalan     pkiDebug("%s: no upn san match found\n", __FUNCTION__);
255159d09a2SMark Phalan 
256159d09a2SMark Phalan     /* We found no match */
257159d09a2SMark Phalan     if (princs != NULL || upns != NULL) {
258159d09a2SMark Phalan 	*valid_san = 0;
259159d09a2SMark Phalan 	/* XXX ??? If there was one or more name in the cert, but
260159d09a2SMark Phalan 	 * none matched the client name, then return mismatch? */
261159d09a2SMark Phalan 	retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
262159d09a2SMark Phalan     }
263159d09a2SMark Phalan     retval = 0;
264159d09a2SMark Phalan 
265159d09a2SMark Phalan out:
266159d09a2SMark Phalan     if (princs != NULL) {
267159d09a2SMark Phalan 	for (i = 0; princs[i] != NULL; i++)
268159d09a2SMark Phalan 	    krb5_free_principal(context, princs[i]);
269159d09a2SMark Phalan 	free(princs);
270159d09a2SMark Phalan     }
271159d09a2SMark Phalan     if (upns != NULL) {
272159d09a2SMark Phalan 	for (i = 0; upns[i] != NULL; i++)
273159d09a2SMark Phalan 	    krb5_free_principal(context, upns[i]);
274159d09a2SMark Phalan 	free(upns);
275159d09a2SMark Phalan     }
276159d09a2SMark Phalan #ifdef DEBUG_SAN_INFO
277159d09a2SMark Phalan     if (client_string != NULL)
278159d09a2SMark Phalan 	krb5_free_unparsed_name(context, client_string);
279159d09a2SMark Phalan #endif
280159d09a2SMark Phalan     pkiDebug("%s: returning retval %d, valid_san %d\n",
281159d09a2SMark Phalan 	     __FUNCTION__, retval, *valid_san);
282159d09a2SMark Phalan     return retval;
283159d09a2SMark Phalan }
284159d09a2SMark Phalan 
285159d09a2SMark Phalan static krb5_error_code
verify_client_eku(krb5_context context,pkinit_kdc_context plgctx,pkinit_kdc_req_context reqctx,int * eku_accepted)286159d09a2SMark Phalan verify_client_eku(krb5_context context,
287159d09a2SMark Phalan 		  pkinit_kdc_context plgctx,
288159d09a2SMark Phalan 		  pkinit_kdc_req_context reqctx,
289159d09a2SMark Phalan 		  int *eku_accepted)
290159d09a2SMark Phalan {
291159d09a2SMark Phalan     krb5_error_code retval;
292159d09a2SMark Phalan 
293159d09a2SMark Phalan     *eku_accepted = 0;
294159d09a2SMark Phalan 
295159d09a2SMark Phalan     if (plgctx->opts->require_eku == 0) {
296159d09a2SMark Phalan 	pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__);
297159d09a2SMark Phalan 	*eku_accepted = 1;
298159d09a2SMark Phalan 	retval = 0;
299159d09a2SMark Phalan 	goto out;
300159d09a2SMark Phalan     }
301159d09a2SMark Phalan 
302159d09a2SMark Phalan     retval = crypto_check_cert_eku(context, plgctx->cryptoctx,
303159d09a2SMark Phalan 				   reqctx->cryptoctx, plgctx->idctx,
304159d09a2SMark Phalan 				   0, /* kdc cert */
305159d09a2SMark Phalan 				   plgctx->opts->accept_secondary_eku,
306159d09a2SMark Phalan 				   eku_accepted);
307159d09a2SMark Phalan     if (retval) {
308159d09a2SMark Phalan 	pkiDebug("%s: Error from crypto_check_cert_eku %d (%s)\n",
309159d09a2SMark Phalan 		 __FUNCTION__, retval, error_message(retval));
310159d09a2SMark Phalan 	goto out;
311159d09a2SMark Phalan     }
312159d09a2SMark Phalan 
313159d09a2SMark Phalan out:
314159d09a2SMark Phalan     pkiDebug("%s: returning retval %d, eku_accepted %d\n",
315159d09a2SMark Phalan 	     __FUNCTION__, retval, *eku_accepted);
316159d09a2SMark Phalan     return retval;
317159d09a2SMark Phalan }
318159d09a2SMark Phalan 
319159d09a2SMark Phalan /* ARGSUSED */
320159d09a2SMark Phalan static krb5_error_code
pkinit_server_verify_padata(krb5_context context,struct _krb5_db_entry_new * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * data,preauth_get_entry_data_proc server_get_entry_data,void * pa_plugin_context,void ** pa_request_context,krb5_data ** e_data,krb5_authdata *** authz_data)321159d09a2SMark Phalan pkinit_server_verify_padata(krb5_context context,
322159d09a2SMark Phalan 			    struct _krb5_db_entry_new * client,
323159d09a2SMark Phalan 			    krb5_data *req_pkt,
324159d09a2SMark Phalan 			    krb5_kdc_req * request,
325159d09a2SMark Phalan 			    krb5_enc_tkt_part * enc_tkt_reply,
326159d09a2SMark Phalan 			    krb5_pa_data * data,
327159d09a2SMark Phalan 			    preauth_get_entry_data_proc server_get_entry_data,
328159d09a2SMark Phalan 			    void *pa_plugin_context,
329159d09a2SMark Phalan 			    void **pa_request_context,
330159d09a2SMark Phalan 			    krb5_data **e_data,
331159d09a2SMark Phalan 			    krb5_authdata ***authz_data)
332159d09a2SMark Phalan {
333*55fea89dSDan Cross     krb5_error_code retval = 0;
334159d09a2SMark Phalan     krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
335159d09a2SMark Phalan     krb5_data *encoded_pkinit_authz_data = NULL;
336159d09a2SMark Phalan     krb5_pa_pk_as_req *reqp = NULL;
337159d09a2SMark Phalan     krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
338159d09a2SMark Phalan     krb5_auth_pack *auth_pack = NULL;
339159d09a2SMark Phalan     krb5_auth_pack_draft9 *auth_pack9 = NULL;
340159d09a2SMark Phalan     pkinit_kdc_context plgctx = NULL;
341159d09a2SMark Phalan     pkinit_kdc_req_context reqctx;
342159d09a2SMark Phalan /* Solaris Kerberos: set but not used */
343159d09a2SMark Phalan #if 0
344159d09a2SMark Phalan     krb5_preauthtype pa_type;
345159d09a2SMark Phalan #endif
346159d09a2SMark Phalan     krb5_checksum cksum = {0, 0, 0, NULL};
347159d09a2SMark Phalan     krb5_data *der_req = NULL;
348159d09a2SMark Phalan     int valid_eku = 0, valid_san = 0;
349159d09a2SMark Phalan     krb5_authdata **my_authz_data = NULL, *pkinit_authz_data = NULL;
350159d09a2SMark Phalan     krb5_kdc_req *tmp_as_req = NULL;
351159d09a2SMark Phalan     krb5_data k5data;
352159d09a2SMark Phalan 
353159d09a2SMark Phalan     pkiDebug("pkinit_verify_padata: entered!\n");
354159d09a2SMark Phalan     /* Solaris Kerberos */
355159d09a2SMark Phalan     if (data == NULL || data->length == 0 || data->contents == NULL)
356159d09a2SMark Phalan 	return 0;
357159d09a2SMark Phalan 
358159d09a2SMark Phalan     if (pa_plugin_context == NULL || e_data == NULL)
359159d09a2SMark Phalan 	return EINVAL;
360159d09a2SMark Phalan 
361159d09a2SMark Phalan     plgctx = pkinit_find_realm_context(context, pa_plugin_context,
362159d09a2SMark Phalan 				       request->server);
363159d09a2SMark Phalan     if (plgctx == NULL)
364159d09a2SMark Phalan 	return 0;
365159d09a2SMark Phalan 
366159d09a2SMark Phalan #ifdef DEBUG_ASN1
367159d09a2SMark Phalan     print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
368159d09a2SMark Phalan #endif
369159d09a2SMark Phalan     /* create a per-request context */
370159d09a2SMark Phalan     retval = pkinit_init_kdc_req_context(context, (void **)&reqctx);
371159d09a2SMark Phalan     if (retval)
372159d09a2SMark Phalan 	goto cleanup;
373159d09a2SMark Phalan     reqctx->pa_type = data->pa_type;
374159d09a2SMark Phalan 
375159d09a2SMark Phalan     PADATA_TO_KRB5DATA(data, &k5data);
376159d09a2SMark Phalan 
377159d09a2SMark Phalan     switch ((int)data->pa_type) {
378159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
379159d09a2SMark Phalan 	    pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
380159d09a2SMark Phalan 	    retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
381159d09a2SMark Phalan 	    if (retval) {
382159d09a2SMark Phalan 		pkiDebug("decode_krb5_pa_pk_as_req failed\n");
383159d09a2SMark Phalan 		goto cleanup;
384159d09a2SMark Phalan 	    }
385159d09a2SMark Phalan #ifdef DEBUG_ASN1
386159d09a2SMark Phalan 	    print_buffer_bin(reqp->signedAuthPack.data,
387159d09a2SMark Phalan 			     reqp->signedAuthPack.length,
388159d09a2SMark Phalan 			     "/tmp/kdc_signed_data");
389159d09a2SMark Phalan #endif
390159d09a2SMark Phalan 	    retval = cms_signeddata_verify(context, plgctx->cryptoctx,
391159d09a2SMark Phalan 		reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_CLIENT,
392159d09a2SMark Phalan 		plgctx->opts->require_crl_checking,
393159d09a2SMark Phalan 		reqp->signedAuthPack.data, reqp->signedAuthPack.length,
394*55fea89dSDan Cross 		&authp_data.data, &authp_data.length, &krb5_authz.data,
395159d09a2SMark Phalan 		&krb5_authz.length);
396159d09a2SMark Phalan 	    break;
397159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
398159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
399159d09a2SMark Phalan 	    pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
400159d09a2SMark Phalan 	    retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
401159d09a2SMark Phalan 	    if (retval) {
402159d09a2SMark Phalan 		pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
403159d09a2SMark Phalan 		goto cleanup;
404159d09a2SMark Phalan 	    }
405159d09a2SMark Phalan #ifdef DEBUG_ASN1
406159d09a2SMark Phalan 	    print_buffer_bin(reqp9->signedAuthPack.data,
407159d09a2SMark Phalan 			     reqp9->signedAuthPack.length,
408159d09a2SMark Phalan 			     "/tmp/kdc_signed_data_draft9");
409159d09a2SMark Phalan #endif
410159d09a2SMark Phalan 
411159d09a2SMark Phalan 	    retval = cms_signeddata_verify(context, plgctx->cryptoctx,
412159d09a2SMark Phalan 		reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9,
413159d09a2SMark Phalan 		plgctx->opts->require_crl_checking,
414159d09a2SMark Phalan 		reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
415*55fea89dSDan Cross 		&authp_data.data, &authp_data.length, &krb5_authz.data,
416159d09a2SMark Phalan 		&krb5_authz.length);
417159d09a2SMark Phalan 	    break;
418159d09a2SMark Phalan 	default:
419159d09a2SMark Phalan 	    pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
420159d09a2SMark Phalan 	    retval = EINVAL;
421159d09a2SMark Phalan 	    goto cleanup;
422159d09a2SMark Phalan     }
423159d09a2SMark Phalan     if (retval) {
424159d09a2SMark Phalan 	pkiDebug("pkcs7_signeddata_verify failed\n");
425159d09a2SMark Phalan 	goto cleanup;
426159d09a2SMark Phalan     }
427159d09a2SMark Phalan 
428159d09a2SMark Phalan     retval = verify_client_san(context, plgctx, reqctx, request->client,
429159d09a2SMark Phalan 			       &valid_san);
430159d09a2SMark Phalan     if (retval)
431159d09a2SMark Phalan 	goto cleanup;
432159d09a2SMark Phalan     if (!valid_san) {
433159d09a2SMark Phalan 	pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
434159d09a2SMark Phalan 		 __FUNCTION__);
435159d09a2SMark Phalan 	retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
436159d09a2SMark Phalan 	goto cleanup;
437159d09a2SMark Phalan     }
438159d09a2SMark Phalan     retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
439159d09a2SMark Phalan     if (retval)
440159d09a2SMark Phalan 	goto cleanup;
441159d09a2SMark Phalan 
442159d09a2SMark Phalan     if (!valid_eku) {
443159d09a2SMark Phalan 	pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
444159d09a2SMark Phalan 		 __FUNCTION__);
445159d09a2SMark Phalan 	retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
446159d09a2SMark Phalan 	goto cleanup;
447159d09a2SMark Phalan     }
448159d09a2SMark Phalan 
449159d09a2SMark Phalan #ifdef DEBUG_ASN1
450159d09a2SMark Phalan     print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
451159d09a2SMark Phalan #endif
452159d09a2SMark Phalan 
453159d09a2SMark Phalan     OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
454159d09a2SMark Phalan     switch ((int)data->pa_type) {
455159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
456159d09a2SMark Phalan 	    retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
457159d09a2SMark Phalan 	    if (retval) {
458159d09a2SMark Phalan 		pkiDebug("failed to decode krb5_auth_pack\n");
459159d09a2SMark Phalan 		goto cleanup;
460159d09a2SMark Phalan 	    }
461159d09a2SMark Phalan 
462159d09a2SMark Phalan 	    /* check dh parameters */
463*55fea89dSDan Cross 	    if (auth_pack->clientPublicValue != NULL) {
464159d09a2SMark Phalan 		retval = server_check_dh(context, plgctx->cryptoctx,
465159d09a2SMark Phalan 		    reqctx->cryptoctx, plgctx->idctx,
466159d09a2SMark Phalan 		    &auth_pack->clientPublicValue->algorithm.parameters,
467159d09a2SMark Phalan 		    plgctx->opts->dh_min_bits);
468159d09a2SMark Phalan 
469159d09a2SMark Phalan 		if (retval) {
470159d09a2SMark Phalan 		    pkiDebug("bad dh parameters\n");
471159d09a2SMark Phalan 		    goto cleanup;
472159d09a2SMark Phalan 		}
473159d09a2SMark Phalan 	    }
474159d09a2SMark Phalan 	    /*
475159d09a2SMark Phalan 	     * The KDC may have modified the request after decoding it.
476159d09a2SMark Phalan 	     * We need to compute the checksum on the data that
477159d09a2SMark Phalan 	     * came from the client.  Therefore, we use the original
478159d09a2SMark Phalan 	     * packet contents.
479159d09a2SMark Phalan 	     */
480*55fea89dSDan Cross 	    retval = k5int_decode_krb5_as_req(req_pkt, &tmp_as_req);
481159d09a2SMark Phalan 	    if (retval) {
482159d09a2SMark Phalan 		pkiDebug("decode_krb5_as_req returned %d\n", (int)retval);
483159d09a2SMark Phalan 		goto cleanup;
484159d09a2SMark Phalan 	    }
485*55fea89dSDan Cross 
486159d09a2SMark Phalan 	    retval = k5int_encode_krb5_kdc_req_body(tmp_as_req, &der_req);
487159d09a2SMark Phalan 	    if (retval) {
488159d09a2SMark Phalan 		pkiDebug("encode_krb5_kdc_req_body returned %d\n", (int) retval);
489159d09a2SMark Phalan 		goto cleanup;
490159d09a2SMark Phalan 	    }
491159d09a2SMark Phalan 	    retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
492159d09a2SMark Phalan 					  0, der_req, &cksum);
493159d09a2SMark Phalan 	    if (retval) {
494159d09a2SMark Phalan 		pkiDebug("unable to calculate AS REQ checksum\n");
495159d09a2SMark Phalan 		goto cleanup;
496159d09a2SMark Phalan 	    }
497159d09a2SMark Phalan 	    if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
498159d09a2SMark Phalan 		memcmp(cksum.contents,
499159d09a2SMark Phalan 		       auth_pack->pkAuthenticator.paChecksum.contents,
500159d09a2SMark Phalan 		       cksum.length)) {
501159d09a2SMark Phalan 		pkiDebug("failed to match the checksum\n");
502159d09a2SMark Phalan #ifdef DEBUG_CKSUM
503159d09a2SMark Phalan 		pkiDebug("calculating checksum on buf size (%d)\n",
504159d09a2SMark Phalan 			 req_pkt->length);
505159d09a2SMark Phalan 		print_buffer(req_pkt->data, req_pkt->length);
506159d09a2SMark Phalan 		pkiDebug("received checksum type=%d size=%d ",
507159d09a2SMark Phalan 			auth_pack->pkAuthenticator.paChecksum.checksum_type,
508159d09a2SMark Phalan 			auth_pack->pkAuthenticator.paChecksum.length);
509159d09a2SMark Phalan 		print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
510159d09a2SMark Phalan 			     auth_pack->pkAuthenticator.paChecksum.length);
511159d09a2SMark Phalan 		pkiDebug("expected checksum type=%d size=%d ",
512159d09a2SMark Phalan 			 cksum.checksum_type, cksum.length);
513159d09a2SMark Phalan 		print_buffer(cksum.contents, cksum.length);
514159d09a2SMark Phalan #endif
515159d09a2SMark Phalan 
516159d09a2SMark Phalan 		retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
517159d09a2SMark Phalan 		goto cleanup;
518159d09a2SMark Phalan 	    }
519159d09a2SMark Phalan 
520159d09a2SMark Phalan 	    /* check if kdcPkId present and match KDC's subjectIdentifier */
521159d09a2SMark Phalan 	    if (reqp->kdcPkId.data != NULL) {
522159d09a2SMark Phalan 		int valid_kdcPkId = 0;
523159d09a2SMark Phalan 		retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
524159d09a2SMark Phalan 		    reqctx->cryptoctx, plgctx->idctx,
525159d09a2SMark Phalan 		    reqp->kdcPkId.data, reqp->kdcPkId.length, &valid_kdcPkId);
526159d09a2SMark Phalan 		if (retval)
527159d09a2SMark Phalan 		    goto cleanup;
528159d09a2SMark Phalan 		if (!valid_kdcPkId)
529159d09a2SMark Phalan 		    pkiDebug("kdcPkId in AS_REQ does not match KDC's cert"
530159d09a2SMark Phalan 			     "RFC says to ignore and proceed\n");
531159d09a2SMark Phalan 
532159d09a2SMark Phalan 	    }
533159d09a2SMark Phalan 	    /* remember the decoded auth_pack for verify_padata routine */
534159d09a2SMark Phalan 	    reqctx->rcv_auth_pack = auth_pack;
535159d09a2SMark Phalan 	    auth_pack = NULL;
536159d09a2SMark Phalan 	    break;
537159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
538159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
539159d09a2SMark Phalan 	    retval = k5int_decode_krb5_auth_pack_draft9(&k5data, &auth_pack9);
540159d09a2SMark Phalan 	    if (retval) {
541159d09a2SMark Phalan 		pkiDebug("failed to decode krb5_auth_pack_draft9\n");
542159d09a2SMark Phalan 		goto cleanup;
543159d09a2SMark Phalan 	    }
544*55fea89dSDan Cross 	    if (auth_pack9->clientPublicValue != NULL) {
545159d09a2SMark Phalan 		retval = server_check_dh(context, plgctx->cryptoctx,
546159d09a2SMark Phalan 		    reqctx->cryptoctx, plgctx->idctx,
547159d09a2SMark Phalan 		    &auth_pack9->clientPublicValue->algorithm.parameters,
548159d09a2SMark Phalan 		    plgctx->opts->dh_min_bits);
549159d09a2SMark Phalan 
550159d09a2SMark Phalan 		if (retval) {
551159d09a2SMark Phalan 		    pkiDebug("bad dh parameters\n");
552159d09a2SMark Phalan 		    goto cleanup;
553159d09a2SMark Phalan 		}
554159d09a2SMark Phalan 	    }
555159d09a2SMark Phalan 	    /* remember the decoded auth_pack for verify_padata routine */
556159d09a2SMark Phalan 	    reqctx->rcv_auth_pack9 = auth_pack9;
557159d09a2SMark Phalan 	    auth_pack9 = NULL;
558159d09a2SMark Phalan 	    break;
559159d09a2SMark Phalan     }
560159d09a2SMark Phalan 
561159d09a2SMark Phalan     /* return authorization data to be included in the ticket */
562159d09a2SMark Phalan     switch ((int)data->pa_type) {
563159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
564159d09a2SMark Phalan 	    my_authz_data = malloc(2 * sizeof(*my_authz_data));
565159d09a2SMark Phalan 	    if (my_authz_data == NULL) {
566159d09a2SMark Phalan 		retval = ENOMEM;
567159d09a2SMark Phalan 		pkiDebug("Couldn't allocate krb5_authdata ptr array\n");
568159d09a2SMark Phalan 		goto cleanup;
569159d09a2SMark Phalan 	    }
570159d09a2SMark Phalan 	    my_authz_data[1] = NULL;
571159d09a2SMark Phalan 	    my_authz_data[0] = malloc(sizeof(krb5_authdata));
572159d09a2SMark Phalan 	    if (my_authz_data[0] == NULL) {
573159d09a2SMark Phalan 		retval = ENOMEM;
574159d09a2SMark Phalan 		pkiDebug("Couldn't allocate krb5_authdata\n");
575159d09a2SMark Phalan 		free(my_authz_data);
576159d09a2SMark Phalan 		goto cleanup;
577159d09a2SMark Phalan 	    }
578159d09a2SMark Phalan 	    /* AD-INITIAL-VERIFIED-CAS must be wrapped in AD-IF-RELEVANT */
579159d09a2SMark Phalan 	    my_authz_data[0]->magic = KV5M_AUTHDATA;
580159d09a2SMark Phalan 	    my_authz_data[0]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
581159d09a2SMark Phalan 
582159d09a2SMark Phalan 	    /* create an internal AD-INITIAL-VERIFIED-CAS data */
583159d09a2SMark Phalan 	    pkinit_authz_data = malloc(sizeof(krb5_authdata));
584159d09a2SMark Phalan 	    if (pkinit_authz_data == NULL) {
585159d09a2SMark Phalan 		retval = ENOMEM;
586159d09a2SMark Phalan 		pkiDebug("Couldn't allocate krb5_authdata\n");
587159d09a2SMark Phalan 		free(my_authz_data[0]);
588159d09a2SMark Phalan 		free(my_authz_data);
589159d09a2SMark Phalan 		goto cleanup;
590159d09a2SMark Phalan 	    }
591159d09a2SMark Phalan 	    pkinit_authz_data->ad_type = KRB5_AUTHDATA_INITIAL_VERIFIED_CAS;
592159d09a2SMark Phalan 	    /* content of this ad-type contains the certification
593159d09a2SMark Phalan 	       path with which the client certificate was validated
594159d09a2SMark Phalan 	     */
595159d09a2SMark Phalan 	    pkinit_authz_data->contents = krb5_authz.data;
596159d09a2SMark Phalan 	    pkinit_authz_data->length = krb5_authz.length;
597*55fea89dSDan Cross 	    retval = k5int_encode_krb5_authdata_elt(pkinit_authz_data,
598159d09a2SMark Phalan 			    &encoded_pkinit_authz_data);
599159d09a2SMark Phalan #ifdef DEBUG_ASN1
600159d09a2SMark Phalan 	    print_buffer_bin((unsigned char *)encoded_pkinit_authz_data->data,
601159d09a2SMark Phalan 			     encoded_pkinit_authz_data->length,
602159d09a2SMark Phalan 			     "/tmp/kdc_pkinit_authz_data");
603159d09a2SMark Phalan #endif
604159d09a2SMark Phalan 	    free(pkinit_authz_data);
605159d09a2SMark Phalan 	    if (retval) {
606159d09a2SMark Phalan 		pkiDebug("k5int_encode_krb5_authdata_elt failed\n");
607159d09a2SMark Phalan 		free(my_authz_data[0]);
608159d09a2SMark Phalan 		free(my_authz_data);
609159d09a2SMark Phalan 		goto cleanup;
610159d09a2SMark Phalan 	    }
611159d09a2SMark Phalan 
612159d09a2SMark Phalan 	    my_authz_data[0]->contents =
613159d09a2SMark Phalan 			    (krb5_octet *) encoded_pkinit_authz_data->data;
614159d09a2SMark Phalan 	    my_authz_data[0]->length = encoded_pkinit_authz_data->length;
615159d09a2SMark Phalan 	    *authz_data = my_authz_data;
616*55fea89dSDan Cross 	    pkiDebug("Returning %d bytes of authorization data\n",
617159d09a2SMark Phalan 		     krb5_authz.length);
618159d09a2SMark Phalan 	    encoded_pkinit_authz_data->data = NULL; /* Don't free during cleanup*/
619159d09a2SMark Phalan 	    free(encoded_pkinit_authz_data);
620159d09a2SMark Phalan 	    break;
621*55fea89dSDan Cross 	default:
622159d09a2SMark Phalan 	    *authz_data = NULL;
623159d09a2SMark Phalan     }
624159d09a2SMark Phalan     /* remember to set the PREAUTH flag in the reply */
625159d09a2SMark Phalan     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
626159d09a2SMark Phalan     *pa_request_context = reqctx;
627159d09a2SMark Phalan     reqctx = NULL;
628159d09a2SMark Phalan 
629159d09a2SMark Phalan   cleanup:
630159d09a2SMark Phalan     if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
631159d09a2SMark Phalan 	pkiDebug("pkinit_verify_padata failed: creating e-data\n");
632159d09a2SMark Phalan 	if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
633159d09a2SMark Phalan 		plgctx->idctx, plgctx->opts, retval, e_data))
634159d09a2SMark Phalan 	    pkiDebug("pkinit_create_edata failed\n");
635159d09a2SMark Phalan     }
636159d09a2SMark Phalan 
637159d09a2SMark Phalan     switch ((int)data->pa_type) {
638159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
639159d09a2SMark Phalan 	    free_krb5_pa_pk_as_req(&reqp);
640159d09a2SMark Phalan 	    if (cksum.contents != NULL)
641159d09a2SMark Phalan 		free(cksum.contents);
642159d09a2SMark Phalan 	    if (der_req != NULL)
643159d09a2SMark Phalan 		 krb5_free_data(context, der_req);
644159d09a2SMark Phalan 	    break;
645159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
646159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
647159d09a2SMark Phalan 	    free_krb5_pa_pk_as_req_draft9(&reqp9);
648159d09a2SMark Phalan     }
649159d09a2SMark Phalan     if (tmp_as_req != NULL)
650*55fea89dSDan Cross 	k5int_krb5_free_kdc_req(context, tmp_as_req);
651159d09a2SMark Phalan     if (authp_data.data != NULL)
652159d09a2SMark Phalan 	free(authp_data.data);
653159d09a2SMark Phalan     if (krb5_authz.data != NULL)
654159d09a2SMark Phalan 	free(krb5_authz.data);
655159d09a2SMark Phalan     if (reqctx != NULL)
656159d09a2SMark Phalan 	pkinit_fini_kdc_req_context(context, reqctx);
657159d09a2SMark Phalan     if (auth_pack != NULL)
658159d09a2SMark Phalan 	free_krb5_auth_pack(&auth_pack);
659159d09a2SMark Phalan     if (auth_pack9 != NULL)
660159d09a2SMark Phalan 	free_krb5_auth_pack_draft9(context, &auth_pack9);
661159d09a2SMark Phalan 
662159d09a2SMark Phalan     return retval;
663159d09a2SMark Phalan }
664159d09a2SMark Phalan 
665159d09a2SMark Phalan /* ARGSUSED */
666159d09a2SMark Phalan static krb5_error_code
pkinit_server_return_padata(krb5_context context,krb5_pa_data * padata,struct _krb5_db_entry_new * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,struct _krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc server_get_entry_data,void * pa_plugin_context,void ** pa_request_context)667159d09a2SMark Phalan pkinit_server_return_padata(krb5_context context,
668159d09a2SMark Phalan 			    krb5_pa_data * padata,
669159d09a2SMark Phalan 			    struct _krb5_db_entry_new * client,
670159d09a2SMark Phalan 			    krb5_data *req_pkt,
671159d09a2SMark Phalan 			    krb5_kdc_req * request,
672159d09a2SMark Phalan 			    krb5_kdc_rep * reply,
673159d09a2SMark Phalan 			    struct _krb5_key_data * client_key,
674159d09a2SMark Phalan 			    krb5_keyblock * encrypting_key,
675159d09a2SMark Phalan 			    krb5_pa_data ** send_pa,
676159d09a2SMark Phalan 			    preauth_get_entry_data_proc server_get_entry_data,
677159d09a2SMark Phalan 			    void *pa_plugin_context,
678159d09a2SMark Phalan 			    void **pa_request_context)
679159d09a2SMark Phalan {
680159d09a2SMark Phalan     krb5_error_code retval = 0;
681159d09a2SMark Phalan     krb5_data scratch = {0, 0, NULL};
682159d09a2SMark Phalan     krb5_pa_pk_as_req *reqp = NULL;
683159d09a2SMark Phalan     krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
684159d09a2SMark Phalan     int i = 0;
685159d09a2SMark Phalan 
686159d09a2SMark Phalan     unsigned char *subjectPublicKey = NULL;
687159d09a2SMark Phalan     unsigned char *dh_pubkey = NULL, *server_key = NULL;
688159d09a2SMark Phalan     unsigned int subjectPublicKey_len = 0;
689159d09a2SMark Phalan     unsigned int server_key_len = 0, dh_pubkey_len = 0;
690159d09a2SMark Phalan 
691159d09a2SMark Phalan     krb5_kdc_dh_key_info dhkey_info;
692159d09a2SMark Phalan     krb5_data *encoded_dhkey_info = NULL;
693159d09a2SMark Phalan     krb5_pa_pk_as_rep *rep = NULL;
694159d09a2SMark Phalan     krb5_pa_pk_as_rep_draft9 *rep9 = NULL;
695159d09a2SMark Phalan     krb5_data *out_data = NULL;
696159d09a2SMark Phalan 
697159d09a2SMark Phalan     krb5_enctype enctype = -1;
698159d09a2SMark Phalan 
699159d09a2SMark Phalan     krb5_reply_key_pack *key_pack = NULL;
700159d09a2SMark Phalan     krb5_reply_key_pack_draft9 *key_pack9 = NULL;
701159d09a2SMark Phalan     krb5_data *encoded_key_pack = NULL;
702159d09a2SMark Phalan     unsigned int num_types;
703159d09a2SMark Phalan     krb5_cksumtype *cksum_types = NULL;
704159d09a2SMark Phalan 
705159d09a2SMark Phalan     pkinit_kdc_context plgctx;
706159d09a2SMark Phalan     pkinit_kdc_req_context reqctx;
707159d09a2SMark Phalan 
708159d09a2SMark Phalan     int fixed_keypack = 0;
709159d09a2SMark Phalan 
710159d09a2SMark Phalan     *send_pa = NULL;
711159d09a2SMark Phalan     /* Solaris Kerberos */
712159d09a2SMark Phalan     if (padata == NULL || padata->length == 0 || padata->contents == NULL)
713159d09a2SMark Phalan 	return 0;
714159d09a2SMark Phalan 
715159d09a2SMark Phalan     if (pa_request_context == NULL || *pa_request_context == NULL) {
716159d09a2SMark Phalan 	pkiDebug("missing request context \n");
717159d09a2SMark Phalan 	return EINVAL;
718159d09a2SMark Phalan     }
719*55fea89dSDan Cross 
720159d09a2SMark Phalan     plgctx = pkinit_find_realm_context(context, pa_plugin_context,
721159d09a2SMark Phalan 				       request->server);
722159d09a2SMark Phalan     if (plgctx == NULL) {
723159d09a2SMark Phalan 	pkiDebug("Unable to locate correct realm context\n");
724159d09a2SMark Phalan 	return ENOENT;
725159d09a2SMark Phalan     }
726159d09a2SMark Phalan 
727159d09a2SMark Phalan     pkiDebug("pkinit_return_padata: entered!\n");
728159d09a2SMark Phalan     reqctx = (pkinit_kdc_req_context)*pa_request_context;
729159d09a2SMark Phalan 
730159d09a2SMark Phalan     if (encrypting_key->contents) {
731159d09a2SMark Phalan 	free(encrypting_key->contents);
732159d09a2SMark Phalan 	encrypting_key->length = 0;
733159d09a2SMark Phalan 	encrypting_key->contents = NULL;
734159d09a2SMark Phalan     }
735159d09a2SMark Phalan 
736159d09a2SMark Phalan     for(i = 0; i < request->nktypes; i++) {
737159d09a2SMark Phalan 	enctype = request->ktype[i];
738159d09a2SMark Phalan 	if (!krb5_c_valid_enctype(enctype))
739159d09a2SMark Phalan 	    continue;
740159d09a2SMark Phalan 	else {
741159d09a2SMark Phalan 	    pkiDebug("KDC picked etype = %d\n", enctype);
742159d09a2SMark Phalan 	    break;
743159d09a2SMark Phalan 	}
744159d09a2SMark Phalan     }
745159d09a2SMark Phalan 
746159d09a2SMark Phalan     if (i == request->nktypes) {
747159d09a2SMark Phalan 	retval = KRB5KDC_ERR_ETYPE_NOSUPP;
748159d09a2SMark Phalan 	goto cleanup;
749159d09a2SMark Phalan     }
750159d09a2SMark Phalan 
751159d09a2SMark Phalan     switch((int)reqctx->pa_type) {
752159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
753159d09a2SMark Phalan 	    init_krb5_pa_pk_as_rep(&rep);
754159d09a2SMark Phalan 	    if (rep == NULL) {
755159d09a2SMark Phalan 		retval = ENOMEM;
756159d09a2SMark Phalan 		goto cleanup;
757159d09a2SMark Phalan 	    }
758159d09a2SMark Phalan 	    /* let's assume it's RSA. we'll reset it to DH if needed */
759159d09a2SMark Phalan 	    rep->choice = choice_pa_pk_as_rep_encKeyPack;
760159d09a2SMark Phalan 	    break;
761159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
762159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
763159d09a2SMark Phalan 	    init_krb5_pa_pk_as_rep_draft9(&rep9);
764159d09a2SMark Phalan 	    if (rep9 == NULL) {
765159d09a2SMark Phalan 		retval = ENOMEM;
766159d09a2SMark Phalan 		goto cleanup;
767159d09a2SMark Phalan 	    }
768159d09a2SMark Phalan 	    rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
769159d09a2SMark Phalan 	    break;
770159d09a2SMark Phalan 	default:
771159d09a2SMark Phalan 	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
772159d09a2SMark Phalan 	    goto cleanup;
773159d09a2SMark Phalan     }
774159d09a2SMark Phalan 
775159d09a2SMark Phalan     if (reqctx->rcv_auth_pack != NULL &&
776159d09a2SMark Phalan 	    reqctx->rcv_auth_pack->clientPublicValue != NULL) {
777159d09a2SMark Phalan 	subjectPublicKey =
778159d09a2SMark Phalan 	    reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
779159d09a2SMark Phalan 	subjectPublicKey_len =
780159d09a2SMark Phalan 	    reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
781159d09a2SMark Phalan 	rep->choice = choice_pa_pk_as_rep_dhInfo;
782159d09a2SMark Phalan     } else if (reqctx->rcv_auth_pack9 != NULL &&
783159d09a2SMark Phalan 		reqctx->rcv_auth_pack9->clientPublicValue != NULL) {
784159d09a2SMark Phalan 	subjectPublicKey =
785159d09a2SMark Phalan 	    reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.data;
786159d09a2SMark Phalan 	subjectPublicKey_len =
787159d09a2SMark Phalan 	    reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length;
788159d09a2SMark Phalan 	rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
789159d09a2SMark Phalan     }
790159d09a2SMark Phalan 
791159d09a2SMark Phalan     /* if this DH, then process finish computing DH key */
7922c2d21e9SRichard Lowe     if (((rep != NULL) && (rep->choice == choice_pa_pk_as_rep_dhInfo)) ||
7932c2d21e9SRichard Lowe 	((rep9 != NULL) && rep9->choice ==
7942c2d21e9SRichard Lowe 	    choice_pa_pk_as_rep_draft9_dhSignedData)) {
795159d09a2SMark Phalan 	pkiDebug("received DH key delivery AS REQ\n");
796159d09a2SMark Phalan 	retval = server_process_dh(context, plgctx->cryptoctx,
797159d09a2SMark Phalan 	    reqctx->cryptoctx, plgctx->idctx, subjectPublicKey,
798*55fea89dSDan Cross 	    subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len,
799159d09a2SMark Phalan 	    &server_key, &server_key_len);
800159d09a2SMark Phalan 	if (retval) {
801159d09a2SMark Phalan 	    pkiDebug("failed to process/create dh paramters\n");
802159d09a2SMark Phalan 	    goto cleanup;
803159d09a2SMark Phalan 	}
804159d09a2SMark Phalan     }
805*55fea89dSDan Cross 
806159d09a2SMark Phalan     if ((rep9 != NULL &&
807159d09a2SMark Phalan 	    rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
808159d09a2SMark Phalan 	(rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
809159d09a2SMark Phalan 	retval = pkinit_octetstring2key(context, enctype, server_key,
810159d09a2SMark Phalan 					server_key_len, encrypting_key);
811159d09a2SMark Phalan 	if (retval) {
812159d09a2SMark Phalan 	    pkiDebug("pkinit_octetstring2key failed: %s\n",
813159d09a2SMark Phalan 		     error_message(retval));
814159d09a2SMark Phalan 	    goto cleanup;
815159d09a2SMark Phalan 	}
816159d09a2SMark Phalan 
817159d09a2SMark Phalan 	dhkey_info.subjectPublicKey.length = dh_pubkey_len;
818159d09a2SMark Phalan 	dhkey_info.subjectPublicKey.data = dh_pubkey;
819159d09a2SMark Phalan 	dhkey_info.nonce = request->nonce;
820159d09a2SMark Phalan 	dhkey_info.dhKeyExpiration = 0;
821159d09a2SMark Phalan 
822159d09a2SMark Phalan 	retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
823159d09a2SMark Phalan 						   &encoded_dhkey_info);
824159d09a2SMark Phalan 	if (retval) {
825159d09a2SMark Phalan 	    pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
826159d09a2SMark Phalan 	    goto cleanup;
827159d09a2SMark Phalan 	}
828159d09a2SMark Phalan #ifdef DEBUG_ASN1
829159d09a2SMark Phalan 	print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
830159d09a2SMark Phalan 			 encoded_dhkey_info->length,
831159d09a2SMark Phalan 			 "/tmp/kdc_dh_key_info");
832159d09a2SMark Phalan #endif
833159d09a2SMark Phalan 
834159d09a2SMark Phalan 	switch ((int)padata->pa_type) {
835159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REQ:
836159d09a2SMark Phalan 		retval = cms_signeddata_create(context, plgctx->cryptoctx,
837159d09a2SMark Phalan 		    reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1,
838159d09a2SMark Phalan 		    (unsigned char *)encoded_dhkey_info->data,
839159d09a2SMark Phalan 		    encoded_dhkey_info->length,
840159d09a2SMark Phalan 		    &rep->u.dh_Info.dhSignedData.data,
841159d09a2SMark Phalan 		    &rep->u.dh_Info.dhSignedData.length);
842159d09a2SMark Phalan 		if (retval) {
843159d09a2SMark Phalan 		    pkiDebug("failed to create pkcs7 signed data\n");
844159d09a2SMark Phalan 		    goto cleanup;
845159d09a2SMark Phalan 		}
846159d09a2SMark Phalan 		break;
847159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REP_OLD:
848159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REQ_OLD:
849159d09a2SMark Phalan 		retval = cms_signeddata_create(context, plgctx->cryptoctx,
850159d09a2SMark Phalan 		    reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1,
851159d09a2SMark Phalan 		    (unsigned char *)encoded_dhkey_info->data,
852159d09a2SMark Phalan 		    encoded_dhkey_info->length,
853159d09a2SMark Phalan 		    &rep9->u.dhSignedData.data,
854159d09a2SMark Phalan 		    &rep9->u.dhSignedData.length);
855159d09a2SMark Phalan 		if (retval) {
856159d09a2SMark Phalan 		    pkiDebug("failed to create pkcs7 signed data\n");
857159d09a2SMark Phalan 		    goto cleanup;
858159d09a2SMark Phalan 		}
859159d09a2SMark Phalan 		break;
860159d09a2SMark Phalan 	}
861159d09a2SMark Phalan     } else {
862159d09a2SMark Phalan 	pkiDebug("received RSA key delivery AS REQ\n");
863159d09a2SMark Phalan 
864159d09a2SMark Phalan 	retval = krb5_c_make_random_key(context, enctype, encrypting_key);
865159d09a2SMark Phalan 	if (retval) {
866159d09a2SMark Phalan 	    pkiDebug("unable to make a session key\n");
867159d09a2SMark Phalan 	    goto cleanup;
868159d09a2SMark Phalan 	}
869159d09a2SMark Phalan 
870159d09a2SMark Phalan 	/* check if PA_TYPE of 132 is present which means the client is
871159d09a2SMark Phalan 	 * requesting that a checksum is send back instead of the nonce
872159d09a2SMark Phalan 	 */
873159d09a2SMark Phalan 	for (i = 0; request->padata[i] != NULL; i++) {
874159d09a2SMark Phalan 	    pkiDebug("%s: Checking pa_type 0x%08x\n",
875159d09a2SMark Phalan 		     __FUNCTION__, request->padata[i]->pa_type);
876159d09a2SMark Phalan 	    if (request->padata[i]->pa_type == 132)
877159d09a2SMark Phalan 		fixed_keypack = 1;
878159d09a2SMark Phalan 	}
879159d09a2SMark Phalan 	pkiDebug("%s: return checksum instead of nonce = %d\n",
880159d09a2SMark Phalan 		 __FUNCTION__, fixed_keypack);
881159d09a2SMark Phalan 
882*55fea89dSDan Cross 	/* if this is an RFC reply or draft9 client requested a checksum
883159d09a2SMark Phalan 	 * in the reply instead of the nonce, create an RFC-style keypack
884159d09a2SMark Phalan 	 */
885159d09a2SMark Phalan 	if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) {
886159d09a2SMark Phalan 	    init_krb5_reply_key_pack(&key_pack);
887159d09a2SMark Phalan 	    if (key_pack == NULL) {
888159d09a2SMark Phalan 		retval = ENOMEM;
889159d09a2SMark Phalan 		goto cleanup;
890159d09a2SMark Phalan 	    }
891159d09a2SMark Phalan 	    /* retrieve checksums for a given enctype of the reply key */
892159d09a2SMark Phalan 	    retval = krb5_c_keyed_checksum_types(context,
893159d09a2SMark Phalan 		encrypting_key->enctype, &num_types, &cksum_types);
894159d09a2SMark Phalan 	    if (retval)
895159d09a2SMark Phalan 		goto cleanup;
896159d09a2SMark Phalan 
897159d09a2SMark Phalan 	    /* pick the first of acceptable enctypes for the checksum */
898159d09a2SMark Phalan 	    retval = krb5_c_make_checksum(context, cksum_types[0],
899159d09a2SMark Phalan 		    encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
900159d09a2SMark Phalan 		    req_pkt, &key_pack->asChecksum);
901159d09a2SMark Phalan 	    if (retval) {
902159d09a2SMark Phalan 		pkiDebug("unable to calculate AS REQ checksum\n");
903159d09a2SMark Phalan 		goto cleanup;
904159d09a2SMark Phalan 	    }
905159d09a2SMark Phalan #ifdef DEBUG_CKSUM
906159d09a2SMark Phalan 	    pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
907159d09a2SMark Phalan 	    print_buffer(req_pkt->data, req_pkt->length);
908159d09a2SMark Phalan 	    pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
909*55fea89dSDan Cross 	    print_buffer(key_pack->asChecksum.contents,
910159d09a2SMark Phalan 			 key_pack->asChecksum.length);
911159d09a2SMark Phalan 	    pkiDebug("encrypting key (%d)\n", encrypting_key->length);
912159d09a2SMark Phalan 	    print_buffer(encrypting_key->contents, encrypting_key->length);
913159d09a2SMark Phalan #endif
914159d09a2SMark Phalan 
915159d09a2SMark Phalan 	    krb5_copy_keyblock_contents(context, encrypting_key,
916159d09a2SMark Phalan 					&key_pack->replyKey);
917159d09a2SMark Phalan 
918159d09a2SMark Phalan 	    retval = k5int_encode_krb5_reply_key_pack(key_pack,
919159d09a2SMark Phalan 						      &encoded_key_pack);
920159d09a2SMark Phalan 	    if (retval) {
921159d09a2SMark Phalan 		pkiDebug("failed to encode reply_key_pack\n");
922159d09a2SMark Phalan 		goto cleanup;
923159d09a2SMark Phalan 	    }
924159d09a2SMark Phalan 	}
925159d09a2SMark Phalan 
926159d09a2SMark Phalan 	switch ((int)padata->pa_type) {
927159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REQ:
928159d09a2SMark Phalan 		rep->choice = choice_pa_pk_as_rep_encKeyPack;
929159d09a2SMark Phalan 		retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
930*55fea89dSDan Cross 		    reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
931159d09a2SMark Phalan 		    (unsigned char *)encoded_key_pack->data,
932159d09a2SMark Phalan 		    encoded_key_pack->length,
933159d09a2SMark Phalan 		    &rep->u.encKeyPack.data, &rep->u.encKeyPack.length);
934159d09a2SMark Phalan 		break;
935159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REP_OLD:
936159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REQ_OLD:
937159d09a2SMark Phalan 		/* if the request is from the broken draft9 client that
938*55fea89dSDan Cross 		 * expects back a nonce, create it now
939159d09a2SMark Phalan 		 */
940159d09a2SMark Phalan 		if (!fixed_keypack) {
941159d09a2SMark Phalan 		    init_krb5_reply_key_pack_draft9(&key_pack9);
942159d09a2SMark Phalan 		    if (key_pack9 == NULL) {
943159d09a2SMark Phalan 			retval = ENOMEM;
944159d09a2SMark Phalan 			goto cleanup;
945159d09a2SMark Phalan 		    }
946159d09a2SMark Phalan 		    key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce;
947159d09a2SMark Phalan 		    krb5_copy_keyblock_contents(context, encrypting_key,
948159d09a2SMark Phalan 						&key_pack9->replyKey);
949159d09a2SMark Phalan 
950159d09a2SMark Phalan 		    retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9,
951159d09a2SMark Phalan 							   &encoded_key_pack);
952159d09a2SMark Phalan 		    if (retval) {
953159d09a2SMark Phalan 			pkiDebug("failed to encode reply_key_pack\n");
954159d09a2SMark Phalan 			goto cleanup;
955159d09a2SMark Phalan 		    }
956*55fea89dSDan Cross 		}
957159d09a2SMark Phalan 
958159d09a2SMark Phalan 		rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
959159d09a2SMark Phalan 		retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
960*55fea89dSDan Cross 		    reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1,
961159d09a2SMark Phalan 		    (unsigned char *)encoded_key_pack->data,
962159d09a2SMark Phalan 		    encoded_key_pack->length,
963159d09a2SMark Phalan 		    &rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length);
964159d09a2SMark Phalan 		break;
965159d09a2SMark Phalan 	}
966159d09a2SMark Phalan 	if (retval) {
967159d09a2SMark Phalan 	    pkiDebug("failed to create pkcs7 enveloped data: %s\n",
968159d09a2SMark Phalan 		     error_message(retval));
969159d09a2SMark Phalan 	    goto cleanup;
970159d09a2SMark Phalan 	}
971159d09a2SMark Phalan #ifdef DEBUG_ASN1
972159d09a2SMark Phalan 	print_buffer_bin((unsigned char *)encoded_key_pack->data,
973159d09a2SMark Phalan 			 encoded_key_pack->length,
974159d09a2SMark Phalan 			 "/tmp/kdc_key_pack");
975159d09a2SMark Phalan 	switch ((int)padata->pa_type) {
976159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REQ:
977159d09a2SMark Phalan 		print_buffer_bin(rep->u.encKeyPack.data,
978159d09a2SMark Phalan 				 rep->u.encKeyPack.length,
979159d09a2SMark Phalan 				 "/tmp/kdc_enc_key_pack");
980159d09a2SMark Phalan 		break;
981159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REP_OLD:
982159d09a2SMark Phalan 	    case KRB5_PADATA_PK_AS_REQ_OLD:
983159d09a2SMark Phalan 		print_buffer_bin(rep9->u.encKeyPack.data,
984159d09a2SMark Phalan 				 rep9->u.encKeyPack.length,
985159d09a2SMark Phalan 				 "/tmp/kdc_enc_key_pack");
986159d09a2SMark Phalan 		break;
987159d09a2SMark Phalan 	}
988159d09a2SMark Phalan #endif
989159d09a2SMark Phalan     }
990159d09a2SMark Phalan 
991159d09a2SMark Phalan     switch ((int)padata->pa_type) {
992159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
993159d09a2SMark Phalan 	    retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
994159d09a2SMark Phalan 	    break;
995159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
996159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
997159d09a2SMark Phalan 	    retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
998159d09a2SMark Phalan 	    break;
999159d09a2SMark Phalan     }
1000159d09a2SMark Phalan     if (retval) {
1001159d09a2SMark Phalan 	pkiDebug("failed to encode AS_REP\n");
1002159d09a2SMark Phalan 	goto cleanup;
1003159d09a2SMark Phalan     }
1004159d09a2SMark Phalan #ifdef DEBUG_ASN1
1005159d09a2SMark Phalan     if (out_data != NULL)
1006159d09a2SMark Phalan 	print_buffer_bin((unsigned char *)out_data->data, out_data->length,
1007159d09a2SMark Phalan 			 "/tmp/kdc_as_rep");
1008159d09a2SMark Phalan #endif
1009159d09a2SMark Phalan 
1010159d09a2SMark Phalan     *send_pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
1011159d09a2SMark Phalan     if (*send_pa == NULL) {
1012159d09a2SMark Phalan 	retval = ENOMEM;
1013159d09a2SMark Phalan 	free(out_data->data);
1014159d09a2SMark Phalan 	free(out_data);
1015159d09a2SMark Phalan 	out_data = NULL;
1016159d09a2SMark Phalan 	goto cleanup;
1017159d09a2SMark Phalan     }
1018159d09a2SMark Phalan     (*send_pa)->magic = KV5M_PA_DATA;
1019159d09a2SMark Phalan     switch ((int)padata->pa_type) {
1020159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
1021159d09a2SMark Phalan 	    (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
1022159d09a2SMark Phalan 	    break;
1023159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
1024159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
1025159d09a2SMark Phalan 	    (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
1026159d09a2SMark Phalan 	    break;
1027159d09a2SMark Phalan     }
1028159d09a2SMark Phalan     (*send_pa)->length = out_data->length;
1029159d09a2SMark Phalan     (*send_pa)->contents = (krb5_octet *) out_data->data;
1030159d09a2SMark Phalan 
1031159d09a2SMark Phalan 
1032159d09a2SMark Phalan   cleanup:
1033159d09a2SMark Phalan     pkinit_fini_kdc_req_context(context, reqctx);
1034159d09a2SMark Phalan     if (scratch.data != NULL)
1035159d09a2SMark Phalan 	free(scratch.data);
1036159d09a2SMark Phalan     if (out_data != NULL)
1037159d09a2SMark Phalan 	free(out_data);
1038159d09a2SMark Phalan     if (encoded_dhkey_info != NULL)
1039159d09a2SMark Phalan 	krb5_free_data(context, encoded_dhkey_info);
1040159d09a2SMark Phalan     if (encoded_key_pack != NULL)
1041159d09a2SMark Phalan 	krb5_free_data(context, encoded_key_pack);
1042159d09a2SMark Phalan     if (dh_pubkey != NULL)
1043159d09a2SMark Phalan 	free(dh_pubkey);
1044159d09a2SMark Phalan     if (server_key != NULL)
1045159d09a2SMark Phalan 	free(server_key);
1046159d09a2SMark Phalan     if (cksum_types != NULL)
1047159d09a2SMark Phalan 	free(cksum_types);
1048159d09a2SMark Phalan 
1049159d09a2SMark Phalan     switch ((int)padata->pa_type) {
1050159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
1051159d09a2SMark Phalan 	    free_krb5_pa_pk_as_req(&reqp);
1052159d09a2SMark Phalan 	    free_krb5_pa_pk_as_rep(&rep);
1053159d09a2SMark Phalan 	    free_krb5_reply_key_pack(&key_pack);
1054159d09a2SMark Phalan 	    break;
1055159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
1056159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
1057159d09a2SMark Phalan 	    free_krb5_pa_pk_as_req_draft9(&reqp9);
1058159d09a2SMark Phalan 	    free_krb5_pa_pk_as_rep_draft9(&rep9);
1059159d09a2SMark Phalan 	    if (!fixed_keypack)
1060159d09a2SMark Phalan 		free_krb5_reply_key_pack_draft9(&key_pack9);
1061159d09a2SMark Phalan 	    else
1062159d09a2SMark Phalan 		free_krb5_reply_key_pack(&key_pack);
1063159d09a2SMark Phalan 	    break;
1064159d09a2SMark Phalan     }
1065159d09a2SMark Phalan 
1066159d09a2SMark Phalan     if (retval)
1067159d09a2SMark Phalan 	pkiDebug("pkinit_verify_padata failure");
1068159d09a2SMark Phalan 
1069159d09a2SMark Phalan     return retval;
1070159d09a2SMark Phalan }
1071159d09a2SMark Phalan 
1072159d09a2SMark Phalan /* ARGSUSED */
1073159d09a2SMark Phalan static int
pkinit_server_get_flags(krb5_context kcontext,krb5_preauthtype patype)1074159d09a2SMark Phalan pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
1075159d09a2SMark Phalan {
1076159d09a2SMark Phalan     return PA_SUFFICIENT | PA_REPLACES_KEY;
1077159d09a2SMark Phalan }
1078159d09a2SMark Phalan 
1079159d09a2SMark Phalan static krb5_preauthtype supported_server_pa_types[] = {
1080159d09a2SMark Phalan     KRB5_PADATA_PK_AS_REQ,
1081159d09a2SMark Phalan     KRB5_PADATA_PK_AS_REQ_OLD,
1082159d09a2SMark Phalan     KRB5_PADATA_PK_AS_REP_OLD,
1083159d09a2SMark Phalan     0
1084159d09a2SMark Phalan };
1085159d09a2SMark Phalan 
1086159d09a2SMark Phalan /* ARGSUSED */
1087159d09a2SMark Phalan static void
pkinit_fini_kdc_profile(krb5_context context,pkinit_kdc_context plgctx)1088159d09a2SMark Phalan pkinit_fini_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1089159d09a2SMark Phalan {
1090159d09a2SMark Phalan     /*
1091159d09a2SMark Phalan      * There is nothing currently allocated by pkinit_init_kdc_profile()
1092159d09a2SMark Phalan      * which needs to be freed here.
1093159d09a2SMark Phalan      */
1094159d09a2SMark Phalan }
1095159d09a2SMark Phalan 
1096159d09a2SMark Phalan static krb5_error_code
pkinit_init_kdc_profile(krb5_context context,pkinit_kdc_context plgctx)1097159d09a2SMark Phalan pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1098159d09a2SMark Phalan {
1099159d09a2SMark Phalan     krb5_error_code retval;
1100159d09a2SMark Phalan     char *eku_string = NULL;
1101159d09a2SMark Phalan 
1102159d09a2SMark Phalan     pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname);
1103159d09a2SMark Phalan     retval = pkinit_kdcdefault_string(context, plgctx->realmname,
1104159d09a2SMark Phalan 				      "pkinit_identity",
1105159d09a2SMark Phalan 				      &plgctx->idopts->identity);
1106159d09a2SMark Phalan     if (retval != 0 || NULL == plgctx->idopts->identity) {
1107159d09a2SMark Phalan 	retval = EINVAL;
1108159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
1109159d09a2SMark Phalan 			       "No pkinit_identity supplied for realm %s",
1110159d09a2SMark Phalan 			       plgctx->realmname);
1111159d09a2SMark Phalan 	goto errout;
1112159d09a2SMark Phalan     }
1113159d09a2SMark Phalan 
1114159d09a2SMark Phalan     retval = pkinit_kdcdefault_strings(context, plgctx->realmname,
1115159d09a2SMark Phalan 				       "pkinit_anchors",
1116159d09a2SMark Phalan 				       &plgctx->idopts->anchors);
1117159d09a2SMark Phalan     if (retval != 0 || NULL == plgctx->idopts->anchors) {
1118159d09a2SMark Phalan 	retval = EINVAL;
1119159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
1120159d09a2SMark Phalan 			       "No pkinit_anchors supplied for realm %s",
1121159d09a2SMark Phalan 			       plgctx->realmname);
1122159d09a2SMark Phalan 	goto errout;
1123159d09a2SMark Phalan     }
1124159d09a2SMark Phalan 
1125159d09a2SMark Phalan     /* Solaris Kerberos */
1126159d09a2SMark Phalan     (void) pkinit_kdcdefault_strings(context, plgctx->realmname,
1127159d09a2SMark Phalan 			      "pkinit_pool",
1128159d09a2SMark Phalan 			      &plgctx->idopts->intermediates);
1129159d09a2SMark Phalan 
1130159d09a2SMark Phalan     (void) pkinit_kdcdefault_strings(context, plgctx->realmname,
1131159d09a2SMark Phalan 			      "pkinit_revoke",
1132159d09a2SMark Phalan 			      &plgctx->idopts->crls);
1133159d09a2SMark Phalan 
1134159d09a2SMark Phalan     (void) pkinit_kdcdefault_string(context, plgctx->realmname,
1135159d09a2SMark Phalan 			     "pkinit_kdc_ocsp",
1136159d09a2SMark Phalan 			     &plgctx->idopts->ocsp);
1137159d09a2SMark Phalan 
1138159d09a2SMark Phalan     (void) pkinit_kdcdefault_string(context, plgctx->realmname,
1139159d09a2SMark Phalan 			     "pkinit_mappings_file",
1140159d09a2SMark Phalan 			     &plgctx->idopts->dn_mapping_file);
1141159d09a2SMark Phalan 
1142159d09a2SMark Phalan     (void) pkinit_kdcdefault_integer(context, plgctx->realmname,
1143159d09a2SMark Phalan 			      "pkinit_dh_min_bits",
1144159d09a2SMark Phalan 			      PKINIT_DEFAULT_DH_MIN_BITS,
1145159d09a2SMark Phalan 			      &plgctx->opts->dh_min_bits);
1146159d09a2SMark Phalan     if (plgctx->opts->dh_min_bits < 1024) {
1147159d09a2SMark Phalan 	pkiDebug("%s: invalid value (%d) for pkinit_dh_min_bits, "
1148159d09a2SMark Phalan 		 "using default value (%d) instead\n", __FUNCTION__,
1149159d09a2SMark Phalan 		 plgctx->opts->dh_min_bits, PKINIT_DEFAULT_DH_MIN_BITS);
1150159d09a2SMark Phalan 	plgctx->opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
1151159d09a2SMark Phalan     }
1152159d09a2SMark Phalan 
1153159d09a2SMark Phalan     (void) pkinit_kdcdefault_boolean(context, plgctx->realmname,
1154159d09a2SMark Phalan 			      "pkinit_allow_upn",
1155159d09a2SMark Phalan 			      0, &plgctx->opts->allow_upn);
1156159d09a2SMark Phalan 
1157159d09a2SMark Phalan     (void) pkinit_kdcdefault_boolean(context, plgctx->realmname,
1158159d09a2SMark Phalan 			      "pkinit_require_crl_checking",
1159159d09a2SMark Phalan 			      0, &plgctx->opts->require_crl_checking);
1160159d09a2SMark Phalan 
1161159d09a2SMark Phalan     (void) pkinit_kdcdefault_string(context, plgctx->realmname,
1162159d09a2SMark Phalan 			     "pkinit_eku_checking",
1163159d09a2SMark Phalan 			     &eku_string);
1164159d09a2SMark Phalan     if (eku_string != NULL) {
1165159d09a2SMark Phalan 	if (strcasecmp(eku_string, "kpClientAuth") == 0) {
1166159d09a2SMark Phalan 	    plgctx->opts->require_eku = 1;
1167159d09a2SMark Phalan 	    plgctx->opts->accept_secondary_eku = 0;
1168159d09a2SMark Phalan 	} else if (strcasecmp(eku_string, "scLogin") == 0) {
1169159d09a2SMark Phalan 	    plgctx->opts->require_eku = 1;
1170159d09a2SMark Phalan 	    plgctx->opts->accept_secondary_eku = 1;
1171159d09a2SMark Phalan 	} else if (strcasecmp(eku_string, "none") == 0) {
1172159d09a2SMark Phalan 	    plgctx->opts->require_eku = 0;
1173159d09a2SMark Phalan 	    plgctx->opts->accept_secondary_eku = 0;
1174159d09a2SMark Phalan 	} else {
1175159d09a2SMark Phalan 	    pkiDebug("%s: Invalid value for pkinit_eku_checking: '%s'\n",
1176159d09a2SMark Phalan 		     __FUNCTION__, eku_string);
1177159d09a2SMark Phalan 	}
1178159d09a2SMark Phalan 	free(eku_string);
1179159d09a2SMark Phalan     }
1180159d09a2SMark Phalan 
1181159d09a2SMark Phalan 
1182159d09a2SMark Phalan     return 0;
1183159d09a2SMark Phalan errout:
1184159d09a2SMark Phalan     pkinit_fini_kdc_profile(context, plgctx);
1185159d09a2SMark Phalan     return retval;
1186159d09a2SMark Phalan }
1187159d09a2SMark Phalan 
1188159d09a2SMark Phalan /* ARGSUSED */
1189159d09a2SMark Phalan static pkinit_kdc_context
pkinit_find_realm_context(krb5_context context,void * pa_plugin_context,krb5_principal princ)1190159d09a2SMark Phalan pkinit_find_realm_context(krb5_context context, void *pa_plugin_context,
1191159d09a2SMark Phalan 			  krb5_principal princ)
1192159d09a2SMark Phalan {
1193159d09a2SMark Phalan     int i;
1194159d09a2SMark Phalan     pkinit_kdc_context *realm_contexts = pa_plugin_context;
1195159d09a2SMark Phalan 
1196159d09a2SMark Phalan     if (pa_plugin_context == NULL)
1197159d09a2SMark Phalan 	return NULL;
1198159d09a2SMark Phalan 
1199159d09a2SMark Phalan     for (i = 0; realm_contexts[i] != NULL; i++) {
1200159d09a2SMark Phalan 	pkinit_kdc_context p = realm_contexts[i];
1201159d09a2SMark Phalan 
1202159d09a2SMark Phalan 	if ((p->realmname_len == princ->realm.length) &&
1203159d09a2SMark Phalan 	    (strncmp(p->realmname, princ->realm.data, p->realmname_len) == 0)) {
1204159d09a2SMark Phalan 	    pkiDebug("%s: returning context at %p for realm '%s'\n",
1205159d09a2SMark Phalan 		     __FUNCTION__, p, p->realmname);
1206159d09a2SMark Phalan 	    return p;
1207159d09a2SMark Phalan 	}
1208159d09a2SMark Phalan     }
1209159d09a2SMark Phalan     pkiDebug("%s: unable to find realm context for realm '%.*s'\n",
1210159d09a2SMark Phalan 	     __FUNCTION__, princ->realm.length, princ->realm.data);
1211159d09a2SMark Phalan     return NULL;
1212159d09a2SMark Phalan }
1213159d09a2SMark Phalan 
1214159d09a2SMark Phalan static int
pkinit_server_plugin_init_realm(krb5_context context,const char * realmname,pkinit_kdc_context * pplgctx)1215159d09a2SMark Phalan pkinit_server_plugin_init_realm(krb5_context context, const char *realmname,
1216159d09a2SMark Phalan 				pkinit_kdc_context *pplgctx)
1217159d09a2SMark Phalan {
1218159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
1219159d09a2SMark Phalan     pkinit_kdc_context plgctx = NULL;
1220159d09a2SMark Phalan 
1221159d09a2SMark Phalan     *pplgctx = NULL;
1222159d09a2SMark Phalan 
1223159d09a2SMark Phalan     plgctx = (pkinit_kdc_context) calloc(1, sizeof(*plgctx));
1224159d09a2SMark Phalan     if (plgctx == NULL)
1225159d09a2SMark Phalan 	goto errout;
1226159d09a2SMark Phalan 
1227159d09a2SMark Phalan     pkiDebug("%s: initializing context at %p for realm '%s'\n",
1228159d09a2SMark Phalan 	     __FUNCTION__, plgctx, realmname);
1229159d09a2SMark Phalan     (void) memset(plgctx, 0, sizeof(*plgctx));
1230159d09a2SMark Phalan     plgctx->magic = PKINIT_CTX_MAGIC;
1231159d09a2SMark Phalan 
1232159d09a2SMark Phalan     plgctx->realmname = strdup(realmname);
1233159d09a2SMark Phalan     if (plgctx->realmname == NULL)
1234159d09a2SMark Phalan 	goto errout;
1235159d09a2SMark Phalan     plgctx->realmname_len = strlen(plgctx->realmname);
1236159d09a2SMark Phalan 
1237159d09a2SMark Phalan     retval = pkinit_init_plg_crypto(&plgctx->cryptoctx);
1238159d09a2SMark Phalan     if (retval)
1239159d09a2SMark Phalan 	goto errout;
1240159d09a2SMark Phalan 
1241159d09a2SMark Phalan     retval = pkinit_init_plg_opts(&plgctx->opts);
1242159d09a2SMark Phalan     if (retval)
1243159d09a2SMark Phalan 	goto errout;
1244159d09a2SMark Phalan 
1245159d09a2SMark Phalan     retval = pkinit_init_identity_crypto(&plgctx->idctx);
1246159d09a2SMark Phalan     if (retval)
1247159d09a2SMark Phalan 	goto errout;
1248159d09a2SMark Phalan 
1249159d09a2SMark Phalan     retval = pkinit_init_identity_opts(&plgctx->idopts);
1250159d09a2SMark Phalan     if (retval)
1251159d09a2SMark Phalan 	goto errout;
1252159d09a2SMark Phalan 
1253159d09a2SMark Phalan     retval = pkinit_init_kdc_profile(context, plgctx);
1254159d09a2SMark Phalan     if (retval)
1255159d09a2SMark Phalan 	goto errout;
1256159d09a2SMark Phalan 
1257159d09a2SMark Phalan     /*
1258159d09a2SMark Phalan      * Solaris Kerberos:
1259159d09a2SMark Phalan      * Some methods of storing key information (PKCS11, PKCS12,...) may
1260159d09a2SMark Phalan      * require interactive prompting.
1261159d09a2SMark Phalan      */
1262159d09a2SMark Phalan     retval = pkinit_identity_set_prompter(plgctx->idctx, krb5_prompter_posix,
1263159d09a2SMark Phalan 					NULL);
1264159d09a2SMark Phalan     if (retval)
1265159d09a2SMark Phalan 	goto errout;
1266159d09a2SMark Phalan 
1267159d09a2SMark Phalan     retval = pkinit_identity_initialize(context, plgctx->cryptoctx, NULL,
1268159d09a2SMark Phalan 					plgctx->idopts, plgctx->idctx, 0, NULL);
1269159d09a2SMark Phalan     if (retval)
1270159d09a2SMark Phalan 	goto errout;
1271159d09a2SMark Phalan 
1272159d09a2SMark Phalan     pkiDebug("%s: returning context at %p for realm '%s'\n",
1273159d09a2SMark Phalan 	     __FUNCTION__, plgctx, realmname);
1274159d09a2SMark Phalan     *pplgctx = plgctx;
1275159d09a2SMark Phalan     retval = 0;
1276159d09a2SMark Phalan 
1277159d09a2SMark Phalan errout:
1278159d09a2SMark Phalan     if (retval)
1279159d09a2SMark Phalan 	pkinit_server_plugin_fini_realm(context, plgctx);
1280159d09a2SMark Phalan 
1281159d09a2SMark Phalan     return retval;
1282159d09a2SMark Phalan }
1283159d09a2SMark Phalan 
1284159d09a2SMark Phalan static int
pkinit_server_plugin_init(krb5_context context,void ** blob,const char ** realmnames)1285159d09a2SMark Phalan pkinit_server_plugin_init(krb5_context context, void **blob,
1286159d09a2SMark Phalan 			  const char **realmnames)
1287159d09a2SMark Phalan {
1288159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
1289159d09a2SMark Phalan     pkinit_kdc_context plgctx, *realm_contexts = NULL;
1290159d09a2SMark Phalan     int i, j;
1291159d09a2SMark Phalan     size_t numrealms;
1292159d09a2SMark Phalan 
1293159d09a2SMark Phalan     retval = pkinit_accessor_init();
1294159d09a2SMark Phalan     if (retval)
1295159d09a2SMark Phalan 	return retval;
1296159d09a2SMark Phalan 
1297159d09a2SMark Phalan     /* Determine how many realms we may need to support */
1298159d09a2SMark Phalan     for (i = 0; realmnames[i] != NULL; i++) {};
1299159d09a2SMark Phalan     numrealms = i;
1300159d09a2SMark Phalan 
1301159d09a2SMark Phalan     realm_contexts = (pkinit_kdc_context *)
1302159d09a2SMark Phalan 			calloc(numrealms+1, sizeof(pkinit_kdc_context));
1303159d09a2SMark Phalan     if (realm_contexts == NULL)
1304159d09a2SMark Phalan 	return ENOMEM;
1305159d09a2SMark Phalan 
1306159d09a2SMark Phalan     for (i = 0, j = 0; i < numrealms; i++) {
1307159d09a2SMark Phalan 	pkiDebug("%s: processing realm '%s'\n", __FUNCTION__, realmnames[i]);
1308159d09a2SMark Phalan 	retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx);
1309159d09a2SMark Phalan 	if (retval == 0 && plgctx != NULL)
1310159d09a2SMark Phalan 	    realm_contexts[j++] = plgctx;
1311159d09a2SMark Phalan     }
1312159d09a2SMark Phalan 
1313159d09a2SMark Phalan     if (j == 0) {
1314159d09a2SMark Phalan 	/*
1315159d09a2SMark Phalan 	 * Solaris Kerberos
1316159d09a2SMark Phalan 	 * Improve error messages for the common case of a single realm
1317159d09a2SMark Phalan 	 */
1318159d09a2SMark Phalan 	if (numrealms != 1) {
1319159d09a2SMark Phalan 	    retval = EINVAL;
1320159d09a2SMark Phalan 	    krb5_set_error_message(context, retval, "No realms configured "
1321159d09a2SMark Phalan 			       "correctly for pkinit support");
1322159d09a2SMark Phalan 	}
1323159d09a2SMark Phalan 
1324159d09a2SMark Phalan 	goto errout;
1325159d09a2SMark Phalan     }
1326159d09a2SMark Phalan 
1327159d09a2SMark Phalan     *blob = realm_contexts;
1328159d09a2SMark Phalan     retval = 0;
1329159d09a2SMark Phalan     pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts);
1330159d09a2SMark Phalan 
1331159d09a2SMark Phalan errout:
1332159d09a2SMark Phalan     if (retval)
1333159d09a2SMark Phalan 	pkinit_server_plugin_fini(context, realm_contexts);
1334159d09a2SMark Phalan 
1335159d09a2SMark Phalan     return retval;
1336159d09a2SMark Phalan }
1337159d09a2SMark Phalan 
1338159d09a2SMark Phalan static void
pkinit_server_plugin_fini_realm(krb5_context context,pkinit_kdc_context plgctx)1339159d09a2SMark Phalan pkinit_server_plugin_fini_realm(krb5_context context, pkinit_kdc_context plgctx)
1340159d09a2SMark Phalan {
1341159d09a2SMark Phalan     if (plgctx == NULL)
1342159d09a2SMark Phalan 	return;
1343159d09a2SMark Phalan 
1344159d09a2SMark Phalan     pkinit_fini_kdc_profile(context, plgctx);
1345159d09a2SMark Phalan     pkinit_fini_identity_opts(plgctx->idopts);
1346159d09a2SMark Phalan     pkinit_fini_identity_crypto(plgctx->idctx);
1347159d09a2SMark Phalan     pkinit_fini_plg_crypto(plgctx->cryptoctx);
1348159d09a2SMark Phalan     pkinit_fini_plg_opts(plgctx->opts);
1349159d09a2SMark Phalan     free(plgctx->realmname);
1350159d09a2SMark Phalan     free(plgctx);
1351159d09a2SMark Phalan }
1352159d09a2SMark Phalan 
1353159d09a2SMark Phalan static void
pkinit_server_plugin_fini(krb5_context context,void * blob)1354159d09a2SMark Phalan pkinit_server_plugin_fini(krb5_context context, void *blob)
1355159d09a2SMark Phalan {
1356159d09a2SMark Phalan     pkinit_kdc_context *realm_contexts = blob;
1357159d09a2SMark Phalan     int i;
1358159d09a2SMark Phalan 
1359159d09a2SMark Phalan     if (realm_contexts == NULL)
1360159d09a2SMark Phalan 	return;
1361159d09a2SMark Phalan 
1362159d09a2SMark Phalan     for (i = 0; realm_contexts[i] != NULL; i++) {
1363159d09a2SMark Phalan 	pkinit_server_plugin_fini_realm(context, realm_contexts[i]);
1364159d09a2SMark Phalan     }
1365159d09a2SMark Phalan     pkiDebug("%s: freeing   context at %p\n", __FUNCTION__, realm_contexts);
1366159d09a2SMark Phalan     free(realm_contexts);
1367159d09a2SMark Phalan }
1368159d09a2SMark Phalan 
1369159d09a2SMark Phalan static krb5_error_code
pkinit_init_kdc_req_context(krb5_context context,void ** ctx)1370159d09a2SMark Phalan pkinit_init_kdc_req_context(krb5_context context, void **ctx)
1371159d09a2SMark Phalan {
1372159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
1373159d09a2SMark Phalan     pkinit_kdc_req_context reqctx = NULL;
1374159d09a2SMark Phalan 
1375159d09a2SMark Phalan     reqctx = (pkinit_kdc_req_context)malloc(sizeof(*reqctx));
1376159d09a2SMark Phalan     if (reqctx == NULL)
1377159d09a2SMark Phalan 	return retval;
1378159d09a2SMark Phalan     (void) memset(reqctx, 0, sizeof(*reqctx));
1379159d09a2SMark Phalan     reqctx->magic = PKINIT_CTX_MAGIC;
1380159d09a2SMark Phalan 
1381159d09a2SMark Phalan     retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
1382159d09a2SMark Phalan     if (retval)
1383159d09a2SMark Phalan 	goto cleanup;
1384159d09a2SMark Phalan     reqctx->rcv_auth_pack = NULL;
1385159d09a2SMark Phalan     reqctx->rcv_auth_pack9 = NULL;
1386159d09a2SMark Phalan 
1387159d09a2SMark Phalan     pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
1388159d09a2SMark Phalan     *ctx = reqctx;
1389159d09a2SMark Phalan     retval = 0;
1390159d09a2SMark Phalan cleanup:
1391159d09a2SMark Phalan     if (retval)
1392159d09a2SMark Phalan 	pkinit_fini_kdc_req_context(context, reqctx);
1393159d09a2SMark Phalan 
1394159d09a2SMark Phalan     return retval;
1395159d09a2SMark Phalan }
1396159d09a2SMark Phalan 
1397159d09a2SMark Phalan static void
pkinit_fini_kdc_req_context(krb5_context context,void * ctx)1398159d09a2SMark Phalan pkinit_fini_kdc_req_context(krb5_context context, void *ctx)
1399159d09a2SMark Phalan {
1400159d09a2SMark Phalan     pkinit_kdc_req_context reqctx = (pkinit_kdc_req_context)ctx;
1401159d09a2SMark Phalan 
1402159d09a2SMark Phalan     if (reqctx == NULL || reqctx->magic != PKINIT_CTX_MAGIC) {
1403159d09a2SMark Phalan 	pkiDebug("pkinit_fini_kdc_req_context: got bad reqctx (%p)!\n", reqctx);
1404159d09a2SMark Phalan 	return;
1405159d09a2SMark Phalan     }
1406159d09a2SMark Phalan     pkiDebug("%s: freeing   reqctx at %p\n", __FUNCTION__, reqctx);
1407159d09a2SMark Phalan 
1408159d09a2SMark Phalan     pkinit_fini_req_crypto(reqctx->cryptoctx);
1409159d09a2SMark Phalan     if (reqctx->rcv_auth_pack != NULL)
1410159d09a2SMark Phalan 	free_krb5_auth_pack(&reqctx->rcv_auth_pack);
1411159d09a2SMark Phalan     if (reqctx->rcv_auth_pack9 != NULL)
1412159d09a2SMark Phalan 	free_krb5_auth_pack_draft9(context, &reqctx->rcv_auth_pack9);
1413159d09a2SMark Phalan 
1414159d09a2SMark Phalan     free(reqctx);
1415159d09a2SMark Phalan }
1416159d09a2SMark Phalan 
1417159d09a2SMark Phalan struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
1418159d09a2SMark Phalan     "pkinit",			/* name */
1419159d09a2SMark Phalan     supported_server_pa_types,	/* pa_type_list */
1420159d09a2SMark Phalan     pkinit_server_plugin_init,	/* (*init_proc) */
1421159d09a2SMark Phalan     pkinit_server_plugin_fini,	/* (*fini_proc) */
1422159d09a2SMark Phalan     pkinit_server_get_flags,	/* (*flags_proc) */
1423159d09a2SMark Phalan     pkinit_server_get_edata,	/* (*edata_proc) */
1424159d09a2SMark Phalan     pkinit_server_verify_padata,/* (*verify_proc) */
1425159d09a2SMark Phalan     pkinit_server_return_padata,/* (*return_proc) */
1426159d09a2SMark Phalan     NULL,			/* (*freepa_reqcontext_proc) */
1427159d09a2SMark Phalan };
1428