1*ccd81fddSJan Pechanec /*
2*ccd81fddSJan Pechanec  * CDDL HEADER START
3*ccd81fddSJan Pechanec  *
4*ccd81fddSJan Pechanec  * The contents of this file are subject to the terms of the
5*ccd81fddSJan Pechanec  * Common Development and Distribution License (the "License").
6*ccd81fddSJan Pechanec  * You may not use this file except in compliance with the License.
7*ccd81fddSJan Pechanec  *
8*ccd81fddSJan Pechanec  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*ccd81fddSJan Pechanec  * or http://www.opensolaris.org/os/licensing.
10*ccd81fddSJan Pechanec  * See the License for the specific language governing permissions
11*ccd81fddSJan Pechanec  * and limitations under the License.
12*ccd81fddSJan Pechanec  *
13*ccd81fddSJan Pechanec  * When distributing Covered Code, include this CDDL HEADER in each
14*ccd81fddSJan Pechanec  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*ccd81fddSJan Pechanec  * If applicable, add the following below this CDDL HEADER, with the
16*ccd81fddSJan Pechanec  * fields enclosed by brackets "[]" replaced with your own identifying
17*ccd81fddSJan Pechanec  * information: Portions Copyright [yyyy] [name of copyright owner]
18*ccd81fddSJan Pechanec  *
19*ccd81fddSJan Pechanec  * CDDL HEADER END
20*ccd81fddSJan Pechanec  *
21*ccd81fddSJan Pechanec  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
22*ccd81fddSJan Pechanec  */
23*ccd81fddSJan Pechanec 
24*ccd81fddSJan Pechanec #include <stdio.h>
25*ccd81fddSJan Pechanec #include <stdlib.h>
26*ccd81fddSJan Pechanec #include <string.h>
27*ccd81fddSJan Pechanec #include <sys/types.h>
28*ccd81fddSJan Pechanec #include <sys/wait.h>
29*ccd81fddSJan Pechanec #include <unistd.h>
30*ccd81fddSJan Pechanec #include <strings.h>
31*ccd81fddSJan Pechanec #include <libgen.h>
32*ccd81fddSJan Pechanec #include <pthread.h>
33*ccd81fddSJan Pechanec 
34*ccd81fddSJan Pechanec #include <security/cryptoki.h>
35*ccd81fddSJan Pechanec #include <security/pkcs11.h>
36*ccd81fddSJan Pechanec 
37*ccd81fddSJan Pechanec #include <cryptoutil.h>
38*ccd81fddSJan Pechanec 
39*ccd81fddSJan Pechanec /* PKCS#11 URI prefix and attributes. */
40*ccd81fddSJan Pechanec #define	PK11_URI_PREFIX		"pkcs11:"
41*ccd81fddSJan Pechanec #define	PK11_TOKEN		"token"
42*ccd81fddSJan Pechanec #define	PK11_MANUF		"manufacturer"
43*ccd81fddSJan Pechanec #define	PK11_SERIAL		"serial"
44*ccd81fddSJan Pechanec #define	PK11_MODEL		"model"
45*ccd81fddSJan Pechanec #define	PK11_OBJECT		"object"
46*ccd81fddSJan Pechanec #define	PK11_OBJECTTYPE		"objecttype"
47*ccd81fddSJan Pechanec #define	PK11_ID			"id"
48*ccd81fddSJan Pechanec #define	PK11_PINFILE		"pinfile"
49*ccd81fddSJan Pechanec 
50*ccd81fddSJan Pechanec /*
51*ccd81fddSJan Pechanec  * Gets a hexadecimal string of the xx:xx:xx-like format and fills the output
52*ccd81fddSJan Pechanec  * buffer with bytes represeting each of the hexadecimal numbers. Returns 0 on
53*ccd81fddSJan Pechanec  * error (missing ':', not a hexadecimal character (eg. 'z'), output buffer
54*ccd81fddSJan Pechanec  * overflow, etc.), or the number of hexadecimal numbers processed.
55*ccd81fddSJan Pechanec  *
56*ccd81fddSJan Pechanec  * Returns:
57*ccd81fddSJan Pechanec  *	0
58*ccd81fddSJan Pechanec  *		on failure
59*ccd81fddSJan Pechanec  *	>0
60*ccd81fddSJan Pechanec  *		number of bytes returned via the output parameter
61*ccd81fddSJan Pechanec  */
62*ccd81fddSJan Pechanec static int
read_id(char * str,unsigned char * output,int out_len)63*ccd81fddSJan Pechanec read_id(char *str, unsigned char *output, int out_len)
64*ccd81fddSJan Pechanec {
65*ccd81fddSJan Pechanec 	int i, len, n;
66*ccd81fddSJan Pechanec 	unsigned int x1, x2;
67*ccd81fddSJan Pechanec 
68*ccd81fddSJan Pechanec 	len = strlen(str);
69*ccd81fddSJan Pechanec 	(void) memset(output, 0, out_len);
70*ccd81fddSJan Pechanec 	/* Counter of the processed bytes. */
71*ccd81fddSJan Pechanec 	i = 0;
72*ccd81fddSJan Pechanec 	/* Counter for the used output bytes. */
73*ccd81fddSJan Pechanec 	n = 0;
74*ccd81fddSJan Pechanec 
75*ccd81fddSJan Pechanec 	while (i < len) {
76*ccd81fddSJan Pechanec 		/* We require at least one hexadecimal character. */
77*ccd81fddSJan Pechanec 		if (sscanf(str + i, "%1x", &x1) != 1)
78*ccd81fddSJan Pechanec 			return (0);
79*ccd81fddSJan Pechanec 		++i;
80*ccd81fddSJan Pechanec 		/* And we accept the 2nd one if it is there. */
81*ccd81fddSJan Pechanec 		if (sscanf(str + i, "%1x", &x2) == 1) {
82*ccd81fddSJan Pechanec 			x1 = x1 * 16 + x2;
83*ccd81fddSJan Pechanec 			++i;
84*ccd81fddSJan Pechanec 		}
85*ccd81fddSJan Pechanec 
86*ccd81fddSJan Pechanec 		/* Output buffer overflow? */
87*ccd81fddSJan Pechanec 		if ((n + 1) > out_len)
88*ccd81fddSJan Pechanec 			return (0);
89*ccd81fddSJan Pechanec 		output[n] = (unsigned char)x1;
90*ccd81fddSJan Pechanec 		/* Still some bytes to process? */
91*ccd81fddSJan Pechanec 		if (i < len) {
92*ccd81fddSJan Pechanec 			/* ':' is the only acceptable delimiter. */
93*ccd81fddSJan Pechanec 			if (str[i] != ':')
94*ccd81fddSJan Pechanec 				return (0);
95*ccd81fddSJan Pechanec 			/* Skip ':' */
96*ccd81fddSJan Pechanec 			++i;
97*ccd81fddSJan Pechanec 		}
98*ccd81fddSJan Pechanec 		++n;
99*ccd81fddSJan Pechanec 	}
100*ccd81fddSJan Pechanec 
101*ccd81fddSJan Pechanec 	return (n);
102*ccd81fddSJan Pechanec }
103*ccd81fddSJan Pechanec 
104*ccd81fddSJan Pechanec /*
105*ccd81fddSJan Pechanec  * Process the PKCS#11 URI. The function expects an allocated URI structure. The
106*ccd81fddSJan Pechanec  * caller is later expected to call pkcs11_free_uri() when the parsed URI is no
107*ccd81fddSJan Pechanec  * longer needed.
108*ccd81fddSJan Pechanec  *
109*ccd81fddSJan Pechanec  * Returns:
110*ccd81fddSJan Pechanec  *      PK11_URI_OK
111*ccd81fddSJan Pechanec  *		success
112*ccd81fddSJan Pechanec  *      PK11_URI_INVALID
113*ccd81fddSJan Pechanec  *		invalid PKCS#11 URI (one that has the "pkcs11:" prefix but is
114*ccd81fddSJan Pechanec  *		otherwise incorrectly specified)
115*ccd81fddSJan Pechanec  *      PK11_MALLOC_ERROR
116*ccd81fddSJan Pechanec  *		malloc(3C) failed when allocating one of the internal buffers
117*ccd81fddSJan Pechanec  *      PK11_URI_VALUE_OVERFLOW
118*ccd81fddSJan Pechanec  *		some attributes in the URI are of the fixed length accroding to
119*ccd81fddSJan Pechanec  *		the spec. If any of those attributes overflows we report an
120*ccd81fddSJan Pechanec  *		error
121*ccd81fddSJan Pechanec  *      PK11_NOT_PKCS11_URI
122*ccd81fddSJan Pechanec  *		the URI supplied is not the PKCS#11 URI at all (does not have
123*ccd81fddSJan Pechanec  *		the "pkcs11:" prefix)
124*ccd81fddSJan Pechanec  */
125*ccd81fddSJan Pechanec int
pkcs11_parse_uri(const char * str,pkcs11_uri_t * uri)126*ccd81fddSJan Pechanec pkcs11_parse_uri(const char *str, pkcs11_uri_t *uri)
127*ccd81fddSJan Pechanec {
128*ccd81fddSJan Pechanec 	char *str2, *l1, *l2, *tok, *name;
129*ccd81fddSJan Pechanec 
130*ccd81fddSJan Pechanec 	/* Initialize the structure. */
131*ccd81fddSJan Pechanec 	(void) memset(uri, 0, sizeof (pkcs11_uri_t));
132*ccd81fddSJan Pechanec 	/* Be really safe. */
133*ccd81fddSJan Pechanec 	uri->objecttype_present = B_FALSE;
134*ccd81fddSJan Pechanec 
135*ccd81fddSJan Pechanec 	/* Check that we have the correct PKCS#11 URI prefix. */
136*ccd81fddSJan Pechanec 	if (strncmp(str, PK11_URI_PREFIX, strlen(PK11_URI_PREFIX)) != 0)
137*ccd81fddSJan Pechanec 		return (PK11_NOT_PKCS11_URI);
138*ccd81fddSJan Pechanec 	/* Dup the string and skip over the prefix then. */
139*ccd81fddSJan Pechanec 	if ((str2 = strdup(str + strlen(PK11_URI_PREFIX))) == NULL)
140*ccd81fddSJan Pechanec 		return (PK11_MALLOC_ERROR);
141*ccd81fddSJan Pechanec 
142*ccd81fddSJan Pechanec 	/*
143*ccd81fddSJan Pechanec 	 * Using strtok_r() would silently skip over multiple semicolons. We
144*ccd81fddSJan Pechanec 	 * must check such situation before moving on. We must also avoid ';' as
145*ccd81fddSJan Pechanec 	 * the first and the last character of the URI.
146*ccd81fddSJan Pechanec 	 */
147*ccd81fddSJan Pechanec 	if (strstr(str2, ";;") != NULL || str2[0] == ';' ||
148*ccd81fddSJan Pechanec 	    (strlen(str2) > 0 && str2[strlen(str2) - 1] == ';'))
149*ccd81fddSJan Pechanec 		goto bad_uri;
150*ccd81fddSJan Pechanec 
151*ccd81fddSJan Pechanec 	/* Now parse the URI. */
152*ccd81fddSJan Pechanec 	tok = strtok_r(str2, ";", &l1);
153*ccd81fddSJan Pechanec 	for (; tok != NULL; tok = strtok_r(NULL, ";", &l1)) {
154*ccd81fddSJan Pechanec 		/* "tok" is not empty so there will be something in "name". */
155*ccd81fddSJan Pechanec 		name = strtok_r(tok, "=", &l2);
156*ccd81fddSJan Pechanec 		/* Check whether there is '=' at all. */
157*ccd81fddSJan Pechanec 		if (l2 == NULL)
158*ccd81fddSJan Pechanec 			goto bad_uri;
159*ccd81fddSJan Pechanec 
160*ccd81fddSJan Pechanec 		/*
161*ccd81fddSJan Pechanec 		 * Fill out the URI structure. We do not accept duplicate
162*ccd81fddSJan Pechanec 		 * attributes.
163*ccd81fddSJan Pechanec 		 */
164*ccd81fddSJan Pechanec 		if (strcmp(name, PK11_TOKEN) == 0) {
165*ccd81fddSJan Pechanec 			/* Check for duplicity. */
166*ccd81fddSJan Pechanec 			if (uri->token != NULL)
167*ccd81fddSJan Pechanec 				goto bad_uri;
168*ccd81fddSJan Pechanec 			if (strlen(l2) > 32)
169*ccd81fddSJan Pechanec 				goto value_overflow;
170*ccd81fddSJan Pechanec 			if ((uri->token = (unsigned char *)strdup(l2)) == NULL)
171*ccd81fddSJan Pechanec 				goto malloc_failed;
172*ccd81fddSJan Pechanec 		} else if (strcmp(name, PK11_MANUF) == 0) {
173*ccd81fddSJan Pechanec 			/* Check for duplicity. */
174*ccd81fddSJan Pechanec 			if (uri->manuf != NULL)
175*ccd81fddSJan Pechanec 				goto bad_uri;
176*ccd81fddSJan Pechanec 			if (strlen(l2) > 32)
177*ccd81fddSJan Pechanec 				goto value_overflow;
178*ccd81fddSJan Pechanec 			if ((uri->manuf = (unsigned char *)strdup(l2)) == NULL)
179*ccd81fddSJan Pechanec 				goto malloc_failed;
180*ccd81fddSJan Pechanec 		} else if (strcmp(name, PK11_SERIAL) == 0) {
181*ccd81fddSJan Pechanec 			/* Check for duplicity. */
182*ccd81fddSJan Pechanec 			if (uri->serial != NULL)
183*ccd81fddSJan Pechanec 				goto bad_uri;
184*ccd81fddSJan Pechanec 			if (strlen(l2) > 16)
185*ccd81fddSJan Pechanec 				goto value_overflow;
186*ccd81fddSJan Pechanec 			if ((uri->serial = (unsigned char *)strdup(l2)) == NULL)
187*ccd81fddSJan Pechanec 				goto malloc_failed;
188*ccd81fddSJan Pechanec 		} else if (strcmp(name, PK11_MODEL) == 0) {
189*ccd81fddSJan Pechanec 			/* Check for duplicity. */
190*ccd81fddSJan Pechanec 			if (uri->model != NULL)
191*ccd81fddSJan Pechanec 				goto bad_uri;
192*ccd81fddSJan Pechanec 			if (strlen(l2) > 16)
193*ccd81fddSJan Pechanec 				goto value_overflow;
194*ccd81fddSJan Pechanec 			if ((uri->model = (unsigned char *)strdup(l2)) == NULL)
195*ccd81fddSJan Pechanec 				goto malloc_failed;
196*ccd81fddSJan Pechanec 		} else if (strcmp(name, PK11_ID) == 0) {
197*ccd81fddSJan Pechanec 			/* Check for duplicity. */
198*ccd81fddSJan Pechanec 			if (uri->id_len != 0)
199*ccd81fddSJan Pechanec 				goto bad_uri;
200*ccd81fddSJan Pechanec 			/*
201*ccd81fddSJan Pechanec 			 * We can have maximum of PK11_MAX_ID_LEN 2-byte
202*ccd81fddSJan Pechanec 			 * numbers separated by ':'s, like
203*ccd81fddSJan Pechanec 			 * 01:02:0A:FF:...
204*ccd81fddSJan Pechanec 			 */
205*ccd81fddSJan Pechanec 			if (strlen(l2) > PK11_MAX_ID_LEN * 2 +
206*ccd81fddSJan Pechanec 			    PK11_MAX_ID_LEN - 1) {
207*ccd81fddSJan Pechanec 				goto value_overflow;
208*ccd81fddSJan Pechanec 			}
209*ccd81fddSJan Pechanec 			if ((uri->id = malloc(PK11_MAX_ID_LEN)) == NULL)
210*ccd81fddSJan Pechanec 				goto malloc_failed;
211*ccd81fddSJan Pechanec 			uri->id_len = read_id(l2, uri->id,
212*ccd81fddSJan Pechanec 			    PK11_MAX_ID_LEN);
213*ccd81fddSJan Pechanec 			if (uri->id_len == 0)
214*ccd81fddSJan Pechanec 				goto bad_uri;
215*ccd81fddSJan Pechanec 		} else if (strcmp(name, PK11_OBJECT) == 0) {
216*ccd81fddSJan Pechanec 			/* Check for duplicity. */
217*ccd81fddSJan Pechanec 			if (uri->object != NULL)
218*ccd81fddSJan Pechanec 				goto bad_uri;
219*ccd81fddSJan Pechanec 			if (strlen(l2) > PK11_MAX_OBJECT_LEN)
220*ccd81fddSJan Pechanec 				goto value_overflow;
221*ccd81fddSJan Pechanec 			if ((uri->object = (unsigned char *)strdup(l2)) == NULL)
222*ccd81fddSJan Pechanec 				goto malloc_failed;
223*ccd81fddSJan Pechanec 		} else if (strcmp(name, PK11_OBJECTTYPE) == 0) {
224*ccd81fddSJan Pechanec 			/*
225*ccd81fddSJan Pechanec 			 * Check for duplicity. objecttype can not be empty, it
226*ccd81fddSJan Pechanec 			 * would not make sense.
227*ccd81fddSJan Pechanec 			 */
228*ccd81fddSJan Pechanec 			if (uri->objecttype_present == CK_TRUE)
229*ccd81fddSJan Pechanec 				goto bad_uri;
230*ccd81fddSJan Pechanec 			if (strcmp(l2, "public") == 0)
231*ccd81fddSJan Pechanec 				uri->objecttype = CKO_PUBLIC_KEY;
232*ccd81fddSJan Pechanec 			else if (strcmp(l2, "private") == 0)
233*ccd81fddSJan Pechanec 				uri->objecttype = CKO_PRIVATE_KEY;
234*ccd81fddSJan Pechanec 			else if (strcmp(l2, "cert") == 0)
235*ccd81fddSJan Pechanec 				uri->objecttype = CKO_CERTIFICATE;
236*ccd81fddSJan Pechanec 			else if (strcmp(l2, "secretkey") == 0)
237*ccd81fddSJan Pechanec 				uri->objecttype = CKO_SECRET_KEY;
238*ccd81fddSJan Pechanec 			else if (strcmp(l2, "data") == 0)
239*ccd81fddSJan Pechanec 				uri->objecttype = CKO_DATA;
240*ccd81fddSJan Pechanec 			else
241*ccd81fddSJan Pechanec 				goto bad_uri;
242*ccd81fddSJan Pechanec 			uri->objecttype_present = CK_TRUE;
243*ccd81fddSJan Pechanec 		} else if (strcmp(name, PK11_PINFILE) == 0)
244*ccd81fddSJan Pechanec 			/* Check for duplicity. */
245*ccd81fddSJan Pechanec 			if (uri->pinfile == NULL) {
246*ccd81fddSJan Pechanec 				if (strlen(l2) > MAXPATHLEN)
247*ccd81fddSJan Pechanec 					goto value_overflow;
248*ccd81fddSJan Pechanec 				if ((uri->pinfile = strdup(l2)) == NULL)
249*ccd81fddSJan Pechanec 					goto malloc_failed;
250*ccd81fddSJan Pechanec 				/* Empty pinfile makes no sense. */
251*ccd81fddSJan Pechanec 				if (uri->pinfile[0] == '\0')
252*ccd81fddSJan Pechanec 					goto bad_uri;
253*ccd81fddSJan Pechanec 			} else
254*ccd81fddSJan Pechanec 				goto bad_uri;
255*ccd81fddSJan Pechanec 		else
256*ccd81fddSJan Pechanec 			/* Unknown attribute name. */
257*ccd81fddSJan Pechanec 			goto bad_uri;
258*ccd81fddSJan Pechanec 	}
259*ccd81fddSJan Pechanec 
260*ccd81fddSJan Pechanec 	free(str2);
261*ccd81fddSJan Pechanec 	return (PK11_URI_OK);
262*ccd81fddSJan Pechanec malloc_failed:
263*ccd81fddSJan Pechanec 	free(str2);
264*ccd81fddSJan Pechanec 	pkcs11_free_uri(uri);
265*ccd81fddSJan Pechanec 	return (PK11_MALLOC_ERROR);
266*ccd81fddSJan Pechanec bad_uri:
267*ccd81fddSJan Pechanec 	free(str2);
268*ccd81fddSJan Pechanec 	pkcs11_free_uri(uri);
269*ccd81fddSJan Pechanec 	return (PK11_URI_INVALID);
270*ccd81fddSJan Pechanec value_overflow:
271*ccd81fddSJan Pechanec 	free(str2);
272*ccd81fddSJan Pechanec 	pkcs11_free_uri(uri);
273*ccd81fddSJan Pechanec 	return (PK11_URI_VALUE_OVERFLOW);
274*ccd81fddSJan Pechanec }
275*ccd81fddSJan Pechanec 
276*ccd81fddSJan Pechanec /*
277*ccd81fddSJan Pechanec  * Free the PKCS#11 URI structure attributes but do not free the structure
278*ccd81fddSJan Pechanec  * itself.
279*ccd81fddSJan Pechanec  */
280*ccd81fddSJan Pechanec void
pkcs11_free_uri(pkcs11_uri_t * uri)281*ccd81fddSJan Pechanec pkcs11_free_uri(pkcs11_uri_t *uri)
282*ccd81fddSJan Pechanec {
283*ccd81fddSJan Pechanec 	if (uri->object != NULL)
284*ccd81fddSJan Pechanec 		free(uri->object);
285*ccd81fddSJan Pechanec 	if (uri->token != NULL)
286*ccd81fddSJan Pechanec 		free(uri->token);
287*ccd81fddSJan Pechanec 	if (uri->manuf != NULL)
288*ccd81fddSJan Pechanec 		free(uri->manuf);
289*ccd81fddSJan Pechanec 	if (uri->serial != NULL)
290*ccd81fddSJan Pechanec 		free(uri->serial);
291*ccd81fddSJan Pechanec 	if (uri->model != NULL)
292*ccd81fddSJan Pechanec 		free(uri->model);
293*ccd81fddSJan Pechanec 	if (uri->id != NULL)
294*ccd81fddSJan Pechanec 		free(uri->id);
295*ccd81fddSJan Pechanec 	if (uri->pinfile != NULL)
296*ccd81fddSJan Pechanec 		free(uri->pinfile);
297*ccd81fddSJan Pechanec }