2016-05-17 19:38:09 +00:00
|
|
|
/*
|
2018-05-29 12:07:08 +00:00
|
|
|
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
|
1998-12-21 10:52:47 +00:00
|
|
|
*
|
2016-05-17 19:38:09 +00:00
|
|
|
* Licensed under the OpenSSL license (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
|
1998-12-21 10:52:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2015-05-14 14:56:48 +00:00
|
|
|
#include "internal/cryptlib.h"
|
2017-08-21 21:17:35 +00:00
|
|
|
#include "internal/refcount.h"
|
1999-04-23 22:13:45 +00:00
|
|
|
#include <openssl/bn.h>
|
2016-04-06 16:49:48 +00:00
|
|
|
#include "dh_locl.h"
|
2016-03-18 18:30:20 +00:00
|
|
|
#include <openssl/engine.h>
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2001-09-25 20:23:40 +00:00
|
|
|
int DH_set_method(DH *dh, const DH_METHOD *meth)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* NB: The caller is specifically setting a method, so it's not up to us
|
|
|
|
* to deal with which ENGINE it comes from.
|
|
|
|
*/
|
|
|
|
const DH_METHOD *mtmp;
|
|
|
|
mtmp = dh->meth;
|
|
|
|
if (mtmp->finish)
|
|
|
|
mtmp->finish(dh);
|
2003-01-30 17:39:26 +00:00
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
2016-02-25 17:09:06 +00:00
|
|
|
ENGINE_finish(dh->engine);
|
|
|
|
dh->engine = NULL;
|
2003-01-30 17:39:26 +00:00
|
|
|
#endif
|
2015-01-22 03:40:55 +00:00
|
|
|
dh->meth = meth;
|
|
|
|
if (meth->init)
|
|
|
|
meth->init(dh);
|
|
|
|
return 1;
|
|
|
|
}
|
1999-08-23 23:11:32 +00:00
|
|
|
|
1999-04-19 21:31:43 +00:00
|
|
|
DH *DH_new(void)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
return DH_new_method(NULL);
|
|
|
|
}
|
1999-08-23 23:11:32 +00:00
|
|
|
|
2000-10-26 21:07:28 +00:00
|
|
|
DH *DH_new_method(ENGINE *engine)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2015-09-03 13:15:26 +00:00
|
|
|
DH *ret = OPENSSL_zalloc(sizeof(*ret));
|
1999-08-23 23:11:32 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (ret == NULL) {
|
|
|
|
DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE);
|
2016-03-04 15:43:46 +00:00
|
|
|
return NULL;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2001-06-23 23:07:34 +00:00
|
|
|
|
2016-03-08 19:11:48 +00:00
|
|
|
ret->references = 1;
|
|
|
|
ret->lock = CRYPTO_THREAD_lock_new();
|
|
|
|
if (ret->lock == NULL) {
|
2016-04-30 14:23:33 +00:00
|
|
|
DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE);
|
2016-03-08 19:11:48 +00:00
|
|
|
OPENSSL_free(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
ret->meth = DH_get_default_method();
|
2003-01-30 17:39:26 +00:00
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
2016-03-08 19:11:48 +00:00
|
|
|
ret->flags = ret->meth->flags; /* early default init */
|
2015-01-22 03:40:55 +00:00
|
|
|
if (engine) {
|
|
|
|
if (!ENGINE_init(engine)) {
|
|
|
|
DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB);
|
2016-03-08 19:11:48 +00:00
|
|
|
goto err;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
ret->engine = engine;
|
|
|
|
} else
|
|
|
|
ret->engine = ENGINE_get_default_DH();
|
|
|
|
if (ret->engine) {
|
|
|
|
ret->meth = ENGINE_get_DH(ret->engine);
|
2016-02-25 17:09:06 +00:00
|
|
|
if (ret->meth == NULL) {
|
2015-01-22 03:40:55 +00:00
|
|
|
DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB);
|
2016-03-08 19:11:48 +00:00
|
|
|
goto err;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
2003-01-30 17:39:26 +00:00
|
|
|
#endif
|
2001-09-25 20:23:40 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
ret->flags = ret->meth->flags;
|
2016-03-04 15:43:46 +00:00
|
|
|
|
2016-03-08 19:11:48 +00:00
|
|
|
if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DH, ret, &ret->ex_data))
|
|
|
|
goto err;
|
2016-03-04 15:43:46 +00:00
|
|
|
|
|
|
|
if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
|
2016-03-08 19:11:48 +00:00
|
|
|
DHerr(DH_F_DH_NEW_METHOD, ERR_R_INIT_FAIL);
|
2018-09-05 09:08:12 +00:00
|
|
|
goto err;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2016-03-04 15:43:46 +00:00
|
|
|
|
|
|
|
return ret;
|
2018-09-05 09:08:12 +00:00
|
|
|
|
|
|
|
err:
|
|
|
|
DH_free(ret);
|
|
|
|
return NULL;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
1998-12-21 10:52:47 +00:00
|
|
|
|
1999-04-19 21:31:43 +00:00
|
|
|
void DH_free(DH *r)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
2015-03-24 14:17:37 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (r == NULL)
|
|
|
|
return;
|
2016-03-04 15:43:46 +00:00
|
|
|
|
2016-08-27 14:01:08 +00:00
|
|
|
CRYPTO_DOWN_REF(&r->references, &i, r->lock);
|
2016-01-30 17:04:25 +00:00
|
|
|
REF_PRINT_COUNT("DH", r);
|
2015-01-22 03:40:55 +00:00
|
|
|
if (i > 0)
|
|
|
|
return;
|
2016-01-30 17:04:25 +00:00
|
|
|
REF_ASSERT_ISNT(i < 0);
|
1999-08-23 23:11:32 +00:00
|
|
|
|
2018-09-05 08:58:55 +00:00
|
|
|
if (r->meth != NULL && r->meth->finish != NULL)
|
2015-01-22 03:40:55 +00:00
|
|
|
r->meth->finish(r);
|
2003-01-30 17:39:26 +00:00
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
2016-02-25 17:09:06 +00:00
|
|
|
ENGINE_finish(r->engine);
|
2003-01-30 17:39:26 +00:00
|
|
|
#endif
|
1999-09-01 23:50:43 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, r, &r->ex_data);
|
2000-11-29 19:59:45 +00:00
|
|
|
|
2016-03-04 15:43:46 +00:00
|
|
|
CRYPTO_THREAD_lock_free(r->lock);
|
|
|
|
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_clear_free(r->p);
|
|
|
|
BN_clear_free(r->g);
|
|
|
|
BN_clear_free(r->q);
|
|
|
|
BN_clear_free(r->j);
|
2015-05-01 14:02:07 +00:00
|
|
|
OPENSSL_free(r->seed);
|
2015-05-01 01:37:06 +00:00
|
|
|
BN_clear_free(r->counter);
|
|
|
|
BN_clear_free(r->pub_key);
|
|
|
|
BN_clear_free(r->priv_key);
|
2015-01-22 03:40:55 +00:00
|
|
|
OPENSSL_free(r);
|
|
|
|
}
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2001-09-05 16:54:32 +00:00
|
|
|
int DH_up_ref(DH *r)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2016-03-04 15:43:46 +00:00
|
|
|
int i;
|
|
|
|
|
2016-08-27 14:01:08 +00:00
|
|
|
if (CRYPTO_UP_REF(&r->references, &i, r->lock) <= 0)
|
2016-03-04 15:43:46 +00:00
|
|
|
return 0;
|
2016-01-30 17:04:25 +00:00
|
|
|
|
|
|
|
REF_PRINT_COUNT("DH", r);
|
|
|
|
REF_ASSERT_ISNT(i < 2);
|
2015-01-22 03:40:55 +00:00
|
|
|
return ((i > 1) ? 1 : 0);
|
|
|
|
}
|
2001-08-25 17:24:21 +00:00
|
|
|
|
2000-01-23 23:41:49 +00:00
|
|
|
int DH_set_ex_data(DH *d, int idx, void *arg)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2017-10-17 14:04:09 +00:00
|
|
|
return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
1999-08-23 23:11:32 +00:00
|
|
|
|
2000-01-23 23:41:49 +00:00
|
|
|
void *DH_get_ex_data(DH *d, int idx)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2017-10-17 14:04:09 +00:00
|
|
|
return CRYPTO_get_ex_data(&d->ex_data, idx);
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
1999-08-23 23:11:32 +00:00
|
|
|
|
2015-04-18 10:23:12 +00:00
|
|
|
int DH_bits(const DH *dh)
|
|
|
|
{
|
|
|
|
return BN_num_bits(dh->p);
|
|
|
|
}
|
|
|
|
|
2000-11-07 14:30:37 +00:00
|
|
|
int DH_size(const DH *dh)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2017-10-17 14:04:09 +00:00
|
|
|
return BN_num_bytes(dh->p);
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2014-01-18 14:51:40 +00:00
|
|
|
|
|
|
|
int DH_security_bits(const DH *dh)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
int N;
|
|
|
|
if (dh->q)
|
|
|
|
N = BN_num_bits(dh->q);
|
|
|
|
else if (dh->length)
|
|
|
|
N = dh->length;
|
|
|
|
else
|
|
|
|
N = -1;
|
|
|
|
return BN_security_bits(BN_num_bits(dh->p), N);
|
|
|
|
}
|
2016-04-06 16:49:48 +00:00
|
|
|
|
|
|
|
|
2016-06-14 13:48:16 +00:00
|
|
|
void DH_get0_pqg(const DH *dh,
|
|
|
|
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
|
2016-04-06 16:49:48 +00:00
|
|
|
{
|
|
|
|
if (p != NULL)
|
|
|
|
*p = dh->p;
|
|
|
|
if (q != NULL)
|
|
|
|
*q = dh->q;
|
|
|
|
if (g != NULL)
|
|
|
|
*g = dh->g;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
|
|
{
|
RSA, DSA, DH: Allow some given input to be NULL on already initialised keys
The diverse {RSA,DSA,DH}_set0_* functions are made to allow some
parameters to be NULL IF the corresponding numbers in the given key
structure have already been previously initialised. Specifically,
this allows the addition of private components to be added to a key
that already has the public half, approximately like this:
RSA_get0_key(rsa, NULL, &e, NULL);
RSA_get0_factors(rsa, &p, &q);
/* calculate new d */
RSA_set0_key(rsa, NULL, NULL, d);
Reviewed-by: Matt Caswell <matt@openssl.org>
2016-04-25 18:28:54 +00:00
|
|
|
/* If the fields p and g in d are NULL, the corresponding input
|
|
|
|
* parameters MUST be non-NULL. q may remain NULL.
|
|
|
|
*/
|
2016-06-16 09:07:32 +00:00
|
|
|
if ((dh->p == NULL && p == NULL)
|
|
|
|
|| (dh->g == NULL && g == NULL))
|
2016-04-06 16:49:48 +00:00
|
|
|
return 0;
|
RSA, DSA, DH: Allow some given input to be NULL on already initialised keys
The diverse {RSA,DSA,DH}_set0_* functions are made to allow some
parameters to be NULL IF the corresponding numbers in the given key
structure have already been previously initialised. Specifically,
this allows the addition of private components to be added to a key
that already has the public half, approximately like this:
RSA_get0_key(rsa, NULL, &e, NULL);
RSA_get0_factors(rsa, &p, &q);
/* calculate new d */
RSA_set0_key(rsa, NULL, NULL, d);
Reviewed-by: Matt Caswell <matt@openssl.org>
2016-04-25 18:28:54 +00:00
|
|
|
|
|
|
|
if (p != NULL) {
|
|
|
|
BN_free(dh->p);
|
|
|
|
dh->p = p;
|
|
|
|
}
|
|
|
|
if (q != NULL) {
|
|
|
|
BN_free(dh->q);
|
|
|
|
dh->q = q;
|
|
|
|
}
|
|
|
|
if (g != NULL) {
|
|
|
|
BN_free(dh->g);
|
|
|
|
dh->g = g;
|
|
|
|
}
|
2016-04-06 16:49:48 +00:00
|
|
|
|
|
|
|
if (q != NULL) {
|
|
|
|
dh->length = BN_num_bits(q);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
long DH_get_length(const DH *dh)
|
|
|
|
{
|
|
|
|
return dh->length;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DH_set_length(DH *dh, long length)
|
|
|
|
{
|
|
|
|
dh->length = length;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-06-14 13:48:16 +00:00
|
|
|
void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
|
2016-04-06 16:49:48 +00:00
|
|
|
{
|
|
|
|
if (pub_key != NULL)
|
|
|
|
*pub_key = dh->pub_key;
|
|
|
|
if (priv_key != NULL)
|
|
|
|
*priv_key = dh->priv_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
|
|
|
|
{
|
RSA, DSA, DH: Allow some given input to be NULL on already initialised keys
The diverse {RSA,DSA,DH}_set0_* functions are made to allow some
parameters to be NULL IF the corresponding numbers in the given key
structure have already been previously initialised. Specifically,
this allows the addition of private components to be added to a key
that already has the public half, approximately like this:
RSA_get0_key(rsa, NULL, &e, NULL);
RSA_get0_factors(rsa, &p, &q);
/* calculate new d */
RSA_set0_key(rsa, NULL, NULL, d);
Reviewed-by: Matt Caswell <matt@openssl.org>
2016-04-25 18:28:54 +00:00
|
|
|
if (pub_key != NULL) {
|
2019-09-06 22:53:24 +00:00
|
|
|
BN_clear_free(dh->pub_key);
|
RSA, DSA, DH: Allow some given input to be NULL on already initialised keys
The diverse {RSA,DSA,DH}_set0_* functions are made to allow some
parameters to be NULL IF the corresponding numbers in the given key
structure have already been previously initialised. Specifically,
this allows the addition of private components to be added to a key
that already has the public half, approximately like this:
RSA_get0_key(rsa, NULL, &e, NULL);
RSA_get0_factors(rsa, &p, &q);
/* calculate new d */
RSA_set0_key(rsa, NULL, NULL, d);
Reviewed-by: Matt Caswell <matt@openssl.org>
2016-04-25 18:28:54 +00:00
|
|
|
dh->pub_key = pub_key;
|
|
|
|
}
|
|
|
|
if (priv_key != NULL) {
|
2019-09-06 22:53:24 +00:00
|
|
|
BN_clear_free(dh->priv_key);
|
RSA, DSA, DH: Allow some given input to be NULL on already initialised keys
The diverse {RSA,DSA,DH}_set0_* functions are made to allow some
parameters to be NULL IF the corresponding numbers in the given key
structure have already been previously initialised. Specifically,
this allows the addition of private components to be added to a key
that already has the public half, approximately like this:
RSA_get0_key(rsa, NULL, &e, NULL);
RSA_get0_factors(rsa, &p, &q);
/* calculate new d */
RSA_set0_key(rsa, NULL, NULL, d);
Reviewed-by: Matt Caswell <matt@openssl.org>
2016-04-25 18:28:54 +00:00
|
|
|
dh->priv_key = priv_key;
|
|
|
|
}
|
2016-04-06 16:49:48 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-05-16 14:18:13 +00:00
|
|
|
const BIGNUM *DH_get0_p(const DH *dh)
|
|
|
|
{
|
|
|
|
return dh->p;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DH_get0_q(const DH *dh)
|
|
|
|
{
|
|
|
|
return dh->q;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DH_get0_g(const DH *dh)
|
|
|
|
{
|
|
|
|
return dh->g;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DH_get0_priv_key(const DH *dh)
|
|
|
|
{
|
|
|
|
return dh->priv_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DH_get0_pub_key(const DH *dh)
|
|
|
|
{
|
|
|
|
return dh->pub_key;
|
|
|
|
}
|
|
|
|
|
2016-04-06 16:49:48 +00:00
|
|
|
void DH_clear_flags(DH *dh, int flags)
|
|
|
|
{
|
|
|
|
dh->flags &= ~flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DH_test_flags(const DH *dh, int flags)
|
|
|
|
{
|
|
|
|
return dh->flags & flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DH_set_flags(DH *dh, int flags)
|
|
|
|
{
|
|
|
|
dh->flags |= flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
ENGINE *DH_get0_engine(DH *dh)
|
|
|
|
{
|
|
|
|
return dh->engine;
|
|
|
|
}
|