diff options
Diffstat (limited to 'src/crypto/ecdsa/ecdsa_asn1.c')
-rw-r--r-- | src/crypto/ecdsa/ecdsa_asn1.c | 183 |
1 files changed, 37 insertions, 146 deletions
diff --git a/src/crypto/ecdsa/ecdsa_asn1.c b/src/crypto/ecdsa/ecdsa_asn1.c index f2d7c36..f557ca7 100644 --- a/src/crypto/ecdsa/ecdsa_asn1.c +++ b/src/crypto/ecdsa/ecdsa_asn1.c @@ -52,33 +52,45 @@ #include <openssl/ecdsa.h> -#include <limits.h> -#include <string.h> - -#include <openssl/bn.h> -#include <openssl/bytestring.h> -#include <openssl/err.h> +#include <openssl/asn1.h> +#include <openssl/asn1t.h> #include <openssl/ec_key.h> #include <openssl/mem.h> #include "../ec/internal.h" +DECLARE_ASN1_FUNCTIONS_const(ECDSA_SIG); +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECDSA_SIG, ECDSA_SIG); + +ASN1_SEQUENCE(ECDSA_SIG) = { + ASN1_SIMPLE(ECDSA_SIG, r, CBIGNUM), + ASN1_SIMPLE(ECDSA_SIG, s, CBIGNUM), +} ASN1_SEQUENCE_END(ECDSA_SIG); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ECDSA_SIG, ECDSA_SIG, ECDSA_SIG); + size_t ECDSA_size(const EC_KEY *key) { - if (key == NULL) { - return 0; - } + size_t ret, i, group_order_size; + ASN1_INTEGER bs; + BIGNUM *order = NULL; + unsigned char buf[4]; + const EC_GROUP *group; - size_t group_order_size; if (key->ecdsa_meth && key->ecdsa_meth->group_order_size) { group_order_size = key->ecdsa_meth->group_order_size(key); } else { - const EC_GROUP *group = EC_KEY_get0_group(key); + size_t num_bits; + + if (key == NULL) { + return 0; + } + group = EC_KEY_get0_group(key); if (group == NULL) { return 0; } - BIGNUM *order = BN_new(); + order = BN_new(); if (order == NULL) { return 0; } @@ -87,11 +99,21 @@ size_t ECDSA_size(const EC_KEY *key) { return 0; } - group_order_size = BN_num_bytes(order); - BN_clear_free(order); + num_bits = BN_num_bits(order); + group_order_size = (num_bits + 7) / 8; } - return ECDSA_SIG_max_len(group_order_size); + bs.length = group_order_size; + bs.data = buf; + bs.type = V_ASN1_INTEGER; + /* If the top bit is set the ASN.1 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); + BN_clear_free(order); + return ret; } ECDSA_SIG *ECDSA_SIG_new(void) { @@ -117,134 +139,3 @@ void ECDSA_SIG_free(ECDSA_SIG *sig) { BN_free(sig->s); OPENSSL_free(sig); } - -ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs) { - ECDSA_SIG *ret = ECDSA_SIG_new(); - if (ret == NULL) { - return NULL; - } - CBS child; - if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || - !BN_cbs2unsigned(&child, ret->r) || - !BN_cbs2unsigned(&child, ret->s) || - CBS_len(&child) != 0) { - OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); - ECDSA_SIG_free(ret); - return NULL; - } - return ret; -} - -ECDSA_SIG *ECDSA_SIG_from_bytes(const uint8_t *in, size_t in_len) { - CBS cbs; - CBS_init(&cbs, in, in_len); - ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs); - if (ret == NULL || CBS_len(&cbs) != 0) { - OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); - ECDSA_SIG_free(ret); - return NULL; - } - return ret; -} - -int ECDSA_SIG_marshal(CBB *cbb, const ECDSA_SIG *sig) { - CBB child; - if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || - !BN_bn2cbb(&child, sig->r) || - !BN_bn2cbb(&child, sig->s) || - !CBB_flush(cbb)) { - OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); - return 0; - } - return 1; -} - -int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len, - const ECDSA_SIG *sig) { - CBB cbb; - CBB_zero(&cbb); - if (!CBB_init(&cbb, 0) || - !ECDSA_SIG_marshal(&cbb, sig) || - !CBB_finish(&cbb, out_bytes, out_len)) { - OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); - CBB_cleanup(&cbb); - return 0; - } - return 1; -} - -/* der_len_len returns the number of bytes needed to represent a length of |len| - * in DER. */ -static size_t der_len_len(size_t len) { - if (len < 0x80) { - return 1; - } - size_t ret = 1; - while (len > 0) { - ret++; - len >>= 8; - } - return ret; -} - -size_t ECDSA_SIG_max_len(size_t order_len) { - /* Compute the maximum length of an |order_len| byte integer. Defensively - * assume that the leading 0x00 is included. */ - size_t integer_len = 1 /* tag */ + der_len_len(order_len + 1) + 1 + order_len; - if (integer_len < order_len) { - return 0; - } - /* An ECDSA signature is two INTEGERs. */ - size_t value_len = 2 * integer_len; - if (value_len < integer_len) { - return 0; - } - /* Add the header. */ - size_t ret = 1 /* tag */ + der_len_len(value_len) + value_len; - if (ret < value_len) { - return 0; - } - return ret; -} - -ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, long len) { - if (len < 0) { - return NULL; - } - CBS cbs; - CBS_init(&cbs, *inp, (size_t)len); - ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs); - if (ret == NULL) { - return NULL; - } - if (out != NULL) { - ECDSA_SIG_free(*out); - *out = ret; - } - *inp += (size_t)len - CBS_len(&cbs); - return ret; -} - -int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp) { - uint8_t *der; - size_t der_len; - if (!ECDSA_SIG_to_bytes(&der, &der_len, sig)) { - return -1; - } - if (der_len > INT_MAX) { - OPENSSL_PUT_ERROR(ECDSA, ERR_R_OVERFLOW); - OPENSSL_free(der); - return -1; - } - if (outp != NULL) { - if (*outp == NULL) { - *outp = der; - der = NULL; - } else { - memcpy(*outp, der, der_len); - *outp += der_len; - } - } - OPENSSL_free(der); - return (int)der_len; -} |