Skip to content

Commit 79399c8

Browse files
committed
Merge #10657: Utils: Improvements to ECDSA key-handling code
63179d0 Scope the ECDSA constant sizes to CPubKey / CKey classes (Jack Grigg) 1ce9f0a Ensure that ECDSA constant sizes are correctly-sized (Jack Grigg) 48abe78 Remove redundant `= 0` initialisations (Jack Grigg) 17fa391 Specify ECDSA constant sizes as constants (Jack Grigg) e4a1086 Update Debian copyright list (Jack Grigg) e181dbe Add comments (Jack Grigg) a3603ac Fix potential overflows in ECDSA DER parsers (Jack Grigg) Pull request description: Mostly trivial, but includes fixes to potential overflows in the ECDSA DER parsers. Cherry-picked from Zcash PR zcash/zcash#2335 Tree-SHA512: 8fcbd51b0bd6723e5d33fa5d592f7cb68ed182796a9b837ecc8217991ad69d6c970258617dc00eb378c8caa4cec5d6b304d9d2c066acd40cda98e4da68e0caa4
2 parents bc66765 + 63179d0 commit 79399c8

File tree

6 files changed

+131
-62
lines changed

6 files changed

+131
-62
lines changed

contrib/debian/copyright

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ Copyright: 2010-2011, Jonas Smedegaard <[email protected]>
1515
2011, Matt Corallo <[email protected]>
1616
License: GPL-2+
1717

18+
Files: src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
19+
Copyright: 2008 Don Anderson <[email protected]>
20+
License: GNU-All-permissive-License
21+
22+
Files: src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4
23+
Copyright: 2008 Paolo Bonzini <[email protected]>
24+
License: GNU-All-permissive-License
25+
1826
Files: src/qt/res/icons/add.png
1927
src/qt/res/icons/address-book.png
2028
src/qt/res/icons/chevron.png
@@ -106,6 +114,12 @@ License: Expat
106114
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
107115
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
108116

117+
License: GNU-All-permissive-License
118+
Copying and distribution of this file, with or without modification, are
119+
permitted in any medium without royalty provided the copyright notice
120+
and this notice are preserved. This file is offered as-is, without any
121+
warranty.
122+
109123
License: GPL-2+
110124
This program is free software; you can redistribute it and/or modify it
111125
under the terms of the GNU General Public License as published by the

src/key.cpp

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright (c) 2009-2016 The Bitcoin Core developers
2+
// Copyright (c) 2017 The Zcash developers
23
// Distributed under the MIT software license, see the accompanying
34
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
45

@@ -15,51 +16,81 @@
1516
static secp256k1_context* secp256k1_context_sign = nullptr;
1617

