void SSLContext::loadCertificateFromBufferPEM(folly::StringPiece cert) { if (cert.data() == nullptr) { throw std::invalid_argument("loadCertificate: <cert> is nullptr"); } ssl::BioUniquePtr bio(BIO_new(BIO_s_mem())); if (bio == nullptr) { throw std::runtime_error("BIO_new: " + getErrors()); } int written = BIO_write(bio.get(), cert.data(), cert.size()); if (written <= 0 || static_cast<unsigned>(written) != cert.size()) { throw std::runtime_error("BIO_write: " + getErrors()); } ssl::X509UniquePtr x509( PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); if (x509 == nullptr) { throw std::runtime_error("PEM_read_bio_X509: " + getErrors()); } if (SSL_CTX_use_certificate(ctx_, x509.get()) == 0) { throw std::runtime_error("SSL_CTX_use_certificate: " + getErrors()); } }
int SSLManager::verifyCallback(bool server, int ok, X509_STORE_CTX* pStore) { if (!ok) { X509* pCert = X509_STORE_CTX_get_current_cert(pStore); X509Certificate x509(pCert); int depth = X509_STORE_CTX_get_error_depth(pStore); int err = X509_STORE_CTX_get_error(pStore); std::string error(X509_verify_cert_error_string(err)); VerificationErrorArgs args(x509, depth, err, error); if (server) SSLManager::instance().ServerVerificationError.notify(&SSLManager::instance(), args); else SSLManager::instance().ClientVerificationError.notify(&SSLManager::instance(), args); ok = args.getIgnoreError() ? 1 : 0; } return ok; }
/** * Verify signature with RSA public key from X.509 certificate. * * @param digestMethod digest method (e.g NID_sha1 for SHA1, see openssl/obj_mac.h). * @param digest digest value, this value is compared with the digest value decrypted from the <code>signature</code>. * @param signature signature value, this value is decrypted to get the digest and compared with * the digest value provided in <code>digest</code>. * @return returns <code>true</code> if the signature value matches with the digest, otherwise <code>false</code> * is returned. * @throws IOException throws exception if X.509 certificate is not missing or does not have a RSA public key. */ bool digidoc::RSACrypt::verify(int digestMethod, std::vector<unsigned char> digest, std::vector<unsigned char> signature) throw(IOException) { // Check that X.509 certificate is set. if(cert == NULL) { THROW_IOEXCEPTION("X.509 certificate parameter is not set in RSACrypt, can not verify signature."); } // Extract RSA public key from X.509 certificate. X509Cert x509(cert); EVP_PKEY* key = x509.getPublicKey(); if(EVP_PKEY_type(key->type) != EVP_PKEY_RSA) { EVP_PKEY_free(key); THROW_IOEXCEPTION("Certificate '%s' does not have a RSA public key, can not verify signature.", x509.getSubject().c_str()); } RSA* publicKey = EVP_PKEY_get1_RSA(key); // Verify signature with RSA public key. int result = RSA_verify(digestMethod, &digest[0], digest.size(), &signature[0], signature.size(), publicKey); RSA_free(publicKey); EVP_PKEY_free(key); return (result == 1); }
// // Load OpenSSL's list of root certificate authorities // void PaymentServer::LoadRootCAs(X509_STORE* _store) { // Unit tests mostly use this, to pass in fake root CAs: if (_store) { certStore.reset(_store); return; } // Normal execution, use either -rootcertificates or system certs: certStore.reset(X509_STORE_new()); // Note: use "-system-" default here so that users can pass -rootcertificates="" // and get 'I don't like X.509 certificates, don't trust anybody' behavior: QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-")); // Empty store if (certFile.isEmpty()) { qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__); return; } QList<QSslCertificate> certList; if (certFile != "-system-") { qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile); certList = QSslCertificate::fromPath(certFile); // Use those certificates when fetching payment requests, too: QSslSocket::setDefaultCaCertificates(certList); } else certList = QSslSocket::systemCaCertificates(); int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); for (const QSslCertificate& cert : certList) { // Don't log NULL certificates if (cert.isNull()) continue; // Not yet active/valid, or expired certificate if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) { ReportInvalidCertificate(cert); continue; } #if QT_VERSION >= 0x050000 // Blacklisted certificate if (cert.isBlacklisted()) { ReportInvalidCertificate(cert); continue; } #endif QByteArray certData = cert.toDer(); const unsigned char *data = (const unsigned char *)certData.data(); std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size())); if (x509 && X509_STORE_add_cert(certStore.get(), x509.get())) { // Note: X509_STORE increases the reference count to the X509 object, // we still have to release our reference to it. ++nRootCerts; } else { ReportInvalidCertificate(cert); continue; } } qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates"; // Project for another day: // Fetch certificate revocation lists, and add them to certStore. // Issues to consider: // performance (start a thread to fetch in background?) // privacy (fetch through tor/proxy so IP address isn't revealed) // would it be easier to just use a compiled-in blacklist? // or use Qt's blacklist? // "certificate stapling" with server-side caching is more efficient }
void CertManager::CopySelfCert(const x509* x) { if (x) list_.push_back(NEW_YS x509(*x)); }
void SecureServer::generateCertificate(const std::string& publicKey, const std::string& privateKey, const std::string& password, const long& secsValid, const std::vector<std::pair<std::string,std::string> >& x509Entries, const std::string& x509Filename) throw (boost::system::system_error) { std::cerr << "generating certificate" << std::endl; std::unique_ptr<X509,void (*)(X509*)> x509(X509_new(), &X509_free); if(ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), std::time(nullptr)) != 1){ throw_system_error_ssl("Could not set X509 parameters"); } X509_gmtime_adj(X509_get_notBefore(x509.get()), 0); X509_gmtime_adj(X509_get_notAfter(x509.get()), secsValid); std::unique_ptr<EVP_PKEY,void(*)(EVP_PKEY*)> privKey(EVP_PKEY_new(), &EVP_PKEY_free); std::unique_ptr<EVP_PKEY,void(*)(EVP_PKEY*)> pubKey(EVP_PKEY_new(), &EVP_PKEY_free); std::unique_ptr<BIO,void (*)(BIO*)> privateBIO(BIO_new_file(privateKey.c_str(), "r"), &BIO_free_all); if(!privateBIO){ throw_system_error_ssl("Could not open "+privateKey+" for reading"); } pem_password_cb* password_cb(nullptr); void *password_u(nullptr); if(!password.empty()){ password_cb = &pemPasswordCBFromString; password_u = (void*)&password; } std::unique_ptr<RSA,void(*)(RSA*)> rsa(PEM_read_bio_RSAPrivateKey(privateBIO.get(), nullptr, password_cb, password_u),&RSA_free); if(!rsa){ throw_system_error_ssl("Could not read PEM RSA private key from "+privateKey); } std::cerr << "read " << privateKey << std::endl; if(EVP_PKEY_set1_RSA(privKey.get(), rsa.get()) != 1){ throw_system_error_ssl("Could not assign EVP_PKEY from RSA private key"); } std::cerr << "assigned EVP_PKEY" << std::endl; std::unique_ptr<BIO,void (*)(BIO*)> publicBIO(BIO_new_file(publicKey.c_str(), "r"), &BIO_free_all); if(!publicBIO){ throw_system_error_ssl("Could not open "+publicKey+" for reading"); } RSA *ptr = rsa.get(); if(PEM_read_bio_RSAPublicKey(publicBIO.get(),&ptr,nullptr,nullptr) == nullptr){ throw_system_error_ssl("Could not read PEM RSA public key from "+publicKey); } std::cerr << "read " << publicKey << std::endl; if(EVP_PKEY_set1_RSA(pubKey.get(), rsa.get()) != 1){ throw_system_error_ssl("Could not assign EVP_PKEY from RSA public key"); } if(X509_set_pubkey(x509.get(), pubKey.get()) != 1){ throw_system_error_ssl("Could nost assign X509 public key from EVP_PKEY"); } X509_NAME *name = X509_get_subject_name(x509.get()); std::cerr << "got subject name" << std::endl; for(const std::pair<std::string,std::string>& entry : x509Entries){ if(X509_NAME_add_entry_by_txt(name, entry.first.c_str(), MBSTRING_ASC, (const unsigned char*)entry.second.c_str(), entry.second.length(), -1, 0) != 1){ throw_system_error_ssl("Could not add X509 entry /"+entry.first+"/ = \""+entry.second+'"'); } std::cerr << "added entry /" << entry.first << "/ = \"" << entry.second << '"' << std::endl; } if(X509_set_issuer_name(x509.get(),name) != 1){ throw_system_error_ssl("Could not set X509 issuer name"); } std::cerr << "set issuer name" << std::endl; std::unique_ptr<EVP_MD_CTX,void(*)(EVP_MD_CTX*)> mctx(EVP_MD_CTX_create(),&EVP_MD_CTX_destroy); // EVP_PKEY_CTX *pkctx(nullptr); if(EVP_DigestSignInit(mctx.get(),nullptr,EVP_sha256(),nullptr,privKey.get()) != 1){ throw_system_error_ssl("Could not init EVP Digest Sign"); } std::cerr << "initialized EVP MD CTX" << std::endl; if(X509_sign_ctx(x509.get(),mctx.get()) <= 0){ throw_system_error_ssl("Could not sign certificate"); } std::cerr << "signed" << std::endl; std::unique_ptr<BIO,void(*)(BIO*)> x509BIO(BIO_new_file(x509Filename.c_str(),"w"),&BIO_free_all); if(PEM_write_bio_X509(x509BIO.get(),x509.get()) != 1){ throw_system_error_ssl("Could not write X509 certificate"); } std::cerr << "written to " << x509Filename << std::endl; }