2 * GnuTLS PKCS#11 support
3 * Copyright (C) 2010-2014 Free Software Foundation, Inc.
4 * Copyright (C) 2014 Red Hat
6 * Authors: Nikos Mavrogiannopoulos
8 * GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
22 #include <gnutls_int.h>
23 #include <gnutls/pkcs11.h>
24 #include <gnutls_global.h>
25 #include <gnutls_errors.h>
26 #include "x509/common.h"
28 #include <pkcs11_int.h>
29 #include <p11-kit/p11-kit.h>
32 struct find_ext_data_st {
34 gnutls_pkcs11_obj_t obj;
38 gnutls_x509_ext_st *exts;
39 unsigned int exts_size;
42 static int override_ext(gnutls_x509_crt_t crt, gnutls_datum_t *ext)
44 gnutls_x509_ext_st parsed;
47 ret = _gnutls_x509_decode_ext(ext, &parsed);
49 return gnutls_assert_val(ret);
51 /* set the new extension */
52 ret = _gnutls_x509_crt_set_extension(crt, parsed.oid, &parsed.data, parsed.critical);
60 gnutls_x509_ext_deinit(&parsed);
64 int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der)
67 gnutls_datum_t new_der = {NULL, 0};
68 struct ck_attribute a[2];
69 struct ck_attribute b[1];
71 unsigned ext_data_size = der->size;
72 uint8_t *ext_data = NULL;
73 ck_object_class_t class = -1;
74 gnutls_x509_crt_t crt = NULL;
75 unsigned finalize = 0;
77 ck_object_handle_t obj;
79 /* retrieve the extensions */
80 class = CKO_X_CERTIFICATE_EXTENSION;
81 a[0].type = CKA_CLASS;
83 a[0].value_len = sizeof class;
85 a[1].type = CKA_PUBLIC_KEY_INFO;
86 a[1].value = spki->data;
87 a[1].value_len = spki->size;
89 rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
93 ("p11: FindObjectsInit failed for cert extensions.\n");
94 ret = pkcs11_rv_to_err(rv);
99 rv = pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count);
100 if (rv == CKR_OK && count == 1) {
101 ext_data = gnutls_malloc(ext_data_size);
102 if (ext_data == NULL) {
104 ret = GNUTLS_E_MEMORY_ERROR;
108 ret = gnutls_x509_crt_init(&crt);
114 ret = gnutls_x509_crt_import(crt, der, GNUTLS_X509_FMT_DER);
122 b[0].type = CKA_VALUE;
123 b[0].value = ext_data;
124 b[0].value_len = ext_data_size;
126 if (pkcs11_get_attribute_value
127 (sinfo->module, sinfo->pks, obj, b, 1) == CKR_OK) {
128 gnutls_datum_t data = { b[0].value, b[0].value_len };
130 ret = override_ext(crt, &data);
136 } while (pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1);
138 /* overwrite the old certificate with the new */
139 ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &new_der);
145 gnutls_free(der->data);
146 der->data = new_der.data;
147 der->size = new_der.size;
153 gnutls_x509_crt_deinit(crt);
155 pkcs11_find_objects_final(sinfo);
156 gnutls_free(ext_data);
162 find_ext_cb(struct pkcs11_session_info *sinfo,
163 struct token_info *info, struct ck_info *lib_info,
166 struct find_ext_data_st *find_data = input;
167 struct ck_attribute a[4];
168 ck_object_class_t class = -1;
171 ck_object_handle_t obj;
175 if (info == NULL) { /* we don't support multiple calls */
177 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
180 /* do not bother reading the token if basic fields do not match
182 if (!p11_kit_uri_match_token_info
183 (find_data->obj->info, &info->tinfo)
184 || !p11_kit_uri_match_module_info(find_data->obj->info,
187 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
190 /* retrieve the extensions */
191 class = CKO_X_CERTIFICATE_EXTENSION;
192 a[0].type = CKA_CLASS;
194 a[0].value_len = sizeof class;
196 a[1].type = CKA_PUBLIC_KEY_INFO;
197 a[1].value = find_data->spki.data;
198 a[1].value_len = find_data->spki.size;
200 rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
204 ("p11: FindObjectsInit failed for cert extensions.\n");
205 return pkcs11_rv_to_err(rv);
208 while(pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1) {
209 rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &ext);
212 find_data->exts = gnutls_realloc_fast(find_data->exts, (1+find_data->exts_size)*sizeof(find_data->exts[0]));
213 if (find_data->exts == NULL) {
215 ret = pkcs11_rv_to_err(rv);
219 if (_gnutls_x509_decode_ext(&ext, &find_data->exts[find_data->exts_size]) == 0) {
220 find_data->exts_size++;
222 gnutls_free(ext.data);
228 pkcs11_find_objects_final(sinfo);
233 * gnutls_pkcs11_obj_get_exts:
234 * @obj: should contain a #gnutls_pkcs11_obj_t type
235 * @exts: a pointer to a %gnutls_x509_ext_st pointer
236 * @exts_size: will be updated with the number of @exts
237 * @flags: Or sequence of %GNUTLS_PKCS11_OBJ_* flags
239 * This function will return information about attached extensions
240 * that associate to the provided object (which should be a certificate).
241 * The extensions are the attached p11-kit trust module extensions.
243 * Each element of @exts must be deinitialized using gnutls_x509_ext_deinit()
244 * while @exts should be deallocated using gnutls_free().
246 * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
251 gnutls_pkcs11_obj_get_exts(gnutls_pkcs11_obj_t obj,
252 gnutls_x509_ext_st **exts, unsigned int *exts_size,
256 gnutls_datum_t spki = {NULL, 0};
257 struct find_ext_data_st find_data;
258 unsigned deinit_spki = 0;
261 memset(&find_data, 0, sizeof(find_data));
265 if (obj->type != GNUTLS_PKCS11_OBJ_X509_CRT && obj->type != GNUTLS_PKCS11_OBJ_PUBKEY)
266 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
268 if (obj->type == GNUTLS_PKCS11_OBJ_PUBKEY) {
269 spki.data = obj->raw.data;
270 spki.size = obj->raw.size;
272 ret = x509_raw_crt_to_raw_pubkey(&obj->raw, &spki);
274 return gnutls_assert_val(ret);
278 find_data.spki.data = spki.data;
279 find_data.spki.size = spki.size;
282 _pkcs11_traverse_tokens(find_ext_cb, &find_data, obj->info,
284 pkcs11_obj_flags_to_int(flags));
290 *exts = find_data.exts;
291 *exts_size = find_data.exts_size;
296 gnutls_free(spki.data);