Skip to content

Commit bf894f3

Browse files
David WoodhouseDavid Woodhouse
David Woodhouse
authored and
David Woodhouse
committed
Accept RFC7512-compliant PKCS#11 URIs as serialized token/certificate IDs
The old format is still accepted for compatibility. Signed-off-by: David Woodhouse <[email protected]>
1 parent ab9856d commit bf894f3

File tree

1 file changed

+256
-49
lines changed

1 file changed

+256
-49
lines changed

lib/pkcs11h-serialization.c

Lines changed: 256 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,26 @@
6161

6262
#if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE)
6363

64+
#define URI_SCHEME "pkcs11:"
65+
66+
#define token_field_ofs(field) ((unsigned long)&(((struct pkcs11h_token_id_s *)0)->field))
67+
#define token_field_size(field) sizeof((((struct pkcs11h_token_id_s *)0)->field))
68+
#define token_field(name, field) { name "=", sizeof(name), \
69+
token_field_ofs(field), token_field_size(field) }
70+
71+
static struct {
72+
const char const *name;
73+
size_t namelen;
74+
unsigned long field_ofs;
75+
size_t field_size;
76+
} __token_fields[] = {
77+
token_field ("model", model),
78+
token_field ("token", label),
79+
token_field ("manufacturer", manufacturerID ),
80+
token_field ("serial", serialNumber ),
81+
{ NULL },
82+
};
83+
6484
CK_RV
6585
pkcs11h_token_serializeTokenId (
6686
OUT char * const sz,
@@ -150,9 +170,147 @@ pkcs11h_token_serializeTokenId (
150170
return rv;
151171
}
152172

173+
static
153174
CK_RV
154-
pkcs11h_token_deserializeTokenId (
155-
OUT pkcs11h_token_id_t *p_token_id,
175+
__parse_token_uri_attr (
176+
const char *uri,
177+
size_t urilen,
178+
char *tokstr,
179+
size_t toklen,
180+
size_t *parsed_len
181+
) {
182+
size_t orig_toklen = toklen;
183+
CK_RV rv = CKR_OK;
184+
185+
while (urilen && toklen > 1) {
186+
if (*uri == '%') {
187+
size_t size = 1;
188+
189+
if (urilen < 3) {
190+
rv = CKR_ATTRIBUTE_VALUE_INVALID;
191+
goto done;
192+
}
193+
194+
rv = _pkcs11h_util_hexToBinary ((unsigned char *)tokstr,
195+
uri + 1, &size);
196+
if (rv != CKR_OK) {
197+
goto done;
198+
}
199+
200+
uri += 2;
201+
urilen -= 2;
202+
} else {
203+
*tokstr = *uri;
204+
}
205+
tokstr++;
206+
uri++;
207+
toklen--;
208+
urilen--;
209+
tokstr[1] = 0;
210+
}
211+
212+
if (urilen) {
213+
rv = CKR_ATTRIBUTE_VALUE_INVALID;
214+
} else if (parsed_len) {
215+
*parsed_len = orig_toklen - toklen;
216+
}
217+
218+
done:
219+
return rv;
220+
}
221+
222+
static
223+
CK_RV
224+
__parse_pkcs11_uri (
225+
OUT pkcs11h_token_id_t token_id,
226+
OUT pkcs11h_certificate_id_t certificate_id,
227+
IN const char * const sz
228+
) {
229+
const char *end, *p;
230+
CK_RV rv = CKR_OK;
231+
232+
_PKCS11H_ASSERT (token_id!=NULL);
233+
_PKCS11H_ASSERT (sz!=NULL);
234+
235+
if (strncmp (sz, URI_SCHEME, strlen (URI_SCHEME)))
236+
return CKR_ATTRIBUTE_VALUE_INVALID;
237+
238+
end = sz + strlen (URI_SCHEME) - 1;
239+
while (rv == CKR_OK && end[0] && end[1]) {
240+
int i;
241+
242+
p = end + 1;
243+
end = strchr (p, ';');
244+
if (!end)
245+
end = p + strlen(p);
246+
247+
for (i = 0; __token_fields[i].name; i++) {
248+
/* Parse the token=, label=, manufacturer= and serial= fields */
249+
if (!strncmp(p, __token_fields[i].name, __token_fields[i].namelen)) {
250+
char *field = ((char *)token_id) + __token_fields[i].field_ofs;
251+
252+
p += __token_fields[i].namelen;
253+
rv = __parse_token_uri_attr (p, end - p, field,
254+
__token_fields[i].field_size,
255+
NULL);
256+
if (rv != CKR_OK) {
257+
goto cleanup;
258+
}
259+
260+
goto matched;
261+
}
262+
}
263+
if (certificate_id && !strncmp(p, "id=", 3)) {
264+
p += 3;
265+
266+
rv = _pkcs11h_mem_malloc ((void *)&certificate_id->attrCKA_ID,
267+
end - p + 1);
268+
if (rv != CKR_OK) {
269+
goto cleanup;
270+
}
271+
272+
rv = __parse_token_uri_attr (p, end - p,
273+
(char *)certificate_id->attrCKA_ID,
274+
end - p + 1,
275+
&certificate_id->attrCKA_ID_size);
276+
if (rv != CKR_OK) {
277+
goto cleanup;
278+
}
279+
280+
goto matched;
281+
}
282+
283+
/* We don't parse object= because the match code doesn't support
284+
matching by label. */
285+
286+
/* Failed to parse PKCS#11 URI element. */
287+
return CKR_ATTRIBUTE_VALUE_INVALID;
288+
289+
matched:
290+
;
291+
}
292+
cleanup:
293+
/* The matching code doesn't support support partial matches; it needs
294+
* *all* of manufacturer, model, serial and label attributes to be
295+
* defined. So reject partial URIs early instead of letting it do the
296+
* wrong thing. We can maybe improve this later. */
297+
if (!token_id->model[0] || !token_id->label[0] ||
298+
!token_id->manufacturerID[0] || !token_id->serialNumber[0]) {
299+
return CKR_ATTRIBUTE_VALUE_INVALID;
300+
}
301+
302+
/* For a certificate ID we need CKA_ID */
303+
if (certificate_id && !certificate_id->attrCKA_ID_size) {
304+
return CKR_ATTRIBUTE_VALUE_INVALID;
305+
}
306+
307+
return rv;
308+
}
309+
310+
static
311+
CK_RV
312+
__pkcs11h_token_legacy_deserializeTokenId (
313+
OUT pkcs11h_token_id_t token_id,
156314
IN const char * const sz
157315
) {
158316
#define __PKCS11H_TARGETS_NUMBER 4
@@ -161,24 +319,11 @@ pkcs11h_token_deserializeTokenId (
161319
size_t s;
162320
} targets[__PKCS11H_TARGETS_NUMBER];
163321

164-
pkcs11h_token_id_t token_id = NULL;
165322
char *p1 = NULL;
166323
char *_sz = NULL;
167324
int e;
168325
CK_RV rv = CKR_FUNCTION_FAILED;
169326

170-
_PKCS11H_ASSERT (p_token_id!=NULL);
171-
_PKCS11H_ASSERT (sz!=NULL);
172-
173-
_PKCS11H_DEBUG (
174-
PKCS11H_LOG_DEBUG2,
175-
"PKCS#11: pkcs11h_token_deserializeTokenId entry p_token_id=%p, sz='%s'",
176-
(void *)p_token_id,
177-
sz
178-
);
179-
180-
*p_token_id = NULL;
181-
182327
if (
183328
(rv = _pkcs11h_mem_strdup (
184329
(void *)&_sz,
@@ -190,10 +335,6 @@ pkcs11h_token_deserializeTokenId (
190335

191336
p1 = _sz;
192337

193-
if ((rv = _pkcs11h_token_newTokenId (&token_id)) != CKR_OK) {
194-
goto cleanup;
195-
}
196-
197338
targets[0].p = token_id->manufacturerID;
198339
targets[0].s = sizeof (token_id->manufacturerID);
199340
targets[1].p = token_id->model;
@@ -252,6 +393,51 @@ pkcs11h_token_deserializeTokenId (
252393
p1 = p2+1;
253394
}
254395

396+
rv = CKR_OK;
397+
398+
cleanup:
399+
400+
if (_sz != NULL) {
401+
_pkcs11h_mem_free ((void *)&_sz);
402+
}
403+
404+
return rv;
405+
#undef __PKCS11H_TARGETS_NUMBER
406+
}
407+
408+
CK_RV
409+
pkcs11h_token_deserializeTokenId (
410+
OUT pkcs11h_token_id_t *p_token_id,
411+
IN const char * const sz
412+
) {
413+
pkcs11h_token_id_t token_id = NULL;
414+
CK_RV rv = CKR_FUNCTION_FAILED;
415+
416+
_PKCS11H_ASSERT (p_token_id!=NULL);
417+
_PKCS11H_ASSERT (sz!=NULL);
418+
419+
_PKCS11H_DEBUG (
420+
PKCS11H_LOG_DEBUG2,
421+
"PKCS#11: pkcs11h_token_deserializeTokenId entry p_token_id=%p, sz='%s'",
422+
(void *)p_token_id,
423+
sz
424+
);
425+
426+
*p_token_id = NULL;
427+
428+
if ((rv = _pkcs11h_token_newTokenId (&token_id)) != CKR_OK) {
429+
goto cleanup;
430+
}
431+
432+
if (!strncmp (sz, URI_SCHEME, strlen (URI_SCHEME))) {
433+
rv = __parse_pkcs11_uri(token_id, NULL, sz);
434+
} else {
435+
rv = __pkcs11h_token_legacy_deserializeTokenId(token_id, sz);
436+
}
437+
if (rv != CKR_OK) {
438+
goto cleanup;
439+
}
440+
255441
strncpy (
256442
token_id->display,
257443
token_id->label,
@@ -264,11 +450,6 @@ pkcs11h_token_deserializeTokenId (
264450
rv = CKR_OK;
265451

266452
cleanup:
267-
268-
if (_sz != NULL) {
269-
_pkcs11h_mem_free ((void *)&_sz);
270-
}
271-
272453
if (token_id != NULL) {
273454
pkcs11h_token_freeTokenId (token_id);
274455
}
@@ -281,7 +462,6 @@ pkcs11h_token_deserializeTokenId (
281462
);
282463

283464
return rv;
284-
#undef __PKCS11H_TARGETS_NUMBER
285465
}
286466

287467
#endif /* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */
@@ -360,29 +540,17 @@ pkcs11h_certificate_serializeCertificateId (
360540
return rv;
361541
}
362542

543+
static
363544
CK_RV
364-
pkcs11h_certificate_deserializeCertificateId (
365-
OUT pkcs11h_certificate_id_t * const p_certificate_id,
545+
__pkcs11h_certificate_legacy_deserializeCertificateId (
546+
OUT pkcs11h_certificate_id_t certificate_id,
366547
IN const char * const sz
367548
) {
368-
pkcs11h_certificate_id_t certificate_id = NULL;
369549
CK_RV rv = CKR_FUNCTION_FAILED;
370550
char *p = NULL;
371551
char *_sz = NULL;
372552
size_t id_hex_len;
373553

374-
_PKCS11H_ASSERT (p_certificate_id!=NULL);
375-
_PKCS11H_ASSERT (sz!=NULL);
376-
377-
*p_certificate_id = NULL;
378-
379-
_PKCS11H_DEBUG (
380-
PKCS11H_LOG_DEBUG2,
381-
"PKCS#11: pkcs11h_certificate_deserializeCertificateId entry p_certificate_id=%p, sz='%s'",
382-
(void *)p_certificate_id,
383-
sz
384-
);
385-
386554
if (
387555
(rv = _pkcs11h_mem_strdup (
388556
(void *)&_sz,
@@ -394,10 +562,6 @@ pkcs11h_certificate_deserializeCertificateId (
394562

395563
p = _sz;
396564

397-
if ((rv = _pkcs11h_certificate_newCertificateId (&certificate_id)) != CKR_OK) {
398-
goto cleanup;
399-
}
400-
401565
if ((p = strrchr (_sz, '/')) == NULL) {
402566
rv = CKR_ATTRIBUTE_VALUE_INVALID;
403567
goto cleanup;
@@ -436,21 +600,64 @@ pkcs11h_certificate_deserializeCertificateId (
436600
goto cleanup;
437601
}
438602

603+
rv = CKR_OK;
604+
605+
cleanup:
606+
607+
if (_sz != NULL) {
608+
_pkcs11h_mem_free ((void *)&_sz);
609+
}
610+
611+
return rv;
612+
613+
}
614+
615+
CK_RV
616+
pkcs11h_certificate_deserializeCertificateId (
617+
OUT pkcs11h_certificate_id_t * const p_certificate_id,
618+
IN const char * const sz
619+
) {
620+
pkcs11h_certificate_id_t certificate_id = NULL;
621+
CK_RV rv = CKR_FUNCTION_FAILED;
622+
623+
_PKCS11H_ASSERT (p_certificate_id!=NULL);
624+
_PKCS11H_ASSERT (sz!=NULL);
625+
626+
*p_certificate_id = NULL;
627+
628+
_PKCS11H_DEBUG (
629+
PKCS11H_LOG_DEBUG2,
630+
"PKCS#11: pkcs11h_certificate_deserializeCertificateId entry p_certificate_id=%p, sz='%s'",
631+
(void *)p_certificate_id,
632+
sz
633+
);
634+
635+
if ((rv = _pkcs11h_certificate_newCertificateId (&certificate_id)) != CKR_OK) {
636+
goto cleanup;
637+
}
638+
if ((rv = _pkcs11h_token_newTokenId (&certificate_id->token_id)) != CKR_OK) {
639+
goto cleanup;
640+
}
641+
642+
if (!strncmp(sz, URI_SCHEME, strlen (URI_SCHEME))) {
643+
rv = __parse_pkcs11_uri (certificate_id->token_id, certificate_id, sz);
644+
} else {
645+
rv = __pkcs11h_certificate_legacy_deserializeCertificateId (certificate_id, sz);
646+
}
647+
if (rv != CKR_OK) {
648+
goto cleanup;
649+
}
650+
439651
*p_certificate_id = certificate_id;
440652
certificate_id = NULL;
441653
rv = CKR_OK;
442654

443655
cleanup:
444-
445656
if (certificate_id != NULL) {
446657
pkcs11h_certificate_freeCertificateId (certificate_id);
447658
certificate_id = NULL;
448659
}
449660

450-
if (_sz != NULL) {
451-
_pkcs11h_mem_free ((void *)&_sz);
452-
}
453-
454661
_PKCS11H_DEBUG (
455662
PKCS11H_LOG_DEBUG2,
456663
"PKCS#11: pkcs11h_certificate_deserializeCertificateId return rv=%lu-'%s'",

0 commit comments

Comments
 (0)