2016-05-17 14:51:26 -04:00
|
|
|
/*
|
2018-05-29 13:07:08 +01:00
|
|
|
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
|
1998-12-21 10:52:47 +00:00
|
|
|
*
|
2018-12-06 13:36:26 +01:00
|
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
2016-05-17 14:51:26 -04:00
|
|
|
* 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 16:56:48 +02:00
|
|
|
#include "internal/cryptlib.h"
|
2017-08-22 07:17:35 +10:00
|
|
|
#include "internal/refcount.h"
|
1999-04-23 22:13:45 +00:00
|
|
|
#include <openssl/bn.h>
|
2019-09-28 00:45:40 +02:00
|
|
|
#include "dsa_local.h"
|
1999-04-23 22:13:45 +00:00
|
|
|
#include <openssl/asn1.h>
|
2016-03-18 14:30:20 -04:00
|
|
|
#include <openssl/engine.h>
|
|
|
|
#include <openssl/dh.h>
|
2020-01-12 11:32:12 +10:00
|
|
|
#include "crypto/dsa.h"
|
|
|
|
|
|
|
|
#ifndef FIPS_MODE
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2020-01-12 11:32:12 +10:00
|
|
|
int DSA_set_ex_data(DSA *d, int idx, void *arg)
|
|
|
|
{
|
|
|
|
return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *DSA_get_ex_data(DSA *d, int idx)
|
|
|
|
{
|
|
|
|
return CRYPTO_get_ex_data(&d->ex_data, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef OPENSSL_NO_DH
|
|
|
|
DH *DSA_dup_DH(const DSA *r)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* DSA has p, q, g, optional pub_key, optional priv_key. DH has p,
|
|
|
|
* optional length, g, optional pub_key, optional priv_key, optional q.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DH *ret = NULL;
|
|
|
|
BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL, *priv_key = NULL;
|
|
|
|
|
|
|
|
if (r == NULL)
|
|
|
|
goto err;
|
|
|
|
ret = DH_new();
|
|
|
|
if (ret == NULL)
|
|
|
|
goto err;
|
|
|
|
if (r->p != NULL || r->g != NULL || r->q != NULL) {
|
|
|
|
if (r->p == NULL || r->g == NULL || r->q == NULL) {
|
|
|
|
/* Shouldn't happen */
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
p = BN_dup(r->p);
|
|
|
|
g = BN_dup(r->g);
|
|
|
|
q = BN_dup(r->q);
|
|
|
|
if (p == NULL || g == NULL || q == NULL || !DH_set0_pqg(ret, p, q, g))
|
|
|
|
goto err;
|
|
|
|
p = g = q = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r->pub_key != NULL) {
|
|
|
|
pub_key = BN_dup(r->pub_key);
|
|
|
|
if (pub_key == NULL)
|
|
|
|
goto err;
|
|
|
|
if (r->priv_key != NULL) {
|
|
|
|
priv_key = BN_dup(r->priv_key);
|
|
|
|
if (priv_key == NULL)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (!DH_set0_key(ret, pub_key, priv_key))
|
|
|
|
goto err;
|
|
|
|
} else if (r->priv_key != NULL) {
|
|
|
|
/* Shouldn't happen */
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
err:
|
|
|
|
BN_free(p);
|
|
|
|
BN_free(g);
|
|
|
|
BN_free(q);
|
|
|
|
BN_free(pub_key);
|
|
|
|
BN_free(priv_key);
|
|
|
|
DH_free(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
const BIGNUM *DSA_get0_p(const DSA *d)
|
|
|
|
{
|
|
|
|
return d->p;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DSA_get0_q(const DSA *d)
|
|
|
|
{
|
|
|
|
return d->q;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DSA_get0_g(const DSA *d)
|
|
|
|
{
|
|
|
|
return d->g;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DSA_get0_pub_key(const DSA *d)
|
|
|
|
{
|
|
|
|
return d->pub_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BIGNUM *DSA_get0_priv_key(const DSA *d)
|
|
|
|
{
|
|
|
|
return d->priv_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DSA_clear_flags(DSA *d, int flags)
|
|
|
|
{
|
|
|
|
d->flags &= ~flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DSA_test_flags(const DSA *d, int flags)
|
|
|
|
{
|
|
|
|
return d->flags & flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DSA_set_flags(DSA *d, int flags)
|
|
|
|
{
|
|
|
|
d->flags |= flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
ENGINE *DSA_get0_engine(DSA *d)
|
|
|
|
{
|
|
|
|
return d->engine;
|
|
|
|
}
|
|
|
|
|
2001-09-25 20:23:40 +00:00
|
|
|
int DSA_set_method(DSA *dsa, const DSA_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 DSA_METHOD *mtmp;
|
|
|
|
mtmp = dsa->meth;
|
|
|
|
if (mtmp->finish)
|
|
|
|
mtmp->finish(dsa);
|
2003-01-30 17:39:26 +00:00
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
2016-02-25 12:09:06 -05:00
|
|
|
ENGINE_finish(dsa->engine);
|
|
|
|
dsa->engine = NULL;
|
2003-01-30 17:39:26 +00:00
|
|
|
#endif
|
2015-01-22 03:40:55 +00:00
|
|
|
dsa->meth = meth;
|
|
|
|
if (meth->init)
|
|
|
|
meth->init(dsa);
|
|
|
|
return 1;
|
|
|
|
}
|
2020-01-12 11:32:12 +10:00
|
|
|
#endif /* FIPS_MODE */
|
|
|
|
|
1999-08-22 17:57:38 +00:00
|
|
|
|
2016-03-30 17:18:55 +01:00
|
|
|
const DSA_METHOD *DSA_get_method(DSA *d)
|
|
|
|
{
|
|
|
|
return d->meth;
|
|
|
|
}
|
|
|
|
|
2020-01-12 11:32:12 +10:00
|
|
|
static DSA *dsa_new_method(OPENSSL_CTX *libctx, ENGINE *engine)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2016-03-08 20:11:48 +01:00
|
|
|
DSA *ret = OPENSSL_zalloc(sizeof(*ret));
|
2015-01-22 03:40:55 +00:00
|
|
|
|
|
|
|
if (ret == NULL) {
|
|
|
|
DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
|
2016-03-04 15:43:46 +00:00
|
|
|
return NULL;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2016-03-08 20:11:48 +01:00
|
|
|
|
|
|
|
ret->references = 1;
|
|
|
|
ret->lock = CRYPTO_THREAD_lock_new();
|
|
|
|
if (ret->lock == NULL) {
|
2016-04-30 16:23:33 +02:00
|
|
|
DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
|
2016-03-08 20:11:48 +01:00
|
|
|
OPENSSL_free(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
ret->meth = DSA_get_default_method();
|
2020-01-12 11:32:12 +10:00
|
|
|
#if !defined(FIPS_MODE) && !defined(OPENSSL_NO_ENGINE)
|
2016-03-08 20:11:48 +01:00
|
|
|
ret->flags = ret->meth->flags & ~DSA_FLAG_NON_FIPS_ALLOW; /* early default init */
|
2015-01-22 03:40:55 +00:00
|
|
|
if (engine) {
|
|
|
|
if (!ENGINE_init(engine)) {
|
|
|
|
DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_ENGINE_LIB);
|
2016-03-08 20:11:48 +01:00
|
|
|
goto err;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
ret->engine = engine;
|
|
|
|
} else
|
|
|
|
ret->engine = ENGINE_get_default_DSA();
|
|
|
|
if (ret->engine) {
|
|
|
|
ret->meth = ENGINE_get_DSA(ret->engine);
|
2016-02-25 12:09:06 -05:00
|
|
|
if (ret->meth == NULL) {
|
2015-01-22 03:40:55 +00:00
|
|
|
DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_ENGINE_LIB);
|
2016-03-08 20:11:48 +01:00
|
|
|
goto err;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
2003-01-30 17:39:26 +00:00
|
|
|
#endif
|
2001-06-23 23:07:34 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
ret->flags = ret->meth->flags & ~DSA_FLAG_NON_FIPS_ALLOW;
|
2016-03-04 15:43:46 +00:00
|
|
|
|
2020-01-14 02:32:42 +01:00
|
|
|
#ifndef FIPS_MODE
|
2020-01-12 11:32:12 +10:00
|
|
|
if (!crypto_new_ex_data_ex(libctx, CRYPTO_EX_INDEX_DSA, ret, &ret->ex_data))
|
2016-03-08 20:11:48 +01:00
|
|
|
goto err;
|
2020-01-14 02:32:42 +01:00
|
|
|
#endif
|
2016-03-04 15:43:46 +00:00
|
|
|
|
|
|
|
if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
|
2016-03-08 20:11:48 +01:00
|
|
|
DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_INIT_FAIL);
|
2018-09-05 12:08:12 +03:00
|
|
|
goto err;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
|
2016-03-04 15:43:46 +00:00
|
|
|
return ret;
|
2018-09-05 12:08:12 +03:00
|
|
|
|
|
|
|
err:
|
|
|
|
DSA_free(ret);
|
|
|
|
return NULL;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2020-01-12 11:32:12 +10:00
|
|
|
DSA *DSA_new_method(ENGINE *engine)
|
|
|
|
{
|
|
|
|
return dsa_new_method(NULL, engine);
|
|
|
|
}
|
|
|
|
|
2020-01-14 02:32:42 +01:00
|
|
|
DSA *DSA_new(void)
|
2020-01-12 11:32:12 +10:00
|
|
|
{
|
2020-01-14 02:32:42 +01:00
|
|
|
return DSA_new_method(NULL);
|
2020-01-12 11:32:12 +10:00
|
|
|
}
|
|
|
|
|
1999-04-19 21:31:43 +00:00
|
|
|
void DSA_free(DSA *r)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (r == NULL)
|
|
|
|
return;
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2016-08-27 16:01:08 +02:00
|
|
|
CRYPTO_DOWN_REF(&r->references, &i, r->lock);
|
2016-01-30 12:04:25 -05:00
|
|
|
REF_PRINT_COUNT("DSA", r);
|
2015-01-22 03:40:55 +00:00
|
|
|
if (i > 0)
|
|
|
|
return;
|
2016-01-30 12:04:25 -05:00
|
|
|
REF_ASSERT_ISNT(i < 0);
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2018-09-05 11:58:55 +03:00
|
|
|
if (r->meth != NULL && r->meth->finish != NULL)
|
2015-01-22 03:40:55 +00:00
|
|
|
r->meth->finish(r);
|
2020-01-12 11:32:12 +10:00
|
|
|
#if !defined(FIPS_MODE) && !defined(OPENSSL_NO_ENGINE)
|
2016-02-28 16:01:41 +01:00
|
|
|
ENGINE_finish(r->engine);
|
2003-01-30 17:39:26 +00:00
|
|
|
#endif
|
1999-08-22 17:57:38 +00:00
|
|
|
|
2020-01-14 02:32:42 +01:00
|
|
|
#ifndef FIPS_MODE
|
2015-01-22 03:40:55 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, r, &r->ex_data);
|
2020-01-14 02:32:42 +01:00
|
|
|
#endif
|
2015-01-22 03:40:55 +00:00
|
|
|
|
2016-03-04 15:43:46 +00:00
|
|
|
CRYPTO_THREAD_lock_free(r->lock);
|
|
|
|
|
2015-04-30 21:37:06 -04:00
|
|
|
BN_clear_free(r->p);
|
|
|
|
BN_clear_free(r->q);
|
|
|
|
BN_clear_free(r->g);
|
|
|
|
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-03 13:40:07 +00:00
|
|
|
int DSA_up_ref(DSA *r)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2016-03-04 15:43:46 +00:00
|
|
|
int i;
|
|
|
|
|
2016-08-27 16:01:08 +02:00
|
|
|
if (CRYPTO_UP_REF(&r->references, &i, r->lock) <= 0)
|
2016-03-04 15:43:46 +00:00
|
|
|
return 0;
|
2016-01-30 12:04:25 -05:00
|
|
|
|
|
|
|
REF_PRINT_COUNT("DSA", 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
|
|
|
|
2016-06-14 15:48:16 +02:00
|
|
|
void DSA_get0_pqg(const DSA *d,
|
|
|
|
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
|
2016-03-30 15:21:39 +01:00
|
|
|
{
|
2016-03-30 17:18:55 +01:00
|
|
|
if (p != NULL)
|
|
|
|
*p = d->p;
|
|
|
|
if (q != NULL)
|
|
|
|
*q = d->q;
|
|
|
|
if (g != NULL)
|
|
|
|
*g = d->g;
|
2016-03-30 15:21:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
|
|
{
|
2016-06-14 15:48:16 +02:00
|
|
|
/* If the fields p, q and g in d are NULL, the corresponding input
|
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 20:28:54 +02:00
|
|
|
* parameters MUST be non-NULL.
|
|
|
|
*/
|
2016-06-16 10:07:32 +01:00
|
|
|
if ((d->p == NULL && p == NULL)
|
|
|
|
|| (d->q == NULL && q == NULL)
|
|
|
|
|| (d->g == NULL && g == NULL))
|
2016-03-30 15:21:39 +01: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 20:28:54 +02:00
|
|
|
|
|
|
|
if (p != NULL) {
|
|
|
|
BN_free(d->p);
|
|
|
|
d->p = p;
|
|
|
|
}
|
|
|
|
if (q != NULL) {
|
|
|
|
BN_free(d->q);
|
|
|
|
d->q = q;
|
|
|
|
}
|
|
|
|
if (g != NULL) {
|
|
|
|
BN_free(d->g);
|
|
|
|
d->g = g;
|
|
|
|
}
|
2019-08-30 13:33:37 +01:00
|
|
|
d->dirty_cnt++;
|
2016-03-30 15:21:39 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-06-14 15:48:16 +02:00
|
|
|
void DSA_get0_key(const DSA *d,
|
|
|
|
const BIGNUM **pub_key, const BIGNUM **priv_key)
|
2016-03-30 15:21:39 +01:00
|
|
|
{
|
2016-03-30 17:18:55 +01:00
|
|
|
if (pub_key != NULL)
|
|
|
|
*pub_key = d->pub_key;
|
|
|
|
if (priv_key != NULL)
|
|
|
|
*priv_key = d->priv_key;
|
2016-03-30 15:21:39 +01:00
|
|
|
}
|
|
|
|
|
2016-03-30 17:18:55 +01:00
|
|
|
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
|
2016-03-30 15:21:39 +01:00
|
|
|
{
|
2016-06-14 15:48:16 +02:00
|
|
|
/* If the field pub_key in d is NULL, the corresponding input
|
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 20:28:54 +02:00
|
|
|
* parameters MUST be non-NULL. The priv_key field may
|
|
|
|
* be left NULL.
|
|
|
|
*/
|
2016-06-14 15:48:16 +02:00
|
|
|
if (d->pub_key == NULL && pub_key == NULL)
|
2016-03-30 15:21:39 +01: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 20:28:54 +02:00
|
|
|
if (pub_key != NULL) {
|
|
|
|
BN_free(d->pub_key);
|
|
|
|
d->pub_key = pub_key;
|
|
|
|
}
|
|
|
|
if (priv_key != NULL) {
|
|
|
|
BN_free(d->priv_key);
|
|
|
|
d->priv_key = priv_key;
|
|
|
|
}
|
2019-08-30 13:33:37 +01:00
|
|
|
d->dirty_cnt++;
|
2016-03-30 15:21:39 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-01-13 12:28:05 +01:00
|
|
|
int DSA_security_bits(const DSA *d)
|
|
|
|
{
|
|
|
|
if (d->p && d->q)
|
|
|
|
return BN_security_bits(BN_num_bits(d->p), BN_num_bits(d->q));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DSA_bits(const DSA *dsa)
|
|
|
|
{
|
|
|
|
return BN_num_bits(dsa->p);
|
|
|
|
}
|