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