Skip to content

Commit

Permalink
Ruby Support - More EVP_PKEY_DSA
Browse files Browse the repository at this point in the history
  • Loading branch information
justsmth committed Oct 28, 2024
1 parent dc3e124 commit c17adaa
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 22 deletions.
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ add_library(
evp_extra/evp_asn1.c
evp_extra/p_dh.c
evp_extra/p_dh_asn1.c
evp_extra/p_dsa.c
evp_extra/p_dsa_asn1.c
evp_extra/p_ec_asn1.c
evp_extra/p_ed25519_asn1.c
Expand Down
1 change: 1 addition & 0 deletions crypto/evp_extra/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ extern const EVP_PKEY_METHOD hkdf_pkey_meth;
extern const EVP_PKEY_METHOD dilithium3_pkey_meth;
extern const EVP_PKEY_METHOD hmac_pkey_meth;
extern const EVP_PKEY_METHOD dh_pkey_meth;
extern const EVP_PKEY_METHOD dsa_pkey_meth;

// evp_pkey_set_method behaves like |EVP_PKEY_set_type|, but takes a pointer to
// a method table. This avoids depending on every |EVP_PKEY_ASN1_METHOD|.
Expand Down
343 changes: 343 additions & 0 deletions crypto/evp_extra/p_dsa.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
// 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 2048A
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);

int ret = 0;
DSA *dsa = NULL;
if (!((dsa = DSA_new())) || !EVP_PKEY_assign_DSA(pkey, dsa) ||
!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
goto err;
}
ret = DSA_generate_key(pkey->pkey.dsa);

err:
if (ret != 1) {
OPENSSL_free(dsa);
}
return ret;
}

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);
return 0;
}
}

if (!((dsa = DSA_new()))) {
goto end;
}

const size_t qsize = EVP_MD_size(pmd);
if (!dsa_internal_paramgen(dsa, dctx->nbits, qsize, 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);

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;
}

if (dctx->md != NULL && tbslen != EVP_MD_size(dctx->md)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
return 0;
}

DSA_SIG *result = DSA_do_sign(tbs, tbslen, dsa);
if (result == NULL) {
return 0;
}
CBB sig_bytes;
if (1 != CBB_init(&sig_bytes, tbslen)) {
return 0;
}
DSA_SIG_marshal(&sig_bytes, result);
uint8_t *sig_buffer = NULL;
if (1 != CBB_finish(&sig_bytes, &sig_buffer, siglen)) {
return 0;
}
OPENSSL_memcpy(sig, sig_buffer, *siglen);
OPENSSL_free(sig_buffer);
return 1;
}

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;
}

CBS sig_cbs;
CBS_init(&sig_cbs, sig, siglen);
DSA_SIG *dsa_sig = DSA_SIG_parse(&sig_cbs);
if (dsa_sig == NULL) {
return 0;
}
if (1 != DSA_do_verify(tbs, tbslen, dsa_sig, dsa)) {
return 0;
}

return 1;
}

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 < 256)
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_dsa:
case NID_dsaWithSHA:
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:
*(const EVP_MD **)p2 = dctx->md;
return 1;

case EVP_PKEY_CTRL_DIGESTINIT:
case EVP_PKEY_CTRL_PKCS7_SIGN:
case EVP_PKEY_CTRL_CMS_SIGN:
return 1;

case EVP_PKEY_CTRL_PEER_KEY:
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return -2;
default:
return -2;
}
}

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;
}
return EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, (int)nbits);
}
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;
}
return EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, (int)qbits);
}
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;
}
return EVP_PKEY_CTX_set_dsa_paramgen_md(ctx, md);
}
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;
}
12 changes: 0 additions & 12 deletions crypto/evp_extra/p_dsa_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,15 +287,3 @@ const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = {

int_dsa_free,
};

int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits) {
// BoringSSL does not support DSA in |EVP_PKEY_CTX|.
OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}

int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits) {
// BoringSSL does not support DSA in |EVP_PKEY_CTX|.
OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
1 change: 1 addition & 0 deletions crypto/evp_extra/p_methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ static const EVP_PKEY_METHOD *const non_fips_pkey_evp_methods[] = {
&dilithium3_pkey_meth,
#endif
&dh_pkey_meth,
&dsa_pkey_meth
};

// We intentionally omit |dh_asn1_meth| from this list. It is not serializable.
Expand Down
Loading

0 comments on commit c17adaa

Please sign in to comment.