Fixed buffer overflow, and also NULL pointer dereference, in ECDSA signature handling.
This commit is contained in:
parent
ccd43452e6
commit
e8ccee8bcd
5 changed files with 80 additions and 3 deletions
|
|
@ -33,6 +33,11 @@ br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
|
||||||
* deviations to DER with regards to minimality of encoding of
|
* deviations to DER with regards to minimality of encoding of
|
||||||
* lengths and integer values. These deviations are still
|
* lengths and integer values. These deviations are still
|
||||||
* unambiguous.
|
* unambiguous.
|
||||||
|
*
|
||||||
|
* Signature format is a SEQUENCE of two INTEGER values. We
|
||||||
|
* support only integers of less than 127 bytes each (signed
|
||||||
|
* encoding) so the resulting raw signature will have length
|
||||||
|
* at most 254 bytes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned char *buf, *r, *s;
|
unsigned char *buf, *r, *s;
|
||||||
|
|
@ -43,9 +48,20 @@ br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
|
||||||
if (sig_len < 8) {
|
if (sig_len < 8) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First byte is SEQUENCE tag.
|
||||||
|
*/
|
||||||
if (buf[0] != 0x30) {
|
if (buf[0] != 0x30) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The SEQUENCE length will be encoded over one or two bytes. We
|
||||||
|
* limit the total SEQUENCE contents to 255 bytes, because it
|
||||||
|
* makes things simpler; this is enough for subgroup orders up
|
||||||
|
* to 999 bits.
|
||||||
|
*/
|
||||||
zlen = buf[1];
|
zlen = buf[1];
|
||||||
if (zlen > 0x80) {
|
if (zlen > 0x80) {
|
||||||
if (zlen != 0x81) {
|
if (zlen != 0x81) {
|
||||||
|
|
@ -62,6 +78,10 @@ br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
|
||||||
}
|
}
|
||||||
off = 2;
|
off = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First INTEGER (r).
|
||||||
|
*/
|
||||||
if (buf[off ++] != 0x02) {
|
if (buf[off ++] != 0x02) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -71,6 +91,10 @@ br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
|
||||||
}
|
}
|
||||||
r = buf + off;
|
r = buf + off;
|
||||||
off += rlen;
|
off += rlen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Second INTEGER (s).
|
||||||
|
*/
|
||||||
if (off + 2 > sig_len) {
|
if (off + 2 > sig_len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -83,6 +107,9 @@ br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
|
||||||
}
|
}
|
||||||
s = buf + off;
|
s = buf + off;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removing leading zeros from r and s.
|
||||||
|
*/
|
||||||
while (rlen > 0 && *r == 0) {
|
while (rlen > 0 && *r == 0) {
|
||||||
rlen --;
|
rlen --;
|
||||||
r ++;
|
r ++;
|
||||||
|
|
@ -92,6 +119,11 @@ br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
|
||||||
s ++;
|
s ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute common length for the two integers, then copy integers
|
||||||
|
* into the temporary buffer, and finally copy it back over the
|
||||||
|
* signature buffer.
|
||||||
|
*/
|
||||||
zlen = rlen > slen ? rlen : slen;
|
zlen = rlen > slen ? rlen : slen;
|
||||||
sig_len = zlen << 1;
|
sig_len = zlen << 1;
|
||||||
memset(tmp, 0, sig_len);
|
memset(tmp, 0, sig_len);
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,13 @@ br_ecdsa_i31_sign_raw(const br_ec_impl *impl,
|
||||||
uint32_t n0i, ctl;
|
uint32_t n0i, ctl;
|
||||||
br_hmac_drbg_context drbg;
|
br_hmac_drbg_context drbg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the curve is not supported, then exit with an error.
|
||||||
|
*/
|
||||||
|
if (((impl->supported_curves >> sk->curve) & 1) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the curve parameters (generator and order).
|
* Get the curve parameters (generator and order).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,13 @@ br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl,
|
||||||
const br_ec_public_key *pk,
|
const br_ec_public_key *pk,
|
||||||
const void *sig, size_t sig_len)
|
const void *sig, size_t sig_len)
|
||||||
{
|
{
|
||||||
unsigned char rsig[(FIELD_LEN << 1) + 12];
|
/*
|
||||||
|
* We use a double-sized buffer because a malformed ASN.1 signature
|
||||||
|
* may trigger a size expansion when converting to "raw" format.
|
||||||
|
*/
|
||||||
|
unsigned char rsig[(FIELD_LEN << 2) + 24];
|
||||||
|
|
||||||
if (sig_len > sizeof rsig) {
|
if (sig_len > ((sizeof rsig) >> 1)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(rsig, sig, sig_len);
|
memcpy(rsig, sig, sig_len);
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,13 @@ br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
|
||||||
size_t nlen, rlen, ulen;
|
size_t nlen, rlen, ulen;
|
||||||
uint32_t n0i, res;
|
uint32_t n0i, res;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the curve is not supported, then report an error.
|
||||||
|
*/
|
||||||
|
if (((impl->supported_curves >> pk->curve) & 1) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the curve parameters (generator and order).
|
* Get the curve parameters (generator and order).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@
|
||||||
|
|
||||||
#include "inner.h"
|
#include "inner.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute ASN.1 encoded length for the provided integer. The ASN.1
|
||||||
|
* encoding is signed, so its leading bit must have value 0; it must
|
||||||
|
* also be of minimal length (so leading bytes of value 0 must be
|
||||||
|
* removed, except if that would contradict the rule about the sign
|
||||||
|
* bit).
|
||||||
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
asn1_int_length(const unsigned char *x, size_t xlen)
|
asn1_int_length(const unsigned char *x, size_t xlen)
|
||||||
{
|
{
|
||||||
|
|
@ -44,7 +51,7 @@ br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
|
||||||
/*
|
/*
|
||||||
* Internal buffer is large enough to accommodate a signature
|
* Internal buffer is large enough to accommodate a signature
|
||||||
* such that r and s fit on 125 bytes each (signed encoding),
|
* such that r and s fit on 125 bytes each (signed encoding),
|
||||||
* meaning a curve order of up to 1000 bits. This is the limit
|
* meaning a curve order of up to 999 bits. This is the limit
|
||||||
* that ensures "simple" length encodings.
|
* that ensures "simple" length encodings.
|
||||||
*/
|
*/
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
|
@ -55,12 +62,20 @@ br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
|
||||||
if ((sig_len & 1) != 0) {
|
if ((sig_len & 1) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute lengths for the two integers.
|
||||||
|
*/
|
||||||
hlen = sig_len >> 1;
|
hlen = sig_len >> 1;
|
||||||
rlen = asn1_int_length(buf, hlen);
|
rlen = asn1_int_length(buf, hlen);
|
||||||
slen = asn1_int_length(buf + hlen, hlen);
|
slen = asn1_int_length(buf + hlen, hlen);
|
||||||
if (rlen > 125 || slen > 125) {
|
if (rlen > 125 || slen > 125) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SEQUENCE header.
|
||||||
|
*/
|
||||||
tmp[0] = 0x30;
|
tmp[0] = 0x30;
|
||||||
zlen = rlen + slen + 4;
|
zlen = rlen + slen + 4;
|
||||||
if (zlen >= 0x80) {
|
if (zlen >= 0x80) {
|
||||||
|
|
@ -71,6 +86,10 @@ br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
|
||||||
tmp[1] = zlen;
|
tmp[1] = zlen;
|
||||||
off = 2;
|
off = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First INTEGER (r).
|
||||||
|
*/
|
||||||
tmp[off ++] = 0x02;
|
tmp[off ++] = 0x02;
|
||||||
tmp[off ++] = rlen;
|
tmp[off ++] = rlen;
|
||||||
if (rlen > hlen) {
|
if (rlen > hlen) {
|
||||||
|
|
@ -80,6 +99,10 @@ br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
|
||||||
memcpy(tmp + off, buf + hlen - rlen, rlen);
|
memcpy(tmp + off, buf + hlen - rlen, rlen);
|
||||||
}
|
}
|
||||||
off += rlen;
|
off += rlen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Second INTEGER (s).
|
||||||
|
*/
|
||||||
tmp[off ++] = 0x02;
|
tmp[off ++] = 0x02;
|
||||||
tmp[off ++] = slen;
|
tmp[off ++] = slen;
|
||||||
if (slen > hlen) {
|
if (slen > hlen) {
|
||||||
|
|
@ -89,6 +112,10 @@ br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
|
||||||
memcpy(tmp + off, buf + sig_len - slen, slen);
|
memcpy(tmp + off, buf + sig_len - slen, slen);
|
||||||
}
|
}
|
||||||
off += slen;
|
off += slen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return ASN.1 signature.
|
||||||
|
*/
|
||||||
memcpy(sig, tmp, off);
|
memcpy(sig, tmp, off);
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue