[paymentservertests] fix certificates and payment requests
Summary:
Procedure:
git clone git@github.com:gavinandresen/paymentrequest.git cd paymentrequest ca_in_a_box/create_ca.sh ca_in_a_box/create_intermediate_cas.sh # get caCert1_BASE64 (root authority) openssl x509 -in ca_in_a_box/certs/cacert.pem -inform PEM -outform DER | openssl enc -base64 cd c++ # ... fix outdated openssl code and then compile make mv ../ca_in_a_box . # get paymentrequest1_cert1_BASE64 by running the program with default certs and privatekey ./paymentrequest-create paytoaddress=1Nf4eZ76SFZdhrHVNLQkLAiS1oPPGaZxSv amount=42 expires=1986627327 | ./paymentrequest-dump ./paymentrequest-create paytoaddress=1Nf4eZ76SFZdhrHVNLQkLAiS1oPPGaZxSv amount=42 expires=1986627327 | base64 # get paymentrequest3_cert1_BASE64 by chaining the certificates ./paymentrequest-create paytoaddress=1Nf4eZ76SFZdhrHVNLQkLAiS1oPPGaZxSv amount=42 expires=4826525372 payment_url=testmerchant8.org certificates=./ca_in_a_box/intermediate_8/certs/demomerchant.pem,./ca_in_a_box/intermediate_8/certs/cacert.pem,./ca_in_a_box/intermediate_7/certs/cacert.pem,./ca_in_a_box/intermediate_6/certs/cacert.pem,./ca_in_a_box/intermediate_5/certs/cacert.pem,./ca_in_a_box/intermediate_4/certs/cacert.pem,./ca_in_a_box/intermediate_3/certs/cacert.pem,./ca_in_a_box/intermediate_2/certs/cacert.pem,./ca_in_a_box/intermediate_1/certs/cacert.pem,./ca_in_a_box/certs/cacert.pem privatekey=./ca_in_a_box/intermediate_8/private/demomerchantkey.pem | base64
The patch to fix the outdated OpenSSL code is:
diff --git a/c++/paymentrequest-create.cpp b/c++/paymentrequest-create.cpp index 5fdbc8c..69d5b8d 100644 --- a/c++/paymentrequest-create.cpp +++ b/c++/paymentrequest-create.cpp @@ -178,16 +178,17 @@ bool decode_base58(const string& btcaddress, unsigned char& version, string& has unsigned char decoded[25]; size_t nBytes = 0; - BIGNUM bn58, bn, bnChar; + BIGNUM *bn58, *bn, *bnChar; BN_CTX *ctx; ctx = BN_CTX_new(); - BN_init(&bn58); - BN_init(&bn); - BN_init(&bnChar); - BN_set_word(&bn58, 58); - BN_set_word(&bn, 0); + bn58 = BN_new(); + bn = BN_new(); + bnChar = BN_new(); + + BN_set_word(bn58, 58); + BN_set_word(bn, 0); for (unsigned int i = 0; i < btcaddress.length(); i++) { const char *p1 = strchr(base58_chars, btcaddress[i]); @@ -195,23 +196,23 @@ bool decode_base58(const string& btcaddress, unsigned char& version, string& has goto out; } - BN_set_word(&bnChar, p1 - base58_chars); + BN_set_word(bnChar, p1 - base58_chars); - assert(BN_mul(&bn, &bn, &bn58, ctx)); - assert(BN_add(&bn, &bn, &bnChar)); + assert(BN_mul(bn, bn, bn58, ctx)); + assert(BN_add(bn, bn, bnChar)); } - nBytes = BN_num_bytes(&bn); + nBytes = BN_num_bytes(bn); if (nBytes == 0 || nBytes > 25) return false; std::fill(decoded, decoded+25, (unsigned char)0); - BN_bn2bin(&bn, &decoded[25-nBytes]); + BN_bn2bin(bn, &decoded[25-nBytes]); out: - BN_clear_free(&bn58); - BN_clear_free(&bn); - BN_clear_free(&bnChar); + BN_clear_free(bn58); + BN_clear_free(bn); + BN_clear_free(bnChar); BN_CTX_free(ctx); version = decoded[0]; diff --git a/c++/paymentrequest-dump.cpp b/c++/paymentrequest-dump.cpp index d20e400..d28d1dd 100644 --- a/c++/paymentrequest-dump.cpp +++ b/c++/paymentrequest-dump.cpp @@ -133,12 +133,14 @@ int main(int argc, char **argv) { request.SerializeToString(&data_to_verify); request.set_signature(signature); - EVP_MD_CTX ctx; + EVP_MD_CTX *ctx; + ctx = EVP_MD_CTX_new(); + EVP_PKEY *pubkey = X509_get_pubkey(signing_cert); - EVP_MD_CTX_init(&ctx); - if (!EVP_VerifyInit_ex(&ctx, digestAlgorithm, NULL) || - !EVP_VerifyUpdate(&ctx, data_to_verify.data(), data_to_verify.size()) || - !EVP_VerifyFinal(&ctx, (const unsigned char*)signature.data(), signature.size(), pubkey)) { + EVP_MD_CTX_init(ctx); + if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, NULL) || + !EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) || + !EVP_VerifyFinal(ctx, (const unsigned char*)signature.data(), signature.size(), pubkey)) { printf("Bad signature, invalid PaymentRequest.\n"); }
Notes:
- the merchant certificate is the first in the chain, then all the intermediate certificate authorities in reverse order, and finally the root certificate authority. The private key is the one for the merchant.
- do not run the create_ca.sh and create_intermediate_cas.sh more than once, or delete the previous results in between two runs. This is because re-running it causes some or all keys to be overwritten, but it fails to recreate the new corresponding certs.
Test Plan: ninja check-bitcoin-qt
Reviewers: #bitcoin_abc, Fabien
Reviewed By: #bitcoin_abc, Fabien
Differential Revision: https://reviews.bitcoinabc.org/D12887