Line data Source code
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 :
42 7 : static int override_ext(gnutls_x509_crt_t crt, gnutls_datum_t *ext)
43 : {
44 7 : gnutls_x509_ext_st parsed;
45 7 : int ret;
46 :
47 7 : ret = _gnutls_x509_decode_ext(ext, &parsed);
48 7 : if (ret < 0)
49 0 : return gnutls_assert_val(ret);
50 :
51 : /* set the new extension */
52 7 : ret = _gnutls_x509_crt_set_extension(crt, parsed.oid, &parsed.data, parsed.critical);
53 7 : if (ret < 0) {
54 0 : gnutls_assert();
55 0 : goto cleanup;
56 : }
57 :
58 : ret = 0;
59 7 : cleanup:
60 7 : gnutls_x509_ext_deinit(&parsed);
61 7 : 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 : */
67 82 : int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der)
68 : {
69 82 : int ret;
70 82 : gnutls_datum_t new_der = {NULL, 0};
71 82 : struct ck_attribute a[2];
72 82 : struct ck_attribute b[1];
73 82 : unsigned long count;
74 82 : unsigned ext_data_size = der->size;
75 82 : uint8_t *ext_data = NULL;
76 82 : ck_object_class_t class = -1;
77 82 : gnutls_x509_crt_t crt = NULL;
78 82 : unsigned finalize = 0;
79 82 : ck_rv_t rv;
80 82 : ck_object_handle_t obj;
81 :
82 82 : if (sinfo->trusted == 0) {
83 0 : _gnutls_debug_log("p11: cannot override extensions on a non-p11-kit trust module\n");
84 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
85 : }
86 :
87 : /* retrieve the extensions */
88 82 : class = CKO_X_CERTIFICATE_EXTENSION;
89 82 : a[0].type = CKA_CLASS;
90 82 : a[0].value = &class;
91 82 : a[0].value_len = sizeof class;
92 :
93 82 : a[1].type = CKA_PUBLIC_KEY_INFO;
94 82 : a[1].value = spki->data;
95 82 : a[1].value_len = spki->size;
96 :
97 82 : rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
98 82 : if (rv != CKR_OK) {
99 0 : gnutls_assert();
100 0 : _gnutls_debug_log
101 : ("p11: FindObjectsInit failed for cert extensions.\n");
102 0 : ret = pkcs11_rv_to_err(rv);
103 0 : goto cleanup;
104 : }
105 82 : finalize = 1;
106 :
107 82 : rv = pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count);
108 82 : if (rv == CKR_OK && count == 1) {
109 4 : ext_data = gnutls_malloc(ext_data_size);
110 4 : if (ext_data == NULL) {
111 0 : gnutls_assert();
112 0 : ret = GNUTLS_E_MEMORY_ERROR;
113 0 : goto cleanup;
114 : }
115 :
116 4 : ret = gnutls_x509_crt_init(&crt);
117 4 : if (ret < 0) {
118 0 : gnutls_assert();
119 0 : goto cleanup;
120 : }
121 :
122 4 : ret = gnutls_x509_crt_import(crt, der, GNUTLS_X509_FMT_DER);
123 4 : if (ret < 0) {
124 0 : gnutls_assert();
125 0 : goto cleanup;
126 : }
127 :
128 7 : do {
129 :
130 7 : b[0].type = CKA_VALUE;
131 7 : b[0].value = ext_data;
132 7 : b[0].value_len = ext_data_size;
133 :
134 7 : if (pkcs11_get_attribute_value
135 : (sinfo->module, sinfo->pks, obj, b, 1) == CKR_OK) {
136 7 : gnutls_datum_t data = { b[0].value, b[0].value_len };
137 :
138 7 : ret = override_ext(crt, &data);
139 7 : if (ret < 0) {
140 0 : gnutls_assert();
141 0 : goto cleanup;
142 : }
143 : }
144 7 : } 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 4 : ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &new_der);
148 4 : if (ret < 0) {
149 0 : gnutls_assert();
150 0 : goto cleanup;
151 : }
152 :
153 4 : gnutls_free(der->data);
154 4 : der->data = new_der.data;
155 4 : der->size = new_der.size;
156 : }
157 :
158 : ret = 0;
159 82 : cleanup:
160 82 : if (crt != NULL)
161 4 : gnutls_x509_crt_deinit(crt);
162 82 : if (finalize != 0)
163 82 : pkcs11_find_objects_final(sinfo);
164 82 : gnutls_free(ext_data);
165 82 : return ret;
166 :
167 : }
168 :
169 : static int
170 1 : 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 1 : struct find_ext_data_st *find_data = input;
175 1 : struct ck_attribute a[4];
176 1 : ck_object_class_t class = -1;
177 1 : unsigned long count;
178 1 : ck_rv_t rv;
179 1 : ck_object_handle_t obj;
180 1 : int ret;
181 1 : gnutls_datum_t ext;
182 :
183 1 : if (tinfo == NULL) { /* we don't support multiple calls */
184 0 : gnutls_assert();
185 0 : return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
186 : }
187 :
188 : /* do not bother reading the token if basic fields do not match
189 : */
190 1 : if (!p11_kit_uri_match_token_info
191 1 : (find_data->obj->info, tinfo)
192 1 : || !p11_kit_uri_match_module_info(find_data->obj->info,
193 : lib_info)) {
194 0 : gnutls_assert();
195 0 : return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
196 : }
197 :
198 : /* retrieve the extensions */
199 1 : class = CKO_X_CERTIFICATE_EXTENSION;
200 1 : a[0].type = CKA_CLASS;
201 1 : a[0].value = &class;
202 1 : a[0].value_len = sizeof class;
203 :
204 1 : a[1].type = CKA_PUBLIC_KEY_INFO;
205 1 : a[1].value = find_data->spki.data;
206 1 : a[1].value_len = find_data->spki.size;
207 :
208 1 : rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
209 1 : if (rv != CKR_OK) {
210 0 : gnutls_assert();
211 0 : _gnutls_debug_log
212 : ("p11: FindObjectsInit failed for cert extensions.\n");
213 0 : return pkcs11_rv_to_err(rv);
214 : }
215 :
216 3 : while(pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1) {
217 2 : rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &ext);
218 2 : if (rv == CKR_OK) {
219 :
220 2 : find_data->exts = gnutls_realloc_fast(find_data->exts, (1+find_data->exts_size)*sizeof(find_data->exts[0]));
221 2 : if (find_data->exts == NULL) {
222 0 : gnutls_assert();
223 0 : ret = pkcs11_rv_to_err(rv);
224 0 : goto cleanup;
225 : }
226 :
227 2 : if (_gnutls_x509_decode_ext(&ext, &find_data->exts[find_data->exts_size]) == 0) {
228 2 : find_data->exts_size++;
229 : }
230 2 : gnutls_free(ext.data);
231 : }
232 : }
233 :
234 : ret = 0;
235 1 : cleanup:
236 1 : pkcs11_find_objects_final(sinfo);
237 1 : 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
259 1 : 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 1 : int ret;
264 1 : gnutls_datum_t spki = {NULL, 0};
265 1 : struct find_ext_data_st find_data;
266 1 : unsigned deinit_spki = 0;
267 :
268 1 : PKCS11_CHECK_INIT;
269 1 : memset(&find_data, 0, sizeof(find_data));
270 :
271 1 : *exts_size = 0;
272 :
273 1 : if (obj->type != GNUTLS_PKCS11_OBJ_X509_CRT && obj->type != GNUTLS_PKCS11_OBJ_PUBKEY)
274 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
275 :
276 1 : if (obj->type == GNUTLS_PKCS11_OBJ_PUBKEY) {
277 0 : spki.data = obj->raw.data;
278 0 : spki.size = obj->raw.size;
279 : } else {
280 1 : ret = _gnutls_x509_raw_crt_to_raw_pubkey(&obj->raw, &spki);
281 1 : if (ret < 0)
282 0 : return gnutls_assert_val(ret);
283 : deinit_spki = 1;
284 : }
285 :
286 1 : find_data.spki.data = spki.data;
287 1 : find_data.spki.size = spki.size;
288 1 : find_data.obj = obj;
289 1 : ret =
290 1 : _pkcs11_traverse_tokens(find_ext_cb, &find_data, obj->info,
291 : &obj->pin,
292 : pkcs11_obj_flags_to_int(flags));
293 1 : if (ret < 0) {
294 0 : gnutls_assert();
295 0 : goto cleanup;
296 : }
297 :
298 1 : *exts = find_data.exts;
299 1 : *exts_size = find_data.exts_size;
300 :
301 1 : ret = 0;
302 1 : cleanup:
303 1 : if (deinit_spki)
304 1 : gnutls_free(spki.data);
305 : return ret;
306 : }
307 :
|