1 /* libp11, a simple layer on to of PKCS#11 API
2 * Copyright (C) 2005 Olaf Kirch <okir@lst.de>
3 * Copyright (C) 2016-2018 Michał Trojnara <Michal.Trojnara@stunnel.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /*
21 * p11_cert.c - Handle certificates residing on a PKCS11 token
22 *
23 * Copyright (C) 2002, Olaf Kirch <okir@lst.de>
24 */
25
26 #include "libp11-int.h"
27 #include <string.h>
28
29 static int pkcs11_find_certs(PKCS11_TOKEN *);
30 static int pkcs11_next_cert(PKCS11_CTX *, PKCS11_TOKEN *, CK_SESSION_HANDLE);
31 static int pkcs11_init_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
32 CK_SESSION_HANDLE session, CK_OBJECT_HANDLE o, PKCS11_CERT **);
33
34 /*
35 * Enumerate all certs on the card
36 */
pkcs11_enumerate_certs(PKCS11_TOKEN * token,PKCS11_CERT ** certp,unsigned int * countp)37 int pkcs11_enumerate_certs(PKCS11_TOKEN *token,
38 PKCS11_CERT **certp, unsigned int *countp)
39 {
40 PKCS11_SLOT *slot = TOKEN2SLOT(token);
41 PKCS11_CTX *ctx = SLOT2CTX(slot);
42 PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
43 PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
44 PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
45 int rv;
46
47 /* Make sure we have a session */
48 if (!spriv->haveSession && PKCS11_open_session(slot, 0))
49 return -1;
50
51 CRYPTO_THREAD_write_lock(cpriv->rwlock);
52 rv = pkcs11_find_certs(token);
53 CRYPTO_THREAD_unlock(cpriv->rwlock);
54 if (rv < 0) {
55 pkcs11_destroy_certs(token);
56 return -1;
57 }
58
59 if (certp)
60 *certp = tpriv->certs;
61 if (countp)
62 *countp = tpriv->ncerts;
63 return 0;
64 }
65
66 /**
67 * Remove a certificate from the associated token
68 */
pkcs11_remove_certificate(PKCS11_CERT * cert)69 int pkcs11_remove_certificate(PKCS11_CERT *cert){
70 PKCS11_SLOT *slot = CERT2SLOT(cert);
71 PKCS11_CTX *ctx = CERT2CTX(cert);
72 PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
73 CK_OBJECT_HANDLE obj;
74 CK_ULONG count;
75 CK_ATTRIBUTE search_parameters[32];
76 unsigned int n = 0;
77 int rv;
78
79 /* First, make sure we have a session */
80 if (!spriv->haveSession && PKCS11_open_session(slot, 1)){
81 return -1;
82 }
83
84 pkcs11_addattr_int(search_parameters + n++, CKA_CLASS, CKO_CERTIFICATE);
85 if (cert->id && cert->id_len){
86 pkcs11_addattr(search_parameters + n++, CKA_ID, cert->id, cert->id_len);
87 }
88 if (cert->label){
89 pkcs11_addattr_s(search_parameters + n++, CKA_LABEL, cert->label);
90 }
91
92 rv = CRYPTOKI_call(ctx,
93 C_FindObjectsInit(spriv->session, search_parameters, n));
94 CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_CERTIFICATE, rv);
95
96 rv = CRYPTOKI_call(ctx, C_FindObjects(spriv->session, &obj, 1, &count));
97 CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_CERTIFICATE, rv);
98
99 CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
100 if (count!=1){
101 pkcs11_zap_attrs(search_parameters, n);
102 return -1;
103 }
104 rv = CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, obj));
105 if (rv != CKR_OK){
106 pkcs11_zap_attrs(search_parameters, n);
107 return -1;
108 }
109 pkcs11_zap_attrs(search_parameters, n);
110 return 0;
111 }
112
113 /*
114 * Find certificate matching a key
115 */
pkcs11_find_certificate(PKCS11_KEY * key)116 PKCS11_CERT *pkcs11_find_certificate(PKCS11_KEY *key)
117 {
118 PKCS11_KEY_private *kpriv;
119 PKCS11_CERT_private *cpriv;
120 PKCS11_CERT *cert;
121 unsigned int n, count;
122
123 kpriv = PRIVKEY(key);
124 if (PKCS11_enumerate_certs(KEY2TOKEN(key), &cert, &count))
125 return NULL;
126 for (n = 0; n < count; n++, cert++) {
127 cpriv = PRIVCERT(cert);
128 if (cpriv->id_len == kpriv->id_len
129 && !memcmp(cpriv->id, kpriv->id, kpriv->id_len))
130 return cert;
131 }
132 return NULL;
133 }
134
135 /*
136 * Find all certs of a given type (public or private)
137 */
pkcs11_find_certs(PKCS11_TOKEN * token)138 static int pkcs11_find_certs(PKCS11_TOKEN *token)
139 {
140 PKCS11_SLOT *slot = TOKEN2SLOT(token);
141 PKCS11_CTX *ctx = SLOT2CTX(slot);
142 PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
143 CK_OBJECT_CLASS cert_search_class;
144 CK_ATTRIBUTE cert_search_attrs[] = {
145 {CKA_CLASS, &cert_search_class, sizeof(cert_search_class)},
146 };
147 int rv, res = -1;
148
149 /* Tell the PKCS11 lib to enumerate all matching objects */
150 cert_search_class = CKO_CERTIFICATE;
151 rv = CRYPTOKI_call(ctx, C_FindObjectsInit(spriv->session, cert_search_attrs, 1));
152 CRYPTOKI_checkerr(CKR_F_PKCS11_FIND_CERTS, rv);
153
154 do {
155 res = pkcs11_next_cert(ctx, token, spriv->session);
156 } while (res == 0);
157
158 CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
159
160 return (res < 0) ? -1 : 0;
161 }
162
pkcs11_next_cert(PKCS11_CTX * ctx,PKCS11_TOKEN * token,CK_SESSION_HANDLE session)163 static int pkcs11_next_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
164 CK_SESSION_HANDLE session)
165 {
166 CK_OBJECT_HANDLE obj;
167 CK_ULONG count;
168 int rv;
169
170 /* Get the next matching object */
171 rv = CRYPTOKI_call(ctx, C_FindObjects(session, &obj, 1, &count));
172 CRYPTOKI_checkerr(CKR_F_PKCS11_NEXT_CERT, rv);
173
174 if (count == 0)
175 return 1;
176
177 if (pkcs11_init_cert(ctx, token, session, obj, NULL))
178 return -1;
179
180 return 0;
181 }
182
pkcs11_init_cert(PKCS11_CTX * ctx,PKCS11_TOKEN * token,CK_SESSION_HANDLE session,CK_OBJECT_HANDLE obj,PKCS11_CERT ** ret)183 static int pkcs11_init_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
184 CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, PKCS11_CERT ** ret)
185 {
186 PKCS11_TOKEN_private *tpriv;
187 PKCS11_CERT_private *cpriv;
188 PKCS11_CERT *cert, *tmp;
189 unsigned char *data;
190 CK_CERTIFICATE_TYPE cert_type;
191 size_t size;
192 int i;
193
194 (void)ctx;
195 (void)session;
196
197 /* Ignore unknown certificate types */
198 size = sizeof(CK_CERTIFICATE_TYPE);
199 if (pkcs11_getattr_var(token, obj, CKA_CERTIFICATE_TYPE, (CK_BYTE *)&cert_type, &size))
200 return -1;
201 if (cert_type != CKC_X_509)
202 return 0;
203
204 /* Prevent re-adding existing PKCS#11 object handles */
205 /* TODO: Rewrite the O(n) algorithm as O(log n),
206 * or it may be too slow with a large number of certificates */
207 for (i=0; i < PRIVTOKEN(token)->ncerts; ++i)
208 if (PRIVCERT(PRIVTOKEN(token)->certs + i)->object == obj)
209 return 0;
210
211 /* Allocate memory */
212 cpriv = OPENSSL_malloc(sizeof(PKCS11_CERT_private));
213 if (!cpriv)
214 return -1;
215 memset(cpriv, 0, sizeof(PKCS11_CERT_private));
216 tpriv = PRIVTOKEN(token);
217 tmp = OPENSSL_realloc(tpriv->certs,
218 (tpriv->ncerts + 1) * sizeof(PKCS11_CERT));
219 if (!tmp)
220 return -1;
221 tpriv->certs = tmp;
222 cert = tpriv->certs + tpriv->ncerts++;
223 memset(cert, 0, sizeof(PKCS11_CERT));
224
225 /* Fill public properties */
226 pkcs11_getattr_alloc(token, obj, CKA_LABEL, (CK_BYTE **)&cert->label, NULL);
227 size = 0;
228 if (!pkcs11_getattr_alloc(token, obj, CKA_VALUE, &data, &size)) {
229 const unsigned char *p = data;
230
231 cert->x509 = d2i_X509(NULL, &p, (long)size);
232 OPENSSL_free(data);
233 }
234 cert->id_len = 0;
235 pkcs11_getattr_alloc(token, obj, CKA_ID, &cert->id, &cert->id_len);
236
237 /* Fill private properties */
238 cert->_private = cpriv;
239 cpriv->object = obj;
240 cpriv->parent = token;
241 cpriv->id_len = sizeof cpriv->id;
242 if (pkcs11_getattr_var(token, obj, CKA_ID, cpriv->id, &cpriv->id_len))
243 cpriv->id_len = 0;
244
245 if (ret)
246 *ret = cert;
247 return 0;
248 }
249
250 /*
251 * Destroy all certs
252 */
pkcs11_destroy_certs(PKCS11_TOKEN * token)253 void pkcs11_destroy_certs(PKCS11_TOKEN *token)
254 {
255 PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
256
257 while (tpriv->ncerts > 0) {
258 PKCS11_CERT *cert = &tpriv->certs[--(tpriv->ncerts)];
259
260 if (cert->x509)
261 X509_free(cert->x509);
262 OPENSSL_free(cert->label);
263 if (cert->id)
264 OPENSSL_free(cert->id);
265 if (cert->_private)
266 OPENSSL_free(cert->_private);
267 }
268 if (tpriv->certs)
269 OPENSSL_free(tpriv->certs);
270 tpriv->certs = NULL;
271 tpriv->ncerts = 0;
272 }
273
274 /*
275 * Store certificate
276 */
pkcs11_store_certificate(PKCS11_TOKEN * token,X509 * x509,char * label,unsigned char * id,size_t id_len,PKCS11_CERT ** ret_cert)277 int pkcs11_store_certificate(PKCS11_TOKEN *token, X509 *x509, char *label,
278 unsigned char *id, size_t id_len, PKCS11_CERT ** ret_cert)
279 {
280 PKCS11_SLOT *slot = TOKEN2SLOT(token);
281 PKCS11_CTX *ctx = SLOT2CTX(slot);
282 PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
283 CK_OBJECT_HANDLE object;
284 CK_ATTRIBUTE attrs[32];
285 unsigned int n = 0;
286 int rv;
287 int signature_nid;
288 const EVP_MD* evp_md;
289 CK_MECHANISM_TYPE ckm_md;
290 unsigned char md[EVP_MAX_MD_SIZE];
291 unsigned int md_len;
292
293 /* First, make sure we have a session */
294 if (!PRIVSLOT(slot)->haveSession && PKCS11_open_session(slot, 1))
295 return -1;
296
297 /* Now build the template */
298 pkcs11_addattr_int(attrs + n++, CKA_CLASS, CKO_CERTIFICATE);
299 pkcs11_addattr_bool(attrs + n++, CKA_TOKEN, TRUE);
300 pkcs11_addattr_int(attrs + n++, CKA_CERTIFICATE_TYPE, CKC_X_509);
301 pkcs11_addattr_obj(attrs + n++, CKA_SUBJECT,
302 (pkcs11_i2d_fn)i2d_X509_NAME, X509_get_subject_name(x509));
303 pkcs11_addattr_obj(attrs + n++, CKA_ISSUER,
304 (pkcs11_i2d_fn)i2d_X509_NAME, X509_get_issuer_name(x509));
305
306 /* Get digest algorithm from x509 certificate */
307 #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
308 signature_nid = X509_get_signature_nid(x509);
309 #else
310 signature_nid = OBJ_obj2nid(x509->sig_alg->algorithm);
311 #endif
312 evp_md = EVP_get_digestbynid(signature_nid);
313 switch (EVP_MD_type(evp_md)) {
314 default:
315 case NID_sha1:
316 ckm_md = CKM_SHA_1;
317 break;
318 case NID_sha224:
319 ckm_md = CKM_SHA224;
320 break;
321 case NID_sha256:
322 ckm_md = CKM_SHA256;
323 break;
324 case NID_sha512:
325 ckm_md = CKM_SHA512;
326 break;
327 case NID_sha384:
328 ckm_md = CKM_SHA384;
329 break;
330 }
331
332 /* Set hash algorithm; default is SHA-1 */
333 pkcs11_addattr_int(attrs + n++, CKA_NAME_HASH_ALGORITHM, ckm_md);
334 if(X509_pubkey_digest(x509,evp_md,md,&md_len))
335 pkcs11_addattr(attrs + n++, CKA_HASH_OF_SUBJECT_PUBLIC_KEY,md,md_len);
336
337 pkcs11_addattr_obj(attrs + n++, CKA_VALUE, (pkcs11_i2d_fn)i2d_X509, x509);
338 if (label)
339 pkcs11_addattr_s(attrs + n++, CKA_LABEL, label);
340 if (id && id_len)
341 pkcs11_addattr(attrs + n++, CKA_ID, id, id_len);
342
343 /* Now call the pkcs11 module to create the object */
344 rv = CRYPTOKI_call(ctx, C_CreateObject(spriv->session, attrs, n, &object));
345
346 /* Zap all memory allocated when building the template */
347 pkcs11_zap_attrs(attrs, n);
348
349 CRYPTOKI_checkerr(CKR_F_PKCS11_STORE_CERTIFICATE, rv);
350
351 /* Gobble the key object */
352 return pkcs11_init_cert(ctx, token, spriv->session, object, ret_cert);
353 }
354
355 /* vim: set noexpandtab: */
356