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