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