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