aboutsummaryrefslogtreecommitdiff
path: root/src/secp256k1/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'src/secp256k1/contrib')
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.c150
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.h91
-rw-r--r--src/secp256k1/contrib/lax_der_privatekey_parsing.c113
-rw-r--r--src/secp256k1/contrib/lax_der_privatekey_parsing.h90
4 files changed, 444 insertions, 0 deletions
diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c
new file mode 100644
index 0000000000..5b141a9948
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_parsing.c
@@ -0,0 +1,150 @@
+/**********************************************************************
+ * 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.*
+ **********************************************************************/
+
+#include <string.h>
+#include <secp256k1.h>
+
+#include "lax_der_parsing.h"
+
+int 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;
+}
+
diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h
new file mode 100644
index 0000000000..6d27871a7c
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_parsing.h
@@ -0,0 +1,91 @@
+/**********************************************************************
+ * 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.*
+ **********************************************************************/
+
+/****
+ * Please do not link this file directly. It is not part of the libsecp256k1
+ * project and does not promise any stability in its API, functionality or
+ * presence. Projects which use this code should instead copy this header
+ * and its accompanying .c file directly into their codebase.
+ ****/
+
+/* This file defines a function 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 <secp256k1.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Parse a signature in "lax DER" format
+ *
+ * Returns: 1 when the signature could be parsed, 0 otherwise.
+ * Args: ctx: a secp256k1 context object
+ * Out: sig: a pointer to a signature object
+ * In: input: a pointer to the signature to be parsed
+ * inputlen: the length of the array pointed to be input
+ *
+ * This function will accept any valid DER encoded signature, even if the
+ * encoded numbers are out of range. In addition, it will accept signatures
+ * which violate the DER spec in various ways. Its purpose is to allow
+ * validation of the Bitcoin blockchain, which includes non-DER signatures
+ * from before the network rules were updated to enforce DER. Note that
+ * the set of supported violations is a strict subset of what OpenSSL will
+ * accept.
+ *
+ * After the call, sig will always be initialized. If parsing failed or the
+ * encoded numbers are out of range, signature validation with it is
+ * guaranteed to fail for every message and public key.
+ */
+int ecdsa_signature_parse_der_lax(
+ const secp256k1_context* ctx,
+ secp256k1_ecdsa_signature* sig,
+ const unsigned char *input,
+ size_t inputlen
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.c b/src/secp256k1/contrib/lax_der_privatekey_parsing.c
new file mode 100644
index 0000000000..c2e63b4b8d
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.c
@@ -0,0 +1,113 @@
+/**********************************************************************
+ * Copyright (c) 2014, 2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <string.h>
+#include <secp256k1.h>
+
+#include "lax_der_privatekey_parsing.h"
+
+int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
+ const unsigned char *end = privkey + privkeylen;
+ int lenb = 0;
+ int len = 0;
+ memset(out32, 0, 32);
+ /* sequence header */
+ if (end < privkey+1 || *privkey != 0x30) {
+ return 0;
+ }
+ privkey++;
+ /* sequence length constructor */
+ if (end < privkey+1 || !(*privkey & 0x80)) {
+ return 0;
+ }
+ lenb = *privkey & ~0x80; privkey++;
+ if (lenb < 1 || lenb > 2) {
+ return 0;
+ }
+ if (end < privkey+lenb) {
+ return 0;
+ }
+ /* sequence length */
+ len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
+ privkey += lenb;
+ if (end < privkey+len) {
+ return 0;
+ }
+ /* sequence element 0: version number (=1) */
+ if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
+ return 0;
+ }
+ privkey += 3;
+ /* sequence element 1: octet string, up to 32 bytes */
+ if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
+ return 0;
+ }
+ memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
+ if (!secp256k1_ec_seckey_verify(ctx, out32)) {
+ memset(out32, 0, 32);
+ return 0;
+ }
+ return 1;
+}
+
+int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
+ secp256k1_pubkey pubkey;
+ size_t pubkeylen = 0;
+ if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
+ *privkeylen = 0;
+ return 0;
+ }
+ if (compressed) {
+ static const unsigned char begin[] = {
+ 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ memcpy(ptr, key32, 32); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ pubkeylen = 33;
+ secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
+ ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ } else {
+ static const unsigned char begin[] = {
+ 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
+ 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
+ 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ memcpy(ptr, key32, 32); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ pubkeylen = 65;
+ secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
+ ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ }
+ return 1;
+}
diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
new file mode 100644
index 0000000000..2fd088f8ab
--- /dev/null
+++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
@@ -0,0 +1,90 @@
+/**********************************************************************
+ * Copyright (c) 2014, 2015 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/****
+ * Please do not link this file directly. It is not part of the libsecp256k1
+ * project and does not promise any stability in its API, functionality or
+ * presence. Projects which use this code should instead copy this header
+ * and its accompanying .c file directly into their codebase.
+ ****/
+
+/* This file contains code snippets that parse DER private keys 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.
+ *
+ * It also contains code to serialize private keys in a compatible
+ * manner.
+ *
+ * These functions are meant for compatibility with applications
+ * that require BER encoded keys. When working with secp256k1-specific
+ * code, the simple 32-byte private keys normally used by the
+ * library are sufficient.
+ */
+
+#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
+#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
+
+#include <secp256k1.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/** Export a private key in DER format.
+ *
+ * Returns: 1 if the private key was valid.
+ * Args: ctx: pointer to a context object, initialized for signing (cannot
+ * be NULL)
+ * Out: privkey: pointer to an array for storing the private key in BER.
+ * Should have space for 279 bytes, and cannot be NULL.
+ * privkeylen: Pointer to an int where the length of the private key in
+ * privkey will be stored.
+ * In: seckey: pointer to a 32-byte secret key to export.
+ * compressed: 1 if the key should be exported in
+ * compressed format, 0 otherwise
+ *
+ * This function is purely meant for compatibility with applications that
+ * require BER encoded keys. When working with secp256k1-specific code, the
+ * simple 32-byte private keys are sufficient.
+ *
+ * Note that this function does not guarantee correct DER output. It is
+ * guaranteed to be parsable by secp256k1_ec_privkey_import_der
+ */
+SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der(
+ const secp256k1_context* ctx,
+ unsigned char *privkey,
+ size_t *privkeylen,
+ const unsigned char *seckey,
+ int compressed
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Import a private key in DER format.
+ * Returns: 1 if a private key was extracted.
+ * Args: ctx: pointer to a context object (cannot be NULL).
+ * Out: seckey: pointer to a 32-byte array for storing the private key.
+ * (cannot be NULL).
+ * In: privkey: pointer to a private key in DER format (cannot be NULL).
+ * privkeylen: length of the DER private key pointed to be privkey.
+ *
+ * This function will accept more than just strict DER, and even allow some BER
+ * violations. The public key stored inside the DER-encoded private key is not
+ * verified for correctness, nor are the curve parameters. Use this function
+ * only if you know in advance it is supposed to contain a secp256k1 private
+ * key.
+ */
+SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
+ const secp256k1_context* ctx,
+ unsigned char *seckey,
+ const unsigned char *privkey,
+ size_t privkeylen
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif