/src/gnutls/lib/x509/pkcs12_bag.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2003-2014 Free Software Foundation, Inc. |
3 | | * Copyright (C) 2014 Red Hat |
4 | | * |
5 | | * Author: Nikos Mavrogiannopoulos |
6 | | * |
7 | | * This file is part of GnuTLS. |
8 | | * |
9 | | * The GnuTLS is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public License |
11 | | * as published by the Free Software Foundation; either version 2.1 of |
12 | | * the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, but |
15 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
21 | | * |
22 | | */ |
23 | | |
24 | | /* Functions that relate on PKCS12 Bag packet parsing. |
25 | | */ |
26 | | |
27 | | #include "gnutls_int.h" |
28 | | |
29 | | #include <datum.h> |
30 | | #include <global.h> |
31 | | #include "errors.h" |
32 | | #include <common.h> |
33 | | #include "x509_int.h" |
34 | | #include "pkcs7_int.h" |
35 | | |
36 | | /** |
37 | | * gnutls_pkcs12_bag_init: |
38 | | * @bag: A pointer to the type to be initialized |
39 | | * |
40 | | * This function will initialize a PKCS12 bag structure. PKCS12 Bags |
41 | | * usually contain private keys, lists of X.509 Certificates and X.509 |
42 | | * Certificate revocation lists. |
43 | | * |
44 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a |
45 | | * negative error value. |
46 | | **/ |
47 | | int gnutls_pkcs12_bag_init(gnutls_pkcs12_bag_t * bag) |
48 | 0 | { |
49 | 0 | *bag = gnutls_calloc(1, sizeof(gnutls_pkcs12_bag_int)); |
50 | |
|
51 | 0 | if (*bag) { |
52 | 0 | return 0; /* success */ |
53 | 0 | } |
54 | 0 | return GNUTLS_E_MEMORY_ERROR; |
55 | 0 | } |
56 | | |
57 | | static inline void _pkcs12_bag_free_data(gnutls_pkcs12_bag_t bag) |
58 | 0 | { |
59 | 0 | unsigned i; |
60 | |
|
61 | 0 | for (i = 0; i < bag->bag_elements; i++) { |
62 | 0 | _gnutls_free_datum(&bag->element[i].data); |
63 | 0 | _gnutls_free_datum(&bag->element[i].local_key_id); |
64 | 0 | gnutls_free(bag->element[i].friendly_name); |
65 | 0 | bag->element[i].type = 0; |
66 | 0 | } |
67 | |
|
68 | 0 | } |
69 | | |
70 | | /** |
71 | | * gnutls_pkcs12_bag_deinit: |
72 | | * @bag: A pointer to the type to be initialized |
73 | | * |
74 | | * This function will deinitialize a PKCS12 Bag structure. |
75 | | **/ |
76 | | void gnutls_pkcs12_bag_deinit(gnutls_pkcs12_bag_t bag) |
77 | 0 | { |
78 | 0 | if (!bag) |
79 | 0 | return; |
80 | | |
81 | 0 | _pkcs12_bag_free_data(bag); |
82 | |
|
83 | 0 | gnutls_free(bag); |
84 | 0 | } |
85 | | |
86 | | /** |
87 | | * gnutls_pkcs12_bag_get_type: |
88 | | * @bag: The bag |
89 | | * @indx: The element of the bag to get the type |
90 | | * |
91 | | * This function will return the bag's type. |
92 | | * |
93 | | * Returns: On error a negative error value or one of the #gnutls_pkcs12_bag_type_t enumerations. |
94 | | **/ |
95 | | int gnutls_pkcs12_bag_get_type(gnutls_pkcs12_bag_t bag, unsigned indx) |
96 | 0 | { |
97 | 0 | if (bag == NULL) { |
98 | 0 | gnutls_assert(); |
99 | 0 | return GNUTLS_E_INVALID_REQUEST; |
100 | 0 | } |
101 | | |
102 | 0 | if (indx >= bag->bag_elements) |
103 | 0 | return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; |
104 | 0 | return bag->element[indx].type; |
105 | 0 | } |
106 | | |
107 | | /** |
108 | | * gnutls_pkcs12_bag_get_count: |
109 | | * @bag: The bag |
110 | | * |
111 | | * This function will return the number of the elements within the bag. |
112 | | * |
113 | | * Returns: Number of elements in bag, or an negative error code on |
114 | | * error. |
115 | | **/ |
116 | | int gnutls_pkcs12_bag_get_count(gnutls_pkcs12_bag_t bag) |
117 | 0 | { |
118 | 0 | if (bag == NULL) { |
119 | 0 | gnutls_assert(); |
120 | 0 | return GNUTLS_E_INVALID_REQUEST; |
121 | 0 | } |
122 | | |
123 | 0 | return bag->bag_elements; |
124 | 0 | } |
125 | | |
126 | | /** |
127 | | * gnutls_pkcs12_bag_get_data: |
128 | | * @bag: The bag |
129 | | * @indx: The element of the bag to get the data from |
130 | | * @data: where the bag's data will be. Should be treated as constant. |
131 | | * |
132 | | * This function will return the bag's data. The data is a constant |
133 | | * that is stored into the bag. Should not be accessed after the bag |
134 | | * is deleted. |
135 | | * |
136 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a |
137 | | * negative error value. |
138 | | **/ |
139 | | int |
140 | | gnutls_pkcs12_bag_get_data(gnutls_pkcs12_bag_t bag, unsigned indx, |
141 | | gnutls_datum_t * data) |
142 | 0 | { |
143 | 0 | if (bag == NULL) { |
144 | 0 | gnutls_assert(); |
145 | 0 | return GNUTLS_E_INVALID_REQUEST; |
146 | 0 | } |
147 | | |
148 | 0 | if (indx >= bag->bag_elements) |
149 | 0 | return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; |
150 | | |
151 | 0 | data->data = bag->element[indx].data.data; |
152 | 0 | data->size = bag->element[indx].data.size; |
153 | |
|
154 | 0 | return 0; |
155 | 0 | } |
156 | | |
157 | 0 | #define X509_CERT_OID "1.2.840.113549.1.9.22.1" |
158 | 0 | #define X509_CRL_OID "1.2.840.113549.1.9.23.1" |
159 | 0 | #define RANDOM_NONCE_OID "1.2.840.113549.1.9.25.3" |
160 | | |
161 | | int |
162 | | _pkcs12_decode_crt_bag(gnutls_pkcs12_bag_type_t type, |
163 | | const gnutls_datum_t * in, gnutls_datum_t * out) |
164 | 0 | { |
165 | 0 | int ret; |
166 | 0 | asn1_node c2 = NULL; |
167 | |
|
168 | 0 | switch (type) { |
169 | 0 | case GNUTLS_BAG_CERTIFICATE: |
170 | 0 | if ((ret = asn1_create_element(_gnutls_get_pkix(), |
171 | 0 | "PKIX1.pkcs-12-CertBag", |
172 | 0 | &c2)) != ASN1_SUCCESS) { |
173 | 0 | gnutls_assert(); |
174 | 0 | ret = _gnutls_asn2err(ret); |
175 | 0 | goto cleanup; |
176 | 0 | } |
177 | | |
178 | 0 | ret = asn1_der_decoding(&c2, in->data, in->size, NULL); |
179 | 0 | if (ret != ASN1_SUCCESS) { |
180 | 0 | gnutls_assert(); |
181 | 0 | ret = _gnutls_asn2err(ret); |
182 | 0 | goto cleanup; |
183 | 0 | } |
184 | | |
185 | 0 | ret = |
186 | 0 | _gnutls_x509_read_string(c2, "certValue", out, |
187 | 0 | ASN1_ETYPE_OCTET_STRING, 1); |
188 | 0 | if (ret < 0) { |
189 | 0 | gnutls_assert(); |
190 | 0 | goto cleanup; |
191 | 0 | } |
192 | 0 | break; |
193 | | |
194 | 0 | case GNUTLS_BAG_CRL: |
195 | 0 | if ((ret = asn1_create_element(_gnutls_get_pkix(), |
196 | 0 | "PKIX1.pkcs-12-CRLBag", |
197 | 0 | &c2)) != ASN1_SUCCESS) { |
198 | 0 | gnutls_assert(); |
199 | 0 | ret = _gnutls_asn2err(ret); |
200 | 0 | goto cleanup; |
201 | 0 | } |
202 | | |
203 | 0 | ret = asn1_der_decoding(&c2, in->data, in->size, NULL); |
204 | 0 | if (ret != ASN1_SUCCESS) { |
205 | 0 | gnutls_assert(); |
206 | 0 | ret = _gnutls_asn2err(ret); |
207 | 0 | goto cleanup; |
208 | 0 | } |
209 | | |
210 | 0 | ret = |
211 | 0 | _gnutls_x509_read_string(c2, "crlValue", out, |
212 | 0 | ASN1_ETYPE_OCTET_STRING, 1); |
213 | 0 | if (ret < 0) { |
214 | 0 | gnutls_assert(); |
215 | 0 | goto cleanup; |
216 | 0 | } |
217 | 0 | break; |
218 | | |
219 | 0 | case GNUTLS_BAG_SECRET: |
220 | 0 | if ((ret = asn1_create_element(_gnutls_get_pkix(), |
221 | 0 | "PKIX1.pkcs-12-SecretBag", |
222 | 0 | &c2)) != ASN1_SUCCESS) { |
223 | 0 | gnutls_assert(); |
224 | 0 | ret = _gnutls_asn2err(ret); |
225 | 0 | goto cleanup; |
226 | 0 | } |
227 | | |
228 | 0 | ret = asn1_der_decoding(&c2, in->data, in->size, NULL); |
229 | 0 | if (ret != ASN1_SUCCESS) { |
230 | 0 | gnutls_assert(); |
231 | 0 | ret = _gnutls_asn2err(ret); |
232 | 0 | goto cleanup; |
233 | 0 | } |
234 | | |
235 | 0 | ret = |
236 | 0 | _gnutls_x509_read_string(c2, "secretValue", out, |
237 | 0 | ASN1_ETYPE_OCTET_STRING, 1); |
238 | 0 | if (ret < 0) { |
239 | 0 | gnutls_assert(); |
240 | 0 | goto cleanup; |
241 | 0 | } |
242 | 0 | break; |
243 | | |
244 | 0 | default: |
245 | 0 | gnutls_assert(); |
246 | 0 | asn1_delete_structure(&c2); |
247 | 0 | return GNUTLS_E_UNIMPLEMENTED_FEATURE; |
248 | 0 | } |
249 | | |
250 | 0 | asn1_delete_structure(&c2); |
251 | |
|
252 | 0 | return 0; |
253 | | |
254 | 0 | cleanup: |
255 | |
|
256 | 0 | asn1_delete_structure(&c2); |
257 | 0 | return ret; |
258 | 0 | } |
259 | | |
260 | | int |
261 | | _pkcs12_encode_crt_bag(gnutls_pkcs12_bag_type_t type, |
262 | | const gnutls_datum_t * raw, gnutls_datum_t * out) |
263 | 0 | { |
264 | 0 | int ret; |
265 | 0 | asn1_node c2 = NULL; |
266 | |
|
267 | 0 | switch (type) { |
268 | 0 | case GNUTLS_BAG_CERTIFICATE: |
269 | 0 | if ((ret = asn1_create_element(_gnutls_get_pkix(), |
270 | 0 | "PKIX1.pkcs-12-CertBag", |
271 | 0 | &c2)) != ASN1_SUCCESS) { |
272 | 0 | gnutls_assert(); |
273 | 0 | ret = _gnutls_asn2err(ret); |
274 | 0 | goto cleanup; |
275 | 0 | } |
276 | | |
277 | 0 | ret = asn1_write_value(c2, "certId", X509_CERT_OID, 1); |
278 | 0 | if (ret != ASN1_SUCCESS) { |
279 | 0 | gnutls_assert(); |
280 | 0 | ret = _gnutls_asn2err(ret); |
281 | 0 | goto cleanup; |
282 | 0 | } |
283 | | |
284 | 0 | ret = |
285 | 0 | _gnutls_x509_write_string(c2, "certValue", raw, |
286 | 0 | ASN1_ETYPE_OCTET_STRING); |
287 | 0 | if (ret < 0) { |
288 | 0 | gnutls_assert(); |
289 | 0 | goto cleanup; |
290 | 0 | } |
291 | 0 | break; |
292 | | |
293 | 0 | case GNUTLS_BAG_CRL: |
294 | 0 | if ((ret = asn1_create_element(_gnutls_get_pkix(), |
295 | 0 | "PKIX1.pkcs-12-CRLBag", |
296 | 0 | &c2)) != ASN1_SUCCESS) { |
297 | 0 | gnutls_assert(); |
298 | 0 | ret = _gnutls_asn2err(ret); |
299 | 0 | goto cleanup; |
300 | 0 | } |
301 | | |
302 | 0 | ret = asn1_write_value(c2, "crlId", X509_CRL_OID, 1); |
303 | 0 | if (ret != ASN1_SUCCESS) { |
304 | 0 | gnutls_assert(); |
305 | 0 | ret = _gnutls_asn2err(ret); |
306 | 0 | goto cleanup; |
307 | 0 | } |
308 | | |
309 | 0 | ret = |
310 | 0 | _gnutls_x509_write_string(c2, "crlValue", raw, |
311 | 0 | ASN1_ETYPE_OCTET_STRING); |
312 | 0 | if (ret < 0) { |
313 | 0 | gnutls_assert(); |
314 | 0 | goto cleanup; |
315 | 0 | } |
316 | 0 | break; |
317 | | |
318 | 0 | case GNUTLS_BAG_SECRET: |
319 | 0 | if ((ret = asn1_create_element(_gnutls_get_pkix(), |
320 | 0 | "PKIX1.pkcs-12-SecretBag", |
321 | 0 | &c2)) != ASN1_SUCCESS) { |
322 | 0 | gnutls_assert(); |
323 | 0 | ret = _gnutls_asn2err(ret); |
324 | 0 | goto cleanup; |
325 | 0 | } |
326 | | |
327 | 0 | ret = asn1_write_value(c2, "secretTypeId", RANDOM_NONCE_OID, 1); |
328 | 0 | if (ret != ASN1_SUCCESS) { |
329 | 0 | gnutls_assert(); |
330 | 0 | ret = _gnutls_asn2err(ret); |
331 | 0 | goto cleanup; |
332 | 0 | } |
333 | | |
334 | 0 | ret = |
335 | 0 | _gnutls_x509_write_string(c2, "secretValue", raw, |
336 | 0 | ASN1_ETYPE_OCTET_STRING); |
337 | 0 | if (ret < 0) { |
338 | 0 | gnutls_assert(); |
339 | 0 | goto cleanup; |
340 | 0 | } |
341 | 0 | break; |
342 | | |
343 | 0 | default: |
344 | 0 | gnutls_assert(); |
345 | 0 | asn1_delete_structure(&c2); |
346 | 0 | return GNUTLS_E_UNIMPLEMENTED_FEATURE; |
347 | 0 | } |
348 | | |
349 | 0 | ret = _gnutls_x509_der_encode(c2, "", out, 0); |
350 | |
|
351 | 0 | if (ret < 0) { |
352 | 0 | gnutls_assert(); |
353 | 0 | goto cleanup; |
354 | 0 | } |
355 | | |
356 | 0 | asn1_delete_structure(&c2); |
357 | |
|
358 | 0 | return 0; |
359 | | |
360 | 0 | cleanup: |
361 | |
|
362 | 0 | asn1_delete_structure(&c2); |
363 | 0 | return ret; |
364 | 0 | } |
365 | | |
366 | | /** |
367 | | * gnutls_pkcs12_bag_set_data: |
368 | | * @bag: The bag |
369 | | * @type: The data's type |
370 | | * @data: the data to be copied. |
371 | | * |
372 | | * This function will insert the given data of the given type into |
373 | | * the bag. |
374 | | * |
375 | | * Returns: the index of the added bag on success, or a negative |
376 | | * value on error. |
377 | | **/ |
378 | | int |
379 | | gnutls_pkcs12_bag_set_data(gnutls_pkcs12_bag_t bag, |
380 | | gnutls_pkcs12_bag_type_t type, |
381 | | const gnutls_datum_t * data) |
382 | 0 | { |
383 | 0 | int ret; |
384 | 0 | if (bag == NULL) { |
385 | 0 | gnutls_assert(); |
386 | 0 | return GNUTLS_E_INVALID_REQUEST; |
387 | 0 | } |
388 | | |
389 | 0 | if (bag->bag_elements == MAX_BAG_ELEMENTS - 1) { |
390 | 0 | gnutls_assert(); |
391 | | /* bag is full */ |
392 | 0 | return GNUTLS_E_MEMORY_ERROR; |
393 | 0 | } |
394 | | |
395 | 0 | if (bag->bag_elements == 1) { |
396 | | /* A bag with a key or an encrypted bag, must have |
397 | | * only one element. |
398 | | */ |
399 | |
|
400 | 0 | if (bag->element[0].type == GNUTLS_BAG_PKCS8_KEY || |
401 | 0 | bag->element[0].type == GNUTLS_BAG_PKCS8_ENCRYPTED_KEY |
402 | 0 | || bag->element[0].type == GNUTLS_BAG_ENCRYPTED) { |
403 | 0 | gnutls_assert(); |
404 | 0 | return GNUTLS_E_INVALID_REQUEST; |
405 | 0 | } |
406 | 0 | } |
407 | | |
408 | 0 | ret = |
409 | 0 | _gnutls_set_datum(&bag->element[bag->bag_elements].data, |
410 | 0 | data->data, data->size); |
411 | |
|
412 | 0 | if (ret < 0) { |
413 | 0 | gnutls_assert(); |
414 | 0 | return ret; |
415 | 0 | } |
416 | | |
417 | 0 | bag->element[bag->bag_elements].type = type; |
418 | |
|
419 | 0 | bag->bag_elements++; |
420 | |
|
421 | 0 | return bag->bag_elements - 1; |
422 | 0 | } |
423 | | |
424 | | /** |
425 | | * gnutls_pkcs12_bag_set_crt: |
426 | | * @bag: The bag |
427 | | * @crt: the certificate to be copied. |
428 | | * |
429 | | * This function will insert the given certificate into the |
430 | | * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data(). |
431 | | * |
432 | | * Returns: the index of the added bag on success, or a negative |
433 | | * value on failure. |
434 | | **/ |
435 | | int gnutls_pkcs12_bag_set_crt(gnutls_pkcs12_bag_t bag, gnutls_x509_crt_t crt) |
436 | 0 | { |
437 | 0 | int ret; |
438 | 0 | gnutls_datum_t data; |
439 | |
|
440 | 0 | if (bag == NULL) { |
441 | 0 | gnutls_assert(); |
442 | 0 | return GNUTLS_E_INVALID_REQUEST; |
443 | 0 | } |
444 | | |
445 | 0 | ret = _gnutls_x509_der_encode(crt->cert, "", &data, 0); |
446 | 0 | if (ret < 0) { |
447 | 0 | gnutls_assert(); |
448 | 0 | return ret; |
449 | 0 | } |
450 | | |
451 | 0 | ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CERTIFICATE, &data); |
452 | |
|
453 | 0 | _gnutls_free_datum(&data); |
454 | |
|
455 | 0 | return ret; |
456 | 0 | } |
457 | | |
458 | | /** |
459 | | * gnutls_pkcs12_bag_set_crl: |
460 | | * @bag: The bag |
461 | | * @crl: the CRL to be copied. |
462 | | * |
463 | | * This function will insert the given CRL into the |
464 | | * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data(). |
465 | | * |
466 | | * Returns: the index of the added bag on success, or a negative error code |
467 | | * on failure. |
468 | | **/ |
469 | | int gnutls_pkcs12_bag_set_crl(gnutls_pkcs12_bag_t bag, gnutls_x509_crl_t crl) |
470 | 0 | { |
471 | 0 | int ret; |
472 | 0 | gnutls_datum_t data; |
473 | |
|
474 | 0 | if (bag == NULL) { |
475 | 0 | gnutls_assert(); |
476 | 0 | return GNUTLS_E_INVALID_REQUEST; |
477 | 0 | } |
478 | | |
479 | 0 | ret = _gnutls_x509_der_encode(crl->crl, "", &data, 0); |
480 | 0 | if (ret < 0) { |
481 | 0 | gnutls_assert(); |
482 | 0 | return ret; |
483 | 0 | } |
484 | | |
485 | 0 | ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CRL, &data); |
486 | |
|
487 | 0 | _gnutls_free_datum(&data); |
488 | |
|
489 | 0 | return ret; |
490 | 0 | } |
491 | | |
492 | | /** |
493 | | * gnutls_pkcs12_bag_set_key_id: |
494 | | * @bag: The bag |
495 | | * @indx: The bag's element to add the id |
496 | | * @id: the ID |
497 | | * |
498 | | * This function will add the given key ID, to the specified, by the |
499 | | * index, bag element. The key ID will be encoded as a 'Local key |
500 | | * identifier' bag attribute, which is usually used to distinguish |
501 | | * the local private key and the certificate pair. |
502 | | * |
503 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a |
504 | | * negative error value. or a negative error code on error. |
505 | | **/ |
506 | | int |
507 | | gnutls_pkcs12_bag_set_key_id(gnutls_pkcs12_bag_t bag, unsigned indx, |
508 | | const gnutls_datum_t * id) |
509 | 0 | { |
510 | 0 | int ret; |
511 | |
|
512 | 0 | if (bag == NULL) { |
513 | 0 | gnutls_assert(); |
514 | 0 | return GNUTLS_E_INVALID_REQUEST; |
515 | 0 | } |
516 | | |
517 | 0 | if (indx > bag->bag_elements - 1) { |
518 | 0 | gnutls_assert(); |
519 | 0 | return GNUTLS_E_INVALID_REQUEST; |
520 | 0 | } |
521 | | |
522 | 0 | ret = _gnutls_set_datum(&bag->element[indx].local_key_id, |
523 | 0 | id->data, id->size); |
524 | |
|
525 | 0 | if (ret < 0) { |
526 | 0 | gnutls_assert(); |
527 | 0 | return ret; |
528 | 0 | } |
529 | | |
530 | 0 | return 0; |
531 | 0 | } |
532 | | |
533 | | /** |
534 | | * gnutls_pkcs12_bag_get_key_id: |
535 | | * @bag: The bag |
536 | | * @indx: The bag's element to add the id |
537 | | * @id: where the ID will be copied (to be treated as const) |
538 | | * |
539 | | * This function will return the key ID, of the specified bag element. |
540 | | * The key ID is usually used to distinguish the local private key and |
541 | | * the certificate pair. |
542 | | * |
543 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a |
544 | | * negative error value. or a negative error code on error. |
545 | | **/ |
546 | | int |
547 | | gnutls_pkcs12_bag_get_key_id(gnutls_pkcs12_bag_t bag, unsigned indx, |
548 | | gnutls_datum_t * id) |
549 | 0 | { |
550 | 0 | if (bag == NULL) { |
551 | 0 | gnutls_assert(); |
552 | 0 | return GNUTLS_E_INVALID_REQUEST; |
553 | 0 | } |
554 | | |
555 | 0 | if (indx > bag->bag_elements - 1) { |
556 | 0 | gnutls_assert(); |
557 | 0 | return GNUTLS_E_INVALID_REQUEST; |
558 | 0 | } |
559 | | |
560 | 0 | id->data = bag->element[indx].local_key_id.data; |
561 | 0 | id->size = bag->element[indx].local_key_id.size; |
562 | |
|
563 | 0 | return 0; |
564 | 0 | } |
565 | | |
566 | | /** |
567 | | * gnutls_pkcs12_bag_get_friendly_name: |
568 | | * @bag: The bag |
569 | | * @indx: The bag's element to add the id |
570 | | * @name: will hold a pointer to the name (to be treated as const) |
571 | | * |
572 | | * This function will return the friendly name, of the specified bag |
573 | | * element. The key ID is usually used to distinguish the local |
574 | | * private key and the certificate pair. |
575 | | * |
576 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a |
577 | | * negative error value. or a negative error code on error. |
578 | | **/ |
579 | | int |
580 | | gnutls_pkcs12_bag_get_friendly_name(gnutls_pkcs12_bag_t bag, unsigned indx, |
581 | | char **name) |
582 | 0 | { |
583 | 0 | if (bag == NULL) { |
584 | 0 | gnutls_assert(); |
585 | 0 | return GNUTLS_E_INVALID_REQUEST; |
586 | 0 | } |
587 | | |
588 | 0 | if (indx > bag->bag_elements - 1) { |
589 | 0 | gnutls_assert(); |
590 | 0 | return GNUTLS_E_INVALID_REQUEST; |
591 | 0 | } |
592 | | |
593 | 0 | *name = bag->element[indx].friendly_name; |
594 | |
|
595 | 0 | return 0; |
596 | 0 | } |
597 | | |
598 | | /** |
599 | | * gnutls_pkcs12_bag_set_friendly_name: |
600 | | * @bag: The bag |
601 | | * @indx: The bag's element to add the id |
602 | | * @name: the name |
603 | | * |
604 | | * This function will add the given key friendly name, to the |
605 | | * specified, by the index, bag element. The name will be encoded as |
606 | | * a 'Friendly name' bag attribute, which is usually used to set a |
607 | | * user name to the local private key and the certificate pair. |
608 | | * |
609 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a |
610 | | * negative error value. or a negative error code on error. |
611 | | **/ |
612 | | int |
613 | | gnutls_pkcs12_bag_set_friendly_name(gnutls_pkcs12_bag_t bag, unsigned indx, |
614 | | const char *name) |
615 | 0 | { |
616 | 0 | if (bag == NULL) { |
617 | 0 | gnutls_assert(); |
618 | 0 | return GNUTLS_E_INVALID_REQUEST; |
619 | 0 | } |
620 | | |
621 | 0 | if (indx > bag->bag_elements - 1) { |
622 | 0 | gnutls_assert(); |
623 | 0 | return GNUTLS_E_INVALID_REQUEST; |
624 | 0 | } |
625 | | |
626 | 0 | bag->element[indx].friendly_name = gnutls_strdup(name); |
627 | |
|
628 | 0 | if (name == NULL) { |
629 | 0 | gnutls_assert(); |
630 | 0 | return GNUTLS_E_MEMORY_ERROR; |
631 | 0 | } |
632 | | |
633 | 0 | return 0; |
634 | 0 | } |
635 | | |
636 | | /** |
637 | | * gnutls_pkcs12_bag_decrypt: |
638 | | * @bag: The bag |
639 | | * @pass: The password used for encryption, must be ASCII. |
640 | | * |
641 | | * This function will decrypt the given encrypted bag and return 0 on |
642 | | * success. |
643 | | * |
644 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, |
645 | | * otherwise a negative error code is returned. |
646 | | **/ |
647 | | int gnutls_pkcs12_bag_decrypt(gnutls_pkcs12_bag_t bag, const char *pass) |
648 | 0 | { |
649 | 0 | int ret; |
650 | 0 | gnutls_datum_t dec; |
651 | |
|
652 | 0 | if (bag == NULL) { |
653 | 0 | gnutls_assert(); |
654 | 0 | return GNUTLS_E_INVALID_REQUEST; |
655 | 0 | } |
656 | | |
657 | 0 | if (bag->element[0].type != GNUTLS_BAG_ENCRYPTED) { |
658 | 0 | gnutls_assert(); |
659 | 0 | return GNUTLS_E_INVALID_REQUEST; |
660 | 0 | } |
661 | | |
662 | 0 | ret = _gnutls_pkcs7_decrypt_data(&bag->element[0].data, pass, &dec); |
663 | |
|
664 | 0 | if (ret < 0) { |
665 | 0 | gnutls_assert(); |
666 | 0 | return ret; |
667 | 0 | } |
668 | | |
669 | | /* decryption succeeded. Now decode the SafeContents |
670 | | * stuff, and parse it. |
671 | | */ |
672 | | |
673 | 0 | _gnutls_free_datum(&bag->element[0].data); |
674 | |
|
675 | 0 | ret = _pkcs12_decode_safe_contents(&dec, bag); |
676 | |
|
677 | 0 | _gnutls_free_datum(&dec); |
678 | |
|
679 | 0 | if (ret < 0) { |
680 | 0 | gnutls_assert(); |
681 | 0 | return ret; |
682 | 0 | } |
683 | | |
684 | 0 | return 0; |
685 | 0 | } |
686 | | |
687 | | /** |
688 | | * gnutls_pkcs12_bag_encrypt: |
689 | | * @bag: The bag |
690 | | * @pass: The password used for encryption, must be ASCII |
691 | | * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd |
692 | | * |
693 | | * This function will encrypt the given bag. |
694 | | * |
695 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, |
696 | | * otherwise a negative error code is returned. |
697 | | **/ |
698 | | int |
699 | | gnutls_pkcs12_bag_encrypt(gnutls_pkcs12_bag_t bag, const char *pass, |
700 | | unsigned int flags) |
701 | 0 | { |
702 | 0 | int ret; |
703 | 0 | asn1_node safe_cont = NULL; |
704 | 0 | gnutls_datum_t der = { NULL, 0 }; |
705 | 0 | gnutls_datum_t enc = { NULL, 0 }; |
706 | 0 | schema_id id; |
707 | |
|
708 | 0 | if (bag == NULL) { |
709 | 0 | gnutls_assert(); |
710 | 0 | return GNUTLS_E_INVALID_REQUEST; |
711 | 0 | } |
712 | | |
713 | 0 | if (bag->element[0].type == GNUTLS_BAG_ENCRYPTED) { |
714 | 0 | gnutls_assert(); |
715 | 0 | return GNUTLS_E_INVALID_REQUEST; |
716 | 0 | } |
717 | | |
718 | | /* Encode the whole bag to a safe contents |
719 | | * structure. |
720 | | */ |
721 | 0 | ret = _pkcs12_encode_safe_contents(bag, &safe_cont, NULL); |
722 | 0 | if (ret < 0) { |
723 | 0 | gnutls_assert(); |
724 | 0 | return ret; |
725 | 0 | } |
726 | | |
727 | | /* DER encode the SafeContents. |
728 | | */ |
729 | 0 | ret = _gnutls_x509_der_encode(safe_cont, "", &der, 0); |
730 | |
|
731 | 0 | asn1_delete_structure(&safe_cont); |
732 | |
|
733 | 0 | if (ret < 0) { |
734 | 0 | gnutls_assert(); |
735 | 0 | return ret; |
736 | 0 | } |
737 | | |
738 | 0 | if (flags & GNUTLS_PKCS_PLAIN) { |
739 | 0 | gnutls_assert(); |
740 | 0 | return GNUTLS_E_INVALID_REQUEST; |
741 | 0 | } |
742 | | |
743 | 0 | id = _gnutls_pkcs_flags_to_schema(flags); |
744 | | |
745 | | /* Now encrypt them. |
746 | | */ |
747 | 0 | ret = _gnutls_pkcs7_encrypt_data(id, &der, pass, &enc); |
748 | |
|
749 | 0 | _gnutls_free_datum(&der); |
750 | |
|
751 | 0 | if (ret < 0) { |
752 | 0 | gnutls_assert(); |
753 | 0 | return ret; |
754 | 0 | } |
755 | | |
756 | | /* encryption succeeded. |
757 | | */ |
758 | | |
759 | 0 | _pkcs12_bag_free_data(bag); |
760 | |
|
761 | 0 | bag->element[0].type = GNUTLS_BAG_ENCRYPTED; |
762 | 0 | bag->element[0].data = enc; |
763 | |
|
764 | 0 | bag->bag_elements = 1; |
765 | |
|
766 | 0 | return 0; |
767 | 0 | } |
768 | | |
769 | | /** |
770 | | * gnutls_pkcs12_bag_enc_info: |
771 | | * @bag: The bag |
772 | | * @schema: indicate the schema as one of %gnutls_pkcs_encrypt_flags_t |
773 | | * @cipher: the cipher used as %gnutls_cipher_algorithm_t |
774 | | * @salt: PBKDF2 salt (if non-NULL then @salt_size initially holds its size) |
775 | | * @salt_size: PBKDF2 salt size |
776 | | * @iter_count: PBKDF2 iteration count |
777 | | * @oid: if non-NULL it will contain an allocated null-terminated variable with the OID |
778 | | * |
779 | | * This function will provide information on the encryption algorithms used |
780 | | * in an encrypted bag. If the structure algorithms |
781 | | * are unknown the code %GNUTLS_E_UNKNOWN_CIPHER_TYPE will be returned, |
782 | | * and only @oid, will be set. That is, @oid will be set on encrypted bags |
783 | | * whether supported or not. It must be deinitialized using gnutls_free(). |
784 | | * The other variables are only set on supported structures. |
785 | | * |
786 | | * Returns: %GNUTLS_E_INVALID_REQUEST if the provided bag isn't encrypted, |
787 | | * %GNUTLS_E_UNKNOWN_CIPHER_TYPE if the structure's encryption isn't supported, or |
788 | | * another negative error code in case of a failure. Zero on success. |
789 | | **/ |
790 | | int |
791 | | gnutls_pkcs12_bag_enc_info(gnutls_pkcs12_bag_t bag, unsigned int *schema, |
792 | | unsigned int *cipher, void *salt, |
793 | | unsigned int *salt_size, unsigned int *iter_count, |
794 | | char **oid) |
795 | 0 | { |
796 | 0 | int ret; |
797 | 0 | struct pbkdf2_params kdf; |
798 | 0 | const struct pkcs_cipher_schema_st *p; |
799 | |
|
800 | 0 | if (bag == NULL) { |
801 | 0 | gnutls_assert(); |
802 | 0 | return GNUTLS_E_INVALID_REQUEST; |
803 | 0 | } |
804 | | |
805 | 0 | if (bag->element[0].type != GNUTLS_BAG_ENCRYPTED) { |
806 | 0 | gnutls_assert(); |
807 | 0 | return GNUTLS_E_INVALID_REQUEST; |
808 | 0 | } |
809 | | |
810 | 0 | ret = _gnutls_pkcs7_data_enc_info(&bag->element[0].data, &p, &kdf, oid); |
811 | |
|
812 | 0 | if (ret < 0) { |
813 | 0 | gnutls_assert(); |
814 | 0 | return ret; |
815 | 0 | } |
816 | | |
817 | 0 | if (schema) |
818 | 0 | *schema = p->flag; |
819 | |
|
820 | 0 | if (cipher) |
821 | 0 | *cipher = p->cipher; |
822 | |
|
823 | 0 | if (iter_count) |
824 | 0 | *iter_count = kdf.iter_count; |
825 | |
|
826 | 0 | if (salt) { |
827 | 0 | if (*salt_size >= (unsigned)kdf.salt_size) { |
828 | 0 | memcpy(salt, kdf.salt, kdf.salt_size); |
829 | 0 | } else { |
830 | 0 | *salt_size = kdf.salt_size; |
831 | 0 | return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); |
832 | 0 | } |
833 | 0 | } |
834 | | |
835 | 0 | if (salt_size) |
836 | 0 | *salt_size = kdf.salt_size; |
837 | |
|
838 | 0 | return 0; |
839 | 0 | } |
840 | | |
841 | | /** |
842 | | * gnutls_pkcs12_bag_set_privkey: |
843 | | * @bag: The bag |
844 | | * @privkey: the private key to be copied. |
845 | | * @password: the password to protect the key with (may be %NULL) |
846 | | * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd |
847 | | * |
848 | | * This function will insert the given private key into the |
849 | | * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data(). |
850 | | * |
851 | | * Returns: the index of the added bag on success, or a negative |
852 | | * value on failure. |
853 | | **/ |
854 | | int |
855 | | gnutls_pkcs12_bag_set_privkey(gnutls_pkcs12_bag_t bag, |
856 | | gnutls_x509_privkey_t privkey, |
857 | | const char *password, unsigned flags) |
858 | 0 | { |
859 | 0 | int ret; |
860 | 0 | gnutls_datum_t data = { NULL, 0 }; |
861 | |
|
862 | 0 | if (bag == NULL) { |
863 | 0 | gnutls_assert(); |
864 | 0 | return GNUTLS_E_INVALID_REQUEST; |
865 | 0 | } |
866 | | |
867 | 0 | ret = gnutls_x509_privkey_export2_pkcs8(privkey, GNUTLS_X509_FMT_DER, |
868 | 0 | password, flags, &data); |
869 | 0 | if (ret < 0) |
870 | 0 | return gnutls_assert_val(ret); |
871 | | |
872 | 0 | if (password == NULL) { |
873 | 0 | ret = |
874 | 0 | gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_PKCS8_KEY, |
875 | 0 | &data); |
876 | 0 | if (ret < 0) { |
877 | 0 | gnutls_assert(); |
878 | 0 | goto cleanup; |
879 | 0 | } |
880 | 0 | } else { |
881 | 0 | ret = |
882 | 0 | gnutls_pkcs12_bag_set_data(bag, |
883 | 0 | GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, |
884 | 0 | &data); |
885 | 0 | if (ret < 0) { |
886 | 0 | gnutls_assert(); |
887 | 0 | goto cleanup; |
888 | 0 | } |
889 | 0 | } |
890 | | |
891 | 0 | cleanup: |
892 | 0 | _gnutls_free_datum(&data); |
893 | |
|
894 | 0 | return ret; |
895 | 0 | } |