xref: /freebsd/crypto/krb5/src/plugins/preauth/pkinit/pkinit_identity.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert  * COPYRIGHT (C) 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 "pkinit.h"
33*7f2fe78bSCy Schubert #include <dirent.h>
34*7f2fe78bSCy Schubert 
35*7f2fe78bSCy Schubert static void
free_list(char ** list)36*7f2fe78bSCy Schubert free_list(char **list)
37*7f2fe78bSCy Schubert {
38*7f2fe78bSCy Schubert     int i;
39*7f2fe78bSCy Schubert 
40*7f2fe78bSCy Schubert     if (list == NULL)
41*7f2fe78bSCy Schubert         return;
42*7f2fe78bSCy Schubert 
43*7f2fe78bSCy Schubert     for (i = 0; list[i] != NULL; i++)
44*7f2fe78bSCy Schubert         free(list[i]);
45*7f2fe78bSCy Schubert     free(list);
46*7f2fe78bSCy Schubert }
47*7f2fe78bSCy Schubert 
48*7f2fe78bSCy Schubert static krb5_error_code
copy_list(char *** dst,char ** src)49*7f2fe78bSCy Schubert copy_list(char ***dst, char **src)
50*7f2fe78bSCy Schubert {
51*7f2fe78bSCy Schubert     int i;
52*7f2fe78bSCy Schubert     char **newlist;
53*7f2fe78bSCy Schubert 
54*7f2fe78bSCy Schubert     if (dst == NULL)
55*7f2fe78bSCy Schubert         return EINVAL;
56*7f2fe78bSCy Schubert     *dst = NULL;
57*7f2fe78bSCy Schubert 
58*7f2fe78bSCy Schubert     if (src == NULL)
59*7f2fe78bSCy Schubert         return 0;
60*7f2fe78bSCy Schubert 
61*7f2fe78bSCy Schubert     for (i = 0; src[i] != NULL; i++);
62*7f2fe78bSCy Schubert 
63*7f2fe78bSCy Schubert     newlist = calloc(1, (i + 1) * sizeof(*newlist));
64*7f2fe78bSCy Schubert     if (newlist == NULL)
65*7f2fe78bSCy Schubert         return ENOMEM;
66*7f2fe78bSCy Schubert 
67*7f2fe78bSCy Schubert     for (i = 0; src[i] != NULL; i++) {
68*7f2fe78bSCy Schubert         newlist[i] = strdup(src[i]);
69*7f2fe78bSCy Schubert         if (newlist[i] == NULL)
70*7f2fe78bSCy Schubert             goto cleanup;
71*7f2fe78bSCy Schubert     }
72*7f2fe78bSCy Schubert     newlist[i] = NULL;
73*7f2fe78bSCy Schubert     *dst = newlist;
74*7f2fe78bSCy Schubert     return 0;
75*7f2fe78bSCy Schubert cleanup:
76*7f2fe78bSCy Schubert     free_list(newlist);
77*7f2fe78bSCy Schubert     return ENOMEM;
78*7f2fe78bSCy Schubert }
79*7f2fe78bSCy Schubert 
80*7f2fe78bSCy Schubert char *
idtype2string(int idtype)81*7f2fe78bSCy Schubert idtype2string(int idtype)
82*7f2fe78bSCy Schubert {
83*7f2fe78bSCy Schubert     switch(idtype) {
84*7f2fe78bSCy Schubert     case IDTYPE_FILE: return "FILE"; break;
85*7f2fe78bSCy Schubert     case IDTYPE_DIR: return "DIR"; break;
86*7f2fe78bSCy Schubert     case IDTYPE_PKCS11: return "PKCS11"; break;
87*7f2fe78bSCy Schubert     case IDTYPE_PKCS12: return "PKCS12"; break;
88*7f2fe78bSCy Schubert     case IDTYPE_ENVVAR: return "ENV"; break;
89*7f2fe78bSCy Schubert     default: return "INVALID"; break;
90*7f2fe78bSCy Schubert     }
91*7f2fe78bSCy Schubert }
92*7f2fe78bSCy Schubert 
93*7f2fe78bSCy Schubert char *
catype2string(int catype)94*7f2fe78bSCy Schubert catype2string(int catype)
95*7f2fe78bSCy Schubert {
96*7f2fe78bSCy Schubert     switch(catype) {
97*7f2fe78bSCy Schubert     case CATYPE_ANCHORS: return "ANCHORS"; break;
98*7f2fe78bSCy Schubert     case CATYPE_INTERMEDIATES: return "INTERMEDIATES"; break;
99*7f2fe78bSCy Schubert     case CATYPE_CRLS: return "CRLS"; break;
100*7f2fe78bSCy Schubert     default: return "INVALID"; break;
101*7f2fe78bSCy Schubert     }
102*7f2fe78bSCy Schubert }
103*7f2fe78bSCy Schubert 
104*7f2fe78bSCy Schubert krb5_error_code
pkinit_init_identity_opts(pkinit_identity_opts ** idopts)105*7f2fe78bSCy Schubert pkinit_init_identity_opts(pkinit_identity_opts **idopts)
106*7f2fe78bSCy Schubert {
107*7f2fe78bSCy Schubert     pkinit_identity_opts *opts = NULL;
108*7f2fe78bSCy Schubert 
109*7f2fe78bSCy Schubert     *idopts = NULL;
110*7f2fe78bSCy Schubert     opts = calloc(1, sizeof(pkinit_identity_opts));
111*7f2fe78bSCy Schubert     if (opts == NULL)
112*7f2fe78bSCy Schubert         return ENOMEM;
113*7f2fe78bSCy Schubert 
114*7f2fe78bSCy Schubert     opts->identity = NULL;
115*7f2fe78bSCy Schubert     opts->anchors = NULL;
116*7f2fe78bSCy Schubert     opts->intermediates = NULL;
117*7f2fe78bSCy Schubert     opts->crls = NULL;
118*7f2fe78bSCy Schubert 
119*7f2fe78bSCy Schubert     opts->cert_filename = NULL;
120*7f2fe78bSCy Schubert     opts->key_filename = NULL;
121*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
122*7f2fe78bSCy Schubert     opts->p11_module_name = NULL;
123*7f2fe78bSCy Schubert     opts->slotid = PK_NOSLOT;
124*7f2fe78bSCy Schubert     opts->token_label = NULL;
125*7f2fe78bSCy Schubert     opts->cert_id_string = NULL;
126*7f2fe78bSCy Schubert     opts->cert_label = NULL;
127*7f2fe78bSCy Schubert #endif
128*7f2fe78bSCy Schubert 
129*7f2fe78bSCy Schubert     *idopts = opts;
130*7f2fe78bSCy Schubert 
131*7f2fe78bSCy Schubert     return 0;
132*7f2fe78bSCy Schubert }
133*7f2fe78bSCy Schubert 
134*7f2fe78bSCy Schubert krb5_error_code
pkinit_dup_identity_opts(pkinit_identity_opts * src_opts,pkinit_identity_opts ** dest_opts)135*7f2fe78bSCy Schubert pkinit_dup_identity_opts(pkinit_identity_opts *src_opts,
136*7f2fe78bSCy Schubert                          pkinit_identity_opts **dest_opts)
137*7f2fe78bSCy Schubert {
138*7f2fe78bSCy Schubert     pkinit_identity_opts *newopts;
139*7f2fe78bSCy Schubert     krb5_error_code retval;
140*7f2fe78bSCy Schubert 
141*7f2fe78bSCy Schubert     *dest_opts = NULL;
142*7f2fe78bSCy Schubert     retval = pkinit_init_identity_opts(&newopts);
143*7f2fe78bSCy Schubert     if (retval)
144*7f2fe78bSCy Schubert         return retval;
145*7f2fe78bSCy Schubert 
146*7f2fe78bSCy Schubert     retval = ENOMEM;
147*7f2fe78bSCy Schubert 
148*7f2fe78bSCy Schubert     if (src_opts->identity != NULL) {
149*7f2fe78bSCy Schubert         newopts->identity = strdup(src_opts->identity);
150*7f2fe78bSCy Schubert         if (newopts->identity == NULL)
151*7f2fe78bSCy Schubert             goto cleanup;
152*7f2fe78bSCy Schubert     }
153*7f2fe78bSCy Schubert 
154*7f2fe78bSCy Schubert     retval = copy_list(&newopts->anchors, src_opts->anchors);
155*7f2fe78bSCy Schubert     if (retval)
156*7f2fe78bSCy Schubert         goto cleanup;
157*7f2fe78bSCy Schubert 
158*7f2fe78bSCy Schubert     retval = copy_list(&newopts->intermediates,src_opts->intermediates);
159*7f2fe78bSCy Schubert     if (retval)
160*7f2fe78bSCy Schubert         goto cleanup;
161*7f2fe78bSCy Schubert 
162*7f2fe78bSCy Schubert     retval = copy_list(&newopts->crls, src_opts->crls);
163*7f2fe78bSCy Schubert     if (retval)
164*7f2fe78bSCy Schubert         goto cleanup;
165*7f2fe78bSCy Schubert 
166*7f2fe78bSCy Schubert     if (src_opts->cert_filename != NULL) {
167*7f2fe78bSCy Schubert         newopts->cert_filename = strdup(src_opts->cert_filename);
168*7f2fe78bSCy Schubert         if (newopts->cert_filename == NULL)
169*7f2fe78bSCy Schubert             goto cleanup;
170*7f2fe78bSCy Schubert     }
171*7f2fe78bSCy Schubert 
172*7f2fe78bSCy Schubert     if (src_opts->key_filename != NULL) {
173*7f2fe78bSCy Schubert         newopts->key_filename = strdup(src_opts->key_filename);
174*7f2fe78bSCy Schubert         if (newopts->key_filename == NULL)
175*7f2fe78bSCy Schubert             goto cleanup;
176*7f2fe78bSCy Schubert     }
177*7f2fe78bSCy Schubert 
178*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
179*7f2fe78bSCy Schubert     if (src_opts->p11_module_name != NULL) {
180*7f2fe78bSCy Schubert         newopts->p11_module_name = strdup(src_opts->p11_module_name);
181*7f2fe78bSCy Schubert         if (newopts->p11_module_name == NULL)
182*7f2fe78bSCy Schubert             goto cleanup;
183*7f2fe78bSCy Schubert     }
184*7f2fe78bSCy Schubert 
185*7f2fe78bSCy Schubert     newopts->slotid = src_opts->slotid;
186*7f2fe78bSCy Schubert 
187*7f2fe78bSCy Schubert     if (src_opts->token_label != NULL) {
188*7f2fe78bSCy Schubert         newopts->token_label = strdup(src_opts->token_label);
189*7f2fe78bSCy Schubert         if (newopts->token_label == NULL)
190*7f2fe78bSCy Schubert             goto cleanup;
191*7f2fe78bSCy Schubert     }
192*7f2fe78bSCy Schubert 
193*7f2fe78bSCy Schubert     if (src_opts->cert_id_string != NULL) {
194*7f2fe78bSCy Schubert         newopts->cert_id_string = strdup(src_opts->cert_id_string);
195*7f2fe78bSCy Schubert         if (newopts->cert_id_string == NULL)
196*7f2fe78bSCy Schubert             goto cleanup;
197*7f2fe78bSCy Schubert     }
198*7f2fe78bSCy Schubert 
199*7f2fe78bSCy Schubert     if (src_opts->cert_label != NULL) {
200*7f2fe78bSCy Schubert         newopts->cert_label = strdup(src_opts->cert_label);
201*7f2fe78bSCy Schubert         if (newopts->cert_label == NULL)
202*7f2fe78bSCy Schubert             goto cleanup;
203*7f2fe78bSCy Schubert     }
204*7f2fe78bSCy Schubert #endif
205*7f2fe78bSCy Schubert 
206*7f2fe78bSCy Schubert 
207*7f2fe78bSCy Schubert     *dest_opts = newopts;
208*7f2fe78bSCy Schubert     return 0;
209*7f2fe78bSCy Schubert cleanup:
210*7f2fe78bSCy Schubert     pkinit_fini_identity_opts(newopts);
211*7f2fe78bSCy Schubert     return retval;
212*7f2fe78bSCy Schubert }
213*7f2fe78bSCy Schubert 
214*7f2fe78bSCy Schubert void
pkinit_fini_identity_opts(pkinit_identity_opts * idopts)215*7f2fe78bSCy Schubert pkinit_fini_identity_opts(pkinit_identity_opts *idopts)
216*7f2fe78bSCy Schubert {
217*7f2fe78bSCy Schubert     if (idopts == NULL)
218*7f2fe78bSCy Schubert         return;
219*7f2fe78bSCy Schubert 
220*7f2fe78bSCy Schubert     if (idopts->identity != NULL)
221*7f2fe78bSCy Schubert         free(idopts->identity);
222*7f2fe78bSCy Schubert     free_list(idopts->anchors);
223*7f2fe78bSCy Schubert     free_list(idopts->intermediates);
224*7f2fe78bSCy Schubert     free_list(idopts->crls);
225*7f2fe78bSCy Schubert     free_list(idopts->identity_alt);
226*7f2fe78bSCy Schubert 
227*7f2fe78bSCy Schubert     free(idopts->cert_filename);
228*7f2fe78bSCy Schubert     free(idopts->key_filename);
229*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
230*7f2fe78bSCy Schubert     free(idopts->p11_module_name);
231*7f2fe78bSCy Schubert     free(idopts->token_label);
232*7f2fe78bSCy Schubert     free(idopts->cert_id_string);
233*7f2fe78bSCy Schubert     free(idopts->cert_label);
234*7f2fe78bSCy Schubert #endif
235*7f2fe78bSCy Schubert     free(idopts);
236*7f2fe78bSCy Schubert }
237*7f2fe78bSCy Schubert 
238*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
239*7f2fe78bSCy Schubert static krb5_error_code
parse_pkcs11_options(krb5_context context,pkinit_identity_opts * idopts,const char * residual)240*7f2fe78bSCy Schubert parse_pkcs11_options(krb5_context context,
241*7f2fe78bSCy Schubert                      pkinit_identity_opts *idopts,
242*7f2fe78bSCy Schubert                      const char *residual)
243*7f2fe78bSCy Schubert {
244*7f2fe78bSCy Schubert     char *s, *cp, *vp, *save;
245*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
246*7f2fe78bSCy Schubert 
247*7f2fe78bSCy Schubert     if (residual == NULL || residual[0] == '\0')
248*7f2fe78bSCy Schubert         return 0;
249*7f2fe78bSCy Schubert 
250*7f2fe78bSCy Schubert     /* Split string into attr=value substrings */
251*7f2fe78bSCy Schubert     s = strdup(residual);
252*7f2fe78bSCy Schubert     if (s == NULL)
253*7f2fe78bSCy Schubert         return retval;
254*7f2fe78bSCy Schubert 
255*7f2fe78bSCy Schubert     for (cp = strtok_r(s, ":", &save); cp; cp = strtok_r(NULL, ":", &save)) {
256*7f2fe78bSCy Schubert         vp = strchr(cp, '=');
257*7f2fe78bSCy Schubert 
258*7f2fe78bSCy Schubert         /* If there is no "=", this is a pkcs11 module name */
259*7f2fe78bSCy Schubert         if (vp == NULL) {
260*7f2fe78bSCy Schubert             free(idopts->p11_module_name);
261*7f2fe78bSCy Schubert             idopts->p11_module_name = strdup(cp);
262*7f2fe78bSCy Schubert             if (idopts->p11_module_name == NULL)
263*7f2fe78bSCy Schubert                 goto cleanup;
264*7f2fe78bSCy Schubert             continue;
265*7f2fe78bSCy Schubert         }
266*7f2fe78bSCy Schubert         *vp++ = '\0';
267*7f2fe78bSCy Schubert         if (!strcmp(cp, "module_name")) {
268*7f2fe78bSCy Schubert             free(idopts->p11_module_name);
269*7f2fe78bSCy Schubert             idopts->p11_module_name = strdup(vp);
270*7f2fe78bSCy Schubert             if (idopts->p11_module_name == NULL)
271*7f2fe78bSCy Schubert                 goto cleanup;
272*7f2fe78bSCy Schubert         } else if (!strcmp(cp, "slotid")) {
273*7f2fe78bSCy Schubert             long slotid = strtol(vp, NULL, 10);
274*7f2fe78bSCy Schubert             if ((slotid == LONG_MIN || slotid == LONG_MAX) && errno != 0) {
275*7f2fe78bSCy Schubert                 retval = EINVAL;
276*7f2fe78bSCy Schubert                 goto cleanup;
277*7f2fe78bSCy Schubert             }
278*7f2fe78bSCy Schubert             if ((long) (int) slotid != slotid) {
279*7f2fe78bSCy Schubert                 retval = EINVAL;
280*7f2fe78bSCy Schubert                 goto cleanup;
281*7f2fe78bSCy Schubert             }
282*7f2fe78bSCy Schubert             idopts->slotid = slotid;
283*7f2fe78bSCy Schubert         } else if (!strcmp(cp, "token")) {
284*7f2fe78bSCy Schubert             free(idopts->token_label);
285*7f2fe78bSCy Schubert             idopts->token_label = strdup(vp);
286*7f2fe78bSCy Schubert             if (idopts->token_label == NULL)
287*7f2fe78bSCy Schubert                 goto cleanup;
288*7f2fe78bSCy Schubert         } else if (!strcmp(cp, "certid")) {
289*7f2fe78bSCy Schubert             free(idopts->cert_id_string);
290*7f2fe78bSCy Schubert             idopts->cert_id_string = strdup(vp);
291*7f2fe78bSCy Schubert             if (idopts->cert_id_string == NULL)
292*7f2fe78bSCy Schubert                 goto cleanup;
293*7f2fe78bSCy Schubert         } else if (!strcmp(cp, "certlabel")) {
294*7f2fe78bSCy Schubert             free(idopts->cert_label);
295*7f2fe78bSCy Schubert             idopts->cert_label = strdup(vp);
296*7f2fe78bSCy Schubert             if (idopts->cert_label == NULL)
297*7f2fe78bSCy Schubert                 goto cleanup;
298*7f2fe78bSCy Schubert         }
299*7f2fe78bSCy Schubert     }
300*7f2fe78bSCy Schubert     retval = 0;
301*7f2fe78bSCy Schubert cleanup:
302*7f2fe78bSCy Schubert     free(s);
303*7f2fe78bSCy Schubert     return retval;
304*7f2fe78bSCy Schubert }
305*7f2fe78bSCy Schubert #endif
306*7f2fe78bSCy Schubert 
307*7f2fe78bSCy Schubert static krb5_error_code
parse_fs_options(krb5_context context,pkinit_identity_opts * idopts,const char * residual)308*7f2fe78bSCy Schubert parse_fs_options(krb5_context context,
309*7f2fe78bSCy Schubert                  pkinit_identity_opts *idopts,
310*7f2fe78bSCy Schubert                  const char *residual)
311*7f2fe78bSCy Schubert {
312*7f2fe78bSCy Schubert     char *certname, *keyname, *save;
313*7f2fe78bSCy Schubert     char *copy = NULL, *cert_filename = NULL, *key_filename = NULL;
314*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
315*7f2fe78bSCy Schubert 
316*7f2fe78bSCy Schubert     if (residual == NULL || residual[0] == '\0' || residual[0] == ',')
317*7f2fe78bSCy Schubert         return EINVAL;
318*7f2fe78bSCy Schubert 
319*7f2fe78bSCy Schubert     copy = strdup(residual);
320*7f2fe78bSCy Schubert     if (copy == NULL)
321*7f2fe78bSCy Schubert         goto cleanup;
322*7f2fe78bSCy Schubert 
323*7f2fe78bSCy Schubert     certname = strtok_r(copy, ",", &save);
324*7f2fe78bSCy Schubert     if (certname == NULL)
325*7f2fe78bSCy Schubert         goto cleanup;
326*7f2fe78bSCy Schubert     keyname = strtok_r(NULL, ",", &save);
327*7f2fe78bSCy Schubert 
328*7f2fe78bSCy Schubert     cert_filename = strdup(certname);
329*7f2fe78bSCy Schubert     if (cert_filename == NULL)
330*7f2fe78bSCy Schubert         goto cleanup;
331*7f2fe78bSCy Schubert 
332*7f2fe78bSCy Schubert     key_filename = strdup((keyname != NULL) ? keyname : certname);
333*7f2fe78bSCy Schubert     if (key_filename == NULL)
334*7f2fe78bSCy Schubert         goto cleanup;
335*7f2fe78bSCy Schubert 
336*7f2fe78bSCy Schubert     free(idopts->cert_filename);
337*7f2fe78bSCy Schubert     free(idopts->key_filename);
338*7f2fe78bSCy Schubert     idopts->cert_filename = cert_filename;
339*7f2fe78bSCy Schubert     idopts->key_filename = key_filename;
340*7f2fe78bSCy Schubert     cert_filename = key_filename = NULL;
341*7f2fe78bSCy Schubert     retval = 0;
342*7f2fe78bSCy Schubert 
343*7f2fe78bSCy Schubert cleanup:
344*7f2fe78bSCy Schubert     free(copy);
345*7f2fe78bSCy Schubert     free(cert_filename);
346*7f2fe78bSCy Schubert     free(key_filename);
347*7f2fe78bSCy Schubert     return retval;
348*7f2fe78bSCy Schubert }
349*7f2fe78bSCy Schubert 
350*7f2fe78bSCy Schubert static krb5_error_code
parse_pkcs12_options(krb5_context context,pkinit_identity_opts * idopts,const char * residual)351*7f2fe78bSCy Schubert parse_pkcs12_options(krb5_context context,
352*7f2fe78bSCy Schubert                      pkinit_identity_opts *idopts,
353*7f2fe78bSCy Schubert                      const char *residual)
354*7f2fe78bSCy Schubert {
355*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
356*7f2fe78bSCy Schubert 
357*7f2fe78bSCy Schubert     if (residual == NULL || residual[0] == '\0')
358*7f2fe78bSCy Schubert         return 0;
359*7f2fe78bSCy Schubert 
360*7f2fe78bSCy Schubert     free(idopts->cert_filename);
361*7f2fe78bSCy Schubert     idopts->cert_filename = strdup(residual);
362*7f2fe78bSCy Schubert     if (idopts->cert_filename == NULL)
363*7f2fe78bSCy Schubert         goto cleanup;
364*7f2fe78bSCy Schubert 
365*7f2fe78bSCy Schubert     free(idopts->key_filename);
366*7f2fe78bSCy Schubert     idopts->key_filename = strdup(residual);
367*7f2fe78bSCy Schubert     if (idopts->key_filename == NULL)
368*7f2fe78bSCy Schubert         goto cleanup;
369*7f2fe78bSCy Schubert 
370*7f2fe78bSCy Schubert     pkiDebug("%s: cert_filename '%s' key_filename '%s'\n",
371*7f2fe78bSCy Schubert              __FUNCTION__, idopts->cert_filename,
372*7f2fe78bSCy Schubert              idopts->key_filename);
373*7f2fe78bSCy Schubert     retval = 0;
374*7f2fe78bSCy Schubert cleanup:
375*7f2fe78bSCy Schubert     return retval;
376*7f2fe78bSCy Schubert }
377*7f2fe78bSCy Schubert 
378*7f2fe78bSCy Schubert static krb5_error_code
process_option_identity(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ,const char * value)379*7f2fe78bSCy Schubert process_option_identity(krb5_context context,
380*7f2fe78bSCy Schubert                         pkinit_plg_crypto_context plg_cryptoctx,
381*7f2fe78bSCy Schubert                         pkinit_req_crypto_context req_cryptoctx,
382*7f2fe78bSCy Schubert                         pkinit_identity_opts *idopts,
383*7f2fe78bSCy Schubert                         pkinit_identity_crypto_context id_cryptoctx,
384*7f2fe78bSCy Schubert                         krb5_principal princ, const char *value)
385*7f2fe78bSCy Schubert {
386*7f2fe78bSCy Schubert     const char *residual;
387*7f2fe78bSCy Schubert     int idtype;
388*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
389*7f2fe78bSCy Schubert 
390*7f2fe78bSCy Schubert     TRACE_PKINIT_IDENTITY_OPTION(context, value);
391*7f2fe78bSCy Schubert     if (value == NULL)
392*7f2fe78bSCy Schubert         return EINVAL;
393*7f2fe78bSCy Schubert 
394*7f2fe78bSCy Schubert     residual = strchr(value, ':');
395*7f2fe78bSCy Schubert     if (residual != NULL) {
396*7f2fe78bSCy Schubert         unsigned int typelen;
397*7f2fe78bSCy Schubert         residual++; /* skip past colon */
398*7f2fe78bSCy Schubert         typelen = residual - value;
399*7f2fe78bSCy Schubert         if (strncmp(value, "FILE:", typelen) == 0) {
400*7f2fe78bSCy Schubert             idtype = IDTYPE_FILE;
401*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
402*7f2fe78bSCy Schubert         } else if (strncmp(value, "PKCS11:", typelen) == 0) {
403*7f2fe78bSCy Schubert             idtype = IDTYPE_PKCS11;
404*7f2fe78bSCy Schubert #endif
405*7f2fe78bSCy Schubert         } else if (strncmp(value, "PKCS12:", typelen) == 0) {
406*7f2fe78bSCy Schubert             idtype = IDTYPE_PKCS12;
407*7f2fe78bSCy Schubert         } else if (strncmp(value, "DIR:", typelen) == 0) {
408*7f2fe78bSCy Schubert             idtype = IDTYPE_DIR;
409*7f2fe78bSCy Schubert         } else if (strncmp(value, "ENV:", typelen) == 0) {
410*7f2fe78bSCy Schubert             idtype = IDTYPE_ENVVAR;
411*7f2fe78bSCy Schubert         } else {
412*7f2fe78bSCy Schubert             pkiDebug("%s: Unsupported type while processing '%s'\n",
413*7f2fe78bSCy Schubert                      __FUNCTION__, value);
414*7f2fe78bSCy Schubert             krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
415*7f2fe78bSCy Schubert                                    _("Unsupported type while processing "
416*7f2fe78bSCy Schubert                                      "'%s'\n"), value);
417*7f2fe78bSCy Schubert             return KRB5_PREAUTH_FAILED;
418*7f2fe78bSCy Schubert         }
419*7f2fe78bSCy Schubert     } else {
420*7f2fe78bSCy Schubert         idtype = IDTYPE_FILE;
421*7f2fe78bSCy Schubert         residual = value;
422*7f2fe78bSCy Schubert     }
423*7f2fe78bSCy Schubert 
424*7f2fe78bSCy Schubert     idopts->idtype = idtype;
425*7f2fe78bSCy Schubert     pkiDebug("%s: idtype is %s\n", __FUNCTION__, idtype2string(idopts->idtype));
426*7f2fe78bSCy Schubert     switch (idtype) {
427*7f2fe78bSCy Schubert     case IDTYPE_ENVVAR:
428*7f2fe78bSCy Schubert         return process_option_identity(context, plg_cryptoctx, req_cryptoctx,
429*7f2fe78bSCy Schubert                                        idopts, id_cryptoctx, princ,
430*7f2fe78bSCy Schubert                                        secure_getenv(residual));
431*7f2fe78bSCy Schubert         break;
432*7f2fe78bSCy Schubert     case IDTYPE_FILE:
433*7f2fe78bSCy Schubert         retval = parse_fs_options(context, idopts, residual);
434*7f2fe78bSCy Schubert         break;
435*7f2fe78bSCy Schubert     case IDTYPE_PKCS12:
436*7f2fe78bSCy Schubert         retval = parse_pkcs12_options(context, idopts, residual);
437*7f2fe78bSCy Schubert         break;
438*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
439*7f2fe78bSCy Schubert     case IDTYPE_PKCS11:
440*7f2fe78bSCy Schubert         retval = parse_pkcs11_options(context, idopts, residual);
441*7f2fe78bSCy Schubert         break;
442*7f2fe78bSCy Schubert #endif
443*7f2fe78bSCy Schubert     case IDTYPE_DIR:
444*7f2fe78bSCy Schubert         free(idopts->cert_filename);
445*7f2fe78bSCy Schubert         idopts->cert_filename = strdup(residual);
446*7f2fe78bSCy Schubert         if (idopts->cert_filename == NULL)
447*7f2fe78bSCy Schubert             retval = ENOMEM;
448*7f2fe78bSCy Schubert         break;
449*7f2fe78bSCy Schubert     default:
450*7f2fe78bSCy Schubert         krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
451*7f2fe78bSCy Schubert                                _("Internal error parsing "
452*7f2fe78bSCy Schubert                                  "X509_user_identity\n"));
453*7f2fe78bSCy Schubert         retval = EINVAL;
454*7f2fe78bSCy Schubert         break;
455*7f2fe78bSCy Schubert     }
456*7f2fe78bSCy Schubert     if (retval)
457*7f2fe78bSCy Schubert         return retval;
458*7f2fe78bSCy Schubert 
459*7f2fe78bSCy Schubert     retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx, idopts,
460*7f2fe78bSCy Schubert                                id_cryptoctx, princ, TRUE);
461*7f2fe78bSCy Schubert     if (retval)
462*7f2fe78bSCy Schubert         return retval;
463*7f2fe78bSCy Schubert 
464*7f2fe78bSCy Schubert     crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx, id_cryptoctx);
465*7f2fe78bSCy Schubert     return 0;
466*7f2fe78bSCy Schubert }
467*7f2fe78bSCy Schubert 
468*7f2fe78bSCy Schubert static krb5_error_code
process_option_ca_crl(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,const char * value,int catype)469*7f2fe78bSCy Schubert process_option_ca_crl(krb5_context context,
470*7f2fe78bSCy Schubert                       pkinit_plg_crypto_context plg_cryptoctx,
471*7f2fe78bSCy Schubert                       pkinit_req_crypto_context req_cryptoctx,
472*7f2fe78bSCy Schubert                       pkinit_identity_opts *idopts,
473*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context id_cryptoctx,
474*7f2fe78bSCy Schubert                       const char *value,
475*7f2fe78bSCy Schubert                       int catype)
476*7f2fe78bSCy Schubert {
477*7f2fe78bSCy Schubert     char *residual;
478*7f2fe78bSCy Schubert     unsigned int typelen;
479*7f2fe78bSCy Schubert     int idtype;
480*7f2fe78bSCy Schubert 
481*7f2fe78bSCy Schubert     pkiDebug("%s: processing catype %s, value '%s'\n",
482*7f2fe78bSCy Schubert              __FUNCTION__, catype2string(catype), value);
483*7f2fe78bSCy Schubert     residual = strchr(value, ':');
484*7f2fe78bSCy Schubert     if (residual == NULL) {
485*7f2fe78bSCy Schubert         pkiDebug("No type given for '%s'\n", value);
486*7f2fe78bSCy Schubert         return EINVAL;
487*7f2fe78bSCy Schubert     }
488*7f2fe78bSCy Schubert     residual++; /* skip past colon */
489*7f2fe78bSCy Schubert     typelen = residual - value;
490*7f2fe78bSCy Schubert     if (strncmp(value, "FILE:", typelen) == 0) {
491*7f2fe78bSCy Schubert         idtype = IDTYPE_FILE;
492*7f2fe78bSCy Schubert     } else if (strncmp(value, "DIR:", typelen) == 0) {
493*7f2fe78bSCy Schubert         idtype = IDTYPE_DIR;
494*7f2fe78bSCy Schubert     } else {
495*7f2fe78bSCy Schubert         return ENOTSUP;
496*7f2fe78bSCy Schubert     }
497*7f2fe78bSCy Schubert     return crypto_load_cas_and_crls(context,
498*7f2fe78bSCy Schubert                                     plg_cryptoctx,
499*7f2fe78bSCy Schubert                                     req_cryptoctx,
500*7f2fe78bSCy Schubert                                     idopts, id_cryptoctx,
501*7f2fe78bSCy Schubert                                     idtype, catype, residual);
502*7f2fe78bSCy Schubert }
503*7f2fe78bSCy Schubert 
504*7f2fe78bSCy Schubert /*
505*7f2fe78bSCy Schubert  * Load any identity information which doesn't require us to ask a controlling
506*7f2fe78bSCy Schubert  * user any questions, and record the names of anything else which would
507*7f2fe78bSCy Schubert  * require us to ask questions.
508*7f2fe78bSCy Schubert  */
509*7f2fe78bSCy Schubert krb5_error_code
pkinit_identity_initialize(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_clpreauth_callbacks cb,krb5_clpreauth_rock rock,krb5_principal princ)510*7f2fe78bSCy Schubert pkinit_identity_initialize(krb5_context context,
511*7f2fe78bSCy Schubert                            pkinit_plg_crypto_context plg_cryptoctx,
512*7f2fe78bSCy Schubert                            pkinit_req_crypto_context req_cryptoctx,
513*7f2fe78bSCy Schubert                            pkinit_identity_opts *idopts,
514*7f2fe78bSCy Schubert                            pkinit_identity_crypto_context id_cryptoctx,
515*7f2fe78bSCy Schubert                            krb5_clpreauth_callbacks cb,
516*7f2fe78bSCy Schubert                            krb5_clpreauth_rock rock,
517*7f2fe78bSCy Schubert                            krb5_principal princ)
518*7f2fe78bSCy Schubert {
519*7f2fe78bSCy Schubert     krb5_error_code retval = EINVAL;
520*7f2fe78bSCy Schubert     int i;
521*7f2fe78bSCy Schubert 
522*7f2fe78bSCy Schubert     pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
523*7f2fe78bSCy Schubert     if (!(princ &&
524*7f2fe78bSCy Schubert           krb5_principal_compare_any_realm(context, princ,
525*7f2fe78bSCy Schubert                                            krb5_anonymous_principal()))) {
526*7f2fe78bSCy Schubert         if (idopts == NULL || id_cryptoctx == NULL)
527*7f2fe78bSCy Schubert             goto errout;
528*7f2fe78bSCy Schubert 
529*7f2fe78bSCy Schubert         /*
530*7f2fe78bSCy Schubert          * If identity was specified, use that.  (For the kdc, this
531*7f2fe78bSCy Schubert          * is specified as pkinit_identity in the kdc.conf.  For users,
532*7f2fe78bSCy Schubert          * this is specified on the command line via X509_user_identity.)
533*7f2fe78bSCy Schubert          * If a user did not specify identity on the command line,
534*7f2fe78bSCy Schubert          * then we will try alternatives which may have been specified
535*7f2fe78bSCy Schubert          * in the config file.
536*7f2fe78bSCy Schubert          */
537*7f2fe78bSCy Schubert         if (idopts->identity != NULL) {
538*7f2fe78bSCy Schubert             retval = process_option_identity(context, plg_cryptoctx,
539*7f2fe78bSCy Schubert                                              req_cryptoctx, idopts,
540*7f2fe78bSCy Schubert                                              id_cryptoctx, princ,
541*7f2fe78bSCy Schubert                                              idopts->identity);
542*7f2fe78bSCy Schubert         } else if (idopts->identity_alt != NULL) {
543*7f2fe78bSCy Schubert             for (i = 0; retval != 0 && idopts->identity_alt[i] != NULL; i++) {
544*7f2fe78bSCy Schubert                 retval = process_option_identity(context, plg_cryptoctx,
545*7f2fe78bSCy Schubert                                                  req_cryptoctx, idopts,
546*7f2fe78bSCy Schubert                                                  id_cryptoctx, princ,
547*7f2fe78bSCy Schubert                                                  idopts->identity_alt[i]);
548*7f2fe78bSCy Schubert             }
549*7f2fe78bSCy Schubert         } else {
550*7f2fe78bSCy Schubert             retval = KRB5_PREAUTH_FAILED;
551*7f2fe78bSCy Schubert             krb5_set_error_message(context, retval,
552*7f2fe78bSCy Schubert                                    _("No user identity options specified"));
553*7f2fe78bSCy Schubert             pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
554*7f2fe78bSCy Schubert             goto errout;
555*7f2fe78bSCy Schubert         }
556*7f2fe78bSCy Schubert     } else {
557*7f2fe78bSCy Schubert         /* We're the anonymous principal. */
558*7f2fe78bSCy Schubert         retval = 0;
559*7f2fe78bSCy Schubert     }
560*7f2fe78bSCy Schubert 
561*7f2fe78bSCy Schubert errout:
562*7f2fe78bSCy Schubert     return retval;
563*7f2fe78bSCy Schubert }
564*7f2fe78bSCy Schubert 
565*7f2fe78bSCy Schubert /*
566*7f2fe78bSCy Schubert  * Load identity information, including that which requires us to ask a
567*7f2fe78bSCy Schubert  * controlling user any questions.  If we have PIN/password values which
568*7f2fe78bSCy Schubert  * correspond to a given identity, use that, otherwise, if one is available,
569*7f2fe78bSCy Schubert  * we'll use the prompter callback.
570*7f2fe78bSCy Schubert  */
571*7f2fe78bSCy Schubert krb5_error_code
pkinit_identity_prompt(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_clpreauth_callbacks cb,krb5_clpreauth_rock rock,int do_matching,krb5_principal princ)572*7f2fe78bSCy Schubert pkinit_identity_prompt(krb5_context context,
573*7f2fe78bSCy Schubert                        pkinit_plg_crypto_context plg_cryptoctx,
574*7f2fe78bSCy Schubert                        pkinit_req_crypto_context req_cryptoctx,
575*7f2fe78bSCy Schubert                        pkinit_identity_opts *idopts,
576*7f2fe78bSCy Schubert                        pkinit_identity_crypto_context id_cryptoctx,
577*7f2fe78bSCy Schubert                        krb5_clpreauth_callbacks cb,
578*7f2fe78bSCy Schubert                        krb5_clpreauth_rock rock,
579*7f2fe78bSCy Schubert                        int do_matching,
580*7f2fe78bSCy Schubert                        krb5_principal princ)
581*7f2fe78bSCy Schubert {
582*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
583*7f2fe78bSCy Schubert     const char *signer_identity;
584*7f2fe78bSCy Schubert     krb5_boolean valid;
585*7f2fe78bSCy Schubert     int i;
586*7f2fe78bSCy Schubert 
587*7f2fe78bSCy Schubert     pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
588*7f2fe78bSCy Schubert     if (!(princ &&
589*7f2fe78bSCy Schubert           krb5_principal_compare_any_realm(context, princ,
590*7f2fe78bSCy Schubert                                            krb5_anonymous_principal()))) {
591*7f2fe78bSCy Schubert         retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
592*7f2fe78bSCy Schubert                                    idopts, id_cryptoctx, princ, FALSE);
593*7f2fe78bSCy Schubert         if (retval)
594*7f2fe78bSCy Schubert             goto errout;
595*7f2fe78bSCy Schubert 
596*7f2fe78bSCy Schubert         if (do_matching) {
597*7f2fe78bSCy Schubert             /*
598*7f2fe78bSCy Schubert              * Try to select exactly one certificate based on matching
599*7f2fe78bSCy Schubert              * criteria.  Typical used for clients.
600*7f2fe78bSCy Schubert              */
601*7f2fe78bSCy Schubert             retval = pkinit_cert_matching(context, plg_cryptoctx,
602*7f2fe78bSCy Schubert                                           req_cryptoctx, id_cryptoctx, princ);
603*7f2fe78bSCy Schubert             if (retval) {
604*7f2fe78bSCy Schubert                 crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
605*7f2fe78bSCy Schubert                                       id_cryptoctx);
606*7f2fe78bSCy Schubert                 goto errout;
607*7f2fe78bSCy Schubert             }
608*7f2fe78bSCy Schubert         } else {
609*7f2fe78bSCy Schubert             /*
610*7f2fe78bSCy Schubert              * Tell crypto code to use the "default" identity.  Typically used
611*7f2fe78bSCy Schubert              * for KDCs.
612*7f2fe78bSCy Schubert              */
613*7f2fe78bSCy Schubert             retval = crypto_cert_select_default(context, plg_cryptoctx,
614*7f2fe78bSCy Schubert                                                 req_cryptoctx, id_cryptoctx);
615*7f2fe78bSCy Schubert             if (retval) {
616*7f2fe78bSCy Schubert                 crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
617*7f2fe78bSCy Schubert                                       id_cryptoctx);
618*7f2fe78bSCy Schubert                 goto errout;
619*7f2fe78bSCy Schubert             }
620*7f2fe78bSCy Schubert         }
621*7f2fe78bSCy Schubert 
622*7f2fe78bSCy Schubert         if (rock != NULL && cb != NULL && retval == 0) {
623*7f2fe78bSCy Schubert             /* Save the signer identity if we're the client. */
624*7f2fe78bSCy Schubert             if (crypto_retrieve_signer_identity(context, id_cryptoctx,
625*7f2fe78bSCy Schubert                                                 &signer_identity) == 0) {
626*7f2fe78bSCy Schubert                 cb->set_cc_config(context, rock, "X509_user_identity",
627*7f2fe78bSCy Schubert                                   signer_identity);
628*7f2fe78bSCy Schubert             }
629*7f2fe78bSCy Schubert         }
630*7f2fe78bSCy Schubert 
631*7f2fe78bSCy Schubert         retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
632*7f2fe78bSCy Schubert                                        id_cryptoctx);
633*7f2fe78bSCy Schubert         if (retval)
634*7f2fe78bSCy Schubert             goto errout;
635*7f2fe78bSCy Schubert     } /* Not anonymous principal */
636*7f2fe78bSCy Schubert 
637*7f2fe78bSCy Schubert     /* Require at least one successful anchor if any are specified. */
638*7f2fe78bSCy Schubert     valid = FALSE;
639*7f2fe78bSCy Schubert     for (i = 0; idopts->anchors != NULL && idopts->anchors[i] != NULL; i++) {
640*7f2fe78bSCy Schubert         retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
641*7f2fe78bSCy Schubert                                        idopts, id_cryptoctx,
642*7f2fe78bSCy Schubert                                        idopts->anchors[i], CATYPE_ANCHORS);
643*7f2fe78bSCy Schubert         if (!retval)
644*7f2fe78bSCy Schubert             valid = TRUE;
645*7f2fe78bSCy Schubert     }
646*7f2fe78bSCy Schubert     if (retval && !valid)
647*7f2fe78bSCy Schubert         goto errout;
648*7f2fe78bSCy Schubert     krb5_clear_error_message(context);
649*7f2fe78bSCy Schubert     retval = 0;
650*7f2fe78bSCy Schubert 
651*7f2fe78bSCy Schubert     /* Require at least one successful intermediate if any are specified. */
652*7f2fe78bSCy Schubert     valid = FALSE;
653*7f2fe78bSCy Schubert     for (i = 0; idopts->intermediates != NULL
654*7f2fe78bSCy Schubert              && idopts->intermediates[i] != NULL; i++) {
655*7f2fe78bSCy Schubert         retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
656*7f2fe78bSCy Schubert                                        idopts, id_cryptoctx,
657*7f2fe78bSCy Schubert                                        idopts->intermediates[i],
658*7f2fe78bSCy Schubert                                        CATYPE_INTERMEDIATES);
659*7f2fe78bSCy Schubert         if (!retval)
660*7f2fe78bSCy Schubert             valid = TRUE;
661*7f2fe78bSCy Schubert     }
662*7f2fe78bSCy Schubert     if (retval && !valid)
663*7f2fe78bSCy Schubert         goto errout;
664*7f2fe78bSCy Schubert     krb5_clear_error_message(context);
665*7f2fe78bSCy Schubert     retval = 0;
666*7f2fe78bSCy Schubert 
667*7f2fe78bSCy Schubert     for (i = 0; idopts->crls != NULL && idopts->crls[i] != NULL; i++) {
668*7f2fe78bSCy Schubert         retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
669*7f2fe78bSCy Schubert                                        idopts, id_cryptoctx, idopts->crls[i],
670*7f2fe78bSCy Schubert                                        CATYPE_CRLS);
671*7f2fe78bSCy Schubert         if (retval)
672*7f2fe78bSCy Schubert             goto errout;
673*7f2fe78bSCy Schubert     }
674*7f2fe78bSCy Schubert 
675*7f2fe78bSCy Schubert errout:
676*7f2fe78bSCy Schubert     return retval;
677*7f2fe78bSCy Schubert }
678*7f2fe78bSCy Schubert 
679*7f2fe78bSCy Schubert /*
680*7f2fe78bSCy Schubert  * Create an entry in the passed-in list for the named identity, optionally
681*7f2fe78bSCy Schubert  * with the specified token flag value and/or supplied password, replacing any
682*7f2fe78bSCy Schubert  * existing entry with the same identity name.
683*7f2fe78bSCy Schubert  */
684*7f2fe78bSCy Schubert krb5_error_code
pkinit_set_deferred_id(pkinit_deferred_id ** identities,const char * identity,unsigned long ck_flags,const char * password)685*7f2fe78bSCy Schubert pkinit_set_deferred_id(pkinit_deferred_id **identities,
686*7f2fe78bSCy Schubert                        const char *identity, unsigned long ck_flags,
687*7f2fe78bSCy Schubert                        const char *password)
688*7f2fe78bSCy Schubert {
689*7f2fe78bSCy Schubert     int i;
690*7f2fe78bSCy Schubert     pkinit_deferred_id *out = NULL, *ids;
691*7f2fe78bSCy Schubert     char *tmp;
692*7f2fe78bSCy Schubert 
693*7f2fe78bSCy Schubert     /* Search for an entry that's already in the list. */
694*7f2fe78bSCy Schubert     ids = *identities;
695*7f2fe78bSCy Schubert     for (i = 0; ids != NULL && ids[i] != NULL; i++) {
696*7f2fe78bSCy Schubert         if (strcmp(ids[i]->identity, identity) == 0) {
697*7f2fe78bSCy Schubert             /* Replace its password value, then we're done. */
698*7f2fe78bSCy Schubert             tmp = password ? strdup(password) : NULL;
699*7f2fe78bSCy Schubert             if (password != NULL && tmp == NULL)
700*7f2fe78bSCy Schubert                 return ENOMEM;
701*7f2fe78bSCy Schubert             ids[i]->ck_flags = ck_flags;
702*7f2fe78bSCy Schubert             free(ids[i]->password);
703*7f2fe78bSCy Schubert             ids[i]->password = tmp;
704*7f2fe78bSCy Schubert             return 0;
705*7f2fe78bSCy Schubert         }
706*7f2fe78bSCy Schubert     }
707*7f2fe78bSCy Schubert 
708*7f2fe78bSCy Schubert     /* Resize the list. */
709*7f2fe78bSCy Schubert     out = realloc(ids, sizeof(*ids) * (i + 2));
710*7f2fe78bSCy Schubert     if (out == NULL)
711*7f2fe78bSCy Schubert         goto oom;
712*7f2fe78bSCy Schubert     *identities = out;
713*7f2fe78bSCy Schubert 
714*7f2fe78bSCy Schubert     /* Allocate the new final entry. */
715*7f2fe78bSCy Schubert     out[i] = malloc(sizeof(*(out[i])));
716*7f2fe78bSCy Schubert     if (out[i] == NULL)
717*7f2fe78bSCy Schubert         goto oom;
718*7f2fe78bSCy Schubert 
719*7f2fe78bSCy Schubert     /* Populate the new entry. */
720*7f2fe78bSCy Schubert     out[i]->magic = PKINIT_DEFERRED_ID_MAGIC;
721*7f2fe78bSCy Schubert     out[i]->identity = strdup(identity);
722*7f2fe78bSCy Schubert     if (out[i]->identity == NULL)
723*7f2fe78bSCy Schubert         goto oom;
724*7f2fe78bSCy Schubert 
725*7f2fe78bSCy Schubert     out[i]->ck_flags = ck_flags;
726*7f2fe78bSCy Schubert     out[i]->password = password ? strdup(password) : NULL;
727*7f2fe78bSCy Schubert     if (password != NULL && out[i]->password == NULL)
728*7f2fe78bSCy Schubert         goto oom;
729*7f2fe78bSCy Schubert 
730*7f2fe78bSCy Schubert     /* Terminate the list. */
731*7f2fe78bSCy Schubert     out[i + 1] = NULL;
732*7f2fe78bSCy Schubert     return 0;
733*7f2fe78bSCy Schubert 
734*7f2fe78bSCy Schubert oom:
735*7f2fe78bSCy Schubert     if (out != NULL && out[i] != NULL) {
736*7f2fe78bSCy Schubert         free(out[i]->identity);
737*7f2fe78bSCy Schubert         free(out[i]);
738*7f2fe78bSCy Schubert         out[i] = NULL;
739*7f2fe78bSCy Schubert     }
740*7f2fe78bSCy Schubert     return ENOMEM;
741*7f2fe78bSCy Schubert }
742*7f2fe78bSCy Schubert 
743*7f2fe78bSCy Schubert /*
744*7f2fe78bSCy Schubert  * Return a password which we've associated with the named identity, if we've
745*7f2fe78bSCy Schubert  * stored one.  Otherwise return NULL.
746*7f2fe78bSCy Schubert  */
747*7f2fe78bSCy Schubert const char *
pkinit_find_deferred_id(pkinit_deferred_id * identities,const char * identity)748*7f2fe78bSCy Schubert pkinit_find_deferred_id(pkinit_deferred_id *identities,
749*7f2fe78bSCy Schubert                         const char *identity)
750*7f2fe78bSCy Schubert {
751*7f2fe78bSCy Schubert     int i;
752*7f2fe78bSCy Schubert 
753*7f2fe78bSCy Schubert     for (i = 0; identities != NULL && identities[i] != NULL; i++) {
754*7f2fe78bSCy Schubert         if (strcmp(identities[i]->identity, identity) == 0)
755*7f2fe78bSCy Schubert             return identities[i]->password;
756*7f2fe78bSCy Schubert     }
757*7f2fe78bSCy Schubert     return NULL;
758*7f2fe78bSCy Schubert }
759*7f2fe78bSCy Schubert 
760*7f2fe78bSCy Schubert /*
761*7f2fe78bSCy Schubert  * Return the flags associated with the specified identity, or 0 if we don't
762*7f2fe78bSCy Schubert  * have such an identity.
763*7f2fe78bSCy Schubert  */
764*7f2fe78bSCy Schubert unsigned long
pkinit_get_deferred_id_flags(pkinit_deferred_id * identities,const char * identity)765*7f2fe78bSCy Schubert pkinit_get_deferred_id_flags(pkinit_deferred_id *identities,
766*7f2fe78bSCy Schubert                              const char *identity)
767*7f2fe78bSCy Schubert {
768*7f2fe78bSCy Schubert     int i;
769*7f2fe78bSCy Schubert 
770*7f2fe78bSCy Schubert     for (i = 0; identities != NULL && identities[i] != NULL; i++) {
771*7f2fe78bSCy Schubert         if (strcmp(identities[i]->identity, identity) == 0)
772*7f2fe78bSCy Schubert             return identities[i]->ck_flags;
773*7f2fe78bSCy Schubert     }
774*7f2fe78bSCy Schubert     return 0;
775*7f2fe78bSCy Schubert }
776*7f2fe78bSCy Schubert 
777*7f2fe78bSCy Schubert /*
778*7f2fe78bSCy Schubert  * Free a deferred_id list.
779*7f2fe78bSCy Schubert  */
780*7f2fe78bSCy Schubert void
pkinit_free_deferred_ids(pkinit_deferred_id * identities)781*7f2fe78bSCy Schubert pkinit_free_deferred_ids(pkinit_deferred_id *identities)
782*7f2fe78bSCy Schubert {
783*7f2fe78bSCy Schubert     int i;
784*7f2fe78bSCy Schubert 
785*7f2fe78bSCy Schubert     for (i = 0; identities != NULL && identities[i] != NULL; i++) {
786*7f2fe78bSCy Schubert         free(identities[i]->identity);
787*7f2fe78bSCy Schubert         free(identities[i]->password);
788*7f2fe78bSCy Schubert         free(identities[i]);
789*7f2fe78bSCy Schubert     }
790*7f2fe78bSCy Schubert     free(identities);
791*7f2fe78bSCy Schubert }
792