1 /*
2 * GnuTLS PKCS#11 support
3 * Copyright (C) 2010-2016 Free Software Foundation, Inc.
4 * Copyright (C) 2016 Red Hat
5 *
6 * Authors: Nikos Mavrogiannopoulos
7 *
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.
12 *
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.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>
20 */
21
22 #include "gnutls_int.h"
23 #include <gnutls/pkcs11.h>
24 #include <global.h>
25 #include "errors.h"
26 #include "x509/common.h"
27
28 #include <pkcs11_int.h>
29 #include <p11-kit/p11-kit.h>
30 #include "pkcs11x.h"
31
32 struct find_ext_data_st {
33 /* in */
34 gnutls_pkcs11_obj_t obj;
35 gnutls_datum_t spki;
36
37 /* out */
38 gnutls_x509_ext_st *exts;
39 unsigned int exts_size;
40 };
41
override_ext(gnutls_x509_crt_t crt,gnutls_datum_t * ext)42 static int override_ext(gnutls_x509_crt_t crt, gnutls_datum_t *ext)
43 {
44 gnutls_x509_ext_st parsed;
45 int ret;
46
47 ret = _gnutls_x509_decode_ext(ext, &parsed);
48 if (ret < 0)
49 return gnutls_assert_val(ret);
50
51 /* set the new extension */
52 ret = _gnutls_x509_crt_set_extension(crt, parsed.oid, &parsed.data, parsed.critical);
53 if (ret < 0) {
54 gnutls_assert();
55 goto cleanup;
56 }
57
58 ret = 0;
59 cleanup:
60 gnutls_x509_ext_deinit(&parsed);
61 return ret;
62 }
63
64 /* This function re-encodes a certificate to contain its stapled extensions.
65 * That assumes that the certificate is not in the distrusted list.
66 */
pkcs11_override_cert_exts(struct pkcs11_session_info * sinfo,gnutls_datum_t * spki,gnutls_datum_t * der)67 int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der)
68 {
69 int ret;
70 gnutls_datum_t new_der = {NULL, 0};
71 struct ck_attribute a[2];
72 struct ck_attribute b[1];
73 unsigned long count;
74 unsigned ext_data_size = der->size;
75 uint8_t *ext_data = NULL;
76 ck_object_class_t class = -1;
77 gnutls_x509_crt_t crt = NULL;
78 unsigned finalize = 0;
79 ck_rv_t rv;
80 ck_object_handle_t obj;
81
82 if (sinfo->trusted == 0) {
83 _gnutls_debug_log("p11: cannot override extensions on a non-p11-kit trust module\n");
84 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
85 }
86
87 /* retrieve the extensions */
88 class = CKO_X_CERTIFICATE_EXTENSION;
89 a[0].type = CKA_CLASS;
90 a[0].value = &class;
91 a[0].value_len = sizeof class;
92
93 a[1].type = CKA_PUBLIC_KEY_INFO;
94 a[1].value = spki->data;
95 a[1].value_len = spki->size;
96
97 rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
98 if (rv != CKR_OK) {
99 gnutls_assert();
100 _gnutls_debug_log
101 ("p11: FindObjectsInit failed for cert extensions.\n");
102 ret = pkcs11_rv_to_err(rv);
103 goto cleanup;
104 }
105 finalize = 1;
106
107 rv = pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count);
108 if (rv == CKR_OK && count == 1) {
109 ext_data = gnutls_malloc(ext_data_size);
110 if (ext_data == NULL) {
111 gnutls_assert();
112 ret = GNUTLS_E_MEMORY_ERROR;
113 goto cleanup;
114 }
115
116 ret = gnutls_x509_crt_init(&crt);
117 if (ret < 0) {
118 gnutls_assert();
119 goto cleanup;
120 }
121
122 ret = gnutls_x509_crt_import(crt, der, GNUTLS_X509_FMT_DER);
123 if (ret < 0) {
124 gnutls_assert();
125 goto cleanup;
126 }
127
128 do {
129
130 b[0].type = CKA_VALUE;
131 b[0].value = ext_data;
132 b[0].value_len = ext_data_size;
133
134 if (pkcs11_get_attribute_value
135 (sinfo->module, sinfo->pks, obj, b, 1) == CKR_OK) {
136 gnutls_datum_t data = { b[0].value, b[0].value_len };
137
138 ret = override_ext(crt, &data);
139 if (ret < 0) {
140 gnutls_assert();
141 goto cleanup;
142 }
143 }
144 } while (pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1);
145
146 /* overwrite the old certificate with the new */
147 ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &new_der);
148 if (ret < 0) {
149 gnutls_assert();
150 goto cleanup;
151 }
152
153 gnutls_free(der->data);
154 der->data = new_der.data;
155 der->size = new_der.size;
156 }
157
158 ret = 0;
159 cleanup:
160 if (crt != NULL)
161 gnutls_x509_crt_deinit(crt);
162 if (finalize != 0)
163 pkcs11_find_objects_final(sinfo);
164 gnutls_free(ext_data);
165 return ret;
166
167 }
168
169 static int
find_ext_cb(struct ck_function_list * module,struct pkcs11_session_info * sinfo,struct ck_token_info * tinfo,struct ck_info * lib_info,void * input)170 find_ext_cb(struct ck_function_list *module, struct pkcs11_session_info *sinfo,
171 struct ck_token_info *tinfo, struct ck_info *lib_info,
172 void *input)
173 {
174 struct find_ext_data_st *find_data = input;
175 struct ck_attribute a[4];
176 ck_object_class_t class = -1;
177 unsigned long count;
178 ck_rv_t rv;
179 ck_object_handle_t obj;
180 int ret;
181 gnutls_datum_t ext;
182
183 if (tinfo == NULL) { /* we don't support multiple calls */
184 gnutls_assert();
185 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
186 }
187
188 /* do not bother reading the token if basic fields do not match
189 */
190 if (!p11_kit_uri_match_token_info
191 (find_data->obj->info, tinfo)
192 || !p11_kit_uri_match_module_info(find_data->obj->info,
193 lib_info)) {
194 gnutls_assert();
195 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
196 }
197
198 /* retrieve the extensions */
199 class = CKO_X_CERTIFICATE_EXTENSION;
200 a[0].type = CKA_CLASS;
201 a[0].value = &class;
202 a[0].value_len = sizeof class;
203
204 a[1].type = CKA_PUBLIC_KEY_INFO;
205 a[1].value = find_data->spki.data;
206 a[1].value_len = find_data->spki.size;
207
208 rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
209 if (rv != CKR_OK) {
210 gnutls_assert();
211 _gnutls_debug_log
212 ("p11: FindObjectsInit failed for cert extensions.\n");
213 return pkcs11_rv_to_err(rv);
214 }
215
216 while(pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1) {
217 rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &ext);
218 if (rv == CKR_OK) {
219
220 find_data->exts = gnutls_realloc_fast(find_data->exts, (1+find_data->exts_size)*sizeof(find_data->exts[0]));
221 if (find_data->exts == NULL) {
222 gnutls_assert();
223 ret = pkcs11_rv_to_err(rv);
224 goto cleanup;
225 }
226
227 if (_gnutls_x509_decode_ext(&ext, &find_data->exts[find_data->exts_size]) == 0) {
228 find_data->exts_size++;
229 }
230 gnutls_free(ext.data);
231 }
232 }
233
234 ret = 0;
235 cleanup:
236 pkcs11_find_objects_final(sinfo);
237 return ret;
238 }
239
240 /**
241 * gnutls_pkcs11_obj_get_exts:
242 * @obj: should contain a #gnutls_pkcs11_obj_t type
243 * @exts: a pointer to a %gnutls_x509_ext_st pointer
244 * @exts_size: will be updated with the number of @exts
245 * @flags: Or sequence of %GNUTLS_PKCS11_OBJ_* flags
246 *
247 * This function will return information about attached extensions
248 * that associate to the provided object (which should be a certificate).
249 * The extensions are the attached p11-kit trust module extensions.
250 *
251 * Each element of @exts must be deinitialized using gnutls_x509_ext_deinit()
252 * while @exts should be deallocated using gnutls_free().
253 *
254 * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
255 *
256 * Since: 3.3.8
257 **/
258 int
gnutls_pkcs11_obj_get_exts(gnutls_pkcs11_obj_t obj,gnutls_x509_ext_st ** exts,unsigned int * exts_size,unsigned int flags)259 gnutls_pkcs11_obj_get_exts(gnutls_pkcs11_obj_t obj,
260 gnutls_x509_ext_st **exts, unsigned int *exts_size,
261 unsigned int flags)
262 {
263 int ret;
264 gnutls_datum_t spki = {NULL, 0};
265 struct find_ext_data_st find_data;
266 unsigned deinit_spki = 0;
267
268 PKCS11_CHECK_INIT;
269 memset(&find_data, 0, sizeof(find_data));
270
271 *exts_size = 0;
272
273 if (obj->type != GNUTLS_PKCS11_OBJ_X509_CRT && obj->type != GNUTLS_PKCS11_OBJ_PUBKEY)
274 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
275
276 if (obj->type == GNUTLS_PKCS11_OBJ_PUBKEY) {
277 spki.data = obj->raw.data;
278 spki.size = obj->raw.size;
279 } else {
280 ret = _gnutls_x509_raw_crt_to_raw_pubkey(&obj->raw, &spki);
281 if (ret < 0)
282 return gnutls_assert_val(ret);
283 deinit_spki = 1;
284 }
285
286 find_data.spki.data = spki.data;
287 find_data.spki.size = spki.size;
288 find_data.obj = obj;
289 ret =
290 _pkcs11_traverse_tokens(find_ext_cb, &find_data, obj->info,
291 &obj->pin,
292 pkcs11_obj_flags_to_int(flags));
293 if (ret < 0) {
294 gnutls_assert();
295 goto cleanup;
296 }
297
298 *exts = find_data.exts;
299 *exts_size = find_data.exts_size;
300
301 ret = 0;
302 cleanup:
303 if (deinit_spki)
304 gnutls_free(spki.data);
305 return ret;
306 }
307
308