1 /* -*- mode: c; c-file-style:"stroustrup"; -*- */
2 
3 /*
4  * Copyright (c) 2018 Mastercard
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 
20 #include <config.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <ctype.h>
26 #include <regex.h>
27 
28 #include "pkcs11lib.h"
29 
30 
31 /*
32    in the following structure, CKA_ID or CKA_LABEL are set at position 0
33    and CKA_CLASS at position 1
34 */
35 
36 
new_idtemplate()37 static pkcs11IdTemplate * new_idtemplate()
38 {
39     pkcs11IdTemplate *idtmpl;
40 
41     idtmpl = calloc(1, sizeof (pkcs11IdTemplate));
42 
43     if(idtmpl) {
44 
45 	idtmpl->template[IDTMPL_OBJECT_CLASS_POS].pValue = &(idtmpl->oclass);
46 	idtmpl->template[IDTMPL_OBJECT_CLASS_POS].ulValueLen = sizeof idtmpl->oclass;
47 	idtmpl->template[IDTMPL_OBJECT_CLASS_POS].type = CKA_CLASS;
48 
49 	idtmpl->has_resource = CK_FALSE;
50 	idtmpl->has_class = CK_FALSE;
51     }
52 
53     return idtmpl;
54 }
55 
56 
delete_idtemplate(pkcs11IdTemplate * idtmpl)57 static inline void delete_idtemplate(pkcs11IdTemplate * idtmpl)
58 {
59     if(idtmpl) {
60 	if(idtmpl->has_resource == CK_TRUE && idtmpl->template[IDTMPL_RESOURCE_POS].pValue != NULL) {
61 	    free(idtmpl->template[IDTMPL_RESOURCE_POS].pValue);
62 	    idtmpl->template[IDTMPL_RESOURCE_POS].pValue = NULL;
63 	    idtmpl->template[IDTMPL_RESOURCE_POS].ulValueLen = 0L;
64 	    idtmpl->has_resource = CK_FALSE;
65 	}
66 	free(idtmpl);
67     }
68 }
69 
70 
adjust_template_len(pkcs11IdTemplate * idtmpl)71 static inline void adjust_template_len(pkcs11IdTemplate *idtmpl)
72 {
73     if(idtmpl) {
74 	idtmpl->template_len = 0;
75 
76 	if(idtmpl->has_resource == CK_TRUE) {
77 	    idtmpl->template_len = 1;
78 	}
79 
80 	if(idtmpl->has_class == CK_TRUE) {
81 	    idtmpl->template_len++;
82 	}
83     }
84 }
85 
idtemplate_setresource(pkcs11IdTemplate * idtmpl,char * id,int size,CK_ATTRIBUTE_TYPE what)86 static void idtemplate_setresource(pkcs11IdTemplate *idtmpl, char *id, int size, CK_ATTRIBUTE_TYPE what)
87 {
88     if(idtmpl && id) {
89 	/* free if already occupied */
90 	if(idtmpl->has_resource == CK_TRUE && idtmpl->template[IDTMPL_RESOURCE_POS].pValue != NULL) {
91 	    free(idtmpl->template[IDTMPL_RESOURCE_POS].pValue);
92 	    idtmpl->template[IDTMPL_RESOURCE_POS].pValue = NULL;
93 	    idtmpl->template[IDTMPL_RESOURCE_POS].ulValueLen = 0L;
94 	    idtmpl->has_resource = CK_FALSE;
95 	}
96 
97 	/* now assign */
98 	idtmpl->template[IDTMPL_RESOURCE_POS].pValue = malloc(size);
99 	if( idtmpl->template[IDTMPL_RESOURCE_POS].pValue ) {
100 	    memcpy( idtmpl->template[IDTMPL_RESOURCE_POS].pValue, id, size);
101 	    idtmpl->template[IDTMPL_RESOURCE_POS].ulValueLen = (CK_ULONG)size;
102 	    idtmpl->template[IDTMPL_RESOURCE_POS].type = what;
103 
104 	    idtmpl->has_resource = CK_TRUE;
105 	}
106 
107 	adjust_template_len(idtmpl);
108     }
109 }
110 
111 
idtemplate_setclass(pkcs11IdTemplate * idtmpl,CK_OBJECT_CLASS cl)112 static void idtemplate_setclass(pkcs11IdTemplate *idtmpl, CK_OBJECT_CLASS cl)
113 {
114     if(idtmpl) {
115 	idtmpl->oclass = cl;	/* copy the object */
116 	idtmpl->has_class = CK_TRUE;
117     }
118 
119     adjust_template_len(idtmpl);
120 }
121 
122 
123 /*------------------------------------------------------------------------*/
124 
125 
126 
pkcs11_make_idtemplate(char * resourceid)127 pkcs11IdTemplate * pkcs11_make_idtemplate(char *resourceid)
128 {
129     pkcs11IdTemplate * idtmpl = NULL;
130     pkcs11IdTemplate * rv = NULL;
131 
132     CK_OBJECT_CLASS objectclass;
133     int has_class = 0;
134     CK_ATTRIBUTE_TYPE cka_resourceid;
135 
136     char *idlblptr = NULL;
137     size_t idlbllen = 0;
138 
139     /* given a label or id, fill in template for performing search */
140 
141     /*
142 
143        [CLASS/][BY_LABEL_OR_ID/]WHAT
144 
145        with:
146        - CLASS (facultative) be one of pubk/, prvk/, seck/, cert/, data/.
147          If missing, CKA_OBJECT is assumed.
148 
149        - BY_LABEL_OR_ID (facultative) be one of id/, label/ or sn/.
150          if missing, CKA_LABEL is assumed.
151 
152        - WHAT (mandatory) be either an hexadecimal string between brackets,
153          eventually with decoration characters that can be whitespace, ':' or '.',
154          or a label ( with no bracket character or '/' allowed ).
155 
156 
157      */
158 
159     char *regexstr = "^(pubk/|prvk/|seck/|cert/|data/)?(id/|label/|sn/|CKA_[[:alpha:]_]+/)?(\\{([[:xdigit:].:[:space:]]+)\\}|([^/{}]+))$";
160     size_t groupcnt = 6;
161 
162     /* groups of this regex:
163 
164        group[0] = the entire string
165        group[1] = pubk/ or prvk/ or seck/ or cert/ or data/
166        group[2] = id/, label/, sn/ or CKA_*something*
167        group[3] = one of group[4] or group[5]
168        group[4] = hex string
169        group[5] = ascii string
170      */
171 
172     regex_t regex;
173 
174     regmatch_t regex_group[groupcnt];
175 
176     int regi=-1;
177 
178 
179     /* allocate structure */
180     idtmpl = new_idtemplate();
181 
182     if(idtmpl==NULL) {
183 	fprintf(stderr, "***ERROR: cannot allocate attribute list\n");
184 	goto err;
185     }
186 
187 
188     /* specific case: if resourceid is NULL, we just return the structure as is */
189     /* meaning that length of template is 0 */
190 
191     if(resourceid!=NULL) {
192 
193 	regi=regcomp(&regex, regexstr, REG_EXTENDED | REG_ICASE);
194 
195 	if (regi!=0)
196 	{
197 	    fprintf(stderr, "***ERROR: cannot compile regex\n");
198 	    goto err;
199 	};
200 
201 	if (regexec(&regex, resourceid, groupcnt, regex_group, 0) != 0)
202 	{
203 	    fprintf(stderr, "***ERROR: invalid path to object: [%s]\n", resourceid);
204 	    goto err;
205 	}
206 
207 
208 	/* analyse regex results */
209 
210 	/* first, determine if there is an object class specified */
211 
212 	if(regex_group[1].rm_so == (size_t)-1) {
213 	    has_class = 0;
214 	    /* no object class specified  */
215 	} else {
216 	    size_t group_len = regex_group[1].rm_eo - regex_group[1].rm_so;
217 	    has_class = 1;
218 	    if(strncasecmp("prvk/", &resourceid[regex_group[1].rm_so], group_len) ==0 ) { /* private key case */
219 		objectclass = CKO_PRIVATE_KEY;
220 	    } else if (strncasecmp("pubk/", &resourceid[regex_group[1].rm_so], group_len) ==0 ) { /* public key case */
221 		objectclass = CKO_PUBLIC_KEY;
222 	    } else if (strncasecmp("seck/", &resourceid[regex_group[1].rm_so], group_len) ==0 ) { /* secret key case */
223 		objectclass = CKO_SECRET_KEY;
224 	    } else if (strncasecmp("cert/", &resourceid[regex_group[1].rm_so], group_len) ==0 ) { /* cert case */
225 		objectclass = CKO_CERTIFICATE;
226 	    } else if (strncasecmp("data/", &resourceid[regex_group[1].rm_so], group_len) ==0 ) { /* cert case */
227 		objectclass = CKO_DATA;
228 	    }
229 	}
230 
231 	/* second, check if we have 'id/' or 'sn/'. In all other cases, we consider it being CKA_LABEL */
232 
233 	if(regex_group[2].rm_so>=0) {
234 	    if(strncasecmp("id/",
235 			   &resourceid[regex_group[2].rm_so],
236 			   regex_group[2].rm_eo - regex_group[2].rm_so) ==0 ) {
237 		cka_resourceid = CKA_ID;
238 	    } else if(strncasecmp("sn/",
239 				  &resourceid[regex_group[2].rm_so],
240 				  regex_group[2].rm_eo - regex_group[2].rm_so) ==0 ) {
241 	    cka_resourceid = CKA_SERIAL_NUMBER;
242 	    } else if(strncasecmp("CKA_", &resourceid[regex_group[2].rm_so], 4) ==0 ) {
243 		/* we need to retrienve the character */
244 		char compare_buf[128];
245 
246 		if(regex_group[2].rm_eo - regex_group[2].rm_so > (sizeof compare_buf)-1 ) {
247 		    fprintf(stderr, "***ERROR: cannot parse attribute in regular expression - attribute name too long\n");
248 		    goto err;
249 		}
250 
251 		/* we copy in compare_buf all chars excepting the trailing '/'  */
252 		memcpy(compare_buf, &resourceid[regex_group[2].rm_so], regex_group[2].rm_eo - regex_group[2].rm_so - 1);
253 		compare_buf[ regex_group[2].rm_eo - regex_group[2].rm_so -1  ] = 0; /* null-terminate string */
254 
255 		cka_resourceid = pkcs11_get_attribute_type_from_name(compare_buf);
256 
257 		if(cka_resourceid == 0xFFFFFFFF) {
258 		    fprintf(stderr, "***ERROR: cannot parse attribute in regular expression - attribute not managed or unknown\n");
259 		    goto err;
260 		}
261 
262 	    } else {
263 		/* last possibility is label */
264 		cka_resourceid = CKA_LABEL;
265 	    }
266 	} else {
267 	    /* no prefix specified, default case is label */
268 	    cka_resourceid = CKA_LABEL;
269 	}
270 
271 
272 	/* third, extract identifier value, ASCII or hex */
273 
274 	if(regex_group[4].rm_so>=0) 	{ /* we have HEX string */
275 
276 	    idlblptr = hex2bin_new( &resourceid[ regex_group[4].rm_so ], regex_group[4].rm_eo - regex_group[4].rm_so, &idlbllen);
277 
278 	    if(idlblptr==NULL) {
279 		fprintf(stderr, "***ERROR: memory error\n");
280 		goto err;
281 	    }
282 	} else { 			/* ASCII */
283 	    idlblptr = &resourceid[ regex_group[5].rm_so ];
284 	    idlbllen = strlen(idlblptr);
285 	}
286 
287 	/* set values */
288 
289 	idtemplate_setresource(idtmpl, idlblptr, idlbllen, cka_resourceid);
290 
291 	if(has_class) {
292 	    idtemplate_setclass(idtmpl, objectclass);
293 	}
294 
295 	/* housekeeping */
296 
297 	if(regex_group[4].rm_so>0) 	{ /* we have HEX string */
298 	    hex2bin_free(idlblptr);
299 	    idlbllen = 0;
300 	}
301     }
302 
303     rv = idtmpl;		/* transfer idtmpl to rv */
304     idtmpl = NULL;
305 
306 err:
307     if(regi==0) { regfree(&regex); } /* if regi==0, regcomp() was successful */
308     if (idtmpl) { delete_idtemplate(idtmpl); idtmpl=NULL; }
309 
310     return rv;
311 }
312 
313 
pkcs11_delete_idtemplate(pkcs11IdTemplate * idtmpl)314 void pkcs11_delete_idtemplate(pkcs11IdTemplate * idtmpl)
315 {
316     delete_idtemplate(idtmpl);
317 }
318 
319 
pkcs11_sizeof_idtemplate(pkcs11IdTemplate * idtmpl)320 int pkcs11_sizeof_idtemplate(pkcs11IdTemplate *idtmpl)
321 {
322     return idtmpl->template_len;
323 }
324 
325