1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * DH low level APIs are deprecated for public use, but still ok for
12e1051a39Sopenharmony_ci * internal use.
13e1051a39Sopenharmony_ci */
14e1051a39Sopenharmony_ci#include "internal/deprecated.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci#include <stdio.h>
17e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
18e1051a39Sopenharmony_ci#include <openssl/bn.h>
19e1051a39Sopenharmony_ci#include "dh_local.h"
20e1051a39Sopenharmony_ci#include "crypto/dh.h"
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ci/*-
23e1051a39Sopenharmony_ci * Check that p and g are suitable enough
24e1051a39Sopenharmony_ci *
25e1051a39Sopenharmony_ci * p is odd
26e1051a39Sopenharmony_ci * 1 < g < p - 1
27e1051a39Sopenharmony_ci */
28e1051a39Sopenharmony_ciint DH_check_params_ex(const DH *dh)
29e1051a39Sopenharmony_ci{
30e1051a39Sopenharmony_ci    int errflags = 0;
31e1051a39Sopenharmony_ci
32e1051a39Sopenharmony_ci    if (!DH_check_params(dh, &errflags))
33e1051a39Sopenharmony_ci        return 0;
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_P_NOT_PRIME) != 0)
36e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME);
37e1051a39Sopenharmony_ci    if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0)
38e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR);
39e1051a39Sopenharmony_ci    if ((errflags & DH_MODULUS_TOO_SMALL) != 0)
40e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
41e1051a39Sopenharmony_ci    if ((errflags & DH_MODULUS_TOO_LARGE) != 0)
42e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
43e1051a39Sopenharmony_ci
44e1051a39Sopenharmony_ci    return errflags == 0;
45e1051a39Sopenharmony_ci}
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_ci#ifdef FIPS_MODULE
48e1051a39Sopenharmony_ciint DH_check_params(const DH *dh, int *ret)
49e1051a39Sopenharmony_ci{
50e1051a39Sopenharmony_ci    int nid;
51e1051a39Sopenharmony_ci
52e1051a39Sopenharmony_ci    *ret = 0;
53e1051a39Sopenharmony_ci    /*
54e1051a39Sopenharmony_ci     * SP800-56A R3 Section 5.5.2 Assurances of Domain Parameter Validity
55e1051a39Sopenharmony_ci     * (1a) The domain parameters correspond to any approved safe prime group.
56e1051a39Sopenharmony_ci     */
57e1051a39Sopenharmony_ci    nid = DH_get_nid((DH *)dh);
58e1051a39Sopenharmony_ci    if (nid != NID_undef)
59e1051a39Sopenharmony_ci        return 1;
60e1051a39Sopenharmony_ci    /*
61e1051a39Sopenharmony_ci     * OR
62e1051a39Sopenharmony_ci     * (2b) FFC domain params conform to FIPS-186-4 explicit domain param
63e1051a39Sopenharmony_ci     * validity tests.
64e1051a39Sopenharmony_ci     */
65e1051a39Sopenharmony_ci    return ossl_ffc_params_FIPS186_4_validate(dh->libctx, &dh->params,
66e1051a39Sopenharmony_ci                                              FFC_PARAM_TYPE_DH, ret, NULL);
67e1051a39Sopenharmony_ci}
68e1051a39Sopenharmony_ci#else
69e1051a39Sopenharmony_ciint DH_check_params(const DH *dh, int *ret)
70e1051a39Sopenharmony_ci{
71e1051a39Sopenharmony_ci    int ok = 0;
72e1051a39Sopenharmony_ci    BIGNUM *tmp = NULL;
73e1051a39Sopenharmony_ci    BN_CTX *ctx = NULL;
74e1051a39Sopenharmony_ci
75e1051a39Sopenharmony_ci    *ret = 0;
76e1051a39Sopenharmony_ci    ctx = BN_CTX_new_ex(dh->libctx);
77e1051a39Sopenharmony_ci    if (ctx == NULL)
78e1051a39Sopenharmony_ci        goto err;
79e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
80e1051a39Sopenharmony_ci    tmp = BN_CTX_get(ctx);
81e1051a39Sopenharmony_ci    if (tmp == NULL)
82e1051a39Sopenharmony_ci        goto err;
83e1051a39Sopenharmony_ci
84e1051a39Sopenharmony_ci    if (!BN_is_odd(dh->params.p))
85e1051a39Sopenharmony_ci        *ret |= DH_CHECK_P_NOT_PRIME;
86e1051a39Sopenharmony_ci    if (BN_is_negative(dh->params.g)
87e1051a39Sopenharmony_ci        || BN_is_zero(dh->params.g)
88e1051a39Sopenharmony_ci        || BN_is_one(dh->params.g))
89e1051a39Sopenharmony_ci        *ret |= DH_NOT_SUITABLE_GENERATOR;
90e1051a39Sopenharmony_ci    if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1))
91e1051a39Sopenharmony_ci        goto err;
92e1051a39Sopenharmony_ci    if (BN_cmp(dh->params.g, tmp) >= 0)
93e1051a39Sopenharmony_ci        *ret |= DH_NOT_SUITABLE_GENERATOR;
94e1051a39Sopenharmony_ci    if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS)
95e1051a39Sopenharmony_ci        *ret |= DH_MODULUS_TOO_SMALL;
96e1051a39Sopenharmony_ci    if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS)
97e1051a39Sopenharmony_ci        *ret |= DH_MODULUS_TOO_LARGE;
98e1051a39Sopenharmony_ci
99e1051a39Sopenharmony_ci    ok = 1;
100e1051a39Sopenharmony_ci err:
101e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
102e1051a39Sopenharmony_ci    BN_CTX_free(ctx);
103e1051a39Sopenharmony_ci    return ok;
104e1051a39Sopenharmony_ci}
105e1051a39Sopenharmony_ci#endif /* FIPS_MODULE */
106e1051a39Sopenharmony_ci
107e1051a39Sopenharmony_ci/*-
108e1051a39Sopenharmony_ci * Check that p is a safe prime and
109e1051a39Sopenharmony_ci * g is a suitable generator.
110e1051a39Sopenharmony_ci */
111e1051a39Sopenharmony_ciint DH_check_ex(const DH *dh)
112e1051a39Sopenharmony_ci{
113e1051a39Sopenharmony_ci    int errflags = 0;
114e1051a39Sopenharmony_ci
115e1051a39Sopenharmony_ci    if (!DH_check(dh, &errflags))
116e1051a39Sopenharmony_ci        return 0;
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ci    if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0)
119e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR);
120e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_Q_NOT_PRIME) != 0)
121e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_Q_NOT_PRIME);
122e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_INVALID_Q_VALUE) != 0)
123e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_Q_VALUE);
124e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_INVALID_J_VALUE) != 0)
125e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_J_VALUE);
126e1051a39Sopenharmony_ci    if ((errflags & DH_UNABLE_TO_CHECK_GENERATOR) != 0)
127e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_UNABLE_TO_CHECK_GENERATOR);
128e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_P_NOT_PRIME) != 0)
129e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME);
130e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_P_NOT_SAFE_PRIME) != 0)
131e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_SAFE_PRIME);
132e1051a39Sopenharmony_ci    if ((errflags & DH_MODULUS_TOO_SMALL) != 0)
133e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
134e1051a39Sopenharmony_ci    if ((errflags & DH_MODULUS_TOO_LARGE) != 0)
135e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
136e1051a39Sopenharmony_ci
137e1051a39Sopenharmony_ci    return errflags == 0;
138e1051a39Sopenharmony_ci}
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci/* Note: according to documentation - this only checks the params */
141e1051a39Sopenharmony_ciint DH_check(const DH *dh, int *ret)
142e1051a39Sopenharmony_ci{
143e1051a39Sopenharmony_ci#ifdef FIPS_MODULE
144e1051a39Sopenharmony_ci    return DH_check_params(dh, ret);
145e1051a39Sopenharmony_ci#else
146e1051a39Sopenharmony_ci    int ok = 0, r, q_good = 0;
147e1051a39Sopenharmony_ci    BN_CTX *ctx = NULL;
148e1051a39Sopenharmony_ci    BIGNUM *t1 = NULL, *t2 = NULL;
149e1051a39Sopenharmony_ci    int nid = DH_get_nid((DH *)dh);
150e1051a39Sopenharmony_ci
151e1051a39Sopenharmony_ci    *ret = 0;
152e1051a39Sopenharmony_ci    if (nid != NID_undef)
153e1051a39Sopenharmony_ci        return 1;
154e1051a39Sopenharmony_ci
155e1051a39Sopenharmony_ci    /* Don't do any checks at all with an excessively large modulus */
156e1051a39Sopenharmony_ci    if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) {
157e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
158e1051a39Sopenharmony_ci        return 0;
159e1051a39Sopenharmony_ci    }
160e1051a39Sopenharmony_ci
161e1051a39Sopenharmony_ci    if (!DH_check_params(dh, ret))
162e1051a39Sopenharmony_ci        return 0;
163e1051a39Sopenharmony_ci
164e1051a39Sopenharmony_ci    ctx = BN_CTX_new_ex(dh->libctx);
165e1051a39Sopenharmony_ci    if (ctx == NULL)
166e1051a39Sopenharmony_ci        goto err;
167e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
168e1051a39Sopenharmony_ci    t1 = BN_CTX_get(ctx);
169e1051a39Sopenharmony_ci    t2 = BN_CTX_get(ctx);
170e1051a39Sopenharmony_ci    if (t2 == NULL)
171e1051a39Sopenharmony_ci        goto err;
172e1051a39Sopenharmony_ci
173e1051a39Sopenharmony_ci    if (dh->params.q != NULL) {
174e1051a39Sopenharmony_ci        if (BN_ucmp(dh->params.p, dh->params.q) > 0)
175e1051a39Sopenharmony_ci            q_good = 1;
176e1051a39Sopenharmony_ci        else
177e1051a39Sopenharmony_ci            *ret |= DH_CHECK_INVALID_Q_VALUE;
178e1051a39Sopenharmony_ci    }
179e1051a39Sopenharmony_ci
180e1051a39Sopenharmony_ci    if (q_good) {
181e1051a39Sopenharmony_ci        if (BN_cmp(dh->params.g, BN_value_one()) <= 0)
182e1051a39Sopenharmony_ci            *ret |= DH_NOT_SUITABLE_GENERATOR;
183e1051a39Sopenharmony_ci        else if (BN_cmp(dh->params.g, dh->params.p) >= 0)
184e1051a39Sopenharmony_ci            *ret |= DH_NOT_SUITABLE_GENERATOR;
185e1051a39Sopenharmony_ci        else {
186e1051a39Sopenharmony_ci            /* Check g^q == 1 mod p */
187e1051a39Sopenharmony_ci            if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx))
188e1051a39Sopenharmony_ci                goto err;
189e1051a39Sopenharmony_ci            if (!BN_is_one(t1))
190e1051a39Sopenharmony_ci                *ret |= DH_NOT_SUITABLE_GENERATOR;
191e1051a39Sopenharmony_ci        }
192e1051a39Sopenharmony_ci        r = BN_check_prime(dh->params.q, ctx, NULL);
193e1051a39Sopenharmony_ci        if (r < 0)
194e1051a39Sopenharmony_ci            goto err;
195e1051a39Sopenharmony_ci        if (!r)
196e1051a39Sopenharmony_ci            *ret |= DH_CHECK_Q_NOT_PRIME;
197e1051a39Sopenharmony_ci        /* Check p == 1 mod q  i.e. q divides p - 1 */
198e1051a39Sopenharmony_ci        if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx))
199e1051a39Sopenharmony_ci            goto err;
200e1051a39Sopenharmony_ci        if (!BN_is_one(t2))
201e1051a39Sopenharmony_ci            *ret |= DH_CHECK_INVALID_Q_VALUE;
202e1051a39Sopenharmony_ci        if (dh->params.j != NULL
203e1051a39Sopenharmony_ci            && BN_cmp(dh->params.j, t1))
204e1051a39Sopenharmony_ci            *ret |= DH_CHECK_INVALID_J_VALUE;
205e1051a39Sopenharmony_ci    }
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    r = BN_check_prime(dh->params.p, ctx, NULL);
208e1051a39Sopenharmony_ci    if (r < 0)
209e1051a39Sopenharmony_ci        goto err;
210e1051a39Sopenharmony_ci    if (!r)
211e1051a39Sopenharmony_ci        *ret |= DH_CHECK_P_NOT_PRIME;
212e1051a39Sopenharmony_ci    else if (dh->params.q == NULL) {
213e1051a39Sopenharmony_ci        if (!BN_rshift1(t1, dh->params.p))
214e1051a39Sopenharmony_ci            goto err;
215e1051a39Sopenharmony_ci        r = BN_check_prime(t1, ctx, NULL);
216e1051a39Sopenharmony_ci        if (r < 0)
217e1051a39Sopenharmony_ci            goto err;
218e1051a39Sopenharmony_ci        if (!r)
219e1051a39Sopenharmony_ci            *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
220e1051a39Sopenharmony_ci    }
221e1051a39Sopenharmony_ci    ok = 1;
222e1051a39Sopenharmony_ci err:
223e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
224e1051a39Sopenharmony_ci    BN_CTX_free(ctx);
225e1051a39Sopenharmony_ci    return ok;
226e1051a39Sopenharmony_ci#endif /* FIPS_MODULE */
227e1051a39Sopenharmony_ci}
228e1051a39Sopenharmony_ci
229e1051a39Sopenharmony_ciint DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key)
230e1051a39Sopenharmony_ci{
231e1051a39Sopenharmony_ci    int errflags = 0;
232e1051a39Sopenharmony_ci
233e1051a39Sopenharmony_ci    if (!DH_check_pub_key(dh, pub_key, &errflags))
234e1051a39Sopenharmony_ci        return 0;
235e1051a39Sopenharmony_ci
236e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_PUBKEY_TOO_SMALL) != 0)
237e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_SMALL);
238e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_PUBKEY_TOO_LARGE) != 0)
239e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_LARGE);
240e1051a39Sopenharmony_ci    if ((errflags & DH_CHECK_PUBKEY_INVALID) != 0)
241e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID);
242e1051a39Sopenharmony_ci
243e1051a39Sopenharmony_ci    return errflags == 0;
244e1051a39Sopenharmony_ci}
245e1051a39Sopenharmony_ci
246e1051a39Sopenharmony_ci/*
247e1051a39Sopenharmony_ci * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation.
248e1051a39Sopenharmony_ci */
249e1051a39Sopenharmony_ciint DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret)
250e1051a39Sopenharmony_ci{
251e1051a39Sopenharmony_ci    /* Don't do any checks at all with an excessively large modulus */
252e1051a39Sopenharmony_ci    if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) {
253e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
254e1051a39Sopenharmony_ci        *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_PUBKEY_INVALID;
255e1051a39Sopenharmony_ci        return 0;
256e1051a39Sopenharmony_ci    }
257e1051a39Sopenharmony_ci
258e1051a39Sopenharmony_ci    if (dh->params.q != NULL && BN_ucmp(dh->params.p, dh->params.q) < 0) {
259e1051a39Sopenharmony_ci        *ret |= DH_CHECK_INVALID_Q_VALUE | DH_CHECK_PUBKEY_INVALID;
260e1051a39Sopenharmony_ci        return 1;
261e1051a39Sopenharmony_ci    }
262e1051a39Sopenharmony_ci
263e1051a39Sopenharmony_ci    return ossl_ffc_validate_public_key(&dh->params, pub_key, ret);
264e1051a39Sopenharmony_ci}
265e1051a39Sopenharmony_ci
266e1051a39Sopenharmony_ci/*
267e1051a39Sopenharmony_ci * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation.
268e1051a39Sopenharmony_ci * To only be used with ephemeral FFC public keys generated using the approved
269e1051a39Sopenharmony_ci * safe-prime groups.
270e1051a39Sopenharmony_ci */
271e1051a39Sopenharmony_ciint ossl_dh_check_pub_key_partial(const DH *dh, const BIGNUM *pub_key, int *ret)
272e1051a39Sopenharmony_ci{
273e1051a39Sopenharmony_ci    return ossl_ffc_validate_public_key_partial(&dh->params, pub_key, ret);
274e1051a39Sopenharmony_ci}
275e1051a39Sopenharmony_ci
276e1051a39Sopenharmony_ciint ossl_dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret)
277e1051a39Sopenharmony_ci{
278e1051a39Sopenharmony_ci    int ok = 0;
279e1051a39Sopenharmony_ci    BIGNUM *two_powN = NULL, *upper;
280e1051a39Sopenharmony_ci
281e1051a39Sopenharmony_ci    *ret = 0;
282e1051a39Sopenharmony_ci    two_powN = BN_new();
283e1051a39Sopenharmony_ci    if (two_powN == NULL)
284e1051a39Sopenharmony_ci        return 0;
285e1051a39Sopenharmony_ci
286e1051a39Sopenharmony_ci    if (dh->params.q != NULL) {
287e1051a39Sopenharmony_ci        upper = dh->params.q;
288e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
289e1051a39Sopenharmony_ci    } else if (dh->params.p != NULL) {
290e1051a39Sopenharmony_ci        /*
291e1051a39Sopenharmony_ci         * We do not have q so we just check the key is within some
292e1051a39Sopenharmony_ci         * reasonable range, or the number of bits is equal to dh->length.
293e1051a39Sopenharmony_ci         */
294e1051a39Sopenharmony_ci        int length = dh->length;
295e1051a39Sopenharmony_ci
296e1051a39Sopenharmony_ci        if (length == 0) {
297e1051a39Sopenharmony_ci            length = BN_num_bits(dh->params.p) - 1;
298e1051a39Sopenharmony_ci            if (BN_num_bits(priv_key) <= length
299e1051a39Sopenharmony_ci                && BN_num_bits(priv_key) > 1)
300e1051a39Sopenharmony_ci                ok = 1;
301e1051a39Sopenharmony_ci        } else if (BN_num_bits(priv_key) == length) {
302e1051a39Sopenharmony_ci            ok = 1;
303e1051a39Sopenharmony_ci        }
304e1051a39Sopenharmony_ci        goto end;
305e1051a39Sopenharmony_ci#endif
306e1051a39Sopenharmony_ci    } else {
307e1051a39Sopenharmony_ci        goto end;
308e1051a39Sopenharmony_ci    }
309e1051a39Sopenharmony_ci
310e1051a39Sopenharmony_ci    /* Is it from an approved Safe prime group ?*/
311e1051a39Sopenharmony_ci    if (DH_get_nid((DH *)dh) != NID_undef && dh->length != 0) {
312e1051a39Sopenharmony_ci        if (!BN_lshift(two_powN, BN_value_one(), dh->length))
313e1051a39Sopenharmony_ci            goto end;
314e1051a39Sopenharmony_ci        if (BN_cmp(two_powN, dh->params.q) < 0)
315e1051a39Sopenharmony_ci            upper = two_powN;
316e1051a39Sopenharmony_ci    }
317e1051a39Sopenharmony_ci    if (!ossl_ffc_validate_private_key(upper, priv_key, ret))
318e1051a39Sopenharmony_ci        goto end;
319e1051a39Sopenharmony_ci
320e1051a39Sopenharmony_ci    ok = 1;
321e1051a39Sopenharmony_ciend:
322e1051a39Sopenharmony_ci    BN_free(two_powN);
323e1051a39Sopenharmony_ci    return ok;
324e1051a39Sopenharmony_ci}
325e1051a39Sopenharmony_ci
326e1051a39Sopenharmony_ci/*
327e1051a39Sopenharmony_ci * FFC pairwise check from SP800-56A R3.
328e1051a39Sopenharmony_ci *    Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency
329e1051a39Sopenharmony_ci */
330e1051a39Sopenharmony_ciint ossl_dh_check_pairwise(const DH *dh)
331e1051a39Sopenharmony_ci{
332e1051a39Sopenharmony_ci    int ret = 0;
333e1051a39Sopenharmony_ci    BN_CTX *ctx = NULL;
334e1051a39Sopenharmony_ci    BIGNUM *pub_key = NULL;
335e1051a39Sopenharmony_ci
336e1051a39Sopenharmony_ci    if (dh->params.p == NULL
337e1051a39Sopenharmony_ci        || dh->params.g == NULL
338e1051a39Sopenharmony_ci        || dh->priv_key == NULL
339e1051a39Sopenharmony_ci        || dh->pub_key == NULL)
340e1051a39Sopenharmony_ci        return 0;
341e1051a39Sopenharmony_ci
342e1051a39Sopenharmony_ci    ctx = BN_CTX_new_ex(dh->libctx);
343e1051a39Sopenharmony_ci    if (ctx == NULL)
344e1051a39Sopenharmony_ci        goto err;
345e1051a39Sopenharmony_ci    pub_key = BN_new();
346e1051a39Sopenharmony_ci    if (pub_key == NULL)
347e1051a39Sopenharmony_ci        goto err;
348e1051a39Sopenharmony_ci
349e1051a39Sopenharmony_ci    /* recalculate the public key = (g ^ priv) mod p */
350e1051a39Sopenharmony_ci    if (!ossl_dh_generate_public_key(ctx, dh, dh->priv_key, pub_key))
351e1051a39Sopenharmony_ci        goto err;
352e1051a39Sopenharmony_ci    /* check it matches the existing pubic_key */
353e1051a39Sopenharmony_ci    ret = BN_cmp(pub_key, dh->pub_key) == 0;
354e1051a39Sopenharmony_cierr:
355e1051a39Sopenharmony_ci    BN_free(pub_key);
356e1051a39Sopenharmony_ci    BN_CTX_free(ctx);
357e1051a39Sopenharmony_ci    return ret;
358e1051a39Sopenharmony_ci}
359