xref: /freebsd/crypto/krb5/src/plugins/preauth/pkinit/pkinit_matching.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 <errno.h>
33*7f2fe78bSCy Schubert #include <string.h>
34*7f2fe78bSCy Schubert #include <stdio.h>
35*7f2fe78bSCy Schubert #include <stdlib.h>
36*7f2fe78bSCy Schubert #include <unistd.h>
37*7f2fe78bSCy Schubert #include <regex.h>
38*7f2fe78bSCy Schubert #include "pkinit.h"
39*7f2fe78bSCy Schubert 
40*7f2fe78bSCy Schubert typedef struct _pkinit_cert_info pkinit_cert_info;
41*7f2fe78bSCy Schubert 
42*7f2fe78bSCy Schubert typedef enum {
43*7f2fe78bSCy Schubert     kw_undefined = 0,
44*7f2fe78bSCy Schubert     kw_subject = 1,
45*7f2fe78bSCy Schubert     kw_issuer = 2,
46*7f2fe78bSCy Schubert     kw_san = 3,
47*7f2fe78bSCy Schubert     kw_eku = 4,
48*7f2fe78bSCy Schubert     kw_ku = 5
49*7f2fe78bSCy Schubert } keyword_type;
50*7f2fe78bSCy Schubert 
51*7f2fe78bSCy Schubert static char *
keyword2string(unsigned int kw)52*7f2fe78bSCy Schubert keyword2string(unsigned int kw)
53*7f2fe78bSCy Schubert {
54*7f2fe78bSCy Schubert     switch(kw) {
55*7f2fe78bSCy Schubert     case kw_undefined: return "NONE"; break;
56*7f2fe78bSCy Schubert     case kw_subject: return "SUBJECT"; break;
57*7f2fe78bSCy Schubert     case kw_issuer: return "ISSUER"; break;
58*7f2fe78bSCy Schubert     case kw_san: return "SAN"; break;
59*7f2fe78bSCy Schubert     case kw_eku: return "EKU"; break;
60*7f2fe78bSCy Schubert     case kw_ku: return "KU"; break;
61*7f2fe78bSCy Schubert     default: return "INVALID"; break;
62*7f2fe78bSCy Schubert     }
63*7f2fe78bSCy Schubert }
64*7f2fe78bSCy Schubert typedef enum {
65*7f2fe78bSCy Schubert     relation_none = 0,
66*7f2fe78bSCy Schubert     relation_and = 1,
67*7f2fe78bSCy Schubert     relation_or = 2
68*7f2fe78bSCy Schubert } relation_type;
69*7f2fe78bSCy Schubert 
70*7f2fe78bSCy Schubert static char *
relation2string(unsigned int rel)71*7f2fe78bSCy Schubert relation2string(unsigned int rel)
72*7f2fe78bSCy Schubert {
73*7f2fe78bSCy Schubert     switch(rel) {
74*7f2fe78bSCy Schubert     case relation_none: return "NONE"; break;
75*7f2fe78bSCy Schubert     case relation_and: return "AND"; break;
76*7f2fe78bSCy Schubert     case relation_or: return "OR"; break;
77*7f2fe78bSCy Schubert     default: return "INVALID"; break;
78*7f2fe78bSCy Schubert     }
79*7f2fe78bSCy Schubert }
80*7f2fe78bSCy Schubert 
81*7f2fe78bSCy Schubert typedef enum {
82*7f2fe78bSCy Schubert     kwvaltype_undefined = 0,
83*7f2fe78bSCy Schubert     kwvaltype_regexp = 1,
84*7f2fe78bSCy Schubert     kwvaltype_list = 2
85*7f2fe78bSCy Schubert } kw_value_type;
86*7f2fe78bSCy Schubert 
87*7f2fe78bSCy Schubert static char *
kwval2string(unsigned int kwval)88*7f2fe78bSCy Schubert kwval2string(unsigned int kwval)
89*7f2fe78bSCy Schubert {
90*7f2fe78bSCy Schubert     switch(kwval) {
91*7f2fe78bSCy Schubert     case kwvaltype_undefined: return "NONE"; break;
92*7f2fe78bSCy Schubert     case kwvaltype_regexp: return "REGEXP"; break;
93*7f2fe78bSCy Schubert     case kwvaltype_list: return "LIST"; break;
94*7f2fe78bSCy Schubert     default: return "INVALID"; break;
95*7f2fe78bSCy Schubert     }
96*7f2fe78bSCy Schubert }
97*7f2fe78bSCy Schubert 
98*7f2fe78bSCy Schubert struct keyword_desc {
99*7f2fe78bSCy Schubert     const char *value;
100*7f2fe78bSCy Schubert     size_t length;
101*7f2fe78bSCy Schubert     keyword_type kwtype;
102*7f2fe78bSCy Schubert     kw_value_type kwvaltype;
103*7f2fe78bSCy Schubert } matching_keywords[] = {
104*7f2fe78bSCy Schubert     { "<KU>",       4, kw_ku, kwvaltype_list },
105*7f2fe78bSCy Schubert     { "<EKU>",      5, kw_eku, kwvaltype_list },
106*7f2fe78bSCy Schubert     { "<SAN>",      5, kw_san, kwvaltype_regexp },
107*7f2fe78bSCy Schubert     { "<ISSUER>",   8, kw_issuer, kwvaltype_regexp },
108*7f2fe78bSCy Schubert     { "<SUBJECT>",  9, kw_subject, kwvaltype_regexp },
109*7f2fe78bSCy Schubert     { NULL, 0, kw_undefined, kwvaltype_undefined},
110*7f2fe78bSCy Schubert };
111*7f2fe78bSCy Schubert 
112*7f2fe78bSCy Schubert struct ku_desc {
113*7f2fe78bSCy Schubert     const char *value;
114*7f2fe78bSCy Schubert     size_t length;
115*7f2fe78bSCy Schubert     unsigned int bitval;
116*7f2fe78bSCy Schubert };
117*7f2fe78bSCy Schubert 
118*7f2fe78bSCy Schubert struct ku_desc ku_keywords[] = {
119*7f2fe78bSCy Schubert     { "digitalSignature",   16, PKINIT_KU_DIGITALSIGNATURE },
120*7f2fe78bSCy Schubert     { "keyEncipherment",    15, PKINIT_KU_KEYENCIPHERMENT },
121*7f2fe78bSCy Schubert     { NULL, 0, 0 },
122*7f2fe78bSCy Schubert };
123*7f2fe78bSCy Schubert 
124*7f2fe78bSCy Schubert struct ku_desc  eku_keywords[] = {
125*7f2fe78bSCy Schubert     { "pkinit",             6,  PKINIT_EKU_PKINIT },
126*7f2fe78bSCy Schubert     { "msScLogin",          9,  PKINIT_EKU_MSSCLOGIN },
127*7f2fe78bSCy Schubert     { "clientAuth",         10, PKINIT_EKU_CLIENTAUTH },
128*7f2fe78bSCy Schubert     { "emailProtection",    15, PKINIT_EKU_EMAILPROTECTION },
129*7f2fe78bSCy Schubert     { NULL, 0, 0 },
130*7f2fe78bSCy Schubert };
131*7f2fe78bSCy Schubert 
132*7f2fe78bSCy Schubert /* Rule component */
133*7f2fe78bSCy Schubert typedef struct _rule_component {
134*7f2fe78bSCy Schubert     struct _rule_component *next;
135*7f2fe78bSCy Schubert     keyword_type kw_type;
136*7f2fe78bSCy Schubert     kw_value_type kwval_type;
137*7f2fe78bSCy Schubert     regex_t regexp;         /* Compiled regular expression */
138*7f2fe78bSCy Schubert     char *regsrc;           /* The regular expression source (for debugging) */
139*7f2fe78bSCy Schubert     unsigned int ku_bits;
140*7f2fe78bSCy Schubert     unsigned int eku_bits;
141*7f2fe78bSCy Schubert } rule_component;
142*7f2fe78bSCy Schubert 
143*7f2fe78bSCy Schubert /* Set rule components */
144*7f2fe78bSCy Schubert typedef struct _rule_set {
145*7f2fe78bSCy Schubert     relation_type relation;
146*7f2fe78bSCy Schubert     int num_crs;
147*7f2fe78bSCy Schubert     rule_component *crs;
148*7f2fe78bSCy Schubert } rule_set;
149*7f2fe78bSCy Schubert 
150*7f2fe78bSCy Schubert static krb5_error_code
free_rule_component(krb5_context context,rule_component * rc)151*7f2fe78bSCy Schubert free_rule_component(krb5_context context,
152*7f2fe78bSCy Schubert                     rule_component *rc)
153*7f2fe78bSCy Schubert {
154*7f2fe78bSCy Schubert     if (rc == NULL)
155*7f2fe78bSCy Schubert         return 0;
156*7f2fe78bSCy Schubert 
157*7f2fe78bSCy Schubert     if (rc->kwval_type == kwvaltype_regexp) {
158*7f2fe78bSCy Schubert         free(rc->regsrc);
159*7f2fe78bSCy Schubert         regfree(&rc->regexp);
160*7f2fe78bSCy Schubert     }
161*7f2fe78bSCy Schubert     free(rc);
162*7f2fe78bSCy Schubert     return 0;
163*7f2fe78bSCy Schubert }
164*7f2fe78bSCy Schubert 
165*7f2fe78bSCy Schubert static krb5_error_code
free_rule_set(krb5_context context,rule_set * rs)166*7f2fe78bSCy Schubert free_rule_set(krb5_context context,
167*7f2fe78bSCy Schubert               rule_set *rs)
168*7f2fe78bSCy Schubert {
169*7f2fe78bSCy Schubert     rule_component *rc, *trc;
170*7f2fe78bSCy Schubert 
171*7f2fe78bSCy Schubert     if (rs == NULL)
172*7f2fe78bSCy Schubert         return 0;
173*7f2fe78bSCy Schubert     for (rc = rs->crs; rc != NULL;) {
174*7f2fe78bSCy Schubert         trc = rc->next;
175*7f2fe78bSCy Schubert         free_rule_component(context, rc);
176*7f2fe78bSCy Schubert         rc = trc;
177*7f2fe78bSCy Schubert     }
178*7f2fe78bSCy Schubert     free(rs);
179*7f2fe78bSCy Schubert     return 0;
180*7f2fe78bSCy Schubert }
181*7f2fe78bSCy Schubert 
182*7f2fe78bSCy Schubert static krb5_error_code
parse_list_value(krb5_context context,keyword_type type,char * value,rule_component * rc)183*7f2fe78bSCy Schubert parse_list_value(krb5_context context,
184*7f2fe78bSCy Schubert                  keyword_type type,
185*7f2fe78bSCy Schubert                  char *value,
186*7f2fe78bSCy Schubert                  rule_component *rc)
187*7f2fe78bSCy Schubert {
188*7f2fe78bSCy Schubert     krb5_error_code retval;
189*7f2fe78bSCy Schubert     char *comma;
190*7f2fe78bSCy Schubert     struct ku_desc *ku = NULL;
191*7f2fe78bSCy Schubert     int found;
192*7f2fe78bSCy Schubert     size_t len;
193*7f2fe78bSCy Schubert     unsigned int *bitptr;
194*7f2fe78bSCy Schubert 
195*7f2fe78bSCy Schubert 
196*7f2fe78bSCy Schubert     if (value == NULL || value[0] == '\0') {
197*7f2fe78bSCy Schubert         pkiDebug("%s: Missing or empty value for list keyword type %d\n",
198*7f2fe78bSCy Schubert                  __FUNCTION__, type);
199*7f2fe78bSCy Schubert         retval = EINVAL;
200*7f2fe78bSCy Schubert         goto out;
201*7f2fe78bSCy Schubert     }
202*7f2fe78bSCy Schubert 
203*7f2fe78bSCy Schubert     if (type == kw_eku) {
204*7f2fe78bSCy Schubert         bitptr = &rc->eku_bits;
205*7f2fe78bSCy Schubert     } else if (type == kw_ku) {
206*7f2fe78bSCy Schubert         bitptr = &rc->ku_bits;
207*7f2fe78bSCy Schubert     } else {
208*7f2fe78bSCy Schubert         pkiDebug("%s: Unknown list keyword type %d\n", __FUNCTION__, type);
209*7f2fe78bSCy Schubert         retval = EINVAL;
210*7f2fe78bSCy Schubert         goto out;
211*7f2fe78bSCy Schubert     }
212*7f2fe78bSCy Schubert 
213*7f2fe78bSCy Schubert     do {
214*7f2fe78bSCy Schubert         found = 0;
215*7f2fe78bSCy Schubert         comma = strchr(value, ',');
216*7f2fe78bSCy Schubert         if (comma != NULL)
217*7f2fe78bSCy Schubert             len = comma - value;
218*7f2fe78bSCy Schubert         else
219*7f2fe78bSCy Schubert             len = strlen(value);
220*7f2fe78bSCy Schubert 
221*7f2fe78bSCy Schubert         if (type == kw_eku) {
222*7f2fe78bSCy Schubert             ku = eku_keywords;
223*7f2fe78bSCy Schubert         } else if (type == kw_ku) {
224*7f2fe78bSCy Schubert             ku = ku_keywords;
225*7f2fe78bSCy Schubert         }
226*7f2fe78bSCy Schubert 
227*7f2fe78bSCy Schubert         for (; ku->value != NULL; ku++) {
228*7f2fe78bSCy Schubert             if (strncasecmp(value, ku->value, len) == 0) {
229*7f2fe78bSCy Schubert                 *bitptr |= ku->bitval;
230*7f2fe78bSCy Schubert                 found = 1;
231*7f2fe78bSCy Schubert                 pkiDebug("%s: Found value '%s', bitfield is now 0x%x\n",
232*7f2fe78bSCy Schubert                          __FUNCTION__, ku->value, *bitptr);
233*7f2fe78bSCy Schubert                 break;
234*7f2fe78bSCy Schubert             }
235*7f2fe78bSCy Schubert         }
236*7f2fe78bSCy Schubert         if (found) {
237*7f2fe78bSCy Schubert             value += ku->length;
238*7f2fe78bSCy Schubert             if (*value == ',')
239*7f2fe78bSCy Schubert                 value += 1;
240*7f2fe78bSCy Schubert         } else {
241*7f2fe78bSCy Schubert             pkiDebug("%s: Urecognized value '%s'\n", __FUNCTION__, value);
242*7f2fe78bSCy Schubert             retval = EINVAL;
243*7f2fe78bSCy Schubert             goto out;
244*7f2fe78bSCy Schubert         }
245*7f2fe78bSCy Schubert     } while (found && *value != '\0');
246*7f2fe78bSCy Schubert 
247*7f2fe78bSCy Schubert     retval = 0;
248*7f2fe78bSCy Schubert out:
249*7f2fe78bSCy Schubert     pkiDebug("%s: returning %d\n", __FUNCTION__, retval);
250*7f2fe78bSCy Schubert     return retval;
251*7f2fe78bSCy Schubert }
252*7f2fe78bSCy Schubert 
253*7f2fe78bSCy Schubert static krb5_error_code
parse_rule_component(krb5_context context,const char ** rule,int * remaining,rule_component ** ret_rule)254*7f2fe78bSCy Schubert parse_rule_component(krb5_context context,
255*7f2fe78bSCy Schubert                      const char **rule,
256*7f2fe78bSCy Schubert                      int *remaining,
257*7f2fe78bSCy Schubert                      rule_component **ret_rule)
258*7f2fe78bSCy Schubert {
259*7f2fe78bSCy Schubert     krb5_error_code retval;
260*7f2fe78bSCy Schubert     rule_component *rc = NULL;
261*7f2fe78bSCy Schubert     keyword_type kw_type;
262*7f2fe78bSCy Schubert     kw_value_type kwval_type;
263*7f2fe78bSCy Schubert     char err_buf[128];
264*7f2fe78bSCy Schubert     int ret;
265*7f2fe78bSCy Schubert     struct keyword_desc *kw, *nextkw;
266*7f2fe78bSCy Schubert     char *nk;
267*7f2fe78bSCy Schubert     int found_next_kw = 0;
268*7f2fe78bSCy Schubert     char *value = NULL;
269*7f2fe78bSCy Schubert     size_t len;
270*7f2fe78bSCy Schubert 
271*7f2fe78bSCy Schubert     for (kw = matching_keywords; kw->value != NULL; kw++) {
272*7f2fe78bSCy Schubert         if (strncmp(*rule, kw->value, kw->length) == 0) {
273*7f2fe78bSCy Schubert             kw_type = kw->kwtype;
274*7f2fe78bSCy Schubert             kwval_type = kw->kwvaltype;
275*7f2fe78bSCy Schubert             *rule += kw->length;
276*7f2fe78bSCy Schubert             *remaining -= kw->length;
277*7f2fe78bSCy Schubert             break;
278*7f2fe78bSCy Schubert         }
279*7f2fe78bSCy Schubert     }
280*7f2fe78bSCy Schubert     if (kw->value == NULL) {
281*7f2fe78bSCy Schubert         pkiDebug("%s: Missing or invalid keyword in rule '%s'\n",
282*7f2fe78bSCy Schubert                  __FUNCTION__, *rule);
283*7f2fe78bSCy Schubert         retval = ENOENT;
284*7f2fe78bSCy Schubert         goto out;
285*7f2fe78bSCy Schubert     }
286*7f2fe78bSCy Schubert 
287*7f2fe78bSCy Schubert     pkiDebug("%s: found keyword '%s'\n", __FUNCTION__, kw->value);
288*7f2fe78bSCy Schubert 
289*7f2fe78bSCy Schubert     rc = calloc(1, sizeof(*rc));
290*7f2fe78bSCy Schubert     if (rc == NULL) {
291*7f2fe78bSCy Schubert         retval = ENOMEM;
292*7f2fe78bSCy Schubert         goto out;
293*7f2fe78bSCy Schubert     }
294*7f2fe78bSCy Schubert     rc->next = NULL;
295*7f2fe78bSCy Schubert     rc->kw_type = kw_type;
296*7f2fe78bSCy Schubert     rc->kwval_type = kwval_type;
297*7f2fe78bSCy Schubert 
298*7f2fe78bSCy Schubert     /*
299*7f2fe78bSCy Schubert      * Before processing the value for this keyword,
300*7f2fe78bSCy Schubert      * (compiling the regular expression or processing the list)
301*7f2fe78bSCy Schubert      * we need to find the end of it.  That means parsing for the
302*7f2fe78bSCy Schubert      * beginning of the next keyword (or the end of the rule).
303*7f2fe78bSCy Schubert      */
304*7f2fe78bSCy Schubert     nk = strchr(*rule, '<');
305*7f2fe78bSCy Schubert     while (nk != NULL) {
306*7f2fe78bSCy Schubert         /* Possibly another keyword, check it out */
307*7f2fe78bSCy Schubert         for (nextkw = matching_keywords; nextkw->value != NULL; nextkw++) {
308*7f2fe78bSCy Schubert             if (strncmp(nk, nextkw->value, nextkw->length) == 0) {
309*7f2fe78bSCy Schubert                 /* Found a keyword, nk points to the beginning */
310*7f2fe78bSCy Schubert                 found_next_kw = 1;
311*7f2fe78bSCy Schubert                 break;  /* Need to break out of the while! */
312*7f2fe78bSCy Schubert             }
313*7f2fe78bSCy Schubert         }
314*7f2fe78bSCy Schubert         if (!found_next_kw)
315*7f2fe78bSCy Schubert             nk = strchr(nk+1, '<');     /* keep looking */
316*7f2fe78bSCy Schubert         else
317*7f2fe78bSCy Schubert             break;
318*7f2fe78bSCy Schubert     }
319*7f2fe78bSCy Schubert 
320*7f2fe78bSCy Schubert     if (nk != NULL && found_next_kw)
321*7f2fe78bSCy Schubert         len = (nk - *rule);
322*7f2fe78bSCy Schubert     else
323*7f2fe78bSCy Schubert         len = (*remaining);
324*7f2fe78bSCy Schubert 
325*7f2fe78bSCy Schubert     if (len == 0) {
326*7f2fe78bSCy Schubert         pkiDebug("%s: Missing value for keyword '%s'\n",
327*7f2fe78bSCy Schubert                  __FUNCTION__, kw->value);
328*7f2fe78bSCy Schubert         retval = EINVAL;
329*7f2fe78bSCy Schubert         goto out;
330*7f2fe78bSCy Schubert     }
331*7f2fe78bSCy Schubert 
332*7f2fe78bSCy Schubert     value = calloc(1, len+1);
333*7f2fe78bSCy Schubert     if (value == NULL) {
334*7f2fe78bSCy Schubert         retval = ENOMEM;
335*7f2fe78bSCy Schubert         goto out;
336*7f2fe78bSCy Schubert     }
337*7f2fe78bSCy Schubert     memcpy(value, *rule, len);
338*7f2fe78bSCy Schubert     *remaining -= len;
339*7f2fe78bSCy Schubert     *rule += len;
340*7f2fe78bSCy Schubert     pkiDebug("%s: found value '%s'\n", __FUNCTION__, value);
341*7f2fe78bSCy Schubert 
342*7f2fe78bSCy Schubert     if (kw->kwvaltype == kwvaltype_regexp) {
343*7f2fe78bSCy Schubert         ret = regcomp(&rc->regexp, value, REG_EXTENDED);
344*7f2fe78bSCy Schubert         if (ret) {
345*7f2fe78bSCy Schubert             regerror(ret, &rc->regexp, err_buf, sizeof(err_buf));
346*7f2fe78bSCy Schubert             pkiDebug("%s: Error compiling reg-exp '%s': %s\n",
347*7f2fe78bSCy Schubert                      __FUNCTION__, value, err_buf);
348*7f2fe78bSCy Schubert             retval = ret;
349*7f2fe78bSCy Schubert             goto out;
350*7f2fe78bSCy Schubert         }
351*7f2fe78bSCy Schubert         rc->regsrc = strdup(value);
352*7f2fe78bSCy Schubert         if (rc->regsrc == NULL) {
353*7f2fe78bSCy Schubert             retval = ENOMEM;
354*7f2fe78bSCy Schubert             goto out;
355*7f2fe78bSCy Schubert         }
356*7f2fe78bSCy Schubert     } else if (kw->kwvaltype == kwvaltype_list) {
357*7f2fe78bSCy Schubert         retval = parse_list_value(context, rc->kw_type, value, rc);
358*7f2fe78bSCy Schubert         if (retval) {
359*7f2fe78bSCy Schubert             pkiDebug("%s: Error %d, parsing list values for keyword %s\n",
360*7f2fe78bSCy Schubert                      __FUNCTION__, retval, kw->value);
361*7f2fe78bSCy Schubert             goto out;
362*7f2fe78bSCy Schubert         }
363*7f2fe78bSCy Schubert     }
364*7f2fe78bSCy Schubert 
365*7f2fe78bSCy Schubert     *ret_rule = rc;
366*7f2fe78bSCy Schubert     retval = 0;
367*7f2fe78bSCy Schubert out:
368*7f2fe78bSCy Schubert     free(value);
369*7f2fe78bSCy Schubert     if (retval && rc != NULL)
370*7f2fe78bSCy Schubert         free_rule_component(context, rc);
371*7f2fe78bSCy Schubert     pkiDebug("%s: returning %d\n", __FUNCTION__, retval);
372*7f2fe78bSCy Schubert     return retval;
373*7f2fe78bSCy Schubert }
374*7f2fe78bSCy Schubert 
375*7f2fe78bSCy Schubert static krb5_error_code
parse_rule_set(krb5_context context,const char * rule_in,rule_set ** out_rs)376*7f2fe78bSCy Schubert parse_rule_set(krb5_context context,
377*7f2fe78bSCy Schubert                const char *rule_in,
378*7f2fe78bSCy Schubert                rule_set **out_rs)
379*7f2fe78bSCy Schubert {
380*7f2fe78bSCy Schubert     const char *rule;
381*7f2fe78bSCy Schubert     int remaining;
382*7f2fe78bSCy Schubert     krb5_error_code ret, retval;
383*7f2fe78bSCy Schubert     rule_component *rc = NULL, *trc;
384*7f2fe78bSCy Schubert     rule_set *rs;
385*7f2fe78bSCy Schubert 
386*7f2fe78bSCy Schubert 
387*7f2fe78bSCy Schubert     if (rule_in == NULL)
388*7f2fe78bSCy Schubert         return EINVAL;
389*7f2fe78bSCy Schubert     rule = rule_in;
390*7f2fe78bSCy Schubert     remaining = strlen(rule);
391*7f2fe78bSCy Schubert 
392*7f2fe78bSCy Schubert     rs = calloc(1, sizeof(*rs));
393*7f2fe78bSCy Schubert     if (rs == NULL) {
394*7f2fe78bSCy Schubert         retval = ENOMEM;
395*7f2fe78bSCy Schubert         goto cleanup;
396*7f2fe78bSCy Schubert     }
397*7f2fe78bSCy Schubert 
398*7f2fe78bSCy Schubert     rs->relation = relation_none;
399*7f2fe78bSCy Schubert     if (remaining > 1) {
400*7f2fe78bSCy Schubert         if (rule[0] == '&' && rule[1] == '&') {
401*7f2fe78bSCy Schubert             rs->relation = relation_and;
402*7f2fe78bSCy Schubert             rule += 2;
403*7f2fe78bSCy Schubert             remaining -= 2;
404*7f2fe78bSCy Schubert         } else if (rule_in[0] == '|' && rule_in[1] == '|') {
405*7f2fe78bSCy Schubert             rs->relation = relation_or;
406*7f2fe78bSCy Schubert             rule +=2;
407*7f2fe78bSCy Schubert             remaining -= 2;
408*7f2fe78bSCy Schubert         }
409*7f2fe78bSCy Schubert     }
410*7f2fe78bSCy Schubert     rs->num_crs = 0;
411*7f2fe78bSCy Schubert     while (remaining > 0) {
412*7f2fe78bSCy Schubert         if (rs->relation == relation_none && rs->num_crs > 0) {
413*7f2fe78bSCy Schubert             pkiDebug("%s: Assuming AND relation for multiple components in rule '%s'\n",
414*7f2fe78bSCy Schubert                      __FUNCTION__, rule_in);
415*7f2fe78bSCy Schubert             rs->relation = relation_and;
416*7f2fe78bSCy Schubert         }
417*7f2fe78bSCy Schubert         ret = parse_rule_component(context, &rule, &remaining, &rc);
418*7f2fe78bSCy Schubert         if (ret) {
419*7f2fe78bSCy Schubert             retval = ret;
420*7f2fe78bSCy Schubert             goto cleanup;
421*7f2fe78bSCy Schubert         }
422*7f2fe78bSCy Schubert         pkiDebug("%s: After parse_rule_component, remaining %d, rule '%s'\n",
423*7f2fe78bSCy Schubert                  __FUNCTION__, remaining, rule);
424*7f2fe78bSCy Schubert         rs->num_crs++;
425*7f2fe78bSCy Schubert 
426*7f2fe78bSCy Schubert         /*
427*7f2fe78bSCy Schubert          * Chain the new component on the end (order matters since
428*7f2fe78bSCy Schubert          * we can short-circuit an OR or an AND relation if an
429*7f2fe78bSCy Schubert          * earlier check passes
430*7f2fe78bSCy Schubert          */
431*7f2fe78bSCy Schubert         for (trc = rs->crs; trc != NULL && trc->next != NULL; trc = trc->next);
432*7f2fe78bSCy Schubert         if (trc == NULL)
433*7f2fe78bSCy Schubert             rs->crs = rc;
434*7f2fe78bSCy Schubert         else {
435*7f2fe78bSCy Schubert             trc->next = rc;
436*7f2fe78bSCy Schubert         }
437*7f2fe78bSCy Schubert     }
438*7f2fe78bSCy Schubert 
439*7f2fe78bSCy Schubert     *out_rs = rs;
440*7f2fe78bSCy Schubert 
441*7f2fe78bSCy Schubert     retval = 0;
442*7f2fe78bSCy Schubert cleanup:
443*7f2fe78bSCy Schubert     if (retval && rs != NULL) {
444*7f2fe78bSCy Schubert         free_rule_set(context, rs);
445*7f2fe78bSCy Schubert     }
446*7f2fe78bSCy Schubert     pkiDebug("%s: returning %d\n", __FUNCTION__, retval);
447*7f2fe78bSCy Schubert     return retval;
448*7f2fe78bSCy Schubert }
449*7f2fe78bSCy Schubert 
450*7f2fe78bSCy Schubert static int
regexp_match(krb5_context context,rule_component * rc,char * value,int idx)451*7f2fe78bSCy Schubert regexp_match(krb5_context context, rule_component *rc, char *value, int idx)
452*7f2fe78bSCy Schubert {
453*7f2fe78bSCy Schubert     int code;
454*7f2fe78bSCy Schubert 
455*7f2fe78bSCy Schubert     code = regexec(&rc->regexp, value, 0, NULL, 0);
456*7f2fe78bSCy Schubert 
457*7f2fe78bSCy Schubert     if (code == 0) {
458*7f2fe78bSCy Schubert         TRACE_PKINIT_REGEXP_MATCH(context, keyword2string(rc->kw_type),
459*7f2fe78bSCy Schubert                                   rc->regsrc, value, idx);
460*7f2fe78bSCy Schubert     } else {
461*7f2fe78bSCy Schubert         TRACE_PKINIT_REGEXP_NOMATCH(context, keyword2string(rc->kw_type),
462*7f2fe78bSCy Schubert                                     rc->regsrc, value, idx);
463*7f2fe78bSCy Schubert     }
464*7f2fe78bSCy Schubert 
465*7f2fe78bSCy Schubert     return (code == 0 ? 1: 0);
466*7f2fe78bSCy Schubert }
467*7f2fe78bSCy Schubert 
468*7f2fe78bSCy Schubert static int
component_match(krb5_context context,rule_component * rc,pkinit_cert_matching_data * md,int idx)469*7f2fe78bSCy Schubert component_match(krb5_context context, rule_component *rc,
470*7f2fe78bSCy Schubert                 pkinit_cert_matching_data *md, int idx)
471*7f2fe78bSCy Schubert {
472*7f2fe78bSCy Schubert     int match = 0;
473*7f2fe78bSCy Schubert     int i;
474*7f2fe78bSCy Schubert     char *princ_string;
475*7f2fe78bSCy Schubert 
476*7f2fe78bSCy Schubert     switch (rc->kwval_type) {
477*7f2fe78bSCy Schubert     case kwvaltype_regexp:
478*7f2fe78bSCy Schubert         switch (rc->kw_type) {
479*7f2fe78bSCy Schubert         case kw_subject:
480*7f2fe78bSCy Schubert             match = regexp_match(context, rc, md->subject_dn, idx);
481*7f2fe78bSCy Schubert             break;
482*7f2fe78bSCy Schubert         case kw_issuer:
483*7f2fe78bSCy Schubert             match = regexp_match(context, rc, md->issuer_dn, idx);
484*7f2fe78bSCy Schubert             break;
485*7f2fe78bSCy Schubert         case kw_san:
486*7f2fe78bSCy Schubert             for (i = 0; md->sans != NULL && md->sans[i] != NULL; i++) {
487*7f2fe78bSCy Schubert                 krb5_unparse_name(context, md->sans[i], &princ_string);
488*7f2fe78bSCy Schubert                 match = regexp_match(context, rc, princ_string, idx);
489*7f2fe78bSCy Schubert                 krb5_free_unparsed_name(context, princ_string);
490*7f2fe78bSCy Schubert                 if (match)
491*7f2fe78bSCy Schubert                     break;
492*7f2fe78bSCy Schubert             }
493*7f2fe78bSCy Schubert             for (i = 0; md->upns != NULL && md->upns[i] != NULL; i++) {
494*7f2fe78bSCy Schubert                 match = regexp_match(context, rc, md->upns[i], idx);
495*7f2fe78bSCy Schubert                 if (match)
496*7f2fe78bSCy Schubert                     break;
497*7f2fe78bSCy Schubert             }
498*7f2fe78bSCy Schubert             break;
499*7f2fe78bSCy Schubert         default:
500*7f2fe78bSCy Schubert             pkiDebug("%s: keyword %s, keyword value %s mismatch\n",
501*7f2fe78bSCy Schubert                      __FUNCTION__, keyword2string(rc->kw_type),
502*7f2fe78bSCy Schubert                      kwval2string(kwvaltype_regexp));
503*7f2fe78bSCy Schubert             break;
504*7f2fe78bSCy Schubert         }
505*7f2fe78bSCy Schubert         break;
506*7f2fe78bSCy Schubert     case kwvaltype_list:
507*7f2fe78bSCy Schubert         switch(rc->kw_type) {
508*7f2fe78bSCy Schubert         case kw_eku:
509*7f2fe78bSCy Schubert             pkiDebug("%s: checking %s: rule 0x%08x, cert 0x%08x\n",
510*7f2fe78bSCy Schubert                      __FUNCTION__, keyword2string(rc->kw_type),
511*7f2fe78bSCy Schubert                      rc->eku_bits, md->eku_bits);
512*7f2fe78bSCy Schubert             if ((rc->eku_bits & md->eku_bits) == rc->eku_bits)
513*7f2fe78bSCy Schubert                 match = 1;
514*7f2fe78bSCy Schubert             break;
515*7f2fe78bSCy Schubert         case kw_ku:
516*7f2fe78bSCy Schubert             pkiDebug("%s: checking %s: rule 0x%08x, cert 0x%08x\n",
517*7f2fe78bSCy Schubert                      __FUNCTION__, keyword2string(rc->kw_type),
518*7f2fe78bSCy Schubert                      rc->ku_bits, md->ku_bits);
519*7f2fe78bSCy Schubert             if ((rc->ku_bits & md->ku_bits) == rc->ku_bits)
520*7f2fe78bSCy Schubert                 match = 1;
521*7f2fe78bSCy Schubert             break;
522*7f2fe78bSCy Schubert         default:
523*7f2fe78bSCy Schubert             pkiDebug("%s: keyword %s, keyword value %s mismatch\n",
524*7f2fe78bSCy Schubert                      __FUNCTION__, keyword2string(rc->kw_type),
525*7f2fe78bSCy Schubert                      kwval2string(kwvaltype_regexp));
526*7f2fe78bSCy Schubert             break;
527*7f2fe78bSCy Schubert         }
528*7f2fe78bSCy Schubert         break;
529*7f2fe78bSCy Schubert     default:
530*7f2fe78bSCy Schubert         pkiDebug("%s: unknown keyword value type %d\n",
531*7f2fe78bSCy Schubert                  __FUNCTION__, rc->kwval_type);
532*7f2fe78bSCy Schubert         break;
533*7f2fe78bSCy Schubert     }
534*7f2fe78bSCy Schubert     pkiDebug("%s: returning match = %d\n", __FUNCTION__, match);
535*7f2fe78bSCy Schubert     return match;
536*7f2fe78bSCy Schubert }
537*7f2fe78bSCy Schubert /*
538*7f2fe78bSCy Schubert  * Returns match_found == 1 only if exactly one certificate matches
539*7f2fe78bSCy Schubert  * the given rule
540*7f2fe78bSCy Schubert  */
541*7f2fe78bSCy Schubert 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,size_t * match_index)542*7f2fe78bSCy Schubert check_all_certs(krb5_context context,
543*7f2fe78bSCy Schubert                 pkinit_plg_crypto_context plg_cryptoctx,
544*7f2fe78bSCy Schubert                 pkinit_req_crypto_context req_cryptoctx,
545*7f2fe78bSCy Schubert                 pkinit_identity_crypto_context id_cryptoctx,
546*7f2fe78bSCy Schubert                 krb5_principal princ,
547*7f2fe78bSCy Schubert                 rule_set *rs,   /* rule to check */
548*7f2fe78bSCy Schubert                 pkinit_cert_matching_data **matchdata,
549*7f2fe78bSCy Schubert                 int *match_found,
550*7f2fe78bSCy Schubert                 size_t *match_index)
551*7f2fe78bSCy Schubert {
552*7f2fe78bSCy Schubert     krb5_error_code retval;
553*7f2fe78bSCy Schubert     pkinit_cert_matching_data *md;
554*7f2fe78bSCy Schubert     int i;
555*7f2fe78bSCy Schubert     int comp_match = 0;
556*7f2fe78bSCy Schubert     int total_cert_matches = 0;
557*7f2fe78bSCy Schubert     rule_component *rc;
558*7f2fe78bSCy Schubert     int certs_checked = 0;
559*7f2fe78bSCy Schubert     size_t save_index = 0;
560*7f2fe78bSCy Schubert 
561*7f2fe78bSCy Schubert     if (match_found == NULL || match_index == NULL)
562*7f2fe78bSCy Schubert         return EINVAL;
563*7f2fe78bSCy Schubert 
564*7f2fe78bSCy Schubert     *match_index = 0;
565*7f2fe78bSCy Schubert     *match_found = 0;
566*7f2fe78bSCy Schubert 
567*7f2fe78bSCy Schubert     pkiDebug("%s: matching rule relation is %s with %d components\n",
568*7f2fe78bSCy Schubert              __FUNCTION__, relation2string(rs->relation), rs->num_crs);
569*7f2fe78bSCy Schubert 
570*7f2fe78bSCy Schubert     /*
571*7f2fe78bSCy Schubert      * Loop through all the certs available and count
572*7f2fe78bSCy Schubert      * how many match the rule
573*7f2fe78bSCy Schubert      */
574*7f2fe78bSCy Schubert     for (i = 0, md = matchdata[i]; md != NULL; md = matchdata[++i]) {
575*7f2fe78bSCy Schubert         pkiDebug("%s: subject: '%s'\n", __FUNCTION__, md->subject_dn);
576*7f2fe78bSCy Schubert         certs_checked++;
577*7f2fe78bSCy Schubert         for (rc = rs->crs; rc != NULL; rc = rc->next) {
578*7f2fe78bSCy Schubert             comp_match = component_match(context, rc, md, i);
579*7f2fe78bSCy Schubert             if (comp_match) {
580*7f2fe78bSCy Schubert                 pkiDebug("%s: match for keyword type %s\n",
581*7f2fe78bSCy Schubert                          __FUNCTION__, keyword2string(rc->kw_type));
582*7f2fe78bSCy Schubert             }
583*7f2fe78bSCy Schubert             if (comp_match && rs->relation == relation_or) {
584*7f2fe78bSCy Schubert                 pkiDebug("%s: cert matches rule (OR relation)\n",
585*7f2fe78bSCy Schubert                          __FUNCTION__);
586*7f2fe78bSCy Schubert                 total_cert_matches++;
587*7f2fe78bSCy Schubert                 save_index = i;
588*7f2fe78bSCy Schubert                 goto nextcert;
589*7f2fe78bSCy Schubert             }
590*7f2fe78bSCy Schubert             if (!comp_match && rs->relation == relation_and) {
591*7f2fe78bSCy Schubert                 pkiDebug("%s: cert does not match rule (AND relation)\n",
592*7f2fe78bSCy Schubert                          __FUNCTION__);
593*7f2fe78bSCy Schubert                 goto nextcert;
594*7f2fe78bSCy Schubert             }
595*7f2fe78bSCy Schubert         }
596*7f2fe78bSCy Schubert         if (rc == NULL && comp_match) {
597*7f2fe78bSCy Schubert             pkiDebug("%s: cert matches rule (AND relation)\n", __FUNCTION__);
598*7f2fe78bSCy Schubert             total_cert_matches++;
599*7f2fe78bSCy Schubert             save_index = i;
600*7f2fe78bSCy Schubert         }
601*7f2fe78bSCy Schubert     nextcert:
602*7f2fe78bSCy Schubert         continue;
603*7f2fe78bSCy Schubert     }
604*7f2fe78bSCy Schubert     TRACE_PKINIT_CERT_NUM_MATCHING(context, certs_checked, total_cert_matches);
605*7f2fe78bSCy Schubert     if (total_cert_matches == 1) {
606*7f2fe78bSCy Schubert         *match_found = 1;
607*7f2fe78bSCy Schubert         *match_index = save_index;
608*7f2fe78bSCy Schubert     }
609*7f2fe78bSCy Schubert 
610*7f2fe78bSCy Schubert     retval = 0;
611*7f2fe78bSCy Schubert 
612*7f2fe78bSCy Schubert     pkiDebug("%s: returning %d, match_found %d\n",
613*7f2fe78bSCy Schubert              __FUNCTION__, retval, *match_found);
614*7f2fe78bSCy Schubert     return retval;
615*7f2fe78bSCy Schubert }
616*7f2fe78bSCy Schubert 
617*7f2fe78bSCy Schubert 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)618*7f2fe78bSCy Schubert pkinit_cert_matching(krb5_context context,
619*7f2fe78bSCy Schubert                      pkinit_plg_crypto_context plg_cryptoctx,
620*7f2fe78bSCy Schubert                      pkinit_req_crypto_context req_cryptoctx,
621*7f2fe78bSCy Schubert                      pkinit_identity_crypto_context id_cryptoctx,
622*7f2fe78bSCy Schubert                      krb5_principal princ)
623*7f2fe78bSCy Schubert {
624*7f2fe78bSCy Schubert 
625*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
626*7f2fe78bSCy Schubert     int x;
627*7f2fe78bSCy Schubert     char **rules = NULL;
628*7f2fe78bSCy Schubert     rule_set *rs = NULL;
629*7f2fe78bSCy Schubert     int match_found = 0;
630*7f2fe78bSCy Schubert     pkinit_cert_matching_data **matchdata = NULL;
631*7f2fe78bSCy Schubert     size_t match_index = 0;
632*7f2fe78bSCy Schubert 
633*7f2fe78bSCy Schubert     /* If no matching rules, select the default cert and we're done */
634*7f2fe78bSCy Schubert     pkinit_libdefault_strings(context, krb5_princ_realm(context, princ),
635*7f2fe78bSCy Schubert                               KRB5_CONF_PKINIT_CERT_MATCH, &rules);
636*7f2fe78bSCy Schubert     if (rules == NULL) {
637*7f2fe78bSCy Schubert         pkiDebug("%s: no matching rules found in config file\n", __FUNCTION__);
638*7f2fe78bSCy Schubert         retval = crypto_cert_select_default(context, plg_cryptoctx,
639*7f2fe78bSCy Schubert                                             req_cryptoctx, id_cryptoctx);
640*7f2fe78bSCy Schubert         goto cleanup;
641*7f2fe78bSCy Schubert     }
642*7f2fe78bSCy Schubert 
643*7f2fe78bSCy Schubert     /* parse each rule line one at a time and check all the certs against it */
644*7f2fe78bSCy Schubert     for (x = 0; rules[x] != NULL; x++) {
645*7f2fe78bSCy Schubert         TRACE_PKINIT_CERT_RULE(context, rules[x]);
646*7f2fe78bSCy Schubert 
647*7f2fe78bSCy Schubert         /* Free rules from previous time through... */
648*7f2fe78bSCy Schubert         if (rs != NULL) {
649*7f2fe78bSCy Schubert             free_rule_set(context, rs);
650*7f2fe78bSCy Schubert             rs = NULL;
651*7f2fe78bSCy Schubert         }
652*7f2fe78bSCy Schubert         retval = parse_rule_set(context, rules[x], &rs);
653*7f2fe78bSCy Schubert         if (retval) {
654*7f2fe78bSCy Schubert             if (retval == EINVAL) {
655*7f2fe78bSCy Schubert                 TRACE_PKINIT_CERT_RULE_INVALID(context, rules[x]);
656*7f2fe78bSCy Schubert                 continue;
657*7f2fe78bSCy Schubert             }
658*7f2fe78bSCy Schubert             goto cleanup;
659*7f2fe78bSCy Schubert         }
660*7f2fe78bSCy Schubert 
661*7f2fe78bSCy Schubert         /*
662*7f2fe78bSCy Schubert          * Optimize so that we do not get cert info unless we have
663*7f2fe78bSCy Schubert          * valid rules to check.  Once obtained, keep it around
664*7f2fe78bSCy Schubert          * until we are done.
665*7f2fe78bSCy Schubert          */
666*7f2fe78bSCy Schubert         if (matchdata == NULL) {
667*7f2fe78bSCy Schubert             retval = crypto_cert_get_matching_data(context, plg_cryptoctx,
668*7f2fe78bSCy Schubert                                                    req_cryptoctx, id_cryptoctx,
669*7f2fe78bSCy Schubert                                                    &matchdata);
670*7f2fe78bSCy Schubert             if (retval || matchdata == NULL) {
671*7f2fe78bSCy Schubert                 pkiDebug("%s: Error %d obtaining certificate information\n",
672*7f2fe78bSCy Schubert                          __FUNCTION__, retval);
673*7f2fe78bSCy Schubert                 retval = ENOENT;
674*7f2fe78bSCy Schubert                 goto cleanup;
675*7f2fe78bSCy Schubert             }
676*7f2fe78bSCy Schubert         }
677*7f2fe78bSCy Schubert 
678*7f2fe78bSCy Schubert         retval = check_all_certs(context, plg_cryptoctx, req_cryptoctx,
679*7f2fe78bSCy Schubert                                  id_cryptoctx, princ, rs, matchdata,
680*7f2fe78bSCy Schubert                                  &match_found, &match_index);
681*7f2fe78bSCy Schubert         if (retval) {
682*7f2fe78bSCy Schubert             pkiDebug("%s: Error %d, checking certs against rule '%s'\n",
683*7f2fe78bSCy Schubert                      __FUNCTION__, retval, rules[x]);
684*7f2fe78bSCy Schubert             goto cleanup;
685*7f2fe78bSCy Schubert         }
686*7f2fe78bSCy Schubert         if (match_found) {
687*7f2fe78bSCy Schubert             pkiDebug("%s: We have an exact match with rule '%s'\n",
688*7f2fe78bSCy Schubert                      __FUNCTION__, rules[x]);
689*7f2fe78bSCy Schubert             break;
690*7f2fe78bSCy Schubert         }
691*7f2fe78bSCy Schubert     }
692*7f2fe78bSCy Schubert 
693*7f2fe78bSCy Schubert     if (match_found) {
694*7f2fe78bSCy Schubert         pkiDebug("%s: Selecting the matching cert!\n", __FUNCTION__);
695*7f2fe78bSCy Schubert         retval = crypto_cert_select(context, id_cryptoctx, match_index);
696*7f2fe78bSCy Schubert         if (retval) {
697*7f2fe78bSCy Schubert             pkiDebug("%s: crypto_cert_select error %d, %s\n",
698*7f2fe78bSCy Schubert                      __FUNCTION__, retval, error_message(retval));
699*7f2fe78bSCy Schubert             goto cleanup;
700*7f2fe78bSCy Schubert         }
701*7f2fe78bSCy Schubert     } else {
702*7f2fe78bSCy Schubert         TRACE_PKINIT_NO_MATCHING_CERT(context);
703*7f2fe78bSCy Schubert         retval = ENOENT;    /* XXX */
704*7f2fe78bSCy Schubert         goto cleanup;
705*7f2fe78bSCy Schubert     }
706*7f2fe78bSCy Schubert 
707*7f2fe78bSCy Schubert     retval = 0;
708*7f2fe78bSCy Schubert 
709*7f2fe78bSCy Schubert cleanup:
710*7f2fe78bSCy Schubert     profile_free_list(rules);
711*7f2fe78bSCy Schubert     free_rule_set(context, rs);
712*7f2fe78bSCy Schubert     crypto_cert_free_matching_data_list(context, matchdata);
713*7f2fe78bSCy Schubert     return retval;
714*7f2fe78bSCy Schubert }
715*7f2fe78bSCy Schubert 
716*7f2fe78bSCy Schubert krb5_error_code
pkinit_client_cert_match(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,const char * match_rule,krb5_boolean * matched)717*7f2fe78bSCy Schubert pkinit_client_cert_match(krb5_context context,
718*7f2fe78bSCy Schubert                          pkinit_plg_crypto_context plgctx,
719*7f2fe78bSCy Schubert                          pkinit_req_crypto_context reqctx,
720*7f2fe78bSCy Schubert                          const char *match_rule,
721*7f2fe78bSCy Schubert                          krb5_boolean *matched)
722*7f2fe78bSCy Schubert {
723*7f2fe78bSCy Schubert     krb5_error_code ret;
724*7f2fe78bSCy Schubert     pkinit_cert_matching_data *md = NULL;
725*7f2fe78bSCy Schubert     rule_component *rc = NULL;
726*7f2fe78bSCy Schubert     int comp_match = 0;
727*7f2fe78bSCy Schubert     rule_set *rs = NULL;
728*7f2fe78bSCy Schubert 
729*7f2fe78bSCy Schubert     *matched = FALSE;
730*7f2fe78bSCy Schubert     ret = parse_rule_set(context, match_rule, &rs);
731*7f2fe78bSCy Schubert     if (ret)
732*7f2fe78bSCy Schubert         goto cleanup;
733*7f2fe78bSCy Schubert 
734*7f2fe78bSCy Schubert     ret = crypto_req_cert_matching_data(context, plgctx, reqctx, &md);
735*7f2fe78bSCy Schubert     if (ret)
736*7f2fe78bSCy Schubert         goto cleanup;
737*7f2fe78bSCy Schubert 
738*7f2fe78bSCy Schubert     for (rc = rs->crs; rc != NULL; rc = rc->next) {
739*7f2fe78bSCy Schubert         comp_match = component_match(context, rc, md, 0);
740*7f2fe78bSCy Schubert         if ((comp_match && rs->relation == relation_or) ||
741*7f2fe78bSCy Schubert             (!comp_match && rs->relation == relation_and)) {
742*7f2fe78bSCy Schubert             break;
743*7f2fe78bSCy Schubert         }
744*7f2fe78bSCy Schubert     }
745*7f2fe78bSCy Schubert     *matched = comp_match;
746*7f2fe78bSCy Schubert 
747*7f2fe78bSCy Schubert cleanup:
748*7f2fe78bSCy Schubert     free_rule_set(context, rs);
749*7f2fe78bSCy Schubert     crypto_cert_free_matching_data(context, md);
750*7f2fe78bSCy Schubert     return ret;
751*7f2fe78bSCy Schubert }
752