1718
/** These functions are taken from the libsecp256k1 distribution and are very ugly. */
19+
20+
/**
21+
* This parses a format loosely based on a DER encoding of the ECPrivateKey type from
22+
* section C.4 of SEC 1 <http://www.secg.org/sec1-v2.pdf>, with the following caveats:
23+
*
24+
* * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is not
25+
* required to be encoded as one octet if it is less than 256, as DER would require.
26+
* * The octet-length of the SEQUENCE must not be greater than the remaining
27+
* length of the key encoding, but need not match it (i.e. the encoding may contain
28+
* junk after the encoded SEQUENCE).
29+
* * The privateKey OCTET STRING is zero-filled on the left to 32 octets.
30+
* * Anything after the encoding of the privateKey OCTET STRING is ignored, whether
31+
* or not it is validly encoded DER.
32+
*
33+
* out32 must point to an output buffer of length at least 32 bytes.
34+
*/
1835
static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
1936
const unsigned char *end = privkey + privkeylen;
20-
int lenb = 0;
21-
int len = 0;
2237
memset(out32, 0, 32);
2338
/* sequence header */
24-
if (end < privkey+1 || *privkey != 0x30) {
39+
if (end - privkey < 1 || *privkey != 0x30u) {
2540
return 0;
2641
}
2742
privkey++;
2843
/* sequence length constructor */
29-
if (end < privkey+1 || !(*privkey & 0x80)) {
44+
if (end - privkey < 1 || !(*privkey & 0x80u)) {
3045
return 0;
3146
}
32-
lenb = *privkey & ~0x80; privkey++;
47+
size_t lenb = *privkey & ~0x80u; privkey++;
3348
if (lenb < 1 || lenb > 2) {
3449
return 0;
3550
}
36-
if (end < privkey+lenb) {
51+
if (end - privkey < lenb) {
3752
return 0;
3853
}
3954
/* sequence length */
40-
len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
55+
size_t len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0u);
4156
privkey += lenb;
42-
if (end < privkey+len) {
57+
if (end - privkey < len) {
4358
return 0;
4459
}
4560
/* sequence element 0: version number (=1) */
46-
if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
61+
if (end - privkey < 3 || privkey[0] != 0x02u || privkey[1] != 0x01u || privkey[2] != 0x01u) {
4762
return 0;
4863
}
4964
privkey += 3;
5065
/* sequence element 1: octet string, up to 32 bytes */
51-
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
66+
if (end - privkey < 2 || privkey[0] != 0x04u) {
67+
return 0;
68+
}
69+
size_t oslen = privkey[1];
70+
privkey += 2;
71+
if (oslen > 32 || end - privkey < oslen) {
5272
return 0;
5373
}
54-
memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
74+
memcpy(out32 + (32 - oslen), privkey, oslen);
5575
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
5676
memset(out32, 0, 32);
5777
return 0;
5878
}
5979
return 1;
6080
}
6181

82+
/**
83+
* This serializes to a DER encoding of the ECPrivateKey type from section C.4 of SEC 1
84+
* <http://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are
85+
* included.
86+
*
87+
* privkey must point to an output buffer of length at least CKey::PRIVATE_KEY_SIZE bytes.
88+
* privkeylen must initially be set to the size of the privkey buffer. Upon return it
89+
* will be set to the number of bytes used in the buffer.
90+
* key32 must point to a 32-byte raw private key.
91+
*/
6292
static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
93+
assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE);
6394
secp256k1_pubkey pubkey;
6495
size_t pubkeylen = 0;
6596
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
@@ -85,10 +116,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr
85116
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
86117
memcpy(ptr, key32, 32); ptr += 32;
87118
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
88-
pubkeylen = 33;
119+
pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE;
89120
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
90121
ptr += pubkeylen;
91122
*privkeylen = ptr - privkey;
123+
assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE);
92124
} else {
93125
static const unsigned char begin[] = {
94126
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
@@ -110,10 +142,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr
110142
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
111143
memcpy(ptr, key32, 32); ptr += 32;
112144
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
113-
pubkeylen = 65;
145+
pubkeylen = CPubKey::PUBLIC_KEY_SIZE;
114146
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
115147
ptr += pubkeylen;
116148
*privkeylen = ptr - privkey;
149+
assert(*privkeylen == CKey::PRIVATE_KEY_SIZE);
117150
}
118151
return 1;
119152
}
@@ -135,8 +168,8 @@ CPrivKey CKey::GetPrivKey() const {
135168
CPrivKey privkey;
136169
int ret;
137170
size_t privkeylen;
138-
privkey.resize(279);
139-
privkeylen = 279;
171+
privkey.resize(PRIVATE_KEY_SIZE);
172+
privkeylen = PRIVATE_KEY_SIZE;
140173
ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*) privkey.data(), &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
141174
assert(ret);
142175
privkey.resize(privkeylen);
@@ -146,7 +179,7 @@ CPrivKey CKey::GetPrivKey() const {
146179
CPubKey CKey::GetPubKey() const {
147180
assert(fValid);
148181
secp256k1_pubkey pubkey;
149-
size_t clen = 65;
182+
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
150183
CPubKey result;
151184
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());
152185
assert(ret);
@@ -159,8 +192,8 @@ CPubKey CKey::GetPubKey() const {
159192
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const {
160193
if (!fValid)
161194
return false;
162-
vchSig.resize(72);
163-
size_t nSigLen = 72;
195+
vchSig.resize(CPubKey::SIGNATURE_SIZE);
196+
size_t nSigLen = CPubKey::SIGNATURE_SIZE;
164197
unsigned char extra_entropy[32] = {0};
165198
WriteLE32(extra_entropy, test_case);
166199
secp256k1_ecdsa_signature sig;
@@ -188,7 +221,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
188221
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
189222
if (!fValid)
190223
return false;
191-
vchSig.resize(65);
224+
vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE);
192225
int rec = -1;
193226
secp256k1_ecdsa_recoverable_signature sig;
194227
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr);
@@ -218,10 +251,10 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
218251
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
219252
if ((nChild >> 31) == 0) {
220253
CPubKey pubkey = GetPubKey();
221-
assert(pubkey.begin() + 33 == pubkey.end());
254+
assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
222255
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data());
223256
} else {
224-
assert(begin() + 32 == end());
257+
assert(size() == 32);
225258
BIP32Hash(cc, nChild, 0, begin(), vout.data());
226259
}
227260
memcpy(ccChild.begin(), vout.data()+32, 32);

src/key.h

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) 2009-2010 Satoshi Nakamoto
22
// Copyright (c) 2009-2016 The Bitcoin Core developers
3+
// Copyright (c) 2017 The Zcash developers
34
// Distributed under the MIT software license, see the accompanying
45
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
56

@@ -15,25 +16,30 @@
1516
#include <vector>
1617

1718

