xref: /onnv-gate/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_clnt.c (revision 12941:2df46ea8f1b1)
17934SMark.Phalan@Sun.COM /*
27934SMark.Phalan@Sun.COM  * COPYRIGHT (C) 2006,2007
37934SMark.Phalan@Sun.COM  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
47934SMark.Phalan@Sun.COM  * ALL RIGHTS RESERVED
57934SMark.Phalan@Sun.COM  *
67934SMark.Phalan@Sun.COM  * Permission is granted to use, copy, create derivative works
77934SMark.Phalan@Sun.COM  * and redistribute this software and such derivative works
87934SMark.Phalan@Sun.COM  * for any purpose, so long as the name of The University of
97934SMark.Phalan@Sun.COM  * Michigan is not used in any advertising or publicity
107934SMark.Phalan@Sun.COM  * pertaining to the use of distribution of this software
117934SMark.Phalan@Sun.COM  * without specific, written prior authorization.  If the
127934SMark.Phalan@Sun.COM  * above copyright notice or any other identification of the
137934SMark.Phalan@Sun.COM  * University of Michigan is included in any copy of any
147934SMark.Phalan@Sun.COM  * portion of this software, then the disclaimer below must
157934SMark.Phalan@Sun.COM  * also be included.
167934SMark.Phalan@Sun.COM  *
177934SMark.Phalan@Sun.COM  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
187934SMark.Phalan@Sun.COM  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
197934SMark.Phalan@Sun.COM  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
207934SMark.Phalan@Sun.COM  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
217934SMark.Phalan@Sun.COM  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
227934SMark.Phalan@Sun.COM  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
237934SMark.Phalan@Sun.COM  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
247934SMark.Phalan@Sun.COM  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
257934SMark.Phalan@Sun.COM  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
267934SMark.Phalan@Sun.COM  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
277934SMark.Phalan@Sun.COM  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
287934SMark.Phalan@Sun.COM  * SUCH DAMAGES.
297934SMark.Phalan@Sun.COM  */
307934SMark.Phalan@Sun.COM 
31*12941Swill.fiveash@oracle.com /*
32*12941Swill.fiveash@oracle.com  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
33*12941Swill.fiveash@oracle.com  */
34*12941Swill.fiveash@oracle.com 
357934SMark.Phalan@Sun.COM #include <stdio.h>
367934SMark.Phalan@Sun.COM #include <stdlib.h>
377934SMark.Phalan@Sun.COM #include <errno.h>
387934SMark.Phalan@Sun.COM #include <unistd.h>
397934SMark.Phalan@Sun.COM #include <string.h>
407934SMark.Phalan@Sun.COM #include <ctype.h>
417934SMark.Phalan@Sun.COM #include <assert.h>
427934SMark.Phalan@Sun.COM #include <dlfcn.h>
437934SMark.Phalan@Sun.COM #include <sys/stat.h>
447934SMark.Phalan@Sun.COM 
457934SMark.Phalan@Sun.COM #include "pkinit.h"
467934SMark.Phalan@Sun.COM 
477934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
487934SMark.Phalan@Sun.COM /*
497934SMark.Phalan@Sun.COM  * It is anticipated that all the special checks currently
507934SMark.Phalan@Sun.COM  * required when talking to a Longhorn server will go away
517934SMark.Phalan@Sun.COM  * by the time it is officially released and all references
527934SMark.Phalan@Sun.COM  * to the longhorn global can be removed and any code
537934SMark.Phalan@Sun.COM  * #ifdef'd with LONGHORN_BETA_COMPAT can be removed.
547934SMark.Phalan@Sun.COM  *
557934SMark.Phalan@Sun.COM  * Current testing (20070620) is against a patched Beta 3
567934SMark.Phalan@Sun.COM  * version of Longhorn.  Most, if not all, problems should
577934SMark.Phalan@Sun.COM  * be fixed in SP1 of Longhorn.
587934SMark.Phalan@Sun.COM  */
597934SMark.Phalan@Sun.COM int longhorn = 0;	/* Talking to a Longhorn server? */
607934SMark.Phalan@Sun.COM #endif
617934SMark.Phalan@Sun.COM 
627934SMark.Phalan@Sun.COM krb5_error_code pkinit_client_process
637934SMark.Phalan@Sun.COM 	(krb5_context context, void *plugin_context, void *request_context,
647934SMark.Phalan@Sun.COM 		krb5_get_init_creds_opt *gic_opt,
657934SMark.Phalan@Sun.COM 		preauth_get_client_data_proc get_data_proc,
667934SMark.Phalan@Sun.COM 		struct _krb5_preauth_client_rock *rock,
677934SMark.Phalan@Sun.COM 		krb5_kdc_req * request, krb5_data *encoded_request_body,
687934SMark.Phalan@Sun.COM 		krb5_data *encoded_previous_request, krb5_pa_data *in_padata,
697934SMark.Phalan@Sun.COM 		krb5_prompter_fct prompter, void *prompter_data,
707934SMark.Phalan@Sun.COM 		preauth_get_as_key_proc gak_fct, void *gak_data,
717934SMark.Phalan@Sun.COM 		krb5_data * salt, krb5_data * s2kparams,
727934SMark.Phalan@Sun.COM 		krb5_keyblock * as_key, krb5_pa_data *** out_padata);
737934SMark.Phalan@Sun.COM 
747934SMark.Phalan@Sun.COM krb5_error_code pkinit_client_tryagain
757934SMark.Phalan@Sun.COM 	(krb5_context context, void *plugin_context, void *request_context,
767934SMark.Phalan@Sun.COM 		krb5_get_init_creds_opt *gic_opt,
777934SMark.Phalan@Sun.COM 		preauth_get_client_data_proc get_data_proc,
787934SMark.Phalan@Sun.COM 		struct _krb5_preauth_client_rock *rock,
797934SMark.Phalan@Sun.COM 		krb5_kdc_req * request, krb5_data *encoded_request_body,
807934SMark.Phalan@Sun.COM 		krb5_data *encoded_previous_request,
817934SMark.Phalan@Sun.COM 		krb5_pa_data *in_padata, krb5_error *err_reply,
827934SMark.Phalan@Sun.COM 		krb5_prompter_fct prompter, void *prompter_data,
837934SMark.Phalan@Sun.COM 		preauth_get_as_key_proc gak_fct, void *gak_data,
847934SMark.Phalan@Sun.COM 		krb5_data * salt, krb5_data * s2kparams,
857934SMark.Phalan@Sun.COM 		krb5_keyblock * as_key, krb5_pa_data *** out_padata);
867934SMark.Phalan@Sun.COM 
877934SMark.Phalan@Sun.COM void pkinit_client_req_init
887934SMark.Phalan@Sun.COM 	(krb5_context contex, void *plugin_context, void **request_context);
897934SMark.Phalan@Sun.COM 
907934SMark.Phalan@Sun.COM void pkinit_client_req_fini
917934SMark.Phalan@Sun.COM 	(krb5_context context, void *plugin_context, void *request_context);
927934SMark.Phalan@Sun.COM 
937934SMark.Phalan@Sun.COM krb5_error_code pa_pkinit_gen_req
947934SMark.Phalan@Sun.COM 	(krb5_context context, pkinit_context plgctx,
957934SMark.Phalan@Sun.COM 		pkinit_req_context reqctx, krb5_kdc_req * request,
967934SMark.Phalan@Sun.COM 		krb5_pa_data * in_padata, krb5_pa_data *** out_padata,
977934SMark.Phalan@Sun.COM 		krb5_prompter_fct prompter, void *prompter_data,
987934SMark.Phalan@Sun.COM 		krb5_get_init_creds_opt *gic_opt);
997934SMark.Phalan@Sun.COM 
1007934SMark.Phalan@Sun.COM krb5_error_code pkinit_as_req_create
1017934SMark.Phalan@Sun.COM 	(krb5_context context, pkinit_context plgctx,
1027934SMark.Phalan@Sun.COM 		pkinit_req_context reqctx, krb5_timestamp ctsec,
1037934SMark.Phalan@Sun.COM 		krb5_int32 cusec, krb5_ui_4 nonce,
1047934SMark.Phalan@Sun.COM 		const krb5_checksum * cksum, krb5_principal server,
1057934SMark.Phalan@Sun.COM 		krb5_data ** as_req);
1067934SMark.Phalan@Sun.COM 
1077934SMark.Phalan@Sun.COM krb5_error_code pkinit_as_rep_parse
1087934SMark.Phalan@Sun.COM 	(krb5_context context, pkinit_context plgctx,
1097934SMark.Phalan@Sun.COM 		pkinit_req_context reqctx, krb5_preauthtype pa_type,
1107934SMark.Phalan@Sun.COM 		krb5_kdc_req * request, const krb5_data * as_rep,
1117934SMark.Phalan@Sun.COM 		krb5_keyblock * key_block, krb5_enctype etype, krb5_data *);
1127934SMark.Phalan@Sun.COM 
1137934SMark.Phalan@Sun.COM krb5_error_code pa_pkinit_parse_rep
1147934SMark.Phalan@Sun.COM 	(krb5_context context, pkinit_context plgctx,
1157934SMark.Phalan@Sun.COM 		pkinit_req_context reqcxt, krb5_kdc_req * request,
1167934SMark.Phalan@Sun.COM 		krb5_pa_data * in_padata, krb5_enctype etype,
1177934SMark.Phalan@Sun.COM 		krb5_keyblock * as_key, krb5_data *);
1187934SMark.Phalan@Sun.COM 
1197934SMark.Phalan@Sun.COM static int pkinit_client_plugin_init(krb5_context context, void **blob);
1207934SMark.Phalan@Sun.COM static void pkinit_client_plugin_fini(krb5_context context, void *blob);
1217934SMark.Phalan@Sun.COM 
1227934SMark.Phalan@Sun.COM /* ARGSUSED */
1237934SMark.Phalan@Sun.COM 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)1247934SMark.Phalan@Sun.COM pa_pkinit_gen_req(krb5_context context,
1257934SMark.Phalan@Sun.COM 		  pkinit_context plgctx,
1267934SMark.Phalan@Sun.COM 		  pkinit_req_context reqctx,
1277934SMark.Phalan@Sun.COM 		  krb5_kdc_req * request,
1287934SMark.Phalan@Sun.COM 		  krb5_pa_data * in_padata,
1297934SMark.Phalan@Sun.COM 		  krb5_pa_data *** out_padata,
1307934SMark.Phalan@Sun.COM 		  krb5_prompter_fct prompter,
1317934SMark.Phalan@Sun.COM 		  void *prompter_data,
1327934SMark.Phalan@Sun.COM 		  krb5_get_init_creds_opt *gic_opt)
1337934SMark.Phalan@Sun.COM {
1347934SMark.Phalan@Sun.COM 
1357934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1367934SMark.Phalan@Sun.COM     krb5_data *out_data = NULL;
1377934SMark.Phalan@Sun.COM     krb5_timestamp ctsec = 0;
1387934SMark.Phalan@Sun.COM     krb5_int32 cusec = 0;
1397934SMark.Phalan@Sun.COM     krb5_ui_4 nonce = 0;
1407934SMark.Phalan@Sun.COM     krb5_checksum cksum;
1417934SMark.Phalan@Sun.COM     krb5_data *der_req = NULL;
1427934SMark.Phalan@Sun.COM     krb5_pa_data **return_pa_data = NULL;
1437934SMark.Phalan@Sun.COM 
1447934SMark.Phalan@Sun.COM     cksum.contents = NULL;
1457934SMark.Phalan@Sun.COM     reqctx->pa_type = in_padata->pa_type;
1467934SMark.Phalan@Sun.COM 
1477934SMark.Phalan@Sun.COM     pkiDebug("kdc_options = 0x%x  till = %d\n",
1487934SMark.Phalan@Sun.COM 	     request->kdc_options, request->till);
1497934SMark.Phalan@Sun.COM     /* If we don't have a client, we're done */
1507934SMark.Phalan@Sun.COM     if (request->client == NULL) {
1517934SMark.Phalan@Sun.COM 	pkiDebug("No request->client; aborting PKINIT\n");
1527934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
1537934SMark.Phalan@Sun.COM     }
1547934SMark.Phalan@Sun.COM 
1557934SMark.Phalan@Sun.COM     retval = pkinit_get_kdc_cert(context, plgctx->cryptoctx, reqctx->cryptoctx,
1567934SMark.Phalan@Sun.COM 				 reqctx->idctx, request->server);
1577934SMark.Phalan@Sun.COM     if (retval) {
1587934SMark.Phalan@Sun.COM 	pkiDebug("pkinit_get_kdc_cert returned %d\n", retval);
1597934SMark.Phalan@Sun.COM 	goto cleanup;
1607934SMark.Phalan@Sun.COM     }
1617934SMark.Phalan@Sun.COM 
1627934SMark.Phalan@Sun.COM     /* checksum of the encoded KDC-REQ-BODY */
1637934SMark.Phalan@Sun.COM     retval = k5int_encode_krb5_kdc_req_body(request, &der_req);
1647934SMark.Phalan@Sun.COM     if (retval) {
1657934SMark.Phalan@Sun.COM 	pkiDebug("encode_krb5_kdc_req_body returned %d\n", (int) retval);
1667934SMark.Phalan@Sun.COM 	goto cleanup;
1677934SMark.Phalan@Sun.COM     }
1687934SMark.Phalan@Sun.COM 
1697934SMark.Phalan@Sun.COM     retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0,
1707934SMark.Phalan@Sun.COM 				  der_req, &cksum);
1717934SMark.Phalan@Sun.COM     if (retval)
1727934SMark.Phalan@Sun.COM 	goto cleanup;
1737934SMark.Phalan@Sun.COM #ifdef DEBUG_CKSUM
1747934SMark.Phalan@Sun.COM     pkiDebug("calculating checksum on buf size (%d)\n", der_req->length);
1757934SMark.Phalan@Sun.COM     print_buffer(der_req->data, der_req->length);
1767934SMark.Phalan@Sun.COM #endif
1777934SMark.Phalan@Sun.COM 
1787934SMark.Phalan@Sun.COM     retval = krb5_us_timeofday(context, &ctsec, &cusec);
1797934SMark.Phalan@Sun.COM     if (retval)
1807934SMark.Phalan@Sun.COM 	goto cleanup;
1817934SMark.Phalan@Sun.COM 
1827934SMark.Phalan@Sun.COM     /* XXX PKINIT RFC says that nonce in PKAuthenticator doesn't have be the
1837934SMark.Phalan@Sun.COM      * same as in the AS_REQ. However, if we pick a different nonce, then we
1847934SMark.Phalan@Sun.COM      * need to remember that info when AS_REP is returned. I'm choosing to
1857934SMark.Phalan@Sun.COM      * reuse the AS_REQ nonce.
1867934SMark.Phalan@Sun.COM      */
1877934SMark.Phalan@Sun.COM     nonce = request->nonce;
1887934SMark.Phalan@Sun.COM 
1897934SMark.Phalan@Sun.COM     retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec,
1907934SMark.Phalan@Sun.COM 				  nonce, &cksum, request->server, &out_data);
1917934SMark.Phalan@Sun.COM     if (retval || !out_data->length) {
1927934SMark.Phalan@Sun.COM 	pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n",
1937934SMark.Phalan@Sun.COM 		 (int) retval);
1947934SMark.Phalan@Sun.COM 	goto cleanup;
1957934SMark.Phalan@Sun.COM     }
1967934SMark.Phalan@Sun.COM     retval = ENOMEM;
1977934SMark.Phalan@Sun.COM     /*
1987934SMark.Phalan@Sun.COM      * The most we'll return is two pa_data, normally just one.
1997934SMark.Phalan@Sun.COM      * We need to make room for the NULL terminator.
2007934SMark.Phalan@Sun.COM      */
2017934SMark.Phalan@Sun.COM     return_pa_data = (krb5_pa_data **) malloc(3 * sizeof(krb5_pa_data *));
2027934SMark.Phalan@Sun.COM     if (return_pa_data == NULL)
2037934SMark.Phalan@Sun.COM 	goto cleanup;
2047934SMark.Phalan@Sun.COM 
2057934SMark.Phalan@Sun.COM     return_pa_data[1] = NULL;	/* in case of an early trip to cleanup */
2067934SMark.Phalan@Sun.COM     return_pa_data[2] = NULL;	/* Terminate the list */
2077934SMark.Phalan@Sun.COM 
2087934SMark.Phalan@Sun.COM     return_pa_data[0] = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
2097934SMark.Phalan@Sun.COM     if (return_pa_data[0] == NULL)
2107934SMark.Phalan@Sun.COM 	goto cleanup;
2117934SMark.Phalan@Sun.COM 
2127934SMark.Phalan@Sun.COM     return_pa_data[1] = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
2137934SMark.Phalan@Sun.COM     if (return_pa_data[1] == NULL)
2147934SMark.Phalan@Sun.COM 	goto cleanup;
2157934SMark.Phalan@Sun.COM 
2167934SMark.Phalan@Sun.COM     return_pa_data[0]->magic = KV5M_PA_DATA;
2177934SMark.Phalan@Sun.COM 
2187934SMark.Phalan@Sun.COM     if (in_padata->pa_type == KRB5_PADATA_PK_AS_REQ_OLD)
2197934SMark.Phalan@Sun.COM 	return_pa_data[0]->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
2207934SMark.Phalan@Sun.COM     else
2217934SMark.Phalan@Sun.COM 	return_pa_data[0]->pa_type = in_padata->pa_type;
2227934SMark.Phalan@Sun.COM     return_pa_data[0]->length = out_data->length;
2237934SMark.Phalan@Sun.COM     return_pa_data[0]->contents = (krb5_octet *) out_data->data;
2247934SMark.Phalan@Sun.COM 
2257934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
2267934SMark.Phalan@Sun.COM     /*
2277934SMark.Phalan@Sun.COM      * LH Beta 3 requires the extra pa-data, even for RFC requests,
2287934SMark.Phalan@Sun.COM      * in order to get the Checksum rather than a Nonce in the reply.
2297934SMark.Phalan@Sun.COM      * This can be removed when LH SP1 is released.
2307934SMark.Phalan@Sun.COM      */
2317934SMark.Phalan@Sun.COM     if ((return_pa_data[0]->pa_type == KRB5_PADATA_PK_AS_REP_OLD
2327934SMark.Phalan@Sun.COM 	&& reqctx->opts->win2k_require_cksum) || (longhorn == 1)) {
2337934SMark.Phalan@Sun.COM #else
2347934SMark.Phalan@Sun.COM     if ((return_pa_data[0]->pa_type == KRB5_PADATA_PK_AS_REP_OLD
2357934SMark.Phalan@Sun.COM 	&& reqctx->opts->win2k_require_cksum)) {
2367934SMark.Phalan@Sun.COM #endif
2377934SMark.Phalan@Sun.COM 	return_pa_data[1]->pa_type = 132;
2387934SMark.Phalan@Sun.COM 	return_pa_data[1]->length = 0;
2397934SMark.Phalan@Sun.COM 	return_pa_data[1]->contents = NULL;
2407934SMark.Phalan@Sun.COM     } else {
2417934SMark.Phalan@Sun.COM 	free(return_pa_data[1]);
2427934SMark.Phalan@Sun.COM 	return_pa_data[1] = NULL;   /* Move the list terminator */
2437934SMark.Phalan@Sun.COM     }
2447934SMark.Phalan@Sun.COM     *out_padata = return_pa_data;
2457934SMark.Phalan@Sun.COM     retval = 0;
2467934SMark.Phalan@Sun.COM 
2477934SMark.Phalan@Sun.COM   cleanup:
2487934SMark.Phalan@Sun.COM     if (der_req != NULL)
2497934SMark.Phalan@Sun.COM 	krb5_free_data(context, der_req);
2507934SMark.Phalan@Sun.COM 
2517934SMark.Phalan@Sun.COM     if (out_data != NULL)
2527934SMark.Phalan@Sun.COM 	free(out_data);
2537934SMark.Phalan@Sun.COM 
2547934SMark.Phalan@Sun.COM     if (retval) {
2557934SMark.Phalan@Sun.COM 	if (return_pa_data) {
2567934SMark.Phalan@Sun.COM 	    if (return_pa_data[0] != NULL)
2577934SMark.Phalan@Sun.COM 		free(return_pa_data[0]);
2587934SMark.Phalan@Sun.COM 	    if (return_pa_data[1] != NULL)
2597934SMark.Phalan@Sun.COM 		free(return_pa_data[1]);
2607934SMark.Phalan@Sun.COM 	    free(return_pa_data);
2617934SMark.Phalan@Sun.COM 	}
2627934SMark.Phalan@Sun.COM 	if (out_data) {
2637934SMark.Phalan@Sun.COM 	    free(out_data->data);
2647934SMark.Phalan@Sun.COM 	    free(out_data);
2657934SMark.Phalan@Sun.COM 	}
2667934SMark.Phalan@Sun.COM     }
2677934SMark.Phalan@Sun.COM     return retval;
2687934SMark.Phalan@Sun.COM }
2697934SMark.Phalan@Sun.COM 
2707934SMark.Phalan@Sun.COM krb5_error_code
2717934SMark.Phalan@Sun.COM pkinit_as_req_create(krb5_context context,
2727934SMark.Phalan@Sun.COM 		     pkinit_context plgctx,
2737934SMark.Phalan@Sun.COM 		     pkinit_req_context reqctx,
2747934SMark.Phalan@Sun.COM 		     krb5_timestamp ctsec,
2757934SMark.Phalan@Sun.COM 		     krb5_int32 cusec,
2767934SMark.Phalan@Sun.COM 		     krb5_ui_4 nonce,
2777934SMark.Phalan@Sun.COM 		     const krb5_checksum * cksum,
2787934SMark.Phalan@Sun.COM 		     krb5_principal server,
2797934SMark.Phalan@Sun.COM 		     krb5_data ** as_req)
2807934SMark.Phalan@Sun.COM {
2817934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
2827934SMark.Phalan@Sun.COM     krb5_subject_pk_info *info = NULL;
2837934SMark.Phalan@Sun.COM     krb5_data *coded_auth_pack = NULL;
2847934SMark.Phalan@Sun.COM     krb5_auth_pack *auth_pack = NULL;
2857934SMark.Phalan@Sun.COM     krb5_pa_pk_as_req *req = NULL;
2867934SMark.Phalan@Sun.COM     krb5_auth_pack_draft9 *auth_pack9 = NULL;
2877934SMark.Phalan@Sun.COM     krb5_pa_pk_as_req_draft9 *req9 = NULL;
2887934SMark.Phalan@Sun.COM     int protocol = reqctx->opts->dh_or_rsa;
2897934SMark.Phalan@Sun.COM 
2907934SMark.Phalan@Sun.COM     pkiDebug("pkinit_as_req_create pa_type = %d\n", reqctx->pa_type);
2917934SMark.Phalan@Sun.COM 
2927934SMark.Phalan@Sun.COM     /* Create the authpack */
2937934SMark.Phalan@Sun.COM     switch((int)reqctx->pa_type) {
2947934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
2957934SMark.Phalan@Sun.COM 	    protocol = RSA_PROTOCOL;
2967934SMark.Phalan@Sun.COM 	    init_krb5_auth_pack_draft9(&auth_pack9);
2977934SMark.Phalan@Sun.COM 	    if (auth_pack9 == NULL)
2987934SMark.Phalan@Sun.COM 		goto cleanup;
2997934SMark.Phalan@Sun.COM 	    auth_pack9->pkAuthenticator.ctime = ctsec;
3007934SMark.Phalan@Sun.COM 	    auth_pack9->pkAuthenticator.cusec = cusec;
3017934SMark.Phalan@Sun.COM 	    auth_pack9->pkAuthenticator.nonce = nonce;
3027934SMark.Phalan@Sun.COM 	    auth_pack9->pkAuthenticator.kdcName = server;
3037934SMark.Phalan@Sun.COM 	    auth_pack9->pkAuthenticator.kdcRealm.magic = 0;
3047934SMark.Phalan@Sun.COM 	    auth_pack9->pkAuthenticator.kdcRealm.data =
3057934SMark.Phalan@Sun.COM 					(unsigned char *)server->realm.data;
3067934SMark.Phalan@Sun.COM 	    auth_pack9->pkAuthenticator.kdcRealm.length = server->realm.length;
3077934SMark.Phalan@Sun.COM 	    free(cksum->contents);
3087934SMark.Phalan@Sun.COM 	    break;
3097934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
3107934SMark.Phalan@Sun.COM 	    init_krb5_subject_pk_info(&info);
3117934SMark.Phalan@Sun.COM 	    if (info == NULL)
3127934SMark.Phalan@Sun.COM 		goto cleanup;
3137934SMark.Phalan@Sun.COM 	    init_krb5_auth_pack(&auth_pack);
3147934SMark.Phalan@Sun.COM 	    if (auth_pack == NULL)
3157934SMark.Phalan@Sun.COM 		goto cleanup;
3167934SMark.Phalan@Sun.COM 	    auth_pack->pkAuthenticator.ctime = ctsec;
3177934SMark.Phalan@Sun.COM 	    auth_pack->pkAuthenticator.cusec = cusec;
3187934SMark.Phalan@Sun.COM 	    auth_pack->pkAuthenticator.nonce = nonce;
3197934SMark.Phalan@Sun.COM 	    auth_pack->pkAuthenticator.paChecksum = *cksum;
3207934SMark.Phalan@Sun.COM 	    auth_pack->clientDHNonce.length = 0;
3217934SMark.Phalan@Sun.COM 	    auth_pack->clientPublicValue = info;
3227934SMark.Phalan@Sun.COM 
3237934SMark.Phalan@Sun.COM 	    /* add List of CMS algorithms */
3247934SMark.Phalan@Sun.COM 	    retval = create_krb5_supportedCMSTypes(context, plgctx->cryptoctx,
3257934SMark.Phalan@Sun.COM 			reqctx->cryptoctx, reqctx->idctx,
3267934SMark.Phalan@Sun.COM 			&auth_pack->supportedCMSTypes);
3277934SMark.Phalan@Sun.COM 	    if (retval)
3287934SMark.Phalan@Sun.COM 		goto cleanup;
3297934SMark.Phalan@Sun.COM 	    break;
3307934SMark.Phalan@Sun.COM 	default:
3317934SMark.Phalan@Sun.COM 	    pkiDebug("as_req: unrecognized pa_type = %d\n",
3327934SMark.Phalan@Sun.COM 		    (int)reqctx->pa_type);
3337934SMark.Phalan@Sun.COM 	    retval = -1;
3347934SMark.Phalan@Sun.COM 	    goto cleanup;
3357934SMark.Phalan@Sun.COM     }
3367934SMark.Phalan@Sun.COM 
3377934SMark.Phalan@Sun.COM     switch(protocol) {
3387934SMark.Phalan@Sun.COM 	case DH_PROTOCOL:
3397934SMark.Phalan@Sun.COM 	    pkiDebug("as_req: DH key transport algorithm\n");
3407934SMark.Phalan@Sun.COM 	    retval = pkinit_copy_krb5_octet_data(&info->algorithm.algorithm, &dh_oid);
3417934SMark.Phalan@Sun.COM 	    if (retval) {
3427934SMark.Phalan@Sun.COM 		pkiDebug("failed to copy dh_oid\n");
3437934SMark.Phalan@Sun.COM 		goto cleanup;
3447934SMark.Phalan@Sun.COM 	    }
3457934SMark.Phalan@Sun.COM 
3467934SMark.Phalan@Sun.COM 	    /* create client-side DH keys */
3477934SMark.Phalan@Sun.COM 	    if ((retval = client_create_dh(context, plgctx->cryptoctx,
3487934SMark.Phalan@Sun.COM 		    reqctx->cryptoctx, reqctx->idctx, reqctx->opts->dh_size,
3497934SMark.Phalan@Sun.COM 		    &info->algorithm.parameters.data,
3507934SMark.Phalan@Sun.COM 		    &info->algorithm.parameters.length,
3517934SMark.Phalan@Sun.COM 		    &info->subjectPublicKey.data,
3527934SMark.Phalan@Sun.COM 		    &info->subjectPublicKey.length)) != 0) {
3537934SMark.Phalan@Sun.COM 		pkiDebug("failed to create dh parameters\n");
3547934SMark.Phalan@Sun.COM 		goto cleanup;
3557934SMark.Phalan@Sun.COM 	    }
3567934SMark.Phalan@Sun.COM 	    break;
3577934SMark.Phalan@Sun.COM 	case RSA_PROTOCOL:
3587934SMark.Phalan@Sun.COM 	    pkiDebug("as_req: RSA key transport algorithm\n");
3597934SMark.Phalan@Sun.COM 	    switch((int)reqctx->pa_type) {
3607934SMark.Phalan@Sun.COM 		case KRB5_PADATA_PK_AS_REQ_OLD:
3617934SMark.Phalan@Sun.COM 		    auth_pack9->clientPublicValue = NULL;
3627934SMark.Phalan@Sun.COM 		    break;
3637934SMark.Phalan@Sun.COM 		case KRB5_PADATA_PK_AS_REQ:
3647934SMark.Phalan@Sun.COM 		    free_krb5_subject_pk_info(&info);
3657934SMark.Phalan@Sun.COM 		    auth_pack->clientPublicValue = NULL;
3667934SMark.Phalan@Sun.COM 		    break;
3677934SMark.Phalan@Sun.COM 	    }
3687934SMark.Phalan@Sun.COM 	    break;
3697934SMark.Phalan@Sun.COM 	default:
3707934SMark.Phalan@Sun.COM 	    pkiDebug("as_req: unknown key transport protocol %d\n",
3717934SMark.Phalan@Sun.COM 		    protocol);
3727934SMark.Phalan@Sun.COM 	    retval = -1;
3737934SMark.Phalan@Sun.COM 	    goto cleanup;
3747934SMark.Phalan@Sun.COM     }
3757934SMark.Phalan@Sun.COM 
3767934SMark.Phalan@Sun.COM     /* Encode the authpack */
3777934SMark.Phalan@Sun.COM     switch((int)reqctx->pa_type) {
3787934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
3797934SMark.Phalan@Sun.COM 	    retval = k5int_encode_krb5_auth_pack(auth_pack, &coded_auth_pack);
3807934SMark.Phalan@Sun.COM 	    break;
3817934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
3827934SMark.Phalan@Sun.COM 	    retval = k5int_encode_krb5_auth_pack_draft9(auth_pack9,
3837934SMark.Phalan@Sun.COM 							&coded_auth_pack);
3847934SMark.Phalan@Sun.COM 	    break;
3857934SMark.Phalan@Sun.COM     }
3867934SMark.Phalan@Sun.COM     if (retval) {
3877934SMark.Phalan@Sun.COM 	pkiDebug("failed to encode the AuthPack %d\n", retval);
3887934SMark.Phalan@Sun.COM 	goto cleanup;
3897934SMark.Phalan@Sun.COM     }
3907934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
3917934SMark.Phalan@Sun.COM     print_buffer_bin((unsigned char *)coded_auth_pack->data,
3927934SMark.Phalan@Sun.COM 		     coded_auth_pack->length,
3937934SMark.Phalan@Sun.COM 		     "/tmp/client_auth_pack");
3947934SMark.Phalan@Sun.COM #endif
3957934SMark.Phalan@Sun.COM 
3967934SMark.Phalan@Sun.COM     /* create PKCS7 object from authpack */
3977934SMark.Phalan@Sun.COM     switch((int)reqctx->pa_type) {
3987934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
3997934SMark.Phalan@Sun.COM 	    init_krb5_pa_pk_as_req(&req);
4007934SMark.Phalan@Sun.COM 	    if (req == NULL) {
4017934SMark.Phalan@Sun.COM 		retval = ENOMEM;
4027934SMark.Phalan@Sun.COM 		goto cleanup;
4037934SMark.Phalan@Sun.COM 	    }
4047934SMark.Phalan@Sun.COM 	    retval = cms_signeddata_create(context, plgctx->cryptoctx,
4057934SMark.Phalan@Sun.COM 		reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_CLIENT, 1,
4067934SMark.Phalan@Sun.COM 		(unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
4077934SMark.Phalan@Sun.COM 		&req->signedAuthPack.data, &req->signedAuthPack.length);
4087934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
4097934SMark.Phalan@Sun.COM 	    print_buffer_bin((unsigned char *)req->signedAuthPack.data,
4107934SMark.Phalan@Sun.COM 			     req->signedAuthPack.length,
4117934SMark.Phalan@Sun.COM 			     "/tmp/client_signed_data");
4127934SMark.Phalan@Sun.COM #endif
4137934SMark.Phalan@Sun.COM 	    break;
4147934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
4157934SMark.Phalan@Sun.COM 	    init_krb5_pa_pk_as_req_draft9(&req9);
4167934SMark.Phalan@Sun.COM 	    if (req9 == NULL) {
4177934SMark.Phalan@Sun.COM 		retval = ENOMEM;
4187934SMark.Phalan@Sun.COM 		goto cleanup;
4197934SMark.Phalan@Sun.COM 	    }
4207934SMark.Phalan@Sun.COM 	    retval = cms_signeddata_create(context, plgctx->cryptoctx,
4217934SMark.Phalan@Sun.COM 		reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_DRAFT9, 1,
4227934SMark.Phalan@Sun.COM 		(unsigned char *)coded_auth_pack->data, coded_auth_pack->length,
4237934SMark.Phalan@Sun.COM 		&req9->signedAuthPack.data, &req9->signedAuthPack.length);
4247934SMark.Phalan@Sun.COM 	    break;
4257934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
4267934SMark.Phalan@Sun.COM 	    print_buffer_bin((unsigned char *)req9->signedAuthPack.data,
4277934SMark.Phalan@Sun.COM 			     req9->signedAuthPack.length,
4287934SMark.Phalan@Sun.COM 			     "/tmp/client_signed_data_draft9");
4297934SMark.Phalan@Sun.COM #endif
4307934SMark.Phalan@Sun.COM     }
4317934SMark.Phalan@Sun.COM     krb5_free_data(context, coded_auth_pack);
4327934SMark.Phalan@Sun.COM     if (retval) {
4337934SMark.Phalan@Sun.COM 	pkiDebug("failed to create pkcs7 signed data\n");
4347934SMark.Phalan@Sun.COM 	goto cleanup;
4357934SMark.Phalan@Sun.COM     }
4367934SMark.Phalan@Sun.COM 
4377934SMark.Phalan@Sun.COM     /* create a list of trusted CAs */
4387934SMark.Phalan@Sun.COM     switch((int)reqctx->pa_type) {
4397934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
4407934SMark.Phalan@Sun.COM 	    retval = create_krb5_trustedCertifiers(context, plgctx->cryptoctx,
4417934SMark.Phalan@Sun.COM 		reqctx->cryptoctx, reqctx->idctx, &req->trustedCertifiers);
4427934SMark.Phalan@Sun.COM 	    if (retval)
4437934SMark.Phalan@Sun.COM 		goto cleanup;
4447934SMark.Phalan@Sun.COM 	    retval = create_issuerAndSerial(context, plgctx->cryptoctx,
4457934SMark.Phalan@Sun.COM 		reqctx->cryptoctx, reqctx->idctx, &req->kdcPkId.data,
4467934SMark.Phalan@Sun.COM 		&req->kdcPkId.length);
4477934SMark.Phalan@Sun.COM 	    if (retval)
4487934SMark.Phalan@Sun.COM 		goto cleanup;
4497934SMark.Phalan@Sun.COM 
4507934SMark.Phalan@Sun.COM 	    /* Encode the as-req */
4517934SMark.Phalan@Sun.COM 	    retval = k5int_encode_krb5_pa_pk_as_req(req, as_req);
4527934SMark.Phalan@Sun.COM 	    break;
4537934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
4547934SMark.Phalan@Sun.COM #if 0
4557934SMark.Phalan@Sun.COM 	    /* W2K3 KDC doesn't like this */
4567934SMark.Phalan@Sun.COM 	    retval = create_krb5_trustedCas(context, plgctx->cryptoctx,
4577934SMark.Phalan@Sun.COM 		reqctx->cryptoctx, reqctx->idctx, 1, &req9->trustedCertifiers);
4587934SMark.Phalan@Sun.COM 	    if (retval)
4597934SMark.Phalan@Sun.COM 		goto cleanup;
4607934SMark.Phalan@Sun.COM 
4617934SMark.Phalan@Sun.COM #endif
4627934SMark.Phalan@Sun.COM 	    retval = create_issuerAndSerial(context, plgctx->cryptoctx,
4637934SMark.Phalan@Sun.COM 		reqctx->cryptoctx, reqctx->idctx, &req9->kdcCert.data,
4647934SMark.Phalan@Sun.COM 		&req9->kdcCert.length);
4657934SMark.Phalan@Sun.COM 	    if (retval)
4667934SMark.Phalan@Sun.COM 		goto cleanup;
4677934SMark.Phalan@Sun.COM 	    /* Encode the as-req */
4687934SMark.Phalan@Sun.COM 	    retval = k5int_encode_krb5_pa_pk_as_req_draft9(req9, as_req);
4697934SMark.Phalan@Sun.COM 	    break;
4707934SMark.Phalan@Sun.COM     }
4717934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
4727934SMark.Phalan@Sun.COM     if (!retval)
4737934SMark.Phalan@Sun.COM 	print_buffer_bin((unsigned char *)(*as_req)->data, (*as_req)->length,
4747934SMark.Phalan@Sun.COM 			 "/tmp/client_as_req");
4757934SMark.Phalan@Sun.COM #endif
4767934SMark.Phalan@Sun.COM 
4777934SMark.Phalan@Sun.COM cleanup:
4787934SMark.Phalan@Sun.COM     switch((int)reqctx->pa_type) {
4797934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
4807934SMark.Phalan@Sun.COM 	    free_krb5_auth_pack(&auth_pack);
4817934SMark.Phalan@Sun.COM 	    free_krb5_pa_pk_as_req(&req);
4827934SMark.Phalan@Sun.COM 	    break;
4837934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
4847934SMark.Phalan@Sun.COM 	    free_krb5_pa_pk_as_req_draft9(&req9);
4857934SMark.Phalan@Sun.COM 	    free(auth_pack9);
4867934SMark.Phalan@Sun.COM 	    break;
4877934SMark.Phalan@Sun.COM     }
4887934SMark.Phalan@Sun.COM 
4897934SMark.Phalan@Sun.COM 
4907934SMark.Phalan@Sun.COM     pkiDebug("pkinit_as_req_create retval=%d\n", (int) retval);
4917934SMark.Phalan@Sun.COM 
4927934SMark.Phalan@Sun.COM     return retval;
4937934SMark.Phalan@Sun.COM }
4947934SMark.Phalan@Sun.COM 
4957934SMark.Phalan@Sun.COM krb5_error_code
4967934SMark.Phalan@Sun.COM pa_pkinit_parse_rep(krb5_context context,
4977934SMark.Phalan@Sun.COM 		    pkinit_context plgctx,
4987934SMark.Phalan@Sun.COM 		    pkinit_req_context reqctx,
4997934SMark.Phalan@Sun.COM 		    krb5_kdc_req * request,
5007934SMark.Phalan@Sun.COM 		    krb5_pa_data * in_padata,
5017934SMark.Phalan@Sun.COM 		    krb5_enctype etype,
5027934SMark.Phalan@Sun.COM 		    krb5_keyblock * as_key,
5037934SMark.Phalan@Sun.COM 		    krb5_data *encoded_request)
5047934SMark.Phalan@Sun.COM {
5057934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
5067934SMark.Phalan@Sun.COM     krb5_data asRep = { 0, 0, NULL};
5077934SMark.Phalan@Sun.COM 
5087934SMark.Phalan@Sun.COM     /*
5097934SMark.Phalan@Sun.COM      * One way or the other - success or failure - no other PA systems can
5107934SMark.Phalan@Sun.COM      * work if the server sent us a PKINIT reply, since only we know how to
5117934SMark.Phalan@Sun.COM      * decrypt the key.
5127934SMark.Phalan@Sun.COM      */
5137934SMark.Phalan@Sun.COM     if ((in_padata == NULL) || (in_padata->length == 0)) {
5147934SMark.Phalan@Sun.COM 	pkiDebug("pa_pkinit_parse_rep: no in_padata\n");
5157934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
5167934SMark.Phalan@Sun.COM     }
5177934SMark.Phalan@Sun.COM 
5187934SMark.Phalan@Sun.COM     asRep.data = (char *) in_padata->contents;
5197934SMark.Phalan@Sun.COM     asRep.length = in_padata->length;
5207934SMark.Phalan@Sun.COM 
5217934SMark.Phalan@Sun.COM     retval =
5227934SMark.Phalan@Sun.COM 	pkinit_as_rep_parse(context, plgctx, reqctx, in_padata->pa_type,
5237934SMark.Phalan@Sun.COM 			    request, &asRep, as_key, etype, encoded_request);
5247934SMark.Phalan@Sun.COM     if (retval) {
5257934SMark.Phalan@Sun.COM 	pkiDebug("pkinit_as_rep_parse returned %d (%s)\n",
5267934SMark.Phalan@Sun.COM 		 retval, error_message(retval));
5277934SMark.Phalan@Sun.COM 	goto cleanup;
5287934SMark.Phalan@Sun.COM     }
5297934SMark.Phalan@Sun.COM 
5307934SMark.Phalan@Sun.COM     retval = 0;
5317934SMark.Phalan@Sun.COM 
5327934SMark.Phalan@Sun.COM cleanup:
5337934SMark.Phalan@Sun.COM 
5347934SMark.Phalan@Sun.COM     return retval;
5357934SMark.Phalan@Sun.COM }
5367934SMark.Phalan@Sun.COM 
5377934SMark.Phalan@Sun.COM static krb5_error_code
5387934SMark.Phalan@Sun.COM verify_kdc_san(krb5_context context,
5397934SMark.Phalan@Sun.COM 	       pkinit_context plgctx,
5407934SMark.Phalan@Sun.COM 	       pkinit_req_context reqctx,
5417934SMark.Phalan@Sun.COM 	       krb5_principal kdcprinc,
5427934SMark.Phalan@Sun.COM 	       int *valid_san,
5437934SMark.Phalan@Sun.COM 	       int *need_eku_checking)
5447934SMark.Phalan@Sun.COM {
5457934SMark.Phalan@Sun.COM     krb5_error_code retval;
5467934SMark.Phalan@Sun.COM     char **certhosts = NULL, **cfghosts = NULL;
5477934SMark.Phalan@Sun.COM     krb5_principal *princs = NULL;
5487934SMark.Phalan@Sun.COM     unsigned char ***get_dns;
5497934SMark.Phalan@Sun.COM     int i, j;
5507934SMark.Phalan@Sun.COM 
5517934SMark.Phalan@Sun.COM     *valid_san = 0;
5527934SMark.Phalan@Sun.COM     *need_eku_checking = 1;
5537934SMark.Phalan@Sun.COM 
5547934SMark.Phalan@Sun.COM     retval = pkinit_libdefault_strings(context,
5557934SMark.Phalan@Sun.COM 				       krb5_princ_realm(context, kdcprinc),
5567934SMark.Phalan@Sun.COM 				       "pkinit_kdc_hostname",
5577934SMark.Phalan@Sun.COM 				       &cfghosts);
5587934SMark.Phalan@Sun.COM     if (retval || cfghosts == NULL) {
5597934SMark.Phalan@Sun.COM 	pkiDebug("%s: No pkinit_kdc_hostname values found in config file\n",
5607934SMark.Phalan@Sun.COM 		 __FUNCTION__);
5617934SMark.Phalan@Sun.COM 	get_dns = NULL;
5627934SMark.Phalan@Sun.COM     } else {
5637934SMark.Phalan@Sun.COM 	pkiDebug("%s: pkinit_kdc_hostname values found in config file\n",
5647934SMark.Phalan@Sun.COM 		 __FUNCTION__);
5657934SMark.Phalan@Sun.COM 	get_dns = (unsigned char ***)&certhosts;
5667934SMark.Phalan@Sun.COM     }
5677934SMark.Phalan@Sun.COM 
5687934SMark.Phalan@Sun.COM     retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx,
5697934SMark.Phalan@Sun.COM 				       reqctx->cryptoctx, reqctx->idctx,
5707934SMark.Phalan@Sun.COM 				       &princs, NULL, get_dns);
5717934SMark.Phalan@Sun.COM     if (retval) {
5727934SMark.Phalan@Sun.COM 	pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
5737934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
5747934SMark.Phalan@Sun.COM 	goto out;
5757934SMark.Phalan@Sun.COM     }
5767934SMark.Phalan@Sun.COM #if 0
5777934SMark.Phalan@Sun.COM     retval = call_san_checking_plugins(context, plgctx, reqctx, idctx,
5787934SMark.Phalan@Sun.COM 				       princs, hosts, &plugin_decision,
5797934SMark.Phalan@Sun.COM 				       need_eku_checking);
5807934SMark.Phalan@Sun.COM     pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
5817934SMark.Phalan@Sun.COM 	     __FUNCTION__);
5827934SMark.Phalan@Sun.COM     if (retval) {
5837934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
5847934SMark.Phalan@Sun.COM 	goto out;
5857934SMark.Phalan@Sun.COM     }
5867934SMark.Phalan@Sun.COM     pkiDebug("%s: call_san_checking_plugins() returned decision %d and "
5877934SMark.Phalan@Sun.COM 	     "need_eku_checking %d\n",
5887934SMark.Phalan@Sun.COM 	     __FUNCTION__, plugin_decision, *need_eku_checking);
5897934SMark.Phalan@Sun.COM     if (plugin_decision != NO_DECISION) {
5907934SMark.Phalan@Sun.COM 	retval = plugin_decision;
5917934SMark.Phalan@Sun.COM 	goto out;
5927934SMark.Phalan@Sun.COM     }
5937934SMark.Phalan@Sun.COM #endif
5947934SMark.Phalan@Sun.COM 
5957934SMark.Phalan@Sun.COM     pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
5967934SMark.Phalan@Sun.COM     for (i = 0; princs != NULL && princs[i] != NULL; i++) {
5977934SMark.Phalan@Sun.COM 	if (krb5_principal_compare(context, princs[i], kdcprinc)) {
5987934SMark.Phalan@Sun.COM 	    pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
5997934SMark.Phalan@Sun.COM 	    *valid_san = 1;
6007934SMark.Phalan@Sun.COM 	    *need_eku_checking = 0;
6017934SMark.Phalan@Sun.COM 	    retval = 0;
6027934SMark.Phalan@Sun.COM 	    goto out;
6037934SMark.Phalan@Sun.COM 	}
6047934SMark.Phalan@Sun.COM     }
6057934SMark.Phalan@Sun.COM     pkiDebug("%s: no pkinit san match found\n", __FUNCTION__);
6067934SMark.Phalan@Sun.COM 
6077934SMark.Phalan@Sun.COM     if (certhosts == NULL) {
6087934SMark.Phalan@Sun.COM 	pkiDebug("%s: no certhosts (or we wouldn't accept them anyway)\n",
6097934SMark.Phalan@Sun.COM 		 __FUNCTION__);
6107934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
6117934SMark.Phalan@Sun.COM 	goto out;
6127934SMark.Phalan@Sun.COM     }
6137934SMark.Phalan@Sun.COM 
6147934SMark.Phalan@Sun.COM     for (i = 0; certhosts[i] != NULL; i++) {
6157934SMark.Phalan@Sun.COM 	for (j = 0; cfghosts != NULL && cfghosts[j] != NULL; j++) {
6167934SMark.Phalan@Sun.COM 	    pkiDebug("%s: comparing cert name '%s' with config name '%s'\n",
6177934SMark.Phalan@Sun.COM 		     __FUNCTION__, certhosts[i], cfghosts[j]);
6187934SMark.Phalan@Sun.COM 	    if (strcmp(certhosts[i], cfghosts[j]) == 0) {
6197934SMark.Phalan@Sun.COM 		pkiDebug("%s: we have a dnsName match\n", __FUNCTION__);
6207934SMark.Phalan@Sun.COM 		*valid_san = 1;
6217934SMark.Phalan@Sun.COM 		retval = 0;
6227934SMark.Phalan@Sun.COM 		goto out;
6237934SMark.Phalan@Sun.COM 	    }
6247934SMark.Phalan@Sun.COM 	}
6257934SMark.Phalan@Sun.COM     }
6267934SMark.Phalan@Sun.COM     pkiDebug("%s: no dnsName san match found\n", __FUNCTION__);
6277934SMark.Phalan@Sun.COM 
6287934SMark.Phalan@Sun.COM     /* We found no match */
6297934SMark.Phalan@Sun.COM     retval = 0;
6307934SMark.Phalan@Sun.COM 
6317934SMark.Phalan@Sun.COM out:
6327934SMark.Phalan@Sun.COM     if (princs != NULL) {
6337934SMark.Phalan@Sun.COM 	for (i = 0; princs[i] != NULL; i++)
6347934SMark.Phalan@Sun.COM 	    krb5_free_principal(context, princs[i]);
6357934SMark.Phalan@Sun.COM 	free(princs);
6367934SMark.Phalan@Sun.COM     }
6377934SMark.Phalan@Sun.COM     if (certhosts != NULL) {
6387934SMark.Phalan@Sun.COM 	for (i = 0; certhosts[i] != NULL; i++)
6397934SMark.Phalan@Sun.COM 	    free(certhosts[i]);
6407934SMark.Phalan@Sun.COM 	free(certhosts);
6417934SMark.Phalan@Sun.COM     }
6427934SMark.Phalan@Sun.COM     if (cfghosts != NULL)
6437934SMark.Phalan@Sun.COM 	profile_free_list(cfghosts);
6447934SMark.Phalan@Sun.COM 
6457934SMark.Phalan@Sun.COM     pkiDebug("%s: returning retval %d, valid_san %d, need_eku_checking %d\n",
6467934SMark.Phalan@Sun.COM 	     __FUNCTION__, retval, *valid_san, *need_eku_checking);
6477934SMark.Phalan@Sun.COM     return retval;
6487934SMark.Phalan@Sun.COM }
6497934SMark.Phalan@Sun.COM 
6507934SMark.Phalan@Sun.COM static krb5_error_code
6517934SMark.Phalan@Sun.COM verify_kdc_eku(krb5_context context,
6527934SMark.Phalan@Sun.COM 	       pkinit_context plgctx,
6537934SMark.Phalan@Sun.COM 	       pkinit_req_context reqctx,
6547934SMark.Phalan@Sun.COM 	       int *eku_accepted)
6557934SMark.Phalan@Sun.COM {
6567934SMark.Phalan@Sun.COM     krb5_error_code retval;
6577934SMark.Phalan@Sun.COM 
6587934SMark.Phalan@Sun.COM     *eku_accepted = 0;
6597934SMark.Phalan@Sun.COM 
6607934SMark.Phalan@Sun.COM     if (reqctx->opts->require_eku == 0) {
6617934SMark.Phalan@Sun.COM 	pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__);
6627934SMark.Phalan@Sun.COM 	*eku_accepted = 1;
6637934SMark.Phalan@Sun.COM 	retval = 0;
6647934SMark.Phalan@Sun.COM 	goto out;
6657934SMark.Phalan@Sun.COM     }
6667934SMark.Phalan@Sun.COM     retval = crypto_check_cert_eku(context, plgctx->cryptoctx,
6677934SMark.Phalan@Sun.COM 				   reqctx->cryptoctx, reqctx->idctx,
6687934SMark.Phalan@Sun.COM 				   1, /* kdc cert */
6697934SMark.Phalan@Sun.COM 				   reqctx->opts->accept_secondary_eku,
6707934SMark.Phalan@Sun.COM 				   eku_accepted);
6717934SMark.Phalan@Sun.COM     if (retval) {
6727934SMark.Phalan@Sun.COM 	pkiDebug("%s: Error from crypto_check_cert_eku %d (%s)\n",
6737934SMark.Phalan@Sun.COM 		 __FUNCTION__, retval, error_message(retval));
6747934SMark.Phalan@Sun.COM 	goto out;
6757934SMark.Phalan@Sun.COM     }
6767934SMark.Phalan@Sun.COM 
6777934SMark.Phalan@Sun.COM out:
6787934SMark.Phalan@Sun.COM     pkiDebug("%s: returning retval %d, eku_accepted %d\n",
6797934SMark.Phalan@Sun.COM 	     __FUNCTION__, retval, *eku_accepted);
6807934SMark.Phalan@Sun.COM     return retval;
6817934SMark.Phalan@Sun.COM }
6827934SMark.Phalan@Sun.COM 
6837934SMark.Phalan@Sun.COM /*
6847934SMark.Phalan@Sun.COM  * Parse PA-PK-AS-REP message. Optionally evaluates the message's
6857934SMark.Phalan@Sun.COM  * certificate chain.
6867934SMark.Phalan@Sun.COM  * Optionally returns various components.
6877934SMark.Phalan@Sun.COM  */
6887934SMark.Phalan@Sun.COM krb5_error_code
6897934SMark.Phalan@Sun.COM pkinit_as_rep_parse(krb5_context context,
6907934SMark.Phalan@Sun.COM 		    pkinit_context plgctx,
6917934SMark.Phalan@Sun.COM   		    pkinit_req_context reqctx,
6927934SMark.Phalan@Sun.COM 		    krb5_preauthtype pa_type,
6937934SMark.Phalan@Sun.COM 		    krb5_kdc_req *request,
6947934SMark.Phalan@Sun.COM 		    const krb5_data *as_rep,
6957934SMark.Phalan@Sun.COM 		    krb5_keyblock *key_block,
6967934SMark.Phalan@Sun.COM 		    krb5_enctype etype,
6977934SMark.Phalan@Sun.COM 		    krb5_data *encoded_request)
6987934SMark.Phalan@Sun.COM {
6997934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
7007934SMark.Phalan@Sun.COM     krb5_pa_pk_as_rep *kdc_reply = NULL;
7017934SMark.Phalan@Sun.COM     krb5_kdc_dh_key_info *kdc_dh = NULL;
7027934SMark.Phalan@Sun.COM     krb5_reply_key_pack *key_pack = NULL;
7037934SMark.Phalan@Sun.COM     krb5_reply_key_pack_draft9 *key_pack9 = NULL;
7047934SMark.Phalan@Sun.COM     krb5_octet_data dh_data = { 0, 0, NULL };
7057934SMark.Phalan@Sun.COM     unsigned char *client_key = NULL, *kdc_hostname = NULL;
7067934SMark.Phalan@Sun.COM     unsigned int client_key_len = 0;
7077934SMark.Phalan@Sun.COM     krb5_checksum cksum = {0, 0, 0, NULL};
7087934SMark.Phalan@Sun.COM     krb5_data k5data;
7097934SMark.Phalan@Sun.COM     int valid_san = 0;
7107934SMark.Phalan@Sun.COM     int valid_eku = 0;
7117934SMark.Phalan@Sun.COM     int need_eku_checking = 1;
7127934SMark.Phalan@Sun.COM 
7137934SMark.Phalan@Sun.COM     assert((as_rep != NULL) && (key_block != NULL));
7147934SMark.Phalan@Sun.COM 
7157934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
7167934SMark.Phalan@Sun.COM     print_buffer_bin((unsigned char *)as_rep->data, as_rep->length,
7177934SMark.Phalan@Sun.COM 		     "/tmp/client_as_rep");
7187934SMark.Phalan@Sun.COM #endif
7197934SMark.Phalan@Sun.COM 
7207934SMark.Phalan@Sun.COM     if ((retval = k5int_decode_krb5_pa_pk_as_rep(as_rep, &kdc_reply))) {
7217934SMark.Phalan@Sun.COM 	pkiDebug("decode_krb5_as_rep failed %d\n", retval);
7227934SMark.Phalan@Sun.COM 	return retval;
7237934SMark.Phalan@Sun.COM     }
7247934SMark.Phalan@Sun.COM 
7257934SMark.Phalan@Sun.COM     switch(kdc_reply->choice) {
7267934SMark.Phalan@Sun.COM 	case choice_pa_pk_as_rep_dhInfo:
7277934SMark.Phalan@Sun.COM 	    pkiDebug("as_rep: DH key transport algorithm\n");
7287934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
7297934SMark.Phalan@Sun.COM     print_buffer_bin(kdc_reply->u.dh_Info.dhSignedData.data,
7307934SMark.Phalan@Sun.COM 	kdc_reply->u.dh_Info.dhSignedData.length, "/tmp/client_kdc_signeddata");
7317934SMark.Phalan@Sun.COM #endif
7327934SMark.Phalan@Sun.COM 	    if ((retval = cms_signeddata_verify(context, plgctx->cryptoctx,
7337934SMark.Phalan@Sun.COM 		    reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_SERVER,
7347934SMark.Phalan@Sun.COM 		    reqctx->opts->require_crl_checking,
7357934SMark.Phalan@Sun.COM 		    kdc_reply->u.dh_Info.dhSignedData.data,
7367934SMark.Phalan@Sun.COM 		    kdc_reply->u.dh_Info.dhSignedData.length,
7377934SMark.Phalan@Sun.COM 		    &dh_data.data, &dh_data.length, NULL, NULL)) != 0) {
7387934SMark.Phalan@Sun.COM 		pkiDebug("failed to verify pkcs7 signed data\n");
7397934SMark.Phalan@Sun.COM 		goto cleanup;
7407934SMark.Phalan@Sun.COM 	    }
7417934SMark.Phalan@Sun.COM 
7427934SMark.Phalan@Sun.COM 	    break;
7437934SMark.Phalan@Sun.COM 	case choice_pa_pk_as_rep_encKeyPack:
7447934SMark.Phalan@Sun.COM 	    pkiDebug("as_rep: RSA key transport algorithm\n");
7457934SMark.Phalan@Sun.COM 	    if ((retval = cms_envelopeddata_verify(context, plgctx->cryptoctx,
7467934SMark.Phalan@Sun.COM 		    reqctx->cryptoctx, reqctx->idctx, pa_type,
7477934SMark.Phalan@Sun.COM 		    reqctx->opts->require_crl_checking,
7487934SMark.Phalan@Sun.COM 		    kdc_reply->u.encKeyPack.data,
7497934SMark.Phalan@Sun.COM 		    kdc_reply->u.encKeyPack.length,
7507934SMark.Phalan@Sun.COM 		    &dh_data.data, &dh_data.length)) != 0) {
7517934SMark.Phalan@Sun.COM 		pkiDebug("failed to verify pkcs7 enveloped data\n");
7527934SMark.Phalan@Sun.COM 		goto cleanup;
7537934SMark.Phalan@Sun.COM 	    }
7547934SMark.Phalan@Sun.COM 	    break;
7557934SMark.Phalan@Sun.COM 	default:
7567934SMark.Phalan@Sun.COM 	    pkiDebug("unknown as_rep type %d\n", kdc_reply->choice);
7577934SMark.Phalan@Sun.COM 	    retval = -1;
7587934SMark.Phalan@Sun.COM 	    goto cleanup;
7597934SMark.Phalan@Sun.COM     }
7607934SMark.Phalan@Sun.COM 
7617934SMark.Phalan@Sun.COM     retval = verify_kdc_san(context, plgctx, reqctx, request->server,
7627934SMark.Phalan@Sun.COM 			    &valid_san, &need_eku_checking);
7637934SMark.Phalan@Sun.COM     if (retval)
7647934SMark.Phalan@Sun.COM 	    goto cleanup;
7657934SMark.Phalan@Sun.COM     if (!valid_san) {
7667934SMark.Phalan@Sun.COM 	pkiDebug("%s: did not find an acceptable SAN in KDC certificate\n",
7677934SMark.Phalan@Sun.COM 		 __FUNCTION__);
7687934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
7697934SMark.Phalan@Sun.COM 	goto cleanup;
7707934SMark.Phalan@Sun.COM     }
7717934SMark.Phalan@Sun.COM 
7727934SMark.Phalan@Sun.COM     if (need_eku_checking) {
7737934SMark.Phalan@Sun.COM 	retval = verify_kdc_eku(context, plgctx, reqctx,
7747934SMark.Phalan@Sun.COM 				&valid_eku);
7757934SMark.Phalan@Sun.COM 	if (retval)
7767934SMark.Phalan@Sun.COM 	    goto cleanup;
7777934SMark.Phalan@Sun.COM 	if (!valid_eku) {
7787934SMark.Phalan@Sun.COM 	    pkiDebug("%s: did not find an acceptable EKU in KDC certificate\n",
7797934SMark.Phalan@Sun.COM 		     __FUNCTION__);
7807934SMark.Phalan@Sun.COM 	    retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
7817934SMark.Phalan@Sun.COM 	    goto cleanup;
7827934SMark.Phalan@Sun.COM 	}
7837934SMark.Phalan@Sun.COM     } else
7847934SMark.Phalan@Sun.COM 	pkiDebug("%s: skipping EKU check\n", __FUNCTION__);
7857934SMark.Phalan@Sun.COM 
7867934SMark.Phalan@Sun.COM     OCTETDATA_TO_KRB5DATA(&dh_data, &k5data);
7877934SMark.Phalan@Sun.COM 
7887934SMark.Phalan@Sun.COM     switch(kdc_reply->choice) {
7897934SMark.Phalan@Sun.COM 	case choice_pa_pk_as_rep_dhInfo:
7907934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
7917934SMark.Phalan@Sun.COM 	    print_buffer_bin(dh_data.data, dh_data.length,
7927934SMark.Phalan@Sun.COM 			     "/tmp/client_dh_key");
7937934SMark.Phalan@Sun.COM #endif
7947934SMark.Phalan@Sun.COM 	    if ((retval = k5int_decode_krb5_kdc_dh_key_info(&k5data,
7957934SMark.Phalan@Sun.COM 		    &kdc_dh)) != 0) {
7967934SMark.Phalan@Sun.COM 		pkiDebug("failed to decode kdc_dh_key_info\n");
7977934SMark.Phalan@Sun.COM 		goto cleanup;
7987934SMark.Phalan@Sun.COM 	    }
7997934SMark.Phalan@Sun.COM 
8007934SMark.Phalan@Sun.COM 	    /* client after KDC reply */
8017934SMark.Phalan@Sun.COM 	    if ((retval = client_process_dh(context, plgctx->cryptoctx,
8027934SMark.Phalan@Sun.COM 		    reqctx->cryptoctx, reqctx->idctx,
8037934SMark.Phalan@Sun.COM 		    kdc_dh->subjectPublicKey.data,
8047934SMark.Phalan@Sun.COM 		    kdc_dh->subjectPublicKey.length,
8057934SMark.Phalan@Sun.COM 		    &client_key, &client_key_len)) != 0) {
8067934SMark.Phalan@Sun.COM 		pkiDebug("failed to process dh params\n");
8077934SMark.Phalan@Sun.COM 		goto cleanup;
8087934SMark.Phalan@Sun.COM 	    }
8097934SMark.Phalan@Sun.COM 
8107934SMark.Phalan@Sun.COM 	    retval = pkinit_octetstring2key(context, etype, client_key,
8117934SMark.Phalan@Sun.COM 					  client_key_len, key_block);
8127934SMark.Phalan@Sun.COM 	    if (retval) {
8137934SMark.Phalan@Sun.COM 		pkiDebug("failed to create key pkinit_octetstring2key %s\n",
8147934SMark.Phalan@Sun.COM 			 error_message(retval));
8157934SMark.Phalan@Sun.COM 		goto cleanup;
8167934SMark.Phalan@Sun.COM 	    }
8177934SMark.Phalan@Sun.COM 
8187934SMark.Phalan@Sun.COM 	    break;
8197934SMark.Phalan@Sun.COM 	case choice_pa_pk_as_rep_encKeyPack:
8207934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
8217934SMark.Phalan@Sun.COM 	    print_buffer_bin(dh_data.data, dh_data.length,
8227934SMark.Phalan@Sun.COM 			     "/tmp/client_key_pack");
8237934SMark.Phalan@Sun.COM #endif
8247934SMark.Phalan@Sun.COM 	    if ((retval = k5int_decode_krb5_reply_key_pack(&k5data,
8257934SMark.Phalan@Sun.COM 		    &key_pack)) != 0) {
8267934SMark.Phalan@Sun.COM 		pkiDebug("failed to decode reply_key_pack\n");
8277934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
8287934SMark.Phalan@Sun.COM     /*
8297934SMark.Phalan@Sun.COM      * LH Beta 3 requires the extra pa-data, even for RFC requests,
8307934SMark.Phalan@Sun.COM      * in order to get the Checksum rather than a Nonce in the reply.
8317934SMark.Phalan@Sun.COM      * This can be removed when LH SP1 is released.
8327934SMark.Phalan@Sun.COM      */
8337934SMark.Phalan@Sun.COM 		if (pa_type == KRB5_PADATA_PK_AS_REP && longhorn == 0)
8347934SMark.Phalan@Sun.COM #else
8357934SMark.Phalan@Sun.COM 		if (pa_type == KRB5_PADATA_PK_AS_REP)
8367934SMark.Phalan@Sun.COM #endif
8377934SMark.Phalan@Sun.COM 		    goto cleanup;
8387934SMark.Phalan@Sun.COM 		else {
8397934SMark.Phalan@Sun.COM 		    if ((retval =
8407934SMark.Phalan@Sun.COM 			k5int_decode_krb5_reply_key_pack_draft9(&k5data,
8417934SMark.Phalan@Sun.COM 							  &key_pack9)) != 0) {
8427934SMark.Phalan@Sun.COM 			pkiDebug("failed to decode reply_key_pack_draft9\n");
8437934SMark.Phalan@Sun.COM 			goto cleanup;
8447934SMark.Phalan@Sun.COM 		    }
8457934SMark.Phalan@Sun.COM 		    pkiDebug("decode reply_key_pack_draft9\n");
8467934SMark.Phalan@Sun.COM 		    if (key_pack9->nonce != request->nonce) {
8477934SMark.Phalan@Sun.COM 			pkiDebug("nonce in AS_REP=%d doesn't match AS_REQ=%d\n",				 key_pack9->nonce, request->nonce);
8487934SMark.Phalan@Sun.COM 			retval = -1;
8497934SMark.Phalan@Sun.COM 			goto cleanup;
8507934SMark.Phalan@Sun.COM 		    }
8517934SMark.Phalan@Sun.COM 		    krb5_copy_keyblock_contents(context, &key_pack9->replyKey,
8527934SMark.Phalan@Sun.COM 						key_block);
8537934SMark.Phalan@Sun.COM 		    break;
8547934SMark.Phalan@Sun.COM 		}
8557934SMark.Phalan@Sun.COM 	    }
8567934SMark.Phalan@Sun.COM 	    /*
8577934SMark.Phalan@Sun.COM 	     * This is hack but Windows sends back SHA1 checksum
8587934SMark.Phalan@Sun.COM 	     * with checksum type of 14. There is currently no
8597934SMark.Phalan@Sun.COM 	     * checksum type of 14 defined.
8607934SMark.Phalan@Sun.COM 	     */
8617934SMark.Phalan@Sun.COM 	    if (key_pack->asChecksum.checksum_type == 14)
8627934SMark.Phalan@Sun.COM 		key_pack->asChecksum.checksum_type = CKSUMTYPE_NIST_SHA;
8637934SMark.Phalan@Sun.COM 	    retval = krb5_c_make_checksum(context,
8647934SMark.Phalan@Sun.COM 					  key_pack->asChecksum.checksum_type,
8657934SMark.Phalan@Sun.COM 					  &key_pack->replyKey,
8667934SMark.Phalan@Sun.COM 					  KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
8677934SMark.Phalan@Sun.COM 					  encoded_request, &cksum);
8687934SMark.Phalan@Sun.COM 	    if (retval) {
8697934SMark.Phalan@Sun.COM 		pkiDebug("failed to make a checksum\n");
8707934SMark.Phalan@Sun.COM 		goto cleanup;
8717934SMark.Phalan@Sun.COM 	    }
8727934SMark.Phalan@Sun.COM 
8737934SMark.Phalan@Sun.COM 	    if ((cksum.length != key_pack->asChecksum.length) ||
8747934SMark.Phalan@Sun.COM 		memcmp(cksum.contents, key_pack->asChecksum.contents,
8757934SMark.Phalan@Sun.COM 			cksum.length)) {
8767934SMark.Phalan@Sun.COM 		pkiDebug("failed to match the checksums\n");
8777934SMark.Phalan@Sun.COM #ifdef DEBUG_CKSUM
8787934SMark.Phalan@Sun.COM 	    pkiDebug("calculating checksum on buf size (%d)\n",
8797934SMark.Phalan@Sun.COM 		     encoded_request->length);
8807934SMark.Phalan@Sun.COM 	    print_buffer(encoded_request->data, encoded_request->length);
8817934SMark.Phalan@Sun.COM 	    pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length);
8827934SMark.Phalan@Sun.COM 	    print_buffer(key_pack->replyKey.contents,
8837934SMark.Phalan@Sun.COM 			 key_pack->replyKey.length);
8847934SMark.Phalan@Sun.COM 	    pkiDebug("received checksum type=%d size=%d ",
8857934SMark.Phalan@Sun.COM 		     key_pack->asChecksum.checksum_type,
8867934SMark.Phalan@Sun.COM 		     key_pack->asChecksum.length);
8877934SMark.Phalan@Sun.COM 	    print_buffer(key_pack->asChecksum.contents,
8887934SMark.Phalan@Sun.COM 			 key_pack->asChecksum.length);
8897934SMark.Phalan@Sun.COM 	    pkiDebug("expected checksum type=%d size=%d ",
8907934SMark.Phalan@Sun.COM 		     cksum.checksum_type, cksum.length);
8917934SMark.Phalan@Sun.COM 	    print_buffer(cksum.contents, cksum.length);
8927934SMark.Phalan@Sun.COM #endif
8937934SMark.Phalan@Sun.COM 		goto cleanup;
8947934SMark.Phalan@Sun.COM 	    } else
8957934SMark.Phalan@Sun.COM 		pkiDebug("checksums match\n");
8967934SMark.Phalan@Sun.COM 
8977934SMark.Phalan@Sun.COM 	    krb5_copy_keyblock_contents(context, &key_pack->replyKey,
8987934SMark.Phalan@Sun.COM 					key_block);
8997934SMark.Phalan@Sun.COM 
9007934SMark.Phalan@Sun.COM 	    break;
9017934SMark.Phalan@Sun.COM 	default:
9027934SMark.Phalan@Sun.COM 	    pkiDebug("unknow as_rep type %d\n", kdc_reply->choice);
9037934SMark.Phalan@Sun.COM 	    goto cleanup;
9047934SMark.Phalan@Sun.COM     }
9057934SMark.Phalan@Sun.COM 
9067934SMark.Phalan@Sun.COM     retval = 0;
9077934SMark.Phalan@Sun.COM 
9087934SMark.Phalan@Sun.COM cleanup:
9097934SMark.Phalan@Sun.COM     if (dh_data.data != NULL)
9107934SMark.Phalan@Sun.COM 	free(dh_data.data);
9117934SMark.Phalan@Sun.COM     if (client_key != NULL)
9127934SMark.Phalan@Sun.COM 	free(client_key);
9137934SMark.Phalan@Sun.COM     free_krb5_kdc_dh_key_info(&kdc_dh);
9147934SMark.Phalan@Sun.COM     free_krb5_pa_pk_as_rep(&kdc_reply);
9157934SMark.Phalan@Sun.COM 
9167934SMark.Phalan@Sun.COM     if (key_pack != NULL) {
9177934SMark.Phalan@Sun.COM 	free_krb5_reply_key_pack(&key_pack);
9187934SMark.Phalan@Sun.COM 	if (cksum.contents != NULL)
9197934SMark.Phalan@Sun.COM 	    free(cksum.contents);
9207934SMark.Phalan@Sun.COM     }
9217934SMark.Phalan@Sun.COM     if (key_pack9 != NULL)
9227934SMark.Phalan@Sun.COM 	free_krb5_reply_key_pack_draft9(&key_pack9);
9237934SMark.Phalan@Sun.COM 
9247934SMark.Phalan@Sun.COM     if (kdc_hostname != NULL)
9257934SMark.Phalan@Sun.COM 	free(kdc_hostname);
9267934SMark.Phalan@Sun.COM 
9277934SMark.Phalan@Sun.COM     pkiDebug("pkinit_as_rep_parse returning %d (%s)\n",
9287934SMark.Phalan@Sun.COM 	     retval, error_message(retval));
9297934SMark.Phalan@Sun.COM     return retval;
9307934SMark.Phalan@Sun.COM }
9317934SMark.Phalan@Sun.COM 
9327934SMark.Phalan@Sun.COM static void
9337934SMark.Phalan@Sun.COM pkinit_client_profile(krb5_context context,
9347934SMark.Phalan@Sun.COM 		      pkinit_context plgctx,
9357934SMark.Phalan@Sun.COM 		      pkinit_req_context reqctx,
9367934SMark.Phalan@Sun.COM 		      krb5_kdc_req *request)
9377934SMark.Phalan@Sun.COM {
9387934SMark.Phalan@Sun.COM     char *eku_string = NULL;
9397934SMark.Phalan@Sun.COM 
9407934SMark.Phalan@Sun.COM     pkiDebug("pkinit_client_profile %p %p %p %p\n",
9417934SMark.Phalan@Sun.COM 	     context, plgctx, reqctx, request);
9427934SMark.Phalan@Sun.COM 
9437934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_boolean(context, &request->server->realm,
9447934SMark.Phalan@Sun.COM 			      "pkinit_win2k",
9457934SMark.Phalan@Sun.COM 			      reqctx->opts->win2k_target,
9467934SMark.Phalan@Sun.COM 			      &reqctx->opts->win2k_target);
9477934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_boolean(context, &request->server->realm,
9487934SMark.Phalan@Sun.COM 			      "pkinit_win2k_require_binding",
9497934SMark.Phalan@Sun.COM 			      reqctx->opts->win2k_require_cksum,
9507934SMark.Phalan@Sun.COM 			      &reqctx->opts->win2k_require_cksum);
9517934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_boolean(context, &request->server->realm,
9527934SMark.Phalan@Sun.COM 			      "pkinit_require_crl_checking",
9537934SMark.Phalan@Sun.COM 			      reqctx->opts->require_crl_checking,
9547934SMark.Phalan@Sun.COM 			      &reqctx->opts->require_crl_checking);
9557934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_integer(context, &request->server->realm,
9567934SMark.Phalan@Sun.COM 			      "pkinit_dh_min_bits",
9577934SMark.Phalan@Sun.COM 			      reqctx->opts->dh_size,
9587934SMark.Phalan@Sun.COM 			      &reqctx->opts->dh_size);
9597934SMark.Phalan@Sun.COM     if (reqctx->opts->dh_size != 1024 && reqctx->opts->dh_size != 2048
9607934SMark.Phalan@Sun.COM         && reqctx->opts->dh_size != 4096) {
9617934SMark.Phalan@Sun.COM 	pkiDebug("%s: invalid value (%d) for pkinit_dh_min_bits, "
9627934SMark.Phalan@Sun.COM 		 "using default value (%d) instead\n", __FUNCTION__,
9637934SMark.Phalan@Sun.COM 		 reqctx->opts->dh_size, PKINIT_DEFAULT_DH_MIN_BITS);
9647934SMark.Phalan@Sun.COM 	reqctx->opts->dh_size = PKINIT_DEFAULT_DH_MIN_BITS;
9657934SMark.Phalan@Sun.COM     }
9667934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_string(context, &request->server->realm,
9677934SMark.Phalan@Sun.COM 			     "pkinit_eku_checking",
9687934SMark.Phalan@Sun.COM 			     &eku_string);
9697934SMark.Phalan@Sun.COM     if (eku_string != NULL) {
9707934SMark.Phalan@Sun.COM 	if (strcasecmp(eku_string, "kpKDC") == 0) {
9717934SMark.Phalan@Sun.COM 	    reqctx->opts->require_eku = 1;
9727934SMark.Phalan@Sun.COM 	    reqctx->opts->accept_secondary_eku = 0;
9737934SMark.Phalan@Sun.COM 	} else if (strcasecmp(eku_string, "kpServerAuth") == 0) {
9747934SMark.Phalan@Sun.COM 	    reqctx->opts->require_eku = 1;
9757934SMark.Phalan@Sun.COM 	    reqctx->opts->accept_secondary_eku = 1;
9767934SMark.Phalan@Sun.COM 	} else if (strcasecmp(eku_string, "none") == 0) {
9777934SMark.Phalan@Sun.COM 	    reqctx->opts->require_eku = 0;
9787934SMark.Phalan@Sun.COM 	    reqctx->opts->accept_secondary_eku = 0;
9797934SMark.Phalan@Sun.COM 	} else {
9807934SMark.Phalan@Sun.COM 	    pkiDebug("%s: Invalid value for pkinit_eku_checking: '%s'\n",
9817934SMark.Phalan@Sun.COM 		     __FUNCTION__, eku_string);
9827934SMark.Phalan@Sun.COM 	}
9837934SMark.Phalan@Sun.COM 	free(eku_string);
9847934SMark.Phalan@Sun.COM     }
9857934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
9867934SMark.Phalan@Sun.COM     /* Temporarily just set global flag from config file */
9877934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_boolean(context, &request->server->realm,
9887934SMark.Phalan@Sun.COM 			      "pkinit_longhorn",
9897934SMark.Phalan@Sun.COM 			      0,
9907934SMark.Phalan@Sun.COM 			      &longhorn);
9917934SMark.Phalan@Sun.COM #endif
9927934SMark.Phalan@Sun.COM 
9937934SMark.Phalan@Sun.COM     /* Only process anchors here if they were not specified on command line */
9947934SMark.Phalan@Sun.COM     if (reqctx->idopts->anchors == NULL)
9957934SMark.Phalan@Sun.COM 	(void) pkinit_libdefault_strings(context, &request->server->realm,
9967934SMark.Phalan@Sun.COM 				  "pkinit_anchors",
9977934SMark.Phalan@Sun.COM 				  &reqctx->idopts->anchors);
9987934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
9997934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_strings(context, &request->server->realm,
10007934SMark.Phalan@Sun.COM 			      "pkinit_pool",
10017934SMark.Phalan@Sun.COM 			      &reqctx->idopts->intermediates);
10027934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_strings(context, &request->server->realm,
10037934SMark.Phalan@Sun.COM 			      "pkinit_revoke",
10047934SMark.Phalan@Sun.COM 			      &reqctx->idopts->crls);
10057934SMark.Phalan@Sun.COM     (void) pkinit_libdefault_strings(context, &request->server->realm,
10067934SMark.Phalan@Sun.COM 			      "pkinit_identities",
10077934SMark.Phalan@Sun.COM 			      &reqctx->idopts->identity_alt);
10087934SMark.Phalan@Sun.COM }
10097934SMark.Phalan@Sun.COM 
10107934SMark.Phalan@Sun.COM /* ARGSUSED */
10117934SMark.Phalan@Sun.COM krb5_error_code
10127934SMark.Phalan@Sun.COM pkinit_client_process(krb5_context context,
10137934SMark.Phalan@Sun.COM 		      void *plugin_context,
10147934SMark.Phalan@Sun.COM 		      void *request_context,
10157934SMark.Phalan@Sun.COM 		      krb5_get_init_creds_opt *gic_opt,
10167934SMark.Phalan@Sun.COM 		      preauth_get_client_data_proc get_data_proc,
10177934SMark.Phalan@Sun.COM 		      struct _krb5_preauth_client_rock *rock,
10187934SMark.Phalan@Sun.COM 		      krb5_kdc_req *request,
10197934SMark.Phalan@Sun.COM 		      krb5_data *encoded_request_body,
10207934SMark.Phalan@Sun.COM 		      krb5_data *encoded_previous_request,
10217934SMark.Phalan@Sun.COM 		      krb5_pa_data *in_padata,
10227934SMark.Phalan@Sun.COM 		      krb5_prompter_fct prompter,
10237934SMark.Phalan@Sun.COM 		      void *prompter_data,
10247934SMark.Phalan@Sun.COM 		      preauth_get_as_key_proc gak_fct,
10257934SMark.Phalan@Sun.COM 		      void *gak_data,
10267934SMark.Phalan@Sun.COM 		      krb5_data *salt,
10277934SMark.Phalan@Sun.COM 		      krb5_data *s2kparams,
10287934SMark.Phalan@Sun.COM 		      krb5_keyblock *as_key,
10297934SMark.Phalan@Sun.COM 		      krb5_pa_data ***out_padata)
10307934SMark.Phalan@Sun.COM {
10317934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
10327934SMark.Phalan@Sun.COM     krb5_enctype enctype = -1;
10337934SMark.Phalan@Sun.COM     krb5_data *cdata = NULL;
10347934SMark.Phalan@Sun.COM     int processing_request = 0;
10357934SMark.Phalan@Sun.COM     pkinit_context plgctx = (pkinit_context)plugin_context;
10367934SMark.Phalan@Sun.COM     pkinit_req_context reqctx = (pkinit_req_context)request_context;
10377934SMark.Phalan@Sun.COM 
10387934SMark.Phalan@Sun.COM     pkiDebug("pkinit_client_process %p %p %p %p\n",
10397934SMark.Phalan@Sun.COM 	     context, plgctx, reqctx, request);
10407934SMark.Phalan@Sun.COM 
10417934SMark.Phalan@Sun.COM     if (plgctx == NULL || reqctx == NULL)
10427934SMark.Phalan@Sun.COM 	return EINVAL;
10437934SMark.Phalan@Sun.COM 
10447934SMark.Phalan@Sun.COM     switch ((int) in_padata->pa_type) {
10457934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
10467934SMark.Phalan@Sun.COM 	    pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
10477934SMark.Phalan@Sun.COM 	    processing_request = 1;
10487934SMark.Phalan@Sun.COM 	    break;
10497934SMark.Phalan@Sun.COM 
10507934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REP:
10517934SMark.Phalan@Sun.COM 	    pkiDebug("processing KRB5_PADATA_PK_AS_REP\n");
10527934SMark.Phalan@Sun.COM 	    break;
10537934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REP_OLD:
10547934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
10557934SMark.Phalan@Sun.COM 	    if (in_padata->length == 0) {
10567934SMark.Phalan@Sun.COM 		pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
10577934SMark.Phalan@Sun.COM 		in_padata->pa_type = KRB5_PADATA_PK_AS_REQ_OLD;
10587934SMark.Phalan@Sun.COM 		processing_request = 1;
10597934SMark.Phalan@Sun.COM 	    } else {
10607934SMark.Phalan@Sun.COM 		pkiDebug("processing KRB5_PADATA_PK_AS_REP_OLD\n");
10617934SMark.Phalan@Sun.COM 		in_padata->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
10627934SMark.Phalan@Sun.COM 	    }
10637934SMark.Phalan@Sun.COM 	    break;
10647934SMark.Phalan@Sun.COM 	default:
10657934SMark.Phalan@Sun.COM 	    pkiDebug("unrecognized patype = %d for PKINIT\n",
10667934SMark.Phalan@Sun.COM 		    in_padata->pa_type);
10677934SMark.Phalan@Sun.COM 	    return EINVAL;
10687934SMark.Phalan@Sun.COM     }
10697934SMark.Phalan@Sun.COM 
10707934SMark.Phalan@Sun.COM     if (processing_request) {
10717934SMark.Phalan@Sun.COM 	pkinit_client_profile(context, plgctx, reqctx, request);
10727934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
10737934SMark.Phalan@Sun.COM 	retval = pkinit_identity_set_prompter(reqctx->idctx, prompter, prompter_data);
10747934SMark.Phalan@Sun.COM 	if (retval) {
10757934SMark.Phalan@Sun.COM 	    pkiDebug("pkinit_identity_set_prompter returned %d (%s)\n",
10767934SMark.Phalan@Sun.COM 		     retval, error_message(retval));
10777934SMark.Phalan@Sun.COM 	    return retval;
10787934SMark.Phalan@Sun.COM 	}
10797934SMark.Phalan@Sun.COM 
10807934SMark.Phalan@Sun.COM 	retval = pkinit_identity_initialize(context, plgctx->cryptoctx,
10817934SMark.Phalan@Sun.COM 					    reqctx->cryptoctx, reqctx->idopts,
10827934SMark.Phalan@Sun.COM 					    reqctx->idctx, 1, request->client);
10837934SMark.Phalan@Sun.COM 	if (retval) {
10847934SMark.Phalan@Sun.COM 	    pkiDebug("pkinit_identity_initialize returned %d (%s)\n",
10857934SMark.Phalan@Sun.COM 		     retval, error_message(retval));
10867934SMark.Phalan@Sun.COM 	    return retval;
10877934SMark.Phalan@Sun.COM 	}
10887934SMark.Phalan@Sun.COM 	retval = pa_pkinit_gen_req(context, plgctx, reqctx, request,
10897934SMark.Phalan@Sun.COM 				   in_padata, out_padata, prompter,
10907934SMark.Phalan@Sun.COM 				   prompter_data, gic_opt);
10917934SMark.Phalan@Sun.COM     } else {
10927934SMark.Phalan@Sun.COM 	/*
10937934SMark.Phalan@Sun.COM 	 * Get the enctype of the reply.
10947934SMark.Phalan@Sun.COM 	 */
10957934SMark.Phalan@Sun.COM 	retval = (*get_data_proc)(context, rock,
10967934SMark.Phalan@Sun.COM 				krb5plugin_preauth_client_get_etype, &cdata);
10977934SMark.Phalan@Sun.COM 	if (retval) {
10987934SMark.Phalan@Sun.COM 	    pkiDebug("get_data_proc returned %d (%s)\n",
10997934SMark.Phalan@Sun.COM 		     retval, error_message(retval));
11007934SMark.Phalan@Sun.COM 	    return retval;
11017934SMark.Phalan@Sun.COM 	}
11027934SMark.Phalan@Sun.COM 	enctype = *((krb5_enctype *)cdata->data);
11037934SMark.Phalan@Sun.COM 	(*get_data_proc)(context, rock,
11047934SMark.Phalan@Sun.COM 			 krb5plugin_preauth_client_free_etype, &cdata);
11057934SMark.Phalan@Sun.COM 	retval = pa_pkinit_parse_rep(context, plgctx, reqctx, request,
11067934SMark.Phalan@Sun.COM 				     in_padata, enctype, as_key,
11077934SMark.Phalan@Sun.COM 				     encoded_previous_request);
11087934SMark.Phalan@Sun.COM     }
11097934SMark.Phalan@Sun.COM 
11107934SMark.Phalan@Sun.COM     pkiDebug("pkinit_client_process: returning %d (%s)\n",
11117934SMark.Phalan@Sun.COM 	     retval, error_message(retval));
11127934SMark.Phalan@Sun.COM     return retval;
11137934SMark.Phalan@Sun.COM }
11147934SMark.Phalan@Sun.COM 
11157934SMark.Phalan@Sun.COM /* ARGSUSED */
11167934SMark.Phalan@Sun.COM krb5_error_code
11177934SMark.Phalan@Sun.COM pkinit_client_tryagain(krb5_context context,
11187934SMark.Phalan@Sun.COM 		       void *plugin_context,
11197934SMark.Phalan@Sun.COM 		       void *request_context,
11207934SMark.Phalan@Sun.COM 		       krb5_get_init_creds_opt *gic_opt,
11217934SMark.Phalan@Sun.COM 		       preauth_get_client_data_proc get_data_proc,
11227934SMark.Phalan@Sun.COM 		       struct _krb5_preauth_client_rock *rock,
11237934SMark.Phalan@Sun.COM 		       krb5_kdc_req *request,
11247934SMark.Phalan@Sun.COM 		       krb5_data *encoded_request_body,
11257934SMark.Phalan@Sun.COM 		       krb5_data *encoded_previous_request,
11267934SMark.Phalan@Sun.COM 		       krb5_pa_data *in_padata,
11277934SMark.Phalan@Sun.COM 		       krb5_error *err_reply,
11287934SMark.Phalan@Sun.COM 		       krb5_prompter_fct prompter,
11297934SMark.Phalan@Sun.COM 		       void *prompter_data,
11307934SMark.Phalan@Sun.COM 		       preauth_get_as_key_proc gak_fct,
11317934SMark.Phalan@Sun.COM 		       void *gak_data,
11327934SMark.Phalan@Sun.COM 		       krb5_data *salt,
11337934SMark.Phalan@Sun.COM 		       krb5_data *s2kparams,
11347934SMark.Phalan@Sun.COM 		       krb5_keyblock *as_key,
11357934SMark.Phalan@Sun.COM 		       krb5_pa_data ***out_padata)
11367934SMark.Phalan@Sun.COM {
11377934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
11387934SMark.Phalan@Sun.COM     pkinit_context plgctx = (pkinit_context)plugin_context;
11397934SMark.Phalan@Sun.COM     pkinit_req_context reqctx = (pkinit_req_context)request_context;
11407934SMark.Phalan@Sun.COM     krb5_typed_data **typed_data = NULL;
11417934SMark.Phalan@Sun.COM     krb5_data scratch;
11427934SMark.Phalan@Sun.COM     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
11437934SMark.Phalan@Sun.COM     krb5_algorithm_identifier **algId = NULL;
11447934SMark.Phalan@Sun.COM     int do_again = 0;
11457934SMark.Phalan@Sun.COM 
11467934SMark.Phalan@Sun.COM     pkiDebug("pkinit_client_tryagain %p %p %p %p\n",
11477934SMark.Phalan@Sun.COM 	     context, plgctx, reqctx, request);
11487934SMark.Phalan@Sun.COM 
11497934SMark.Phalan@Sun.COM     if (reqctx->pa_type != in_padata->pa_type)
11507934SMark.Phalan@Sun.COM 	return retval;
11517934SMark.Phalan@Sun.COM 
11527934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
11537934SMark.Phalan@Sun.COM     print_buffer_bin((unsigned char *)err_reply->e_data.data,
11547934SMark.Phalan@Sun.COM 		     err_reply->e_data.length, "/tmp/client_edata");
11557934SMark.Phalan@Sun.COM #endif
11567934SMark.Phalan@Sun.COM     retval = k5int_decode_krb5_typed_data(&err_reply->e_data, &typed_data);
11577934SMark.Phalan@Sun.COM     if (retval) {
11587934SMark.Phalan@Sun.COM 	pkiDebug("decode_krb5_typed_data failed\n");
11597934SMark.Phalan@Sun.COM 	goto cleanup;
11607934SMark.Phalan@Sun.COM     }
11617934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
11627934SMark.Phalan@Sun.COM     print_buffer_bin(typed_data[0]->data, typed_data[0]->length,
11637934SMark.Phalan@Sun.COM 		     "/tmp/client_typed_data");
11647934SMark.Phalan@Sun.COM #endif
11657934SMark.Phalan@Sun.COM     OCTETDATA_TO_KRB5DATA(typed_data[0], &scratch);
11667934SMark.Phalan@Sun.COM 
11677934SMark.Phalan@Sun.COM     switch(typed_data[0]->type) {
11687934SMark.Phalan@Sun.COM 	case TD_TRUSTED_CERTIFIERS:
11697934SMark.Phalan@Sun.COM 	case TD_INVALID_CERTIFICATES:
11707934SMark.Phalan@Sun.COM 	    retval = k5int_decode_krb5_td_trusted_certifiers(&scratch,
11717934SMark.Phalan@Sun.COM 		&krb5_trusted_certifiers);
11727934SMark.Phalan@Sun.COM 	    if (retval) {
11737934SMark.Phalan@Sun.COM 		pkiDebug("failed to decode sequence of trusted certifiers\n");
11747934SMark.Phalan@Sun.COM 		goto cleanup;
11757934SMark.Phalan@Sun.COM 	    }
11767934SMark.Phalan@Sun.COM 	    retval = pkinit_process_td_trusted_certifiers(context,
11777934SMark.Phalan@Sun.COM 		    plgctx->cryptoctx, reqctx->cryptoctx, reqctx->idctx,
11787934SMark.Phalan@Sun.COM 		    krb5_trusted_certifiers, typed_data[0]->type);
11797934SMark.Phalan@Sun.COM 	    if (!retval)
11807934SMark.Phalan@Sun.COM 		do_again = 1;
11817934SMark.Phalan@Sun.COM 	    break;
11827934SMark.Phalan@Sun.COM 	case TD_DH_PARAMETERS:
11837934SMark.Phalan@Sun.COM 	    retval = k5int_decode_krb5_td_dh_parameters(&scratch, &algId);
11847934SMark.Phalan@Sun.COM 	    if (retval) {
11857934SMark.Phalan@Sun.COM 		pkiDebug("failed to decode td_dh_parameters\n");
11867934SMark.Phalan@Sun.COM 		goto cleanup;
11877934SMark.Phalan@Sun.COM 	    }
11887934SMark.Phalan@Sun.COM 	    retval = pkinit_process_td_dh_params(context, plgctx->cryptoctx,
11897934SMark.Phalan@Sun.COM 		reqctx->cryptoctx, reqctx->idctx, algId,
11907934SMark.Phalan@Sun.COM 		&reqctx->opts->dh_size);
11917934SMark.Phalan@Sun.COM 	    if (!retval)
11927934SMark.Phalan@Sun.COM 		do_again = 1;
11937934SMark.Phalan@Sun.COM 	    break;
11947934SMark.Phalan@Sun.COM 	default:
11957934SMark.Phalan@Sun.COM 	    break;
11967934SMark.Phalan@Sun.COM     }
11977934SMark.Phalan@Sun.COM 
11987934SMark.Phalan@Sun.COM     if (do_again) {
11997934SMark.Phalan@Sun.COM 	retval = pa_pkinit_gen_req(context, plgctx, reqctx, request, in_padata,
12007934SMark.Phalan@Sun.COM 				   out_padata, prompter, prompter_data, gic_opt);
12017934SMark.Phalan@Sun.COM 	if (retval)
12027934SMark.Phalan@Sun.COM 	    goto cleanup;
12037934SMark.Phalan@Sun.COM     }
12047934SMark.Phalan@Sun.COM 
12057934SMark.Phalan@Sun.COM     retval = 0;
12067934SMark.Phalan@Sun.COM cleanup:
12077934SMark.Phalan@Sun.COM     if (krb5_trusted_certifiers != NULL)
12087934SMark.Phalan@Sun.COM 	free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
12097934SMark.Phalan@Sun.COM 
12107934SMark.Phalan@Sun.COM     if (typed_data != NULL)
12117934SMark.Phalan@Sun.COM 	free_krb5_typed_data(&typed_data);
12127934SMark.Phalan@Sun.COM 
12137934SMark.Phalan@Sun.COM     if (algId != NULL)
12147934SMark.Phalan@Sun.COM 	free_krb5_algorithm_identifiers(&algId);
12157934SMark.Phalan@Sun.COM 
12167934SMark.Phalan@Sun.COM     pkiDebug("pkinit_client_tryagain: returning %d (%s)\n",
12177934SMark.Phalan@Sun.COM 	     retval, error_message(retval));
12187934SMark.Phalan@Sun.COM     return retval;
12197934SMark.Phalan@Sun.COM }
12207934SMark.Phalan@Sun.COM 
12217934SMark.Phalan@Sun.COM /* ARGSUSED */
12227934SMark.Phalan@Sun.COM static int
12237934SMark.Phalan@Sun.COM pkinit_client_get_flags(krb5_context kcontext, krb5_preauthtype patype)
12247934SMark.Phalan@Sun.COM {
12257934SMark.Phalan@Sun.COM     return PA_REAL;
12267934SMark.Phalan@Sun.COM }
12277934SMark.Phalan@Sun.COM 
12287934SMark.Phalan@Sun.COM static krb5_preauthtype supported_client_pa_types[] = {
12297934SMark.Phalan@Sun.COM     KRB5_PADATA_PK_AS_REP,
12307934SMark.Phalan@Sun.COM     KRB5_PADATA_PK_AS_REQ,
12317934SMark.Phalan@Sun.COM     KRB5_PADATA_PK_AS_REP_OLD,
12327934SMark.Phalan@Sun.COM     KRB5_PADATA_PK_AS_REQ_OLD,
12337934SMark.Phalan@Sun.COM     0
12347934SMark.Phalan@Sun.COM };
12357934SMark.Phalan@Sun.COM 
12367934SMark.Phalan@Sun.COM /* ARGSUSED */
12377934SMark.Phalan@Sun.COM void
12387934SMark.Phalan@Sun.COM pkinit_client_req_init(krb5_context context,
12397934SMark.Phalan@Sun.COM 		       void *plugin_context,
12407934SMark.Phalan@Sun.COM 		       void **request_context)
12417934SMark.Phalan@Sun.COM {
12427934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
12437934SMark.Phalan@Sun.COM     struct _pkinit_req_context *reqctx = NULL;
12447934SMark.Phalan@Sun.COM     struct _pkinit_context *plgctx = (struct _pkinit_context *)plugin_context;
12457934SMark.Phalan@Sun.COM 
12467934SMark.Phalan@Sun.COM     *request_context = NULL;
12477934SMark.Phalan@Sun.COM 
12487934SMark.Phalan@Sun.COM     reqctx = (struct _pkinit_req_context *) malloc(sizeof(*reqctx));
12497934SMark.Phalan@Sun.COM     if (reqctx == NULL)
12507934SMark.Phalan@Sun.COM 	return;
12517934SMark.Phalan@Sun.COM     (void) memset(reqctx, 0, sizeof(*reqctx));
12527934SMark.Phalan@Sun.COM 
12537934SMark.Phalan@Sun.COM     reqctx->magic = PKINIT_REQ_CTX_MAGIC;
12547934SMark.Phalan@Sun.COM     reqctx->cryptoctx = NULL;
12557934SMark.Phalan@Sun.COM     reqctx->opts = NULL;
12567934SMark.Phalan@Sun.COM     reqctx->idctx = NULL;
12577934SMark.Phalan@Sun.COM     reqctx->idopts = NULL;
12587934SMark.Phalan@Sun.COM 
12597934SMark.Phalan@Sun.COM     retval = pkinit_init_req_opts(&reqctx->opts);
12607934SMark.Phalan@Sun.COM     if (retval)
12617934SMark.Phalan@Sun.COM 	goto cleanup;
12627934SMark.Phalan@Sun.COM 
12637934SMark.Phalan@Sun.COM     reqctx->opts->require_eku = plgctx->opts->require_eku;
12647934SMark.Phalan@Sun.COM     reqctx->opts->accept_secondary_eku = plgctx->opts->accept_secondary_eku;
12657934SMark.Phalan@Sun.COM     reqctx->opts->dh_or_rsa = plgctx->opts->dh_or_rsa;
12667934SMark.Phalan@Sun.COM     reqctx->opts->allow_upn = plgctx->opts->allow_upn;
12677934SMark.Phalan@Sun.COM     reqctx->opts->require_crl_checking = plgctx->opts->require_crl_checking;
12687934SMark.Phalan@Sun.COM 
12697934SMark.Phalan@Sun.COM     retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
12707934SMark.Phalan@Sun.COM     if (retval)
12717934SMark.Phalan@Sun.COM 	goto cleanup;
12727934SMark.Phalan@Sun.COM 
12737934SMark.Phalan@Sun.COM     retval = pkinit_init_identity_crypto(&reqctx->idctx);
12747934SMark.Phalan@Sun.COM     if (retval)
12757934SMark.Phalan@Sun.COM 	goto cleanup;
12767934SMark.Phalan@Sun.COM 
12777934SMark.Phalan@Sun.COM     retval = pkinit_dup_identity_opts(plgctx->idopts, &reqctx->idopts);
12787934SMark.Phalan@Sun.COM     if (retval)
12797934SMark.Phalan@Sun.COM 	goto cleanup;
12807934SMark.Phalan@Sun.COM 
12817934SMark.Phalan@Sun.COM     *request_context = (void *) reqctx;
12827934SMark.Phalan@Sun.COM     pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
12837934SMark.Phalan@Sun.COM 
12847934SMark.Phalan@Sun.COM cleanup:
12857934SMark.Phalan@Sun.COM     if (retval) {
12867934SMark.Phalan@Sun.COM 	if (reqctx->idctx != NULL)
12877934SMark.Phalan@Sun.COM 	    pkinit_fini_identity_crypto(reqctx->idctx);
12887934SMark.Phalan@Sun.COM 	if (reqctx->cryptoctx != NULL)
12897934SMark.Phalan@Sun.COM 	    pkinit_fini_req_crypto(reqctx->cryptoctx);
12907934SMark.Phalan@Sun.COM 	if (reqctx->opts != NULL)
12917934SMark.Phalan@Sun.COM 	    pkinit_fini_req_opts(reqctx->opts);
12927934SMark.Phalan@Sun.COM 	if (reqctx->idopts != NULL)
12937934SMark.Phalan@Sun.COM 	    pkinit_fini_identity_opts(reqctx->idopts);
12947934SMark.Phalan@Sun.COM 	free(reqctx);
12957934SMark.Phalan@Sun.COM     }
12967934SMark.Phalan@Sun.COM 
12977934SMark.Phalan@Sun.COM     return;
12987934SMark.Phalan@Sun.COM }
12997934SMark.Phalan@Sun.COM 
13007934SMark.Phalan@Sun.COM /* ARGSUSED */
13017934SMark.Phalan@Sun.COM void
13027934SMark.Phalan@Sun.COM pkinit_client_req_fini(krb5_context context,
13037934SMark.Phalan@Sun.COM 		      void *plugin_context,
13047934SMark.Phalan@Sun.COM 		      void *request_context)
13057934SMark.Phalan@Sun.COM {
13067934SMark.Phalan@Sun.COM     struct _pkinit_req_context *reqctx =
13077934SMark.Phalan@Sun.COM 	(struct _pkinit_req_context *)request_context;
13087934SMark.Phalan@Sun.COM 
13097934SMark.Phalan@Sun.COM     pkiDebug("%s: received reqctx at %p\n", __FUNCTION__, reqctx);
13107934SMark.Phalan@Sun.COM     if (reqctx == NULL)
13117934SMark.Phalan@Sun.COM 	return;
13127934SMark.Phalan@Sun.COM     if (reqctx->magic != PKINIT_REQ_CTX_MAGIC) {
13137934SMark.Phalan@Sun.COM 	pkiDebug("%s: Bad magic value (%x) in req ctx\n",
13147934SMark.Phalan@Sun.COM 		 __FUNCTION__, reqctx->magic);
13157934SMark.Phalan@Sun.COM 	return;
13167934SMark.Phalan@Sun.COM     }
13177934SMark.Phalan@Sun.COM     if (reqctx->opts != NULL)
13187934SMark.Phalan@Sun.COM 	pkinit_fini_req_opts(reqctx->opts);
13197934SMark.Phalan@Sun.COM 
13207934SMark.Phalan@Sun.COM     if (reqctx->cryptoctx != NULL)
13217934SMark.Phalan@Sun.COM 	pkinit_fini_req_crypto(reqctx->cryptoctx);
13227934SMark.Phalan@Sun.COM 
13237934SMark.Phalan@Sun.COM     if (reqctx->idctx != NULL)
13247934SMark.Phalan@Sun.COM 	pkinit_fini_identity_crypto(reqctx->idctx);
13257934SMark.Phalan@Sun.COM 
13267934SMark.Phalan@Sun.COM     if (reqctx->idopts != NULL)
13277934SMark.Phalan@Sun.COM 	pkinit_fini_identity_opts(reqctx->idopts);
13287934SMark.Phalan@Sun.COM 
13297934SMark.Phalan@Sun.COM     free(reqctx);
13307934SMark.Phalan@Sun.COM     return;
13317934SMark.Phalan@Sun.COM }
13327934SMark.Phalan@Sun.COM 
13337934SMark.Phalan@Sun.COM /* ARGSUSED */
13347934SMark.Phalan@Sun.COM static void
13357934SMark.Phalan@Sun.COM pkinit_fini_client_profile(krb5_context context, pkinit_context plgctx)
13367934SMark.Phalan@Sun.COM {
13377934SMark.Phalan@Sun.COM     /* This should clean up anything allocated in pkinit_init_client_profile */
13387934SMark.Phalan@Sun.COM }
13397934SMark.Phalan@Sun.COM 
13407934SMark.Phalan@Sun.COM /* ARGSUSED */
13417934SMark.Phalan@Sun.COM static krb5_error_code
13427934SMark.Phalan@Sun.COM pkinit_init_client_profile(krb5_context context, pkinit_context plgctx)
13437934SMark.Phalan@Sun.COM {
13447934SMark.Phalan@Sun.COM     return 0;
13457934SMark.Phalan@Sun.COM }
13467934SMark.Phalan@Sun.COM 
13477934SMark.Phalan@Sun.COM static int
13487934SMark.Phalan@Sun.COM pkinit_client_plugin_init(krb5_context context, void **blob)
13497934SMark.Phalan@Sun.COM {
13507934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
13517934SMark.Phalan@Sun.COM     struct _pkinit_context *ctx = NULL;
13527934SMark.Phalan@Sun.COM 
13537934SMark.Phalan@Sun.COM     ctx = (struct _pkinit_context *)calloc(1, sizeof(*ctx));
13547934SMark.Phalan@Sun.COM     if (ctx == NULL)
13557934SMark.Phalan@Sun.COM 	return ENOMEM;
13567934SMark.Phalan@Sun.COM     (void) memset(ctx, 0, sizeof(*ctx));
13577934SMark.Phalan@Sun.COM     ctx->magic = PKINIT_CTX_MAGIC;
13587934SMark.Phalan@Sun.COM     ctx->opts = NULL;
13597934SMark.Phalan@Sun.COM     ctx->cryptoctx = NULL;
13607934SMark.Phalan@Sun.COM     ctx->idopts = NULL;
13617934SMark.Phalan@Sun.COM 
13627934SMark.Phalan@Sun.COM     retval = pkinit_accessor_init();
13637934SMark.Phalan@Sun.COM     if (retval)
13647934SMark.Phalan@Sun.COM 	goto errout;
13657934SMark.Phalan@Sun.COM 
13667934SMark.Phalan@Sun.COM     retval = pkinit_init_plg_opts(&ctx->opts);
13677934SMark.Phalan@Sun.COM     if (retval)
13687934SMark.Phalan@Sun.COM 	goto errout;
13697934SMark.Phalan@Sun.COM 
13707934SMark.Phalan@Sun.COM     retval = pkinit_init_plg_crypto(&ctx->cryptoctx);
13717934SMark.Phalan@Sun.COM     if (retval)
13727934SMark.Phalan@Sun.COM 	goto errout;
13737934SMark.Phalan@Sun.COM 
13747934SMark.Phalan@Sun.COM     retval = pkinit_init_identity_opts(&ctx->idopts);
13757934SMark.Phalan@Sun.COM     if (retval)
13767934SMark.Phalan@Sun.COM 	goto errout;
13777934SMark.Phalan@Sun.COM 
13787934SMark.Phalan@Sun.COM     retval = pkinit_init_client_profile(context, ctx);
13797934SMark.Phalan@Sun.COM     if (retval)
13807934SMark.Phalan@Sun.COM 	goto errout;
13817934SMark.Phalan@Sun.COM 
13827934SMark.Phalan@Sun.COM     *blob = ctx;
13837934SMark.Phalan@Sun.COM 
13847934SMark.Phalan@Sun.COM     pkiDebug("%s: returning plgctx at %p\n", __FUNCTION__, ctx);
13857934SMark.Phalan@Sun.COM 
13867934SMark.Phalan@Sun.COM errout:
13877934SMark.Phalan@Sun.COM     if (retval)
13887934SMark.Phalan@Sun.COM 	pkinit_client_plugin_fini(context, ctx);
13897934SMark.Phalan@Sun.COM 
13907934SMark.Phalan@Sun.COM     return retval;
13917934SMark.Phalan@Sun.COM }
13927934SMark.Phalan@Sun.COM 
13937934SMark.Phalan@Sun.COM static void
13947934SMark.Phalan@Sun.COM pkinit_client_plugin_fini(krb5_context context, void *blob)
13957934SMark.Phalan@Sun.COM {
13967934SMark.Phalan@Sun.COM     struct _pkinit_context *ctx = (struct _pkinit_context *)blob;
13977934SMark.Phalan@Sun.COM 
13987934SMark.Phalan@Sun.COM     if (ctx == NULL || ctx->magic != PKINIT_CTX_MAGIC) {
13997934SMark.Phalan@Sun.COM 	pkiDebug("pkinit_lib_fini: got bad plgctx (%p)!\n", ctx);
14007934SMark.Phalan@Sun.COM 	return;
14017934SMark.Phalan@Sun.COM     }
14027934SMark.Phalan@Sun.COM     pkiDebug("%s: got plgctx at %p\n", __FUNCTION__, ctx);
14037934SMark.Phalan@Sun.COM 
14047934SMark.Phalan@Sun.COM     pkinit_fini_client_profile(context, ctx);
14057934SMark.Phalan@Sun.COM     pkinit_fini_identity_opts(ctx->idopts);
14067934SMark.Phalan@Sun.COM     pkinit_fini_plg_crypto(ctx->cryptoctx);
14077934SMark.Phalan@Sun.COM     pkinit_fini_plg_opts(ctx->opts);
14087934SMark.Phalan@Sun.COM     free(ctx);
14097934SMark.Phalan@Sun.COM 
14107934SMark.Phalan@Sun.COM }
14117934SMark.Phalan@Sun.COM 
14127934SMark.Phalan@Sun.COM /* ARGSUSED */
14137934SMark.Phalan@Sun.COM static krb5_error_code
14147934SMark.Phalan@Sun.COM add_string_to_array(krb5_context context, char ***array, const char *addition)
14157934SMark.Phalan@Sun.COM {
14167934SMark.Phalan@Sun.COM     char **out = NULL;
14177934SMark.Phalan@Sun.COM 
14187934SMark.Phalan@Sun.COM     if (*array == NULL) {
14197934SMark.Phalan@Sun.COM 	out = malloc(2 * sizeof(char *));
14207934SMark.Phalan@Sun.COM 	if (out == NULL)
14217934SMark.Phalan@Sun.COM 	    return ENOMEM;
14227934SMark.Phalan@Sun.COM 	out[1] = NULL;
14237934SMark.Phalan@Sun.COM 	out[0] = strdup(addition);
14247934SMark.Phalan@Sun.COM 	if (out[0] == NULL) {
14257934SMark.Phalan@Sun.COM 	    free(out);
14267934SMark.Phalan@Sun.COM 	    return ENOMEM;
14277934SMark.Phalan@Sun.COM 	}
14287934SMark.Phalan@Sun.COM     } else {
14297934SMark.Phalan@Sun.COM 	int i;
14307934SMark.Phalan@Sun.COM 	char **a = *array;
14317934SMark.Phalan@Sun.COM 	for (i = 0; a[i] != NULL; i++);
14327934SMark.Phalan@Sun.COM 	out = malloc( (i + 2) * sizeof(char *));
14337934SMark.Phalan@Sun.COM 	if (out == NULL)
14347934SMark.Phalan@Sun.COM 	    return ENOMEM;
14357934SMark.Phalan@Sun.COM 	for (i = 0; a[i] != NULL; i++) {
14367934SMark.Phalan@Sun.COM 	    out[i] = a[i];
14377934SMark.Phalan@Sun.COM 	}
14387934SMark.Phalan@Sun.COM 	out[i++] = strdup(addition);
14397934SMark.Phalan@Sun.COM 	if (out == NULL) {
14407934SMark.Phalan@Sun.COM 	    free(out);
14417934SMark.Phalan@Sun.COM 	    return ENOMEM;
14427934SMark.Phalan@Sun.COM 	}
14437934SMark.Phalan@Sun.COM 	out[i] = NULL;
14447934SMark.Phalan@Sun.COM 	free(*array);
14457934SMark.Phalan@Sun.COM     }
14467934SMark.Phalan@Sun.COM     *array = out;
14477934SMark.Phalan@Sun.COM 
14487934SMark.Phalan@Sun.COM     return 0;
14497934SMark.Phalan@Sun.COM }
14507934SMark.Phalan@Sun.COM static krb5_error_code
14517934SMark.Phalan@Sun.COM handle_gic_opt(krb5_context context,
14527934SMark.Phalan@Sun.COM 	       struct _pkinit_context *plgctx,
14537934SMark.Phalan@Sun.COM 	       const char *attr,
14547934SMark.Phalan@Sun.COM 	       const char *value)
14557934SMark.Phalan@Sun.COM {
14567934SMark.Phalan@Sun.COM     krb5_error_code retval;
14577934SMark.Phalan@Sun.COM 
14587934SMark.Phalan@Sun.COM     if (strcmp(attr, "X509_user_identity") == 0) {
14597934SMark.Phalan@Sun.COM 	if (plgctx->idopts->identity != NULL) {
14607934SMark.Phalan@Sun.COM 	    krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
14617934SMark.Phalan@Sun.COM 		"X509_user_identity can not be given twice\n");
14627934SMark.Phalan@Sun.COM 	    return KRB5_PREAUTH_FAILED;
14637934SMark.Phalan@Sun.COM 	}
14647934SMark.Phalan@Sun.COM 	plgctx->idopts->identity = strdup(value);
14657934SMark.Phalan@Sun.COM 	if (plgctx->idopts->identity == NULL) {
14667934SMark.Phalan@Sun.COM 	    krb5_set_error_message(context, ENOMEM,
14677934SMark.Phalan@Sun.COM 		"Could not duplicate X509_user_identity value\n");
14687934SMark.Phalan@Sun.COM 	    return ENOMEM;
14697934SMark.Phalan@Sun.COM 	}
14707934SMark.Phalan@Sun.COM     } else if (strcmp(attr, "X509_anchors") == 0) {
14717934SMark.Phalan@Sun.COM 	retval = add_string_to_array(context, &plgctx->idopts->anchors, value);
14727934SMark.Phalan@Sun.COM 	if (retval)
14737934SMark.Phalan@Sun.COM 	    return retval;
14747934SMark.Phalan@Sun.COM     } else if (strcmp(attr, "flag_RSA_PROTOCOL") == 0) {
14757934SMark.Phalan@Sun.COM 	if (strcmp(value, "yes") == 0) {
14767934SMark.Phalan@Sun.COM 	    pkiDebug("Setting flag to use RSA_PROTOCOL\n");
14777934SMark.Phalan@Sun.COM 	    plgctx->opts->dh_or_rsa = RSA_PROTOCOL;
14787934SMark.Phalan@Sun.COM 	}
1479*12941Swill.fiveash@oracle.com     } else if (strcmp(attr, "PIN") == 0) {
1480*12941Swill.fiveash@oracle.com 	/* Solaris Kerberos: handle our PIN attr */
1481*12941Swill.fiveash@oracle.com 	plgctx->idopts->PIN = strdup(value);
1482*12941Swill.fiveash@oracle.com 	if (plgctx->idopts->PIN == NULL)
1483*12941Swill.fiveash@oracle.com 	    return ENOMEM;
14847934SMark.Phalan@Sun.COM     }
14857934SMark.Phalan@Sun.COM     return 0;
14867934SMark.Phalan@Sun.COM }
14877934SMark.Phalan@Sun.COM 
14887934SMark.Phalan@Sun.COM /* ARGSUSED */
14897934SMark.Phalan@Sun.COM static krb5_error_code
14907934SMark.Phalan@Sun.COM pkinit_client_gic_opt(krb5_context context,
14917934SMark.Phalan@Sun.COM 		      void *plugin_context,
14927934SMark.Phalan@Sun.COM 		      krb5_get_init_creds_opt *gic_opt,
14937934SMark.Phalan@Sun.COM 		      const char *attr,
14947934SMark.Phalan@Sun.COM 		      const char *value)
14957934SMark.Phalan@Sun.COM {
14967934SMark.Phalan@Sun.COM     krb5_error_code retval;
14977934SMark.Phalan@Sun.COM     struct _pkinit_context *plgctx = (struct _pkinit_context *)plugin_context;
14987934SMark.Phalan@Sun.COM 
14997934SMark.Phalan@Sun.COM     pkiDebug("(pkinit) received '%s' = '%s'\n", attr, value);
15007934SMark.Phalan@Sun.COM     retval = handle_gic_opt(context, plgctx, attr, value);
15017934SMark.Phalan@Sun.COM     if (retval)
15027934SMark.Phalan@Sun.COM 	return retval;
15037934SMark.Phalan@Sun.COM 
15047934SMark.Phalan@Sun.COM     return 0;
15057934SMark.Phalan@Sun.COM }
15067934SMark.Phalan@Sun.COM 
15077934SMark.Phalan@Sun.COM struct krb5plugin_preauth_client_ftable_v1 preauthentication_client_1 = {
15087934SMark.Phalan@Sun.COM     "pkinit",			/* name */
15097934SMark.Phalan@Sun.COM     supported_client_pa_types,	/* pa_type_list */
15107934SMark.Phalan@Sun.COM     NULL,			/* enctype_list */
15117934SMark.Phalan@Sun.COM     pkinit_client_plugin_init,	/* (*init) */
15127934SMark.Phalan@Sun.COM     pkinit_client_plugin_fini,	/* (*fini) */
15137934SMark.Phalan@Sun.COM     pkinit_client_get_flags,	/* (*flags) */
15147934SMark.Phalan@Sun.COM     pkinit_client_req_init,     /* (*client_req_init) */
15157934SMark.Phalan@Sun.COM     pkinit_client_req_fini,     /* (*client_req_fini) */
15167934SMark.Phalan@Sun.COM     pkinit_client_process,	/* (*process) */
15177934SMark.Phalan@Sun.COM     pkinit_client_tryagain,	/* (*tryagain) */
15187934SMark.Phalan@Sun.COM     pkinit_client_gic_opt	/* (*gic_opt) */
15197934SMark.Phalan@Sun.COM };
1520