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_verify_key.c
14    DSA implementation, verify a key, Tom St Denis
15 */
16 
17 #ifdef LTC_MDSA
18 
19 /**
20    Validate a DSA key
21 
22      Yeah, this function should've been called dsa_validate_key()
23      in the first place and for compat-reasons we keep it
24      as it was (for now).
25 
26    @param key   The key to validate
27    @param stat  [out]  Result of test, 1==valid, 0==invalid
28    @return CRYPT_OK if successful
29 */
dsa_verify_key(const dsa_key * key,int * stat)30 int dsa_verify_key(const dsa_key *key, int *stat)
31 {
32    int err;
33 
34    err = dsa_int_validate_primes(key, stat);
35    if (err != CRYPT_OK || *stat == 0) return err;
36 
37    err = dsa_int_validate_pqg(key, stat);
38    if (err != CRYPT_OK || *stat == 0) return err;
39 
40    return dsa_int_validate_xy(key, stat);
41 }
42 
43 /**
44    Non-complex part (no primality testing) of the validation
45    of DSA params (p, q, g)
46 
47    @param key   The key to validate
48    @param stat  [out]  Result of test, 1==valid, 0==invalid
49    @return CRYPT_OK if successful
50 */
dsa_int_validate_pqg(const dsa_key * key,int * stat)51 int dsa_int_validate_pqg(const dsa_key *key, int *stat)
52 {
53    void *tmp1, *tmp2;
54    int  err;
55 
56    LTC_ARGCHK(key  != NULL);
57    LTC_ARGCHK(stat != NULL);
58    *stat = 0;
59 
60    /* check q-order */
61    if ( key->qord >= LTC_MDSA_MAX_GROUP || key->qord <= 15 ||
62         (unsigned long)key->qord >= mp_unsigned_bin_size(key->p) ||
63         (mp_unsigned_bin_size(key->p) - key->qord) >= LTC_MDSA_DELTA ) {
64       return CRYPT_OK;
65    }
66 
67    /* FIPS 186-4 chapter 4.1: 1 < g < p */
68    if (mp_cmp_d(key->g, 1) != LTC_MP_GT || mp_cmp(key->g, key->p) != LTC_MP_LT) {
69       return CRYPT_OK;
70    }
71 
72    if ((err = mp_init_multi(&tmp1, &tmp2, NULL)) != CRYPT_OK)        { return err; }
73 
74    /* FIPS 186-4 chapter 4.1: q is a divisor of (p - 1) */
75    if ((err = mp_sub_d(key->p, 1, tmp1)) != CRYPT_OK)                { goto error; }
76    if ((err = mp_div(tmp1, key->q, tmp1, tmp2)) != CRYPT_OK)         { goto error; }
77    if (mp_iszero(tmp2) != LTC_MP_YES) {
78       err = CRYPT_OK;
79       goto error;
80    }
81 
82    /* FIPS 186-4 chapter 4.1: g is a generator of a subgroup of order q in
83     * the multiplicative group of GF(p) - so we make sure that g^q mod p = 1
84     */
85    if ((err = mp_exptmod(key->g, key->q, key->p, tmp1)) != CRYPT_OK) { goto error; }
86    if (mp_cmp_d(tmp1, 1) != LTC_MP_EQ) {
87       err = CRYPT_OK;
88       goto error;
89    }
90 
91    err   = CRYPT_OK;
92    *stat = 1;
93 error:
94    mp_clear_multi(tmp2, tmp1, NULL);
95    return err;
96 }
97 
98 /**
99    Primality testing of DSA params p and q
100 
101    @param key   The key to validate
102    @param stat  [out]  Result of test, 1==valid, 0==invalid
103    @return CRYPT_OK if successful
104 */
dsa_int_validate_primes(const dsa_key * key,int * stat)105 int dsa_int_validate_primes(const dsa_key *key, int *stat)
106 {
107    int err, res;
108 
109    *stat = 0;
110    LTC_ARGCHK(key  != NULL);
111    LTC_ARGCHK(stat != NULL);
112 
113    /* key->q prime? */
114    if ((err = mp_prime_is_prime(key->q, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) {
115       return err;
116    }
117    if (res == LTC_MP_NO) {
118       return CRYPT_OK;
119    }
120 
121    /* key->p prime? */
122    if ((err = mp_prime_is_prime(key->p, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) {
123       return err;
124    }
125    if (res == LTC_MP_NO) {
126       return CRYPT_OK;
127    }
128 
129    *stat = 1;
130    return CRYPT_OK;
131 }
132 
133 /**
134    Validation of a DSA key (x and y values)
135 
136    @param key   The key to validate
137    @param stat  [out]  Result of test, 1==valid, 0==invalid
138    @return CRYPT_OK if successful
139 */
dsa_int_validate_xy(const dsa_key * key,int * stat)140 int dsa_int_validate_xy(const dsa_key *key, int *stat)
141 {
142    void *tmp;
143    int  err;
144 
145    *stat = 0;
146    LTC_ARGCHK(key  != NULL);
147    LTC_ARGCHK(stat != NULL);
148 
149    /* 1 < y < p-1 */
150    if ((err = mp_init(&tmp)) != CRYPT_OK) {
151       return err;
152    }
153    if ((err = mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) {
154       goto error;
155    }
156    if (mp_cmp_d(key->y, 1) != LTC_MP_GT || mp_cmp(key->y, tmp) != LTC_MP_LT) {
157       err = CRYPT_OK;
158       goto error;
159    }
160 
161    if (key->type == PK_PRIVATE) {
162       /* FIPS 186-4 chapter 4.1: 0 < x < q */
163       if (mp_cmp_d(key->x, 0) != LTC_MP_GT || mp_cmp(key->x, key->q) != LTC_MP_LT) {
164          err = CRYPT_OK;
165          goto error;
166       }
167       /* FIPS 186-4 chapter 4.1: y = g^x mod p */
168       if ((err = mp_exptmod(key->g, key->x, key->p, tmp)) != CRYPT_OK) {
169          goto error;
170       }
171       if (mp_cmp(tmp, key->y) != LTC_MP_EQ) {
172          err = CRYPT_OK;
173          goto error;
174       }
175    }
176    else {
177       /* with just a public key we cannot test y = g^x mod p therefore we
178        * only test that y^q mod p = 1, which makes sure y is in g^x mod p
179        */
180       if ((err = mp_exptmod(key->y, key->q, key->p, tmp)) != CRYPT_OK) {
181          goto error;
182       }
183       if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) {
184          err = CRYPT_OK;
185          goto error;
186       }
187    }
188 
189    err   = CRYPT_OK;
190    *stat = 1;
191 error:
192    mp_clear(tmp);
193    return err;
194 }
195 
196 #endif
197 
198 /* ref:         $Format:%D$ */
199 /* git commit:  $Format:%H$ */
200 /* commit time: $Format:%ai$ */
201