1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6   @file ec25519_import_pkcs8.c
7   Generic import of a Curve/Ed25519 private key in PKCS#8 format, Steffen Jaeckel
8 */
9 
10 #ifdef LTC_CURVE25519
11 
12 /**
13   Generic import of a Curve/Ed25519 private key in PKCS#8 format
14   @param in        The DER-encoded PKCS#8-formatted private key
15   @param inlen     The length of the input data
16   @param passwd    The password to decrypt the private key
17   @param passwdlen Password's length (octets)
18   @param key       [out] Where to import the key to
19   @return CRYPT_OK if successful, on error all allocated memory is freed automatically
20 */
ec25519_import_pkcs8(const unsigned char * in,unsigned long inlen,const void * pwd,unsigned long pwdlen,enum ltc_oid_id id,sk_to_pk fp,curve25519_key * key)21 int ec25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
22                        const void *pwd, unsigned long pwdlen,
23                        enum ltc_oid_id id, sk_to_pk fp,
24                        curve25519_key *key)
25 {
26    int err;
27    ltc_asn1_list *l = NULL;
28    const char *oid;
29    ltc_asn1_list alg_id[1];
30    unsigned char private_key[34];
31    unsigned long version, key_len;
32    unsigned long tmpoid[16];
33 
34    LTC_ARGCHK(in  != NULL);
35    LTC_ARGCHK(key != NULL);
36    LTC_ARGCHK(fp != NULL);
37 
38    if ((err = pkcs8_decode_flexi(in, inlen, pwd, pwdlen, &l)) == CRYPT_OK) {
39 
40       LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid) / sizeof(tmpoid[0]));
41 
42       key_len = sizeof(private_key);
43       if ((err = der_decode_sequence_multi(l->data, l->size,
44                                            LTC_ASN1_SHORT_INTEGER,      1uL, &version,
45                                            LTC_ASN1_SEQUENCE,           1uL, alg_id,
46                                            LTC_ASN1_OCTET_STRING,   key_len, private_key,
47                                            LTC_ASN1_EOL,                0uL, NULL))
48           != CRYPT_OK) {
49          /* If there are attributes added after the private_key it is tagged with version 1 and
50           * we get an 'input too long' error but the rest is already decoded and can be
51           * handled the same as for version 0
52           */
53          if ((err == CRYPT_INPUT_TOO_LONG) && (version == 1)) {
54             version = 0;
55          } else {
56             goto out;
57          }
58       }
59 
60       if ((err = pk_get_oid(id, &oid)) != CRYPT_OK) {
61          goto out;
62       }
63       if ((err = pk_oid_cmp_with_asn1(oid, &alg_id[0])) != CRYPT_OK) {
64          goto out;
65       }
66 
67       if (version == 0) {
68          key_len = sizeof(key->priv);
69          if ((err = der_decode_octet_string(private_key, sizeof(private_key), key->priv, &key_len)) == CRYPT_OK) {
70             fp(key->pub, key->priv);
71             key->type = PK_PRIVATE;
72             key->algo = id;
73          }
74       } else {
75          err = CRYPT_PK_INVALID_TYPE;
76       }
77    }
78 out:
79    if (l) der_free_sequence_flexi(l);
80 #ifdef LTC_CLEAN_STACK
81    zeromem(private_key, sizeof(private_key));
82 #endif
83 
84    return err;
85 }
86 
87 #endif
88