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