2016-05-17 19:38:09 +00:00
|
|
|
/*
|
|
|
|
* Copyright 1995-2016 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"
|
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-07-27 12:35:27 +00:00
|
|
|
static const DH_METHOD *default_DH_method = NULL;
|
1999-08-23 23:11:32 +00:00
|
|
|
|
2001-09-25 20:23:40 +00:00
|
|
|
void DH_set_default_method(const DH_METHOD *meth)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
default_DH_method = meth;
|
|
|
|
}
|
1999-08-23 23:11:32 +00:00
|
|
|
|
2001-09-25 20:23:40 +00:00
|
|
|
const DH_METHOD *DH_get_default_method(void)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
if (!default_DH_method)
|
|
|
|
default_DH_method = DH_OpenSSL();
|
|
|
|
return default_DH_method;
|
|
|
|
}
|
1999-08-23 23:11:32 +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);
|
|
|
|
err:
|
2016-03-04 15:43:46 +00:00
|
|
|
DH_free(ret);
|
2015-01-22 03:40:55 +00:00
|
|
|
ret = NULL;
|
|
|
|
}
|
2016-03-04 15:43:46 +00:00
|
|
|
|
|
|
|
return ret;
|
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
|
|
|
|
|
|
|
CRYPTO_atomic_add(&r->references, -1, &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
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (r->meth->finish)
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (CRYPTO_atomic_add(&r->references, 1, &i, r->lock) <= 0)
|
|
|
|
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
|
|
|
{
|
|
|
|
return (CRYPTO_set_ex_data(&d->ex_data, idx, arg));
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
return (CRYPTO_get_ex_data(&d->ex_data, idx));
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
return (BN_num_bytes(dh->p));
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
|
|
|
void DH_get0_pqg(const DH *dh, BIGNUM **p, BIGNUM **q, BIGNUM **g)
|
|
|
|
{
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
* It is an error to give the results from get0 on d
|
|
|
|
* as input parameters.
|
|
|
|
*/
|
|
|
|
if (p == dh->p || (dh->q != NULL && q == dh->q) || g == dh->g)
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DH_get0_key(const DH *dh, BIGNUM **pub_key, BIGNUM **priv_key)
|
|
|
|
{
|
|
|
|
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 the pub_key in dh is NULL, the corresponding input
|
|
|
|
* parameters MUST be non-NULL. The priv_key field may
|
|
|
|
* be left NULL.
|
|
|
|
*
|
|
|
|
* It is an error to give the results from get0 on dh
|
|
|
|
* as input parameters.
|
|
|
|
*/
|
|
|
|
if (dh->pub_key == pub_key
|
2016-04-27 19:08:33 +00:00
|
|
|
|| (dh->priv_key != NULL && priv_key == dh->priv_key))
|
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 (pub_key != NULL) {
|
|
|
|
BN_free(dh->pub_key);
|
|
|
|
dh->pub_key = pub_key;
|
|
|
|
}
|
|
|
|
if (priv_key != NULL) {
|
|
|
|
BN_free(dh->priv_key);
|
|
|
|
dh->priv_key = priv_key;
|
|
|
|
}
|
2016-04-06 16:49:48 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|