361 lines
9.0 KiB
C
361 lines
9.0 KiB
C
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0 OR ISC
|
|
|
|
#include <openssl/dsa.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/evp.h>
|
|
|
|
#include "../dsa/internal.h"
|
|
#include "../internal.h"
|
|
#include "./internal.h"
|
|
|
|
typedef struct {
|
|
int nbits; // defaults to 2048
|
|
int qbits;
|
|
const EVP_MD *pmd; // MD for paramgen
|
|
const EVP_MD *md; // MD for signing
|
|
} DSA_PKEY_CTX;
|
|
|
|
static int pkey_dsa_init(EVP_PKEY_CTX *ctx) {
|
|
DSA_PKEY_CTX *dctx = NULL;
|
|
if (!(dctx = (DSA_PKEY_CTX *)OPENSSL_zalloc(sizeof(DSA_PKEY_CTX)))) {
|
|
return 0;
|
|
}
|
|
dctx->nbits = 2048;
|
|
dctx->qbits = 256;
|
|
dctx->pmd = NULL;
|
|
dctx->md = NULL;
|
|
|
|
ctx->data = dctx;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int pkey_dsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
|
|
DSA_PKEY_CTX *dctx = NULL;
|
|
DSA_PKEY_CTX *sctx = NULL;
|
|
if (!pkey_dsa_init(dst)) {
|
|
return 0;
|
|
}
|
|
sctx = (DSA_PKEY_CTX *)src->data;
|
|
dctx = (DSA_PKEY_CTX *)dst->data;
|
|
if (sctx == NULL || dctx == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
dctx->nbits = sctx->nbits;
|
|
dctx->qbits = sctx->qbits;
|
|
dctx->pmd = sctx->pmd;
|
|
dctx->md = sctx->md;
|
|
return 1;
|
|
}
|
|
|
|
static void pkey_dsa_cleanup(EVP_PKEY_CTX *ctx) {
|
|
OPENSSL_free(ctx->data);
|
|
ctx->data = NULL;
|
|
}
|
|
|
|
static int pkey_dsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
|
|
GUARD_PTR(ctx->pkey);
|
|
|
|
DSA *dsa = DSA_new();
|
|
if (dsa == NULL || !EVP_PKEY_assign_DSA(pkey, dsa)) {
|
|
DSA_free(dsa);
|
|
return 0;
|
|
}
|
|
|
|
// |pkey| now has ownership of DSA, and EVP_PKEY_free will handle from this
|
|
// point on.
|
|
|
|
if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
|
|
return 0;
|
|
}
|
|
|
|
return DSA_generate_key(pkey->pkey.dsa);
|
|
}
|
|
|
|
static int pkey_dsa_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
|
|
BN_GENCB *pkey_ctx_cb = NULL;
|
|
DSA *dsa = NULL;
|
|
DSA_PKEY_CTX *dctx = (DSA_PKEY_CTX *)ctx->data;
|
|
GUARD_PTR(dctx);
|
|
|
|
int ret = 0;
|
|
|
|
if (ctx->pkey_gencb) {
|
|
pkey_ctx_cb = BN_GENCB_new();
|
|
if (pkey_ctx_cb == NULL) {
|
|
goto end;
|
|
}
|
|
evp_pkey_set_cb_translate(pkey_ctx_cb, ctx);
|
|
}
|
|
|
|
const EVP_MD *pmd = dctx->pmd;
|
|
if (pmd == NULL) {
|
|
switch (dctx->qbits) {
|
|
case 160:
|
|
pmd = EVP_sha1();
|
|
break;
|
|
case 224:
|
|
pmd = EVP_sha224();
|
|
break;
|
|
case 256:
|
|
pmd = EVP_sha256();
|
|
break;
|
|
default:
|
|
// This should not be possible.
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (!((dsa = DSA_new()))) {
|
|
goto end;
|
|
}
|
|
|
|
if (!dsa_internal_paramgen(dsa, dctx->nbits, pmd, NULL, 0, NULL, NULL,
|
|
pkey_ctx_cb)) {
|
|
goto end;
|
|
}
|
|
|
|
ret = EVP_PKEY_assign_DSA(pkey, dsa);
|
|
end:
|
|
BN_GENCB_free(pkey_ctx_cb);
|
|
if (ret != 1) {
|
|
OPENSSL_free(dsa);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int pkey_dsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
|
|
const unsigned char *tbs, size_t tbslen) {
|
|
GUARD_PTR(ctx->pkey);
|
|
GUARD_PTR(ctx->pkey->pkey.ptr);
|
|
GUARD_PTR(ctx->data);
|
|
GUARD_PTR(siglen);
|
|
|
|
DSA_PKEY_CTX *dctx = ctx->data;
|
|
DSA *dsa = ctx->pkey->pkey.dsa;
|
|
|
|
if (sig == NULL) {
|
|
// Passing NULL for sig indicates a query for the size of the signature
|
|
*siglen = DSA_size(dsa);
|
|
return 1;
|
|
}
|
|
|
|
DSA_SIG *result = NULL;
|
|
uint8_t *sig_buffer = NULL;
|
|
int retval = 0;
|
|
|
|
if (dctx->md != NULL && tbslen != EVP_MD_size(dctx->md)) {
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
|
|
goto end;
|
|
}
|
|
|
|
result = DSA_do_sign(tbs, tbslen, dsa);
|
|
if (result == NULL) {
|
|
goto end;
|
|
}
|
|
CBB sig_bytes;
|
|
if (1 != CBB_init(&sig_bytes, tbslen)) {
|
|
goto end;
|
|
}
|
|
DSA_SIG_marshal(&sig_bytes, result);
|
|
if (1 != CBB_finish(&sig_bytes, &sig_buffer, siglen)) {
|
|
goto end;
|
|
}
|
|
OPENSSL_memcpy(sig, sig_buffer, *siglen);
|
|
retval = 1;
|
|
end:
|
|
OPENSSL_free(sig_buffer);
|
|
DSA_SIG_free(result);
|
|
return retval;
|
|
}
|
|
|
|
static int pkey_dsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
|
|
size_t siglen, const unsigned char *tbs,
|
|
size_t tbslen) {
|
|
GUARD_PTR(ctx->pkey);
|
|
GUARD_PTR(ctx->pkey->pkey.ptr);
|
|
GUARD_PTR(ctx->data);
|
|
GUARD_PTR(tbs);
|
|
|
|
DSA_PKEY_CTX *dctx = ctx->data;
|
|
const DSA *dsa = ctx->pkey->pkey.dsa;
|
|
|
|
if (dctx->md != NULL && tbslen != EVP_MD_size(dctx->md)) {
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
|
|
return 0;
|
|
}
|
|
|
|
DSA_SIG *dsa_sig = NULL;
|
|
int retval = 0;
|
|
|
|
CBS sig_cbs;
|
|
CBS_init(&sig_cbs, sig, siglen);
|
|
dsa_sig = DSA_SIG_parse(&sig_cbs);
|
|
// Allocation failure, invalid asn1 encoding, or trailing garbage
|
|
if (dsa_sig == NULL || CBS_len(&sig_cbs) != 0) {
|
|
goto end;
|
|
}
|
|
if (1 != DSA_do_verify(tbs, tbslen, dsa_sig, dsa)) {
|
|
goto end;
|
|
}
|
|
retval = 1;
|
|
end:
|
|
DSA_SIG_free(dsa_sig);
|
|
return retval;
|
|
}
|
|
|
|
static int pkey_dsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
|
|
DSA_PKEY_CTX *dctx = ctx->data;
|
|
|
|
switch (type) {
|
|
case EVP_PKEY_CTRL_DSA_PARAMGEN_BITS:
|
|
if (p1 < 512) {
|
|
return -2;
|
|
}
|
|
dctx->nbits = p1;
|
|
return 1;
|
|
|
|
case EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS: {
|
|
switch (p1) {
|
|
case 160:
|
|
case 224:
|
|
case 256:
|
|
dctx->qbits = p1;
|
|
return 1;
|
|
default:
|
|
return -2;
|
|
}
|
|
}
|
|
|
|
case EVP_PKEY_CTRL_DSA_PARAMGEN_MD: {
|
|
const EVP_MD *pmd = (const EVP_MD *)p2;
|
|
if (pmd == NULL) {
|
|
return 0;
|
|
}
|
|
switch (EVP_MD_type(pmd)) {
|
|
case NID_sha1:
|
|
case NID_sha224:
|
|
case NID_sha256:
|
|
dctx->pmd = pmd;
|
|
return 1;
|
|
default:
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
|
|
return 0;
|
|
}
|
|
}
|
|
case EVP_PKEY_CTRL_MD: {
|
|
const EVP_MD *md = (const EVP_MD *)p2;
|
|
if (md == NULL) {
|
|
return 0;
|
|
}
|
|
switch (EVP_MD_type(md)) {
|
|
case NID_sha1:
|
|
case NID_sha224:
|
|
case NID_sha256:
|
|
case NID_sha384:
|
|
case NID_sha512:
|
|
case NID_sha3_224:
|
|
case NID_sha3_256:
|
|
case NID_sha3_384:
|
|
case NID_sha3_512:
|
|
dctx->md = md;
|
|
return 1;
|
|
default:
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
|
|
return 0;
|
|
}
|
|
}
|
|
case EVP_PKEY_CTRL_GET_MD:
|
|
if (p2 == NULL) {
|
|
return 0;
|
|
}
|
|
*(const EVP_MD **)p2 = dctx->md;
|
|
return 1;
|
|
|
|
case EVP_PKEY_CTRL_PEER_KEY:
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
return -2;
|
|
default:
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int pkey_dsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
|
|
const char *value) {
|
|
if (strcmp(type, "dsa_paramgen_bits") == 0) {
|
|
char *str_end = NULL;
|
|
long nbits = strtol(value, &str_end, 10);
|
|
if (str_end == value || nbits < 0 || nbits > INT_MAX) {
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
|
|
return 0;
|
|
}
|
|
OPENSSL_BEGIN_ALLOW_DEPRECATED
|
|
return EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, (int)nbits);
|
|
OPENSSL_END_ALLOW_DEPRECATED
|
|
}
|
|
if (strcmp(type, "dsa_paramgen_q_bits") == 0) {
|
|
char *str_end = NULL;
|
|
long qbits = strtol(value, &str_end, 10);
|
|
if (str_end == value || qbits < 0 || qbits > INT_MAX) {
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
|
|
return 0;
|
|
}
|
|
OPENSSL_BEGIN_ALLOW_DEPRECATED
|
|
return EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, (int)qbits);
|
|
OPENSSL_END_ALLOW_DEPRECATED
|
|
}
|
|
if (strcmp(type, "dsa_paramgen_md") == 0) {
|
|
const EVP_MD *md = EVP_get_digestbyname(value);
|
|
|
|
if (md == NULL) {
|
|
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
|
|
return 0;
|
|
}
|
|
OPENSSL_BEGIN_ALLOW_DEPRECATED
|
|
return EVP_PKEY_CTX_set_dsa_paramgen_md(ctx, md);
|
|
OPENSSL_END_ALLOW_DEPRECATED
|
|
}
|
|
return -2;
|
|
}
|
|
|
|
const EVP_PKEY_METHOD dsa_pkey_meth = {.pkey_id = EVP_PKEY_DSA,
|
|
.init = pkey_dsa_init,
|
|
.copy = pkey_dsa_copy,
|
|
.cleanup = pkey_dsa_cleanup,
|
|
.keygen = pkey_dsa_keygen,
|
|
.paramgen = pkey_dsa_paramgen,
|
|
.sign = pkey_dsa_sign,
|
|
.verify = pkey_dsa_verify,
|
|
.ctrl = pkey_dsa_ctrl,
|
|
.ctrl_str = pkey_dsa_ctrl_str};
|
|
|
|
|
|
int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits) {
|
|
if (1 == EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
|
|
EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, nbits, NULL)) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits) {
|
|
if (1 == EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
|
|
EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits, NULL)) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int EVP_PKEY_CTX_set_dsa_paramgen_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
|
|
if (1 == EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
|
|
EVP_PKEY_CTRL_DSA_PARAMGEN_MD, 0, (void *)md)) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|