1159d09a2SMark Phalan /*
2159d09a2SMark Phalan  * COPYRIGHT (C) 2007
3159d09a2SMark Phalan  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
4159d09a2SMark Phalan  * ALL RIGHTS RESERVED
5159d09a2SMark Phalan  *
6159d09a2SMark Phalan  * Permission is granted to use, copy, create derivative works
7159d09a2SMark Phalan  * and redistribute this software and such derivative works
8159d09a2SMark Phalan  * for any purpose, so long as the name of The University of
9159d09a2SMark Phalan  * Michigan is not used in any advertising or publicity
10159d09a2SMark Phalan  * pertaining to the use of distribution of this software
11159d09a2SMark Phalan  * without specific, written prior authorization.  If the
12159d09a2SMark Phalan  * above copyright notice or any other identification of the
13159d09a2SMark Phalan  * University of Michigan is included in any copy of any
14159d09a2SMark Phalan  * portion of this software, then the disclaimer below must
15159d09a2SMark Phalan  * also be included.
16159d09a2SMark Phalan  *
17159d09a2SMark Phalan  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18159d09a2SMark Phalan  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19159d09a2SMark Phalan  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20159d09a2SMark Phalan  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21159d09a2SMark Phalan  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22159d09a2SMark Phalan  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23159d09a2SMark Phalan  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24159d09a2SMark Phalan  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25159d09a2SMark Phalan  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26159d09a2SMark Phalan  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27159d09a2SMark Phalan  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
28159d09a2SMark Phalan  * SUCH DAMAGES.
29159d09a2SMark Phalan  */
30159d09a2SMark Phalan 
31488060a6SWill Fiveash /*
32488060a6SWill Fiveash  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
33488060a6SWill Fiveash  */
34488060a6SWill Fiveash 
35159d09a2SMark Phalan #include <errno.h>
36159d09a2SMark Phalan #include <string.h>
37159d09a2SMark Phalan #include <stdio.h>
38159d09a2SMark Phalan #include <stdlib.h>
39159d09a2SMark Phalan #include <dlfcn.h>
40159d09a2SMark Phalan #include <unistd.h>
41159d09a2SMark Phalan #include <dirent.h>
42159d09a2SMark Phalan 
43159d09a2SMark Phalan #include <libintl.h>
44159d09a2SMark Phalan 
45159d09a2SMark Phalan #include "pkinit.h"
46159d09a2SMark Phalan 
47159d09a2SMark Phalan static void
free_list(char ** list)48159d09a2SMark Phalan free_list(char **list)
49159d09a2SMark Phalan {
50159d09a2SMark Phalan     int i;
51159d09a2SMark Phalan 
52159d09a2SMark Phalan     if (list == NULL)
53159d09a2SMark Phalan 	return;
54159d09a2SMark Phalan 
55159d09a2SMark Phalan     for (i = 0; list[i] != NULL; i++)
56159d09a2SMark Phalan 	free(list[i]);
57159d09a2SMark Phalan      free(list);
58159d09a2SMark Phalan }
59159d09a2SMark Phalan 
60159d09a2SMark Phalan static krb5_error_code
copy_list(char *** dst,char ** src)61159d09a2SMark Phalan copy_list(char ***dst, char **src)
62159d09a2SMark Phalan {
63159d09a2SMark Phalan     int i;
64159d09a2SMark Phalan     char **newlist;
65159d09a2SMark Phalan 
66159d09a2SMark Phalan     if (dst == NULL)
67159d09a2SMark Phalan 	return EINVAL;
68159d09a2SMark Phalan     *dst = NULL;
69159d09a2SMark Phalan 
70159d09a2SMark Phalan     if (src == NULL)
71159d09a2SMark Phalan 	return 0;
72159d09a2SMark Phalan 
73159d09a2SMark Phalan     for (i = 0; src[i] != NULL; i++);
74159d09a2SMark Phalan 
75159d09a2SMark Phalan     newlist = calloc(1, (i + 1) * sizeof(*newlist));
76159d09a2SMark Phalan     if (newlist == NULL)
77159d09a2SMark Phalan 	return ENOMEM;
78159d09a2SMark Phalan 
79159d09a2SMark Phalan     for (i = 0; src[i] != NULL; i++) {
80159d09a2SMark Phalan 	newlist[i] = strdup(src[i]);
81159d09a2SMark Phalan 	if (newlist[i] == NULL)
82159d09a2SMark Phalan 	    goto cleanup;
83159d09a2SMark Phalan     }
84159d09a2SMark Phalan     newlist[i] = NULL;
85159d09a2SMark Phalan     *dst = newlist;
86159d09a2SMark Phalan     return 0;
87159d09a2SMark Phalan cleanup:
88159d09a2SMark Phalan     free_list(newlist);
89159d09a2SMark Phalan     return ENOMEM;
90159d09a2SMark Phalan }
91159d09a2SMark Phalan 
92159d09a2SMark Phalan char *
idtype2string(int idtype)93159d09a2SMark Phalan idtype2string(int idtype)
94159d09a2SMark Phalan {
95159d09a2SMark Phalan /* Solaris Kerberos: Removed "break"s (lint) */
96159d09a2SMark Phalan     switch(idtype) {
97159d09a2SMark Phalan     case IDTYPE_FILE: return "FILE";
98159d09a2SMark Phalan     case IDTYPE_DIR: return "DIR";
99159d09a2SMark Phalan     case IDTYPE_PKCS11: return "PKCS11";
100159d09a2SMark Phalan     case IDTYPE_PKCS12: return "PKCS12";
101159d09a2SMark Phalan     case IDTYPE_ENVVAR: return "ENV";
102159d09a2SMark Phalan     default: return "INVALID";
103159d09a2SMark Phalan     }
104159d09a2SMark Phalan }
105159d09a2SMark Phalan 
106159d09a2SMark Phalan char *
catype2string(int catype)107159d09a2SMark Phalan catype2string(int catype)
108159d09a2SMark Phalan {
109159d09a2SMark Phalan /* Solaris Kerberos: Removed "break"s (lint) */
110159d09a2SMark Phalan     switch(catype) {
111159d09a2SMark Phalan     case CATYPE_ANCHORS: return "ANCHORS";
112159d09a2SMark Phalan     case CATYPE_INTERMEDIATES: return "INTERMEDIATES";
113159d09a2SMark Phalan     case CATYPE_CRLS: return "CRLS";
114159d09a2SMark Phalan     default: return "INVALID";
115159d09a2SMark Phalan     }
116159d09a2SMark Phalan }
117159d09a2SMark Phalan 
118159d09a2SMark Phalan krb5_error_code
pkinit_init_identity_opts(pkinit_identity_opts ** idopts)119159d09a2SMark Phalan pkinit_init_identity_opts(pkinit_identity_opts **idopts)
120159d09a2SMark Phalan {
121159d09a2SMark Phalan     pkinit_identity_opts *opts = NULL;
122159d09a2SMark Phalan 
123159d09a2SMark Phalan     *idopts = NULL;
124159d09a2SMark Phalan     opts = (pkinit_identity_opts *) calloc(1, sizeof(pkinit_identity_opts));
125159d09a2SMark Phalan     if (opts == NULL)
126159d09a2SMark Phalan 	return ENOMEM;
127159d09a2SMark Phalan 
128159d09a2SMark Phalan     opts->identity = NULL;
129159d09a2SMark Phalan     opts->anchors = NULL;
130159d09a2SMark Phalan     opts->intermediates = NULL;
131159d09a2SMark Phalan     opts->crls = NULL;
132159d09a2SMark Phalan     opts->ocsp = NULL;
133159d09a2SMark Phalan     opts->dn_mapping_file = NULL;
134159d09a2SMark Phalan 
135159d09a2SMark Phalan     opts->cert_filename = NULL;
136159d09a2SMark Phalan     opts->key_filename = NULL;
137159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
138159d09a2SMark Phalan     opts->p11_module_name = NULL;
139159d09a2SMark Phalan     opts->slotid = PK_NOSLOT;
140159d09a2SMark Phalan     opts->token_label = NULL;
141159d09a2SMark Phalan     opts->cert_id_string = NULL;
142159d09a2SMark Phalan     opts->cert_label = NULL;
143488060a6SWill Fiveash     opts->PIN = NULL;
144159d09a2SMark Phalan #endif
145159d09a2SMark Phalan 
146159d09a2SMark Phalan     *idopts = opts;
147159d09a2SMark Phalan 
148159d09a2SMark Phalan     return 0;
149159d09a2SMark Phalan }
150159d09a2SMark Phalan 
151159d09a2SMark Phalan krb5_error_code
pkinit_dup_identity_opts(pkinit_identity_opts * src_opts,pkinit_identity_opts ** dest_opts)152159d09a2SMark Phalan pkinit_dup_identity_opts(pkinit_identity_opts *src_opts,
153159d09a2SMark Phalan 			 pkinit_identity_opts **dest_opts)
154159d09a2SMark Phalan {
155159d09a2SMark Phalan     pkinit_identity_opts *newopts;
156159d09a2SMark Phalan     krb5_error_code retval;
157159d09a2SMark Phalan 
158159d09a2SMark Phalan     *dest_opts = NULL;
159159d09a2SMark Phalan     retval = pkinit_init_identity_opts(&newopts);
160159d09a2SMark Phalan     if (retval)
161159d09a2SMark Phalan 	return retval;
162159d09a2SMark Phalan 
163159d09a2SMark Phalan     retval = ENOMEM;
164159d09a2SMark Phalan 
165159d09a2SMark Phalan     if (src_opts->identity != NULL) {
166159d09a2SMark Phalan 	newopts->identity = strdup(src_opts->identity);
167159d09a2SMark Phalan 	if (newopts->identity == NULL)
168159d09a2SMark Phalan 	    goto cleanup;
169159d09a2SMark Phalan     }
170159d09a2SMark Phalan 
171159d09a2SMark Phalan     retval = copy_list(&newopts->anchors, src_opts->anchors);
172159d09a2SMark Phalan     if (retval)
173159d09a2SMark Phalan 	goto cleanup;
174159d09a2SMark Phalan 
175159d09a2SMark Phalan     retval = copy_list(&newopts->intermediates,src_opts->intermediates);
176159d09a2SMark Phalan     if (retval)
177159d09a2SMark Phalan 	goto cleanup;
178159d09a2SMark Phalan 
179159d09a2SMark Phalan     retval = copy_list(&newopts->crls, src_opts->crls);
180159d09a2SMark Phalan     if (retval)
181159d09a2SMark Phalan 	goto cleanup;
182159d09a2SMark Phalan 
183159d09a2SMark Phalan     if (src_opts->ocsp != NULL) {
184159d09a2SMark Phalan 	newopts->ocsp = strdup(src_opts->ocsp);
185159d09a2SMark Phalan 	if (newopts->ocsp == NULL)
186159d09a2SMark Phalan 	    goto cleanup;
187159d09a2SMark Phalan     }
188159d09a2SMark Phalan 
189159d09a2SMark Phalan     if (src_opts->cert_filename != NULL) {
190159d09a2SMark Phalan 	newopts->cert_filename = strdup(src_opts->cert_filename);
191159d09a2SMark Phalan 	if (newopts->cert_filename == NULL)
192159d09a2SMark Phalan 	    goto cleanup;
193159d09a2SMark Phalan     }
194159d09a2SMark Phalan 
195159d09a2SMark Phalan     if (src_opts->key_filename != NULL) {
196159d09a2SMark Phalan 	newopts->key_filename = strdup(src_opts->key_filename);
197159d09a2SMark Phalan 	if (newopts->key_filename == NULL)
198159d09a2SMark Phalan 	    goto cleanup;
199159d09a2SMark Phalan     }
200159d09a2SMark Phalan 
201159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
202159d09a2SMark Phalan     if (src_opts->p11_module_name != NULL) {
203159d09a2SMark Phalan 	newopts->p11_module_name = strdup(src_opts->p11_module_name);
204159d09a2SMark Phalan 	if (newopts->p11_module_name == NULL)
205159d09a2SMark Phalan 	    goto cleanup;
206159d09a2SMark Phalan     }
207159d09a2SMark Phalan 
208159d09a2SMark Phalan     newopts->slotid = src_opts->slotid;
209159d09a2SMark Phalan 
210159d09a2SMark Phalan     if (src_opts->token_label != NULL) {
211159d09a2SMark Phalan 	newopts->token_label = strdup(src_opts->token_label);
212159d09a2SMark Phalan 	if (newopts->token_label == NULL)
213159d09a2SMark Phalan 	    goto cleanup;
214159d09a2SMark Phalan     }
215159d09a2SMark Phalan 
216159d09a2SMark Phalan     if (src_opts->cert_id_string != NULL) {
217159d09a2SMark Phalan 	newopts->cert_id_string = strdup(src_opts->cert_id_string);
218159d09a2SMark Phalan 	if (newopts->cert_id_string == NULL)
219159d09a2SMark Phalan 	    goto cleanup;
220159d09a2SMark Phalan     }
221159d09a2SMark Phalan 
222159d09a2SMark Phalan     if (src_opts->cert_label != NULL) {
223159d09a2SMark Phalan 	newopts->cert_label = strdup(src_opts->cert_label);
224159d09a2SMark Phalan 	if (newopts->cert_label == NULL)
225159d09a2SMark Phalan 	    goto cleanup;
226159d09a2SMark Phalan     }
227488060a6SWill Fiveash     if (src_opts->PIN != NULL) {
228488060a6SWill Fiveash 	newopts->PIN = strdup(src_opts->PIN);
229488060a6SWill Fiveash 	if (newopts->PIN == NULL)
230488060a6SWill Fiveash 	    goto cleanup;
231488060a6SWill Fiveash     }
232159d09a2SMark Phalan #endif
233159d09a2SMark Phalan 
234159d09a2SMark Phalan 
235159d09a2SMark Phalan     *dest_opts = newopts;
236159d09a2SMark Phalan     return 0;
237159d09a2SMark Phalan cleanup:
238159d09a2SMark Phalan     pkinit_fini_identity_opts(newopts);
239159d09a2SMark Phalan     return retval;
240159d09a2SMark Phalan }
241159d09a2SMark Phalan 
242159d09a2SMark Phalan void
pkinit_fini_identity_opts(pkinit_identity_opts * idopts)243159d09a2SMark Phalan pkinit_fini_identity_opts(pkinit_identity_opts *idopts)
244159d09a2SMark Phalan {
245159d09a2SMark Phalan     if (idopts == NULL)
246159d09a2SMark Phalan 	return;
247159d09a2SMark Phalan 
248159d09a2SMark Phalan     if (idopts->identity != NULL)
249159d09a2SMark Phalan 	free(idopts->identity);
250159d09a2SMark Phalan     free_list(idopts->anchors);
251159d09a2SMark Phalan     free_list(idopts->intermediates);
252159d09a2SMark Phalan     free_list(idopts->crls);
253159d09a2SMark Phalan     free_list(idopts->identity_alt);
254159d09a2SMark Phalan 
255159d09a2SMark Phalan     if (idopts->cert_filename != NULL)
256159d09a2SMark Phalan 	free(idopts->cert_filename);
257159d09a2SMark Phalan     if (idopts->key_filename != NULL)
258159d09a2SMark Phalan 	free(idopts->key_filename);
259159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
260159d09a2SMark Phalan     if (idopts->p11_module_name != NULL)
261159d09a2SMark Phalan 	free(idopts->p11_module_name);
262159d09a2SMark Phalan     if (idopts->token_label != NULL)
263159d09a2SMark Phalan 	free(idopts->token_label);
264159d09a2SMark Phalan     if (idopts->cert_id_string != NULL)
265159d09a2SMark Phalan 	free(idopts->cert_id_string);
266159d09a2SMark Phalan     if (idopts->cert_label != NULL)
267159d09a2SMark Phalan 	free(idopts->cert_label);
268488060a6SWill Fiveash     if (idopts->PIN != NULL) {
269488060a6SWill Fiveash 	(void) memset(idopts->PIN, 0, strlen(idopts->PIN));
270488060a6SWill Fiveash 	free(idopts->PIN);
271488060a6SWill Fiveash     }
272159d09a2SMark Phalan #endif
273159d09a2SMark Phalan     free(idopts);
274159d09a2SMark Phalan }
275159d09a2SMark Phalan 
276159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
277159d09a2SMark Phalan /* ARGSUSED */
278159d09a2SMark Phalan static krb5_error_code
parse_pkcs11_options(krb5_context context,pkinit_identity_opts * idopts,const char * residual)279159d09a2SMark Phalan parse_pkcs11_options(krb5_context context,
280159d09a2SMark Phalan 		     pkinit_identity_opts *idopts,
281159d09a2SMark Phalan 		     const char *residual)
282159d09a2SMark Phalan {
283159d09a2SMark Phalan     char *s, *cp, *vp;
284159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
285159d09a2SMark Phalan 
286159d09a2SMark Phalan     if (residual == NULL || residual[0] == '\0')
287159d09a2SMark Phalan 	return 0;
288159d09a2SMark Phalan 
289159d09a2SMark Phalan     /* Split string into attr=value substrings */
290159d09a2SMark Phalan     s = strdup(residual);
291159d09a2SMark Phalan     if (s == NULL)
292159d09a2SMark Phalan 	return retval;
293159d09a2SMark Phalan 
294159d09a2SMark Phalan     for ((cp = strtok(s, ":")); cp; (cp = strtok(NULL, ":"))) {
295159d09a2SMark Phalan 	vp = strchr(cp, '=');
296159d09a2SMark Phalan 
297159d09a2SMark Phalan 	/* If there is no "=", this is a pkcs11 module name */
298159d09a2SMark Phalan 	if (vp == NULL) {
299159d09a2SMark Phalan 	    if (idopts->p11_module_name != NULL)
300159d09a2SMark Phalan 		free(idopts->p11_module_name);
301159d09a2SMark Phalan 	    idopts->p11_module_name = strdup(cp);
302159d09a2SMark Phalan 	    if (idopts->p11_module_name == NULL)
303159d09a2SMark Phalan 		goto cleanup;
304159d09a2SMark Phalan 	    continue;
305159d09a2SMark Phalan 	}
306159d09a2SMark Phalan 	*vp++ = '\0';
307159d09a2SMark Phalan 	if (!strcmp(cp, "module_name")) {
308159d09a2SMark Phalan 	    if (idopts->p11_module_name != NULL)
309159d09a2SMark Phalan 		free(idopts->p11_module_name);
310159d09a2SMark Phalan 	    idopts->p11_module_name = strdup(vp);
311159d09a2SMark Phalan 	    if (idopts->p11_module_name == NULL)
312159d09a2SMark Phalan 		goto cleanup;
313159d09a2SMark Phalan 	} else if (!strcmp(cp, "slotid")) {
314159d09a2SMark Phalan 	    long slotid = strtol(vp, NULL, 10);
315159d09a2SMark Phalan 	    if ((slotid == LONG_MIN || slotid == LONG_MAX) && errno != 0) {
316159d09a2SMark Phalan 		retval = EINVAL;
317159d09a2SMark Phalan 		goto cleanup;
318159d09a2SMark Phalan 	    }
319159d09a2SMark Phalan 	    if ((long) (int) slotid != slotid) {
320159d09a2SMark Phalan 		retval = EINVAL;
321159d09a2SMark Phalan 		goto cleanup;
322159d09a2SMark Phalan 	    }
323159d09a2SMark Phalan 	    idopts->slotid = slotid;
324159d09a2SMark Phalan 	} else if (!strcmp(cp, "token")) {
325159d09a2SMark Phalan 	    if (idopts->token_label != NULL)
326159d09a2SMark Phalan 		free(idopts->token_label);
327159d09a2SMark Phalan 	    idopts->token_label = strdup(vp);
328159d09a2SMark Phalan 	    if (idopts->token_label == NULL)
329159d09a2SMark Phalan 		goto cleanup;
330159d09a2SMark Phalan 	} else if (!strcmp(cp, "certid")) {
331159d09a2SMark Phalan 	    if (idopts->cert_id_string != NULL)
332159d09a2SMark Phalan 		free(idopts->cert_id_string);
333159d09a2SMark Phalan 	    idopts->cert_id_string = strdup(vp);
334159d09a2SMark Phalan 	    if (idopts->cert_id_string == NULL)
335159d09a2SMark Phalan 		goto cleanup;
336159d09a2SMark Phalan 	} else if (!strcmp(cp, "certlabel")) {
337159d09a2SMark Phalan 	    if (idopts->cert_label != NULL)
338159d09a2SMark Phalan 		free(idopts->cert_label);
339159d09a2SMark Phalan 	    idopts->cert_label = strdup(vp);
340159d09a2SMark Phalan 	    if (idopts->cert_label == NULL)
341159d09a2SMark Phalan 		goto cleanup;
342159d09a2SMark Phalan 	}
343159d09a2SMark Phalan     }
344159d09a2SMark Phalan     retval = 0;
345159d09a2SMark Phalan cleanup:
346159d09a2SMark Phalan     free(s);
347159d09a2SMark Phalan     return retval;
348159d09a2SMark Phalan }
349159d09a2SMark Phalan #endif
350159d09a2SMark Phalan 
351159d09a2SMark Phalan /* ARGSUSED */
352159d09a2SMark Phalan static krb5_error_code
parse_fs_options(krb5_context context,pkinit_identity_opts * idopts,const char * residual)353159d09a2SMark Phalan parse_fs_options(krb5_context context,
354159d09a2SMark Phalan 		 pkinit_identity_opts *idopts,
355159d09a2SMark Phalan 		 const char *residual)
356159d09a2SMark Phalan {
357159d09a2SMark Phalan     char *certname, *keyname;
358159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
359159d09a2SMark Phalan 
360159d09a2SMark Phalan     if (residual == NULL || residual[0] == '\0')
361159d09a2SMark Phalan 	return 0;
362159d09a2SMark Phalan 
363159d09a2SMark Phalan     certname = strdup(residual);
364159d09a2SMark Phalan     if (certname == NULL)
365159d09a2SMark Phalan 	goto cleanup;
366159d09a2SMark Phalan 
367159d09a2SMark Phalan     certname = strtok(certname, ",");
368159d09a2SMark Phalan     keyname = strtok(NULL, ",");
369159d09a2SMark Phalan 
370159d09a2SMark Phalan     idopts->cert_filename = strdup(certname);
371159d09a2SMark Phalan     if (idopts->cert_filename == NULL)
372159d09a2SMark Phalan 	goto cleanup;
373159d09a2SMark Phalan 
374159d09a2SMark Phalan     idopts->key_filename = strdup(keyname ? keyname : certname);
375159d09a2SMark Phalan     if (idopts->key_filename == NULL)
376159d09a2SMark Phalan 	goto cleanup;
377159d09a2SMark Phalan 
378159d09a2SMark Phalan     retval = 0;
379159d09a2SMark Phalan cleanup:
380159d09a2SMark Phalan     if (certname != NULL)
381159d09a2SMark Phalan 	free(certname);
382159d09a2SMark Phalan     return retval;
383159d09a2SMark Phalan }
384159d09a2SMark Phalan 
385159d09a2SMark Phalan /* ARGSUSED */
386159d09a2SMark Phalan static krb5_error_code
parse_pkcs12_options(krb5_context context,pkinit_identity_opts * idopts,const char * residual)387159d09a2SMark Phalan parse_pkcs12_options(krb5_context context,
388159d09a2SMark Phalan 		     pkinit_identity_opts *idopts,
389159d09a2SMark Phalan 		     const char *residual)
390159d09a2SMark Phalan {
391159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
392159d09a2SMark Phalan 
393159d09a2SMark Phalan     if (residual == NULL || residual[0] == '\0')
394159d09a2SMark Phalan 	return 0;
395159d09a2SMark Phalan 
396159d09a2SMark Phalan     idopts->cert_filename = strdup(residual);
397159d09a2SMark Phalan     if (idopts->cert_filename == NULL)
398159d09a2SMark Phalan 	goto cleanup;
399159d09a2SMark Phalan 
400159d09a2SMark Phalan     idopts->key_filename = strdup(residual);
401159d09a2SMark Phalan     if (idopts->key_filename == NULL)
402159d09a2SMark Phalan 	goto cleanup;
403159d09a2SMark Phalan 
404159d09a2SMark Phalan     pkiDebug("%s: cert_filename '%s' key_filename '%s'\n",
405159d09a2SMark Phalan 	     __FUNCTION__, idopts->cert_filename,
406159d09a2SMark Phalan 	     idopts->key_filename);
407159d09a2SMark Phalan     retval = 0;
408159d09a2SMark Phalan cleanup:
409159d09a2SMark Phalan     return retval;
410159d09a2SMark Phalan }
411159d09a2SMark Phalan 
412159d09a2SMark Phalan 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,const char * value)413159d09a2SMark Phalan process_option_identity(krb5_context context,
414159d09a2SMark Phalan 			pkinit_plg_crypto_context plg_cryptoctx,
415159d09a2SMark Phalan 			pkinit_req_crypto_context req_cryptoctx,
416159d09a2SMark Phalan 			pkinit_identity_opts *idopts,
417159d09a2SMark Phalan 			pkinit_identity_crypto_context id_cryptoctx,
418159d09a2SMark Phalan 			const char *value)
419159d09a2SMark Phalan {
420159d09a2SMark Phalan     const char *residual;
421159d09a2SMark Phalan     int idtype;
422159d09a2SMark Phalan     krb5_error_code retval = 0;
423159d09a2SMark Phalan 
424159d09a2SMark Phalan     pkiDebug("%s: processing value '%s'\n",
425159d09a2SMark Phalan 	     __FUNCTION__, value ? value : "NULL");
426159d09a2SMark Phalan     if (value == NULL)
427159d09a2SMark Phalan 	return EINVAL;
428159d09a2SMark Phalan 
429159d09a2SMark Phalan     residual = strchr(value, ':');
430159d09a2SMark Phalan     if (residual != NULL) {
431159d09a2SMark Phalan 	unsigned int typelen;
432159d09a2SMark Phalan 	residual++; /* skip past colon */
433159d09a2SMark Phalan 	typelen = residual - value;
434159d09a2SMark Phalan 	if (strncmp(value, "FILE:", typelen) == 0) {
435159d09a2SMark Phalan 	    idtype = IDTYPE_FILE;
436159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
437159d09a2SMark Phalan 	} else if (strncmp(value, "PKCS11:", typelen) == 0) {
438159d09a2SMark Phalan 	    idtype = IDTYPE_PKCS11;
439159d09a2SMark Phalan #endif
440159d09a2SMark Phalan 	} else if (strncmp(value, "PKCS12:", typelen) == 0) {
441159d09a2SMark Phalan 	    idtype = IDTYPE_PKCS12;
442159d09a2SMark Phalan 	} else if (strncmp(value, "DIR:", typelen) == 0) {
443159d09a2SMark Phalan 	    idtype = IDTYPE_DIR;
444159d09a2SMark Phalan 	} else if (strncmp(value, "ENV:", typelen) == 0) {
445159d09a2SMark Phalan 	    idtype = IDTYPE_ENVVAR;
446159d09a2SMark Phalan 	} else {
447159d09a2SMark Phalan 	    pkiDebug("%s: Unsupported type while processing '%s'\n",
448159d09a2SMark Phalan 		     __FUNCTION__, value);
449159d09a2SMark Phalan 	    krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
450159d09a2SMark Phalan 				   "Unsupported type while processing '%s'\n",
451159d09a2SMark Phalan 				   value);
452159d09a2SMark Phalan 	    return KRB5_PREAUTH_FAILED;
453159d09a2SMark Phalan 	}
454159d09a2SMark Phalan     } else {
455159d09a2SMark Phalan 	idtype = IDTYPE_FILE;
456159d09a2SMark Phalan 	residual = value;
457159d09a2SMark Phalan     }
458159d09a2SMark Phalan 
459159d09a2SMark Phalan     idopts->idtype = idtype;
460159d09a2SMark Phalan     pkiDebug("%s: idtype is %s\n", __FUNCTION__, idtype2string(idopts->idtype));
461159d09a2SMark Phalan     switch (idtype) {
462159d09a2SMark Phalan     case IDTYPE_ENVVAR: {
463159d09a2SMark Phalan 	    /* Solaris Kerberos: Improved error messages */
464159d09a2SMark Phalan 	    char *envvar = getenv(residual);
465159d09a2SMark Phalan 	    if (envvar == NULL) {
466159d09a2SMark Phalan 		    krb5_set_error_message(context, EINVAL,
467159d09a2SMark Phalan 		        gettext("failed to find environmental variable \'%s\'"),
468159d09a2SMark Phalan 		        residual);
469159d09a2SMark Phalan 		    return EINVAL;
470159d09a2SMark Phalan 	    }
471159d09a2SMark Phalan 	    return process_option_identity(context, plg_cryptoctx,
472159d09a2SMark Phalan 				       req_cryptoctx, idopts, id_cryptoctx,
473159d09a2SMark Phalan 				       envvar);
474159d09a2SMark Phalan 	    /* Solaris Kerberos: not reached */
475159d09a2SMark Phalan 	}
476159d09a2SMark Phalan     case IDTYPE_FILE:
477159d09a2SMark Phalan 	retval = parse_fs_options(context, idopts, residual);
478159d09a2SMark Phalan 	break;
479159d09a2SMark Phalan     case IDTYPE_PKCS12:
480159d09a2SMark Phalan 	retval = parse_pkcs12_options(context, idopts, residual);
481159d09a2SMark Phalan 	break;
482159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
483159d09a2SMark Phalan     case IDTYPE_PKCS11:
484159d09a2SMark Phalan 	retval = parse_pkcs11_options(context, idopts, residual);
485159d09a2SMark Phalan 	break;
486159d09a2SMark Phalan #endif
487159d09a2SMark Phalan     case IDTYPE_DIR:
488159d09a2SMark Phalan 	idopts->cert_filename = strdup(residual);
489159d09a2SMark Phalan 	if (idopts->cert_filename == NULL)
490159d09a2SMark Phalan 	    retval = ENOMEM;
491159d09a2SMark Phalan 	break;
492159d09a2SMark Phalan     default:
493159d09a2SMark Phalan 	krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
494159d09a2SMark Phalan 			       "Internal error parsing X509_user_identity\n");
495159d09a2SMark Phalan 	retval = EINVAL;
496159d09a2SMark Phalan 	break;
497159d09a2SMark Phalan     }
498159d09a2SMark Phalan     return retval;
499159d09a2SMark Phalan }
500159d09a2SMark Phalan 
501159d09a2SMark Phalan 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)502159d09a2SMark Phalan process_option_ca_crl(krb5_context context,
503159d09a2SMark Phalan 		      pkinit_plg_crypto_context plg_cryptoctx,
504159d09a2SMark Phalan 		      pkinit_req_crypto_context req_cryptoctx,
505*55fea89dSDan Cross 		      pkinit_identity_opts *idopts,
506159d09a2SMark Phalan 		      pkinit_identity_crypto_context id_cryptoctx,
507159d09a2SMark Phalan 		      const char *value,
508159d09a2SMark Phalan 		      int catype)
509159d09a2SMark Phalan {
510159d09a2SMark Phalan     char *residual;
511159d09a2SMark Phalan     unsigned int typelen;
512159d09a2SMark Phalan     int idtype;
513159d09a2SMark Phalan 
514159d09a2SMark Phalan     pkiDebug("%s: processing catype %s, value '%s'\n",
515159d09a2SMark Phalan 	     __FUNCTION__, catype2string(catype), value);
516159d09a2SMark Phalan     residual = strchr(value, ':');
517159d09a2SMark Phalan     if (residual == NULL) {
518159d09a2SMark Phalan 	pkiDebug("No type given for '%s'\n", value);
519159d09a2SMark Phalan 	return EINVAL;
520159d09a2SMark Phalan     }
521159d09a2SMark Phalan     residual++; /* skip past colon */
522159d09a2SMark Phalan     typelen = residual - value;
523159d09a2SMark Phalan     if (strncmp(value, "FILE:", typelen) == 0) {
524159d09a2SMark Phalan 	idtype = IDTYPE_FILE;
525159d09a2SMark Phalan     } else if (strncmp(value, "DIR:", typelen) == 0) {
526159d09a2SMark Phalan 	idtype = IDTYPE_DIR;
527159d09a2SMark Phalan     } else {
528159d09a2SMark Phalan 	return ENOTSUP;
529159d09a2SMark Phalan     }
530159d09a2SMark Phalan     return crypto_load_cas_and_crls(context,
531159d09a2SMark Phalan 				    plg_cryptoctx,
532159d09a2SMark Phalan 				    req_cryptoctx,
533159d09a2SMark Phalan 				    idopts, id_cryptoctx,
534159d09a2SMark Phalan 				    idtype, catype, residual);
535159d09a2SMark Phalan }
536159d09a2SMark Phalan 
537159d09a2SMark Phalan static krb5_error_code
pkinit_identity_process_option(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,int attr,const char * value)538159d09a2SMark Phalan pkinit_identity_process_option(krb5_context context,
539159d09a2SMark Phalan 			       pkinit_plg_crypto_context plg_cryptoctx,
540159d09a2SMark Phalan 			       pkinit_req_crypto_context req_cryptoctx,
541159d09a2SMark Phalan 			       pkinit_identity_opts *idopts,
542159d09a2SMark Phalan 			       pkinit_identity_crypto_context id_cryptoctx,
543159d09a2SMark Phalan 			       int attr,
544159d09a2SMark Phalan 			       const char *value)
545159d09a2SMark Phalan {
546159d09a2SMark Phalan     krb5_error_code retval = 0;
547159d09a2SMark Phalan 
548159d09a2SMark Phalan     switch (attr) {
549159d09a2SMark Phalan 	case PKINIT_ID_OPT_USER_IDENTITY:
550159d09a2SMark Phalan 	    retval = process_option_identity(context, plg_cryptoctx,
551159d09a2SMark Phalan 					     req_cryptoctx, idopts,
552159d09a2SMark Phalan 					     id_cryptoctx, value);
553159d09a2SMark Phalan 	    break;
554159d09a2SMark Phalan 	case PKINIT_ID_OPT_ANCHOR_CAS:
555159d09a2SMark Phalan 	    retval = process_option_ca_crl(context, plg_cryptoctx,
556159d09a2SMark Phalan 					   req_cryptoctx, idopts,
557159d09a2SMark Phalan 					   id_cryptoctx, value,
558159d09a2SMark Phalan 					   CATYPE_ANCHORS);
559159d09a2SMark Phalan 	    break;
560159d09a2SMark Phalan 	case PKINIT_ID_OPT_INTERMEDIATE_CAS:
561159d09a2SMark Phalan 	    retval = process_option_ca_crl(context, plg_cryptoctx,
562159d09a2SMark Phalan 					   req_cryptoctx, idopts,
563159d09a2SMark Phalan 					   id_cryptoctx,
564159d09a2SMark Phalan 					   value, CATYPE_INTERMEDIATES);
565159d09a2SMark Phalan 	    break;
566159d09a2SMark Phalan 	case PKINIT_ID_OPT_CRLS:
567159d09a2SMark Phalan 	    retval = process_option_ca_crl(context, plg_cryptoctx,
568159d09a2SMark Phalan 					   req_cryptoctx, idopts,
569159d09a2SMark Phalan 					   id_cryptoctx,
570159d09a2SMark Phalan 					   value, CATYPE_CRLS);
571159d09a2SMark Phalan 	    break;
572159d09a2SMark Phalan 	case PKINIT_ID_OPT_OCSP:
573159d09a2SMark Phalan 	    retval = ENOTSUP;
574159d09a2SMark Phalan 	    break;
575159d09a2SMark Phalan 	default:
576159d09a2SMark Phalan 	    retval = EINVAL;
577159d09a2SMark Phalan 	    break;
578159d09a2SMark Phalan     }
579159d09a2SMark Phalan     return retval;
580159d09a2SMark Phalan }
581159d09a2SMark Phalan 
582159d09a2SMark Phalan 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,int do_matching,krb5_principal princ)583159d09a2SMark Phalan pkinit_identity_initialize(krb5_context context,
584159d09a2SMark Phalan 			   pkinit_plg_crypto_context plg_cryptoctx,
585159d09a2SMark Phalan 			   pkinit_req_crypto_context req_cryptoctx,
586159d09a2SMark Phalan 			   pkinit_identity_opts *idopts,
587159d09a2SMark Phalan 			   pkinit_identity_crypto_context id_cryptoctx,
588159d09a2SMark Phalan 			   int do_matching,
589159d09a2SMark Phalan 			   krb5_principal princ)
590159d09a2SMark Phalan {
591159d09a2SMark Phalan     krb5_error_code retval = EINVAL;
592159d09a2SMark Phalan     int i;
593159d09a2SMark Phalan 
594159d09a2SMark Phalan     pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
595159d09a2SMark Phalan     if (idopts == NULL || id_cryptoctx == NULL)
596159d09a2SMark Phalan 	goto errout;
597159d09a2SMark Phalan 
598159d09a2SMark Phalan     /*
599159d09a2SMark Phalan      * If identity was specified, use that.  (For the kdc, this
600159d09a2SMark Phalan      * is specified as pkinit_identity in the kdc.conf.  For users,
601159d09a2SMark Phalan      * this is specified on the command line via X509_user_identity.)
602159d09a2SMark Phalan      * If a user did not specify identity on the command line,
603159d09a2SMark Phalan      * then we will try alternatives which may have been specified
604159d09a2SMark Phalan      * in the config file.
605159d09a2SMark Phalan      */
606159d09a2SMark Phalan     if (idopts->identity != NULL) {
607159d09a2SMark Phalan 	retval = pkinit_identity_process_option(context, plg_cryptoctx,
608159d09a2SMark Phalan 						req_cryptoctx, idopts,
609159d09a2SMark Phalan 						id_cryptoctx,
610159d09a2SMark Phalan 						PKINIT_ID_OPT_USER_IDENTITY,
611159d09a2SMark Phalan 						idopts->identity);
612159d09a2SMark Phalan     } else if (idopts->identity_alt != NULL) {
613159d09a2SMark Phalan 	for (i = 0; retval != 0 && idopts->identity_alt[i] != NULL; i++)
614159d09a2SMark Phalan 		retval = pkinit_identity_process_option(context, plg_cryptoctx,
615159d09a2SMark Phalan 						    req_cryptoctx, idopts,
616159d09a2SMark Phalan 						    id_cryptoctx,
617159d09a2SMark Phalan 						    PKINIT_ID_OPT_USER_IDENTITY,
618159d09a2SMark Phalan 						    idopts->identity_alt[i]);
619159d09a2SMark Phalan     } else {
620159d09a2SMark Phalan 	pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
621159d09a2SMark Phalan 	goto errout;
622159d09a2SMark Phalan     }
623159d09a2SMark Phalan     if (retval)
624159d09a2SMark Phalan 	goto errout;
625159d09a2SMark Phalan 
626159d09a2SMark Phalan     retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
6279e11d51cSWill Fiveash 			       idopts, id_cryptoctx, princ, do_matching);
628159d09a2SMark Phalan     if (retval)
629159d09a2SMark Phalan 	goto errout;
630159d09a2SMark Phalan 
631159d09a2SMark Phalan     if (do_matching) {
632159d09a2SMark Phalan 	retval = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
6339e11d51cSWill Fiveash 				      id_cryptoctx, princ, TRUE);
634159d09a2SMark Phalan 	if (retval) {
635159d09a2SMark Phalan 	    pkiDebug("%s: No matching certificate found\n", __FUNCTION__);
636159d09a2SMark Phalan 	    (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
637159d09a2SMark Phalan 				  id_cryptoctx);
638159d09a2SMark Phalan 	    goto errout;
639159d09a2SMark Phalan 	}
640159d09a2SMark Phalan     } else {
641159d09a2SMark Phalan 	/* Tell crypto code to use the "default" */
642159d09a2SMark Phalan 	retval = crypto_cert_select_default(context, plg_cryptoctx,
643159d09a2SMark Phalan 					    req_cryptoctx, id_cryptoctx);
644159d09a2SMark Phalan 	if (retval) {
645159d09a2SMark Phalan 	    pkiDebug("%s: Failed while selecting default certificate\n",
646159d09a2SMark Phalan 		     __FUNCTION__);
647159d09a2SMark Phalan 	    (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
648159d09a2SMark Phalan 				  id_cryptoctx);
649159d09a2SMark Phalan 	    goto errout;
650159d09a2SMark Phalan 	}
651159d09a2SMark Phalan     }
652*55fea89dSDan Cross 
653159d09a2SMark Phalan     retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
654159d09a2SMark Phalan 				   id_cryptoctx);
655159d09a2SMark Phalan     if (retval)
656159d09a2SMark Phalan 	    goto errout;
657159d09a2SMark Phalan 
658159d09a2SMark Phalan     for (i = 0; idopts->anchors != NULL && idopts->anchors[i] != NULL; i++) {
659159d09a2SMark Phalan 	retval = pkinit_identity_process_option(context, plg_cryptoctx,
660159d09a2SMark Phalan 						req_cryptoctx, idopts,
661159d09a2SMark Phalan 						id_cryptoctx,
662159d09a2SMark Phalan 						PKINIT_ID_OPT_ANCHOR_CAS,
663159d09a2SMark Phalan 						idopts->anchors[i]);
664159d09a2SMark Phalan 	if (retval)
665159d09a2SMark Phalan 	    goto errout;
666159d09a2SMark Phalan     }
667159d09a2SMark Phalan     for (i = 0; idopts->intermediates != NULL
668159d09a2SMark Phalan 		&& idopts->intermediates[i] != NULL; i++) {
669159d09a2SMark Phalan 	retval = pkinit_identity_process_option(context, plg_cryptoctx,
670159d09a2SMark Phalan 						req_cryptoctx, idopts,
671159d09a2SMark Phalan 						id_cryptoctx,
672159d09a2SMark Phalan 						PKINIT_ID_OPT_INTERMEDIATE_CAS,
673159d09a2SMark Phalan 						idopts->intermediates[i]);
674159d09a2SMark Phalan 	if (retval)
675159d09a2SMark Phalan 	    goto errout;
676159d09a2SMark Phalan     }
677159d09a2SMark Phalan     for (i = 0; idopts->crls != NULL && idopts->crls[i] != NULL; i++) {
678159d09a2SMark Phalan 	retval = pkinit_identity_process_option(context, plg_cryptoctx,
679159d09a2SMark Phalan 						req_cryptoctx, idopts,
680159d09a2SMark Phalan 						id_cryptoctx,
681159d09a2SMark Phalan 						PKINIT_ID_OPT_CRLS,
682159d09a2SMark Phalan 						idopts->crls[i]);
683159d09a2SMark Phalan 	if (retval)
684159d09a2SMark Phalan 	    goto errout;
685159d09a2SMark Phalan     }
686159d09a2SMark Phalan     if (idopts->ocsp != NULL) {
687159d09a2SMark Phalan 	retval = pkinit_identity_process_option(context, plg_cryptoctx,
688159d09a2SMark Phalan 						req_cryptoctx, idopts,
689159d09a2SMark Phalan 						id_cryptoctx,
690159d09a2SMark Phalan 						PKINIT_ID_OPT_OCSP,
691159d09a2SMark Phalan 						idopts->ocsp);
692159d09a2SMark Phalan 	if (retval)
693159d09a2SMark Phalan 	    goto errout;
694159d09a2SMark Phalan     }
695159d09a2SMark Phalan 
696159d09a2SMark Phalan errout:
697159d09a2SMark Phalan     return retval;
698159d09a2SMark Phalan }
699159d09a2SMark Phalan 
700