// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <map>
-#include <boost/tuple/tuple.hpp>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include "key.h"
-#include "util.h"
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
-// if check is nonzero, additional checks are performed
+// if check is non-zero, additional checks are performed
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{
if (!eckey) return 0;
return ret;
}
+int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
+ while (c1len > c2len) {
+ if (*c1)
+ return 1;
+ c1++;
+ c1len--;
+ }
+ while (c2len > c1len) {
+ if (*c2)
+ return -1;
+ c2++;
+ c2len--;
+ }
+ while (c1len > 0) {
+ if (*c1 > *c2)
+ return 1;
+ if (*c2 > *c1)
+ return -1;
+ c1++;
+ c2++;
+ c1len--;
+ }
+ return 0;
+}
+
+// Order of secp256k1's generator minus 1.
+const unsigned char vchMaxModOrder[32] = {
+ 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,0x40
+};
+
+// Half of the order of secp256k1's generator minus 1.
+const unsigned char vchMaxModHalfOrder[32] = {
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D,
+ 0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0
+};
+
+const unsigned char *vchZero = NULL;
+
+
+
void CKey::SetCompressedPubKey()
{
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
void CKey::Reset()
{
fCompressedPubKey = false;
+ if (pkey != NULL)
+ EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (pkey == NULL)
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
CKey::CKey()
{
+ pkey = NULL;
Reset();
}
return fCompressedPubKey;
}
+bool CKey::CheckSignatureElement(const unsigned char *vch, int len, bool half) {
+ return CompareBigEndian(vch, len, vchZero, 0) > 0 &&
+ CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0;
+}
+
void CKey::MakeNewKey(bool fCompressed)
{
if (!EC_KEY_generate_key(pkey))
bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
{
const unsigned char* pbegin = &vchPrivKey[0];
- if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
- return false;
- fSet = true;
- return true;
+ if (d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
+ {
+ // In testing, d2i_ECPrivateKey can return true
+ // but fill in pkey with a key that fails
+ // EC_KEY_check_key, so:
+ if (EC_KEY_check_key(pkey))
+ {
+ fSet = true;
+ return true;
+ }
+ }
+ // If vchPrivKey data is bad d2i_ECPrivateKey() can
+ // leave pkey in a state where calling EC_KEY_free()
+ // crashes. To avoid that, set pkey to NULL and
+ // leak the memory (a leak is better than a crash)
+ pkey = NULL;
+ Reset();
+ return false;
}
bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
return vchPrivKey;
}
-bool CKey::SetPubKey(const std::vector<unsigned char>& vchPubKey)
+bool CKey::SetPubKey(const CPubKey& vchPubKey)
{
- const unsigned char* pbegin = &vchPubKey[0];
- if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
- return false;
- fSet = true;
- if (vchPubKey.size() == 33)
- SetCompressedPubKey();
- return true;
+ const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
+ if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
+ {
+ fSet = true;
+ if (vchPubKey.vchPubKey.size() == 33)
+ SetCompressedPubKey();
+ return true;
+ }
+ pkey = NULL;
+ Reset();
+ return false;
}
-std::vector<unsigned char> CKey::GetPubKey() const
+CPubKey CKey::GetPubKey() const
{
int nSize = i2o_ECPublicKey(pkey, NULL);
if (!nSize)
unsigned char* pbegin = &vchPubKey[0];
if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
- return vchPubKey;
+ return CPubKey(vchPubKey);
}
bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
{
+ vchSig.clear();
+ ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
+ if (sig==NULL)
+ return false;
+ const EC_GROUP *group = EC_KEY_get0_group(pkey);
+ CBigNum order, halforder;
+ EC_GROUP_get_order(group, &order, NULL);
+ BN_rshift1(&halforder, &order);
+ // enforce low S values, by negating the value (modulo the order) if above order/2.
+ if (BN_cmp(sig->s, &halforder) > 0) {
+ BN_sub(sig->s, &order, sig->s);
+ }
unsigned int nSize = ECDSA_size(pkey);
vchSig.resize(nSize); // Make sure it is big enough
- if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
- {
+ unsigned char *pos = &vchSig[0];
+ nSize = i2d_ECDSA_SIG(sig, &pos);
+ ECDSA_SIG_free(sig);
+ vchSig.resize(nSize); // Shrink to fit actual size
+ // Testing our new signature
+ if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) {
vchSig.clear();
return false;
}
- vchSig.resize(nSize); // Shrink to fit actual size
return true;
}
ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
if (sig==NULL)
return false;
+ const EC_GROUP *group = EC_KEY_get0_group(pkey);
+ CBigNum order, halforder;
+ EC_GROUP_get_order(group, &order, NULL);
+ BN_rshift1(&halforder, &order);
+ // enforce low S values, by negating the value (modulo the order) if above order/2.
+ if (BN_cmp(sig->s, &halforder) > 0) {
+ BN_sub(sig->s, &order, sig->s);
+ }
vchSig.clear();
vchSig.resize(65,0);
int nBitsR = BN_num_bits(sig->r);
}
if (nRecId == -1)
+ {
+ ECDSA_SIG_free(sig);
throw key_error("CKey::SignCompact() : unable to construct recoverable key");
+ }
vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
ECDSA_SIG_free(sig);
return true;
}
+ ECDSA_SIG_free(sig);
return false;
}
-// Valid signature cache, to avoid doing expensive ECDSA signature checking
-// twice for every transaction (once when accepted into memory pool, and
-// again when accepted into the block chain)
-
-// sigdata_type is (signature hash, signature, public key):
-typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type;
-static std::set< sigdata_type> setValidSigCache;
-static CCriticalSection cs_sigcache;
-
-static bool
-GetValidSigCache(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
-{
- LOCK(cs_sigcache);
-
- sigdata_type k(hash, vchSig, pubKey);
- std::set<sigdata_type>::iterator mi = setValidSigCache.find(k);
- if (mi != setValidSigCache.end())
- return true;
- return false;
-}
-
-static void
-SetValidSigCache(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
{
- // DoS prevention: limit cache size to less than 10MB
- // (~200 bytes per cache entry times 50,000 entries)
- // Since there are a maximum of 20,000 signature operations per block
- // 50,000 is a reasonable default.
- int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
- if (nMaxCacheSize <= 0) return;
-
- LOCK(cs_sigcache);
+ if (vchSig.empty())
+ return false;
- while (setValidSigCache.size() > nMaxCacheSize)
+ // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
+ unsigned char *norm_der = NULL;
+ ECDSA_SIG *norm_sig = ECDSA_SIG_new();
+ const unsigned char* sigptr = &vchSig[0];
+ assert(norm_sig);
+ if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL)
{
- // Evict a random entry. Random because that helps
- // foil would-be DoS attackers who might try to pre-generate
- // and re-use a set of valid signatures just-slightly-greater
- // than our cache size.
- uint256 randomHash = GetRandHash();
- std::vector<unsigned char> unused;
- std::set<sigdata_type>::iterator it =
- setValidSigCache.lower_bound(sigdata_type(randomHash, unused, unused));
- if (it == setValidSigCache.end())
- it = setValidSigCache.begin();
- setValidSigCache.erase(*it);
+ /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on
+ * error. But OpenSSL's own use of this function redundantly frees the
+ * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a
+ * clear contract for the function behaving the same way is more
+ * conservative.
+ */
+ ECDSA_SIG_free(norm_sig);
+ return false;
}
-
- sigdata_type k(hash, vchSig, pubKey);
- setValidSigCache.insert(k);
-}
-
-
-bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
-{
- if (GetValidSigCache(hash, vchSig, GetPubKey()))
- return true;
-
- // -1 = error, 0 = bad sig, 1 = good
- if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
+ int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der);
+ ECDSA_SIG_free(norm_sig);
+ if (derlen <= 0)
return false;
- // good sig
- SetValidSigCache(hash, vchSig, GetPubKey());
- return true;
+ // -1 = error, 0 = bad sig, 1 = good
+ bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1;
+ OPENSSL_free(norm_der);
+ return ret;
}
bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
{
- if (GetValidSigCache(hash, vchSig, GetPubKey()))
- return true;
-
CKey key;
if (!key.SetCompactSignature(hash, vchSig))
return false;
if (GetPubKey() != key.GetPubKey())
return false;
- SetValidSigCache(hash, vchSig, GetPubKey());
return true;
}
if (!fSet)
return false;
+ if (!EC_KEY_check_key(pkey))
+ return false;
+
bool fCompr;
CSecret secret = GetSecret(fCompr);
CKey key2;