1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 #include "tomcrypt_private.h"
11 
12 /**
13   @file rsa_import_pkcs8.c
14   Import a PKCS RSA key
15 */
16 
17 #ifdef LTC_MRSA
18 
19 /* Public-Key Cryptography Standards (PKCS) #8:
20  * Private-Key Information Syntax Specification Version 1.2
21  * https://tools.ietf.org/html/rfc5208
22  *
23  * PrivateKeyInfo ::= SEQUENCE {
24  *      version                   Version,
25  *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
26  *      privateKey                PrivateKey,
27  *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
28  * where:
29  * - Version ::= INTEGER
30  * - PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
31  * - PrivateKey ::= OCTET STRING
32  * - Attributes ::= SET OF Attribute
33  *
34  * EncryptedPrivateKeyInfo ::= SEQUENCE {
35  *        encryptionAlgorithm  EncryptionAlgorithmIdentifier,
36  *        encryptedData        EncryptedData }
37  * where:
38  * - EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
39  * - EncryptedData ::= OCTET STRING
40  */
41 
42 /**
43   Import an RSAPrivateKey in PKCS#8 format
44   @param in        The packet to import from
45   @param inlen     It's length (octets)
46   @param passwd    The password for decrypting privkey
47   @param passwdlen Password's length (octets)
48   @param key       [out] Destination for newly imported key
49   @return CRYPT_OK if successful, upon error allocated memory is freed
50 */
rsa_import_pkcs8(const unsigned char * in,unsigned long inlen,const void * passwd,unsigned long passwdlen,rsa_key * key)51 int rsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
52                      const void *passwd, unsigned long passwdlen,
53                      rsa_key *key)
54 {
55    int           err;
56    void          *zero, *iter;
57    unsigned char *buf1 = NULL, *buf2 = NULL;
58    unsigned long buf1len, buf2len;
59    unsigned long oid[16];
60    const char    *rsaoid;
61    ltc_asn1_list alg_seq[2], top_seq[3];
62    ltc_asn1_list *l = NULL;
63    unsigned char *decrypted = NULL;
64    unsigned long decryptedlen;
65 
66    LTC_ARGCHK(in          != NULL);
67    LTC_ARGCHK(key         != NULL);
68    LTC_ARGCHK(ltc_mp.name != NULL);
69 
70    /* get RSA alg oid */
71    err = pk_get_oid(PKA_RSA, &rsaoid);
72    if (err != CRYPT_OK) { goto LBL_NOFREE; }
73 
74    /* alloc buffers */
75    buf1len = inlen; /* approx. */
76    buf1 = XMALLOC(buf1len);
77    if (buf1 == NULL) { err = CRYPT_MEM; goto LBL_NOFREE; }
78    buf2len = inlen; /* approx. */
79    buf2 = XMALLOC(buf2len);
80    if (buf2 == NULL) { err = CRYPT_MEM; goto LBL_FREE1; }
81 
82    /* init key */
83    err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, &zero, &iter, NULL);
84    if (err != CRYPT_OK) { goto LBL_FREE2; }
85 
86    /* try to decode encrypted priv key */
87    if ((err = pkcs8_decode_flexi(in, inlen, passwd, passwdlen, &l)) != CRYPT_OK) {
88       goto LBL_ERR;
89    }
90    decrypted    = l->data;
91    decryptedlen = l->size;
92 
93    /* try to decode unencrypted priv key */
94    LTC_SET_ASN1(alg_seq, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, 16UL);
95    LTC_SET_ASN1(alg_seq, 1, LTC_ASN1_NULL, NULL, 0UL);
96    LTC_SET_ASN1(top_seq, 0, LTC_ASN1_INTEGER, zero, 1UL);
97    LTC_SET_ASN1(top_seq, 1, LTC_ASN1_SEQUENCE, alg_seq, 2UL);
98    LTC_SET_ASN1(top_seq, 2, LTC_ASN1_OCTET_STRING, buf1, buf1len);
99    err=der_decode_sequence(decrypted, decryptedlen, top_seq, 3UL);
100    if (err != CRYPT_OK) { goto LBL_ERR; }
101 
102    /* check alg oid */
103    if ((err = pk_oid_cmp_with_asn1(rsaoid, &alg_seq[0])) != CRYPT_OK) {
104       goto LBL_ERR;
105    }
106 
107    err = der_decode_sequence_multi(buf1, top_seq[2].size,
108                                    LTC_ASN1_INTEGER, 1UL, zero,
109                                    LTC_ASN1_INTEGER, 1UL, key->N,
110                                    LTC_ASN1_INTEGER, 1UL, key->e,
111                                    LTC_ASN1_INTEGER, 1UL, key->d,
112                                    LTC_ASN1_INTEGER, 1UL, key->p,
113                                    LTC_ASN1_INTEGER, 1UL, key->q,
114                                    LTC_ASN1_INTEGER, 1UL, key->dP,
115                                    LTC_ASN1_INTEGER, 1UL, key->dQ,
116                                    LTC_ASN1_INTEGER, 1UL, key->qP,
117                                    LTC_ASN1_EOL,     0UL, NULL);
118    if (err != CRYPT_OK) { goto LBL_ERR; }
119    key->type = PK_PRIVATE;
120    err = CRYPT_OK;
121    goto LBL_FREE2;
122 
123 LBL_ERR:
124    rsa_free(key);
125 LBL_FREE2:
126    if (l) der_free_sequence_flexi(l);
127    mp_clear_multi(iter, zero, NULL);
128    XFREE(buf2);
129 LBL_FREE1:
130    XFREE(buf1);
131 LBL_NOFREE:
132    return err;
133 }
134 
135 #endif /* LTC_MRSA */
136 
137 /* ref:         $Format:%D$ */
138 /* git commit:  $Format:%H$ */
139 /* commit time: $Format:%ai$ */
140