Change contrib/laxder from headers-only to files compilable as standalone C
Verified that both programs compile with gcc -I. -I../include -lsecp256k1 -c -W -Wextra -Wall -Werror -ansi -pedantic lax_der_privatekey_parsing.c gcc -I. -I../include -lsecp256k1 -c -W -Wextra -Wall -Werror -ansi -pedantic lax_der_parsing.c
This commit is contained in:
parent
d7eb1ae96d
commit
eed87af10a
|
@ -41,7 +41,9 @@ noinst_HEADERS += src/field.h
|
||||||
noinst_HEADERS += src/field_impl.h
|
noinst_HEADERS += src/field_impl.h
|
||||||
noinst_HEADERS += src/bench.h
|
noinst_HEADERS += src/bench.h
|
||||||
noinst_HEADERS += contrib/lax_der_parsing.h
|
noinst_HEADERS += contrib/lax_der_parsing.h
|
||||||
|
noinst_HEADERS += contrib/lax_der_parsing.c
|
||||||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
|
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
|
||||||
|
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libsecp256k1.pc
|
pkgconfig_DATA = libsecp256k1.pc
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,14 @@
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
/* This file contains a code snippet that parses DER with various errors and
|
/****
|
||||||
|
* 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. This is not a part of the library itself, because the allowed
|
||||||
* violations are chosen arbitrarily and do not follow or establish any
|
* violations are chosen arbitrarily and do not follow or establish any
|
||||||
* standard.
|
* standard.
|
||||||
|
@ -44,148 +51,41 @@
|
||||||
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
||||||
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <secp256k1.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);
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
static int secp256k1_ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
|
/** Parse a signature in "lax DER" format
|
||||||
size_t rpos, rlen, spos, slen;
|
*
|
||||||
size_t pos = 0;
|
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||||
size_t lenbyte;
|
* Args: ctx: a secp256k1 context object
|
||||||
unsigned char tmpsig[64] = {0};
|
* Out: sig: a pointer to a signature object
|
||||||
int overflow = 0;
|
* 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);
|
||||||
|
|
||||||
/* Hack to initialize sig with a correctly-parsed but invalid signature. */
|
#ifdef __cplusplus
|
||||||
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
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* 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);
|
||||||
|
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);
|
||||||
|
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
|
||||||
|
ptr += pubkeylen;
|
||||||
|
*privkeylen = ptr - privkey;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,13 @@
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* 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
|
/* This file contains code snippets that parse DER private keys with
|
||||||
* various errors and violations. This is not a part of the library
|
* various errors and violations. This is not a part of the library
|
||||||
* itself, because the allowed violations are chosen arbitrarily and
|
* itself, because the allowed violations are chosen arbitrarily and
|
||||||
|
@ -21,9 +28,12 @@
|
||||||
#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
||||||
#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <secp256k1.h>
|
#include <secp256k1.h>
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
/** Export a private key in DER format.
|
/** Export a private key in DER format.
|
||||||
*
|
*
|
||||||
* Returns: 1 if the private key was valid.
|
* Returns: 1 if the private key was valid.
|
||||||
|
@ -44,7 +54,7 @@
|
||||||
* Note that this function does not guarantee correct DER output. It is
|
* Note that this function does not guarantee correct DER output. It is
|
||||||
* guaranteed to be parsable by secp256k1_ec_privkey_import_der
|
* guaranteed to be parsable by secp256k1_ec_privkey_import_der
|
||||||
*/
|
*/
|
||||||
static SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export_der(
|
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der(
|
||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
unsigned char *privkey,
|
unsigned char *privkey,
|
||||||
size_t *privkeylen,
|
size_t *privkeylen,
|
||||||
|
@ -66,112 +76,15 @@ static SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export_der(
|
||||||
* only if you know in advance it is supposed to contain a secp256k1 private
|
* only if you know in advance it is supposed to contain a secp256k1 private
|
||||||
* key.
|
* key.
|
||||||
*/
|
*/
|
||||||
static SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import_der(
|
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
|
||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
unsigned char *seckey,
|
unsigned char *seckey,
|
||||||
const unsigned char *privkey,
|
const unsigned char *privkey,
|
||||||
size_t privkeylen
|
size_t privkeylen
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
static int secp256k1_ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
|
#ifdef __cplusplus
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_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);
|
|
||||||
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);
|
|
||||||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
|
|
||||||
ptr += pubkeylen;
|
|
||||||
*privkeylen = ptr - privkey;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
16
src/tests.c
16
src/tests.c
|
@ -24,8 +24,8 @@
|
||||||
#include "openssl/obj_mac.h"
|
#include "openssl/obj_mac.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "contrib/lax_der_parsing.h"
|
#include "contrib/lax_der_parsing.c"
|
||||||
#include "contrib/lax_der_privatekey_parsing.h"
|
#include "contrib/lax_der_privatekey_parsing.c"
|
||||||
|
|
||||||
#if !defined(VG_CHECK)
|
#if !defined(VG_CHECK)
|
||||||
# if defined(VALGRIND)
|
# if defined(VALGRIND)
|
||||||
|
@ -2580,8 +2580,8 @@ void test_ecdsa_end_to_end(void) {
|
||||||
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
|
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
|
||||||
|
|
||||||
/* Verify private key import and export. */
|
/* Verify private key import and export. */
|
||||||
CHECK(secp256k1_ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
|
CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
|
||||||
CHECK(secp256k1_ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
|
CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
|
||||||
CHECK(memcmp(privkey, privkey2, 32) == 0);
|
CHECK(memcmp(privkey, privkey2, 32) == 0);
|
||||||
|
|
||||||
/* Optionally tweak the keys using addition. */
|
/* Optionally tweak the keys using addition. */
|
||||||
|
@ -2783,7 +2783,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_
|
||||||
roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0;
|
roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed_der_lax = secp256k1_ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen);
|
parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen);
|
||||||
if (parsed_der_lax) {
|
if (parsed_der_lax) {
|
||||||
ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10;
|
ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10;
|
||||||
valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0);
|
valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0);
|
||||||
|
@ -3399,9 +3399,9 @@ void test_ecdsa_edge_cases(void) {
|
||||||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
|
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
|
||||||
};
|
};
|
||||||
size_t outlen = 300;
|
size_t outlen = 300;
|
||||||
CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0));
|
CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0));
|
||||||
outlen = 300;
|
outlen = 300;
|
||||||
CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1));
|
CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3416,7 +3416,7 @@ EC_KEY *get_openssl_key(const unsigned char *key32) {
|
||||||
const unsigned char* pbegin = privkey;
|
const unsigned char* pbegin = privkey;
|
||||||
int compr = secp256k1_rand_bits(1);
|
int compr = secp256k1_rand_bits(1);
|
||||||
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
|
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||||
CHECK(secp256k1_ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr));
|
CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr));
|
||||||
CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
|
CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
|
||||||
CHECK(EC_KEY_check_key(ec_key));
|
CHECK(EC_KEY_check_key(ec_key));
|
||||||
return ec_key;
|
return ec_key;
|
||||||
|
|
Loading…
Reference in New Issue