diff options
Diffstat (limited to 'lib/x509/pkcs12_bag.c')
-rw-r--r-- | lib/x509/pkcs12_bag.c | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/lib/x509/pkcs12_bag.c b/lib/x509/pkcs12_bag.c new file mode 100644 index 0000000..51a506e --- /dev/null +++ b/lib/x509/pkcs12_bag.c @@ -0,0 +1,906 @@ +/* + * Copyright (C) 2003-2014 Free Software Foundation, Inc. + * Copyright (C) 2014 Red Hat + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + * + */ + +/* Functions that relate on PKCS12 Bag packet parsing. + */ + +#include "gnutls_int.h" + +#include <datum.h> +#include <global.h> +#include "errors.h" +#include <common.h> +#include "x509_int.h" +#include "pkcs7_int.h" + +/** + * gnutls_pkcs12_bag_init: + * @bag: A pointer to the type to be initialized + * + * This function will initialize a PKCS12 bag structure. PKCS12 Bags + * usually contain private keys, lists of X.509 Certificates and X.509 + * Certificate revocation lists. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + **/ +int gnutls_pkcs12_bag_init(gnutls_pkcs12_bag_t * bag) +{ + *bag = gnutls_calloc(1, sizeof(gnutls_pkcs12_bag_int)); + + if (*bag) { + return 0; /* success */ + } + return GNUTLS_E_MEMORY_ERROR; +} + +static inline void _pkcs12_bag_free_data(gnutls_pkcs12_bag_t bag) +{ + unsigned i; + + for (i = 0; i < bag->bag_elements; i++) { + _gnutls_free_datum(&bag->element[i].data); + _gnutls_free_datum(&bag->element[i].local_key_id); + gnutls_free(bag->element[i].friendly_name); + bag->element[i].type = 0; + } + +} + + +/** + * gnutls_pkcs12_bag_deinit: + * @bag: A pointer to the type to be initialized + * + * This function will deinitialize a PKCS12 Bag structure. + **/ +void gnutls_pkcs12_bag_deinit(gnutls_pkcs12_bag_t bag) +{ + if (!bag) + return; + + _pkcs12_bag_free_data(bag); + + gnutls_free(bag); +} + +/** + * gnutls_pkcs12_bag_get_type: + * @bag: The bag + * @indx: The element of the bag to get the type + * + * This function will return the bag's type. + * + * Returns: On error a negative error value or one of the #gnutls_pkcs12_bag_type_t enumerations. + **/ +int +gnutls_pkcs12_bag_get_type(gnutls_pkcs12_bag_t bag, unsigned indx) +{ + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (indx >= bag->bag_elements) + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + return bag->element[indx].type; +} + +/** + * gnutls_pkcs12_bag_get_count: + * @bag: The bag + * + * This function will return the number of the elements within the bag. + * + * Returns: Number of elements in bag, or an negative error code on + * error. + **/ +int gnutls_pkcs12_bag_get_count(gnutls_pkcs12_bag_t bag) +{ + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + return bag->bag_elements; +} + +/** + * gnutls_pkcs12_bag_get_data: + * @bag: The bag + * @indx: The element of the bag to get the data from + * @data: where the bag's data will be. Should be treated as constant. + * + * This function will return the bag's data. The data is a constant + * that is stored into the bag. Should not be accessed after the bag + * is deleted. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + **/ +int +gnutls_pkcs12_bag_get_data(gnutls_pkcs12_bag_t bag, unsigned indx, + gnutls_datum_t * data) +{ + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (indx >= bag->bag_elements) + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + + data->data = bag->element[indx].data.data; + data->size = bag->element[indx].data.size; + + return 0; +} + +#define X509_CERT_OID "1.2.840.113549.1.9.22.1" +#define X509_CRL_OID "1.2.840.113549.1.9.23.1" +#define RANDOM_NONCE_OID "1.2.840.113549.1.9.25.3" + +int +_pkcs12_decode_crt_bag(gnutls_pkcs12_bag_type_t type, + const gnutls_datum_t * in, gnutls_datum_t * out) +{ + int ret; + asn1_node c2 = NULL; + + switch (type) { + case GNUTLS_BAG_CERTIFICATE: + if ((ret = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-CertBag", + &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = asn1_der_decoding(&c2, in->data, in->size, NULL); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = + _gnutls_x509_read_string(c2, "certValue", out, + ASN1_ETYPE_OCTET_STRING, 1); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + break; + + case GNUTLS_BAG_CRL: + if ((ret = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-CRLBag", + &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = asn1_der_decoding(&c2, in->data, in->size, NULL); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = + _gnutls_x509_read_string(c2, "crlValue", out, + ASN1_ETYPE_OCTET_STRING, 1); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + break; + + case GNUTLS_BAG_SECRET: + if ((ret = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-SecretBag", + &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = asn1_der_decoding(&c2, in->data, in->size, NULL); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = + _gnutls_x509_read_string(c2, "secretValue", out, + ASN1_ETYPE_OCTET_STRING, 1); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + break; + + default: + gnutls_assert(); + asn1_delete_structure(&c2); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + asn1_delete_structure(&c2); + + return 0; + + + cleanup: + + asn1_delete_structure(&c2); + return ret; +} + + +int +_pkcs12_encode_crt_bag(gnutls_pkcs12_bag_type_t type, + const gnutls_datum_t * raw, gnutls_datum_t * out) +{ + int ret; + asn1_node c2 = NULL; + + switch (type) { + case GNUTLS_BAG_CERTIFICATE: + if ((ret = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-CertBag", + &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = asn1_write_value(c2, "certId", X509_CERT_OID, 1); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = + _gnutls_x509_write_string(c2, "certValue", raw, + ASN1_ETYPE_OCTET_STRING); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + break; + + case GNUTLS_BAG_CRL: + if ((ret = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-CRLBag", + &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = asn1_write_value(c2, "crlId", X509_CRL_OID, 1); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = + _gnutls_x509_write_string(c2, "crlValue", raw, + ASN1_ETYPE_OCTET_STRING); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + break; + + case GNUTLS_BAG_SECRET: + if ((ret = asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-SecretBag", + &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = + asn1_write_value(c2, "secretTypeId", RANDOM_NONCE_OID, + 1); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = + _gnutls_x509_write_string(c2, "secretValue", raw, + ASN1_ETYPE_OCTET_STRING); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + break; + + default: + gnutls_assert(); + asn1_delete_structure(&c2); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + ret = _gnutls_x509_der_encode(c2, "", out, 0); + + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + asn1_delete_structure(&c2); + + return 0; + + + cleanup: + + asn1_delete_structure(&c2); + return ret; +} + + +/** + * gnutls_pkcs12_bag_set_data: + * @bag: The bag + * @type: The data's type + * @data: the data to be copied. + * + * This function will insert the given data of the given type into + * the bag. + * + * Returns: the index of the added bag on success, or a negative + * value on error. + **/ +int +gnutls_pkcs12_bag_set_data(gnutls_pkcs12_bag_t bag, + gnutls_pkcs12_bag_type_t type, + const gnutls_datum_t * data) +{ + int ret; + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (bag->bag_elements == MAX_BAG_ELEMENTS - 1) { + gnutls_assert(); + /* bag is full */ + return GNUTLS_E_MEMORY_ERROR; + } + + if (bag->bag_elements == 1) { + /* A bag with a key or an encrypted bag, must have + * only one element. + */ + + if (bag->element[0].type == GNUTLS_BAG_PKCS8_KEY || + bag->element[0].type == GNUTLS_BAG_PKCS8_ENCRYPTED_KEY + || bag->element[0].type == GNUTLS_BAG_ENCRYPTED) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + } + + ret = + _gnutls_set_datum(&bag->element[bag->bag_elements].data, + data->data, data->size); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + bag->element[bag->bag_elements].type = type; + + bag->bag_elements++; + + return bag->bag_elements - 1; +} + +/** + * gnutls_pkcs12_bag_set_crt: + * @bag: The bag + * @crt: the certificate to be copied. + * + * This function will insert the given certificate into the + * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data(). + * + * Returns: the index of the added bag on success, or a negative + * value on failure. + **/ +int +gnutls_pkcs12_bag_set_crt(gnutls_pkcs12_bag_t bag, gnutls_x509_crt_t crt) +{ + int ret; + gnutls_datum_t data; + + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = _gnutls_x509_der_encode(crt->cert, "", &data, 0); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + ret = + gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CERTIFICATE, &data); + + _gnutls_free_datum(&data); + + return ret; +} + +/** + * gnutls_pkcs12_bag_set_crl: + * @bag: The bag + * @crl: the CRL to be copied. + * + * This function will insert the given CRL into the + * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data(). + * + * Returns: the index of the added bag on success, or a negative error code + * on failure. + **/ +int +gnutls_pkcs12_bag_set_crl(gnutls_pkcs12_bag_t bag, gnutls_x509_crl_t crl) +{ + int ret; + gnutls_datum_t data; + + + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = _gnutls_x509_der_encode(crl->crl, "", &data, 0); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CRL, &data); + + _gnutls_free_datum(&data); + + return ret; +} + +/** + * gnutls_pkcs12_bag_set_key_id: + * @bag: The bag + * @indx: The bag's element to add the id + * @id: the ID + * + * This function will add the given key ID, to the specified, by the + * index, bag element. The key ID will be encoded as a 'Local key + * identifier' bag attribute, which is usually used to distinguish + * the local private key and the certificate pair. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. or a negative error code on error. + **/ +int +gnutls_pkcs12_bag_set_key_id(gnutls_pkcs12_bag_t bag, unsigned indx, + const gnutls_datum_t * id) +{ + int ret; + + + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (indx > bag->bag_elements - 1) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = _gnutls_set_datum(&bag->element[indx].local_key_id, + id->data, id->size); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + return 0; +} + +/** + * gnutls_pkcs12_bag_get_key_id: + * @bag: The bag + * @indx: The bag's element to add the id + * @id: where the ID will be copied (to be treated as const) + * + * This function will return the key ID, of the specified bag element. + * The key ID is usually used to distinguish the local private key and + * the certificate pair. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. or a negative error code on error. + **/ +int +gnutls_pkcs12_bag_get_key_id(gnutls_pkcs12_bag_t bag, unsigned indx, + gnutls_datum_t * id) +{ + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (indx > bag->bag_elements - 1) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + id->data = bag->element[indx].local_key_id.data; + id->size = bag->element[indx].local_key_id.size; + + return 0; +} + +/** + * gnutls_pkcs12_bag_get_friendly_name: + * @bag: The bag + * @indx: The bag's element to add the id + * @name: will hold a pointer to the name (to be treated as const) + * + * This function will return the friendly name, of the specified bag + * element. The key ID is usually used to distinguish the local + * private key and the certificate pair. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. or a negative error code on error. + **/ +int +gnutls_pkcs12_bag_get_friendly_name(gnutls_pkcs12_bag_t bag, unsigned indx, + char **name) +{ + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (indx > bag->bag_elements - 1) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + *name = bag->element[indx].friendly_name; + + return 0; +} + + +/** + * gnutls_pkcs12_bag_set_friendly_name: + * @bag: The bag + * @indx: The bag's element to add the id + * @name: the name + * + * This function will add the given key friendly name, to the + * specified, by the index, bag element. The name will be encoded as + * a 'Friendly name' bag attribute, which is usually used to set a + * user name to the local private key and the certificate pair. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. or a negative error code on error. + **/ +int +gnutls_pkcs12_bag_set_friendly_name(gnutls_pkcs12_bag_t bag, unsigned indx, + const char *name) +{ + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (indx > bag->bag_elements - 1) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + bag->element[indx].friendly_name = gnutls_strdup(name); + + if (name == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; +} + + +/** + * gnutls_pkcs12_bag_decrypt: + * @bag: The bag + * @pass: The password used for encryption, must be ASCII. + * + * This function will decrypt the given encrypted bag and return 0 on + * success. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, + * otherwise a negative error code is returned. + **/ +int gnutls_pkcs12_bag_decrypt(gnutls_pkcs12_bag_t bag, const char *pass) +{ + int ret; + gnutls_datum_t dec; + + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (bag->element[0].type != GNUTLS_BAG_ENCRYPTED) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = + _gnutls_pkcs7_decrypt_data(&bag->element[0].data, pass, &dec); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + /* decryption succeeded. Now decode the SafeContents + * stuff, and parse it. + */ + + _gnutls_free_datum(&bag->element[0].data); + + ret = _pkcs12_decode_safe_contents(&dec, bag); + + _gnutls_free_datum(&dec); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + return 0; +} + +/** + * gnutls_pkcs12_bag_encrypt: + * @bag: The bag + * @pass: The password used for encryption, must be ASCII + * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd + * + * This function will encrypt the given bag. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, + * otherwise a negative error code is returned. + **/ +int +gnutls_pkcs12_bag_encrypt(gnutls_pkcs12_bag_t bag, const char *pass, + unsigned int flags) +{ + int ret; + asn1_node safe_cont = NULL; + gnutls_datum_t der = { NULL, 0 }; + gnutls_datum_t enc = { NULL, 0 }; + schema_id id; + + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (bag->element[0].type == GNUTLS_BAG_ENCRYPTED) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* Encode the whole bag to a safe contents + * structure. + */ + ret = _pkcs12_encode_safe_contents(bag, &safe_cont, NULL); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + /* DER encode the SafeContents. + */ + ret = _gnutls_x509_der_encode(safe_cont, "", &der, 0); + + asn1_delete_structure(&safe_cont); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (flags & GNUTLS_PKCS_PLAIN) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + id = _gnutls_pkcs_flags_to_schema(flags); + + /* Now encrypt them. + */ + ret = _gnutls_pkcs7_encrypt_data(id, &der, pass, &enc); + + _gnutls_free_datum(&der); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + /* encryption succeeded. + */ + + _pkcs12_bag_free_data(bag); + + bag->element[0].type = GNUTLS_BAG_ENCRYPTED; + bag->element[0].data = enc; + + bag->bag_elements = 1; + + + return 0; +} + +/** + * gnutls_pkcs12_bag_enc_info: + * @bag: The bag + * @schema: indicate the schema as one of %gnutls_pkcs_encrypt_flags_t + * @cipher: the cipher used as %gnutls_cipher_algorithm_t + * @salt: PBKDF2 salt (if non-NULL then @salt_size initially holds its size) + * @salt_size: PBKDF2 salt size + * @iter_count: PBKDF2 iteration count + * @oid: if non-NULL it will contain an allocated null-terminated variable with the OID + * + * This function will provide information on the encryption algorithms used + * in an encrypted bag. If the structure algorithms + * are unknown the code %GNUTLS_E_UNKNOWN_CIPHER_TYPE will be returned, + * and only @oid, will be set. That is, @oid will be set on encrypted bags + * whether supported or not. It must be deinitialized using gnutls_free(). + * The other variables are only set on supported structures. + * + * Returns: %GNUTLS_E_INVALID_REQUEST if the provided bag isn't encrypted, + * %GNUTLS_E_UNKNOWN_CIPHER_TYPE if the structure's encryption isn't supported, or + * another negative error code in case of a failure. Zero on success. + **/ +int +gnutls_pkcs12_bag_enc_info(gnutls_pkcs12_bag_t bag, unsigned int *schema, unsigned int *cipher, + void *salt, unsigned int *salt_size, unsigned int *iter_count, char **oid) +{ + int ret; + struct pbkdf2_params kdf; + const struct pkcs_cipher_schema_st *p; + + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (bag->element[0].type != GNUTLS_BAG_ENCRYPTED) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = + _gnutls_pkcs7_data_enc_info(&bag->element[0].data, &p, &kdf, oid); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (schema) + *schema = p->flag; + + if (cipher) + *cipher = p->cipher; + + if (iter_count) + *iter_count = kdf.iter_count; + + if (salt) { + if (*salt_size >= (unsigned)kdf.salt_size) { + memcpy(salt, kdf.salt, kdf.salt_size); + } else { + *salt_size = kdf.salt_size; + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + } + } + + if (salt_size) + *salt_size = kdf.salt_size; + + + return 0; +} + +/** + * gnutls_pkcs12_bag_set_privkey: + * @bag: The bag + * @privkey: the private key to be copied. + * @password: the password to protect the key with (may be %NULL) + * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd + * + * This function will insert the given private key into the + * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data(). + * + * Returns: the index of the added bag on success, or a negative + * value on failure. + **/ +int +gnutls_pkcs12_bag_set_privkey(gnutls_pkcs12_bag_t bag, gnutls_x509_privkey_t privkey, + const char *password, unsigned flags) +{ + int ret; + gnutls_datum_t data = {NULL, 0}; + + if (bag == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = gnutls_x509_privkey_export2_pkcs8(privkey, GNUTLS_X509_FMT_DER, + password, flags, &data); + if (ret < 0) + return gnutls_assert_val(ret); + + if (password == NULL) { + ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_PKCS8_KEY, &data); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + } else { + ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, &data); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + } + + cleanup: + _gnutls_free_datum(&data); + + return ret; +} |