2016-05-17 18:51:26 +00:00
|
|
|
/*
|
2017-08-18 03:52:46 +00:00
|
|
|
* Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
|
1998-12-21 10:52:47 +00:00
|
|
|
*
|
2016-05-17 18:51:26 +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
|
|
|
*/
|
|
|
|
|
1998-12-22 15:04:48 +00:00
|
|
|
/* Original version from Steven Schoch <schoch@sheba.arc.nasa.gov> */
|
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-03-30 14:21:39 +00:00
|
|
|
#include "dsa_locl.h"
|
1999-04-23 22:13:45 +00:00
|
|
|
#include <openssl/asn1.h>
|
2016-03-18 18:30:20 +00:00
|
|
|
#include <openssl/engine.h>
|
|
|
|
#include <openssl/dh.h>
|
1998-12-21 10:52:47 +00:00
|
|
|
|
1999-04-19 21:31:43 +00:00
|
|
|
DSA *DSA_new(void)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
return DSA_new_method(NULL);
|
|
|
|
}
|
1999-08-22 17:57:38 +00:00
|
|
|
|
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 17:09:06 +00: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;
|
|
|
|
}
|
1999-08-22 17:57:38 +00:00
|
|
|
|
2016-03-30 16:18:55 +00:00
|
|
|
const DSA_METHOD *DSA_get_method(DSA *d)
|
|
|
|
{
|
|
|
|
return d->meth;
|
|
|
|
}
|
|
|
|
|
2000-10-26 21:07:28 +00:00
|
|
|
DSA *DSA_new_method(ENGINE *engine)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2016-03-08 19:11:48 +00: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 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
|
|
|
DSAerr(DSA_F_DSA_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 = DSA_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 & ~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 19:11:48 +00: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 17:09:06 +00: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 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-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
|
|
|
|
2016-03-08 19:11:48 +00:00
|
|
|
if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DSA, 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
|
|
|
DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_INIT_FAIL);
|
|
|
|
err:
|
2016-03-04 15:43:46 +00:00
|
|
|
DSA_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 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 14:01:08 +00:00
|
|
|
CRYPTO_DOWN_REF(&r->references, &i, r->lock);
|
2016-01-30 17:04:25 +00:00
|
|
|
REF_PRINT_COUNT("DSA", 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);
|
1998-12-21 10:52:47 +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-28 15:01:41 +00:00
|
|
|
ENGINE_finish(r->engine);
|
2003-01-30 17:39:26 +00:00
|
|
|
#endif
|
1999-08-22 17:57:38 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, r, &r->ex_data);
|
|
|
|
|
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->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 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("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
|
|
|
|
2000-11-07 13:54:39 +00:00
|
|
|
int DSA_size(const DSA *r)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
int ret, i;
|
|
|
|
ASN1_INTEGER bs;
|
|
|
|
unsigned char buf[4]; /* 4 bytes looks really small. However,
|
|
|
|
* i2d_ASN1_INTEGER() will not look beyond
|
|
|
|
* the first byte, as long as the second
|
|
|
|
* parameter is NULL. */
|
|
|
|
|
|
|
|
i = BN_num_bits(r->q);
|
|
|
|
bs.length = (i + 7) / 8;
|
|
|
|
bs.data = buf;
|
|
|
|
bs.type = V_ASN1_INTEGER;
|
|
|
|
/* If the top bit is set the asn1 encoding is 1 larger. */
|
|
|
|
buf[0] = 0xff;
|
|
|
|
|
|
|
|
i = i2d_ASN1_INTEGER(&bs, NULL);
|
|
|
|
i += i; /* r and s */
|
|
|
|
ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE);
|
|
|
|
return (ret);
|
|
|
|
}
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2000-01-23 23:41:49 +00:00
|
|
|
int DSA_set_ex_data(DSA *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-22 17:57:38 +00:00
|
|
|
|
2000-01-23 23:41:49 +00:00
|
|
|
void *DSA_get_ex_data(DSA *d, int idx)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
return (CRYPTO_get_ex_data(&d->ex_data, idx));
|
|
|
|
}
|
1999-08-22 17:57:38 +00:00
|
|
|
|
2014-01-18 14:51:40 +00:00
|
|
|
int DSA_security_bits(const DSA *d)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2015-12-30 13:34:53 +00:00
|
|
|
if (d->p && d->q)
|
|
|
|
return BN_security_bits(BN_num_bits(d->p), BN_num_bits(d->q));
|
|
|
|
return -1;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2014-01-18 14:51:40 +00:00
|
|
|
|
2001-02-19 16:06:34 +00:00
|
|
|
#ifndef OPENSSL_NO_DH
|
2000-11-07 13:54:39 +00:00
|
|
|
DH *DSA_dup_DH(const DSA *r)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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;
|
2016-04-06 16:49:48 +00:00
|
|
|
BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL, *priv_key = NULL;
|
2015-01-22 03:40:55 +00:00
|
|
|
|
|
|
|
if (r == NULL)
|
|
|
|
goto err;
|
|
|
|
ret = DH_new();
|
|
|
|
if (ret == NULL)
|
|
|
|
goto err;
|
2016-04-06 16:49:48 +00:00
|
|
|
if (r->p != NULL || r->g != NULL || r->q != NULL) {
|
|
|
|
if (r->p == NULL || r->g == NULL || r->q == NULL) {
|
|
|
|
/* Shouldn't happen */
|
2015-01-22 03:40:55 +00:00
|
|
|
goto err;
|
2016-04-06 16:49:48 +00:00
|
|
|
}
|
|
|
|
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))
|
2015-01-22 03:40:55 +00:00
|
|
|
goto err;
|
2016-04-07 13:08:52 +00:00
|
|
|
p = g = q = NULL;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2016-04-06 16:49:48 +00:00
|
|
|
|
|
|
|
if (r->pub_key != NULL) {
|
|
|
|
pub_key = BN_dup(r->pub_key);
|
|
|
|
if (pub_key == NULL)
|
2015-01-22 03:40:55 +00:00
|
|
|
goto err;
|
2016-04-06 16:49:48 +00:00
|
|
|
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))
|
2015-01-22 03:40:55 +00:00
|
|
|
goto err;
|
2016-04-06 16:49:48 +00:00
|
|
|
} else if (r->priv_key != NULL) {
|
|
|
|
/* Shouldn't happen */
|
|
|
|
goto err;
|
|
|
|
}
|
2015-01-22 03:40:55 +00:00
|
|
|
|
|
|
|
return ret;
|
1999-08-05 11:50:18 +00:00
|
|
|
|
|
|
|
err:
|
2016-04-06 16:49:48 +00:00
|
|
|
BN_free(p);
|
|
|
|
BN_free(g);
|
|
|
|
BN_free(q);
|
|
|
|
BN_free(pub_key);
|
|
|
|
BN_free(priv_key);
|
2015-03-24 14:17:37 +00:00
|
|
|
DH_free(ret);
|
2015-01-22 03:40:55 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
1999-08-05 11:50:18 +00:00
|
|
|
#endif
|
2016-03-30 14:21:39 +00:00
|
|
|
|
2016-06-14 13:48:16 +00:00
|
|
|
void DSA_get0_pqg(const DSA *d,
|
|
|
|
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
|
2016-03-30 14:21:39 +00:00
|
|
|
{
|
2016-03-30 16:18:55 +00:00
|
|
|
if (p != NULL)
|
|
|
|
*p = d->p;
|
|
|
|
if (q != NULL)
|
|
|
|
*q = d->q;
|
|
|
|
if (g != NULL)
|
|
|
|
*g = d->g;
|
2016-03-30 14:21:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
|
|
{
|
2016-06-14 13:48:16 +00: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 18:28:54 +00:00
|
|
|
* parameters MUST be non-NULL.
|
|
|
|
*/
|
2016-06-16 09:07:32 +00:00
|
|
|
if ((d->p == NULL && p == NULL)
|
|
|
|
|| (d->q == NULL && q == NULL)
|
|
|
|
|| (d->g == NULL && g == NULL))
|
2016-03-30 14:21:39 +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(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;
|
|
|
|
}
|
2016-03-30 14:21:39 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-06-14 13:48:16 +00:00
|
|
|
void DSA_get0_key(const DSA *d,
|
|
|
|
const BIGNUM **pub_key, const BIGNUM **priv_key)
|
2016-03-30 14:21:39 +00:00
|
|
|
{
|
2016-03-30 16:18:55 +00:00
|
|
|
if (pub_key != NULL)
|
|
|
|
*pub_key = d->pub_key;
|
|
|
|
if (priv_key != NULL)
|
|
|
|
*priv_key = d->priv_key;
|
2016-03-30 14:21:39 +00:00
|
|
|
}
|
|
|
|
|
2016-03-30 16:18:55 +00:00
|
|
|
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
|
2016-03-30 14:21:39 +00:00
|
|
|
{
|
2016-06-14 13:48:16 +00: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 18:28:54 +00:00
|
|
|
* parameters MUST be non-NULL. The priv_key field may
|
|
|
|
* be left NULL.
|
|
|
|
*/
|
2016-06-14 13:48:16 +00:00
|
|
|
if (d->pub_key == NULL && pub_key == NULL)
|
2016-03-30 14:21:39 +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(d->pub_key);
|
|
|
|
d->pub_key = pub_key;
|
|
|
|
}
|
|
|
|
if (priv_key != NULL) {
|
|
|
|
BN_free(d->priv_key);
|
|
|
|
d->priv_key = priv_key;
|
|
|
|
}
|
2016-03-30 14:21:39 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2016-08-01 17:37:03 +00:00
|
|
|
|
|
|
|
int DSA_bits(const DSA *dsa)
|
|
|
|
{
|
|
|
|
return BN_num_bits(dsa->p);
|
|
|
|
}
|