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 
319e11d51cSWill Fiveash /*
329e11d51cSWill Fiveash  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
339e11d51cSWill Fiveash  */
349e11d51cSWill Fiveash 
35159d09a2SMark Phalan #include <errno.h>
36159d09a2SMark Phalan #include <string.h>
37159d09a2SMark Phalan #include <stdio.h>
38159d09a2SMark Phalan #include <stdlib.h>
39159d09a2SMark Phalan #include <unistd.h>
40159d09a2SMark Phalan #include <regex.h>
41159d09a2SMark Phalan #include <krb5.h>
42159d09a2SMark Phalan #include "pkinit.h"
43159d09a2SMark Phalan 
44159d09a2SMark Phalan typedef struct _pkinit_cert_info pkinit_cert_info;
45159d09a2SMark Phalan 
46159d09a2SMark Phalan typedef enum {
47159d09a2SMark Phalan     kw_undefined = 0,
48159d09a2SMark Phalan     kw_subject = 1,
49159d09a2SMark Phalan     kw_issuer = 2,
50159d09a2SMark Phalan     kw_san = 3,
51159d09a2SMark Phalan     kw_eku = 4,
52159d09a2SMark Phalan     kw_ku = 5
53159d09a2SMark Phalan } keyword_type;
54159d09a2SMark Phalan 
55159d09a2SMark Phalan static char *
keyword2string(unsigned int kw)56159d09a2SMark Phalan keyword2string(unsigned int kw)
57159d09a2SMark Phalan {
58159d09a2SMark Phalan     /* Solaris Kerberos: removed "break"s (lint) */
59159d09a2SMark Phalan     switch(kw) {
60159d09a2SMark Phalan     case kw_undefined: return "NONE";
61159d09a2SMark Phalan     case kw_subject: return "SUBJECT";
62159d09a2SMark Phalan     case kw_issuer: return "ISSUER";
63159d09a2SMark Phalan     case kw_san: return "SAN";
64159d09a2SMark Phalan     case kw_eku: return "EKU";
65159d09a2SMark Phalan     case kw_ku: return "KU";
66159d09a2SMark Phalan     default: return "INVALID";
67159d09a2SMark Phalan     }
68159d09a2SMark Phalan }
69159d09a2SMark Phalan typedef enum {
70159d09a2SMark Phalan     relation_none = 0,
71159d09a2SMark Phalan     relation_and = 1,
72159d09a2SMark Phalan     relation_or = 2
73159d09a2SMark Phalan } relation_type;
74159d09a2SMark Phalan 
75159d09a2SMark Phalan static char *
relation2string(unsigned int rel)76159d09a2SMark Phalan relation2string(unsigned int rel)
77159d09a2SMark Phalan {
78159d09a2SMark Phalan     /* Solaris Kerberos: removed "break"s (lint) */
79159d09a2SMark Phalan     switch(rel) {
80159d09a2SMark Phalan     case relation_none: return "NONE";
81159d09a2SMark Phalan     case relation_and: return "AND";
82159d09a2SMark Phalan     case relation_or: return "OR";
83159d09a2SMark Phalan     default: return "INVALID";
84159d09a2SMark Phalan     }
85159d09a2SMark Phalan }
86159d09a2SMark Phalan 
87159d09a2SMark Phalan typedef enum {
88159d09a2SMark Phalan     kwvaltype_undefined = 0,
89159d09a2SMark Phalan     kwvaltype_regexp = 1,
90159d09a2SMark Phalan     kwvaltype_list = 2
91159d09a2SMark Phalan } kw_value_type;
92159d09a2SMark Phalan 
93159d09a2SMark Phalan static char *
kwval2string(unsigned int kwval)94159d09a2SMark Phalan kwval2string(unsigned int kwval)
95159d09a2SMark Phalan {
96159d09a2SMark Phalan     /* Solaris Kerberos: removed "break"s (lint) */
97159d09a2SMark Phalan     switch(kwval) {
98159d09a2SMark Phalan     case kwvaltype_undefined: return "NONE";
99159d09a2SMark Phalan     case kwvaltype_regexp: return "REGEXP";
100159d09a2SMark Phalan     case kwvaltype_list: return "LIST";
101159d09a2SMark Phalan     default: return "INVALID";
102159d09a2SMark Phalan     }
103159d09a2SMark Phalan }
104159d09a2SMark Phalan 
105159d09a2SMark Phalan struct keyword_desc {
106159d09a2SMark Phalan     const char *value;
107159d09a2SMark Phalan     size_t length;
108159d09a2SMark Phalan     keyword_type kwtype;
109159d09a2SMark Phalan     kw_value_type kwvaltype;
110159d09a2SMark Phalan } matching_keywords[] = {
111159d09a2SMark Phalan     { "<KU>",	    4, kw_ku, kwvaltype_list },
112159d09a2SMark Phalan     { "<EKU>",	    5, kw_eku, kwvaltype_list },
113159d09a2SMark Phalan     { "<SAN>",	    5, kw_san, kwvaltype_regexp },
114159d09a2SMark Phalan     { "<ISSUER>",   8, kw_issuer, kwvaltype_regexp },
115159d09a2SMark Phalan     { "<SUBJECT>",  9, kw_subject, kwvaltype_regexp },
116159d09a2SMark Phalan     { NULL, 0, kw_undefined, kwvaltype_undefined},
117159d09a2SMark Phalan };
118159d09a2SMark Phalan 
119159d09a2SMark Phalan struct ku_desc {
120159d09a2SMark Phalan     const char *value;
121159d09a2SMark Phalan     size_t length;
122159d09a2SMark Phalan     unsigned int bitval;
123159d09a2SMark Phalan };
124159d09a2SMark Phalan 
125159d09a2SMark Phalan struct ku_desc ku_keywords[] = {
126159d09a2SMark Phalan     { "digitalSignature",   16, PKINIT_KU_DIGITALSIGNATURE },
127159d09a2SMark Phalan     { "keyEncipherment",    15, PKINIT_KU_KEYENCIPHERMENT },
128159d09a2SMark Phalan     { NULL, 0, 0 },
129159d09a2SMark Phalan };
130159d09a2SMark Phalan 
131159d09a2SMark Phalan struct ku_desc  eku_keywords[] = {
132159d09a2SMark Phalan     { "pkinit",		    6,  PKINIT_EKU_PKINIT },
133159d09a2SMark Phalan     { "msScLogin",	    9,  PKINIT_EKU_MSSCLOGIN },
134159d09a2SMark Phalan     { "clientAuth",	    10, PKINIT_EKU_CLIENTAUTH },
135159d09a2SMark Phalan     { "emailProtection",    15, PKINIT_EKU_EMAILPROTECTION },
136159d09a2SMark Phalan     { NULL, 0, 0 },
137159d09a2SMark Phalan };
138159d09a2SMark Phalan 
139159d09a2SMark Phalan /* Rule component */
140159d09a2SMark Phalan typedef struct _rule_component {
141159d09a2SMark Phalan     struct _rule_component *next;
142159d09a2SMark Phalan     keyword_type kw_type;
143159d09a2SMark Phalan     kw_value_type kwval_type;
144159d09a2SMark Phalan     regex_t regexp;	    /* Compiled regular expression */
145159d09a2SMark Phalan     char *regsrc;	    /* The regular expression source (for debugging) */
146*55fea89dSDan Cross     unsigned int ku_bits;
147159d09a2SMark Phalan     unsigned int eku_bits;
148159d09a2SMark Phalan } rule_component;
149*55fea89dSDan Cross 
150159d09a2SMark Phalan /* Set rule components */
151159d09a2SMark Phalan typedef struct _rule_set {
152159d09a2SMark Phalan     relation_type relation;
153159d09a2SMark Phalan     int num_crs;
154159d09a2SMark Phalan     rule_component *crs;
155159d09a2SMark Phalan } rule_set;
156159d09a2SMark Phalan 
157159d09a2SMark Phalan /* ARGSUSED */
158159d09a2SMark Phalan static krb5_error_code
free_rule_component(krb5_context context,rule_component * rc)159159d09a2SMark Phalan free_rule_component(krb5_context context,
160159d09a2SMark Phalan 		    rule_component *rc)
161159d09a2SMark Phalan {
162159d09a2SMark Phalan     if (rc == NULL)
163159d09a2SMark Phalan 	return 0;
164159d09a2SMark Phalan 
165159d09a2SMark Phalan     if (rc->kwval_type == kwvaltype_regexp) {
166159d09a2SMark Phalan 	if (rc->regsrc)
167159d09a2SMark Phalan 	    free(rc->regsrc);
168159d09a2SMark Phalan 	regfree(&rc->regexp);
169159d09a2SMark Phalan     }
170159d09a2SMark Phalan     free(rc);
171159d09a2SMark Phalan     return 0;
172159d09a2SMark Phalan }
173159d09a2SMark Phalan 
174159d09a2SMark Phalan static krb5_error_code
free_rule_set(krb5_context context,rule_set * rs)175159d09a2SMark Phalan free_rule_set(krb5_context context,
176159d09a2SMark Phalan 	      rule_set *rs)
177159d09a2SMark Phalan {
178159d09a2SMark Phalan     rule_component *rc, *trc;
179159d09a2SMark Phalan 
180159d09a2SMark Phalan     if (rs == NULL)
181159d09a2SMark Phalan 	return 0;
182159d09a2SMark Phalan     for (rc = rs->crs; rc != NULL;) {
183159d09a2SMark Phalan 	trc = rc->next;
184159d09a2SMark Phalan 	/* Solaris Kerberos */
185159d09a2SMark Phalan 	(void) free_rule_component(context, rc);
186159d09a2SMark Phalan 	rc = trc;
187159d09a2SMark Phalan     }
188159d09a2SMark Phalan     free(rs);
189159d09a2SMark Phalan     return 0;
190159d09a2SMark Phalan }
191159d09a2SMark Phalan 
192159d09a2SMark Phalan /* ARGSUSED */
193159d09a2SMark Phalan static krb5_error_code
parse_list_value(krb5_context context,keyword_type type,char * value,rule_component * rc)194159d09a2SMark Phalan parse_list_value(krb5_context context,
195*55fea89dSDan Cross 		 keyword_type type,
196159d09a2SMark Phalan 		 char *value,
197159d09a2SMark Phalan 		 rule_component *rc)
198159d09a2SMark Phalan {
199159d09a2SMark Phalan     krb5_error_code retval;
200159d09a2SMark Phalan     char *comma;
201159d09a2SMark Phalan     struct ku_desc *ku = NULL;
202159d09a2SMark Phalan     int found;
203159d09a2SMark Phalan     size_t len;
204159d09a2SMark Phalan     unsigned int *bitptr;
205159d09a2SMark Phalan 
206159d09a2SMark Phalan 
207159d09a2SMark Phalan     if (value == NULL || value[0] == '\0') {
208159d09a2SMark Phalan 	pkiDebug("%s: Missing or empty value for list keyword type %d\n",
209159d09a2SMark Phalan 		 __FUNCTION__, type);
210159d09a2SMark Phalan 	retval = EINVAL;
211159d09a2SMark Phalan 	goto out;
212159d09a2SMark Phalan     }
213159d09a2SMark Phalan 
214159d09a2SMark Phalan     if (type == kw_eku) {
215159d09a2SMark Phalan 	bitptr = &rc->eku_bits;
216159d09a2SMark Phalan     } else if (type == kw_ku) {
217159d09a2SMark Phalan 	bitptr = &rc->ku_bits;
218159d09a2SMark Phalan     } else {
219159d09a2SMark Phalan 	pkiDebug("%s: Unknown list keyword type %d\n", __FUNCTION__, type);
220159d09a2SMark Phalan 	retval = EINVAL;
221159d09a2SMark Phalan 	goto out;
222159d09a2SMark Phalan     }
223159d09a2SMark Phalan 
224159d09a2SMark Phalan     do {
225159d09a2SMark Phalan 	found = 0;
226159d09a2SMark Phalan 	comma = strchr(value, ',');
227159d09a2SMark Phalan 	if (comma != NULL)
228159d09a2SMark Phalan 	    len = comma - value;
229159d09a2SMark Phalan 	else
230159d09a2SMark Phalan 	    len = strlen(value);
231159d09a2SMark Phalan 
232159d09a2SMark Phalan 	if (type == kw_eku) {
233159d09a2SMark Phalan 	    ku = eku_keywords;
234159d09a2SMark Phalan 	} else if (type == kw_ku) {
235159d09a2SMark Phalan 	    ku = ku_keywords;
236159d09a2SMark Phalan 	}
237159d09a2SMark Phalan 
238159d09a2SMark Phalan 	for (; ku->value != NULL; ku++) {
239159d09a2SMark Phalan 	    if (strncasecmp(value, ku->value, len) == 0) {
240159d09a2SMark Phalan 		*bitptr |= ku->bitval;
241159d09a2SMark Phalan 		found = 1;
242159d09a2SMark Phalan 		pkiDebug("%s: Found value '%s', bitfield is now 0x%x\n",
243159d09a2SMark Phalan 			 __FUNCTION__, ku->value, *bitptr);
244159d09a2SMark Phalan 		break;
245159d09a2SMark Phalan 	    }
246159d09a2SMark Phalan 	}
247159d09a2SMark Phalan 	if (found) {
248159d09a2SMark Phalan 	    value += ku->length;
249159d09a2SMark Phalan 	    if (*value == ',')
250159d09a2SMark Phalan 		value += 1;
251159d09a2SMark Phalan 	} else {
252159d09a2SMark Phalan 	    pkiDebug("%s: Urecognized value '%s'\n", __FUNCTION__, value);
253159d09a2SMark Phalan 	    retval = EINVAL;
254159d09a2SMark Phalan 	    goto out;
255159d09a2SMark Phalan 	}
256159d09a2SMark Phalan     } while (found && *value != '\0');
257159d09a2SMark Phalan 
258159d09a2SMark Phalan     retval = 0;
259159d09a2SMark Phalan out:
260159d09a2SMark Phalan     pkiDebug("%s: returning %d\n", __FUNCTION__, retval);
261159d09a2SMark Phalan     return retval;
262159d09a2SMark Phalan }
263159d09a2SMark Phalan 
264159d09a2SMark Phalan static krb5_error_code
parse_rule_component(krb5_context context,const char ** rule,int * remaining,rule_component ** ret_rule)265159d09a2SMark Phalan parse_rule_component(krb5_context context,
266159d09a2SMark Phalan 		     const char **rule,
267159d09a2SMark Phalan 		     int *remaining,
268159d09a2SMark Phalan 		     rule_component **ret_rule)
269159d09a2SMark Phalan {
270159d09a2SMark Phalan     krb5_error_code retval;
271159d09a2SMark Phalan     rule_component *rc = NULL;
272159d09a2SMark Phalan     keyword_type kw_type;
273159d09a2SMark Phalan     kw_value_type kwval_type;
274159d09a2SMark Phalan     char err_buf[128];
275159d09a2SMark Phalan     int ret;
276159d09a2SMark Phalan     struct keyword_desc *kw, *nextkw;
277159d09a2SMark Phalan     char *nk;
278159d09a2SMark Phalan     int found_next_kw = 0;
279159d09a2SMark Phalan     char *value = NULL;
280159d09a2SMark Phalan     size_t len;
281159d09a2SMark Phalan 
282159d09a2SMark Phalan     for (kw = matching_keywords; kw->value != NULL; kw++) {
283159d09a2SMark Phalan 	if (strncmp(*rule, kw->value, kw->length) == 0) {
284159d09a2SMark Phalan 	    kw_type = kw->kwtype;
285159d09a2SMark Phalan 	    kwval_type = kw->kwvaltype;
286159d09a2SMark Phalan 	    *rule += kw->length;
287159d09a2SMark Phalan 	    *remaining -= kw->length;
288159d09a2SMark Phalan 	    break;
289159d09a2SMark Phalan 	}
290159d09a2SMark Phalan     }
291159d09a2SMark Phalan     if (kw->value == NULL) {
292159d09a2SMark Phalan 	pkiDebug("%s: Missing or invalid keyword in rule '%s'\n",
293159d09a2SMark Phalan 		 __FUNCTION__, *rule);
294159d09a2SMark Phalan 	retval = ENOENT;
295159d09a2SMark Phalan 	goto out;
296159d09a2SMark Phalan     }
297159d09a2SMark Phalan 
298159d09a2SMark Phalan     pkiDebug("%s: found keyword '%s'\n", __FUNCTION__, kw->value);
299159d09a2SMark Phalan 
300159d09a2SMark Phalan     rc = calloc(1, sizeof(*rc));
301159d09a2SMark Phalan     if (rc == NULL) {
302159d09a2SMark Phalan 	retval = ENOMEM;
303159d09a2SMark Phalan 	goto out;
304159d09a2SMark Phalan     }
305159d09a2SMark Phalan     rc->next = NULL;
306159d09a2SMark Phalan     rc->kw_type = kw_type;
307159d09a2SMark Phalan     rc->kwval_type = kwval_type;
308159d09a2SMark Phalan 
309159d09a2SMark Phalan     /*
310159d09a2SMark Phalan      * Before procesing the value for this keyword,
311159d09a2SMark Phalan      * (compiling the regular expression or processing the list)
312159d09a2SMark Phalan      * we need to find the end of it.  That means parsing for the
313159d09a2SMark Phalan      * beginning of the next keyword (or the end of the rule).
314159d09a2SMark Phalan      */
315159d09a2SMark Phalan     nk = strchr(*rule, '<');
316159d09a2SMark Phalan     while (nk != NULL) {
317159d09a2SMark Phalan 	/* Possibly another keyword, check it out */
318159d09a2SMark Phalan 	for (nextkw = matching_keywords; nextkw->value != NULL; nextkw++) {
319159d09a2SMark Phalan 	    if (strncmp(nk, nextkw->value, nextkw->length) == 0) {
320159d09a2SMark Phalan 		/* Found a keyword, nk points to the beginning */
321159d09a2SMark Phalan 		found_next_kw = 1;
322159d09a2SMark Phalan 		break;	/* Need to break out of the while! */
323159d09a2SMark Phalan 	    }
324159d09a2SMark Phalan 	}
325159d09a2SMark Phalan 	if (!found_next_kw)
326159d09a2SMark Phalan 	    nk = strchr(nk+1, '<');	/* keep looking */
327159d09a2SMark Phalan 	else
328159d09a2SMark Phalan 	    break;
329159d09a2SMark Phalan     }
330159d09a2SMark Phalan 
331159d09a2SMark Phalan     if (nk != NULL && found_next_kw)
332159d09a2SMark Phalan 	len = (nk - *rule);
333159d09a2SMark Phalan     else
334159d09a2SMark Phalan 	len = (*remaining);
335159d09a2SMark Phalan 
336159d09a2SMark Phalan     if (len == 0) {
337159d09a2SMark Phalan 	pkiDebug("%s: Missing value for keyword '%s'\n",
338159d09a2SMark Phalan 		 __FUNCTION__, kw->value);
339159d09a2SMark Phalan 	retval = EINVAL;
340159d09a2SMark Phalan 	goto out;
341159d09a2SMark Phalan     }
342159d09a2SMark Phalan 
343159d09a2SMark Phalan     value = calloc(1, len+1);
344159d09a2SMark Phalan     if (value == NULL) {
345159d09a2SMark Phalan 	retval = ENOMEM;
346159d09a2SMark Phalan 	goto out;
347159d09a2SMark Phalan     }
348159d09a2SMark Phalan     (void) memcpy(value, *rule, len);
349159d09a2SMark Phalan     *remaining -= len;
350159d09a2SMark Phalan     *rule += len;
351159d09a2SMark Phalan     pkiDebug("%s: found value '%s'\n", __FUNCTION__, value);
352159d09a2SMark Phalan 
353159d09a2SMark Phalan     if (kw->kwvaltype == kwvaltype_regexp) {
354159d09a2SMark Phalan 	ret = regcomp(&rc->regexp, value, REG_EXTENDED);
355159d09a2SMark Phalan 	if (ret) {
356159d09a2SMark Phalan 	    (void) regerror(ret, &rc->regexp, err_buf, sizeof(err_buf));
357159d09a2SMark Phalan 	    pkiDebug("%s: Error compiling reg-exp '%s': %s\n",
358159d09a2SMark Phalan 		     __FUNCTION__, value, err_buf);
359159d09a2SMark Phalan 	    retval = ret;
360159d09a2SMark Phalan 	    goto out;
361159d09a2SMark Phalan 	}
362159d09a2SMark Phalan 	rc->regsrc = strdup(value);
363159d09a2SMark Phalan 	if (rc->regsrc == NULL) {
364159d09a2SMark Phalan 	    retval = ENOMEM;
365159d09a2SMark Phalan 	    goto out;
366159d09a2SMark Phalan 	}
367159d09a2SMark Phalan     } else if (kw->kwvaltype == kwvaltype_list) {
368159d09a2SMark Phalan 	retval = parse_list_value(context, rc->kw_type, value, rc);
369159d09a2SMark Phalan 	if (retval) {
370159d09a2SMark Phalan 	    pkiDebug("%s: Error %d, parsing list values for keyword %s\n",
371159d09a2SMark Phalan 		     __FUNCTION__, retval, kw->value);
372159d09a2SMark Phalan 	    goto out;
373159d09a2SMark Phalan 	}
374159d09a2SMark Phalan     }
375159d09a2SMark Phalan 
376159d09a2SMark Phalan     *ret_rule = rc;
377159d09a2SMark Phalan     retval = 0;
378159d09a2SMark Phalan out:
379159d09a2SMark Phalan     if (value != NULL)
380159d09a2SMark Phalan 	free(value);
381159d09a2SMark Phalan     if (retval && rc != NULL)
382159d09a2SMark Phalan 	(void) free_rule_component(context, rc);
383159d09a2SMark Phalan     pkiDebug("%s: returning %d\n", __FUNCTION__, retval);
384159d09a2SMark Phalan     return retval;
385159d09a2SMark Phalan }
386159d09a2SMark Phalan 
387159d09a2SMark Phalan /* ARGSUSED */
388159d09a2SMark Phalan static krb5_error_code
parse_rule_set(krb5_context context,const char * rule_in,rule_set ** out_rs)389159d09a2SMark Phalan parse_rule_set(krb5_context context,
390159d09a2SMark Phalan 	       const char *rule_in,
391159d09a2SMark Phalan 	       rule_set **out_rs)
392159d09a2SMark Phalan {
393159d09a2SMark Phalan     const char *rule;
394159d09a2SMark Phalan     /* Solaris Kerberos */
395159d09a2SMark Phalan     int remaining;
396159d09a2SMark Phalan     krb5_error_code ret, retval;
397159d09a2SMark Phalan     rule_component *rc = NULL, *trc;
398159d09a2SMark Phalan     rule_set *rs;
399159d09a2SMark Phalan 
400159d09a2SMark Phalan 
401159d09a2SMark Phalan     if (rule_in == NULL)
402159d09a2SMark Phalan 	return EINVAL;
403159d09a2SMark Phalan     rule = rule_in;
404159d09a2SMark Phalan     /* Solaris Kerberos */
405159d09a2SMark Phalan     remaining = strlen(rule);
406159d09a2SMark Phalan 
407159d09a2SMark Phalan     rs = calloc(1, sizeof(*rs));
408159d09a2SMark Phalan     if (rs == NULL) {
409159d09a2SMark Phalan 	retval = ENOMEM;
410159d09a2SMark Phalan 	goto cleanup;
411159d09a2SMark Phalan     }
412159d09a2SMark Phalan 
413159d09a2SMark Phalan     rs->relation = relation_none;
414159d09a2SMark Phalan     if (remaining > 1) {
415159d09a2SMark Phalan 	if (rule[0] == '&' && rule[1] == '&') {
416159d09a2SMark Phalan 	    rs->relation = relation_and;
417159d09a2SMark Phalan 	    rule += 2;
418159d09a2SMark Phalan 	    remaining -= 2;
419159d09a2SMark Phalan 	} else if (rule_in[0] == '|' && rule_in[1] == '|') {
420159d09a2SMark Phalan 	    rs->relation = relation_or;
421159d09a2SMark Phalan 	    rule +=2;
422159d09a2SMark Phalan 	    remaining -= 2;
423159d09a2SMark Phalan 	}
424159d09a2SMark Phalan     }
425159d09a2SMark Phalan     rs->num_crs = 0;
426159d09a2SMark Phalan     while (remaining > 0) {
427159d09a2SMark Phalan 	if (rs->relation == relation_none && rs->num_crs > 1) {
428159d09a2SMark Phalan 	    pkiDebug("%s: Assuming AND relation for multiple components in rule '%s'\n",
429159d09a2SMark Phalan 		     __FUNCTION__, rule_in);
430159d09a2SMark Phalan 	    rs->relation = relation_and;
431159d09a2SMark Phalan 	}
432159d09a2SMark Phalan 	ret = parse_rule_component(context, &rule, &remaining, &rc);
433159d09a2SMark Phalan 	if (ret) {
434159d09a2SMark Phalan 	    retval = ret;
435159d09a2SMark Phalan 	    goto cleanup;
436159d09a2SMark Phalan 	}
437159d09a2SMark Phalan 	pkiDebug("%s: After parse_rule_component, remaining %d, rule '%s'\n",
438159d09a2SMark Phalan 		 __FUNCTION__, remaining, rule);
439159d09a2SMark Phalan 	rs->num_crs++;
440159d09a2SMark Phalan 
441159d09a2SMark Phalan 	/*
442159d09a2SMark Phalan 	 * Chain the new component on the end (order matters since
443159d09a2SMark Phalan 	 * we can short-circuit an OR or an AND relation if an
444159d09a2SMark Phalan 	 * earlier check passes
445159d09a2SMark Phalan 	 */
446159d09a2SMark Phalan 	for (trc = rs->crs; trc != NULL && trc->next != NULL; trc = trc->next);
447159d09a2SMark Phalan 	if (trc == NULL)
448159d09a2SMark Phalan 	    rs->crs = rc;
449159d09a2SMark Phalan 	else {
450159d09a2SMark Phalan 	    trc->next = rc;
451159d09a2SMark Phalan 	}
452159d09a2SMark Phalan     }
453159d09a2SMark Phalan 
454159d09a2SMark Phalan     *out_rs = rs;
455159d09a2SMark Phalan 
456159d09a2SMark Phalan     retval = 0;
457159d09a2SMark Phalan cleanup:
458159d09a2SMark Phalan     if (retval && rs != NULL) {
459159d09a2SMark Phalan 	(void) free_rule_set(context, rs);
460159d09a2SMark Phalan     }
461159d09a2SMark Phalan     pkiDebug("%s: returning %d\n", __FUNCTION__, retval);
462159d09a2SMark Phalan     return retval;
463159d09a2SMark Phalan }
464159d09a2SMark Phalan 
465159d09a2SMark Phalan /* ARGSUSED */
466159d09a2SMark Phalan static int
regexp_match(krb5_context context,rule_component * rc,char * value)467159d09a2SMark Phalan regexp_match(krb5_context context, rule_component *rc, char *value)
468159d09a2SMark Phalan {
469159d09a2SMark Phalan     int code;
470159d09a2SMark Phalan 
471159d09a2SMark Phalan     pkiDebug("%s: checking %s rule '%s' with value '%s'\n",
472159d09a2SMark Phalan 	     __FUNCTION__, keyword2string(rc->kw_type), rc->regsrc, value);
473159d09a2SMark Phalan 
474159d09a2SMark Phalan     code = regexec(&rc->regexp, value, 0, NULL, 0);
475159d09a2SMark Phalan 
476159d09a2SMark Phalan     pkiDebug("%s: the result is%s a match\n", __FUNCTION__,
477159d09a2SMark Phalan 	     code == REG_NOMATCH ? " NOT" : "");
478159d09a2SMark Phalan 
479159d09a2SMark Phalan     return (code == 0 ? 1: 0);
480159d09a2SMark Phalan }
481159d09a2SMark Phalan 
482159d09a2SMark Phalan static int
component_match(krb5_context context,rule_component * rc,pkinit_cert_matching_data * md)483159d09a2SMark Phalan component_match(krb5_context context,
484159d09a2SMark Phalan 		rule_component *rc,
485159d09a2SMark Phalan 		pkinit_cert_matching_data *md)
486159d09a2SMark Phalan {
487159d09a2SMark Phalan     int match = 0;
488159d09a2SMark Phalan     int i;
489159d09a2SMark Phalan     krb5_principal p;
490159d09a2SMark Phalan     char *princ_string;
491159d09a2SMark Phalan 
492159d09a2SMark Phalan     switch (rc->kwval_type) {
493159d09a2SMark Phalan     case kwvaltype_regexp:
494159d09a2SMark Phalan 	switch (rc->kw_type) {
495159d09a2SMark Phalan 	case kw_subject:
496159d09a2SMark Phalan 	    match = regexp_match(context, rc, md->subject_dn);
497159d09a2SMark Phalan 	    break;
498159d09a2SMark Phalan 	case kw_issuer:
499159d09a2SMark Phalan 	    match = regexp_match(context, rc, md->issuer_dn);
500159d09a2SMark Phalan 	    break;
501159d09a2SMark Phalan 	case kw_san:
502159d09a2SMark Phalan 	    if (md->sans == NULL)
503159d09a2SMark Phalan 		break;
504159d09a2SMark Phalan 	    for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i]) {
505159d09a2SMark Phalan 		krb5_unparse_name(context, p, &princ_string);
506159d09a2SMark Phalan 		match = regexp_match(context, rc, princ_string);
507159d09a2SMark Phalan 		krb5_free_unparsed_name(context, princ_string);
508159d09a2SMark Phalan 		if (match)
509159d09a2SMark Phalan 		    break;
510159d09a2SMark Phalan 	    }
511159d09a2SMark Phalan 	    break;
512159d09a2SMark Phalan 	default:
513159d09a2SMark Phalan 	    pkiDebug("%s: keyword %s, keyword value %s mismatch\n",
514159d09a2SMark Phalan 		     __FUNCTION__, keyword2string(rc->kw_type),
515159d09a2SMark Phalan 		     kwval2string(kwvaltype_regexp));
516159d09a2SMark Phalan 	    break;
517159d09a2SMark Phalan 	}
518159d09a2SMark Phalan 	break;
519159d09a2SMark Phalan     case kwvaltype_list:
520159d09a2SMark Phalan 	switch(rc->kw_type) {
521159d09a2SMark Phalan 	case kw_eku:
522159d09a2SMark Phalan 	    pkiDebug("%s: checking %s: rule 0x%08x, cert 0x%08x\n",
523159d09a2SMark Phalan 		     __FUNCTION__, keyword2string(rc->kw_type),
524159d09a2SMark Phalan 		     rc->eku_bits, md->eku_bits);
525159d09a2SMark Phalan 	    if ((rc->eku_bits & md->eku_bits) == rc->eku_bits)
526159d09a2SMark Phalan 		match = 1;
527159d09a2SMark Phalan 	    break;
528159d09a2SMark Phalan 	case kw_ku:
529159d09a2SMark Phalan 	    pkiDebug("%s: checking %s: rule 0x%08x, cert 0x%08x\n",
530159d09a2SMark Phalan 		     __FUNCTION__, keyword2string(rc->kw_type),
531159d09a2SMark Phalan 		     rc->ku_bits, md->ku_bits);
532159d09a2SMark Phalan 	    if ((rc->ku_bits & md->ku_bits) == rc->ku_bits)
533159d09a2SMark Phalan 		match = 1;
534159d09a2SMark Phalan 	    break;
535159d09a2SMark Phalan 	default:
536159d09a2SMark Phalan 	    pkiDebug("%s: keyword %s, keyword value %s mismatch\n",
537159d09a2SMark Phalan 		     __FUNCTION__, keyword2string(rc->kw_type),
538159d09a2SMark Phalan 		     kwval2string(kwvaltype_regexp));
539159d09a2SMark Phalan 	    break;
540159d09a2SMark Phalan 	}
541159d09a2SMark Phalan 	break;
542159d09a2SMark Phalan     default:
543159d09a2SMark Phalan 	pkiDebug("%s: unknown keyword value type %d\n",
544159d09a2SMark Phalan 		 __FUNCTION__, rc->kwval_type);
545159d09a2SMark Phalan 	break;
546159d09a2SMark Phalan     }
547159d09a2SMark Phalan     pkiDebug("%s: returning match = %d\n", __FUNCTION__, match);
548159d09a2SMark Phalan     return match;
549159d09a2SMark Phalan }
550159d09a2SMark Phalan /*
551159d09a2SMark Phalan  * Returns match_found == 1 only if exactly one certificate matches
552159d09a2SMark Phalan  * the given rule
553159d09a2SMark Phalan  */
554159d09a2SMark Phalan /* ARGSUSED */
555159d09a2SMark Phalan static krb5_error_code
check_all_certs(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ,rule_set * rs,pkinit_cert_matching_data ** matchdata,int * match_found,pkinit_cert_matching_data ** matching_cert)556159d09a2SMark Phalan check_all_certs(krb5_context context,
557159d09a2SMark Phalan 		pkinit_plg_crypto_context plg_cryptoctx,
558159d09a2SMark Phalan 		pkinit_req_crypto_context req_cryptoctx,
559159d09a2SMark Phalan 		pkinit_identity_crypto_context id_cryptoctx,
560159d09a2SMark Phalan 		krb5_principal princ,
561159d09a2SMark Phalan 		rule_set *rs,	/* rule to check */
562159d09a2SMark Phalan 		pkinit_cert_matching_data **matchdata,
563159d09a2SMark Phalan 		int *match_found,
564159d09a2SMark Phalan 		pkinit_cert_matching_data **matching_cert)
565159d09a2SMark Phalan {
566159d09a2SMark Phalan     krb5_error_code retval;
567159d09a2SMark Phalan     pkinit_cert_matching_data *md;
568159d09a2SMark Phalan     int i;
569159d09a2SMark Phalan     int comp_match = 0;
570159d09a2SMark Phalan     int total_cert_matches = 0;
571159d09a2SMark Phalan     rule_component *rc;
572159d09a2SMark Phalan     int certs_checked = 0;
573159d09a2SMark Phalan     pkinit_cert_matching_data *save_match = NULL;
574159d09a2SMark Phalan 
575159d09a2SMark Phalan     if (match_found == NULL || matching_cert == NULL)
576159d09a2SMark Phalan 	return EINVAL;
577159d09a2SMark Phalan 
578159d09a2SMark Phalan     *matching_cert = NULL;
579159d09a2SMark Phalan     *match_found = 0;
580159d09a2SMark Phalan 
581159d09a2SMark Phalan     pkiDebug("%s: matching rule relation is %s with %d components\n",
582159d09a2SMark Phalan 	     __FUNCTION__, relation2string(rs->relation), rs->num_crs);
583159d09a2SMark Phalan 
584159d09a2SMark Phalan     /*
585159d09a2SMark Phalan      * Loop through all the certs available and count
586159d09a2SMark Phalan      * how many match the rule
587159d09a2SMark Phalan      */
588159d09a2SMark Phalan     for (i = 0, md = matchdata[i]; md != NULL; md = matchdata[++i]) {
589159d09a2SMark Phalan 	pkiDebug("%s: subject: '%s'\n", __FUNCTION__, md->subject_dn);
590159d09a2SMark Phalan #if 0
591159d09a2SMark Phalan 	pkiDebug("%s: issuer:  '%s'\n", __FUNCTION__, md->subject_dn);
592159d09a2SMark Phalan 	for (j = 0, p = md->sans[j]; p != NULL; p = md->sans[++j]) {
593159d09a2SMark Phalan 	    char *san_string;
594159d09a2SMark Phalan 	    krb5_unparse_name(context, p, &san_string);
595159d09a2SMark Phalan 	    pkiDebug("%s: san: '%s'\n", __FUNCTION__, san_string);
596159d09a2SMark Phalan 	    krb5_free_unparsed_name(context, san_string);
597159d09a2SMark Phalan 	}
598159d09a2SMark Phalan #endif
599159d09a2SMark Phalan 	certs_checked++;
600159d09a2SMark Phalan 	for (rc = rs->crs; rc != NULL; rc = rc->next) {
601159d09a2SMark Phalan 	    comp_match = component_match(context, rc, md);
602159d09a2SMark Phalan 	    if (comp_match) {
603159d09a2SMark Phalan 		pkiDebug("%s: match for keyword type %s\n",
604159d09a2SMark Phalan 			 __FUNCTION__, keyword2string(rc->kw_type));
605159d09a2SMark Phalan 	    }
606159d09a2SMark Phalan 	    if (comp_match && rs->relation == relation_or) {
607159d09a2SMark Phalan 		pkiDebug("%s: cert matches rule (OR relation)\n",
608159d09a2SMark Phalan 			 __FUNCTION__);
609159d09a2SMark Phalan 		total_cert_matches++;
610159d09a2SMark Phalan 		save_match = md;
611159d09a2SMark Phalan 		goto nextcert;
612159d09a2SMark Phalan 	    }
613159d09a2SMark Phalan 	    if (!comp_match && rs->relation == relation_and) {
614159d09a2SMark Phalan 		pkiDebug("%s: cert does not match rule (AND relation)\n",
615159d09a2SMark Phalan 			 __FUNCTION__);
616159d09a2SMark Phalan 		goto nextcert;
617159d09a2SMark Phalan 	    }
618159d09a2SMark Phalan 	}
619159d09a2SMark Phalan 	if (rc == NULL && comp_match) {
620159d09a2SMark Phalan 	    pkiDebug("%s: cert matches rule (AND relation)\n", __FUNCTION__);
621159d09a2SMark Phalan 	    total_cert_matches++;
622159d09a2SMark Phalan 	    save_match = md;
623159d09a2SMark Phalan 	}
624159d09a2SMark Phalan nextcert:
625159d09a2SMark Phalan 	continue;
626159d09a2SMark Phalan     }
627159d09a2SMark Phalan     pkiDebug("%s: After checking %d certs, we found %d matches\n",
628159d09a2SMark Phalan 	     __FUNCTION__, certs_checked, total_cert_matches);
629159d09a2SMark Phalan     if (total_cert_matches == 1) {
630*55fea89dSDan Cross 	*match_found = 1;
631159d09a2SMark Phalan 	*matching_cert = save_match;
632159d09a2SMark Phalan     }
633159d09a2SMark Phalan 
634159d09a2SMark Phalan     retval = 0;
635159d09a2SMark Phalan 
636159d09a2SMark Phalan     pkiDebug("%s: returning %d, match_found %d\n",
637159d09a2SMark Phalan 	     __FUNCTION__, retval, *match_found);
638159d09a2SMark Phalan     return retval;
639159d09a2SMark Phalan }
640159d09a2SMark Phalan 
641159d09a2SMark Phalan static krb5_error_code
free_all_cert_matching_data(krb5_context context,pkinit_cert_matching_data ** matchdata)642159d09a2SMark Phalan free_all_cert_matching_data(krb5_context context,
643159d09a2SMark Phalan 			    pkinit_cert_matching_data **matchdata)
644159d09a2SMark Phalan {
645159d09a2SMark Phalan     krb5_error_code retval;
646159d09a2SMark Phalan     pkinit_cert_matching_data *md;
647159d09a2SMark Phalan     int i;
648159d09a2SMark Phalan 
649159d09a2SMark Phalan     if (matchdata == NULL)
650159d09a2SMark Phalan 	return EINVAL;
651159d09a2SMark Phalan 
652159d09a2SMark Phalan     for (i = 0, md = matchdata[i]; md != NULL; md = matchdata[++i]) {
653159d09a2SMark Phalan 	pkinit_cert_handle ch = md->ch;
654159d09a2SMark Phalan 	retval = crypto_cert_free_matching_data(context, md);
655159d09a2SMark Phalan 	if (retval) {
656159d09a2SMark Phalan 	    pkiDebug("%s: crypto_cert_free_matching_data error %d, %s\n",
657159d09a2SMark Phalan 		     __FUNCTION__, retval, error_message(retval));
658159d09a2SMark Phalan 	    goto cleanup;
659159d09a2SMark Phalan 	}
660159d09a2SMark Phalan 	retval = crypto_cert_release(context, ch);
661159d09a2SMark Phalan 	if (retval) {
662159d09a2SMark Phalan 	    pkiDebug("%s: crypto_cert_release error %d, %s\n",
663159d09a2SMark Phalan 		     __FUNCTION__, retval, error_message(retval));
664159d09a2SMark Phalan 	    goto cleanup;
665159d09a2SMark Phalan 	}
666159d09a2SMark Phalan     }
667159d09a2SMark Phalan     free(matchdata);
668159d09a2SMark Phalan     retval = 0;
669159d09a2SMark Phalan 
670159d09a2SMark Phalan cleanup:
671159d09a2SMark Phalan     return retval;
672159d09a2SMark Phalan }
673159d09a2SMark Phalan 
674159d09a2SMark Phalan static krb5_error_code
obtain_all_cert_matching_data(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,pkinit_cert_matching_data *** all_matching_data)675159d09a2SMark Phalan obtain_all_cert_matching_data(krb5_context context,
676159d09a2SMark Phalan 			      pkinit_plg_crypto_context plg_cryptoctx,
677159d09a2SMark Phalan 			      pkinit_req_crypto_context req_cryptoctx,
678159d09a2SMark Phalan 			      pkinit_identity_crypto_context id_cryptoctx,
679159d09a2SMark Phalan 			      pkinit_cert_matching_data ***all_matching_data)
680159d09a2SMark Phalan {
681159d09a2SMark Phalan     krb5_error_code retval;
682159d09a2SMark Phalan     int i, cert_count;
683159d09a2SMark Phalan     pkinit_cert_iter_handle ih = NULL;
684159d09a2SMark Phalan     pkinit_cert_handle ch;
685159d09a2SMark Phalan     pkinit_cert_matching_data **matchdata = NULL;
686159d09a2SMark Phalan 
687159d09a2SMark Phalan     retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
688159d09a2SMark Phalan 				   id_cryptoctx, &cert_count);
689159d09a2SMark Phalan     if (retval) {
690159d09a2SMark Phalan 	pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
691159d09a2SMark Phalan 		 __FUNCTION__, retval, error_message(retval));
692159d09a2SMark Phalan 	goto cleanup;
693159d09a2SMark Phalan     }
694159d09a2SMark Phalan 
695159d09a2SMark Phalan     pkiDebug("%s: crypto_cert_get_count says there are %d certs\n",
696159d09a2SMark Phalan 	      __FUNCTION__, cert_count);
697159d09a2SMark Phalan 
698159d09a2SMark Phalan     matchdata = calloc((size_t)cert_count + 1, sizeof(*matchdata));
699159d09a2SMark Phalan     if (matchdata == NULL)
700159d09a2SMark Phalan 	return ENOMEM;
701159d09a2SMark Phalan 
702159d09a2SMark Phalan     retval = crypto_cert_iteration_begin(context, plg_cryptoctx, req_cryptoctx,
703159d09a2SMark Phalan 					 id_cryptoctx, &ih);
704159d09a2SMark Phalan     if (retval) {
705159d09a2SMark Phalan 	pkiDebug("%s: crypto_cert_iteration_begin returned %d, %s\n",
706159d09a2SMark Phalan 		 __FUNCTION__, retval, error_message(retval));
707159d09a2SMark Phalan 	goto cleanup;
708159d09a2SMark Phalan     }
709159d09a2SMark Phalan 
710159d09a2SMark Phalan     for (i = 0; i < cert_count; i++) {
711159d09a2SMark Phalan 	retval = crypto_cert_iteration_next(context, ih, &ch);
712159d09a2SMark Phalan 	if (retval) {
713159d09a2SMark Phalan 	    if (retval == PKINIT_ITER_NO_MORE)
714159d09a2SMark Phalan 		pkiDebug("%s: We thought there were %d certs, but "
715159d09a2SMark Phalan 			 "crypto_cert_iteration_next stopped after %d?\n",
716159d09a2SMark Phalan 			 __FUNCTION__, cert_count, i);
717159d09a2SMark Phalan 	    else
718159d09a2SMark Phalan 		pkiDebug("%s: crypto_cert_iteration_next error %d, %s\n",
719159d09a2SMark Phalan 			 __FUNCTION__, retval, error_message(retval));
720159d09a2SMark Phalan 	    goto cleanup;
721159d09a2SMark Phalan 	}
722159d09a2SMark Phalan 
723159d09a2SMark Phalan 	retval = crypto_cert_get_matching_data(context, ch, &matchdata[i]);
724159d09a2SMark Phalan 	if (retval) {
725159d09a2SMark Phalan 	    pkiDebug("%s: crypto_cert_get_matching_data error %d, %s\n",
726159d09a2SMark Phalan 		     __FUNCTION__, retval, error_message(retval));
727159d09a2SMark Phalan 	    goto cleanup;
728159d09a2SMark Phalan 	}
729159d09a2SMark Phalan 
730159d09a2SMark Phalan     }
731159d09a2SMark Phalan 
732159d09a2SMark Phalan     *all_matching_data = matchdata;
733159d09a2SMark Phalan     retval = 0;
734159d09a2SMark Phalan cleanup:
735159d09a2SMark Phalan     if (ih != NULL)
736159d09a2SMark Phalan 	/* Solaris Kerberos */
737159d09a2SMark Phalan 	(void) crypto_cert_iteration_end(context, ih);
738159d09a2SMark Phalan     if (retval) {
739159d09a2SMark Phalan 	if (matchdata != NULL)
740159d09a2SMark Phalan 	    (void) free_all_cert_matching_data(context, matchdata);
741159d09a2SMark Phalan     }
742159d09a2SMark Phalan     pkiDebug("%s: returning %d, certinfo %p\n",
743159d09a2SMark Phalan 	     __FUNCTION__, retval, *all_matching_data);
744159d09a2SMark Phalan     return retval;
745159d09a2SMark Phalan }
746159d09a2SMark Phalan 
747159d09a2SMark Phalan krb5_error_code
pkinit_cert_matching(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ,krb5_boolean do_select)748159d09a2SMark Phalan pkinit_cert_matching(krb5_context context,
749159d09a2SMark Phalan 		     pkinit_plg_crypto_context plg_cryptoctx,
750159d09a2SMark Phalan 		     pkinit_req_crypto_context req_cryptoctx,
751159d09a2SMark Phalan 		     pkinit_identity_crypto_context id_cryptoctx,
7529e11d51cSWill Fiveash 		     krb5_principal princ,
7539e11d51cSWill Fiveash                      krb5_boolean do_select)
754159d09a2SMark Phalan {
755159d09a2SMark Phalan 
756159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
757159d09a2SMark Phalan     int x;
758159d09a2SMark Phalan     char **rules = NULL;
759159d09a2SMark Phalan     rule_set *rs = NULL;
760159d09a2SMark Phalan     int match_found = 0;
761159d09a2SMark Phalan     pkinit_cert_matching_data **matchdata = NULL;
762159d09a2SMark Phalan     pkinit_cert_matching_data *the_matching_cert = NULL;
763159d09a2SMark Phalan 
764159d09a2SMark Phalan     /* If no matching rules, select the default cert and we're done */
765159d09a2SMark Phalan     (void) pkinit_libdefault_strings(context, krb5_princ_realm(context, princ),
766159d09a2SMark Phalan 			      "pkinit_cert_match", &rules);
767159d09a2SMark Phalan     if (rules == NULL) {
768159d09a2SMark Phalan 	pkiDebug("%s: no matching rules found in config file\n", __FUNCTION__);
7699e11d51cSWill Fiveash         if (do_select == TRUE) {
7709e11d51cSWill Fiveash             retval = crypto_cert_select_default(context, plg_cryptoctx,
7719e11d51cSWill Fiveash                                                 req_cryptoctx, id_cryptoctx);
7729e11d51cSWill Fiveash         } else
7739e11d51cSWill Fiveash             retval = 0;
774159d09a2SMark Phalan 	goto cleanup;
775159d09a2SMark Phalan     }
776159d09a2SMark Phalan 
777159d09a2SMark Phalan     /* parse each rule line one at a time and check all the certs against it */
778159d09a2SMark Phalan     for (x = 0; rules[x] != NULL; x++) {
779159d09a2SMark Phalan 	pkiDebug("%s: Processing rule '%s'\n", __FUNCTION__, rules[x]);
780159d09a2SMark Phalan 
781159d09a2SMark Phalan 	/* Free rules from previous time through... */
782159d09a2SMark Phalan 	if (rs != NULL) {
783159d09a2SMark Phalan 	    (void) free_rule_set(context, rs);
784159d09a2SMark Phalan 	    rs = NULL;
785159d09a2SMark Phalan 	}
786159d09a2SMark Phalan 	retval = parse_rule_set(context, rules[x], &rs);
787159d09a2SMark Phalan 	if (retval) {
788159d09a2SMark Phalan 	    if (retval == EINVAL) {
789159d09a2SMark Phalan 		pkiDebug("%s: Ignoring invalid rule pkinit_cert_match = '%s'\n",
790*55fea89dSDan Cross 			 __FUNCTION__, rules[x]);
791159d09a2SMark Phalan 		continue;
792159d09a2SMark Phalan 	    }
793159d09a2SMark Phalan 	    goto cleanup;
794159d09a2SMark Phalan 	}
795159d09a2SMark Phalan 
796159d09a2SMark Phalan 	/*
797159d09a2SMark Phalan 	 * Optimize so that we do not get cert info unless we have
798159d09a2SMark Phalan 	 * valid rules to check.  Once obtained, keep it around
799159d09a2SMark Phalan 	 * until we are done.
800159d09a2SMark Phalan 	 */
801159d09a2SMark Phalan 	if (matchdata == NULL) {
802159d09a2SMark Phalan 	    retval = obtain_all_cert_matching_data(context, plg_cryptoctx,
803159d09a2SMark Phalan 						   req_cryptoctx, id_cryptoctx,
804159d09a2SMark Phalan 						   &matchdata);
805159d09a2SMark Phalan 	    if (retval || matchdata == NULL) {
806159d09a2SMark Phalan 		pkiDebug("%s: Error %d obtaining certificate information\n",
807159d09a2SMark Phalan 			 __FUNCTION__, retval);
808159d09a2SMark Phalan 		retval = ENOENT;
809159d09a2SMark Phalan 		goto cleanup;
810159d09a2SMark Phalan 	    }
811159d09a2SMark Phalan 	}
812159d09a2SMark Phalan 
813159d09a2SMark Phalan 	retval = check_all_certs(context, plg_cryptoctx, req_cryptoctx,
814159d09a2SMark Phalan 				 id_cryptoctx, princ, rs, matchdata,
815159d09a2SMark Phalan 				 &match_found, &the_matching_cert);
816159d09a2SMark Phalan 	if (retval) {
817159d09a2SMark Phalan 	    pkiDebug("%s: Error %d, checking certs against rule '%s'\n",
818159d09a2SMark Phalan 		     __FUNCTION__, retval, rules[x]);
819159d09a2SMark Phalan 	    goto cleanup;
820159d09a2SMark Phalan 	}
821159d09a2SMark Phalan 	if (match_found) {
822159d09a2SMark Phalan 	    pkiDebug("%s: We have an exact match with rule '%s'\n",
823159d09a2SMark Phalan 		     __FUNCTION__, rules[x]);
824159d09a2SMark Phalan 	    break;
825159d09a2SMark Phalan 	}
826159d09a2SMark Phalan     }
827159d09a2SMark Phalan 
828159d09a2SMark Phalan     if (match_found && the_matching_cert != NULL) {
8299e11d51cSWill Fiveash         if (do_select == TRUE) {
8309e11d51cSWill Fiveash             pkiDebug("%s: Selecting the matching cert!\n", __FUNCTION__);
8319e11d51cSWill Fiveash             retval = crypto_cert_select(context, the_matching_cert);
8329e11d51cSWill Fiveash             if (retval) {
8339e11d51cSWill Fiveash                 pkiDebug("%s: crypto_cert_select error %d, %s\n",
8349e11d51cSWill Fiveash                          __FUNCTION__, retval, error_message(retval));
8359e11d51cSWill Fiveash                 goto cleanup;
8369e11d51cSWill Fiveash             }
8379e11d51cSWill Fiveash         }
838159d09a2SMark Phalan     } else {
839159d09a2SMark Phalan 	retval = ENOENT;    /* XXX */
840159d09a2SMark Phalan 	goto cleanup;
841159d09a2SMark Phalan     }
842159d09a2SMark Phalan 
843159d09a2SMark Phalan     retval = 0;
844159d09a2SMark Phalan cleanup:
845159d09a2SMark Phalan     if (rules != NULL)
846159d09a2SMark Phalan 	profile_free_list(rules);
847159d09a2SMark Phalan     if (rs != NULL)
848159d09a2SMark Phalan 	/* Solaris Kerberos */
849159d09a2SMark Phalan 	(void) free_rule_set(context, rs);
850159d09a2SMark Phalan     if (matchdata != NULL)
851159d09a2SMark Phalan 	(void) free_all_cert_matching_data(context, matchdata);
852159d09a2SMark Phalan     return retval;
853159d09a2SMark Phalan }
854