Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / lib / pkcs11x.c
1 /*
2  * GnuTLS PKCS#11 support
3  * Copyright (C) 2010-2014 Free Software Foundation, Inc.
4  * Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
20  */
21
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"
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 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 int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der)
65 {
66         int ret;
67         gnutls_datum_t new_der = {NULL, 0};
68         struct ck_attribute a[2];
69         struct ck_attribute b[1];
70         unsigned long count;
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;
76         ck_rv_t rv;
77         ck_object_handle_t obj;
78
79         /* retrieve the extensions */
80         class = CKO_X_CERTIFICATE_EXTENSION;
81         a[0].type = CKA_CLASS;
82         a[0].value = &class;
83         a[0].value_len = sizeof class;
84
85         a[1].type = CKA_PUBLIC_KEY_INFO;
86         a[1].value = spki->data;
87         a[1].value_len = spki->size;
88
89         rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
90         if (rv != CKR_OK) {
91                 gnutls_assert();
92                 _gnutls_debug_log
93                     ("p11: FindObjectsInit failed for cert extensions.\n");
94                 ret = pkcs11_rv_to_err(rv);
95                 goto cleanup;
96         }
97         finalize = 1;
98
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) {
103                         gnutls_assert();
104                         ret = GNUTLS_E_MEMORY_ERROR;
105                         goto cleanup;
106                 }
107
108                 ret = gnutls_x509_crt_init(&crt);
109                 if (ret < 0) {
110                         gnutls_assert();
111                         goto cleanup;
112                 }
113
114                 ret = gnutls_x509_crt_import(crt, der, GNUTLS_X509_FMT_DER);
115                 if (ret < 0) {
116                         gnutls_assert();
117                         goto cleanup;
118                 }
119
120                 do {
121
122                         b[0].type = CKA_VALUE;
123                         b[0].value = ext_data;
124                         b[0].value_len = ext_data_size;
125
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 };
129
130                                 ret = override_ext(crt, &data);
131                                 if (ret < 0) {
132                                         gnutls_assert();
133                                         goto cleanup;
134                                 }
135                         }
136                 } while (pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1);
137
138                 /* overwrite the old certificate with the new */
139                 ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &new_der);
140                 if (ret < 0) {
141                         gnutls_assert();
142                         goto cleanup;
143                 }
144
145                 gnutls_free(der->data);
146                 der->data = new_der.data;
147                 der->size = new_der.size;
148         }
149
150         ret = 0;
151  cleanup:
152         if (crt != NULL)
153                 gnutls_x509_crt_deinit(crt);
154         if (finalize != 0)
155                 pkcs11_find_objects_final(sinfo);
156         gnutls_free(ext_data);
157         return ret;
158
159 }
160
161 static int
162 find_ext_cb(struct pkcs11_session_info *sinfo,
163              struct token_info *info, struct ck_info *lib_info,
164              void *input)
165 {
166         struct find_ext_data_st *find_data = input;
167         struct ck_attribute a[4];
168         ck_object_class_t class = -1;
169         unsigned long count;
170         ck_rv_t rv;
171         ck_object_handle_t obj;
172         int ret;
173         gnutls_datum_t ext;
174
175         if (info == NULL) {     /* we don't support multiple calls */
176                 gnutls_assert();
177                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
178         }
179
180         /* do not bother reading the token if basic fields do not match
181          */
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,
185                                               lib_info)) {
186                 gnutls_assert();
187                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
188         }
189
190         /* retrieve the extensions */
191         class = CKO_X_CERTIFICATE_EXTENSION;
192         a[0].type = CKA_CLASS;
193         a[0].value = &class;
194         a[0].value_len = sizeof class;
195
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;
199
200         rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
201         if (rv != CKR_OK) {
202                 gnutls_assert();
203                 _gnutls_debug_log
204                     ("p11: FindObjectsInit failed for cert extensions.\n");
205                 return pkcs11_rv_to_err(rv);
206         }
207
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);
210                 if (rv == CKR_OK) {
211
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) {
214                                 gnutls_assert();
215                                 ret = pkcs11_rv_to_err(rv);
216                                 goto cleanup;
217                         }
218
219                         if (_gnutls_x509_decode_ext(&ext, &find_data->exts[find_data->exts_size]) == 0) {
220                                 find_data->exts_size++;
221                         }
222                         gnutls_free(ext.data);
223                 }
224         }
225
226         ret = 0;
227  cleanup:
228         pkcs11_find_objects_final(sinfo);
229         return ret;
230 }
231
232 /**
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 
238  *
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.
242  *
243  * Each element of @exts must be deinitialized using gnutls_x509_ext_deinit()
244  * while @exts should be deallocated using gnutls_free().
245  *
246  * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
247  *
248  * Since: 3.3.8
249  **/
250 int
251 gnutls_pkcs11_obj_get_exts(gnutls_pkcs11_obj_t obj,
252                            gnutls_x509_ext_st **exts, unsigned int *exts_size,
253                            unsigned int flags)
254 {
255         int ret;
256         gnutls_datum_t spki = {NULL, 0};
257         struct find_ext_data_st find_data;
258         unsigned deinit_spki = 0;
259
260         PKCS11_CHECK_INIT;
261         memset(&find_data, 0, sizeof(find_data));
262
263         *exts_size = 0;
264
265         if (obj->type != GNUTLS_PKCS11_OBJ_X509_CRT && obj->type != GNUTLS_PKCS11_OBJ_PUBKEY)
266                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
267
268         if (obj->type == GNUTLS_PKCS11_OBJ_PUBKEY) {
269                 spki.data = obj->raw.data;
270                 spki.size = obj->raw.size;
271         } else {
272                 ret = x509_raw_crt_to_raw_pubkey(&obj->raw, &spki);
273                 if (ret < 0)
274                         return gnutls_assert_val(ret);
275                 deinit_spki = 1;
276         }
277
278         find_data.spki.data = spki.data;
279         find_data.spki.size = spki.size;
280         find_data.obj = obj;
281         ret =
282             _pkcs11_traverse_tokens(find_ext_cb, &find_data, obj->info,
283                                     &obj->pin,
284                                     pkcs11_obj_flags_to_int(flags));
285         if (ret < 0) {
286                 gnutls_assert();
287                 goto cleanup;
288         }
289
290         *exts = find_data.exts;
291         *exts_size = find_data.exts_size;
292
293         ret = 0;
294  cleanup:
295         if (deinit_spki)
296                 gnutls_free(spki.data);
297         return ret;
298 }
299