18-
/**
19-
* secp256k1:
20-
* const unsigned int PRIVATE_KEY_SIZE = 279;
21-
* const unsigned int PUBLIC_KEY_SIZE = 65;
22-
* const unsigned int SIGNATURE_SIZE = 72;
23-
*
24-
* see www.keylength.com
25-
* script supports up to 75 for single byte push
26-
*/
27-
2819
/**
2920
* secure_allocator is defined in allocators.h
30-
* CPrivKey is a serialized private key, with all parameters included (279 bytes)
21+
* CPrivKey is a serialized private key, with all parameters included
22+
* (PRIVATE_KEY_SIZE bytes)
3123
*/
3224
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
3325

3426
/** An encapsulated private key. */
3527
class CKey
3628
{
29+
public:
30+
/**
31+
* secp256k1:
32+
*/
33+
static const unsigned int PRIVATE_KEY_SIZE = 279;
34+
static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214;
35+
/**
36+
* see www.keylength.com
37+
* script supports up to 75 for single byte push
38+
*/
39+
static_assert(
40+
PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE,
41+
"COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE");
42+
3743
private:
3844
//! Whether this private key is valid. We check for correctness when modifying the key
3945
//! data, so fValid should always correspond to the actual state.

src/pubkey.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright (c) 2009-2016 The Bitcoin Core developers
2+
// Copyright (c) 2017 The Zcash developers
23
// Distributed under the MIT software license, see the accompanying
34
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
45

@@ -46,7 +47,7 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
4647
lenbyte = input[pos++];
4748
if (lenbyte & 0x80) {
4849
lenbyte -= 0x80;
49-
if (pos + lenbyte > inputlen) {
50+
if (lenbyte > inputlen - pos) {
5051
return 0;
5152
}
5253
pos += lenbyte;
@@ -65,14 +66,15 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
6566
lenbyte = input[pos++];
6667
if (lenbyte & 0x80) {
6768
lenbyte -= 0x80;
68-
if (pos + lenbyte > inputlen) {
69+
if (lenbyte > inputlen - pos) {
6970
return 0;
7071
}
7172
while (lenbyte > 0 && input[pos] == 0) {
7273
pos++;
7374
lenbyte--;
7475
}
75-
if (lenbyte >= sizeof(size_t)) {
76+
static_assert(sizeof(size_t) >= 4, "size_t too small");
77+
if (lenbyte >= 4) {
7678
return 0;
7779
}
7880
rlen = 0;
@@ -103,14 +105,15 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
103105
lenbyte = input[pos++];
104106
if (lenbyte & 0x80) {
105107
lenbyte -= 0x80;
106-
if (pos + lenbyte > inputlen) {
108+
if (lenbyte > inputlen - pos) {
107109
return 0;
108110
}
109111
while (lenbyte > 0 && input[pos] == 0) {
110112
pos++;
111113
lenbyte--;
112114
}
113-
if (lenbyte >= sizeof(size_t)) {
115+
static_assert(sizeof(size_t) >= 4, "size_t too small");
116+
if (lenbyte >= 4) {
114117
return 0;
115118
}
116119
slen = 0;
@@ -181,7 +184,7 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
181184
}
182185

183186
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
184-
if (vchSig.size() != 65)
187+
if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
185188
return false;
186189
int recid = (vchSig[0] - 27) & 3;
187190
bool fComp = ((vchSig[0] - 27) & 4) != 0;
@@ -193,8 +196,8 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha
193196
if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
194197
return false;
195198
}
196-
unsigned char pub[65];
197-
size_t publen = 65;
199+
unsigned char pub[PUBLIC_KEY_SIZE];
200+
size_t publen = PUBLIC_KEY_SIZE;
198201
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
199202
Set(pub, pub + publen);
200203
return true;
@@ -214,8 +217,8 @@ bool CPubKey::Decompress() {
214217
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
215218
return false;
216219
}
217-
unsigned char pub[65];
218-
size_t publen = 65;
220+
unsigned char pub[PUBLIC_KEY_SIZE];
221+
size_t publen = PUBLIC_KEY_SIZE;
219222
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
220223
Set(pub, pub + publen);
221224
return true;
@@ -224,7 +227,7 @@ bool CPubKey::Decompress() {
224227
bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
225228
assert(IsValid());
226229
assert((nChild >> 31) == 0);
227-
assert(begin() + 33 == end());
230+
assert(size() == COMPRESSED_PUBLIC_KEY_SIZE);
228231
unsigned char out[64];
229232
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
230233
memcpy(ccChild.begin(), out+32, 32);
@@ -235,8 +238,8 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
235238
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
236239
return false;
237240
}
238-
unsigned char pub[33];
239-
size_t publen = 33;
241+
unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE];
242+
size_t publen = COMPRESSED_PUBLIC_KEY_SIZE;
240243
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
241244
pubkeyChild.Set(pub, pub + publen);
242245
return true;
@@ -248,8 +251,8 @@ void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
248251
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
249252
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
250253
memcpy(code+9, chaincode.begin(), 32);
251-
assert(pubkey.size() == 33);
252-
memcpy(code+41, pubkey.begin(), 33);
254+
assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
255+
memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
253256
}
254257

255258
void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {

0 commit comments

Comments
 (0)