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