|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Copyright (C) 2003-2016 Free Software Foundation, Inc.
|
|
Packit |
aea12f |
* Copyright (C) 2014-2017 Red Hat
|
|
Packit |
aea12f |
* Copyright (C) 2014-2016 Nikos Mavrogiannopoulos
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Author: Nikos Mavrogiannopoulos
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This file is part of GnuTLS.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit |
aea12f |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
aea12f |
* the License, or (at your option) any later version.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
aea12f |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
aea12f |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
aea12f |
* Lesser General Public License for more details.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
#include "gnutls_int.h"
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
#include <datum.h>
|
|
Packit |
aea12f |
#include <global.h>
|
|
Packit |
aea12f |
#include "errors.h"
|
|
Packit |
aea12f |
#include <common.h>
|
|
Packit |
aea12f |
#include <x509.h>
|
|
Packit |
aea12f |
#include <x509_b64.h>
|
|
Packit |
aea12f |
#include "x509_int.h"
|
|
Packit |
aea12f |
#include "pkcs7_int.h"
|
|
Packit |
aea12f |
#include <algorithms.h>
|
|
Packit |
aea12f |
#include <num.h>
|
|
Packit |
aea12f |
#include <random.h>
|
|
Packit |
aea12f |
#include <pk.h>
|
|
Packit |
aea12f |
#include "attributes.h"
|
|
Packit |
aea12f |
#include "prov-seed.h"
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int _decode_pkcs8_ecc_key(ASN1_TYPE pkcs8_asn,
|
|
Packit |
aea12f |
gnutls_x509_privkey_t pkey);
|
|
Packit |
aea12f |
static
|
|
Packit |
aea12f |
int pkcs8_key_info(const gnutls_datum_t * raw_key,
|
|
Packit |
aea12f |
const struct pkcs_cipher_schema_st **p,
|
|
Packit |
aea12f |
struct pbkdf2_params *kdf_params,
|
|
Packit |
aea12f |
char **oid);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int decode_private_key_info(const gnutls_datum_t * der,
|
|
Packit |
aea12f |
gnutls_x509_privkey_t pkey);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
#define PEM_PKCS8 "ENCRYPTED PRIVATE KEY"
|
|
Packit |
aea12f |
#define PEM_UNENCRYPTED_PKCS8 "PRIVATE KEY"
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Returns a negative error code if the encryption schema in
|
|
Packit |
aea12f |
* the OID is not supported. The schema ID is returned.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
/* Encodes a private key to the raw format PKCS #8 needs.
|
|
Packit |
aea12f |
* For RSA it is a PKCS #1 DER private key and for DSA it is
|
|
Packit |
aea12f |
* an ASN.1 INTEGER of the x value.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
inline static int
|
|
Packit |
aea12f |
_encode_privkey(gnutls_x509_privkey_t pkey, gnutls_datum_t * raw)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
ASN1_TYPE spk = ASN1_TYPE_EMPTY;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
switch (pkey->params.algo) {
|
|
Packit |
aea12f |
case GNUTLS_PK_EDDSA_ED25519:
|
|
Packit Service |
991b93 |
case GNUTLS_PK_EDDSA_ED448:
|
|
Packit |
aea12f |
/* we encode as octet string (which is going to be stored inside
|
|
Packit |
aea12f |
* another octet string). No comments. */
|
|
Packit |
aea12f |
ret = _gnutls_x509_encode_string(ASN1_ETYPE_OCTET_STRING,
|
|
Packit |
aea12f |
pkey->params.raw_priv.data, pkey->params.raw_priv.size,
|
|
Packit |
aea12f |
raw);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
case GNUTLS_PK_GOST_01:
|
|
Packit |
aea12f |
case GNUTLS_PK_GOST_12_256:
|
|
Packit |
aea12f |
case GNUTLS_PK_GOST_12_512:
|
|
Packit |
aea12f |
if ((ret = asn1_create_element
|
|
Packit |
aea12f |
(_gnutls_get_gnutls_asn(), "GNUTLS.GOSTPrivateKey", &spk))
|
|
Packit |
aea12f |
!= ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = _gnutls_asn2err(ret);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_write_key_int_le(spk, "", pkey->params.params[GOST_K]);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_der_encode(spk, "", raw, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
asn1_delete_structure2(&spk, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
case GNUTLS_PK_RSA:
|
|
Packit |
aea12f |
case GNUTLS_PK_RSA_PSS:
|
|
Packit |
aea12f |
case GNUTLS_PK_ECDSA:
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_export_int2(pkey->key, GNUTLS_X509_FMT_DER,
|
|
Packit |
aea12f |
"", raw);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
case GNUTLS_PK_DSA:
|
|
Packit |
aea12f |
/* DSAPublicKey == INTEGER */
|
|
Packit |
aea12f |
if ((ret = asn1_create_element
|
|
Packit |
aea12f |
(_gnutls_get_gnutls_asn(), "GNUTLS.DSAPublicKey",
|
|
Packit |
aea12f |
&spk))
|
|
Packit |
aea12f |
!= ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return _gnutls_asn2err(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_write_int(spk, "", pkey->params.params[4],
|
|
Packit |
aea12f |
1);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
ret = _gnutls_x509_der_encode(spk, "", raw, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
asn1_delete_structure2(&spk, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
default:
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
asn1_delete_structure2(&spk, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
asn1_delete_structure(&spk;;
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Encodes a PKCS #1 private key to a PKCS #8 private key
|
|
Packit |
aea12f |
* info. The output will be allocated and stored into der. Also
|
|
Packit |
aea12f |
* the ASN1_TYPE of private key info will be returned.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
encode_to_private_key_info(gnutls_x509_privkey_t pkey,
|
|
Packit |
aea12f |
gnutls_datum_t * der, ASN1_TYPE * pkey_info)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result, len;
|
|
Packit |
aea12f |
uint8_t null = 0;
|
|
Packit |
aea12f |
const char *oid;
|
|
Packit |
aea12f |
gnutls_datum_t algo_params = { NULL, 0 };
|
|
Packit |
aea12f |
gnutls_datum_t algo_privkey = { NULL, 0 };
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
oid = gnutls_pk_get_oid(pkey->params.algo);
|
|
Packit |
aea12f |
if (oid == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_x509_write_pubkey_params(&pkey->params, &algo_params);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result =
|
|
Packit |
aea12f |
asn1_create_element(_gnutls_get_pkix(),
|
|
Packit |
aea12f |
"PKIX1.pkcs-8-PrivateKeyInfo",
|
|
Packit |
aea12f |
pkey_info)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Write the version.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result = asn1_write_value(*pkey_info, "version", &null, 1);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* write the privateKeyAlgorithm
|
|
Packit |
aea12f |
* fields. (OID+NULL data)
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_write_value(*pkey_info, "privateKeyAlgorithm.algorithm",
|
|
Packit |
aea12f |
oid, 1);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_write_value(*pkey_info, "privateKeyAlgorithm.parameters",
|
|
Packit |
aea12f |
algo_params.data, algo_params.size);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&algo_params);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Write the raw private key
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result = _encode_privkey(pkey, &algo_privkey);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_write_value(*pkey_info, "privateKey", algo_privkey.data,
|
|
Packit |
aea12f |
algo_privkey.size);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&algo_privkey);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((pkey->params.pkflags & GNUTLS_PK_FLAG_PROVABLE) && pkey->params.seed_size > 0) {
|
|
Packit |
aea12f |
gnutls_datum_t seed_info;
|
|
Packit |
aea12f |
/* rfc8479 attribute encoding */
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = _x509_encode_provable_seed(pkey, &seed_info);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = _x509_set_attribute(*pkey_info, "attributes", OID_ATTR_PROV_SEED, &seed_info);
|
|
Packit |
aea12f |
gnutls_free(seed_info.data);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
/* Append an empty Attributes field.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result = asn1_write_value(*pkey_info, "attributes", NULL, 0);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* DER Encode the generated private key info.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
len = 0;
|
|
Packit |
aea12f |
result = asn1_der_coding(*pkey_info, "", NULL, &len, NULL);
|
|
Packit |
aea12f |
if (result != ASN1_MEM_ERROR) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* allocate data for the der
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
der->size = len;
|
|
Packit |
aea12f |
der->data = gnutls_malloc(len);
|
|
Packit |
aea12f |
if (der->data == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = asn1_der_coding(*pkey_info, "", der->data, &len, NULL);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
asn1_delete_structure2(pkey_info, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
_gnutls_free_datum(&algo_params);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&algo_privkey);
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Converts a PKCS #8 private key info to
|
|
Packit |
aea12f |
* a PKCS #8 EncryptedPrivateKeyInfo.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
encode_to_pkcs8_key(schema_id schema, const gnutls_datum_t * der_key,
|
|
Packit |
aea12f |
const char *password, ASN1_TYPE * out)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result;
|
|
Packit |
aea12f |
gnutls_datum_t key = { NULL, 0 };
|
|
Packit |
aea12f |
gnutls_datum_t tmp = { NULL, 0 };
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY;
|
|
Packit |
aea12f |
struct pbkdf2_params kdf_params;
|
|
Packit |
aea12f |
struct pbe_enc_params enc_params;
|
|
Packit |
aea12f |
const struct pkcs_cipher_schema_st *s;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
s = _gnutls_pkcs_schema_get(schema);
|
|
Packit |
aea12f |
if (s == NULL || s->decrypt_only) {
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result =
|
|
Packit |
aea12f |
asn1_create_element(_gnutls_get_pkix(),
|
|
Packit |
aea12f |
"PKIX1.pkcs-8-EncryptedPrivateKeyInfo",
|
|
Packit |
aea12f |
&pkcs8_asn)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return _gnutls_asn2err(result);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Write the encryption schema OID
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_write_value(pkcs8_asn, "encryptionAlgorithm.algorithm",
|
|
Packit |
aea12f |
s->write_oid, 1);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Generate a symmetric key.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_pkcs_generate_key(schema, password, &kdf_params, &enc_params, &key);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_pkcs_write_schema_params(schema, pkcs8_asn,
|
|
Packit |
aea12f |
"encryptionAlgorithm.parameters",
|
|
Packit |
aea12f |
&kdf_params, &enc_params);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Parameters have been encoded. Now
|
|
Packit |
aea12f |
* encrypt the Data.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result = _gnutls_pkcs_raw_encrypt_data(der_key, &enc_params, &key, &tmp);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* write the encrypted data.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_write_value(pkcs8_asn, "encryptedData", tmp.data,
|
|
Packit |
aea12f |
tmp.size);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_free_datum(&tmp);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&key);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
*out = pkcs8_asn;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&key);
|
|
Packit |
aea12f |
_gnutls_free_datum(&tmp);
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkcs8_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/**
|
|
Packit |
aea12f |
* gnutls_x509_privkey_export_pkcs8:
|
|
Packit |
aea12f |
* @key: Holds the key
|
|
Packit |
aea12f |
* @format: the format of output params. One of PEM or DER.
|
|
Packit |
aea12f |
* @password: the password that will be used to encrypt the key.
|
|
Packit |
aea12f |
* @flags: an ORed sequence of gnutls_pkcs_encrypt_flags_t
|
|
Packit |
aea12f |
* @output_data: will contain a private key PEM or DER encoded
|
|
Packit |
aea12f |
* @output_data_size: holds the size of output_data (and will be
|
|
Packit |
aea12f |
* replaced by the actual size of parameters)
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This function will export the private key to a PKCS8 structure.
|
|
Packit |
aea12f |
* Both RSA and DSA keys can be exported. For DSA keys we use
|
|
Packit |
aea12f |
* PKCS #11 definitions. If the flags do not specify the encryption
|
|
Packit |
aea12f |
* cipher, then the default 3DES (PBES2) will be used.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The @password can be either ASCII or UTF-8 in the default PBES2
|
|
Packit |
aea12f |
* encryption schemas, or ASCII for the PKCS12 schemas.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* If the buffer provided is not long enough to hold the output, then
|
|
Packit |
aea12f |
* *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
|
|
Packit |
aea12f |
* be returned.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* If the structure is PEM encoded, it will have a header
|
|
Packit |
aea12f |
* of "BEGIN ENCRYPTED PRIVATE KEY" or "BEGIN PRIVATE KEY" if
|
|
Packit |
aea12f |
* encryption is not used.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Returns: In case of failure a negative error code will be
|
|
Packit |
aea12f |
* returned, and 0 on success.
|
|
Packit |
aea12f |
**/
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
gnutls_x509_privkey_export_pkcs8(gnutls_x509_privkey_t key,
|
|
Packit |
aea12f |
gnutls_x509_crt_fmt_t format,
|
|
Packit |
aea12f |
const char *password,
|
|
Packit |
aea12f |
unsigned int flags,
|
|
Packit |
aea12f |
void *output_data,
|
|
Packit |
aea12f |
size_t * output_data_size)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn = NULL, pkey_info;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp = {NULL, 0};
|
|
Packit |
aea12f |
schema_id schema;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (key == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Get the private key info
|
|
Packit |
aea12f |
* tmp holds the DER encoding.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
ret = encode_to_private_key_info(key, &tmp, &pkey_info);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
schema = _gnutls_pkcs_flags_to_schema(flags);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (((flags & GNUTLS_PKCS_PLAIN) || password == NULL)
|
|
Packit |
aea12f |
&& !(flags & GNUTLS_PKCS_NULL_PASSWORD)) {
|
|
Packit |
aea12f |
_gnutls_free_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_export_int(pkey_info, format,
|
|
Packit |
aea12f |
PEM_UNENCRYPTED_PKCS8,
|
|
Packit |
aea12f |
output_data, output_data_size);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_info, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_info, ASN1_DELETE_FLAG_ZEROIZE); /* we don't need it */
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
encode_to_pkcs8_key(schema, &tmp, password,
|
|
Packit |
aea12f |
&pkcs8_asn);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_export_int(pkcs8_asn, format, PEM_PKCS8,
|
|
Packit |
aea12f |
output_data, output_data_size);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkcs8_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/**
|
|
Packit |
aea12f |
* gnutls_pkcs8_info:
|
|
Packit |
aea12f |
* @data: Holds the PKCS #8 data
|
|
Packit |
aea12f |
* @format: the format of the PKCS #8 data
|
|
Packit |
aea12f |
* @schema: indicate the schema as one of %gnutls_pkcs_encrypt_flags_t
|
|
Packit |
aea12f |
* @cipher: the cipher used as %gnutls_cipher_algorithm_t
|
|
Packit |
aea12f |
* @salt: PBKDF2 salt (if non-NULL then @salt_size initially holds its size)
|
|
Packit |
aea12f |
* @salt_size: PBKDF2 salt size
|
|
Packit |
aea12f |
* @iter_count: PBKDF2 iteration count
|
|
Packit |
aea12f |
* @oid: if non-NULL it will contain an allocated null-terminated variable with the OID
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This function will provide information on the algorithms used
|
|
Packit |
aea12f |
* in a particular PKCS #8 structure. If the structure algorithms
|
|
Packit |
aea12f |
* are unknown the code %GNUTLS_E_UNKNOWN_CIPHER_TYPE will be returned,
|
|
Packit |
aea12f |
* and only @oid, will be set. That is, @oid will be set on encrypted PKCS #8
|
|
Packit |
aea12f |
* structures whether supported or not. It must be deinitialized using gnutls_free().
|
|
Packit |
aea12f |
* The other variables are only set on supported structures.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Returns: %GNUTLS_E_INVALID_REQUEST if the provided structure isn't an encrypted key,
|
|
Packit |
aea12f |
* %GNUTLS_E_UNKNOWN_CIPHER_TYPE if the structure's encryption isn't supported, or
|
|
Packit |
aea12f |
* another negative error code in case of a failure. Zero on success.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Since: 3.4.0
|
|
Packit |
aea12f |
**/
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
gnutls_pkcs8_info(const gnutls_datum_t * data, gnutls_x509_crt_fmt_t format,
|
|
Packit |
aea12f |
unsigned int *schema, unsigned int *cipher,
|
|
Packit |
aea12f |
void *salt, unsigned int *salt_size,
|
|
Packit |
aea12f |
unsigned int *iter_count,
|
|
Packit |
aea12f |
char **oid)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret = 0, need_free = 0;
|
|
Packit |
aea12f |
gnutls_datum_t _data;
|
|
Packit |
aea12f |
const struct pkcs_cipher_schema_st *p = NULL;
|
|
Packit |
aea12f |
struct pbkdf2_params kdf;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memset(&kdf, 0, sizeof(kdf));
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (oid)
|
|
Packit |
aea12f |
*oid = NULL;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_data.data = data->data;
|
|
Packit |
aea12f |
_data.size = data->size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* If the Certificate is in PEM format then decode it
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
if (format == GNUTLS_X509_FMT_PEM) {
|
|
Packit |
aea12f |
/* Try the first header
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_fbase64_decode(PEM_UNENCRYPTED_PKCS8,
|
|
Packit |
aea12f |
data->data, data->size, &_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) { /* Try the encrypted header
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_fbase64_decode(PEM_PKCS8, data->data,
|
|
Packit |
aea12f |
data->size, &_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
need_free = 1;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = pkcs8_key_info(&_data, &p, &kdf, oid);
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_DECRYPTION_FAILED)
|
|
Packit |
aea12f |
ret = GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
assert(p != NULL);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (need_free)
|
|
Packit |
aea12f |
_gnutls_free_datum(&_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (schema)
|
|
Packit |
aea12f |
*schema = p->flag;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (cipher)
|
|
Packit |
aea12f |
*cipher = p->cipher;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (iter_count)
|
|
Packit |
aea12f |
*iter_count = kdf.iter_count;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (salt) {
|
|
Packit |
aea12f |
if (*salt_size >= (unsigned)kdf.salt_size) {
|
|
Packit |
aea12f |
memcpy(salt, kdf.salt, kdf.salt_size);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
*salt_size = kdf.salt_size;
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (salt_size)
|
|
Packit |
aea12f |
*salt_size = kdf.salt_size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
if (ret != GNUTLS_E_UNKNOWN_CIPHER_TYPE && oid) {
|
|
Packit |
aea12f |
gnutls_free(*oid);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
if (need_free)
|
|
Packit |
aea12f |
_gnutls_free_datum(&_data);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/**
|
|
Packit |
aea12f |
* gnutls_x509_privkey_export2_pkcs8:
|
|
Packit |
aea12f |
* @key: Holds the key
|
|
Packit |
aea12f |
* @format: the format of output params. One of PEM or DER.
|
|
Packit |
aea12f |
* @password: the password that will be used to encrypt the key.
|
|
Packit |
aea12f |
* @flags: an ORed sequence of gnutls_pkcs_encrypt_flags_t
|
|
Packit |
aea12f |
* @out: will contain a private key PEM or DER encoded
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This function will export the private key to a PKCS8 structure.
|
|
Packit |
aea12f |
* Both RSA and DSA keys can be exported. For DSA keys we use
|
|
Packit |
aea12f |
* PKCS #11 definitions. If the flags do not specify the encryption
|
|
Packit |
aea12f |
* cipher, then the default 3DES (PBES2) will be used.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The @password can be either ASCII or UTF-8 in the default PBES2
|
|
Packit |
aea12f |
* encryption schemas, or ASCII for the PKCS12 schemas.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The output buffer is allocated using gnutls_malloc().
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* If the structure is PEM encoded, it will have a header
|
|
Packit |
aea12f |
* of "BEGIN ENCRYPTED PRIVATE KEY" or "BEGIN PRIVATE KEY" if
|
|
Packit |
aea12f |
* encryption is not used.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Returns: In case of failure a negative error code will be
|
|
Packit |
aea12f |
* returned, and 0 on success.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Since 3.1.3
|
|
Packit |
aea12f |
**/
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
gnutls_x509_privkey_export2_pkcs8(gnutls_x509_privkey_t key,
|
|
Packit |
aea12f |
gnutls_x509_crt_fmt_t format,
|
|
Packit |
aea12f |
const char *password,
|
|
Packit |
aea12f |
unsigned int flags, gnutls_datum_t * out)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn = NULL, pkey_info;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp = {NULL, 0};
|
|
Packit |
aea12f |
schema_id schema;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (key == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Get the private key info
|
|
Packit |
aea12f |
* tmp holds the DER encoding.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
ret = encode_to_private_key_info(key, &tmp, &pkey_info);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
schema = _gnutls_pkcs_flags_to_schema(flags);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (((flags & GNUTLS_PKCS_PLAIN) || password == NULL)
|
|
Packit |
aea12f |
&& !(flags & GNUTLS_PKCS_NULL_PASSWORD)) {
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_export_int2(pkey_info, format,
|
|
Packit |
aea12f |
PEM_UNENCRYPTED_PKCS8, out);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_info, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_info, ASN1_DELETE_FLAG_ZEROIZE); /* we don't need it */
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
encode_to_pkcs8_key(schema, &tmp, password,
|
|
Packit |
aea12f |
&pkcs8_asn);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_export_int2(pkcs8_asn, format, PEM_PKCS8,
|
|
Packit |
aea12f |
out);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkcs8_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* We've gotten this far. In the real world it's almost certain
|
|
Packit |
aea12f |
* that we're dealing with a good file, but wrong password.
|
|
Packit |
aea12f |
* Sadly like 90% of random data is somehow valid DER for the
|
|
Packit |
aea12f |
* a first small number of bytes, so no easy way to guarantee. */
|
|
Packit |
aea12f |
#define CHECK_ERR_FOR_ENCRYPTED(result) \
|
|
Packit |
aea12f |
if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_DER_ERROR || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_VALUE_NOT_FOUND || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_GENERIC_ERROR || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_VALUE_NOT_VALID || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_TAG_ERROR || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_TAG_IMPLICIT || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_TYPE_ANY_ERROR || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_SYNTAX_ERROR || \
|
|
Packit |
aea12f |
result == GNUTLS_E_ASN1_DER_OVERFLOW) { \
|
|
Packit |
aea12f |
result = GNUTLS_E_DECRYPTION_FAILED; \
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int pkcs8_key_decrypt(const gnutls_datum_t * raw_key,
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn, const char *password,
|
|
Packit |
aea12f |
gnutls_x509_privkey_t pkey)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result, len;
|
|
Packit |
aea12f |
char enc_oid[MAX_OID_SIZE];
|
|
Packit |
aea12f |
gnutls_datum_t tmp = {NULL, 0};
|
|
Packit |
aea12f |
int params_start, params_end, params_len;
|
|
Packit |
aea12f |
struct pbkdf2_params kdf_params;
|
|
Packit |
aea12f |
struct pbe_enc_params enc_params;
|
|
Packit |
aea12f |
schema_id schema;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Check the encryption schema OID
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
len = sizeof(enc_oid);
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_read_value(pkcs8_asn, "encryptionAlgorithm.algorithm",
|
|
Packit |
aea12f |
enc_oid, &len;;
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result = _gnutls_check_pkcs_cipher_schema(enc_oid)) < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
schema = result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Get the DER encoding of the parameters.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_der_decoding_startEnd(pkcs8_asn, raw_key->data,
|
|
Packit |
aea12f |
raw_key->size,
|
|
Packit |
aea12f |
"encryptionAlgorithm.parameters",
|
|
Packit |
aea12f |
¶ms_start, ¶ms_end);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
params_len = params_end - params_start + 1;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_read_pkcs_schema_params(&schema, password,
|
|
Packit |
aea12f |
&raw_key->data[params_start],
|
|
Packit |
aea12f |
params_len, &kdf_params, &enc_params);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Parameters have been decoded. Now
|
|
Packit |
aea12f |
* decrypt the EncryptedData.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_pkcs_raw_decrypt_data(schema, pkcs8_asn, "encryptedData", password,
|
|
Packit |
aea12f |
&kdf_params, &enc_params, &tmp);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = GNUTLS_E_DECRYPTION_FAILED;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = decode_private_key_info(&tmp, pkey);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
CHECK_ERR_FOR_ENCRYPTED(result);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int check_for_decrypted(const gnutls_datum_t *der)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result;
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result =
|
|
Packit |
aea12f |
asn1_create_element(_gnutls_get_pkix(),
|
|
Packit |
aea12f |
"PKIX1.pkcs-8-PrivateKeyInfo",
|
|
Packit |
aea12f |
&pkcs8_asn)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return _gnutls_asn2err(result);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = _asn1_strict_der_decode(&pkcs8_asn, der->data, der->size, NULL);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = 0;
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkcs8_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static
|
|
Packit |
aea12f |
int pkcs8_key_info(const gnutls_datum_t * raw_key,
|
|
Packit |
aea12f |
const struct pkcs_cipher_schema_st **p,
|
|
Packit |
aea12f |
struct pbkdf2_params *kdf_params,
|
|
Packit |
aea12f |
char **oid)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result, len;
|
|
Packit |
aea12f |
char enc_oid[MAX_OID_SIZE*2];
|
|
Packit |
aea12f |
int params_start, params_end, params_len;
|
|
Packit |
aea12f |
struct pbe_enc_params enc_params;
|
|
Packit |
aea12f |
schema_id schema;
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memset(&enc_params, 0, sizeof(enc_params));
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = check_for_decrypted(raw_key);
|
|
Packit |
aea12f |
if (result == 0)
|
|
Packit |
aea12f |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result =
|
|
Packit |
aea12f |
asn1_create_element(_gnutls_get_pkix(),
|
|
Packit |
aea12f |
"PKIX1.pkcs-8-EncryptedPrivateKeyInfo",
|
|
Packit |
aea12f |
&pkcs8_asn)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_asn1_strict_der_decode(&pkcs8_asn, raw_key->data, raw_key->size,
|
|
Packit |
aea12f |
NULL);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Check the encryption schema OID
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
len = sizeof(enc_oid);
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_read_value(pkcs8_asn, "encryptionAlgorithm.algorithm",
|
|
Packit |
aea12f |
enc_oid, &len;;
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (oid) {
|
|
Packit |
aea12f |
*oid = gnutls_strdup(enc_oid);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result = _gnutls_check_pkcs_cipher_schema(enc_oid)) < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
schema = result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Get the DER encoding of the parameters.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_der_decoding_startEnd(pkcs8_asn, raw_key->data,
|
|
Packit |
aea12f |
raw_key->size,
|
|
Packit |
aea12f |
"encryptionAlgorithm.parameters",
|
|
Packit |
aea12f |
¶ms_start, ¶ms_end);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
params_len = params_end - params_start + 1;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_read_pkcs_schema_params(&schema, NULL,
|
|
Packit |
aea12f |
&raw_key->data[params_start],
|
|
Packit |
aea12f |
params_len, kdf_params, &enc_params);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
if (oid && enc_params.pbes2_oid[0] != 0) {
|
|
Packit |
aea12f |
snprintf(enc_oid, sizeof(enc_oid), "%s/%s", *oid, enc_params.pbes2_oid);
|
|
Packit |
aea12f |
gnutls_free(*oid);
|
|
Packit |
aea12f |
*oid = gnutls_strdup(enc_oid);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
*p = _gnutls_pkcs_schema_get(schema);
|
|
Packit |
aea12f |
if (*p == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = GNUTLS_E_UNKNOWN_CIPHER_TYPE;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkcs8_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Converts a PKCS #8 key to
|
|
Packit |
aea12f |
* an internal structure (gnutls_private_key)
|
|
Packit |
aea12f |
* (normally a PKCS #1 encoded RSA key)
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
pkcs8_key_decode(const gnutls_datum_t * raw_key,
|
|
Packit |
aea12f |
const char *password, gnutls_x509_privkey_t pkey,
|
|
Packit |
aea12f |
unsigned int decrypt)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result;
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result =
|
|
Packit |
aea12f |
asn1_create_element(_gnutls_get_pkix(),
|
|
Packit |
aea12f |
"PKIX1.pkcs-8-EncryptedPrivateKeyInfo",
|
|
Packit |
aea12f |
&pkcs8_asn)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_asn1_strict_der_decode(&pkcs8_asn, raw_key->data, raw_key->size,
|
|
Packit |
aea12f |
NULL);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (decrypt)
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
pkcs8_key_decrypt(raw_key, pkcs8_asn, password, pkey);
|
|
Packit |
aea12f |
else
|
|
Packit |
aea12f |
result = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkcs8_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Decodes an RSA privateKey from a PKCS8 structure.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
_decode_pkcs8_rsa_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp = {NULL, 0};
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_value(pkcs8_asn, "privateKey", &tmp);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pkey->key = _gnutls_privkey_decode_pkcs1_rsa_key(&tmp, pkey);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (pkey->key == NULL) {
|
|
Packit |
aea12f |
ret = GNUTLS_E_PK_INVALID_PRIVKEY;
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Decodes an RSA-PSS privateKey from a PKCS8 structure.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
_decode_pkcs8_rsa_pss_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp = {NULL, 0};
|
|
Packit |
aea12f |
gnutls_x509_spki_st params;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memset(¶ms, 0, sizeof(params));
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_value(pkcs8_asn,
|
|
Packit |
aea12f |
"privateKeyAlgorithm.parameters", &tmp);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_ASN1_VALUE_NOT_FOUND || ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
|
|
Packit |
aea12f |
goto skip_params;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_rsa_pss_params(tmp.data, tmp.size, ¶ms);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
skip_params:
|
|
Packit |
aea12f |
ret = _decode_pkcs8_rsa_key(pkcs8_asn, pkey);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pkey->params.algo = GNUTLS_PK_RSA_PSS;
|
|
Packit |
aea12f |
memcpy(&pkey->params.spki, ¶ms, sizeof(gnutls_x509_spki_st));
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Decodes an ECC privateKey from a PKCS8 structure.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
_decode_pkcs8_ecc_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp = {NULL, 0};
|
|
Packit |
aea12f |
unsigned char oid[MAX_OID_SIZE];
|
|
Packit |
aea12f |
unsigned curve = GNUTLS_ECC_CURVE_INVALID;
|
|
Packit |
aea12f |
int len, result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* openssl PKCS #8 files with ECC keys place the curve in
|
|
Packit |
aea12f |
* privateKeyAlgorithm.parameters instead of the ECPrivateKey.parameters.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
len = sizeof(oid);
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_read_value(pkcs8_asn, "privateKeyAlgorithm.parameters",
|
|
Packit |
aea12f |
oid, &len;;
|
|
Packit |
aea12f |
if (result == ASN1_SUCCESS) {
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_ecc_params(oid, len, &curve);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
_gnutls_debug_log("PKCS#8: unknown curve OID %s\n", oid);
|
|
Packit |
aea12f |
curve = GNUTLS_ECC_CURVE_INVALID;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_value(pkcs8_asn, "privateKey", &tmp);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_privkey_decode_ecc_key(&pkey->key, &tmp, pkey, curve);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
_decode_pkcs8_eddsa_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey, const char *oid)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp;
|
|
Packit |
aea12f |
gnutls_ecc_curve_t curve = GNUTLS_ECC_CURVE_INVALID;
|
|
Packit |
aea12f |
const gnutls_ecc_curve_entry_st *ce;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_pk_params_init(&pkey->params);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
curve = gnutls_oid_to_ecc_curve(oid);
|
|
Packit |
aea12f |
if (curve == GNUTLS_ECC_CURVE_INVALID) {
|
|
Packit |
aea12f |
_gnutls_debug_log("PKCS#8: unknown curve OID %s\n", oid);
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ce = _gnutls_ecc_curve_get_params(curve);
|
|
Packit |
aea12f |
if (_curve_is_eddsa(ce)) {
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_string(pkcs8_asn, "privateKey", &tmp, ASN1_ETYPE_OCTET_STRING, 1);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (tmp.size != ce->size) {
|
|
Packit |
aea12f |
gnutls_free(tmp.data);
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
gnutls_free(pkey->params.raw_priv.data);
|
|
Packit Service |
991b93 |
switch (curve) {
|
|
Packit Service |
991b93 |
case GNUTLS_ECC_CURVE_ED25519:
|
|
Packit Service |
991b93 |
pkey->params.algo = GNUTLS_PK_EDDSA_ED25519;
|
|
Packit Service |
991b93 |
break;
|
|
Packit Service |
991b93 |
case GNUTLS_ECC_CURVE_ED448:
|
|
Packit Service |
991b93 |
pkey->params.algo = GNUTLS_PK_EDDSA_ED448;
|
|
Packit Service |
991b93 |
break;
|
|
Packit Service |
991b93 |
default:
|
|
Packit Service |
991b93 |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit Service |
991b93 |
}
|
|
Packit |
aea12f |
pkey->params.raw_priv.data = tmp.data;
|
|
Packit |
aea12f |
pkey->params.raw_priv.size = tmp.size;
|
|
Packit |
aea12f |
pkey->params.curve = curve;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
tmp.data = NULL;
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Converts a GOST key to
|
|
Packit |
aea12f |
* an internal structure (gnutls_private_key)
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
_privkey_decode_gost_key(const gnutls_datum_t * raw_key,
|
|
Packit |
aea12f |
gnutls_x509_privkey_t pkey)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
int ecc_size = gnutls_ecc_curve_get_size(pkey->params.curve);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Just to be sure here */
|
|
Packit |
aea12f |
if (ecc_size <= 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Private key form described in R 50.1.112-2016.
|
|
Packit |
aea12f |
* Private key can come up as masked value concatenated with several masks.
|
|
Packit |
aea12f |
* each part is of ecc_size bytes. Key will be unmasked in pk_fixup */
|
|
Packit |
aea12f |
if (raw_key->size % ecc_size == 0) {
|
|
Packit |
aea12f |
ret = _gnutls_mpi_init_scan_le(&pkey->params.params[GOST_K],
|
|
Packit |
aea12f |
raw_key->data, raw_key->size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else if (raw_key->data[0] == ASN1_TAG_INTEGER) {
|
|
Packit |
aea12f |
ASN1_TYPE pkey_asn;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Very old format: INTEGER packed in OCTET STRING */
|
|
Packit |
aea12f |
if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
|
|
Packit |
aea12f |
"GNUTLS.GOSTPrivateKeyOld",
|
|
Packit |
aea12f |
&pkey_asn)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = _gnutls_asn2err(ret);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _asn1_strict_der_decode(&pkey_asn,
|
|
Packit |
aea12f |
raw_key->data, raw_key->size,
|
|
Packit |
aea12f |
NULL);
|
|
Packit |
aea12f |
if (ret != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = _gnutls_asn2err(ret);
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_key_int(pkey_asn, "",
|
|
Packit |
aea12f |
&pkey->params.params[GOST_K]);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
} else if (raw_key->data[0] == ASN1_TAG_OCTET_STRING) {
|
|
Packit |
aea12f |
ASN1_TYPE pkey_asn;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* format: OCTET STRING packed in OCTET STRING */
|
|
Packit |
aea12f |
if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
|
|
Packit |
aea12f |
"GNUTLS.GOSTPrivateKey",
|
|
Packit |
aea12f |
&pkey_asn)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = _gnutls_asn2err(ret);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _asn1_strict_der_decode(&pkey_asn,
|
|
Packit |
aea12f |
raw_key->data, raw_key->size,
|
|
Packit |
aea12f |
NULL);
|
|
Packit |
aea12f |
if (ret != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = _gnutls_asn2err(ret);
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_key_int_le(pkey_asn, "",
|
|
Packit |
aea12f |
&pkey->params.params[GOST_K]);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_PARSING_ERROR;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pkey->params.params_nr++;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Decodes a GOST privateKey from a PKCS8 structure.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
_decode_pkcs8_gost_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey,
|
|
Packit |
aea12f |
gnutls_pk_algorithm_t algo)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp;
|
|
Packit |
aea12f |
unsigned char oid[3 * MAX_OID_SIZE]; /* GOST parameters can have 3 OIDs at most */
|
|
Packit |
aea12f |
int len, result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_pk_params_init(&pkey->params);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
len = sizeof(oid);
|
|
Packit |
aea12f |
result = asn1_read_value(pkcs8_asn, "privateKeyAlgorithm.parameters",
|
|
Packit |
aea12f |
oid, &len;;
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_PARSING_ERROR;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_gost_params(oid, len, &pkey->params, algo);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Will be fixed later by pk_fixup */
|
|
Packit |
aea12f |
ret = _gnutls_mpi_init(&pkey->params.params[GOST_X]);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
pkey->params.params_nr++;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_mpi_init(&pkey->params.params[GOST_Y]);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
pkey->params.params_nr++;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_mpi_set_ui(pkey->params.params[GOST_X], 0);
|
|
Packit |
aea12f |
_gnutls_mpi_set_ui(pkey->params.params[GOST_Y], 0);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_value(pkcs8_asn, "privateKey", &tmp);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _privkey_decode_gost_key(&tmp, pkey);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pkey->params.algo = algo;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
gnutls_pk_params_clear(&pkey->params);
|
|
Packit |
aea12f |
gnutls_pk_params_release(&pkey->params);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Decodes an DSA privateKey and params from a PKCS8 structure.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
_decode_pkcs8_dsa_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t tmp = {NULL, 0};
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_pk_params_init(&pkey->params);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_x509_read_value(pkcs8_asn, "privateKey", &tmp);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_read_der_int(tmp.data, tmp.size,
|
|
Packit |
aea12f |
&pkey->params.params[4]);
|
|
Packit |
aea12f |
_gnutls_free_key_datum(&tmp);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_read_value(pkcs8_asn,
|
|
Packit |
aea12f |
"privateKeyAlgorithm.parameters",
|
|
Packit |
aea12f |
&tmp);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_x509_read_pubkey_params(GNUTLS_PK_DSA, tmp.data,
|
|
Packit |
aea12f |
tmp.size, &pkey->params);
|
|
Packit |
aea12f |
_gnutls_free_datum(&tmp);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (_gnutls_mpi_cmp_ui(pkey->params.params[0], 0) == 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_ILLEGAL_PARAMETER;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* the public key can be generated as g^x mod p */
|
|
Packit |
aea12f |
ret = _gnutls_mpi_init(&pkey->params.params[3]);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_mpi_powm(pkey->params.params[3], pkey->params.params[2],
|
|
Packit |
aea12f |
pkey->params.params[4], pkey->params.params[0]);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pkey->params.algo = GNUTLS_PK_DSA;
|
|
Packit |
aea12f |
pkey->params.params_nr = DSA_PRIVATE_PARAMS;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_asn1_encode_privkey(&pkey->key,
|
|
Packit |
aea12f |
&pkey->params);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
if (pkey->params.params_nr != DSA_PRIVATE_PARAMS)
|
|
Packit |
aea12f |
_gnutls_mpi_release(&pkey->params.params[4]);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
decode_private_key_info(const gnutls_datum_t * der,
|
|
Packit |
aea12f |
gnutls_x509_privkey_t pkey)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result, len;
|
|
Packit |
aea12f |
char oid[MAX_OID_SIZE];
|
|
Packit |
aea12f |
ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY;
|
|
Packit |
aea12f |
gnutls_datum_t sder;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((result =
|
|
Packit |
aea12f |
asn1_create_element(_gnutls_get_pkix(),
|
|
Packit |
aea12f |
"PKIX1.pkcs-8-PrivateKeyInfo",
|
|
Packit |
aea12f |
&pkcs8_asn)) != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = _asn1_strict_der_decode(&pkcs8_asn, der->data, der->size, NULL);
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Check the private key algorithm OID
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
len = sizeof(oid);
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
asn1_read_value(pkcs8_asn, "privateKeyAlgorithm.algorithm",
|
|
Packit |
aea12f |
oid, &len;;
|
|
Packit |
aea12f |
if (result != ASN1_SUCCESS) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
result = _gnutls_asn2err(result);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pkey->params.algo = gnutls_oid_to_pk(oid);
|
|
Packit |
aea12f |
if (pkey->params.algo == GNUTLS_PK_UNKNOWN) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
_gnutls_debug_log
|
|
Packit |
aea12f |
("PKCS #8 private key OID '%s' is unsupported.\n",
|
|
Packit |
aea12f |
oid);
|
|
Packit |
aea12f |
result = GNUTLS_E_UNKNOWN_PK_ALGORITHM;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Get the DER encoding of the actual private key.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
switch(pkey->params.algo) {
|
|
Packit |
aea12f |
case GNUTLS_PK_RSA:
|
|
Packit |
aea12f |
result = _decode_pkcs8_rsa_key(pkcs8_asn, pkey);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
case GNUTLS_PK_RSA_PSS:
|
|
Packit |
aea12f |
result = _decode_pkcs8_rsa_pss_key(pkcs8_asn, pkey);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
case GNUTLS_PK_DSA:
|
|
Packit |
aea12f |
result = _decode_pkcs8_dsa_key(pkcs8_asn, pkey);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
case GNUTLS_PK_ECDSA:
|
|
Packit |
aea12f |
result = _decode_pkcs8_ecc_key(pkcs8_asn, pkey);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
case GNUTLS_PK_EDDSA_ED25519:
|
|
Packit Service |
991b93 |
case GNUTLS_PK_EDDSA_ED448:
|
|
Packit |
aea12f |
result = _decode_pkcs8_eddsa_key(pkcs8_asn, pkey, oid);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
case GNUTLS_PK_GOST_01:
|
|
Packit |
aea12f |
case GNUTLS_PK_GOST_12_256:
|
|
Packit |
aea12f |
case GNUTLS_PK_GOST_12_512:
|
|
Packit |
aea12f |
result = _decode_pkcs8_gost_key(pkcs8_asn,
|
|
Packit |
aea12f |
pkey, pkey->params.algo);
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
default:
|
|
Packit |
aea12f |
result = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* check for provable parameters attribute */
|
|
Packit |
aea12f |
ret = _x509_parse_attribute(pkcs8_asn, "attributes", OID_ATTR_PROV_SEED, 0, 1, &sder);
|
|
Packit |
aea12f |
if (ret >= 0) { /* ignore it when not being present */
|
|
Packit |
aea12f |
ret = _x509_decode_provable_seed(pkey, &sder);
|
|
Packit |
aea12f |
gnutls_free(sder.data);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
result = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
asn1_delete_structure2(&pkcs8_asn, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/**
|
|
Packit |
aea12f |
* gnutls_x509_privkey_import_pkcs8:
|
|
Packit |
aea12f |
* @key: The data to store the parsed key
|
|
Packit |
aea12f |
* @data: The DER or PEM encoded key.
|
|
Packit |
aea12f |
* @format: One of DER or PEM
|
|
Packit |
aea12f |
* @password: the password to decrypt the key (if it is encrypted).
|
|
Packit |
aea12f |
* @flags: 0 if encrypted or GNUTLS_PKCS_PLAIN if not encrypted.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This function will convert the given DER or PEM encoded PKCS8 2.0
|
|
Packit |
aea12f |
* encrypted key to the native gnutls_x509_privkey_t format. The
|
|
Packit |
aea12f |
* output will be stored in @key. Both RSA and DSA keys can be
|
|
Packit |
aea12f |
* imported, and flags can only be used to indicate an unencrypted
|
|
Packit |
aea12f |
* key.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The @password can be either ASCII or UTF-8 in the default PBES2
|
|
Packit |
aea12f |
* encryption schemas, or ASCII for the PKCS12 schemas.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* If the Certificate is PEM encoded it should have a header of
|
|
Packit |
aea12f |
* "ENCRYPTED PRIVATE KEY", or "PRIVATE KEY". You only need to
|
|
Packit |
aea12f |
* specify the flags if the key is DER encoded, since in that case
|
|
Packit |
aea12f |
* the encryption status cannot be auto-detected.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* If the %GNUTLS_PKCS_PLAIN flag is specified and the supplied data
|
|
Packit |
aea12f |
* are encrypted then %GNUTLS_E_DECRYPTION_FAILED is returned.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
aea12f |
* negative error value.
|
|
Packit |
aea12f |
**/
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey_t key,
|
|
Packit |
aea12f |
const gnutls_datum_t * data,
|
|
Packit |
aea12f |
gnutls_x509_crt_fmt_t format,
|
|
Packit |
aea12f |
const char *password, unsigned int flags)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int result = 0, need_free = 0;
|
|
Packit |
aea12f |
gnutls_datum_t _data;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (key == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_data.data = data->data;
|
|
Packit |
aea12f |
_data.size = data->size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
key->params.algo = GNUTLS_PK_UNKNOWN;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* If the Certificate is in PEM format then decode it
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
if (format == GNUTLS_X509_FMT_PEM) {
|
|
Packit |
aea12f |
/* Try the first header
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_fbase64_decode(PEM_UNENCRYPTED_PKCS8,
|
|
Packit |
aea12f |
data->data, data->size, &_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result < 0) { /* Try the encrypted header
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_fbase64_decode(PEM_PKCS8, data->data,
|
|
Packit |
aea12f |
data->size, &_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else if (flags == 0)
|
|
Packit |
aea12f |
flags |= GNUTLS_PKCS_PLAIN;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
need_free = 1;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (key->expanded) {
|
|
Packit |
aea12f |
_gnutls_x509_privkey_reinit(key);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
key->expanded = 1;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Here we don't check for password == NULL to maintain a backwards
|
|
Packit |
aea12f |
* compatibility behavior, with old versions that were encrypting using
|
|
Packit |
aea12f |
* a NULL password.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
if (flags & GNUTLS_PKCS_PLAIN) {
|
|
Packit |
aea12f |
result = decode_private_key_info(&_data, key);
|
|
Packit |
aea12f |
if (result < 0) { /* check if it is encrypted */
|
|
Packit |
aea12f |
if (pkcs8_key_decode(&_data, "", key, 0) == 0)
|
|
Packit |
aea12f |
result = GNUTLS_E_DECRYPTION_FAILED;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else { /* encrypted. */
|
|
Packit |
aea12f |
result = pkcs8_key_decode(&_data, password, key, 1);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* This part is necessary to get the public key on certain algorithms.
|
|
Packit |
aea12f |
* In the import above we only get the private key. */
|
|
Packit |
aea12f |
result =
|
|
Packit |
aea12f |
_gnutls_pk_fixup(key->params.algo, GNUTLS_IMPORT, &key->params);
|
|
Packit |
aea12f |
if (result < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (need_free)
|
|
Packit |
aea12f |
_gnutls_free_datum(&_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* The key has now been decoded.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
asn1_delete_structure2(&key->key, ASN1_DELETE_FLAG_ZEROIZE);
|
|
Packit |
aea12f |
key->params.algo = GNUTLS_PK_UNKNOWN;
|
|
Packit |
aea12f |
if (need_free)
|
|
Packit |
aea12f |
_gnutls_free_datum(&_data);
|
|
Packit |
aea12f |
return result;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|