/*
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "internal/nelem.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/obj_mac.h>
#include "testutil.h"
#ifndef OPENSSL_NO_DH
# include <openssl/dh.h>
# include "crypto/bn_dh.h"
# include "crypto/dh.h"
static int cb(int p, int n, BN_GENCB *arg);
static int dh_test(void)
{
DH *dh = NULL;
BIGNUM *p = NULL, *q = NULL, *g = NULL;
const BIGNUM *p2, *q2, *g2;
BIGNUM *priv_key = NULL;
const BIGNUM *pub_key2, *priv_key2;
BN_GENCB *_cb = NULL;
DH *a = NULL;
DH *b = NULL;
DH *c = NULL;
const BIGNUM *ap = NULL, *ag = NULL, *apub_key = NULL;
const BIGNUM *bpub_key = NULL, *bpriv_key = NULL;
BIGNUM *bp = NULL, *bg = NULL, *cpriv_key = NULL;
unsigned char *abuf = NULL;
unsigned char *bbuf = NULL;
unsigned char *cbuf = NULL;
int i, alen, blen, clen, aout, bout, cout;
int ret = 0;
if (!TEST_ptr(dh = DH_new())
|| !TEST_ptr(p = BN_new())
|| !TEST_ptr(q = BN_new())
|| !TEST_ptr(g = BN_new())
|| !TEST_ptr(priv_key = BN_new()))
goto err1;
/*
* I) basic tests
*/
/* using a small predefined Sophie Germain DH group with generator 3 */
if (!TEST_true(BN_set_word(p, 4079L))
|| !TEST_true(BN_set_word(q, 2039L))
|| !TEST_true(BN_set_word(g, 3L))
|| !TEST_true(DH_set0_pqg(dh, p, q, g)))
goto err1;
/* check fails, because p is way too small */
if (!DH_check(dh, &i))
goto err2;
i ^= DH_MODULUS_TOO_SMALL;
if (!TEST_false(i & DH_CHECK_P_NOT_PRIME)
|| !TEST_false(i & DH_CHECK_P_NOT_SAFE_PRIME)
|| !TEST_false(i & DH_UNABLE_TO_CHECK_GENERATOR)
|| !TEST_false(i & DH_NOT_SUITABLE_GENERATOR)
|| !TEST_false(i & DH_CHECK_Q_NOT_PRIME)
|| !TEST_false(i & DH_CHECK_INVALID_Q_VALUE)
|| !TEST_false(i & DH_CHECK_INVALID_J_VALUE)
|| !TEST_false(i & DH_MODULUS_TOO_SMALL)
|| !TEST_false(i & DH_MODULUS_TOO_LARGE)
|| !TEST_false(i))
goto err2;
/* test the combined getter for p, q, and g */
DH_get0_pqg(dh, &p2, &q2, &g2);
if (!TEST_ptr_eq(p2, p)
|| !TEST_ptr_eq(q2, q)
|| !TEST_ptr_eq(g2, g))
goto err2;
/* test the simple getters for p, q, and g */
if (!TEST_ptr_eq(DH_get0_p(dh), p2)
|| !TEST_ptr_eq(DH_get0_q(dh), q2)
|| !TEST_ptr_eq(DH_get0_g(dh), g2))
goto err2;
/* set the private key only*/
if (!TEST_true(BN_set_word(priv_key, 1234L))
|| !TEST_true(DH_set0_key(dh, NULL, priv_key)))
goto err2;
/* test the combined getter for pub_key and priv_key */
DH_get0_key(dh, &pub_key2, &priv_key2);
if (!TEST_ptr_eq(pub_key2, NULL)
|| !TEST_ptr_eq(priv_key2, priv_key))
goto err3;
/* test the simple getters for pub_key and priv_key */
if (!TEST_ptr_eq(DH_get0_pub_key(dh), pub_key2)
|| !TEST_ptr_eq(DH_get0_priv_key(dh), priv_key2))
goto err3;
/* now generate a key pair (expect failure since modulus is too small) */
if (!TEST_false(DH_generate_key(dh)))
goto err3;
/* We'll have a stale error on the queue from the above test so clear it */
ERR_clear_error();
/*
* II) key generation
*/
/* generate a DH group ... */
if (!TEST_ptr(_cb = BN_GENCB_new()))
goto err3;
BN_GENCB_set(_cb, &cb, NULL);
if (!TEST_ptr(a = DH_new())
|| !TEST_true(DH_generate_parameters_ex(a, 512,
DH_GENERATOR_5, _cb)))
goto err3;
/* ... and check whether it is valid */
if (!DH_check(a, &i))
goto err3;
if (!TEST_false(i & DH_CHECK_P_NOT_PRIME)
|| !TEST_false(i & DH_CHECK_P_NOT_SAFE_PRIME)
||