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(®ex, 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(®ex, 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(®ex); } /* 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