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 dsa_import.c
14    DSA implementation, import a DSA key, Tom St Denis
15 */
16 
17 #ifdef LTC_MDSA
18 
19 /**
20    Import a DSA key
21    @param in       The binary packet to import from
22    @param inlen    The length of the binary packet
23    @param key      [out] Where to store the imported key
24    @return CRYPT_OK if successful, upon error this function will free all allocated memory
25 */
dsa_import(const unsigned char * in,unsigned long inlen,dsa_key * key)26 int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
27 {
28    int           err, stat;
29    unsigned long zero = 0, len;
30    unsigned char* tmpbuf = NULL;
31    unsigned char flags[1];
32 
33    LTC_ARGCHK(in  != NULL);
34    LTC_ARGCHK(key != NULL);
35    LTC_ARGCHK(ltc_mp.name != NULL);
36 
37    /* init key */
38    if (mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL) != CRYPT_OK) {
39       return CRYPT_MEM;
40    }
41 
42    /* try to match the old libtomcrypt format */
43    err = der_decode_sequence_multi(in, inlen, LTC_ASN1_BIT_STRING, 1UL, flags,
44                                               LTC_ASN1_EOL,        0UL, NULL);
45 
46    if (err == CRYPT_OK || err == CRYPT_INPUT_TOO_LONG) {
47        /* private key */
48        if (flags[0] == 1) {
49            if ((err = der_decode_sequence_multi(in, inlen,
50                                   LTC_ASN1_BIT_STRING,   1UL, flags,
51                                   LTC_ASN1_INTEGER,      1UL, key->g,
52                                   LTC_ASN1_INTEGER,      1UL, key->p,
53                                   LTC_ASN1_INTEGER,      1UL, key->q,
54                                   LTC_ASN1_INTEGER,      1UL, key->y,
55                                   LTC_ASN1_INTEGER,      1UL, key->x,
56                                   LTC_ASN1_EOL,          0UL, NULL)) != CRYPT_OK) {
57                goto LBL_ERR;
58            }
59            key->type = PK_PRIVATE;
60            goto LBL_OK;
61        }
62        /* public key */
63        else if (flags[0] == 0) {
64            if ((err = der_decode_sequence_multi(in, inlen,
65                                       LTC_ASN1_BIT_STRING,   1UL, flags,
66                                       LTC_ASN1_INTEGER,      1UL, key->g,
67                                       LTC_ASN1_INTEGER,      1UL, key->p,
68                                       LTC_ASN1_INTEGER,      1UL, key->q,
69                                       LTC_ASN1_INTEGER,      1UL, key->y,
70                                       LTC_ASN1_EOL,          0UL, NULL)) != CRYPT_OK) {
71                goto LBL_ERR;
72            }
73            key->type = PK_PUBLIC;
74            goto LBL_OK;
75        }
76        else {
77           err = CRYPT_INVALID_PACKET;
78           goto LBL_ERR;
79        }
80    }
81    /* get key type */
82    if ((err = der_decode_sequence_multi(in, inlen,
83                           LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
84                           LTC_ASN1_INTEGER,      1UL, key->p,
85                           LTC_ASN1_INTEGER,      1UL, key->q,
86                           LTC_ASN1_INTEGER,      1UL, key->g,
87                           LTC_ASN1_INTEGER,      1UL, key->y,
88                           LTC_ASN1_INTEGER,      1UL, key->x,
89                           LTC_ASN1_EOL,          0UL, NULL)) == CRYPT_OK) {
90 
91        key->type = PK_PRIVATE;
92    } else { /* public */
93       ltc_asn1_list params[3];
94       unsigned long tmpbuf_len = inlen;
95 
96       LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL);
97       LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL);
98       LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL);
99 
100       tmpbuf = XCALLOC(1, tmpbuf_len);
101       if (tmpbuf == NULL) {
102          err = CRYPT_MEM;
103          goto LBL_ERR;
104       }
105 
106       len = 3;
107       err = x509_decode_subject_public_key_info(in, inlen, PKA_DSA,
108                                                tmpbuf, &tmpbuf_len,
109                                                LTC_ASN1_SEQUENCE, params, &len);
110       if (err != CRYPT_OK) {
111          XFREE(tmpbuf);
112          goto LBL_ERR;
113       }
114 
115       if ((err=der_decode_integer(tmpbuf, tmpbuf_len, key->y)) != CRYPT_OK) {
116          XFREE(tmpbuf);
117          goto LBL_ERR;
118       }
119 
120       XFREE(tmpbuf);
121       key->type = PK_PUBLIC;
122    }
123 
124 LBL_OK:
125    key->qord = mp_unsigned_bin_size(key->q);
126 
127    /* quick p, q, g validation, without primality testing */
128    if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) {
129       goto LBL_ERR;
130    }
131    if (stat == 0) {
132       err = CRYPT_INVALID_PACKET;
133       goto LBL_ERR;
134    }
135    /* validate x, y */
136    if ((err = dsa_int_validate_xy(key, &stat)) != CRYPT_OK) {
137       goto LBL_ERR;
138    }
139    if (stat == 0) {
140       err = CRYPT_INVALID_PACKET;
141       goto LBL_ERR;
142    }
143 
144   return CRYPT_OK;
145 LBL_ERR:
146    dsa_free(key);
147    return err;
148 }
149 
150 #endif
151 
152 /* ref:         $Format:%D$ */
153 /* git commit:  $Format:%H$ */
154 /* commit time: $Format:%ai$ */
155