blob: bc9e54bed5750f41d6d27ea3a773727f8c620a69 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/
#include "tomcrypt_private.h"
#ifdef LTC_MECC
typedef struct {
ltc_asn1_type t;
ltc_asn1_list **pp;
} der_flexi_check;
#define LTC_SET_DER_FLEXI_CHECK(list, index, Type, P) \
do { \
int LTC_SDFC_temp##__LINE__ = (index); \
list[LTC_SDFC_temp##__LINE__].t = Type; \
list[LTC_SDFC_temp##__LINE__].pp = P; \
} while (0)
static int _der_flexi_sequence_cmp(const ltc_asn1_list *flexi, der_flexi_check *check)
{
const ltc_asn1_list *cur;
if (flexi->type != LTC_ASN1_SEQUENCE) {
return CRYPT_INVALID_PACKET;
}
cur = flexi->child;
while(check->t != LTC_ASN1_EOL) {
if (!LTC_ASN1_IS_TYPE(cur, check->t)) {
return CRYPT_INVALID_PACKET;
}
if (check->pp != NULL) *check->pp = (ltc_asn1_list*)cur;
cur = cur->next;
check++;
}
return CRYPT_OK;
}
/* NOTE: _der_decode_pkcs8_flexi & related stuff can be shared with rsa_import_pkcs8() */
int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen,
const void *pwd, unsigned long pwdlen,
ecc_key *key)
{
void *a, *b, *gx, *gy;
unsigned long len, cofactor, n;
const char *pka_ec_oid;
int err;
char OID[256];
const ltc_ecc_curve *curve;
ltc_asn1_list *p = NULL, *l = NULL;
der_flexi_check flexi_should[7];
ltc_asn1_list *seq, *priv_key;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
/* get EC alg oid */
err = pk_get_oid(PKA_EC, &pka_ec_oid);
if (err != CRYPT_OK) return err;
/* init key */
err = mp_init_multi(&a, &b, &gx, &gy, NULL);
if (err != CRYPT_OK) return err;
if ((err = pkcs8_decode_flexi(in, inlen, pwd, pwdlen, &l)) == CRYPT_OK) {
/* Setup for basic structure */
n=0;
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, NULL);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seq);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &priv_key);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
if (((err = _der_flexi_sequence_cmp(l, flexi_should)) == CRYPT_OK) &&
(pk_oid_cmp_with_asn1(pka_ec_oid, seq->child) == CRYPT_OK)) {
ltc_asn1_list *version, *field, *point, *point_g, *order, *p_cofactor;
/* Setup for CASE 2 */
n=0;
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &version);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &field);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &point);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &point_g);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &order);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &p_cofactor);
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
if (LTC_ASN1_IS_TYPE(seq->child->next, LTC_ASN1_OBJECT_IDENTIFIER)) {
/* CASE 1: curve by OID (AKA short variant):
* 0:d=0 hl=2 l= 100 cons: SEQUENCE
* 2:d=1 hl=2 l= 1 prim: INTEGER :00
* 5:d=1 hl=2 l= 16 cons: SEQUENCE (== *seq)
* 7:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
* 16:d=2 hl=2 l= 5 prim: OBJECT :(== *curve_oid (e.g. secp256k1 (== 1.3.132.0.10)))
* 23:d=1 hl=2 l= 77 prim: OCTET STRING :bytes (== *priv_key)
*/
ltc_asn1_list *curve_oid = seq->child->next;
len = sizeof(OID);
if ((err = pk_oid_num_to_str(curve_oid->data, curve_oid->size, OID, &len)) != CRYPT_OK) { goto LBL_DONE; }
if ((err = ecc_find_curve(OID, &curve)) != CRYPT_OK) { goto LBL_DONE; }
if ((err = ecc_set_curve(curve, key)) != CRYPT_OK) { goto LBL_DONE; }
}
else if ((err = _der_flexi_sequence_cmp(seq->child->next, flexi_should)) == CRYPT_OK) {
/* CASE 2: explicit curve parameters (AKA long variant):
* 0:d=0 hl=3 l= 227 cons: SEQUENCE
* 3:d=1 hl=2 l= 1 prim: INTEGER :00
* 6:d=1 hl=3 l= 142 cons: SEQUENCE (== *seq)
* 9:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
* 18:d=2 hl=3 l= 130 cons: SEQUENCE
* 21:d=3 hl=2 l= 1 prim: INTEGER :01
* 24:d=3 hl=2 l= 44 cons: SEQUENCE (== *field)
* 26:d=4 hl=2 l= 7 prim: OBJECT :prime-field
* 35:d=4 hl=2 l= 33 prim: INTEGER :(== *prime / curve.prime)
* 70:d=3 hl=2 l= 6 cons: SEQUENCE (== *point)
* 72:d=4 hl=2 l= 1 prim: OCTET STRING :bytes (== curve.A)
* 75:d=4 hl=2 l= 1 prim: OCTET STRING :bytes (== curve.B)
* 78:d=3 hl=2 l= 33 prim: OCTET STRING :bytes (== *g_point / curve.G-point)
* 113:d=3 hl=2 l= 33 prim: INTEGER :(== *order / curve.order)
* 148:d=3 hl=2 l= 1 prim: INTEGER :(== curve.cofactor)
* 151:d=1 hl=2 l= 77 prim: OCTET STRING :bytes (== *priv_key)
*/
if (mp_get_int(version->data) != 1) {
goto LBL_DONE;
}
cofactor = mp_get_int(p_cofactor->data);
if (LTC_ASN1_IS_TYPE(field->child, LTC_ASN1_OBJECT_IDENTIFIER) &&
LTC_ASN1_IS_TYPE(field->child->next, LTC_ASN1_INTEGER) &&
LTC_ASN1_IS_TYPE(point->child, LTC_ASN1_OCTET_STRING) &&
LTC_ASN1_IS_TYPE(point->child->next, LTC_ASN1_OCTET_STRING)) {
ltc_asn1_list *prime = field->child->next;
if ((err = mp_read_unsigned_bin(a, point->child->data, point->child->size)) != CRYPT_OK) {
goto LBL_DONE;
}
if ((err = mp_read_unsigned_bin(b, point->child->next->data, point->child->next->size)) != CRYPT_OK) {
goto LBL_DONE;
}
if ((err = ltc_ecc_import_point(point_g->data, point_g->size, prime->data, a, b, gx, gy)) != CRYPT_OK) {
goto LBL_DONE;
}
if ((err = ecc_set_curve_from_mpis(a, b, prime->data, order->data, gx, gy, cofactor, key)) != CRYPT_OK) {
goto LBL_DONE;
}
}
}
else {
err = CRYPT_INVALID_PACKET;
goto LBL_DONE;
}
/* load private key value 'k' */
len = priv_key->size;
if ((err = der_decode_sequence_flexi(priv_key->data, &len, &p)) == CRYPT_OK) {
if (p->type == LTC_ASN1_SEQUENCE &&
LTC_ASN1_IS_TYPE(p->child, LTC_ASN1_INTEGER) &&
LTC_ASN1_IS_TYPE(p->child->next, LTC_ASN1_OCTET_STRING)) {
ltc_asn1_list *lk = p->child->next;
if (mp_cmp_d(p->child->data, 1) != LTC_MP_EQ) {
err = CRYPT_INVALID_PACKET;
goto LBL_ECCFREE;
}
if ((err = ecc_set_key(lk->data, lk->size, PK_PRIVATE, key)) != CRYPT_OK) {
goto LBL_ECCFREE;
}
goto LBL_DONE; /* success */
}
}
}
}
err = CRYPT_INVALID_PACKET;
goto LBL_DONE;
LBL_ECCFREE:
ecc_free(key);
LBL_DONE:
mp_clear_multi(a, b, gx, gy, NULL);
if (l) der_free_sequence_flexi(l);
if (p) der_free_sequence_flexi(p);
return err;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */