Move ECDSA_SIG out of BCM
This CL adjusts the libcrypto <-> BCM ECDSA interface. Previously, we
used ECDSA_do_sign and ECDSA_do_verify. This meant we have an allocated
BIGNUM-based type (ECDSA_SIG) at the boundary.
Instead use the fixed-width P1363 format at the boundary, which is nice
and straightforward. For now, I haven't exported it out of anything,
though we do have some things (Channel ID, WebCrypto) which actually
want this format, so that may be worth revisiting later.
Bug: 42290602
Change-Id: Ifbe0600fd23addc5f05141d18baad21a669ceca8
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/66829
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
diff --git a/crypto/ecdsa_extra/ecdsa_asn1.c b/crypto/ecdsa_extra/ecdsa_asn1.c
index 8ddfb3b..b2d4fc6 100644
--- a/crypto/ecdsa_extra/ecdsa_asn1.c
+++ b/crypto/ecdsa_extra/ecdsa_asn1.c
@@ -62,34 +62,87 @@
#include <openssl/mem.h>
#include "../bytestring/internal.h"
-#include "../fipsmodule/ec/internal.h"
+#include "../fipsmodule/ecdsa/internal.h"
#include "../internal.h"
+static ECDSA_SIG *ecdsa_sig_from_fixed(const EC_KEY *key, const uint8_t *in,
+ size_t len) {
+ const EC_GROUP *group = EC_KEY_get0_group(key);
+ if (group == NULL) {
+ OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+ size_t scalar_len = BN_num_bytes(EC_GROUP_get0_order(group));
+ if (len != 2 * scalar_len) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
+ return NULL;
+ }
+ ECDSA_SIG *ret = ECDSA_SIG_new();
+ if (ret == NULL ||
+ !BN_bin2bn(in, scalar_len, ret->r) ||
+ !BN_bin2bn(in + scalar_len, scalar_len, ret->s)) {
+ ECDSA_SIG_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+static int ecdsa_sig_to_fixed(const EC_KEY *key, uint8_t *out, size_t *out_len,
+ size_t max_out, const ECDSA_SIG *sig) {
+ const EC_GROUP *group = EC_KEY_get0_group(key);
+ if (group == NULL) {
+ OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ size_t scalar_len = BN_num_bytes(EC_GROUP_get0_order(group));
+ if (max_out < 2 * scalar_len) {
+ OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ if (BN_is_negative(sig->r) ||
+ !BN_bn2bin_padded(out, scalar_len, sig->r) ||
+ BN_is_negative(sig->s) ||
+ !BN_bn2bin_padded(out + scalar_len, scalar_len, sig->s)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
+ return 0;
+ }
+ *out_len = 2 * scalar_len;
+ return 1;
+}
+
int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
- unsigned int *sig_len, const EC_KEY *eckey) {
+ unsigned int *out_sig_len, const EC_KEY *eckey) {
if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
- return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len,
+ return eckey->ecdsa_meth->sign(digest, digest_len, sig, out_sig_len,
(EC_KEY*) eckey /* cast away const */);
}
- int ret = 0;
- ECDSA_SIG *s = ECDSA_do_sign(digest, digest_len, eckey);
- if (s == NULL) {
- *sig_len = 0;
- goto err;
+ *out_sig_len = 0;
+ uint8_t fixed[ECDSA_MAX_FIXED_LEN];
+ size_t fixed_len;
+ if (!ecdsa_sign_fixed(digest, digest_len, fixed, &fixed_len, sizeof(fixed),
+ eckey)) {
+ return 0;
}
+ // TODO(davidben): We can actually do better and go straight from the DER
+ // format to the fixed-width format without a malloc.
+ ECDSA_SIG *s = ecdsa_sig_from_fixed(eckey, fixed, fixed_len);
+ if (s == NULL) {
+ return 0;
+ }
+
+ int ret = 0;
CBB cbb;
CBB_init_fixed(&cbb, sig, ECDSA_size(eckey));
size_t len;
if (!ECDSA_SIG_marshal(&cbb, s) ||
!CBB_finish(&cbb, NULL, &len)) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR);
- *sig_len = 0;
goto err;
}
- *sig_len = (unsigned)len;
+ *out_sig_len = (unsigned)len;
ret = 1;
err:
@@ -99,12 +152,13 @@
int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len,
const uint8_t *sig, size_t sig_len, const EC_KEY *eckey) {
- ECDSA_SIG *s;
+ // Decode the ECDSA signature.
+ //
+ // TODO(davidben): We can actually do better and go straight from the DER
+ // format to the fixed-width format without a malloc.
int ret = 0;
uint8_t *der = NULL;
-
- // Decode the ECDSA signature.
- s = ECDSA_SIG_from_bytes(sig, sig_len);
+ ECDSA_SIG *s = ECDSA_SIG_from_bytes(sig, sig_len);
if (s == NULL) {
goto err;
}
@@ -118,7 +172,10 @@
goto err;
}
- ret = ECDSA_do_verify(digest, digest_len, s, eckey);
+ uint8_t fixed[ECDSA_MAX_FIXED_LEN];
+ size_t fixed_len;
+ ret = ecdsa_sig_to_fixed(eckey, fixed, &fixed_len, sizeof(fixed), s) &&
+ ecdsa_verify_fixed(digest, digest_len, fixed, fixed_len, eckey);
err:
OPENSSL_free(der);
@@ -147,6 +204,95 @@
return ECDSA_SIG_max_len(group_order_size);
}
+ECDSA_SIG *ECDSA_SIG_new(void) {
+ ECDSA_SIG *sig = OPENSSL_malloc(sizeof(ECDSA_SIG));
+ if (sig == NULL) {
+ return NULL;
+ }
+ sig->r = BN_new();
+ sig->s = BN_new();
+ if (sig->r == NULL || sig->s == NULL) {
+ ECDSA_SIG_free(sig);
+ return NULL;
+ }
+ return sig;
+}
+
+void ECDSA_SIG_free(ECDSA_SIG *sig) {
+ if (sig == NULL) {
+ return;
+ }
+
+ BN_free(sig->r);
+ BN_free(sig->s);
+ OPENSSL_free(sig);
+}
+
+const BIGNUM *ECDSA_SIG_get0_r(const ECDSA_SIG *sig) {
+ return sig->r;
+}
+
+const BIGNUM *ECDSA_SIG_get0_s(const ECDSA_SIG *sig) {
+ return sig->s;
+}
+
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **out_r,
+ const BIGNUM **out_s) {
+ if (out_r != NULL) {
+ *out_r = sig->r;
+ }
+ if (out_s != NULL) {
+ *out_s = sig->s;
+ }
+}
+
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
+ if (r == NULL || s == NULL) {
+ return 0;
+ }
+ BN_free(sig->r);
+ BN_free(sig->s);
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
+ const ECDSA_SIG *sig, const EC_KEY *eckey) {
+ uint8_t fixed[ECDSA_MAX_FIXED_LEN];
+ size_t fixed_len;
+ return ecdsa_sig_to_fixed(eckey, fixed, &fixed_len, sizeof(fixed), sig) &&
+ ecdsa_verify_fixed(digest, digest_len, fixed, fixed_len, eckey);
+}
+
+// This function is only exported for testing and is not called in production
+// code.
+ECDSA_SIG *ECDSA_sign_with_nonce_and_leak_private_key_for_testing(
+ const uint8_t *digest, size_t digest_len, const EC_KEY *eckey,
+ const uint8_t *nonce, size_t nonce_len) {
+ uint8_t sig[ECDSA_MAX_FIXED_LEN];
+ size_t sig_len;
+ if (!ecdsa_sign_fixed_with_nonce_for_known_answer_test(
+ digest, digest_len, sig, &sig_len, sizeof(sig), eckey, nonce,
+ nonce_len)) {
+ return NULL;
+ }
+
+ return ecdsa_sig_from_fixed(eckey, sig, sig_len);
+}
+
+ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
+ const EC_KEY *eckey) {
+ uint8_t sig[ECDSA_MAX_FIXED_LEN];
+ size_t sig_len;
+ if (!ecdsa_sign_fixed(digest, digest_len, sig, &sig_len, sizeof(sig),
+ eckey)) {
+ return NULL;
+ }
+
+ return ecdsa_sig_from_fixed(eckey, sig, sig_len);
+}
+
ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs) {
ECDSA_SIG *ret = ECDSA_SIG_new();
if (ret == NULL) {
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index c356730..48becb9 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -196,7 +196,7 @@
assert_within(start, RAND_bytes, end);
assert_within(start, EC_GROUP_cmp, end);
assert_within(start, SHA256_Update, end);
- assert_within(start, ECDSA_do_verify, end);
+ assert_within(start, ecdsa_verify_fixed, end);
assert_within(start, EVP_AEAD_CTX_seal, end);
#if defined(BORINGSSL_SHARED_LIBRARY)
diff --git a/crypto/fipsmodule/ec/ec_key.c b/crypto/fipsmodule/ec/ec_key.c
index 8cdb5c3..1eef021 100644
--- a/crypto/fipsmodule/ec/ec_key.c
+++ b/crypto/fipsmodule/ec/ec_key.c
@@ -75,10 +75,12 @@
#include <openssl/err.h>
#include <openssl/ex_data.h>
#include <openssl/mem.h>
+#include <openssl/sha.h>
#include <openssl/thread.h>
#include "internal.h"
#include "../delocate.h"
+#include "../ecdsa/internal.h"
#include "../service_indicator/internal.h"
#include "../../internal.h"
@@ -344,15 +346,17 @@
}
if (key->priv_key) {
- uint8_t data[16] = {0};
- ECDSA_SIG *sig = ECDSA_do_sign(data, sizeof(data), key);
- if (boringssl_fips_break_test("ECDSA_PWCT")) {
- data[0] = ~data[0];
+ uint8_t digest[SHA256_DIGEST_LENGTH] = {0};
+ uint8_t sig[ECDSA_MAX_FIXED_LEN];
+ size_t sig_len;
+ if (!ecdsa_sign_fixed(digest, sizeof(digest), sig, &sig_len, sizeof(sig),
+ key)) {
+ goto end;
}
- int ok = sig != NULL &&
- ECDSA_do_verify(data, sizeof(data), sig, key);
- ECDSA_SIG_free(sig);
- if (!ok) {
+ if (boringssl_fips_break_test("ECDSA_PWCT")) {
+ digest[0] = ~digest[0];
+ }
+ if (!ecdsa_verify_fixed(digest, sizeof(digest), sig, sig_len, key)) {
OPENSSL_PUT_ERROR(EC, EC_R_PUBLIC_KEY_VALIDATION_FAILED);
goto end;
}
diff --git a/crypto/fipsmodule/ecdsa/ecdsa.c b/crypto/fipsmodule/ecdsa/ecdsa.c
index 3bd018d..cba8972 100644
--- a/crypto/fipsmodule/ecdsa/ecdsa.c
+++ b/crypto/fipsmodule/ecdsa/ecdsa.c
@@ -95,61 +95,9 @@
order->width);
}
-ECDSA_SIG *ECDSA_SIG_new(void) {
- ECDSA_SIG *sig = OPENSSL_malloc(sizeof(ECDSA_SIG));
- if (sig == NULL) {
- return NULL;
- }
- sig->r = BN_new();
- sig->s = BN_new();
- if (sig->r == NULL || sig->s == NULL) {
- ECDSA_SIG_free(sig);
- return NULL;
- }
- return sig;
-}
-
-void ECDSA_SIG_free(ECDSA_SIG *sig) {
- if (sig == NULL) {
- return;
- }
-
- BN_free(sig->r);
- BN_free(sig->s);
- OPENSSL_free(sig);
-}
-
-const BIGNUM *ECDSA_SIG_get0_r(const ECDSA_SIG *sig) {
- return sig->r;
-}
-
-const BIGNUM *ECDSA_SIG_get0_s(const ECDSA_SIG *sig) {
- return sig->s;
-}
-
-void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **out_r,
- const BIGNUM **out_s) {
- if (out_r != NULL) {
- *out_r = sig->r;
- }
- if (out_s != NULL) {
- *out_s = sig->s;
- }
-}
-
-int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
- if (r == NULL || s == NULL) {
- return 0;
- }
- BN_free(sig->r);
- BN_free(sig->s);
- sig->r = r;
- sig->s = s;
- return 1;
-}
-
-int ecdsa_do_verify_no_self_test(const uint8_t *digest, size_t digest_len,
- const ECDSA_SIG *sig, const EC_KEY *eckey) {
+int ecdsa_verify_fixed_no_self_test(const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len,
+ const EC_KEY *eckey) {
const EC_GROUP *group = EC_KEY_get0_group(eckey);
const EC_POINT *pub_key = EC_KEY_get0_public_key(eckey);
if (group == NULL || pub_key == NULL || sig == NULL) {
@@ -157,11 +105,13 @@
return 0;
}
+ size_t scalar_len = BN_num_bytes(EC_GROUP_get0_order(group));
EC_SCALAR r, s, u1, u2, s_inv_mont, m;
- if (BN_is_zero(sig->r) ||
- !ec_bignum_to_scalar(group, &r, sig->r) ||
- BN_is_zero(sig->s) ||
- !ec_bignum_to_scalar(group, &s, sig->s)) {
+ if (sig_len != 2 * scalar_len ||
+ !ec_scalar_from_bytes(group, &r, sig, scalar_len) ||
+ ec_scalar_is_zero(group, &r) ||
+ !ec_scalar_from_bytes(group, &s, sig + scalar_len, scalar_len) ||
+ ec_scalar_is_zero(group, &s)) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
return 0;
}
@@ -195,24 +145,31 @@
return 1;
}
-int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
- const ECDSA_SIG *sig, const EC_KEY *eckey) {
+int ecdsa_verify_fixed(const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len, const EC_KEY *key) {
boringssl_ensure_ecc_self_test();
- return ecdsa_do_verify_no_self_test(digest, digest_len, sig, eckey);
+ return ecdsa_verify_fixed_no_self_test(digest, digest_len, sig, sig_len, key);
}
-static ECDSA_SIG *ecdsa_sign_impl(const EC_GROUP *group, int *out_retry,
- const EC_SCALAR *priv_key, const EC_SCALAR *k,
- const uint8_t *digest, size_t digest_len) {
+static int ecdsa_sign_impl(const EC_GROUP *group, int *out_retry, uint8_t *sig,
+ size_t *out_sig_len, size_t max_sig_len,
+ const EC_SCALAR *priv_key, const EC_SCALAR *k,
+ const uint8_t *digest, size_t digest_len) {
*out_retry = 0;
// Check that the size of the group order is FIPS compliant (FIPS 186-4
// B.5.2).
const BIGNUM *order = EC_GROUP_get0_order(group);
if (BN_num_bits(order) < 160) {
- OPENSSL_PUT_ERROR(ECDSA, EC_R_INVALID_GROUP_ORDER);
- return NULL;
+ OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
+ return 0;
+ }
+
+ size_t sig_len = 2 * BN_num_bytes(order);
+ if (sig_len > max_sig_len) {
+ OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
+ return 0;
}
// Compute r, the x-coordinate of k * generator.
@@ -220,12 +177,12 @@
EC_SCALAR r;
if (!ec_point_mul_scalar_base(group, &tmp_point, k) ||
!ec_get_x_coordinate_as_scalar(group, &r, &tmp_point)) {
- return NULL;
+ return 0;
}
if (constant_time_declassify_int(ec_scalar_is_zero(group, &r))) {
*out_retry = 1;
- return NULL;
+ return 0;
}
// s = priv_key * r. Note if only one parameter is in the Montgomery domain,
@@ -252,71 +209,59 @@
ec_scalar_mul_montgomery(group, &s, &s, &tmp);
if (constant_time_declassify_int(ec_scalar_is_zero(group, &s))) {
*out_retry = 1;
- return NULL;
+ return 0;
}
CONSTTIME_DECLASSIFY(r.words, sizeof(r.words));
CONSTTIME_DECLASSIFY(s.words, sizeof(r.words));
- ECDSA_SIG *ret = ECDSA_SIG_new();
- if (ret == NULL || //
- !bn_set_words(ret->r, r.words, order->width) ||
- !bn_set_words(ret->s, s.words, order->width)) {
- ECDSA_SIG_free(ret);
- return NULL;
- }
- return ret;
+ size_t len;
+ ec_scalar_to_bytes(group, sig, &len, &r);
+ assert(len == sig_len / 2);
+ ec_scalar_to_bytes(group, sig + len, &len, &s);
+ assert(len == sig_len / 2);
+ *out_sig_len = sig_len;
+ return 1;
}
-ECDSA_SIG *ecdsa_sign_with_nonce_for_known_answer_test(const uint8_t *digest,
- size_t digest_len,
- const EC_KEY *eckey,
- const uint8_t *nonce,
- size_t nonce_len) {
+int ecdsa_sign_fixed_with_nonce_for_known_answer_test(
+ const uint8_t *digest, size_t digest_len, uint8_t *sig, size_t *out_sig_len,
+ size_t max_sig_len, const EC_KEY *eckey, const uint8_t *nonce,
+ size_t nonce_len) {
if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
- return NULL;
+ return 0;
}
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if (group == NULL || eckey->priv_key == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
- return NULL;
+ return 0;
}
const EC_SCALAR *priv_key = &eckey->priv_key->scalar;
EC_SCALAR k;
if (!ec_scalar_from_bytes(group, &k, nonce, nonce_len)) {
- return NULL;
+ return 0;
}
int retry_ignored;
- return ecdsa_sign_impl(group, &retry_ignored, priv_key, &k, digest,
- digest_len);
+ return ecdsa_sign_impl(group, &retry_ignored, sig, out_sig_len, max_sig_len,
+ priv_key, &k, digest, digest_len);
}
-// This function is only exported for testing and is not called in production
-// code.
-ECDSA_SIG *ECDSA_sign_with_nonce_and_leak_private_key_for_testing(
- const uint8_t *digest, size_t digest_len, const EC_KEY *eckey,
- const uint8_t *nonce, size_t nonce_len) {
- boringssl_ensure_ecc_self_test();
-
- return ecdsa_sign_with_nonce_for_known_answer_test(digest, digest_len, eckey,
- nonce, nonce_len);
-}
-
-ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
- const EC_KEY *eckey) {
+int ecdsa_sign_fixed(const uint8_t *digest, size_t digest_len, uint8_t *sig,
+ size_t *out_sig_len, size_t max_sig_len,
+ const EC_KEY *eckey) {
boringssl_ensure_ecc_self_test();
if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
- return NULL;
+ return 0;
}
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if (group == NULL || eckey->priv_key == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
- return NULL;
+ return 0;
}
const BIGNUM *order = EC_GROUP_get0_order(group);
const EC_SCALAR *priv_key = &eckey->priv_key->scalar;
@@ -340,12 +285,11 @@
// FIPS) because the probability of requiring even one retry is negligible,
// let alone 32.
static const int kMaxIterations = 32;
- ECDSA_SIG *ret = NULL;
+ int ret = 0;
int iters = 0;
for (;;) {
EC_SCALAR k;
if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
- ret = NULL;
goto out;
}
@@ -354,8 +298,9 @@
CONSTTIME_SECRET(k.words, sizeof(k.words));
int retry;
- ret = ecdsa_sign_impl(group, &retry, priv_key, &k, digest, digest_len);
- if (ret != NULL || !retry) {
+ ret = ecdsa_sign_impl(group, &retry, sig, out_sig_len, max_sig_len,
+ priv_key, &k, digest, digest_len);
+ if (ret || !retry) {
goto out;
}
diff --git a/crypto/fipsmodule/ecdsa/ecdsa_test.cc b/crypto/fipsmodule/ecdsa/ecdsa_test.cc
index 5876935..1856210 100644
--- a/crypto/fipsmodule/ecdsa/ecdsa_test.cc
+++ b/crypto/fipsmodule/ecdsa/ecdsa_test.cc
@@ -285,6 +285,14 @@
// Verify a tampered signature.
TestTamperedSig(kRawAPI, digest, 20, ecdsa_sig.get(), eckey.get(), order);
+
+ // Negative components should not be accepted.
+ BN_set_negative(ecdsa_sig->r, 1);
+ EXPECT_FALSE(ECDSA_do_verify(digest, 20, ecdsa_sig.get(), eckey.get()));
+ BN_set_negative(ecdsa_sig->r, 0);
+ BN_set_negative(ecdsa_sig->s, 1);
+ EXPECT_FALSE(ECDSA_do_verify(digest, 20, ecdsa_sig.get(), eckey.get()));
+ BN_set_negative(ecdsa_sig->s, 0);
}
}
diff --git a/crypto/fipsmodule/ecdsa/internal.h b/crypto/fipsmodule/ecdsa/internal.h
index 645959f..0ae08ac 100644
--- a/crypto/fipsmodule/ecdsa/internal.h
+++ b/crypto/fipsmodule/ecdsa/internal.h
@@ -17,25 +17,42 @@
#include <openssl/base.h>
+#include "../ec/internal.h"
+
#if defined(__cplusplus)
extern "C" {
#endif
-// ecdsa_sign_with_nonce_for_known_answer_test behaves like |ECDSA_do_sign| but
-// takes a fixed nonce. This function is used as part of known-answer tests in
-// the FIPS module.
-ECDSA_SIG *ecdsa_sign_with_nonce_for_known_answer_test(const uint8_t *digest,
- size_t digest_len,
- const EC_KEY *eckey,
- const uint8_t *nonce,
- size_t nonce_len);
+// ECDSA_MAX_FIXED_LEN is the maximum length of an ECDSA signature in the
+// fixed-width, big-endian format from IEEE P1363.
+#define ECDSA_MAX_FIXED_LEN (2 * EC_MAX_BYTES)
-// ecdsa_do_verify_no_self_test does the same as |ECDSA_do_verify|, but doesn't
+// ecdsa_sign_fixed behaves like |ECDSA_sign| but uses the fixed-width,
+// big-endian format from IEEE P1363.
+int ecdsa_sign_fixed(const uint8_t *digest, size_t digest_len, uint8_t *sig,
+ size_t *out_sig_len, size_t max_sig_len,
+ const EC_KEY *key);
+
+// ecdsa_sign_fixed_with_nonce_for_known_answer_test behaves like
+// |ecdsa_sign_fixed| but takes a caller-supplied nonce. This function is used
+// as part of known-answer tests in the FIPS module.
+int ecdsa_sign_fixed_with_nonce_for_known_answer_test(
+ const uint8_t *digest, size_t digest_len, uint8_t *sig, size_t *out_sig_len,
+ size_t max_sig_len, const EC_KEY *key, const uint8_t *nonce,
+ size_t nonce_len);
+
+// ecdsa_verify_fixed behaves like |ECDSA_verify| but uses the fixed-width,
+// big-endian format from IEEE P1363.
+int ecdsa_verify_fixed(const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len, const EC_KEY *key);
+
+// ecdsa_verify_fixed_no_self_test behaves like ecdsa_verify_fixed, but doesn't
// try to run the self-test first. This is for use in the self tests themselves,
// to prevent an infinite loop.
-int ecdsa_do_verify_no_self_test(const uint8_t *digest, size_t digest_len,
- const ECDSA_SIG *sig, const EC_KEY *eckey);
+int ecdsa_verify_fixed_no_self_test(const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len,
+ const EC_KEY *key);
#if defined(__cplusplus)
diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c
index 1984630..7afcb75 100644
--- a/crypto/fipsmodule/self_check/self_check.c
+++ b/crypto/fipsmodule/self_check/self_check.c
@@ -77,28 +77,6 @@
return *out != NULL;
}
-static int serialize_ecdsa_sig(uint8_t *out, size_t out_len,
- const ECDSA_SIG *sig) {
- if ((out_len & 1) || //
- !BN_bn2bin_padded(out, out_len / 2, sig->r) ||
- !BN_bn2bin_padded(out + out_len / 2, out_len / 2, sig->s)) {
- return 0;
- }
- return 1;
-}
-
-static ECDSA_SIG *parse_ecdsa_sig(const uint8_t *in, size_t in_len) {
- ECDSA_SIG *ret = ECDSA_SIG_new();
- if (!ret || //
- (in_len & 1) ||
- BN_bin2bn(in, in_len/2, ret->r) == NULL ||
- BN_bin2bn(in + in_len/2, in_len/2, ret->s) == NULL) {
- ECDSA_SIG_free(ret);
- ret = NULL;
- }
- return ret;
-}
-
static RSA *self_test_rsa_key(void) {
static const uint8_t kN[] = {
0xd3, 0x3a, 0x62, 0x9f, 0x07, 0x77, 0xb0, 0x18, 0xf3, 0xff, 0xfe, 0xcc,
@@ -415,7 +393,6 @@
EC_POINT *ec_point_in = NULL;
EC_POINT *ec_point_out = NULL;
BIGNUM *ec_scalar = NULL;
- ECDSA_SIG *sig = NULL;
ec_key = self_test_ecdsa_key();
if (ec_key == NULL) {
@@ -443,13 +420,12 @@
uint8_t ecdsa_k[32] = {0};
ecdsa_k[31] = 42;
- sig = ecdsa_sign_with_nonce_for_known_answer_test(
- kECDSASignDigest, sizeof(kECDSASignDigest), ec_key, ecdsa_k,
- sizeof(ecdsa_k));
-
uint8_t ecdsa_sign_output[64];
- if (sig == NULL ||
- !serialize_ecdsa_sig(ecdsa_sign_output, sizeof(ecdsa_sign_output), sig) ||
+ size_t ecdsa_sign_output_len;
+ if (!ecdsa_sign_fixed_with_nonce_for_known_answer_test(
+ kECDSASignDigest, sizeof(kECDSASignDigest), ecdsa_sign_output,
+ &ecdsa_sign_output_len, sizeof(ecdsa_sign_output), ec_key, ecdsa_k,
+ sizeof(ecdsa_k)) ||
!check_test(kECDSASignSig, ecdsa_sign_output, sizeof(ecdsa_sign_output),
"ECDSA-sign signature")) {
fprintf(stderr, "ECDSA-sign KAT failed.\n");
@@ -470,11 +446,9 @@
0x8e, 0x5f, 0x64, 0xc3, 0x7e, 0xa2, 0xcf, 0x05, 0x29,
};
- ECDSA_SIG_free(sig);
- sig = parse_ecdsa_sig(kECDSAVerifySig, sizeof(kECDSAVerifySig));
- if (!sig ||
- !ecdsa_do_verify_no_self_test(kECDSAVerifyDigest,
- sizeof(kECDSAVerifyDigest), sig, ec_key)) {
+ if (!ecdsa_verify_fixed_no_self_test(
+ kECDSAVerifyDigest, sizeof(kECDSAVerifyDigest), kECDSAVerifySig,
+ sizeof(kECDSAVerifySig), ec_key)) {
fprintf(stderr, "ECDSA-verify KAT failed.\n");
goto err;
}
@@ -532,7 +506,6 @@
EC_POINT_free(ec_point_in);
EC_POINT_free(ec_point_out);
BN_free(ec_scalar);
- ECDSA_SIG_free(sig);
return ret;
}