1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 #include "tomcrypt_private.h"
5 
6 #ifdef LTC_MECC
7 
8 typedef struct {
9    ltc_asn1_type t;
10    ltc_asn1_list **pp;
11 } der_flexi_check;
12 
13 #define LTC_SET_DER_FLEXI_CHECK(list, index, Type, P)    \
14    do {                                         \
15       int LTC_SDFC_temp##__LINE__ = (index);   \
16       list[LTC_SDFC_temp##__LINE__].t = Type;  \
17       list[LTC_SDFC_temp##__LINE__].pp = P;    \
18    } while (0)
19 
s_der_flexi_sequence_cmp(const ltc_asn1_list * flexi,der_flexi_check * check)20 static int s_der_flexi_sequence_cmp(const ltc_asn1_list *flexi, der_flexi_check *check)
21 {
22    const ltc_asn1_list *cur;
23    if (flexi->type != LTC_ASN1_SEQUENCE) {
24       return CRYPT_INVALID_PACKET;
25    }
26    cur = flexi->child;
27    while(check->t != LTC_ASN1_EOL) {
28       if (!LTC_ASN1_IS_TYPE(cur, check->t)) {
29          return CRYPT_INVALID_PACKET;
30       }
31       if (check->pp != NULL) *check->pp = (ltc_asn1_list*)cur;
32       cur = cur->next;
33       check++;
34    }
35    return CRYPT_OK;
36 }
37 
38 /* NOTE: s_der_decode_pkcs8_flexi & related stuff can be shared with rsa_import_pkcs8() */
39 
ecc_import_pkcs8(const unsigned char * in,unsigned long inlen,const void * pwd,unsigned long pwdlen,ecc_key * key)40 int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen,
41                      const void *pwd, unsigned long pwdlen,
42                      ecc_key *key)
43 {
44    void          *a, *b, *gx, *gy;
45    unsigned long len, cofactor, n;
46    const char    *pka_ec_oid;
47    int           err;
48    char          OID[256];
49    const ltc_ecc_curve *curve;
50    ltc_asn1_list *p = NULL, *l = NULL;
51    der_flexi_check flexi_should[7];
52    ltc_asn1_list *seq, *priv_key;
53 
54    LTC_ARGCHK(in          != NULL);
55    LTC_ARGCHK(key         != NULL);
56    LTC_ARGCHK(ltc_mp.name != NULL);
57 
58    /* get EC alg oid */
59    err = pk_get_oid(LTC_OID_EC, &pka_ec_oid);
60    if (err != CRYPT_OK) return err;
61 
62    /* init key */
63    err = mp_init_multi(&a, &b, &gx, &gy, LTC_NULL);
64    if (err != CRYPT_OK) return err;
65 
66 
67    if ((err = pkcs8_decode_flexi(in, inlen, pwd, pwdlen, &l)) == CRYPT_OK) {
68 
69       /* Setup for basic structure */
70       n=0;
71       LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, NULL);
72       LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seq);
73       LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &priv_key);
74       LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
75 
76       if (((err = s_der_flexi_sequence_cmp(l, flexi_should)) == CRYPT_OK) &&
77             (pk_oid_cmp_with_asn1(pka_ec_oid, seq->child) == CRYPT_OK)) {
78          ltc_asn1_list *version, *field, *point, *point_g, *order, *p_cofactor;
79 
80          /* Setup for CASE 2 */
81          n=0;
82          LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &version);
83          LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &field);
84          LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &point);
85          LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &point_g);
86          LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &order);
87          LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &p_cofactor);
88          LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
89 
90          if (LTC_ASN1_IS_TYPE(seq->child->next, LTC_ASN1_OBJECT_IDENTIFIER)) {
91             /* CASE 1: curve by OID (AKA short variant):
92              *   0:d=0  hl=2 l= 100 cons: SEQUENCE
93              *   2:d=1  hl=2 l=   1 prim:   INTEGER        :00
94              *   5:d=1  hl=2 l=  16 cons:   SEQUENCE       (== *seq)
95              *   7:d=2  hl=2 l=   7 prim:     OBJECT       :id-ecPublicKey
96              *  16:d=2  hl=2 l=   5 prim:     OBJECT       :(== *curve_oid (e.g. secp256k1 (== 1.3.132.0.10)))
97              *  23:d=1  hl=2 l=  77 prim:   OCTET STRING   :bytes (== *priv_key)
98              */
99             ltc_asn1_list *curve_oid = seq->child->next;
100             len = sizeof(OID);
101             if ((err = pk_oid_num_to_str(curve_oid->data, curve_oid->size, OID, &len)) != CRYPT_OK) { goto LBL_DONE; }
102             if ((err = ecc_find_curve(OID, &curve)) != CRYPT_OK)                          { goto LBL_DONE; }
103             if ((err = ecc_set_curve(curve, key)) != CRYPT_OK)                            { goto LBL_DONE; }
104          }
105          else if ((err = s_der_flexi_sequence_cmp(seq->child->next, flexi_should)) == CRYPT_OK) {
106             /* CASE 2: explicit curve parameters (AKA long variant):
107              *   0:d=0  hl=3 l= 227 cons: SEQUENCE
108              *   3:d=1  hl=2 l=   1 prim:   INTEGER              :00
109              *   6:d=1  hl=3 l= 142 cons:   SEQUENCE             (== *seq)
110              *   9:d=2  hl=2 l=   7 prim:     OBJECT             :id-ecPublicKey
111              *  18:d=2  hl=3 l= 130 cons:     SEQUENCE
112              *  21:d=3  hl=2 l=   1 prim:       INTEGER          :01
113              *  24:d=3  hl=2 l=  44 cons:       SEQUENCE         (== *field)
114              *  26:d=4  hl=2 l=   7 prim:         OBJECT         :prime-field
115              *  35:d=4  hl=2 l=  33 prim:         INTEGER        :(== *prime / curve.prime)
116              *  70:d=3  hl=2 l=   6 cons:       SEQUENCE         (== *point)
117              *  72:d=4  hl=2 l=   1 prim:         OCTET STRING   :bytes (== curve.A)
118              *  75:d=4  hl=2 l=   1 prim:         OCTET STRING   :bytes (== curve.B)
119              *  78:d=3  hl=2 l=  33 prim:       OCTET STRING     :bytes (== *g_point / curve.G-point)
120              * 113:d=3  hl=2 l=  33 prim:       INTEGER          :(== *order / curve.order)
121              * 148:d=3  hl=2 l=   1 prim:       INTEGER          :(== curve.cofactor)
122              * 151:d=1  hl=2 l=  77 prim:   OCTET STRING         :bytes (== *priv_key)
123              */
124 
125             if (mp_get_int(version->data) != 1) {
126                goto LBL_DONE;
127             }
128             cofactor = mp_get_int(p_cofactor->data);
129 
130             if (LTC_ASN1_IS_TYPE(field->child, LTC_ASN1_OBJECT_IDENTIFIER) &&
131                 LTC_ASN1_IS_TYPE(field->child->next, LTC_ASN1_INTEGER) &&
132                 LTC_ASN1_IS_TYPE(point->child, LTC_ASN1_OCTET_STRING) &&
133                 LTC_ASN1_IS_TYPE(point->child->next, LTC_ASN1_OCTET_STRING)) {
134 
135                ltc_asn1_list *prime = field->child->next;
136                if ((err = mp_read_unsigned_bin(a, point->child->data, point->child->size)) != CRYPT_OK) {
137                   goto LBL_DONE;
138                }
139                if ((err = mp_read_unsigned_bin(b, point->child->next->data, point->child->next->size)) != CRYPT_OK) {
140                   goto LBL_DONE;
141                }
142                if ((err = ltc_ecc_import_point(point_g->data, point_g->size, prime->data, a, b, gx, gy)) != CRYPT_OK) {
143                   goto LBL_DONE;
144                }
145                if ((err = ecc_set_curve_from_mpis(a, b, prime->data, order->data, gx, gy, cofactor, key)) != CRYPT_OK) {
146                   goto LBL_DONE;
147                }
148             }
149          }
150          else {
151             err = CRYPT_INVALID_PACKET;
152             goto LBL_DONE;
153          }
154 
155          /* load private key value 'k' */
156          len = priv_key->size;
157          if ((err = der_decode_sequence_flexi(priv_key->data, &len, &p)) == CRYPT_OK) {
158             if (p->type == LTC_ASN1_SEQUENCE &&
159                 LTC_ASN1_IS_TYPE(p->child, LTC_ASN1_INTEGER) &&
160                 LTC_ASN1_IS_TYPE(p->child->next, LTC_ASN1_OCTET_STRING)) {
161                ltc_asn1_list *lk = p->child->next;
162                if (mp_cmp_d(p->child->data, 1) != LTC_MP_EQ) {
163                   err = CRYPT_INVALID_PACKET;
164                   goto LBL_ECCFREE;
165                }
166                if ((err = ecc_set_key(lk->data, lk->size, PK_PRIVATE, key)) != CRYPT_OK) {
167                   goto LBL_ECCFREE;
168                }
169                goto LBL_DONE; /* success */
170             }
171          }
172       }
173    }
174    err = CRYPT_INVALID_PACKET;
175    goto LBL_DONE;
176 
177 LBL_ECCFREE:
178    ecc_free(key);
179 LBL_DONE:
180    mp_clear_multi(a, b, gx, gy, LTC_NULL);
181    if (l) der_free_sequence_flexi(l);
182    if (p) der_free_sequence_flexi(p);
183    return err;
184 }
185 
186 #endif
187