Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport DH_check from OpenSSL 1.1.0. #3375

Merged
merged 5 commits into from
Feb 3, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion src/_cffi_src/openssl/dh.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
DH *DH_new(void);
void DH_free(DH *);
int DH_size(const DH *);
int DH_check(const DH *, int *);
int DH_check_pub_key(const DH *, const BIGNUM *, int *);
int DH_generate_key(DH *);
int DH_compute_key(unsigned char *, const BIGNUM *, DH *);
Expand All @@ -34,6 +33,8 @@
int DH_set0_pqg(DH *, BIGNUM *, BIGNUM *, BIGNUM *);
void DH_get0_key(const DH *, const BIGNUM **, const BIGNUM **);
int DH_set0_key(DH *, BIGNUM *, BIGNUM *);

int Cryptography_DH_check(const DH *, int *);
"""

MACROS = """
Expand Down Expand Up @@ -114,4 +115,106 @@
return 1;
}
#endif

#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 || defined(LIBRESSL_VERSION_NUMBER)
# define DH_CHECK_Q_NOT_PRIME 0x10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should each be ifndef for safety since we don't want to fail with duplicate definitions if/when LibreSSL adds these.

# define DH_CHECK_INVALID_Q_VALUE 0x20
# define DH_CHECK_INVALID_J_VALUE 0x40

/*-
* Check that p is a safe prime and
* if g is 2, 3 or 5, check that it is a suitable generator
* where
* for 2, p mod 24 == 11
* for 3, p mod 12 == 5
* for 5, p mod 10 == 3 or 7
* should hold.
*/

int Cryptography_DH_check(const DH *dh, int *ret)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For review purposes, is this from 1.1.0d? Could you add a comment stating what version it came from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub says 1.1.0pre6 - not sure which letter release that is. How can I find out?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.1.0pre6 is itself a release number (it was the last pre-release prior to 1.1.0). So just add a comment saying it was updated to its current form in 1.1.0pre6

{
int ok = 0, r;
BN_CTX *ctx = NULL;
BN_ULONG l;
BIGNUM *t1 = NULL, *t2 = NULL;

*ret = 0;
ctx = BN_CTX_new();
if (ctx == NULL)
goto err;
BN_CTX_start(ctx);
t1 = BN_CTX_get(ctx);
if (t1 == NULL)
goto err;
t2 = BN_CTX_get(ctx);
if (t2 == NULL)
goto err;

if (dh->q) {
if (BN_cmp(dh->g, BN_value_one()) <= 0)
*ret |= DH_NOT_SUITABLE_GENERATOR;
else if (BN_cmp(dh->g, dh->p) >= 0)
*ret |= DH_NOT_SUITABLE_GENERATOR;
else {
/* Check g^q == 1 mod p */
if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx))
goto err;
if (!BN_is_one(t1))
*ret |= DH_NOT_SUITABLE_GENERATOR;
}
r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL);
if (r < 0)
goto err;
if (!r)
*ret |= DH_CHECK_Q_NOT_PRIME;
/* Check p == 1 mod q i.e. q divides p - 1 */
if (!BN_div(t1, t2, dh->p, dh->q, ctx))
goto err;
if (!BN_is_one(t2))
*ret |= DH_CHECK_INVALID_Q_VALUE;
if (dh->j && BN_cmp(dh->j, t1))
*ret |= DH_CHECK_INVALID_J_VALUE;

} else if (BN_is_word(dh->g, DH_GENERATOR_2)) {
l = BN_mod_word(dh->p, 24);
if (l == (BN_ULONG)-1)
goto err;
if (l != 11)
*ret |= DH_NOT_SUITABLE_GENERATOR;
} else if (BN_is_word(dh->g, DH_GENERATOR_5)) {
l = BN_mod_word(dh->p, 10);
if (l == (BN_ULONG)-1)
goto err;
if ((l != 3) && (l != 7))
*ret |= DH_NOT_SUITABLE_GENERATOR;
} else
*ret |= DH_UNABLE_TO_CHECK_GENERATOR;

r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL);
if (r < 0)
goto err;
if (!r)
*ret |= DH_CHECK_P_NOT_PRIME;
else if (!dh->q) {
if (!BN_rshift1(t1, dh->p))
goto err;
r = BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL);
if (r < 0)
goto err;
if (!r)
*ret |= DH_CHECK_P_NOT_SAFE_PRIME;
}
ok = 1;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
return (ok);
}
#else
int Cryptography_DH_check(const DH *dh, int *ret) {
return DH_check(dh, ret);
}
#endif
"""
4 changes: 2 additions & 2 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,7 @@ def load_dh_private_numbers(self, numbers):
self.openssl_assert(res == 1)

codes = self._ffi.new("int[]", 1)
res = self._lib.DH_check(dh_cdata, codes)
res = self._lib.Cryptography_DH_check(dh_cdata, codes)
self.openssl_assert(res == 1)

if codes[0] != 0:
Expand Down Expand Up @@ -1815,7 +1815,7 @@ def dh_parameters_supported(self, p, g):
self.openssl_assert(res == 1)

codes = self._ffi.new("int[]", 1)
res = self._lib.DH_check(dh_cdata, codes)
res = self._lib.Cryptography_DH_check(dh_cdata, codes)
self.openssl_assert(res == 1)

return codes[0] == 0
Expand Down