1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
7INCLUDES = """
8#include <openssl/dh.h>
9"""
10
11TYPES = """
12typedef ... DH;
13
14const long DH_NOT_SUITABLE_GENERATOR;
15"""
16
17FUNCTIONS = """
18DH *DH_new(void);
19void DH_free(DH *);
20int DH_size(const DH *);
21int DH_check_pub_key(const DH *, const BIGNUM *, int *);
22int DH_generate_key(DH *);
23int DH_compute_key(unsigned char *, const BIGNUM *, DH *);
24int DH_set_ex_data(DH *, int, void *);
25void *DH_get_ex_data(DH *, int);
26DH *d2i_DHparams(DH **, const unsigned char **, long);
27int i2d_DHparams(const DH *, unsigned char **);
28int DHparams_print_fp(FILE *, const DH *);
29int DHparams_print(BIO *, const DH *);
30DH *DHparams_dup(DH *);
31
32/* added in 1.1.0 when the DH struct was opaqued */
33void DH_get0_pqg(const DH *, const BIGNUM **, const BIGNUM **,
34                 const BIGNUM **);
35int DH_set0_pqg(DH *, BIGNUM *, BIGNUM *, BIGNUM *);
36void DH_get0_key(const DH *, const BIGNUM **, const BIGNUM **);
37int DH_set0_key(DH *, BIGNUM *, BIGNUM *);
38
39int Cryptography_DH_check(const DH *, int *);
40int DH_generate_parameters_ex(DH *, int, int, BN_GENCB *);
41DH *d2i_DHparams_bio(BIO *, DH **);
42int i2d_DHparams_bio(BIO *, DH *);
43DH *Cryptography_d2i_DHxparams_bio(BIO *bp, DH **x);
44int Cryptography_i2d_DHxparams_bio(BIO *bp, DH *x);
45"""
46
47CUSTOMIZATIONS = """
48/* These functions were added in OpenSSL 1.1.0 */
49#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER
50void DH_get0_pqg(const DH *dh,
51                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
52{
53    if (p != NULL)
54        *p = dh->p;
55    if (q != NULL)
56        *q = dh->q;
57    if (g != NULL)
58        *g = dh->g;
59}
60
61int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
62{
63    /* If the fields p and g in d are NULL, the corresponding input
64     * parameters MUST be non-NULL.  q may remain NULL.
65     */
66    if ((dh->p == NULL && p == NULL)
67        || (dh->g == NULL && g == NULL))
68        return 0;
69
70    if (p != NULL) {
71        BN_free(dh->p);
72        dh->p = p;
73    }
74    if (q != NULL) {
75        BN_free(dh->q);
76        dh->q = q;
77    }
78    if (g != NULL) {
79        BN_free(dh->g);
80        dh->g = g;
81    }
82
83    if (q != NULL) {
84        dh->length = BN_num_bits(q);
85    }
86
87    return 1;
88}
89
90void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
91{
92    if (pub_key != NULL)
93        *pub_key = dh->pub_key;
94    if (priv_key != NULL)
95        *priv_key = dh->priv_key;
96}
97
98int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
99{
100    /* If the field pub_key in dh is NULL, the corresponding input
101     * parameters MUST be non-NULL.  The priv_key field may
102     * be left NULL.
103     */
104    if (dh->pub_key == NULL && pub_key == NULL)
105        return 0;
106
107    if (pub_key != NULL) {
108        BN_free(dh->pub_key);
109        dh->pub_key = pub_key;
110    }
111    if (priv_key != NULL) {
112        BN_free(dh->priv_key);
113        dh->priv_key = priv_key;
114    }
115
116    return 1;
117}
118#endif
119
120#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
121#ifndef DH_CHECK_Q_NOT_PRIME
122#define DH_CHECK_Q_NOT_PRIME            0x10
123#endif
124
125#ifndef DH_CHECK_INVALID_Q_VALUE
126#define DH_CHECK_INVALID_Q_VALUE        0x20
127#endif
128
129#ifndef DH_CHECK_INVALID_J_VALUE
130#define DH_CHECK_INVALID_J_VALUE        0x40
131#endif
132
133/* DH_check implementation taken from OpenSSL 1.1.0pre6 */
134
135/*-
136 * Check that p is a safe prime and
137 * if g is 2, 3 or 5, check that it is a suitable generator
138 * where
139 * for 2, p mod 24 == 11
140 * for 3, p mod 12 == 5
141 * for 5, p mod 10 == 3 or 7
142 * should hold.
143 */
144
145int Cryptography_DH_check(const DH *dh, int *ret)
146{
147    int ok = 0, r;
148    BN_CTX *ctx = NULL;
149    BN_ULONG l;
150    BIGNUM *t1 = NULL, *t2 = NULL;
151
152    *ret = 0;
153    ctx = BN_CTX_new();
154    if (ctx == NULL)
155        goto err;
156    BN_CTX_start(ctx);
157    t1 = BN_CTX_get(ctx);
158    if (t1 == NULL)
159        goto err;
160    t2 = BN_CTX_get(ctx);
161    if (t2 == NULL)
162        goto err;
163
164    if (dh->q) {
165        if (BN_cmp(dh->g, BN_value_one()) <= 0)
166            *ret |= DH_NOT_SUITABLE_GENERATOR;
167        else if (BN_cmp(dh->g, dh->p) >= 0)
168            *ret |= DH_NOT_SUITABLE_GENERATOR;
169        else {
170            /* Check g^q == 1 mod p */
171            if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx))
172                goto err;
173            if (!BN_is_one(t1))
174                *ret |= DH_NOT_SUITABLE_GENERATOR;
175        }
176        r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL);
177        if (r < 0)
178            goto err;
179        if (!r)
180            *ret |= DH_CHECK_Q_NOT_PRIME;
181        /* Check p == 1 mod q  i.e. q divides p - 1 */
182        if (!BN_div(t1, t2, dh->p, dh->q, ctx))
183            goto err;
184        if (!BN_is_one(t2))
185            *ret |= DH_CHECK_INVALID_Q_VALUE;
186        if (dh->j && BN_cmp(dh->j, t1))
187            *ret |= DH_CHECK_INVALID_J_VALUE;
188
189    } else if (BN_is_word(dh->g, DH_GENERATOR_2)) {
190        l = BN_mod_word(dh->p, 24);
191        if (l == (BN_ULONG)-1)
192            goto err;
193        if (l != 11)
194            *ret |= DH_NOT_SUITABLE_GENERATOR;
195    } else if (BN_is_word(dh->g, DH_GENERATOR_5)) {
196        l = BN_mod_word(dh->p, 10);
197        if (l == (BN_ULONG)-1)
198            goto err;
199        if ((l != 3) && (l != 7))
200            *ret |= DH_NOT_SUITABLE_GENERATOR;
201    } else
202        *ret |= DH_UNABLE_TO_CHECK_GENERATOR;
203
204    r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL);
205    if (r < 0)
206        goto err;
207    if (!r)
208        *ret |= DH_CHECK_P_NOT_PRIME;
209    else if (!dh->q) {
210        if (!BN_rshift1(t1, dh->p))
211            goto err;
212        r = BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL);
213        if (r < 0)
214            goto err;
215        if (!r)
216            *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
217    }
218    ok = 1;
219 err:
220    if (ctx != NULL) {
221        BN_CTX_end(ctx);
222        BN_CTX_free(ctx);
223    }
224    return (ok);
225}
226#else
227int Cryptography_DH_check(const DH *dh, int *ret) {
228    return DH_check(dh, ret);
229}
230#endif
231
232/* These functions were added in OpenSSL 1.1.0f commit d0c50e80a8 */
233/* Define our own to simplify support across all versions. */
234#if defined(EVP_PKEY_DHX) && EVP_PKEY_DHX != -1
235DH *Cryptography_d2i_DHxparams_bio(BIO *bp, DH **x) {
236    return ASN1_d2i_bio_of(DH, DH_new, d2i_DHxparams, bp, x);
237}
238int Cryptography_i2d_DHxparams_bio(BIO *bp, DH *x) {
239    return ASN1_i2d_bio_of_const(DH, i2d_DHxparams, bp, x);
240}
241#else
242DH *(*Cryptography_d2i_DHxparams_bio)(BIO *bp, DH **x) = NULL;
243int (*Cryptography_i2d_DHxparams_bio)(BIO *bp, DH *x) = NULL;
244#endif
245"""
246