xref: /freebsd/crypto/krb5/src/plugins/preauth/pkinit/pkinit_srv.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert  * COPYRIGHT (C) 2006,2007
4*7f2fe78bSCy Schubert  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
5*7f2fe78bSCy Schubert  * ALL RIGHTS RESERVED
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Permission is granted to use, copy, create derivative works
8*7f2fe78bSCy Schubert  * and redistribute this software and such derivative works
9*7f2fe78bSCy Schubert  * for any purpose, so long as the name of The University of
10*7f2fe78bSCy Schubert  * Michigan is not used in any advertising or publicity
11*7f2fe78bSCy Schubert  * pertaining to the use of distribution of this software
12*7f2fe78bSCy Schubert  * without specific, written prior authorization.  If the
13*7f2fe78bSCy Schubert  * above copyright notice or any other identification of the
14*7f2fe78bSCy Schubert  * University of Michigan is included in any copy of any
15*7f2fe78bSCy Schubert  * portion of this software, then the disclaimer below must
16*7f2fe78bSCy Schubert  * also be included.
17*7f2fe78bSCy Schubert  *
18*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
19*7f2fe78bSCy Schubert  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
20*7f2fe78bSCy Schubert  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
21*7f2fe78bSCy Schubert  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
22*7f2fe78bSCy Schubert  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
23*7f2fe78bSCy Schubert  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
24*7f2fe78bSCy Schubert  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
25*7f2fe78bSCy Schubert  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
26*7f2fe78bSCy Schubert  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
27*7f2fe78bSCy Schubert  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
28*7f2fe78bSCy Schubert  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
29*7f2fe78bSCy Schubert  * SUCH DAMAGES.
30*7f2fe78bSCy Schubert  */
31*7f2fe78bSCy Schubert 
32*7f2fe78bSCy Schubert #include <k5-int.h>
33*7f2fe78bSCy Schubert #include "pkinit.h"
34*7f2fe78bSCy Schubert #include "krb5/certauth_plugin.h"
35*7f2fe78bSCy Schubert 
36*7f2fe78bSCy Schubert /* Aliases used by the built-in certauth modules */
37*7f2fe78bSCy Schubert struct certauth_req_opts {
38*7f2fe78bSCy Schubert     krb5_kdcpreauth_callbacks cb;
39*7f2fe78bSCy Schubert     krb5_kdcpreauth_rock rock;
40*7f2fe78bSCy Schubert     pkinit_kdc_context plgctx;
41*7f2fe78bSCy Schubert     pkinit_kdc_req_context reqctx;
42*7f2fe78bSCy Schubert };
43*7f2fe78bSCy Schubert 
44*7f2fe78bSCy Schubert typedef struct certauth_module_handle_st {
45*7f2fe78bSCy Schubert     struct krb5_certauth_vtable_st vt;
46*7f2fe78bSCy Schubert     krb5_certauth_moddata moddata;
47*7f2fe78bSCy Schubert } *certauth_handle;
48*7f2fe78bSCy Schubert 
49*7f2fe78bSCy Schubert struct krb5_kdcpreauth_moddata_st {
50*7f2fe78bSCy Schubert     pkinit_kdc_context *realm_contexts;
51*7f2fe78bSCy Schubert     certauth_handle *certauth_modules;
52*7f2fe78bSCy Schubert };
53*7f2fe78bSCy Schubert 
54*7f2fe78bSCy Schubert static krb5_error_code
55*7f2fe78bSCy Schubert pkinit_init_kdc_req_context(krb5_context, pkinit_kdc_req_context *blob);
56*7f2fe78bSCy Schubert 
57*7f2fe78bSCy Schubert static void
58*7f2fe78bSCy Schubert pkinit_fini_kdc_req_context(krb5_context context, void *blob);
59*7f2fe78bSCy Schubert 
60*7f2fe78bSCy Schubert static void
61*7f2fe78bSCy Schubert pkinit_server_plugin_fini_realm(krb5_context context,
62*7f2fe78bSCy Schubert                                 pkinit_kdc_context plgctx);
63*7f2fe78bSCy Schubert 
64*7f2fe78bSCy Schubert static void
65*7f2fe78bSCy Schubert pkinit_server_plugin_fini(krb5_context context,
66*7f2fe78bSCy Schubert                           krb5_kdcpreauth_moddata moddata);
67*7f2fe78bSCy Schubert 
68*7f2fe78bSCy Schubert static pkinit_kdc_context
69*7f2fe78bSCy Schubert pkinit_find_realm_context(krb5_context context,
70*7f2fe78bSCy Schubert                           krb5_kdcpreauth_moddata moddata,
71*7f2fe78bSCy Schubert                           krb5_principal princ);
72*7f2fe78bSCy Schubert 
73*7f2fe78bSCy Schubert static void
free_realm_contexts(krb5_context context,pkinit_kdc_context * realm_contexts)74*7f2fe78bSCy Schubert free_realm_contexts(krb5_context context, pkinit_kdc_context *realm_contexts)
75*7f2fe78bSCy Schubert {
76*7f2fe78bSCy Schubert     int i;
77*7f2fe78bSCy Schubert 
78*7f2fe78bSCy Schubert     if (realm_contexts == NULL)
79*7f2fe78bSCy Schubert         return;
80*7f2fe78bSCy Schubert     for (i = 0; realm_contexts[i] != NULL; i++)
81*7f2fe78bSCy Schubert         pkinit_server_plugin_fini_realm(context, realm_contexts[i]);
82*7f2fe78bSCy Schubert     pkiDebug("%s: freeing context at %p\n", __FUNCTION__, realm_contexts);
83*7f2fe78bSCy Schubert     free(realm_contexts);
84*7f2fe78bSCy Schubert }
85*7f2fe78bSCy Schubert 
86*7f2fe78bSCy Schubert static void
free_certauth_handles(krb5_context context,certauth_handle * list)87*7f2fe78bSCy Schubert free_certauth_handles(krb5_context context, certauth_handle *list)
88*7f2fe78bSCy Schubert {
89*7f2fe78bSCy Schubert     int i;
90*7f2fe78bSCy Schubert 
91*7f2fe78bSCy Schubert     if (list == NULL)
92*7f2fe78bSCy Schubert         return;
93*7f2fe78bSCy Schubert     for (i = 0; list[i] != NULL; i++) {
94*7f2fe78bSCy Schubert         if (list[i]->vt.fini != NULL)
95*7f2fe78bSCy Schubert             list[i]->vt.fini(context, list[i]->moddata);
96*7f2fe78bSCy Schubert         free(list[i]);
97*7f2fe78bSCy Schubert     }
98*7f2fe78bSCy Schubert     free(list);
99*7f2fe78bSCy Schubert }
100*7f2fe78bSCy Schubert 
101*7f2fe78bSCy Schubert 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_pa_data *** e_data_out)102*7f2fe78bSCy Schubert pkinit_create_edata(krb5_context context,
103*7f2fe78bSCy Schubert                     pkinit_plg_crypto_context plg_cryptoctx,
104*7f2fe78bSCy Schubert                     pkinit_req_crypto_context req_cryptoctx,
105*7f2fe78bSCy Schubert                     pkinit_identity_crypto_context id_cryptoctx,
106*7f2fe78bSCy Schubert                     pkinit_plg_opts *opts,
107*7f2fe78bSCy Schubert                     krb5_error_code err_code,
108*7f2fe78bSCy Schubert                     krb5_pa_data ***e_data_out)
109*7f2fe78bSCy Schubert {
110*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
111*7f2fe78bSCy Schubert 
112*7f2fe78bSCy Schubert     pkiDebug("pkinit_create_edata: creating edata for error %d (%s)\n",
113*7f2fe78bSCy Schubert              err_code, error_message(err_code));
114*7f2fe78bSCy Schubert     switch(err_code) {
115*7f2fe78bSCy Schubert     case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
116*7f2fe78bSCy Schubert         retval = pkinit_create_td_trusted_certifiers(context,
117*7f2fe78bSCy Schubert                                                      plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data_out);
118*7f2fe78bSCy Schubert         break;
119*7f2fe78bSCy Schubert     case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
120*7f2fe78bSCy Schubert         retval = pkinit_create_td_dh_parameters(context, plg_cryptoctx,
121*7f2fe78bSCy Schubert                                                 req_cryptoctx, id_cryptoctx, opts, e_data_out);
122*7f2fe78bSCy Schubert         break;
123*7f2fe78bSCy Schubert     case KRB5KDC_ERR_INVALID_CERTIFICATE:
124*7f2fe78bSCy Schubert     case KRB5KDC_ERR_REVOKED_CERTIFICATE:
125*7f2fe78bSCy Schubert         retval = pkinit_create_td_invalid_certificate(context,
126*7f2fe78bSCy Schubert                                                       plg_cryptoctx, req_cryptoctx, id_cryptoctx, e_data_out);
127*7f2fe78bSCy Schubert         break;
128*7f2fe78bSCy Schubert     default:
129*7f2fe78bSCy Schubert         pkiDebug("no edata needed for error %d (%s)\n",
130*7f2fe78bSCy Schubert                  err_code, error_message(err_code));
131*7f2fe78bSCy Schubert         retval = 0;
132*7f2fe78bSCy Schubert         goto cleanup;
133*7f2fe78bSCy Schubert     }
134*7f2fe78bSCy Schubert 
135*7f2fe78bSCy Schubert cleanup:
136*7f2fe78bSCy Schubert 
137*7f2fe78bSCy Schubert     return retval;
138*7f2fe78bSCy Schubert }
139*7f2fe78bSCy Schubert 
140*7f2fe78bSCy Schubert static void
pkinit_server_get_edata(krb5_context context,krb5_kdc_req * request,krb5_kdcpreauth_callbacks cb,krb5_kdcpreauth_rock rock,krb5_kdcpreauth_moddata moddata,krb5_preauthtype pa_type,krb5_kdcpreauth_edata_respond_fn respond,void * arg)141*7f2fe78bSCy Schubert pkinit_server_get_edata(krb5_context context,
142*7f2fe78bSCy Schubert                         krb5_kdc_req *request,
143*7f2fe78bSCy Schubert                         krb5_kdcpreauth_callbacks cb,
144*7f2fe78bSCy Schubert                         krb5_kdcpreauth_rock rock,
145*7f2fe78bSCy Schubert                         krb5_kdcpreauth_moddata moddata,
146*7f2fe78bSCy Schubert                         krb5_preauthtype pa_type,
147*7f2fe78bSCy Schubert                         krb5_kdcpreauth_edata_respond_fn respond,
148*7f2fe78bSCy Schubert                         void *arg)
149*7f2fe78bSCy Schubert {
150*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
151*7f2fe78bSCy Schubert     pkinit_kdc_context plgctx = NULL;
152*7f2fe78bSCy Schubert 
153*7f2fe78bSCy Schubert     pkiDebug("pkinit_server_get_edata: entered!\n");
154*7f2fe78bSCy Schubert 
155*7f2fe78bSCy Schubert 
156*7f2fe78bSCy Schubert     /*
157*7f2fe78bSCy Schubert      * If we don't have a realm context for the given realm,
158*7f2fe78bSCy Schubert      * don't tell the client that we support pkinit!
159*7f2fe78bSCy Schubert      */
160*7f2fe78bSCy Schubert     plgctx = pkinit_find_realm_context(context, moddata, request->server);
161*7f2fe78bSCy Schubert     if (plgctx == NULL)
162*7f2fe78bSCy Schubert         retval = EINVAL;
163*7f2fe78bSCy Schubert 
164*7f2fe78bSCy Schubert     /* Send a freshness token if the client requested one. */
165*7f2fe78bSCy Schubert     if (!retval)
166*7f2fe78bSCy Schubert         cb->send_freshness_token(context, rock);
167*7f2fe78bSCy Schubert 
168*7f2fe78bSCy Schubert     (*respond)(arg, retval, NULL);
169*7f2fe78bSCy Schubert }
170*7f2fe78bSCy Schubert 
171*7f2fe78bSCy Schubert static krb5_error_code
verify_client_san(krb5_context context,pkinit_kdc_context plgctx,pkinit_kdc_req_context reqctx,krb5_kdcpreauth_callbacks cb,krb5_kdcpreauth_rock rock,krb5_const_principal client,int * valid_san)172*7f2fe78bSCy Schubert verify_client_san(krb5_context context,
173*7f2fe78bSCy Schubert                   pkinit_kdc_context plgctx,
174*7f2fe78bSCy Schubert                   pkinit_kdc_req_context reqctx,
175*7f2fe78bSCy Schubert                   krb5_kdcpreauth_callbacks cb,
176*7f2fe78bSCy Schubert                   krb5_kdcpreauth_rock rock,
177*7f2fe78bSCy Schubert                   krb5_const_principal client,
178*7f2fe78bSCy Schubert                   int *valid_san)
179*7f2fe78bSCy Schubert {
180*7f2fe78bSCy Schubert     krb5_error_code retval;
181*7f2fe78bSCy Schubert     krb5_principal *princs = NULL, upn;
182*7f2fe78bSCy Schubert     krb5_boolean match;
183*7f2fe78bSCy Schubert     char **upns = NULL;
184*7f2fe78bSCy Schubert     int i;
185*7f2fe78bSCy Schubert #ifdef DEBUG_SAN_INFO
186*7f2fe78bSCy Schubert     char *client_string = NULL, *san_string;
187*7f2fe78bSCy Schubert #endif
188*7f2fe78bSCy Schubert 
189*7f2fe78bSCy Schubert     *valid_san = 0;
190*7f2fe78bSCy Schubert     retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx,
191*7f2fe78bSCy Schubert                                        reqctx->cryptoctx, plgctx->idctx,
192*7f2fe78bSCy Schubert                                        &princs,
193*7f2fe78bSCy Schubert                                        plgctx->opts->allow_upn ? &upns : NULL,
194*7f2fe78bSCy Schubert                                        NULL);
195*7f2fe78bSCy Schubert     if (retval) {
196*7f2fe78bSCy Schubert         pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__);
197*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
198*7f2fe78bSCy Schubert         goto out;
199*7f2fe78bSCy Schubert     }
200*7f2fe78bSCy Schubert 
201*7f2fe78bSCy Schubert     if (princs == NULL && upns == NULL) {
202*7f2fe78bSCy Schubert         TRACE_PKINIT_SERVER_NO_SAN(context);
203*7f2fe78bSCy Schubert         retval = ENOENT;
204*7f2fe78bSCy Schubert         goto out;
205*7f2fe78bSCy Schubert     }
206*7f2fe78bSCy Schubert 
207*7f2fe78bSCy Schubert #ifdef DEBUG_SAN_INFO
208*7f2fe78bSCy Schubert     krb5_unparse_name(context, client, &client_string);
209*7f2fe78bSCy Schubert #endif
210*7f2fe78bSCy Schubert     pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
211*7f2fe78bSCy Schubert     for (i = 0; princs != NULL && princs[i] != NULL; i++) {
212*7f2fe78bSCy Schubert #ifdef DEBUG_SAN_INFO
213*7f2fe78bSCy Schubert         krb5_unparse_name(context, princs[i], &san_string);
214*7f2fe78bSCy Schubert         pkiDebug("%s: Comparing client '%s' to pkinit san value '%s'\n",
215*7f2fe78bSCy Schubert                  __FUNCTION__, client_string, san_string);
216*7f2fe78bSCy Schubert         krb5_free_unparsed_name(context, san_string);
217*7f2fe78bSCy Schubert #endif
218*7f2fe78bSCy Schubert         if (cb->match_client(context, rock, princs[i])) {
219*7f2fe78bSCy Schubert             TRACE_PKINIT_SERVER_MATCHING_SAN_FOUND(context);
220*7f2fe78bSCy Schubert             *valid_san = 1;
221*7f2fe78bSCy Schubert             retval = 0;
222*7f2fe78bSCy Schubert             goto out;
223*7f2fe78bSCy Schubert         }
224*7f2fe78bSCy Schubert     }
225*7f2fe78bSCy Schubert     pkiDebug("%s: no pkinit san match found\n", __FUNCTION__);
226*7f2fe78bSCy Schubert     /*
227*7f2fe78bSCy Schubert      * XXX if cert has names but none match, should we
228*7f2fe78bSCy Schubert      * be returning KRB5KDC_ERR_CLIENT_NAME_MISMATCH here?
229*7f2fe78bSCy Schubert      */
230*7f2fe78bSCy Schubert 
231*7f2fe78bSCy Schubert     if (upns == NULL) {
232*7f2fe78bSCy Schubert         pkiDebug("%s: no upn sans (or we wouldn't accept them anyway)\n",
233*7f2fe78bSCy Schubert                  __FUNCTION__);
234*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
235*7f2fe78bSCy Schubert         goto out;
236*7f2fe78bSCy Schubert     }
237*7f2fe78bSCy Schubert 
238*7f2fe78bSCy Schubert     pkiDebug("%s: Checking upn sans\n", __FUNCTION__);
239*7f2fe78bSCy Schubert     for (i = 0; upns[i] != NULL; i++) {
240*7f2fe78bSCy Schubert #ifdef DEBUG_SAN_INFO
241*7f2fe78bSCy Schubert         pkiDebug("%s: Comparing client '%s' to upn san value '%s'\n",
242*7f2fe78bSCy Schubert                  __FUNCTION__, client_string, upns[i]);
243*7f2fe78bSCy Schubert #endif
244*7f2fe78bSCy Schubert         retval = krb5_parse_name_flags(context, upns[i],
245*7f2fe78bSCy Schubert                                        KRB5_PRINCIPAL_PARSE_ENTERPRISE, &upn);
246*7f2fe78bSCy Schubert         if (retval) {
247*7f2fe78bSCy Schubert             TRACE_PKINIT_SERVER_UPN_PARSE_FAIL(context, upns[i], retval);
248*7f2fe78bSCy Schubert             continue;
249*7f2fe78bSCy Schubert         }
250*7f2fe78bSCy Schubert         match = cb->match_client(context, rock, upn);
251*7f2fe78bSCy Schubert         krb5_free_principal(context, upn);
252*7f2fe78bSCy Schubert         if (match) {
253*7f2fe78bSCy Schubert             TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(context);
254*7f2fe78bSCy Schubert             *valid_san = 1;
255*7f2fe78bSCy Schubert             retval = 0;
256*7f2fe78bSCy Schubert             goto out;
257*7f2fe78bSCy Schubert         }
258*7f2fe78bSCy Schubert     }
259*7f2fe78bSCy Schubert     pkiDebug("%s: no upn san match found\n", __FUNCTION__);
260*7f2fe78bSCy Schubert 
261*7f2fe78bSCy Schubert     retval = 0;
262*7f2fe78bSCy Schubert out:
263*7f2fe78bSCy Schubert     if (princs != NULL) {
264*7f2fe78bSCy Schubert         for (i = 0; princs[i] != NULL; i++)
265*7f2fe78bSCy Schubert             krb5_free_principal(context, princs[i]);
266*7f2fe78bSCy Schubert         free(princs);
267*7f2fe78bSCy Schubert     }
268*7f2fe78bSCy Schubert     if (upns != NULL) {
269*7f2fe78bSCy Schubert         for (i = 0; upns[i] != NULL; i++)
270*7f2fe78bSCy Schubert             free(upns[i]);
271*7f2fe78bSCy Schubert         free(upns);
272*7f2fe78bSCy Schubert     }
273*7f2fe78bSCy Schubert #ifdef DEBUG_SAN_INFO
274*7f2fe78bSCy Schubert     if (client_string != NULL)
275*7f2fe78bSCy Schubert         krb5_free_unparsed_name(context, client_string);
276*7f2fe78bSCy Schubert #endif
277*7f2fe78bSCy Schubert     pkiDebug("%s: returning retval %d, valid_san %d\n",
278*7f2fe78bSCy Schubert              __FUNCTION__, retval, *valid_san);
279*7f2fe78bSCy Schubert     return retval;
280*7f2fe78bSCy Schubert }
281*7f2fe78bSCy Schubert 
282*7f2fe78bSCy Schubert static krb5_error_code
verify_client_eku(krb5_context context,pkinit_kdc_context plgctx,pkinit_kdc_req_context reqctx,int * eku_accepted)283*7f2fe78bSCy Schubert verify_client_eku(krb5_context context,
284*7f2fe78bSCy Schubert                   pkinit_kdc_context plgctx,
285*7f2fe78bSCy Schubert                   pkinit_kdc_req_context reqctx,
286*7f2fe78bSCy Schubert                   int *eku_accepted)
287*7f2fe78bSCy Schubert {
288*7f2fe78bSCy Schubert     krb5_error_code retval;
289*7f2fe78bSCy Schubert 
290*7f2fe78bSCy Schubert     *eku_accepted = 0;
291*7f2fe78bSCy Schubert 
292*7f2fe78bSCy Schubert     if (plgctx->opts->require_eku == 0) {
293*7f2fe78bSCy Schubert         TRACE_PKINIT_SERVER_EKU_SKIP(context);
294*7f2fe78bSCy Schubert         *eku_accepted = 1;
295*7f2fe78bSCy Schubert         retval = 0;
296*7f2fe78bSCy Schubert         goto out;
297*7f2fe78bSCy Schubert     }
298*7f2fe78bSCy Schubert 
299*7f2fe78bSCy Schubert     retval = crypto_check_cert_eku(context, plgctx->cryptoctx,
300*7f2fe78bSCy Schubert                                    reqctx->cryptoctx, plgctx->idctx,
301*7f2fe78bSCy Schubert                                    0, /* kdc cert */
302*7f2fe78bSCy Schubert                                    plgctx->opts->accept_secondary_eku,
303*7f2fe78bSCy Schubert                                    eku_accepted);
304*7f2fe78bSCy Schubert     if (retval) {
305*7f2fe78bSCy Schubert         pkiDebug("%s: Error from crypto_check_cert_eku %d (%s)\n",
306*7f2fe78bSCy Schubert                  __FUNCTION__, retval, error_message(retval));
307*7f2fe78bSCy Schubert         goto out;
308*7f2fe78bSCy Schubert     }
309*7f2fe78bSCy Schubert 
310*7f2fe78bSCy Schubert out:
311*7f2fe78bSCy Schubert     pkiDebug("%s: returning retval %d, eku_accepted %d\n",
312*7f2fe78bSCy Schubert              __FUNCTION__, retval, *eku_accepted);
313*7f2fe78bSCy Schubert     return retval;
314*7f2fe78bSCy Schubert }
315*7f2fe78bSCy Schubert 
316*7f2fe78bSCy Schubert 
317*7f2fe78bSCy Schubert /* Run the received, verified certificate through certauth modules, to verify
318*7f2fe78bSCy Schubert  * that it is authorized to authenticate as client. */
319*7f2fe78bSCy Schubert static krb5_error_code
authorize_cert(krb5_context context,certauth_handle * certauth_modules,pkinit_kdc_context plgctx,pkinit_kdc_req_context reqctx,krb5_kdcpreauth_callbacks cb,krb5_kdcpreauth_rock rock,krb5_principal client,krb5_boolean * hwauth_out)320*7f2fe78bSCy Schubert authorize_cert(krb5_context context, certauth_handle *certauth_modules,
321*7f2fe78bSCy Schubert                pkinit_kdc_context plgctx, pkinit_kdc_req_context reqctx,
322*7f2fe78bSCy Schubert                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
323*7f2fe78bSCy Schubert                krb5_principal client, krb5_boolean *hwauth_out)
324*7f2fe78bSCy Schubert {
325*7f2fe78bSCy Schubert     krb5_error_code ret;
326*7f2fe78bSCy Schubert     certauth_handle h;
327*7f2fe78bSCy Schubert     struct certauth_req_opts opts;
328*7f2fe78bSCy Schubert     krb5_boolean accepted = FALSE, hwauth = FALSE;
329*7f2fe78bSCy Schubert     uint8_t *cert;
330*7f2fe78bSCy Schubert     size_t i, cert_len;
331*7f2fe78bSCy Schubert     void *db_ent = NULL;
332*7f2fe78bSCy Schubert     char **ais = NULL, **ai = NULL;
333*7f2fe78bSCy Schubert 
334*7f2fe78bSCy Schubert     /* Re-encode the received certificate into DER, which is extra work, but
335*7f2fe78bSCy Schubert      * avoids creating an X.509 library dependency in the interface. */
336*7f2fe78bSCy Schubert     ret = crypto_encode_der_cert(context, reqctx->cryptoctx, &cert, &cert_len);
337*7f2fe78bSCy Schubert     if (ret)
338*7f2fe78bSCy Schubert         goto cleanup;
339*7f2fe78bSCy Schubert 
340*7f2fe78bSCy Schubert     /* Set options for the builtin module. */
341*7f2fe78bSCy Schubert     opts.plgctx = plgctx;
342*7f2fe78bSCy Schubert     opts.reqctx = reqctx;
343*7f2fe78bSCy Schubert     opts.cb = cb;
344*7f2fe78bSCy Schubert     opts.rock = rock;
345*7f2fe78bSCy Schubert 
346*7f2fe78bSCy Schubert     db_ent = cb->client_entry(context, rock);
347*7f2fe78bSCy Schubert 
348*7f2fe78bSCy Schubert     /*
349*7f2fe78bSCy Schubert      * Check the certificate against each certauth module.  For the certificate
350*7f2fe78bSCy Schubert      * to be authorized at least one module must return 0 or
351*7f2fe78bSCy Schubert      * KRB5_CERTAUTH_HWAUTH, and no module can return an error code other than
352*7f2fe78bSCy Schubert      * KRB5_PLUGIN_NO_HANDLE (pass) or KRB5_CERTAUTH_HWAUTH_PASS (pass but
353*7f2fe78bSCy Schubert      * set hw-authent).  Add indicators from all modules.
354*7f2fe78bSCy Schubert      */
355*7f2fe78bSCy Schubert     ret = KRB5_PLUGIN_NO_HANDLE;
356*7f2fe78bSCy Schubert     for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) {
357*7f2fe78bSCy Schubert         h = certauth_modules[i];
358*7f2fe78bSCy Schubert         TRACE_PKINIT_SERVER_CERT_AUTH(context, h->vt.name);
359*7f2fe78bSCy Schubert         ret = h->vt.authorize(context, h->moddata, cert, cert_len, client,
360*7f2fe78bSCy Schubert                               &opts, db_ent, &ais);
361*7f2fe78bSCy Schubert         if (ret == 0)
362*7f2fe78bSCy Schubert             accepted = TRUE;
363*7f2fe78bSCy Schubert         else if (ret == KRB5_CERTAUTH_HWAUTH)
364*7f2fe78bSCy Schubert             accepted = hwauth = TRUE;
365*7f2fe78bSCy Schubert         else if (ret == KRB5_CERTAUTH_HWAUTH_PASS)
366*7f2fe78bSCy Schubert             hwauth = TRUE;
367*7f2fe78bSCy Schubert         else if (ret != KRB5_PLUGIN_NO_HANDLE)
368*7f2fe78bSCy Schubert             goto cleanup;
369*7f2fe78bSCy Schubert 
370*7f2fe78bSCy Schubert         if (ais != NULL) {
371*7f2fe78bSCy Schubert             /* Assert authentication indicators from the module. */
372*7f2fe78bSCy Schubert             for (ai = ais; *ai != NULL; ai++) {
373*7f2fe78bSCy Schubert                 ret = cb->add_auth_indicator(context, rock, *ai);
374*7f2fe78bSCy Schubert                 if (ret)
375*7f2fe78bSCy Schubert                     goto cleanup;
376*7f2fe78bSCy Schubert             }
377*7f2fe78bSCy Schubert             h->vt.free_ind(context, h->moddata, ais);
378*7f2fe78bSCy Schubert             ais = NULL;
379*7f2fe78bSCy Schubert         }
380*7f2fe78bSCy Schubert     }
381*7f2fe78bSCy Schubert 
382*7f2fe78bSCy Schubert     *hwauth_out = hwauth;
383*7f2fe78bSCy Schubert     ret = accepted ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
384*7f2fe78bSCy Schubert 
385*7f2fe78bSCy Schubert cleanup:
386*7f2fe78bSCy Schubert     free(cert);
387*7f2fe78bSCy Schubert     return ret;
388*7f2fe78bSCy Schubert }
389*7f2fe78bSCy Schubert 
390*7f2fe78bSCy Schubert /* Return an error if freshness tokens are required and one was not received.
391*7f2fe78bSCy Schubert  * Log an appropriate message indicating whether a valid token was received. */
392*7f2fe78bSCy Schubert static krb5_error_code
check_log_freshness(krb5_context context,pkinit_kdc_context plgctx,krb5_kdc_req * request,krb5_boolean valid_freshness_token)393*7f2fe78bSCy Schubert check_log_freshness(krb5_context context, pkinit_kdc_context plgctx,
394*7f2fe78bSCy Schubert                     krb5_kdc_req *request, krb5_boolean valid_freshness_token)
395*7f2fe78bSCy Schubert {
396*7f2fe78bSCy Schubert     krb5_error_code ret;
397*7f2fe78bSCy Schubert     char *name = NULL;
398*7f2fe78bSCy Schubert 
399*7f2fe78bSCy Schubert     ret = krb5_unparse_name(context, request->client, &name);
400*7f2fe78bSCy Schubert     if (ret)
401*7f2fe78bSCy Schubert         return ret;
402*7f2fe78bSCy Schubert     if (plgctx->opts->require_freshness && !valid_freshness_token) {
403*7f2fe78bSCy Schubert         com_err("", 0, _("PKINIT: no freshness token, rejecting auth from %s"),
404*7f2fe78bSCy Schubert                 name);
405*7f2fe78bSCy Schubert         ret = KRB5KDC_ERR_PREAUTH_FAILED;
406*7f2fe78bSCy Schubert     } else if (valid_freshness_token) {
407*7f2fe78bSCy Schubert         com_err("", 0, _("PKINIT: freshness token received from %s"), name);
408*7f2fe78bSCy Schubert     } else {
409*7f2fe78bSCy Schubert         com_err("", 0, _("PKINIT: no freshness token received from %s"), name);
410*7f2fe78bSCy Schubert     }
411*7f2fe78bSCy Schubert     krb5_free_unparsed_name(context, name);
412*7f2fe78bSCy Schubert     return ret;
413*7f2fe78bSCy Schubert }
414*7f2fe78bSCy Schubert 
415*7f2fe78bSCy Schubert static void
pkinit_server_verify_padata(krb5_context context,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * data,krb5_kdcpreauth_callbacks cb,krb5_kdcpreauth_rock rock,krb5_kdcpreauth_moddata moddata,krb5_kdcpreauth_verify_respond_fn respond,void * arg)416*7f2fe78bSCy Schubert pkinit_server_verify_padata(krb5_context context,
417*7f2fe78bSCy Schubert                             krb5_data *req_pkt,
418*7f2fe78bSCy Schubert                             krb5_kdc_req * request,
419*7f2fe78bSCy Schubert                             krb5_enc_tkt_part * enc_tkt_reply,
420*7f2fe78bSCy Schubert                             krb5_pa_data * data,
421*7f2fe78bSCy Schubert                             krb5_kdcpreauth_callbacks cb,
422*7f2fe78bSCy Schubert                             krb5_kdcpreauth_rock rock,
423*7f2fe78bSCy Schubert                             krb5_kdcpreauth_moddata moddata,
424*7f2fe78bSCy Schubert                             krb5_kdcpreauth_verify_respond_fn respond,
425*7f2fe78bSCy Schubert                             void *arg)
426*7f2fe78bSCy Schubert {
427*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
428*7f2fe78bSCy Schubert     krb5_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
429*7f2fe78bSCy Schubert     krb5_pa_pk_as_req *reqp = NULL;
430*7f2fe78bSCy Schubert     krb5_auth_pack *auth_pack = NULL;
431*7f2fe78bSCy Schubert     pkinit_kdc_context plgctx = NULL;
432*7f2fe78bSCy Schubert     pkinit_kdc_req_context reqctx = NULL;
433*7f2fe78bSCy Schubert     krb5_checksum cksum = {0, 0, 0, NULL};
434*7f2fe78bSCy Schubert     krb5_data *der_req = NULL;
435*7f2fe78bSCy Schubert     krb5_data k5data, *ftoken;
436*7f2fe78bSCy Schubert     int is_signed = 1;
437*7f2fe78bSCy Schubert     krb5_pa_data **e_data = NULL;
438*7f2fe78bSCy Schubert     krb5_kdcpreauth_modreq modreq = NULL;
439*7f2fe78bSCy Schubert     krb5_boolean valid_freshness_token = FALSE, hwauth = FALSE;
440*7f2fe78bSCy Schubert     char **sp;
441*7f2fe78bSCy Schubert 
442*7f2fe78bSCy Schubert     pkiDebug("pkinit_verify_padata: entered!\n");
443*7f2fe78bSCy Schubert     if (data == NULL || data->length <= 0 || data->contents == NULL) {
444*7f2fe78bSCy Schubert         (*respond)(arg, EINVAL, NULL, NULL, NULL);
445*7f2fe78bSCy Schubert         return;
446*7f2fe78bSCy Schubert     }
447*7f2fe78bSCy Schubert 
448*7f2fe78bSCy Schubert 
449*7f2fe78bSCy Schubert     if (moddata == NULL) {
450*7f2fe78bSCy Schubert         (*respond)(arg, EINVAL, NULL, NULL, NULL);
451*7f2fe78bSCy Schubert         return;
452*7f2fe78bSCy Schubert     }
453*7f2fe78bSCy Schubert 
454*7f2fe78bSCy Schubert     plgctx = pkinit_find_realm_context(context, moddata, request->server);
455*7f2fe78bSCy Schubert     if (plgctx == NULL) {
456*7f2fe78bSCy Schubert         (*respond)(arg, EINVAL, NULL, NULL, NULL);
457*7f2fe78bSCy Schubert         return;
458*7f2fe78bSCy Schubert     }
459*7f2fe78bSCy Schubert 
460*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
461*7f2fe78bSCy Schubert     print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
462*7f2fe78bSCy Schubert #endif
463*7f2fe78bSCy Schubert     /* create a per-request context */
464*7f2fe78bSCy Schubert     retval = pkinit_init_kdc_req_context(context, &reqctx);
465*7f2fe78bSCy Schubert     if (retval)
466*7f2fe78bSCy Schubert         goto cleanup;
467*7f2fe78bSCy Schubert     reqctx->pa_type = data->pa_type;
468*7f2fe78bSCy Schubert 
469*7f2fe78bSCy Schubert     PADATA_TO_KRB5DATA(data, &k5data);
470*7f2fe78bSCy Schubert 
471*7f2fe78bSCy Schubert     if (data->pa_type != KRB5_PADATA_PK_AS_REQ) {
472*7f2fe78bSCy Schubert         pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
473*7f2fe78bSCy Schubert         retval = EINVAL;
474*7f2fe78bSCy Schubert         goto cleanup;
475*7f2fe78bSCy Schubert     }
476*7f2fe78bSCy Schubert 
477*7f2fe78bSCy Schubert     TRACE_PKINIT_SERVER_PADATA_VERIFY(context);
478*7f2fe78bSCy Schubert     retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
479*7f2fe78bSCy Schubert     if (retval) {
480*7f2fe78bSCy Schubert         pkiDebug("decode_krb5_pa_pk_as_req failed\n");
481*7f2fe78bSCy Schubert         goto cleanup;
482*7f2fe78bSCy Schubert     }
483*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
484*7f2fe78bSCy Schubert     print_buffer_bin(reqp->signedAuthPack.data, reqp->signedAuthPack.length,
485*7f2fe78bSCy Schubert                      "/tmp/kdc_signed_data");
486*7f2fe78bSCy Schubert #endif
487*7f2fe78bSCy Schubert     retval = cms_signeddata_verify(context, plgctx->cryptoctx,
488*7f2fe78bSCy Schubert                                    reqctx->cryptoctx, plgctx->idctx,
489*7f2fe78bSCy Schubert                                    CMS_SIGN_CLIENT,
490*7f2fe78bSCy Schubert                                    plgctx->opts->require_crl_checking,
491*7f2fe78bSCy Schubert                                    (unsigned char *)reqp->signedAuthPack.data,
492*7f2fe78bSCy Schubert                                    reqp->signedAuthPack.length,
493*7f2fe78bSCy Schubert                                    (unsigned char **)&authp_data.data,
494*7f2fe78bSCy Schubert                                    &authp_data.length,
495*7f2fe78bSCy Schubert                                    (unsigned char **)&krb5_authz.data,
496*7f2fe78bSCy Schubert                                    &krb5_authz.length, &is_signed);
497*7f2fe78bSCy Schubert     if (retval) {
498*7f2fe78bSCy Schubert         TRACE_PKINIT_SERVER_PADATA_VERIFY_FAIL(context);
499*7f2fe78bSCy Schubert         goto cleanup;
500*7f2fe78bSCy Schubert     }
501*7f2fe78bSCy Schubert     if (is_signed) {
502*7f2fe78bSCy Schubert         retval = authorize_cert(context, moddata->certauth_modules, plgctx,
503*7f2fe78bSCy Schubert                                 reqctx, cb, rock, request->client, &hwauth);
504*7f2fe78bSCy Schubert         if (retval)
505*7f2fe78bSCy Schubert             goto cleanup;
506*7f2fe78bSCy Schubert 
507*7f2fe78bSCy Schubert     } else { /* !is_signed */
508*7f2fe78bSCy Schubert         if (!krb5_principal_compare(context, request->client,
509*7f2fe78bSCy Schubert                                     krb5_anonymous_principal())) {
510*7f2fe78bSCy Schubert             retval = KRB5KDC_ERR_PREAUTH_FAILED;
511*7f2fe78bSCy Schubert             krb5_set_error_message(context, retval,
512*7f2fe78bSCy Schubert                                    _("Pkinit request not signed, but client "
513*7f2fe78bSCy Schubert                                      "not anonymous."));
514*7f2fe78bSCy Schubert             goto cleanup;
515*7f2fe78bSCy Schubert         }
516*7f2fe78bSCy Schubert     }
517*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
518*7f2fe78bSCy Schubert     print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
519*7f2fe78bSCy Schubert #endif
520*7f2fe78bSCy Schubert 
521*7f2fe78bSCy Schubert     OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
522*7f2fe78bSCy Schubert     retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
523*7f2fe78bSCy Schubert     if (retval) {
524*7f2fe78bSCy Schubert         pkiDebug("failed to decode krb5_auth_pack\n");
525*7f2fe78bSCy Schubert         goto cleanup;
526*7f2fe78bSCy Schubert     }
527*7f2fe78bSCy Schubert 
528*7f2fe78bSCy Schubert     retval = krb5_check_clockskew(context, auth_pack->pkAuthenticator.ctime);
529*7f2fe78bSCy Schubert     if (retval)
530*7f2fe78bSCy Schubert         goto cleanup;
531*7f2fe78bSCy Schubert 
532*7f2fe78bSCy Schubert     /* check dh parameters */
533*7f2fe78bSCy Schubert     if (auth_pack->clientPublicValue.length > 0) {
534*7f2fe78bSCy Schubert         retval = server_check_dh(context, plgctx->cryptoctx,
535*7f2fe78bSCy Schubert                                  reqctx->cryptoctx, plgctx->idctx,
536*7f2fe78bSCy Schubert                                  &auth_pack->clientPublicValue,
537*7f2fe78bSCy Schubert                                  plgctx->opts->dh_min_bits);
538*7f2fe78bSCy Schubert         if (retval) {
539*7f2fe78bSCy Schubert             pkiDebug("bad dh parameters\n");
540*7f2fe78bSCy Schubert             goto cleanup;
541*7f2fe78bSCy Schubert         }
542*7f2fe78bSCy Schubert     } else if (!is_signed) {
543*7f2fe78bSCy Schubert         /*Anonymous pkinit requires DH*/
544*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_PREAUTH_FAILED;
545*7f2fe78bSCy Schubert         krb5_set_error_message(context, retval,
546*7f2fe78bSCy Schubert                                _("Anonymous pkinit without DH public "
547*7f2fe78bSCy Schubert                                  "value not supported."));
548*7f2fe78bSCy Schubert         goto cleanup;
549*7f2fe78bSCy Schubert     }
550*7f2fe78bSCy Schubert     der_req = cb->request_body(context, rock);
551*7f2fe78bSCy Schubert     retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
552*7f2fe78bSCy Schubert                                   &cksum);
553*7f2fe78bSCy Schubert     if (retval) {
554*7f2fe78bSCy Schubert         pkiDebug("unable to calculate AS REQ checksum\n");
555*7f2fe78bSCy Schubert         goto cleanup;
556*7f2fe78bSCy Schubert     }
557*7f2fe78bSCy Schubert     if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
558*7f2fe78bSCy Schubert         k5_bcmp(cksum.contents, auth_pack->pkAuthenticator.paChecksum.contents,
559*7f2fe78bSCy Schubert                 cksum.length) != 0) {
560*7f2fe78bSCy Schubert         pkiDebug("failed to match the checksum\n");
561*7f2fe78bSCy Schubert #ifdef DEBUG_CKSUM
562*7f2fe78bSCy Schubert         pkiDebug("calculating checksum on buf size (%d)\n", req_pkt->length);
563*7f2fe78bSCy Schubert         print_buffer(req_pkt->data, req_pkt->length);
564*7f2fe78bSCy Schubert         pkiDebug("received checksum type=%d size=%d ",
565*7f2fe78bSCy Schubert                  auth_pack->pkAuthenticator.paChecksum.checksum_type,
566*7f2fe78bSCy Schubert                  auth_pack->pkAuthenticator.paChecksum.length);
567*7f2fe78bSCy Schubert         print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
568*7f2fe78bSCy Schubert                      auth_pack->pkAuthenticator.paChecksum.length);
569*7f2fe78bSCy Schubert         pkiDebug("expected checksum type=%d size=%d ",
570*7f2fe78bSCy Schubert                  cksum.checksum_type, cksum.length);
571*7f2fe78bSCy Schubert         print_buffer(cksum.contents, cksum.length);
572*7f2fe78bSCy Schubert #endif
573*7f2fe78bSCy Schubert 
574*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
575*7f2fe78bSCy Schubert         goto cleanup;
576*7f2fe78bSCy Schubert     }
577*7f2fe78bSCy Schubert 
578*7f2fe78bSCy Schubert     ftoken = auth_pack->pkAuthenticator.freshnessToken;
579*7f2fe78bSCy Schubert     if (ftoken != NULL) {
580*7f2fe78bSCy Schubert         retval = cb->check_freshness_token(context, rock, ftoken);
581*7f2fe78bSCy Schubert         if (retval)
582*7f2fe78bSCy Schubert             goto cleanup;
583*7f2fe78bSCy Schubert         valid_freshness_token = TRUE;
584*7f2fe78bSCy Schubert     }
585*7f2fe78bSCy Schubert 
586*7f2fe78bSCy Schubert     /* check if kdcPkId present and match KDC's subjectIdentifier */
587*7f2fe78bSCy Schubert     if (reqp->kdcPkId.data != NULL) {
588*7f2fe78bSCy Schubert         int valid_kdcPkId = 0;
589*7f2fe78bSCy Schubert         retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
590*7f2fe78bSCy Schubert                                        reqctx->cryptoctx, plgctx->idctx,
591*7f2fe78bSCy Schubert                                        (unsigned char *)reqp->kdcPkId.data,
592*7f2fe78bSCy Schubert                                        reqp->kdcPkId.length, &valid_kdcPkId);
593*7f2fe78bSCy Schubert         if (retval)
594*7f2fe78bSCy Schubert             goto cleanup;
595*7f2fe78bSCy Schubert         if (!valid_kdcPkId) {
596*7f2fe78bSCy Schubert             pkiDebug("kdcPkId in AS_REQ does not match KDC's cert; "
597*7f2fe78bSCy Schubert                      "RFC says to ignore and proceed\n");
598*7f2fe78bSCy Schubert         }
599*7f2fe78bSCy Schubert     }
600*7f2fe78bSCy Schubert     /* remember the decoded auth_pack for verify_padata routine */
601*7f2fe78bSCy Schubert     reqctx->rcv_auth_pack = auth_pack;
602*7f2fe78bSCy Schubert     auth_pack = NULL;
603*7f2fe78bSCy Schubert 
604*7f2fe78bSCy Schubert     if (is_signed) {
605*7f2fe78bSCy Schubert         retval = check_log_freshness(context, plgctx, request,
606*7f2fe78bSCy Schubert                                      valid_freshness_token);
607*7f2fe78bSCy Schubert         if (retval)
608*7f2fe78bSCy Schubert             goto cleanup;
609*7f2fe78bSCy Schubert     }
610*7f2fe78bSCy Schubert 
611*7f2fe78bSCy Schubert     if (is_signed && plgctx->auth_indicators != NULL) {
612*7f2fe78bSCy Schubert         /* Assert configured authentication indicators. */
613*7f2fe78bSCy Schubert         for (sp = plgctx->auth_indicators; *sp != NULL; sp++) {
614*7f2fe78bSCy Schubert             retval = cb->add_auth_indicator(context, rock, *sp);
615*7f2fe78bSCy Schubert             if (retval)
616*7f2fe78bSCy Schubert                 goto cleanup;
617*7f2fe78bSCy Schubert         }
618*7f2fe78bSCy Schubert     }
619*7f2fe78bSCy Schubert 
620*7f2fe78bSCy Schubert     /* remember to set the PREAUTH flag in the reply */
621*7f2fe78bSCy Schubert     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
622*7f2fe78bSCy Schubert     if (hwauth)
623*7f2fe78bSCy Schubert         enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
624*7f2fe78bSCy Schubert     modreq = (krb5_kdcpreauth_modreq)reqctx;
625*7f2fe78bSCy Schubert     reqctx = NULL;
626*7f2fe78bSCy Schubert 
627*7f2fe78bSCy Schubert cleanup:
628*7f2fe78bSCy Schubert     if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
629*7f2fe78bSCy Schubert         pkiDebug("pkinit_verify_padata failed: creating e-data\n");
630*7f2fe78bSCy Schubert         if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
631*7f2fe78bSCy Schubert                                 plgctx->idctx, plgctx->opts, retval, &e_data))
632*7f2fe78bSCy Schubert             pkiDebug("pkinit_create_edata failed\n");
633*7f2fe78bSCy Schubert     }
634*7f2fe78bSCy Schubert 
635*7f2fe78bSCy Schubert     free_krb5_pa_pk_as_req(&reqp);
636*7f2fe78bSCy Schubert     free(cksum.contents);
637*7f2fe78bSCy Schubert     free(authp_data.data);
638*7f2fe78bSCy Schubert     free(krb5_authz.data);
639*7f2fe78bSCy Schubert     if (reqctx != NULL)
640*7f2fe78bSCy Schubert         pkinit_fini_kdc_req_context(context, reqctx);
641*7f2fe78bSCy Schubert     free_krb5_auth_pack(&auth_pack);
642*7f2fe78bSCy Schubert 
643*7f2fe78bSCy Schubert     (*respond)(arg, retval, modreq, e_data, NULL);
644*7f2fe78bSCy Schubert }
645*7f2fe78bSCy Schubert static krb5_error_code
return_pkinit_kx(krb5_context context,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_keyblock * encrypting_key,krb5_pa_data ** out_padata)646*7f2fe78bSCy Schubert return_pkinit_kx(krb5_context context, krb5_kdc_req *request,
647*7f2fe78bSCy Schubert                  krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
648*7f2fe78bSCy Schubert                  krb5_pa_data **out_padata)
649*7f2fe78bSCy Schubert {
650*7f2fe78bSCy Schubert     krb5_error_code ret = 0;
651*7f2fe78bSCy Schubert     krb5_keyblock *session = reply->ticket->enc_part2->session;
652*7f2fe78bSCy Schubert     krb5_keyblock *new_session = NULL;
653*7f2fe78bSCy Schubert     krb5_pa_data *pa = NULL;
654*7f2fe78bSCy Schubert     krb5_enc_data enc;
655*7f2fe78bSCy Schubert     krb5_data *scratch = NULL;
656*7f2fe78bSCy Schubert 
657*7f2fe78bSCy Schubert     *out_padata = NULL;
658*7f2fe78bSCy Schubert     enc.ciphertext.data = NULL;
659*7f2fe78bSCy Schubert     if (!krb5_principal_compare(context, request->client,
660*7f2fe78bSCy Schubert                                 krb5_anonymous_principal()))
661*7f2fe78bSCy Schubert         return 0;
662*7f2fe78bSCy Schubert     /*
663*7f2fe78bSCy Schubert      * The KDC contribution key needs to be a fresh key of an enctype supported
664*7f2fe78bSCy Schubert      * by the client and server. The existing session key meets these
665*7f2fe78bSCy Schubert      * requirements so we use it.
666*7f2fe78bSCy Schubert      */
667*7f2fe78bSCy Schubert     ret = krb5_c_fx_cf2_simple(context, session, "PKINIT",
668*7f2fe78bSCy Schubert                                encrypting_key, "KEYEXCHANGE",
669*7f2fe78bSCy Schubert                                &new_session);
670*7f2fe78bSCy Schubert     if (ret)
671*7f2fe78bSCy Schubert         goto cleanup;
672*7f2fe78bSCy Schubert     ret = encode_krb5_encryption_key( session, &scratch);
673*7f2fe78bSCy Schubert     if (ret)
674*7f2fe78bSCy Schubert         goto cleanup;
675*7f2fe78bSCy Schubert     ret = krb5_encrypt_helper(context, encrypting_key,
676*7f2fe78bSCy Schubert                               KRB5_KEYUSAGE_PA_PKINIT_KX, scratch, &enc);
677*7f2fe78bSCy Schubert     if (ret)
678*7f2fe78bSCy Schubert         goto cleanup;
679*7f2fe78bSCy Schubert     memset(scratch->data, 0, scratch->length);
680*7f2fe78bSCy Schubert     krb5_free_data(context, scratch);
681*7f2fe78bSCy Schubert     scratch = NULL;
682*7f2fe78bSCy Schubert     ret = encode_krb5_enc_data(&enc, &scratch);
683*7f2fe78bSCy Schubert     if (ret)
684*7f2fe78bSCy Schubert         goto cleanup;
685*7f2fe78bSCy Schubert     pa = malloc(sizeof(krb5_pa_data));
686*7f2fe78bSCy Schubert     if (pa == NULL) {
687*7f2fe78bSCy Schubert         ret = ENOMEM;
688*7f2fe78bSCy Schubert         goto cleanup;
689*7f2fe78bSCy Schubert     }
690*7f2fe78bSCy Schubert     pa->pa_type = KRB5_PADATA_PKINIT_KX;
691*7f2fe78bSCy Schubert     pa->length = scratch->length;
692*7f2fe78bSCy Schubert     pa->contents = (krb5_octet *) scratch->data;
693*7f2fe78bSCy Schubert     *out_padata = pa;
694*7f2fe78bSCy Schubert     scratch->data = NULL;
695*7f2fe78bSCy Schubert     memset(session->contents, 0, session->length);
696*7f2fe78bSCy Schubert     krb5_free_keyblock_contents(context, session);
697*7f2fe78bSCy Schubert     *session = *new_session;
698*7f2fe78bSCy Schubert     new_session->contents = NULL;
699*7f2fe78bSCy Schubert cleanup:
700*7f2fe78bSCy Schubert     krb5_free_data_contents(context, &enc.ciphertext);
701*7f2fe78bSCy Schubert     krb5_free_keyblock(context, new_session);
702*7f2fe78bSCy Schubert     krb5_free_data(context, scratch);
703*7f2fe78bSCy Schubert     return ret;
704*7f2fe78bSCy Schubert }
705*7f2fe78bSCy Schubert 
706*7f2fe78bSCy Schubert static krb5_error_code
pkinit_pick_kdf_alg(krb5_context context,krb5_data ** kdf_list,krb5_data ** alg_oid)707*7f2fe78bSCy Schubert pkinit_pick_kdf_alg(krb5_context context, krb5_data **kdf_list,
708*7f2fe78bSCy Schubert                     krb5_data **alg_oid)
709*7f2fe78bSCy Schubert {
710*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
711*7f2fe78bSCy Schubert     krb5_data *req_oid = NULL;
712*7f2fe78bSCy Schubert     const krb5_data *supp_oid = NULL;
713*7f2fe78bSCy Schubert     krb5_data *tmp_oid = NULL;
714*7f2fe78bSCy Schubert     int i, j = 0;
715*7f2fe78bSCy Schubert 
716*7f2fe78bSCy Schubert     /* if we don't find a match, return NULL value */
717*7f2fe78bSCy Schubert     *alg_oid = NULL;
718*7f2fe78bSCy Schubert 
719*7f2fe78bSCy Schubert     /* for each of the OIDs that the server supports... */
720*7f2fe78bSCy Schubert     for (i = 0; NULL != (supp_oid = supported_kdf_alg_ids[i]); i++) {
721*7f2fe78bSCy Schubert         /* if the requested OID is in the client's list, use it. */
722*7f2fe78bSCy Schubert         for (j = 0; NULL != (req_oid = kdf_list[j]); j++) {
723*7f2fe78bSCy Schubert             if ((req_oid->length == supp_oid->length) &&
724*7f2fe78bSCy Schubert                 (0 == memcmp(req_oid->data, supp_oid->data, req_oid->length))) {
725*7f2fe78bSCy Schubert                 tmp_oid = k5alloc(sizeof(krb5_data), &retval);
726*7f2fe78bSCy Schubert                 if (retval)
727*7f2fe78bSCy Schubert                     goto cleanup;
728*7f2fe78bSCy Schubert                 tmp_oid->data = k5memdup(supp_oid->data, supp_oid->length,
729*7f2fe78bSCy Schubert                                          &retval);
730*7f2fe78bSCy Schubert                 if (retval)
731*7f2fe78bSCy Schubert                     goto cleanup;
732*7f2fe78bSCy Schubert                 tmp_oid->length = supp_oid->length;
733*7f2fe78bSCy Schubert                 *alg_oid = tmp_oid;
734*7f2fe78bSCy Schubert                 /* don't free the OID in clean-up if we are returning it */
735*7f2fe78bSCy Schubert                 tmp_oid = NULL;
736*7f2fe78bSCy Schubert                 goto cleanup;
737*7f2fe78bSCy Schubert             }
738*7f2fe78bSCy Schubert         }
739*7f2fe78bSCy Schubert     }
740*7f2fe78bSCy Schubert cleanup:
741*7f2fe78bSCy Schubert     if (tmp_oid)
742*7f2fe78bSCy Schubert         krb5_free_data(context, tmp_oid);
743*7f2fe78bSCy Schubert     return retval;
744*7f2fe78bSCy Schubert }
745*7f2fe78bSCy Schubert 
746*7f2fe78bSCy Schubert static krb5_error_code
pkinit_server_return_padata(krb5_context context,krb5_pa_data * padata,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,krb5_kdcpreauth_callbacks cb,krb5_kdcpreauth_rock rock,krb5_kdcpreauth_moddata moddata,krb5_kdcpreauth_modreq modreq)747*7f2fe78bSCy Schubert pkinit_server_return_padata(krb5_context context,
748*7f2fe78bSCy Schubert                             krb5_pa_data * padata,
749*7f2fe78bSCy Schubert                             krb5_data *req_pkt,
750*7f2fe78bSCy Schubert                             krb5_kdc_req * request,
751*7f2fe78bSCy Schubert                             krb5_kdc_rep * reply,
752*7f2fe78bSCy Schubert                             krb5_keyblock * encrypting_key,
753*7f2fe78bSCy Schubert                             krb5_pa_data ** send_pa,
754*7f2fe78bSCy Schubert                             krb5_kdcpreauth_callbacks cb,
755*7f2fe78bSCy Schubert                             krb5_kdcpreauth_rock rock,
756*7f2fe78bSCy Schubert                             krb5_kdcpreauth_moddata moddata,
757*7f2fe78bSCy Schubert                             krb5_kdcpreauth_modreq modreq)
758*7f2fe78bSCy Schubert {
759*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
760*7f2fe78bSCy Schubert     krb5_data scratch = {0, 0, NULL};
761*7f2fe78bSCy Schubert     krb5_pa_pk_as_req *reqp = NULL;
762*7f2fe78bSCy Schubert     int i = 0;
763*7f2fe78bSCy Schubert 
764*7f2fe78bSCy Schubert     unsigned char *dh_pubkey = NULL, *server_key = NULL;
765*7f2fe78bSCy Schubert     unsigned int server_key_len = 0, dh_pubkey_len = 0;
766*7f2fe78bSCy Schubert     krb5_keyblock reply_key = { 0 };
767*7f2fe78bSCy Schubert 
768*7f2fe78bSCy Schubert     krb5_kdc_dh_key_info dhkey_info;
769*7f2fe78bSCy Schubert     krb5_data *encoded_dhkey_info = NULL;
770*7f2fe78bSCy Schubert     krb5_pa_pk_as_rep *rep = NULL;
771*7f2fe78bSCy Schubert     krb5_data *out_data = NULL;
772*7f2fe78bSCy Schubert     krb5_data secret;
773*7f2fe78bSCy Schubert 
774*7f2fe78bSCy Schubert     krb5_enctype enctype = -1;
775*7f2fe78bSCy Schubert 
776*7f2fe78bSCy Schubert     krb5_reply_key_pack *key_pack = NULL;
777*7f2fe78bSCy Schubert     krb5_data *encoded_key_pack = NULL;
778*7f2fe78bSCy Schubert 
779*7f2fe78bSCy Schubert     pkinit_kdc_context plgctx;
780*7f2fe78bSCy Schubert     pkinit_kdc_req_context reqctx;
781*7f2fe78bSCy Schubert 
782*7f2fe78bSCy Schubert     *send_pa = NULL;
783*7f2fe78bSCy Schubert     if (padata->pa_type == KRB5_PADATA_PKINIT_KX) {
784*7f2fe78bSCy Schubert         return return_pkinit_kx(context, request, reply,
785*7f2fe78bSCy Schubert                                 encrypting_key, send_pa);
786*7f2fe78bSCy Schubert     }
787*7f2fe78bSCy Schubert     if (padata->length <= 0 || padata->contents == NULL)
788*7f2fe78bSCy Schubert         return 0;
789*7f2fe78bSCy Schubert 
790*7f2fe78bSCy Schubert     if (modreq == NULL) {
791*7f2fe78bSCy Schubert         pkiDebug("missing request context \n");
792*7f2fe78bSCy Schubert         return EINVAL;
793*7f2fe78bSCy Schubert     }
794*7f2fe78bSCy Schubert 
795*7f2fe78bSCy Schubert     plgctx = pkinit_find_realm_context(context, moddata, request->server);
796*7f2fe78bSCy Schubert     if (plgctx == NULL) {
797*7f2fe78bSCy Schubert         pkiDebug("Unable to locate correct realm context\n");
798*7f2fe78bSCy Schubert         return ENOENT;
799*7f2fe78bSCy Schubert     }
800*7f2fe78bSCy Schubert 
801*7f2fe78bSCy Schubert     TRACE_PKINIT_SERVER_RETURN_PADATA(context);
802*7f2fe78bSCy Schubert     reqctx = (pkinit_kdc_req_context)modreq;
803*7f2fe78bSCy Schubert 
804*7f2fe78bSCy Schubert     for(i = 0; i < request->nktypes; i++) {
805*7f2fe78bSCy Schubert         enctype = request->ktype[i];
806*7f2fe78bSCy Schubert         if (!krb5_c_valid_enctype(enctype))
807*7f2fe78bSCy Schubert             continue;
808*7f2fe78bSCy Schubert         else {
809*7f2fe78bSCy Schubert             pkiDebug("KDC picked etype = %d\n", enctype);
810*7f2fe78bSCy Schubert             break;
811*7f2fe78bSCy Schubert         }
812*7f2fe78bSCy Schubert     }
813*7f2fe78bSCy Schubert 
814*7f2fe78bSCy Schubert     if (i == request->nktypes) {
815*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_ETYPE_NOSUPP;
816*7f2fe78bSCy Schubert         goto cleanup;
817*7f2fe78bSCy Schubert     }
818*7f2fe78bSCy Schubert 
819*7f2fe78bSCy Schubert     init_krb5_pa_pk_as_rep(&rep);
820*7f2fe78bSCy Schubert     if (rep == NULL) {
821*7f2fe78bSCy Schubert         retval = ENOMEM;
822*7f2fe78bSCy Schubert         goto cleanup;
823*7f2fe78bSCy Schubert     }
824*7f2fe78bSCy Schubert     /* let's assume it's RSA. we'll reset it to DH if needed */
825*7f2fe78bSCy Schubert     rep->choice = choice_pa_pk_as_rep_encKeyPack;
826*7f2fe78bSCy Schubert 
827*7f2fe78bSCy Schubert     if (reqctx->rcv_auth_pack != NULL &&
828*7f2fe78bSCy Schubert         reqctx->rcv_auth_pack->clientPublicValue.length > 0) {
829*7f2fe78bSCy Schubert         rep->choice = choice_pa_pk_as_rep_dhInfo;
830*7f2fe78bSCy Schubert 
831*7f2fe78bSCy Schubert         pkiDebug("received DH key delivery AS REQ\n");
832*7f2fe78bSCy Schubert         retval = server_process_dh(context, plgctx->cryptoctx,
833*7f2fe78bSCy Schubert                                    reqctx->cryptoctx, plgctx->idctx,
834*7f2fe78bSCy Schubert                                    &dh_pubkey, &dh_pubkey_len,
835*7f2fe78bSCy Schubert                                    &server_key, &server_key_len);
836*7f2fe78bSCy Schubert         if (retval) {
837*7f2fe78bSCy Schubert             pkiDebug("failed to process/create dh parameters\n");
838*7f2fe78bSCy Schubert             goto cleanup;
839*7f2fe78bSCy Schubert         }
840*7f2fe78bSCy Schubert 
841*7f2fe78bSCy Schubert         /*
842*7f2fe78bSCy Schubert          * This is DH, so don't generate the key until after we
843*7f2fe78bSCy Schubert          * encode the reply, because the encoded reply is needed
844*7f2fe78bSCy Schubert          * to generate the key in some cases.
845*7f2fe78bSCy Schubert          */
846*7f2fe78bSCy Schubert 
847*7f2fe78bSCy Schubert         dhkey_info.subjectPublicKey.length = dh_pubkey_len;
848*7f2fe78bSCy Schubert         dhkey_info.subjectPublicKey.data = (char *)dh_pubkey;
849*7f2fe78bSCy Schubert         dhkey_info.nonce = request->nonce;
850*7f2fe78bSCy Schubert         dhkey_info.dhKeyExpiration = 0;
851*7f2fe78bSCy Schubert 
852*7f2fe78bSCy Schubert         retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
853*7f2fe78bSCy Schubert                                                    &encoded_dhkey_info);
854*7f2fe78bSCy Schubert         if (retval) {
855*7f2fe78bSCy Schubert             pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
856*7f2fe78bSCy Schubert             goto cleanup;
857*7f2fe78bSCy Schubert         }
858*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
859*7f2fe78bSCy Schubert         print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
860*7f2fe78bSCy Schubert                          encoded_dhkey_info->length,
861*7f2fe78bSCy Schubert                          "/tmp/kdc_dh_key_info");
862*7f2fe78bSCy Schubert #endif
863*7f2fe78bSCy Schubert 
864*7f2fe78bSCy Schubert         retval = cms_signeddata_create(context, plgctx->cryptoctx,
865*7f2fe78bSCy Schubert                                        reqctx->cryptoctx, plgctx->idctx,
866*7f2fe78bSCy Schubert                                        CMS_SIGN_SERVER,
867*7f2fe78bSCy Schubert                                        (unsigned char *)
868*7f2fe78bSCy Schubert                                        encoded_dhkey_info->data,
869*7f2fe78bSCy Schubert                                        encoded_dhkey_info->length,
870*7f2fe78bSCy Schubert                                        (unsigned char **)
871*7f2fe78bSCy Schubert                                        &rep->u.dh_Info.dhSignedData.data,
872*7f2fe78bSCy Schubert                                        &rep->u.dh_Info.dhSignedData.length);
873*7f2fe78bSCy Schubert         if (retval) {
874*7f2fe78bSCy Schubert             pkiDebug("failed to create pkcs7 signed data\n");
875*7f2fe78bSCy Schubert             goto cleanup;
876*7f2fe78bSCy Schubert         }
877*7f2fe78bSCy Schubert 
878*7f2fe78bSCy Schubert     } else {
879*7f2fe78bSCy Schubert         pkiDebug("received RSA key delivery AS REQ\n");
880*7f2fe78bSCy Schubert 
881*7f2fe78bSCy Schubert         init_krb5_reply_key_pack(&key_pack);
882*7f2fe78bSCy Schubert         if (key_pack == NULL) {
883*7f2fe78bSCy Schubert             retval = ENOMEM;
884*7f2fe78bSCy Schubert             goto cleanup;
885*7f2fe78bSCy Schubert         }
886*7f2fe78bSCy Schubert 
887*7f2fe78bSCy Schubert         retval = krb5_c_make_random_key(context, enctype, &key_pack->replyKey);
888*7f2fe78bSCy Schubert         if (retval) {
889*7f2fe78bSCy Schubert             pkiDebug("unable to make a session key\n");
890*7f2fe78bSCy Schubert             goto cleanup;
891*7f2fe78bSCy Schubert         }
892*7f2fe78bSCy Schubert 
893*7f2fe78bSCy Schubert         retval = krb5_c_make_checksum(context, 0, &key_pack->replyKey,
894*7f2fe78bSCy Schubert                                       KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
895*7f2fe78bSCy Schubert                                       req_pkt, &key_pack->asChecksum);
896*7f2fe78bSCy Schubert         if (retval) {
897*7f2fe78bSCy Schubert             pkiDebug("unable to calculate AS REQ checksum\n");
898*7f2fe78bSCy Schubert             goto cleanup;
899*7f2fe78bSCy Schubert         }
900*7f2fe78bSCy Schubert #ifdef DEBUG_CKSUM
901*7f2fe78bSCy Schubert         pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
902*7f2fe78bSCy Schubert         print_buffer(req_pkt->data, req_pkt->length);
903*7f2fe78bSCy Schubert         pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
904*7f2fe78bSCy Schubert         print_buffer(key_pack->asChecksum.contents,
905*7f2fe78bSCy Schubert                      key_pack->asChecksum.length);
906*7f2fe78bSCy Schubert         pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length);
907*7f2fe78bSCy Schubert         print_buffer(key_pack->replyKey.contents, key_pack->replyKey.length);
908*7f2fe78bSCy Schubert #endif
909*7f2fe78bSCy Schubert 
910*7f2fe78bSCy Schubert         retval = k5int_encode_krb5_reply_key_pack(key_pack,
911*7f2fe78bSCy Schubert                                                   &encoded_key_pack);
912*7f2fe78bSCy Schubert         if (retval) {
913*7f2fe78bSCy Schubert             pkiDebug("failed to encode reply_key_pack\n");
914*7f2fe78bSCy Schubert             goto cleanup;
915*7f2fe78bSCy Schubert         }
916*7f2fe78bSCy Schubert 
917*7f2fe78bSCy Schubert         rep->choice = choice_pa_pk_as_rep_encKeyPack;
918*7f2fe78bSCy Schubert         retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
919*7f2fe78bSCy Schubert                                           reqctx->cryptoctx, plgctx->idctx,
920*7f2fe78bSCy Schubert                                           padata->pa_type,
921*7f2fe78bSCy Schubert                                           (unsigned char *)
922*7f2fe78bSCy Schubert                                           encoded_key_pack->data,
923*7f2fe78bSCy Schubert                                           encoded_key_pack->length,
924*7f2fe78bSCy Schubert                                           (unsigned char **)
925*7f2fe78bSCy Schubert                                           &rep->u.encKeyPack.data,
926*7f2fe78bSCy Schubert                                           &rep->u.encKeyPack.length);
927*7f2fe78bSCy Schubert         if (retval) {
928*7f2fe78bSCy Schubert             pkiDebug("failed to create pkcs7 enveloped data: %s\n",
929*7f2fe78bSCy Schubert                      error_message(retval));
930*7f2fe78bSCy Schubert             goto cleanup;
931*7f2fe78bSCy Schubert         }
932*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
933*7f2fe78bSCy Schubert         print_buffer_bin((unsigned char *)encoded_key_pack->data,
934*7f2fe78bSCy Schubert                          encoded_key_pack->length,
935*7f2fe78bSCy Schubert                          "/tmp/kdc_key_pack");
936*7f2fe78bSCy Schubert         print_buffer_bin(rep->u.encKeyPack.data, rep->u.encKeyPack.length,
937*7f2fe78bSCy Schubert                          "/tmp/kdc_enc_key_pack");
938*7f2fe78bSCy Schubert #endif
939*7f2fe78bSCy Schubert 
940*7f2fe78bSCy Schubert         retval = cb->replace_reply_key(context, rock, &key_pack->replyKey,
941*7f2fe78bSCy Schubert                                        FALSE);
942*7f2fe78bSCy Schubert         if (retval)
943*7f2fe78bSCy Schubert             goto cleanup;
944*7f2fe78bSCy Schubert     }
945*7f2fe78bSCy Schubert 
946*7f2fe78bSCy Schubert     if (rep->choice == choice_pa_pk_as_rep_dhInfo &&
947*7f2fe78bSCy Schubert         ((reqctx->rcv_auth_pack != NULL &&
948*7f2fe78bSCy Schubert           reqctx->rcv_auth_pack->supportedKDFs != NULL))) {
949*7f2fe78bSCy Schubert 
950*7f2fe78bSCy Schubert         /* If using the alg-agility KDF, put the algorithm in the reply
951*7f2fe78bSCy Schubert          * before encoding it.
952*7f2fe78bSCy Schubert          */
953*7f2fe78bSCy Schubert         if (reqctx->rcv_auth_pack != NULL &&
954*7f2fe78bSCy Schubert             reqctx->rcv_auth_pack->supportedKDFs != NULL) {
955*7f2fe78bSCy Schubert             retval = pkinit_pick_kdf_alg(context, reqctx->rcv_auth_pack->supportedKDFs,
956*7f2fe78bSCy Schubert                                          &(rep->u.dh_Info.kdfID));
957*7f2fe78bSCy Schubert             if (retval) {
958*7f2fe78bSCy Schubert                 pkiDebug("pkinit_pick_kdf_alg failed: %s\n",
959*7f2fe78bSCy Schubert                          error_message(retval));
960*7f2fe78bSCy Schubert                 goto cleanup;
961*7f2fe78bSCy Schubert             }
962*7f2fe78bSCy Schubert         }
963*7f2fe78bSCy Schubert     }
964*7f2fe78bSCy Schubert 
965*7f2fe78bSCy Schubert     retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
966*7f2fe78bSCy Schubert     if (retval) {
967*7f2fe78bSCy Schubert         pkiDebug("failed to encode AS_REP\n");
968*7f2fe78bSCy Schubert         goto cleanup;
969*7f2fe78bSCy Schubert     }
970*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
971*7f2fe78bSCy Schubert     if (out_data != NULL)
972*7f2fe78bSCy Schubert         print_buffer_bin((unsigned char *)out_data->data, out_data->length,
973*7f2fe78bSCy Schubert                          "/tmp/kdc_as_rep");
974*7f2fe78bSCy Schubert #endif
975*7f2fe78bSCy Schubert 
976*7f2fe78bSCy Schubert     /* If this is DH, we haven't computed the key yet, so do it now. */
977*7f2fe78bSCy Schubert     if (rep->choice == choice_pa_pk_as_rep_dhInfo) {
978*7f2fe78bSCy Schubert 
979*7f2fe78bSCy Schubert         /* If mutually supported KDFs were found, use the algorithm agility
980*7f2fe78bSCy Schubert          * KDF. */
981*7f2fe78bSCy Schubert         if (rep->u.dh_Info.kdfID) {
982*7f2fe78bSCy Schubert             secret.data = (char *)server_key;
983*7f2fe78bSCy Schubert             secret.length = server_key_len;
984*7f2fe78bSCy Schubert 
985*7f2fe78bSCy Schubert             retval = pkinit_alg_agility_kdf(context, &secret,
986*7f2fe78bSCy Schubert                                             rep->u.dh_Info.kdfID,
987*7f2fe78bSCy Schubert                                             request->client, request->server,
988*7f2fe78bSCy Schubert                                             enctype, req_pkt, out_data,
989*7f2fe78bSCy Schubert                                             &reply_key);
990*7f2fe78bSCy Schubert             if (retval) {
991*7f2fe78bSCy Schubert                 pkiDebug("pkinit_alg_agility_kdf failed: %s\n",
992*7f2fe78bSCy Schubert                          error_message(retval));
993*7f2fe78bSCy Schubert                 goto cleanup;
994*7f2fe78bSCy Schubert             }
995*7f2fe78bSCy Schubert 
996*7f2fe78bSCy Schubert             /* Otherwise, use the older octetstring2key() function */
997*7f2fe78bSCy Schubert         } else {
998*7f2fe78bSCy Schubert             retval = pkinit_octetstring2key(context, enctype, server_key,
999*7f2fe78bSCy Schubert                                             server_key_len, &reply_key);
1000*7f2fe78bSCy Schubert             if (retval) {
1001*7f2fe78bSCy Schubert                 pkiDebug("pkinit_octetstring2key failed: %s\n",
1002*7f2fe78bSCy Schubert                          error_message(retval));
1003*7f2fe78bSCy Schubert                 goto cleanup;
1004*7f2fe78bSCy Schubert             }
1005*7f2fe78bSCy Schubert         }
1006*7f2fe78bSCy Schubert         retval = cb->replace_reply_key(context, rock, &reply_key, FALSE);
1007*7f2fe78bSCy Schubert         if (retval)
1008*7f2fe78bSCy Schubert             goto cleanup;
1009*7f2fe78bSCy Schubert     }
1010*7f2fe78bSCy Schubert 
1011*7f2fe78bSCy Schubert     *send_pa = malloc(sizeof(krb5_pa_data));
1012*7f2fe78bSCy Schubert     if (*send_pa == NULL) {
1013*7f2fe78bSCy Schubert         retval = ENOMEM;
1014*7f2fe78bSCy Schubert         free(out_data->data);
1015*7f2fe78bSCy Schubert         free(out_data);
1016*7f2fe78bSCy Schubert         out_data = NULL;
1017*7f2fe78bSCy Schubert         goto cleanup;
1018*7f2fe78bSCy Schubert     }
1019*7f2fe78bSCy Schubert     (*send_pa)->magic = KV5M_PA_DATA;
1020*7f2fe78bSCy Schubert     (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
1021*7f2fe78bSCy Schubert     (*send_pa)->length = out_data->length;
1022*7f2fe78bSCy Schubert     (*send_pa)->contents = (krb5_octet *) out_data->data;
1023*7f2fe78bSCy Schubert 
1024*7f2fe78bSCy Schubert cleanup:
1025*7f2fe78bSCy Schubert     free(scratch.data);
1026*7f2fe78bSCy Schubert     free(out_data);
1027*7f2fe78bSCy Schubert     if (encoded_dhkey_info != NULL)
1028*7f2fe78bSCy Schubert         krb5_free_data(context, encoded_dhkey_info);
1029*7f2fe78bSCy Schubert     if (encoded_key_pack != NULL)
1030*7f2fe78bSCy Schubert         krb5_free_data(context, encoded_key_pack);
1031*7f2fe78bSCy Schubert     free(dh_pubkey);
1032*7f2fe78bSCy Schubert     free(server_key);
1033*7f2fe78bSCy Schubert     free_krb5_pa_pk_as_req(&reqp);
1034*7f2fe78bSCy Schubert     free_krb5_pa_pk_as_rep(&rep);
1035*7f2fe78bSCy Schubert     free_krb5_reply_key_pack(&key_pack);
1036*7f2fe78bSCy Schubert     krb5_free_keyblock_contents(context, &reply_key);
1037*7f2fe78bSCy Schubert 
1038*7f2fe78bSCy Schubert     if (retval)
1039*7f2fe78bSCy Schubert         pkiDebug("pkinit_verify_padata failure");
1040*7f2fe78bSCy Schubert 
1041*7f2fe78bSCy Schubert     return retval;
1042*7f2fe78bSCy Schubert }
1043*7f2fe78bSCy Schubert 
1044*7f2fe78bSCy Schubert static int
pkinit_server_get_flags(krb5_context kcontext,krb5_preauthtype patype)1045*7f2fe78bSCy Schubert pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
1046*7f2fe78bSCy Schubert {
1047*7f2fe78bSCy Schubert     if (patype == KRB5_PADATA_PKINIT_KX)
1048*7f2fe78bSCy Schubert         return PA_INFO;
1049*7f2fe78bSCy Schubert     /* PKINIT does not normally set the hw-authent ticket flag, but a
1050*7f2fe78bSCy Schubert      * certauth module can cause it to do so. */
1051*7f2fe78bSCy Schubert     return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA | PA_HARDWARE;
1052*7f2fe78bSCy Schubert }
1053*7f2fe78bSCy Schubert 
1054*7f2fe78bSCy Schubert static krb5_preauthtype supported_server_pa_types[] = {
1055*7f2fe78bSCy Schubert     KRB5_PADATA_PK_AS_REQ,
1056*7f2fe78bSCy Schubert     KRB5_PADATA_PKINIT_KX,
1057*7f2fe78bSCy Schubert     0
1058*7f2fe78bSCy Schubert };
1059*7f2fe78bSCy Schubert 
1060*7f2fe78bSCy Schubert static void
pkinit_fini_kdc_profile(krb5_context context,pkinit_kdc_context plgctx)1061*7f2fe78bSCy Schubert pkinit_fini_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1062*7f2fe78bSCy Schubert {
1063*7f2fe78bSCy Schubert     /*
1064*7f2fe78bSCy Schubert      * There is nothing currently allocated by pkinit_init_kdc_profile()
1065*7f2fe78bSCy Schubert      * which needs to be freed here.
1066*7f2fe78bSCy Schubert      */
1067*7f2fe78bSCy Schubert }
1068*7f2fe78bSCy Schubert 
1069*7f2fe78bSCy Schubert static krb5_error_code
pkinit_init_kdc_profile(krb5_context context,pkinit_kdc_context plgctx)1070*7f2fe78bSCy Schubert pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
1071*7f2fe78bSCy Schubert {
1072*7f2fe78bSCy Schubert     krb5_error_code retval;
1073*7f2fe78bSCy Schubert     char *eku_string = NULL, *ocsp_check = NULL;
1074*7f2fe78bSCy Schubert 
1075*7f2fe78bSCy Schubert     pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname);
1076*7f2fe78bSCy Schubert     retval = pkinit_kdcdefault_string(context, plgctx->realmname,
1077*7f2fe78bSCy Schubert                                       KRB5_CONF_PKINIT_IDENTITY,
1078*7f2fe78bSCy Schubert                                       &plgctx->idopts->identity);
1079*7f2fe78bSCy Schubert     if (retval != 0 || NULL == plgctx->idopts->identity) {
1080*7f2fe78bSCy Schubert         retval = EINVAL;
1081*7f2fe78bSCy Schubert         krb5_set_error_message(context, retval,
1082*7f2fe78bSCy Schubert                                _("No pkinit_identity supplied for realm %s"),
1083*7f2fe78bSCy Schubert                                plgctx->realmname);
1084*7f2fe78bSCy Schubert         goto errout;
1085*7f2fe78bSCy Schubert     }
1086*7f2fe78bSCy Schubert 
1087*7f2fe78bSCy Schubert     retval = pkinit_kdcdefault_strings(context, plgctx->realmname,
1088*7f2fe78bSCy Schubert                                        KRB5_CONF_PKINIT_ANCHORS,
1089*7f2fe78bSCy Schubert                                        &plgctx->idopts->anchors);
1090*7f2fe78bSCy Schubert     if (retval != 0 || NULL == plgctx->idopts->anchors) {
1091*7f2fe78bSCy Schubert         retval = EINVAL;
1092*7f2fe78bSCy Schubert         krb5_set_error_message(context, retval,
1093*7f2fe78bSCy Schubert                                _("No pkinit_anchors supplied for realm %s"),
1094*7f2fe78bSCy Schubert                                plgctx->realmname);
1095*7f2fe78bSCy Schubert         goto errout;
1096*7f2fe78bSCy Schubert     }
1097*7f2fe78bSCy Schubert 
1098*7f2fe78bSCy Schubert     pkinit_kdcdefault_strings(context, plgctx->realmname,
1099*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_POOL,
1100*7f2fe78bSCy Schubert                               &plgctx->idopts->intermediates);
1101*7f2fe78bSCy Schubert 
1102*7f2fe78bSCy Schubert     pkinit_kdcdefault_strings(context, plgctx->realmname,
1103*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_REVOKE,
1104*7f2fe78bSCy Schubert                               &plgctx->idopts->crls);
1105*7f2fe78bSCy Schubert 
1106*7f2fe78bSCy Schubert     pkinit_kdcdefault_string(context, plgctx->realmname,
1107*7f2fe78bSCy Schubert                              KRB5_CONF_PKINIT_KDC_OCSP,
1108*7f2fe78bSCy Schubert                              &ocsp_check);
1109*7f2fe78bSCy Schubert     if (ocsp_check != NULL) {
1110*7f2fe78bSCy Schubert         free(ocsp_check);
1111*7f2fe78bSCy Schubert         retval = ENOTSUP;
1112*7f2fe78bSCy Schubert         krb5_set_error_message(context, retval,
1113*7f2fe78bSCy Schubert                                _("OCSP is not supported: (realm: %s)"),
1114*7f2fe78bSCy Schubert                                plgctx->realmname);
1115*7f2fe78bSCy Schubert         goto errout;
1116*7f2fe78bSCy Schubert     }
1117*7f2fe78bSCy Schubert 
1118*7f2fe78bSCy Schubert     pkinit_kdcdefault_integer(context, plgctx->realmname,
1119*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_DH_MIN_BITS,
1120*7f2fe78bSCy Schubert                               PKINIT_DEFAULT_DH_MIN_BITS,
1121*7f2fe78bSCy Schubert                               &plgctx->opts->dh_min_bits);
1122*7f2fe78bSCy Schubert     if (plgctx->opts->dh_min_bits < PKINIT_DH_MIN_CONFIG_BITS) {
1123*7f2fe78bSCy Schubert         pkiDebug("%s: invalid value (%d < %d) for pkinit_dh_min_bits, "
1124*7f2fe78bSCy Schubert                  "using default value (%d) instead\n", __FUNCTION__,
1125*7f2fe78bSCy Schubert                  plgctx->opts->dh_min_bits, PKINIT_DH_MIN_CONFIG_BITS,
1126*7f2fe78bSCy Schubert                  PKINIT_DEFAULT_DH_MIN_BITS);
1127*7f2fe78bSCy Schubert         plgctx->opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
1128*7f2fe78bSCy Schubert     }
1129*7f2fe78bSCy Schubert 
1130*7f2fe78bSCy Schubert     pkinit_kdcdefault_boolean(context, plgctx->realmname,
1131*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_ALLOW_UPN,
1132*7f2fe78bSCy Schubert                               0, &plgctx->opts->allow_upn);
1133*7f2fe78bSCy Schubert 
1134*7f2fe78bSCy Schubert     pkinit_kdcdefault_boolean(context, plgctx->realmname,
1135*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING,
1136*7f2fe78bSCy Schubert                               0, &plgctx->opts->require_crl_checking);
1137*7f2fe78bSCy Schubert 
1138*7f2fe78bSCy Schubert     pkinit_kdcdefault_boolean(context, plgctx->realmname,
1139*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_REQUIRE_FRESHNESS,
1140*7f2fe78bSCy Schubert                               0, &plgctx->opts->require_freshness);
1141*7f2fe78bSCy Schubert 
1142*7f2fe78bSCy Schubert     pkinit_kdcdefault_string(context, plgctx->realmname,
1143*7f2fe78bSCy Schubert                              KRB5_CONF_PKINIT_EKU_CHECKING,
1144*7f2fe78bSCy Schubert                              &eku_string);
1145*7f2fe78bSCy Schubert     if (eku_string != NULL) {
1146*7f2fe78bSCy Schubert         if (strcasecmp(eku_string, "kpClientAuth") == 0) {
1147*7f2fe78bSCy Schubert             plgctx->opts->require_eku = 1;
1148*7f2fe78bSCy Schubert             plgctx->opts->accept_secondary_eku = 0;
1149*7f2fe78bSCy Schubert         } else if (strcasecmp(eku_string, "scLogin") == 0) {
1150*7f2fe78bSCy Schubert             plgctx->opts->require_eku = 1;
1151*7f2fe78bSCy Schubert             plgctx->opts->accept_secondary_eku = 1;
1152*7f2fe78bSCy Schubert         } else if (strcasecmp(eku_string, "none") == 0) {
1153*7f2fe78bSCy Schubert             plgctx->opts->require_eku = 0;
1154*7f2fe78bSCy Schubert             plgctx->opts->accept_secondary_eku = 0;
1155*7f2fe78bSCy Schubert         } else {
1156*7f2fe78bSCy Schubert             pkiDebug("%s: Invalid value for pkinit_eku_checking: '%s'\n",
1157*7f2fe78bSCy Schubert                      __FUNCTION__, eku_string);
1158*7f2fe78bSCy Schubert         }
1159*7f2fe78bSCy Schubert         free(eku_string);
1160*7f2fe78bSCy Schubert     }
1161*7f2fe78bSCy Schubert 
1162*7f2fe78bSCy Schubert     pkinit_kdcdefault_strings(context, plgctx->realmname,
1163*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_INDICATOR,
1164*7f2fe78bSCy Schubert                               &plgctx->auth_indicators);
1165*7f2fe78bSCy Schubert 
1166*7f2fe78bSCy Schubert     return 0;
1167*7f2fe78bSCy Schubert errout:
1168*7f2fe78bSCy Schubert     pkinit_fini_kdc_profile(context, plgctx);
1169*7f2fe78bSCy Schubert     return retval;
1170*7f2fe78bSCy Schubert }
1171*7f2fe78bSCy Schubert 
1172*7f2fe78bSCy Schubert static pkinit_kdc_context
pkinit_find_realm_context(krb5_context context,krb5_kdcpreauth_moddata moddata,krb5_principal princ)1173*7f2fe78bSCy Schubert pkinit_find_realm_context(krb5_context context,
1174*7f2fe78bSCy Schubert                           krb5_kdcpreauth_moddata moddata,
1175*7f2fe78bSCy Schubert                           krb5_principal princ)
1176*7f2fe78bSCy Schubert {
1177*7f2fe78bSCy Schubert     int i;
1178*7f2fe78bSCy Schubert     pkinit_kdc_context *realm_contexts;
1179*7f2fe78bSCy Schubert 
1180*7f2fe78bSCy Schubert     if (moddata == NULL)
1181*7f2fe78bSCy Schubert         return NULL;
1182*7f2fe78bSCy Schubert 
1183*7f2fe78bSCy Schubert     realm_contexts = moddata->realm_contexts;
1184*7f2fe78bSCy Schubert     if (realm_contexts == NULL)
1185*7f2fe78bSCy Schubert         return NULL;
1186*7f2fe78bSCy Schubert 
1187*7f2fe78bSCy Schubert     for (i = 0; realm_contexts[i] != NULL; i++) {
1188*7f2fe78bSCy Schubert         pkinit_kdc_context p = realm_contexts[i];
1189*7f2fe78bSCy Schubert 
1190*7f2fe78bSCy Schubert         if ((p->realmname_len == princ->realm.length) &&
1191*7f2fe78bSCy Schubert             (strncmp(p->realmname, princ->realm.data, p->realmname_len) == 0)) {
1192*7f2fe78bSCy Schubert             pkiDebug("%s: returning context at %p for realm '%s'\n",
1193*7f2fe78bSCy Schubert                      __FUNCTION__, p, p->realmname);
1194*7f2fe78bSCy Schubert             return p;
1195*7f2fe78bSCy Schubert         }
1196*7f2fe78bSCy Schubert     }
1197*7f2fe78bSCy Schubert     pkiDebug("%s: unable to find realm context for realm '%.*s'\n",
1198*7f2fe78bSCy Schubert              __FUNCTION__, princ->realm.length, princ->realm.data);
1199*7f2fe78bSCy Schubert     return NULL;
1200*7f2fe78bSCy Schubert }
1201*7f2fe78bSCy Schubert 
1202*7f2fe78bSCy Schubert static int
pkinit_server_plugin_init_realm(krb5_context context,const char * realmname,pkinit_kdc_context * pplgctx)1203*7f2fe78bSCy Schubert pkinit_server_plugin_init_realm(krb5_context context, const char *realmname,
1204*7f2fe78bSCy Schubert                                 pkinit_kdc_context *pplgctx)
1205*7f2fe78bSCy Schubert {
1206*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1207*7f2fe78bSCy Schubert     pkinit_kdc_context plgctx = NULL;
1208*7f2fe78bSCy Schubert 
1209*7f2fe78bSCy Schubert     *pplgctx = NULL;
1210*7f2fe78bSCy Schubert 
1211*7f2fe78bSCy Schubert     plgctx = calloc(1, sizeof(*plgctx));
1212*7f2fe78bSCy Schubert     if (plgctx == NULL)
1213*7f2fe78bSCy Schubert         goto errout;
1214*7f2fe78bSCy Schubert 
1215*7f2fe78bSCy Schubert     pkiDebug("%s: initializing context at %p for realm '%s'\n",
1216*7f2fe78bSCy Schubert              __FUNCTION__, plgctx, realmname);
1217*7f2fe78bSCy Schubert     memset(plgctx, 0, sizeof(*plgctx));
1218*7f2fe78bSCy Schubert     plgctx->magic = PKINIT_CTX_MAGIC;
1219*7f2fe78bSCy Schubert 
1220*7f2fe78bSCy Schubert     plgctx->realmname = strdup(realmname);
1221*7f2fe78bSCy Schubert     if (plgctx->realmname == NULL)
1222*7f2fe78bSCy Schubert         goto errout;
1223*7f2fe78bSCy Schubert     plgctx->realmname_len = strlen(plgctx->realmname);
1224*7f2fe78bSCy Schubert 
1225*7f2fe78bSCy Schubert     retval = pkinit_init_plg_crypto(&plgctx->cryptoctx);
1226*7f2fe78bSCy Schubert     if (retval)
1227*7f2fe78bSCy Schubert         goto errout;
1228*7f2fe78bSCy Schubert 
1229*7f2fe78bSCy Schubert     retval = pkinit_init_plg_opts(&plgctx->opts);
1230*7f2fe78bSCy Schubert     if (retval)
1231*7f2fe78bSCy Schubert         goto errout;
1232*7f2fe78bSCy Schubert 
1233*7f2fe78bSCy Schubert     retval = pkinit_init_identity_crypto(&plgctx->idctx);
1234*7f2fe78bSCy Schubert     if (retval)
1235*7f2fe78bSCy Schubert         goto errout;
1236*7f2fe78bSCy Schubert 
1237*7f2fe78bSCy Schubert     retval = pkinit_init_identity_opts(&plgctx->idopts);
1238*7f2fe78bSCy Schubert     if (retval)
1239*7f2fe78bSCy Schubert         goto errout;
1240*7f2fe78bSCy Schubert 
1241*7f2fe78bSCy Schubert     retval = pkinit_init_kdc_profile(context, plgctx);
1242*7f2fe78bSCy Schubert     if (retval)
1243*7f2fe78bSCy Schubert         goto errout;
1244*7f2fe78bSCy Schubert 
1245*7f2fe78bSCy Schubert     retval = pkinit_identity_initialize(context, plgctx->cryptoctx, NULL,
1246*7f2fe78bSCy Schubert                                         plgctx->idopts, plgctx->idctx,
1247*7f2fe78bSCy Schubert                                         NULL, NULL, NULL);
1248*7f2fe78bSCy Schubert     if (retval)
1249*7f2fe78bSCy Schubert         goto errout;
1250*7f2fe78bSCy Schubert     retval = pkinit_identity_prompt(context, plgctx->cryptoctx, NULL,
1251*7f2fe78bSCy Schubert                                     plgctx->idopts, plgctx->idctx,
1252*7f2fe78bSCy Schubert                                     NULL, NULL, 0, NULL);
1253*7f2fe78bSCy Schubert     if (retval)
1254*7f2fe78bSCy Schubert         goto errout;
1255*7f2fe78bSCy Schubert 
1256*7f2fe78bSCy Schubert     pkiDebug("%s: returning context at %p for realm '%s'\n",
1257*7f2fe78bSCy Schubert              __FUNCTION__, plgctx, realmname);
1258*7f2fe78bSCy Schubert     *pplgctx = plgctx;
1259*7f2fe78bSCy Schubert     retval = 0;
1260*7f2fe78bSCy Schubert 
1261*7f2fe78bSCy Schubert errout:
1262*7f2fe78bSCy Schubert     if (retval)
1263*7f2fe78bSCy Schubert         pkinit_server_plugin_fini_realm(context, plgctx);
1264*7f2fe78bSCy Schubert 
1265*7f2fe78bSCy Schubert     return retval;
1266*7f2fe78bSCy Schubert }
1267*7f2fe78bSCy Schubert 
1268*7f2fe78bSCy Schubert static krb5_error_code
pkinit_san_authorize(krb5_context context,krb5_certauth_moddata moddata,const uint8_t * cert,size_t cert_len,krb5_const_principal princ,const void * opts,const struct _krb5_db_entry_new * db_entry,char *** authinds_out)1269*7f2fe78bSCy Schubert pkinit_san_authorize(krb5_context context, krb5_certauth_moddata moddata,
1270*7f2fe78bSCy Schubert                      const uint8_t *cert, size_t cert_len,
1271*7f2fe78bSCy Schubert                      krb5_const_principal princ, const void *opts,
1272*7f2fe78bSCy Schubert                      const struct _krb5_db_entry_new *db_entry,
1273*7f2fe78bSCy Schubert                      char ***authinds_out)
1274*7f2fe78bSCy Schubert {
1275*7f2fe78bSCy Schubert     krb5_error_code ret;
1276*7f2fe78bSCy Schubert     int valid_san;
1277*7f2fe78bSCy Schubert     const struct certauth_req_opts *req_opts = opts;
1278*7f2fe78bSCy Schubert 
1279*7f2fe78bSCy Schubert     *authinds_out = NULL;
1280*7f2fe78bSCy Schubert 
1281*7f2fe78bSCy Schubert     ret = verify_client_san(context, req_opts->plgctx, req_opts->reqctx,
1282*7f2fe78bSCy Schubert                             req_opts->cb, req_opts->rock, princ, &valid_san);
1283*7f2fe78bSCy Schubert     if (ret == ENOENT)
1284*7f2fe78bSCy Schubert         return KRB5_PLUGIN_NO_HANDLE;
1285*7f2fe78bSCy Schubert     else if (ret)
1286*7f2fe78bSCy Schubert         return ret;
1287*7f2fe78bSCy Schubert 
1288*7f2fe78bSCy Schubert     if (!valid_san) {
1289*7f2fe78bSCy Schubert         TRACE_PKINIT_SERVER_SAN_REJECT(context);
1290*7f2fe78bSCy Schubert         return KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
1291*7f2fe78bSCy Schubert     }
1292*7f2fe78bSCy Schubert 
1293*7f2fe78bSCy Schubert     return 0;
1294*7f2fe78bSCy Schubert }
1295*7f2fe78bSCy Schubert 
1296*7f2fe78bSCy Schubert static krb5_error_code
pkinit_eku_authorize(krb5_context context,krb5_certauth_moddata moddata,const uint8_t * cert,size_t cert_len,krb5_const_principal princ,const void * opts,const struct _krb5_db_entry_new * db_entry,char *** authinds_out)1297*7f2fe78bSCy Schubert pkinit_eku_authorize(krb5_context context, krb5_certauth_moddata moddata,
1298*7f2fe78bSCy Schubert                      const uint8_t *cert, size_t cert_len,
1299*7f2fe78bSCy Schubert                      krb5_const_principal princ, const void *opts,
1300*7f2fe78bSCy Schubert                      const struct _krb5_db_entry_new *db_entry,
1301*7f2fe78bSCy Schubert                      char ***authinds_out)
1302*7f2fe78bSCy Schubert {
1303*7f2fe78bSCy Schubert     krb5_error_code ret;
1304*7f2fe78bSCy Schubert     int valid_eku;
1305*7f2fe78bSCy Schubert     const struct certauth_req_opts *req_opts = opts;
1306*7f2fe78bSCy Schubert 
1307*7f2fe78bSCy Schubert     *authinds_out = NULL;
1308*7f2fe78bSCy Schubert 
1309*7f2fe78bSCy Schubert     /* Verify the client EKU. */
1310*7f2fe78bSCy Schubert     ret = verify_client_eku(context, req_opts->plgctx, req_opts->reqctx,
1311*7f2fe78bSCy Schubert                             &valid_eku);
1312*7f2fe78bSCy Schubert     if (ret)
1313*7f2fe78bSCy Schubert         return ret;
1314*7f2fe78bSCy Schubert 
1315*7f2fe78bSCy Schubert     if (!valid_eku) {
1316*7f2fe78bSCy Schubert         TRACE_PKINIT_SERVER_EKU_REJECT(context);
1317*7f2fe78bSCy Schubert         return KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
1318*7f2fe78bSCy Schubert     }
1319*7f2fe78bSCy Schubert 
1320*7f2fe78bSCy Schubert     return KRB5_PLUGIN_NO_HANDLE;
1321*7f2fe78bSCy Schubert }
1322*7f2fe78bSCy Schubert 
1323*7f2fe78bSCy Schubert static krb5_error_code
certauth_pkinit_san_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)1324*7f2fe78bSCy Schubert certauth_pkinit_san_initvt(krb5_context context, int maj_ver, int min_ver,
1325*7f2fe78bSCy Schubert                            krb5_plugin_vtable vtable)
1326*7f2fe78bSCy Schubert {
1327*7f2fe78bSCy Schubert     krb5_certauth_vtable vt;
1328*7f2fe78bSCy Schubert 
1329*7f2fe78bSCy Schubert     if (maj_ver != 1)
1330*7f2fe78bSCy Schubert         return KRB5_PLUGIN_VER_NOTSUPP;
1331*7f2fe78bSCy Schubert     vt = (krb5_certauth_vtable)vtable;
1332*7f2fe78bSCy Schubert     vt->name = "pkinit_san";
1333*7f2fe78bSCy Schubert     vt->authorize = pkinit_san_authorize;
1334*7f2fe78bSCy Schubert     return 0;
1335*7f2fe78bSCy Schubert }
1336*7f2fe78bSCy Schubert 
1337*7f2fe78bSCy Schubert static krb5_error_code
certauth_pkinit_eku_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)1338*7f2fe78bSCy Schubert certauth_pkinit_eku_initvt(krb5_context context, int maj_ver, int min_ver,
1339*7f2fe78bSCy Schubert                            krb5_plugin_vtable vtable)
1340*7f2fe78bSCy Schubert {
1341*7f2fe78bSCy Schubert     krb5_certauth_vtable vt;
1342*7f2fe78bSCy Schubert 
1343*7f2fe78bSCy Schubert     if (maj_ver != 1)
1344*7f2fe78bSCy Schubert         return KRB5_PLUGIN_VER_NOTSUPP;
1345*7f2fe78bSCy Schubert     vt = (krb5_certauth_vtable)vtable;
1346*7f2fe78bSCy Schubert     vt->name = "pkinit_eku";
1347*7f2fe78bSCy Schubert     vt->authorize = pkinit_eku_authorize;
1348*7f2fe78bSCy Schubert     return 0;
1349*7f2fe78bSCy Schubert }
1350*7f2fe78bSCy Schubert 
1351*7f2fe78bSCy Schubert /*
1352*7f2fe78bSCy Schubert  * Do certificate auth based on a match expression in the pkinit_cert_match
1353*7f2fe78bSCy Schubert  * attribute string.  An expression should be in the same form as those used
1354*7f2fe78bSCy Schubert  * for the pkinit_cert_match configuration option.
1355*7f2fe78bSCy Schubert  */
1356*7f2fe78bSCy Schubert static krb5_error_code
dbmatch_authorize(krb5_context context,krb5_certauth_moddata moddata,const uint8_t * cert,size_t cert_len,krb5_const_principal princ,const void * opts,const struct _krb5_db_entry_new * db_entry,char *** authinds_out)1357*7f2fe78bSCy Schubert dbmatch_authorize(krb5_context context, krb5_certauth_moddata moddata,
1358*7f2fe78bSCy Schubert                   const uint8_t *cert, size_t cert_len,
1359*7f2fe78bSCy Schubert                   krb5_const_principal princ, const void *opts,
1360*7f2fe78bSCy Schubert                   const struct _krb5_db_entry_new *db_entry,
1361*7f2fe78bSCy Schubert                   char ***authinds_out)
1362*7f2fe78bSCy Schubert {
1363*7f2fe78bSCy Schubert     krb5_error_code ret;
1364*7f2fe78bSCy Schubert     const struct certauth_req_opts *req_opts = opts;
1365*7f2fe78bSCy Schubert     char *pattern;
1366*7f2fe78bSCy Schubert     krb5_boolean matched;
1367*7f2fe78bSCy Schubert 
1368*7f2fe78bSCy Schubert     *authinds_out = NULL;
1369*7f2fe78bSCy Schubert 
1370*7f2fe78bSCy Schubert     /* Fetch the matching pattern.  Pass if it isn't specified. */
1371*7f2fe78bSCy Schubert     ret = req_opts->cb->get_string(context, req_opts->rock,
1372*7f2fe78bSCy Schubert                                    "pkinit_cert_match", &pattern);
1373*7f2fe78bSCy Schubert     if (ret)
1374*7f2fe78bSCy Schubert         return ret;
1375*7f2fe78bSCy Schubert     if (pattern == NULL)
1376*7f2fe78bSCy Schubert         return KRB5_PLUGIN_NO_HANDLE;
1377*7f2fe78bSCy Schubert 
1378*7f2fe78bSCy Schubert     /* Check the certificate against the match expression. */
1379*7f2fe78bSCy Schubert     ret = pkinit_client_cert_match(context, req_opts->plgctx->cryptoctx,
1380*7f2fe78bSCy Schubert                                    req_opts->reqctx->cryptoctx, pattern,
1381*7f2fe78bSCy Schubert                                    &matched);
1382*7f2fe78bSCy Schubert     req_opts->cb->free_string(context, req_opts->rock, pattern);
1383*7f2fe78bSCy Schubert     if (ret)
1384*7f2fe78bSCy Schubert         return ret;
1385*7f2fe78bSCy Schubert     return matched ? 0 : KRB5KDC_ERR_CERTIFICATE_MISMATCH;
1386*7f2fe78bSCy Schubert }
1387*7f2fe78bSCy Schubert 
1388*7f2fe78bSCy Schubert static krb5_error_code
certauth_dbmatch_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)1389*7f2fe78bSCy Schubert certauth_dbmatch_initvt(krb5_context context, int maj_ver, int min_ver,
1390*7f2fe78bSCy Schubert                         krb5_plugin_vtable vtable)
1391*7f2fe78bSCy Schubert {
1392*7f2fe78bSCy Schubert     krb5_certauth_vtable vt;
1393*7f2fe78bSCy Schubert 
1394*7f2fe78bSCy Schubert     if (maj_ver != 1)
1395*7f2fe78bSCy Schubert         return KRB5_PLUGIN_VER_NOTSUPP;
1396*7f2fe78bSCy Schubert     vt = (krb5_certauth_vtable)vtable;
1397*7f2fe78bSCy Schubert     vt->name = "dbmatch";
1398*7f2fe78bSCy Schubert     vt->authorize = dbmatch_authorize;
1399*7f2fe78bSCy Schubert     return 0;
1400*7f2fe78bSCy Schubert }
1401*7f2fe78bSCy Schubert 
1402*7f2fe78bSCy Schubert static krb5_error_code
load_certauth_plugins(krb5_context context,const char * const * realmnames,certauth_handle ** handle_out)1403*7f2fe78bSCy Schubert load_certauth_plugins(krb5_context context, const char *const *realmnames,
1404*7f2fe78bSCy Schubert                       certauth_handle **handle_out)
1405*7f2fe78bSCy Schubert {
1406*7f2fe78bSCy Schubert     krb5_error_code ret;
1407*7f2fe78bSCy Schubert     krb5_plugin_initvt_fn *modules = NULL, *mod;
1408*7f2fe78bSCy Schubert     certauth_handle *list = NULL, h;
1409*7f2fe78bSCy Schubert     size_t count;
1410*7f2fe78bSCy Schubert 
1411*7f2fe78bSCy Schubert     /* Register the builtin modules. */
1412*7f2fe78bSCy Schubert     ret = k5_plugin_register(context, PLUGIN_INTERFACE_CERTAUTH,
1413*7f2fe78bSCy Schubert                              "pkinit_san", certauth_pkinit_san_initvt);
1414*7f2fe78bSCy Schubert     if (ret)
1415*7f2fe78bSCy Schubert         goto cleanup;
1416*7f2fe78bSCy Schubert 
1417*7f2fe78bSCy Schubert     ret = k5_plugin_register(context, PLUGIN_INTERFACE_CERTAUTH,
1418*7f2fe78bSCy Schubert                              "pkinit_eku", certauth_pkinit_eku_initvt);
1419*7f2fe78bSCy Schubert     if (ret)
1420*7f2fe78bSCy Schubert         goto cleanup;
1421*7f2fe78bSCy Schubert 
1422*7f2fe78bSCy Schubert     ret = k5_plugin_register(context, PLUGIN_INTERFACE_CERTAUTH, "dbmatch",
1423*7f2fe78bSCy Schubert                              certauth_dbmatch_initvt);
1424*7f2fe78bSCy Schubert     if (ret)
1425*7f2fe78bSCy Schubert         goto cleanup;
1426*7f2fe78bSCy Schubert 
1427*7f2fe78bSCy Schubert     ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_CERTAUTH, &modules);
1428*7f2fe78bSCy Schubert     if (ret)
1429*7f2fe78bSCy Schubert         goto cleanup;
1430*7f2fe78bSCy Schubert 
1431*7f2fe78bSCy Schubert     /* Allocate handle list. */
1432*7f2fe78bSCy Schubert     for (count = 0; modules[count]; count++);
1433*7f2fe78bSCy Schubert     list = k5calloc(count + 1, sizeof(*list), &ret);
1434*7f2fe78bSCy Schubert     if (list == NULL)
1435*7f2fe78bSCy Schubert         goto cleanup;
1436*7f2fe78bSCy Schubert 
1437*7f2fe78bSCy Schubert     /* Initialize each module, ignoring ones that fail. */
1438*7f2fe78bSCy Schubert     count = 0;
1439*7f2fe78bSCy Schubert     for (mod = modules; *mod != NULL; mod++) {
1440*7f2fe78bSCy Schubert         h = k5calloc(1, sizeof(*h), &ret);
1441*7f2fe78bSCy Schubert         if (h == NULL)
1442*7f2fe78bSCy Schubert             goto cleanup;
1443*7f2fe78bSCy Schubert 
1444*7f2fe78bSCy Schubert         ret = (*mod)(context, 1, 2, (krb5_plugin_vtable)&h->vt);
1445*7f2fe78bSCy Schubert         if (ret) {
1446*7f2fe78bSCy Schubert             TRACE_CERTAUTH_VTINIT_FAIL(context, ret);
1447*7f2fe78bSCy Schubert             free(h);
1448*7f2fe78bSCy Schubert             continue;
1449*7f2fe78bSCy Schubert         }
1450*7f2fe78bSCy Schubert         h->moddata = NULL;
1451*7f2fe78bSCy Schubert         if (h->vt.init_ex != NULL)
1452*7f2fe78bSCy Schubert             ret = h->vt.init_ex(context, realmnames, &h->moddata);
1453*7f2fe78bSCy Schubert         else if (h->vt.init != NULL)
1454*7f2fe78bSCy Schubert             ret = h->vt.init(context, &h->moddata);
1455*7f2fe78bSCy Schubert         if (ret) {
1456*7f2fe78bSCy Schubert             TRACE_CERTAUTH_INIT_FAIL(context, h->vt.name, ret);
1457*7f2fe78bSCy Schubert             free(h);
1458*7f2fe78bSCy Schubert             continue;
1459*7f2fe78bSCy Schubert         }
1460*7f2fe78bSCy Schubert         list[count++] = h;
1461*7f2fe78bSCy Schubert         list[count] = NULL;
1462*7f2fe78bSCy Schubert     }
1463*7f2fe78bSCy Schubert     list[count] = NULL;
1464*7f2fe78bSCy Schubert 
1465*7f2fe78bSCy Schubert     ret = 0;
1466*7f2fe78bSCy Schubert     *handle_out = list;
1467*7f2fe78bSCy Schubert     list = NULL;
1468*7f2fe78bSCy Schubert 
1469*7f2fe78bSCy Schubert cleanup:
1470*7f2fe78bSCy Schubert     k5_plugin_free_modules(context, modules);
1471*7f2fe78bSCy Schubert     free_certauth_handles(context, list);
1472*7f2fe78bSCy Schubert     return ret;
1473*7f2fe78bSCy Schubert }
1474*7f2fe78bSCy Schubert 
1475*7f2fe78bSCy Schubert static int
pkinit_server_plugin_init(krb5_context context,krb5_kdcpreauth_moddata * moddata_out,const char ** realmnames)1476*7f2fe78bSCy Schubert pkinit_server_plugin_init(krb5_context context,
1477*7f2fe78bSCy Schubert                           krb5_kdcpreauth_moddata *moddata_out,
1478*7f2fe78bSCy Schubert                           const char **realmnames)
1479*7f2fe78bSCy Schubert {
1480*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1481*7f2fe78bSCy Schubert     pkinit_kdc_context plgctx, *realm_contexts = NULL;
1482*7f2fe78bSCy Schubert     certauth_handle *certauth_modules = NULL;
1483*7f2fe78bSCy Schubert     krb5_kdcpreauth_moddata moddata;
1484*7f2fe78bSCy Schubert     size_t  i, j;
1485*7f2fe78bSCy Schubert     size_t numrealms;
1486*7f2fe78bSCy Schubert 
1487*7f2fe78bSCy Schubert     retval = pkinit_accessor_init();
1488*7f2fe78bSCy Schubert     if (retval)
1489*7f2fe78bSCy Schubert         return retval;
1490*7f2fe78bSCy Schubert 
1491*7f2fe78bSCy Schubert     /* Determine how many realms we may need to support */
1492*7f2fe78bSCy Schubert     for (i = 0; realmnames[i] != NULL; i++) {};
1493*7f2fe78bSCy Schubert     numrealms = i;
1494*7f2fe78bSCy Schubert 
1495*7f2fe78bSCy Schubert     realm_contexts = calloc(numrealms+1, sizeof(pkinit_kdc_context));
1496*7f2fe78bSCy Schubert     if (realm_contexts == NULL)
1497*7f2fe78bSCy Schubert         return ENOMEM;
1498*7f2fe78bSCy Schubert 
1499*7f2fe78bSCy Schubert     for (i = 0, j = 0; i < numrealms; i++) {
1500*7f2fe78bSCy Schubert         TRACE_PKINIT_SERVER_INIT_REALM(context, realmnames[i]);
1501*7f2fe78bSCy Schubert         krb5_clear_error_message(context);
1502*7f2fe78bSCy Schubert         retval = pkinit_server_plugin_init_realm(context, realmnames[i],
1503*7f2fe78bSCy Schubert                                                  &plgctx);
1504*7f2fe78bSCy Schubert         if (retval)
1505*7f2fe78bSCy Schubert             TRACE_PKINIT_SERVER_INIT_FAIL(context, realmnames[i], retval);
1506*7f2fe78bSCy Schubert         else
1507*7f2fe78bSCy Schubert             realm_contexts[j++] = plgctx;
1508*7f2fe78bSCy Schubert     }
1509*7f2fe78bSCy Schubert 
1510*7f2fe78bSCy Schubert     if (j == 0) {
1511*7f2fe78bSCy Schubert         if (numrealms == 1) {
1512*7f2fe78bSCy Schubert             k5_prependmsg(context, retval, "PKINIT initialization failed");
1513*7f2fe78bSCy Schubert         } else {
1514*7f2fe78bSCy Schubert             retval = EINVAL;
1515*7f2fe78bSCy Schubert             k5_setmsg(context, retval,
1516*7f2fe78bSCy Schubert                       _("No realms configured correctly for pkinit support"));
1517*7f2fe78bSCy Schubert         }
1518*7f2fe78bSCy Schubert         goto errout;
1519*7f2fe78bSCy Schubert     }
1520*7f2fe78bSCy Schubert 
1521*7f2fe78bSCy Schubert     retval = load_certauth_plugins(context, realmnames, &certauth_modules);
1522*7f2fe78bSCy Schubert     if (retval)
1523*7f2fe78bSCy Schubert         goto errout;
1524*7f2fe78bSCy Schubert 
1525*7f2fe78bSCy Schubert     moddata = k5calloc(1, sizeof(*moddata), &retval);
1526*7f2fe78bSCy Schubert     if (moddata == NULL)
1527*7f2fe78bSCy Schubert         goto errout;
1528*7f2fe78bSCy Schubert     moddata->realm_contexts = realm_contexts;
1529*7f2fe78bSCy Schubert     moddata->certauth_modules = certauth_modules;
1530*7f2fe78bSCy Schubert     *moddata_out = moddata;
1531*7f2fe78bSCy Schubert     pkiDebug("%s: returning context at %p\n", __FUNCTION__, moddata);
1532*7f2fe78bSCy Schubert     return 0;
1533*7f2fe78bSCy Schubert 
1534*7f2fe78bSCy Schubert errout:
1535*7f2fe78bSCy Schubert     free_realm_contexts(context, realm_contexts);
1536*7f2fe78bSCy Schubert     free_certauth_handles(context, certauth_modules);
1537*7f2fe78bSCy Schubert     return retval;
1538*7f2fe78bSCy Schubert }
1539*7f2fe78bSCy Schubert 
1540*7f2fe78bSCy Schubert static void
pkinit_server_plugin_fini_realm(krb5_context context,pkinit_kdc_context plgctx)1541*7f2fe78bSCy Schubert pkinit_server_plugin_fini_realm(krb5_context context, pkinit_kdc_context plgctx)
1542*7f2fe78bSCy Schubert {
1543*7f2fe78bSCy Schubert     char **sp;
1544*7f2fe78bSCy Schubert 
1545*7f2fe78bSCy Schubert     if (plgctx == NULL)
1546*7f2fe78bSCy Schubert         return;
1547*7f2fe78bSCy Schubert 
1548*7f2fe78bSCy Schubert     pkinit_fini_kdc_profile(context, plgctx);
1549*7f2fe78bSCy Schubert     pkinit_fini_identity_opts(plgctx->idopts);
1550*7f2fe78bSCy Schubert     pkinit_fini_identity_crypto(plgctx->idctx);
1551*7f2fe78bSCy Schubert     pkinit_fini_plg_crypto(plgctx->cryptoctx);
1552*7f2fe78bSCy Schubert     pkinit_fini_plg_opts(plgctx->opts);
1553*7f2fe78bSCy Schubert     for (sp = plgctx->auth_indicators; sp != NULL && *sp != NULL; sp++)
1554*7f2fe78bSCy Schubert         free(*sp);
1555*7f2fe78bSCy Schubert     free(plgctx->auth_indicators);
1556*7f2fe78bSCy Schubert     free(plgctx->realmname);
1557*7f2fe78bSCy Schubert     free(plgctx);
1558*7f2fe78bSCy Schubert }
1559*7f2fe78bSCy Schubert 
1560*7f2fe78bSCy Schubert static void
pkinit_server_plugin_fini(krb5_context context,krb5_kdcpreauth_moddata moddata)1561*7f2fe78bSCy Schubert pkinit_server_plugin_fini(krb5_context context,
1562*7f2fe78bSCy Schubert                           krb5_kdcpreauth_moddata moddata)
1563*7f2fe78bSCy Schubert {
1564*7f2fe78bSCy Schubert     if (moddata == NULL)
1565*7f2fe78bSCy Schubert         return;
1566*7f2fe78bSCy Schubert     free_realm_contexts(context, moddata->realm_contexts);
1567*7f2fe78bSCy Schubert     free_certauth_handles(context, moddata->certauth_modules);
1568*7f2fe78bSCy Schubert     free(moddata);
1569*7f2fe78bSCy Schubert }
1570*7f2fe78bSCy Schubert 
1571*7f2fe78bSCy Schubert static krb5_error_code
pkinit_init_kdc_req_context(krb5_context context,pkinit_kdc_req_context * ctx)1572*7f2fe78bSCy Schubert pkinit_init_kdc_req_context(krb5_context context, pkinit_kdc_req_context *ctx)
1573*7f2fe78bSCy Schubert {
1574*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1575*7f2fe78bSCy Schubert     pkinit_kdc_req_context reqctx = NULL;
1576*7f2fe78bSCy Schubert 
1577*7f2fe78bSCy Schubert     reqctx = malloc(sizeof(*reqctx));
1578*7f2fe78bSCy Schubert     if (reqctx == NULL)
1579*7f2fe78bSCy Schubert         return retval;
1580*7f2fe78bSCy Schubert     memset(reqctx, 0, sizeof(*reqctx));
1581*7f2fe78bSCy Schubert     reqctx->magic = PKINIT_CTX_MAGIC;
1582*7f2fe78bSCy Schubert 
1583*7f2fe78bSCy Schubert     retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
1584*7f2fe78bSCy Schubert     if (retval)
1585*7f2fe78bSCy Schubert         goto cleanup;
1586*7f2fe78bSCy Schubert     reqctx->rcv_auth_pack = NULL;
1587*7f2fe78bSCy Schubert 
1588*7f2fe78bSCy Schubert     pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
1589*7f2fe78bSCy Schubert     *ctx = reqctx;
1590*7f2fe78bSCy Schubert     retval = 0;
1591*7f2fe78bSCy Schubert cleanup:
1592*7f2fe78bSCy Schubert     if (retval)
1593*7f2fe78bSCy Schubert         pkinit_fini_kdc_req_context(context, reqctx);
1594*7f2fe78bSCy Schubert 
1595*7f2fe78bSCy Schubert     return retval;
1596*7f2fe78bSCy Schubert }
1597*7f2fe78bSCy Schubert 
1598*7f2fe78bSCy Schubert static void
pkinit_fini_kdc_req_context(krb5_context context,void * ctx)1599*7f2fe78bSCy Schubert pkinit_fini_kdc_req_context(krb5_context context, void *ctx)
1600*7f2fe78bSCy Schubert {
1601*7f2fe78bSCy Schubert     pkinit_kdc_req_context reqctx = (pkinit_kdc_req_context)ctx;
1602*7f2fe78bSCy Schubert 
1603*7f2fe78bSCy Schubert     if (reqctx == NULL || reqctx->magic != PKINIT_CTX_MAGIC) {
1604*7f2fe78bSCy Schubert         pkiDebug("pkinit_fini_kdc_req_context: got bad reqctx (%p)!\n", reqctx);
1605*7f2fe78bSCy Schubert         return;
1606*7f2fe78bSCy Schubert     }
1607*7f2fe78bSCy Schubert     pkiDebug("%s: freeing reqctx at %p\n", __FUNCTION__, reqctx);
1608*7f2fe78bSCy Schubert 
1609*7f2fe78bSCy Schubert     pkinit_fini_req_crypto(reqctx->cryptoctx);
1610*7f2fe78bSCy Schubert     if (reqctx->rcv_auth_pack != NULL)
1611*7f2fe78bSCy Schubert         free_krb5_auth_pack(&reqctx->rcv_auth_pack);
1612*7f2fe78bSCy Schubert 
1613*7f2fe78bSCy Schubert     free(reqctx);
1614*7f2fe78bSCy Schubert }
1615*7f2fe78bSCy Schubert 
1616*7f2fe78bSCy Schubert static void
pkinit_free_modreq(krb5_context context,krb5_kdcpreauth_moddata moddata,krb5_kdcpreauth_modreq modreq)1617*7f2fe78bSCy Schubert pkinit_free_modreq(krb5_context context, krb5_kdcpreauth_moddata moddata,
1618*7f2fe78bSCy Schubert                    krb5_kdcpreauth_modreq modreq)
1619*7f2fe78bSCy Schubert {
1620*7f2fe78bSCy Schubert     pkinit_fini_kdc_req_context(context, modreq);
1621*7f2fe78bSCy Schubert }
1622*7f2fe78bSCy Schubert 
1623*7f2fe78bSCy Schubert krb5_error_code
1624*7f2fe78bSCy Schubert kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
1625*7f2fe78bSCy Schubert                          krb5_plugin_vtable vtable);
1626*7f2fe78bSCy Schubert 
1627*7f2fe78bSCy Schubert krb5_error_code
kdcpreauth_pkinit_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)1628*7f2fe78bSCy Schubert kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
1629*7f2fe78bSCy Schubert                          krb5_plugin_vtable vtable)
1630*7f2fe78bSCy Schubert {
1631*7f2fe78bSCy Schubert     krb5_kdcpreauth_vtable vt;
1632*7f2fe78bSCy Schubert 
1633*7f2fe78bSCy Schubert     if (maj_ver != 1)
1634*7f2fe78bSCy Schubert         return KRB5_PLUGIN_VER_NOTSUPP;
1635*7f2fe78bSCy Schubert     vt = (krb5_kdcpreauth_vtable)vtable;
1636*7f2fe78bSCy Schubert     vt->name = "pkinit";
1637*7f2fe78bSCy Schubert     vt->pa_type_list = supported_server_pa_types;
1638*7f2fe78bSCy Schubert     vt->init = pkinit_server_plugin_init;
1639*7f2fe78bSCy Schubert     vt->fini = pkinit_server_plugin_fini;
1640*7f2fe78bSCy Schubert     vt->flags = pkinit_server_get_flags;
1641*7f2fe78bSCy Schubert     vt->edata = pkinit_server_get_edata;
1642*7f2fe78bSCy Schubert     vt->verify = pkinit_server_verify_padata;
1643*7f2fe78bSCy Schubert     vt->return_padata = pkinit_server_return_padata;
1644*7f2fe78bSCy Schubert     vt->free_modreq = pkinit_free_modreq;
1645*7f2fe78bSCy Schubert     return 0;
1646*7f2fe78bSCy Schubert }
1647