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