You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

paymentrequestplus.cpp 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright (c) 2011-2016 The Starwels developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. //
  5. // Wraps dumb protocol buffer paymentRequest
  6. // with some extra methods
  7. //
  8. #include "paymentrequestplus.h"
  9. #include "util.h"
  10. #include <stdexcept>
  11. #include <openssl/x509_vfy.h>
  12. #include <QDateTime>
  13. #include <QDebug>
  14. #include <QSslCertificate>
  15. class SSLVerifyError : public std::runtime_error
  16. {
  17. public:
  18. SSLVerifyError(std::string err) : std::runtime_error(err) { }
  19. };
  20. bool PaymentRequestPlus::parse(const QByteArray& data)
  21. {
  22. bool parseOK = paymentRequest.ParseFromArray(data.data(), data.size());
  23. if (!parseOK) {
  24. qWarning() << "PaymentRequestPlus::parse: Error parsing payment request";
  25. return false;
  26. }
  27. if (paymentRequest.payment_details_version() > 1) {
  28. qWarning() << "PaymentRequestPlus::parse: Received up-version payment details, version=" << paymentRequest.payment_details_version();
  29. return false;
  30. }
  31. parseOK = details.ParseFromString(paymentRequest.serialized_payment_details());
  32. if (!parseOK)
  33. {
  34. qWarning() << "PaymentRequestPlus::parse: Error parsing payment details";
  35. paymentRequest.Clear();
  36. return false;
  37. }
  38. return true;
  39. }
  40. bool PaymentRequestPlus::SerializeToString(std::string* output) const
  41. {
  42. return paymentRequest.SerializeToString(output);
  43. }
  44. bool PaymentRequestPlus::IsInitialized() const
  45. {
  46. return paymentRequest.IsInitialized();
  47. }
  48. bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) const
  49. {
  50. merchant.clear();
  51. if (!IsInitialized())
  52. return false;
  53. // One day we'll support more PKI types, but just
  54. // x509 for now:
  55. const EVP_MD* digestAlgorithm = nullptr;
  56. if (paymentRequest.pki_type() == "x509+sha256") {
  57. digestAlgorithm = EVP_sha256();
  58. }
  59. else if (paymentRequest.pki_type() == "x509+sha1") {
  60. digestAlgorithm = EVP_sha1();
  61. }
  62. else if (paymentRequest.pki_type() == "none") {
  63. qWarning() << "PaymentRequestPlus::getMerchant: Payment request: pki_type == none";
  64. return false;
  65. }
  66. else {
  67. qWarning() << "PaymentRequestPlus::getMerchant: Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type());
  68. return false;
  69. }
  70. payments::X509Certificates certChain;
  71. if (!certChain.ParseFromString(paymentRequest.pki_data())) {
  72. qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error parsing pki_data";
  73. return false;
  74. }
  75. std::vector<X509*> certs;
  76. const QDateTime currentTime = QDateTime::currentDateTime();
  77. for (int i = 0; i < certChain.certificate_size(); i++) {
  78. QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size());
  79. QSslCertificate qCert(certData, QSsl::Der);
  80. if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) {
  81. qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate expired or not yet active: " << qCert;
  82. return false;
  83. }
  84. #if QT_VERSION >= 0x050000
  85. if (qCert.isBlacklisted()) {
  86. qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate blacklisted: " << qCert;
  87. return false;
  88. }
  89. #endif
  90. const unsigned char *data = (const unsigned char *)certChain.certificate(i).data();
  91. X509 *cert = d2i_X509(nullptr, &data, certChain.certificate(i).size());
  92. if (cert)
  93. certs.push_back(cert);
  94. }
  95. if (certs.empty()) {
  96. qWarning() << "PaymentRequestPlus::getMerchant: Payment request: empty certificate chain";
  97. return false;
  98. }
  99. // The first cert is the signing cert, the rest are untrusted certs that chain
  100. // to a valid root authority. OpenSSL needs them separately.
  101. STACK_OF(X509) *chain = sk_X509_new_null();
  102. for (int i = certs.size() - 1; i > 0; i--) {
  103. sk_X509_push(chain, certs[i]);
  104. }
  105. X509 *signing_cert = certs[0];
  106. // Now create a "store context", which is a single use object for checking,
  107. // load the signing cert into it and verify.
  108. X509_STORE_CTX *store_ctx = X509_STORE_CTX_new();
  109. if (!store_ctx) {
  110. qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error creating X509_STORE_CTX";
  111. return false;
  112. }
  113. char *website = nullptr;
  114. bool fResult = true;
  115. try
  116. {
  117. if (!X509_STORE_CTX_init(store_ctx, certStore, signing_cert, chain))
  118. {
  119. int error = X509_STORE_CTX_get_error(store_ctx);
  120. throw SSLVerifyError(X509_verify_cert_error_string(error));
  121. }
  122. // Now do the verification!
  123. int result = X509_verify_cert(store_ctx);
  124. if (result != 1) {
  125. int error = X509_STORE_CTX_get_error(store_ctx);
  126. // For testing payment requests, we allow self signed root certs!
  127. // This option is just shown in the UI options, if -help-debug is enabled.
  128. if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && gArgs.GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS))) {
  129. throw SSLVerifyError(X509_verify_cert_error_string(error));
  130. } else {
  131. qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true.";
  132. }
  133. }
  134. X509_NAME *certname = X509_get_subject_name(signing_cert);
  135. // Valid cert; check signature:
  136. payments::PaymentRequest rcopy(paymentRequest); // Copy
  137. rcopy.set_signature(std::string(""));
  138. std::string data_to_verify; // Everything but the signature
  139. rcopy.SerializeToString(&data_to_verify);
  140. #if HAVE_DECL_EVP_MD_CTX_NEW
  141. EVP_MD_CTX *ctx = EVP_MD_CTX_new();
  142. if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context.");
  143. #else
  144. EVP_MD_CTX _ctx;
  145. EVP_MD_CTX *ctx;
  146. ctx = &_ctx;
  147. #endif
  148. EVP_PKEY *pubkey = X509_get_pubkey(signing_cert);
  149. EVP_MD_CTX_init(ctx);
  150. if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, nullptr) ||
  151. !EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) ||
  152. !EVP_VerifyFinal(ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) {
  153. throw SSLVerifyError("Bad signature, invalid payment request.");
  154. }
  155. #if HAVE_DECL_EVP_MD_CTX_NEW
  156. EVP_MD_CTX_free(ctx);
  157. #endif
  158. // OpenSSL API for getting human printable strings from certs is baroque.
  159. int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, nullptr, 0);
  160. website = new char[textlen + 1];
  161. if (X509_NAME_get_text_by_NID(certname, NID_commonName, website, textlen + 1) == textlen && textlen > 0) {
  162. merchant = website;
  163. }
  164. else {
  165. throw SSLVerifyError("Bad certificate, missing common name.");
  166. }
  167. // TODO: detect EV certificates and set merchant = business name instead of unfriendly NID_commonName ?
  168. }
  169. catch (const SSLVerifyError& err) {
  170. fResult = false;
  171. qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err.what();
  172. }
  173. if (website)
  174. delete[] website;
  175. X509_STORE_CTX_free(store_ctx);
  176. for (unsigned int i = 0; i < certs.size(); i++)
  177. X509_free(certs[i]);
  178. return fResult;
  179. }
  180. QList<std::pair<CScript,CAmount> > PaymentRequestPlus::getPayTo() const
  181. {
  182. QList<std::pair<CScript,CAmount> > result;
  183. for (int i = 0; i < details.outputs_size(); i++)
  184. {
  185. const unsigned char* scriptStr = (const unsigned char*)details.outputs(i).script().data();
  186. CScript s(scriptStr, scriptStr+details.outputs(i).script().size());
  187. result.append(std::make_pair(s, details.outputs(i).amount()));
  188. }
  189. return result;
  190. }