1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 // Wraps dumb protocol buffer paymentRequest
7 // with some extra methods
10 #include "paymentrequestplus.h"
16 #include <openssl/x509_vfy.h>
20 #include <QSslCertificate>
22 class SSLVerifyError
: public std::runtime_error
25 explicit SSLVerifyError(std::string err
) : std::runtime_error(err
) { }
28 bool PaymentRequestPlus::parse(const QByteArray
& data
)
30 bool parseOK
= paymentRequest
.ParseFromArray(data
.data(), data
.size());
32 qWarning() << "PaymentRequestPlus::parse: Error parsing payment request";
35 if (paymentRequest
.payment_details_version() > 1) {
36 qWarning() << "PaymentRequestPlus::parse: Received up-version payment details, version=" << paymentRequest
.payment_details_version();
40 parseOK
= details
.ParseFromString(paymentRequest
.serialized_payment_details());
43 qWarning() << "PaymentRequestPlus::parse: Error parsing payment details";
44 paymentRequest
.Clear();
50 bool PaymentRequestPlus::SerializeToString(std::string
* output
) const
52 return paymentRequest
.SerializeToString(output
);
55 bool PaymentRequestPlus::IsInitialized() const
57 return paymentRequest
.IsInitialized();
60 bool PaymentRequestPlus::getMerchant(X509_STORE
* certStore
, QString
& merchant
) const
67 // One day we'll support more PKI types, but just
69 const EVP_MD
* digestAlgorithm
= nullptr;
70 if (paymentRequest
.pki_type() == "x509+sha256") {
71 digestAlgorithm
= EVP_sha256();
73 else if (paymentRequest
.pki_type() == "x509+sha1") {
74 digestAlgorithm
= EVP_sha1();
76 else if (paymentRequest
.pki_type() == "none") {
77 qWarning() << "PaymentRequestPlus::getMerchant: Payment request: pki_type == none";
81 qWarning() << "PaymentRequestPlus::getMerchant: Payment request: unknown pki_type " << QString::fromStdString(paymentRequest
.pki_type());
85 payments::X509Certificates certChain
;
86 if (!certChain
.ParseFromString(paymentRequest
.pki_data())) {
87 qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error parsing pki_data";
91 std::vector
<X509
*> certs
;
92 const QDateTime currentTime
= QDateTime::currentDateTime();
93 for (int i
= 0; i
< certChain
.certificate_size(); i
++) {
94 QByteArray
certData(certChain
.certificate(i
).data(), certChain
.certificate(i
).size());
95 QSslCertificate
qCert(certData
, QSsl::Der
);
96 if (currentTime
< qCert
.effectiveDate() || currentTime
> qCert
.expiryDate()) {
97 qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate expired or not yet active: " << qCert
;
100 #if QT_VERSION >= 0x050000
101 if (qCert
.isBlacklisted()) {
102 qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate blacklisted: " << qCert
;
106 const unsigned char *data
= (const unsigned char *)certChain
.certificate(i
).data();
107 X509
*cert
= d2i_X509(nullptr, &data
, certChain
.certificate(i
).size());
109 certs
.push_back(cert
);
112 qWarning() << "PaymentRequestPlus::getMerchant: Payment request: empty certificate chain";
116 // The first cert is the signing cert, the rest are untrusted certs that chain
117 // to a valid root authority. OpenSSL needs them separately.
118 STACK_OF(X509
) *chain
= sk_X509_new_null();
119 for (int i
= certs
.size() - 1; i
> 0; i
--) {
120 sk_X509_push(chain
, certs
[i
]);
122 X509
*signing_cert
= certs
[0];
124 // Now create a "store context", which is a single use object for checking,
125 // load the signing cert into it and verify.
126 X509_STORE_CTX
*store_ctx
= X509_STORE_CTX_new();
128 qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error creating X509_STORE_CTX";
132 char *website
= nullptr;
136 if (!X509_STORE_CTX_init(store_ctx
, certStore
, signing_cert
, chain
))
138 int error
= X509_STORE_CTX_get_error(store_ctx
);
139 throw SSLVerifyError(X509_verify_cert_error_string(error
));
142 // Now do the verification!
143 int result
= X509_verify_cert(store_ctx
);
145 int error
= X509_STORE_CTX_get_error(store_ctx
);
146 // For testing payment requests, we allow self signed root certs!
147 // This option is just shown in the UI options, if -help-debug is enabled.
148 if (!(error
== X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
&& gArgs
.GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS
))) {
149 throw SSLVerifyError(X509_verify_cert_error_string(error
));
151 qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true.";
154 X509_NAME
*certname
= X509_get_subject_name(signing_cert
);
156 // Valid cert; check signature:
157 payments::PaymentRequest
rcopy(paymentRequest
); // Copy
158 rcopy
.set_signature(std::string(""));
159 std::string data_to_verify
; // Everything but the signature
160 rcopy
.SerializeToString(&data_to_verify
);
162 #if HAVE_DECL_EVP_MD_CTX_NEW
163 EVP_MD_CTX
*ctx
= EVP_MD_CTX_new();
164 if (!ctx
) throw SSLVerifyError("Error allocating OpenSSL context.");
170 EVP_PKEY
*pubkey
= X509_get_pubkey(signing_cert
);
171 EVP_MD_CTX_init(ctx
);
172 if (!EVP_VerifyInit_ex(ctx
, digestAlgorithm
, nullptr) ||
173 !EVP_VerifyUpdate(ctx
, data_to_verify
.data(), data_to_verify
.size()) ||
174 !EVP_VerifyFinal(ctx
, (const unsigned char*)paymentRequest
.signature().data(), (unsigned int)paymentRequest
.signature().size(), pubkey
)) {
175 throw SSLVerifyError("Bad signature, invalid payment request.");
177 #if HAVE_DECL_EVP_MD_CTX_NEW
178 EVP_MD_CTX_free(ctx
);
181 // OpenSSL API for getting human printable strings from certs is baroque.
182 int textlen
= X509_NAME_get_text_by_NID(certname
, NID_commonName
, nullptr, 0);
183 website
= new char[textlen
+ 1];
184 if (X509_NAME_get_text_by_NID(certname
, NID_commonName
, website
, textlen
+ 1) == textlen
&& textlen
> 0) {
188 throw SSLVerifyError("Bad certificate, missing common name.");
190 // TODO: detect EV certificates and set merchant = business name instead of unfriendly NID_commonName ?
192 catch (const SSLVerifyError
& err
) {
194 qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err
.what();
199 X509_STORE_CTX_free(store_ctx
);
200 for (unsigned int i
= 0; i
< certs
.size(); i
++)
206 QList
<std::pair
<CScript
,CAmount
> > PaymentRequestPlus::getPayTo() const
208 QList
<std::pair
<CScript
,CAmount
> > result
;
209 for (int i
= 0; i
< details
.outputs_size(); i
++)
211 const unsigned char* scriptStr
= (const unsigned char*)details
.outputs(i
).script().data();
212 CScript
s(scriptStr
, scriptStr
+details
.outputs(i
).script().size());
214 result
.append(std::make_pair(s
, details
.outputs(i
).amount()));