rust-secp256k1-unsafe-fast/depend/secp256k1/contrib/lax_der_parsing.h

192 lines
5.5 KiB
C

/**********************************************************************
* Copyright (c) 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/* This file contains a code snippet that parses DER with various errors and
* violations. This is not a part of the library itself, because the allowed
* violations are chosen arbitrarily and do not follow or establish any
* standard.
*
* In many places it matters that different implementations do not only accept
* the same set of valid signatures, but also reject the same set of signatures.
* The only means to accomplish that is by strictly obeying a standard, and not
* accepting anything else.
*
* Nonetheless, sometimes there is a need for compatibility with systems that
* use signatures which do not strictly obey DER. The snippet below shows how
* certain violations are easily supported. You may need to adapt it.
*
* Do not use this for new systems. Use well-defined DER or compact signatures
* instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and
* secp256k1_ecdsa_signature_parse_compact).
*
* The supported violations are:
* - All numbers are parsed as nonnegative integers, even though X.609-0207
* section 8.3.3 specifies that integers are always encoded as two's
* complement.
* - Integers can have length 0, even though section 8.3.1 says they can't.
* - Integers with overly long padding are accepted, violation section
* 8.3.2.
* - 127-byte long length descriptors are accepted, even though section
* 8.1.3.5.c says that they are not.
* - Trailing garbage data inside or after the signature is ignored.
* - The length descriptor of the sequence is ignored.
*
* Compared to for example OpenSSL, many violations are NOT supported:
* - Using overly long tag descriptors for the sequence or integers inside,
* violating section 8.1.2.2.
* - Encoding primitive integers as constructed values, violating section
* 8.3.1.
*/
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
#include <string.h>
#include <secp256k1.h>
static int secp256k1_ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen);
static int secp256k1_ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
size_t rpos, rlen, spos, slen;
size_t pos = 0;
size_t lenbyte;
unsigned char tmpsig[64] = {0};
int overflow = 0;
/* Hack to initialize sig with a correctly-parsed but invalid signature. */
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
/* Sequence tag byte */
if (pos == inputlen || input[pos] != 0x30) {
return 0;
}
pos++;
/* Sequence length bytes */
if (pos == inputlen) {
return 0;
}
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
return 0;
}
pos += lenbyte;
}
/* Integer tag byte for R */
if (pos == inputlen || input[pos] != 0x02) {
return 0;
}
pos++;
/* Integer length for R */
if (pos == inputlen) {
return 0;
}
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
pos++;
lenbyte--;
}
if (lenbyte >= sizeof(size_t)) {
return 0;
}
rlen = 0;
while (lenbyte > 0) {
rlen = (rlen << 8) + input[pos];
pos++;
lenbyte--;
}
} else {
rlen = lenbyte;
}
if (rlen > inputlen - pos) {
return 0;
}
rpos = pos;
pos += rlen;
/* Integer tag byte for S */
if (pos == inputlen || input[pos] != 0x02) {
return 0;
}
pos++;
/* Integer length for S */
if (pos == inputlen) {
return 0;
}
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
pos++;
lenbyte--;
}
if (lenbyte >= sizeof(size_t)) {
return 0;
}
slen = 0;
while (lenbyte > 0) {
slen = (slen << 8) + input[pos];
pos++;
lenbyte--;
}
} else {
slen = lenbyte;
}
if (slen > inputlen - pos) {
return 0;
}
spos = pos;
pos += slen;
/* Ignore leading zeroes in R */
while (rlen > 0 && input[rpos] == 0) {
rlen--;
rpos++;
}
/* Copy R value */
if (rlen > 32) {
overflow = 1;
} else {
memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
}
/* Ignore leading zeroes in S */
while (slen > 0 && input[spos] == 0) {
slen--;
spos++;
}
/* Copy S value */
if (slen > 32) {
overflow = 1;
} else {
memcpy(tmpsig + 64 - slen, input + spos, slen);
}
if (!overflow) {
overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
}
if (overflow) {
memset(tmpsig, 0, 64);
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
}
return 1;
}
#endif