I've been away doing other projects but spent a few hours playing with cbitcoin this evening and found a few more bugs and possible solutions. I've compiled some unified diffs. The diffs are between the current git repository and a fork (named cbitcoin-2014-03-21).
1. Function CBNewBlockChainStorage() crashes when trying to free self->database which is never initialized at this point. At this point, the function is doing cleanup on an error but should just free self since everything before it has already been freed.
--- ./library/dependencies/storage/CBBlockChainStorage.c 2014-03-21 19:53:02.744321264 -0400
+++ ../cbitcoin-2014-03-21/./library/dependencies/storage/CBBlockChainStorage.c 2014-03-21 01:17:12.000000000 -0400
@@ -38,7 +38,7 @@
CBFreeIndex(self->blockHashIndex);
}
CBLogError("Could not load one of the block chain storage indices.");
- CBFreeDatabase(self->database);
+ free(self);
return false;
}
void CBFreeBlockChainStorage(CBDepObject self){
2. Function CBOnUpToDate is never declared (nor do I know how to use it) nor is CBCallBacks callbacks initialized to point to it. This then crashes cbitcoin example server whenever some routine tries to access callbacks->updatetodate. Simple fix.
--- ./client-server/src/main.c 2014-03-21 19:53:02.738321373 -0400
+++ ../cbitcoin-2014-03-21/./client-server/src/main.c 2014-03-21 18:36:45.608202593 -0400
@@ -66,6 +66,9 @@
void CBOnTransactionUnconfirmed(CBNode * node, uint8_t * txHash){
}
+void CBOnUpToDate(CBNode * node, bool truefalse){
+
+}
CBNetworkAddress * CBReadNetworkAddress(char * ipStr, bool isPublic){
CBSocketAddress saddr = {NULL, 8333};
char * portStart;
@@ -286,7 +289,8 @@
CBOnNewTransaction,
CBOnTransactionConfirmed,
CBOnDoubleSpend,
- CBOnTransactionUnconfirmed
+ CBOnTransactionUnconfirmed,
+ CBOnUpToDate
};
CBNodeFull * node = CBNewNodeFull(database, nodeFlags, otherTxsSizeLimit, callbacks);
if (!node) {
3. This is a tricky one. in CBEcdsaVerify() if o2i_ECPublicKey() fails it writes a NULL into key which EC_KEY then tries to free. Result: crash. This is a work around which creates two copies of the new EC_KEY. If key gets stomped on then we can free the copy in eckey. Interestingly, ECDSA_verify harmlessly passes over any NULL value in key (although I wouldn't count on any future version doing so).
--- ./library/dependencies/crypto/CBOpenSSLCrypto.c 2014-03-21 19:53:02.741321318 -0400
+++ ../cbitcoin-2014-03-21/./library/dependencies/crypto/CBOpenSSLCrypto.c 2014-03-21 19:44:44.181601752 -0400
@@ -84,9 +84,13 @@
RIPEMD160(data, len, output);
}
bool CBEcdsaVerify(uint8_t * signature, uint8_t sigLen, uint8_t * hash, uint8_t * pubKey, uint8_t keyLen){
- EC_KEY * key = EC_KEY_new_by_curve_name(NID_secp256k1);
+ EC_KEY *eckey, * key;
+ int res = 0;
+
+ eckey = key = EC_KEY_new_by_curve_name(NID_secp256k1);
o2i_ECPublicKey(&key, (const unsigned char **)&pubKey, keyLen);
- int res = ECDSA_verify(0, hash, 32, signature, sigLen, key);
- EC_KEY_free(key);
+ if ( key != NULL )
+ res = ECDSA_verify(0, hash, 32, signature, sigLen, key);
+ EC_KEY_free(eckey);
return res == 1;
}