return ret;
}
+void AsyncSSLSocket::setSSLCertVerificationAlert(std::string alert) {
+ sslVerificationAlert_ = std::move(alert);
+}
+
+std::string AsyncSSLSocket::getSSLCertVerificationAlert() const {
+ return sslVerificationAlert_;
+}
+
void AsyncSSLSocket::getSSLSharedCiphers(std::string& sharedCiphers) const {
char ciphersBuffer[1024];
ciphersBuffer[0] = '\0';
std::string getSSLAlertsReceived() const;
+ /*
+ * Save an optional alert message generated during certificate verify
+ */
+ void setSSLCertVerificationAlert(std::string alert);
+
+ std::string getSSLCertVerificationAlert() const;
+
/**
* Get the list of shared ciphers between the server and the client.
* Works well for only SSLv2, not so good for SSLv3 or TLSv1.
std::chrono::milliseconds totalConnectTimeout_{0};
std::unique_ptr<IOBuf> preReceivedData_;
+ std::string sslVerificationAlert_;
};
} // namespace
* limitations under the License.
*/
#include <folly/ssl/OpenSSLCertUtils.h>
+#include <folly/String.h>
+#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
}
return ret;
}
+
+Optional<std::string> OpenSSLCertUtils::getSubject(X509& x509) {
+ auto subject = X509_get_subject_name(&x509);
+ if (!subject) {
+ return none;
+ }
+
+ auto bio = BioUniquePtr(BIO_new(BIO_s_mem()));
+ if (bio == nullptr) {
+ throw std::runtime_error("Cannot allocate bio");
+ }
+ if (X509_NAME_print_ex(bio.get(), subject, 0, XN_FLAG_ONELINE) <= 0) {
+ return none;
+ }
+
+ char* bioData = nullptr;
+ size_t bioLen = BIO_get_mem_data(bio.get(), &bioData);
+ return std::string(bioData, bioLen);
}
+
+Optional<std::string> OpenSSLCertUtils::getIssuer(X509& x509) {
+ auto issuer = X509_get_issuer_name(&x509);
+ if (!issuer) {
+ return none;
+ }
+
+ auto bio = BioUniquePtr(BIO_new(BIO_s_mem()));
+ if (bio == nullptr) {
+ throw std::runtime_error("Cannot allocate bio");
+ }
+
+ if (X509_NAME_print_ex(bio.get(), issuer, 0, XN_FLAG_ONELINE) <= 0) {
+ return none;
+ }
+
+ char* bioData = nullptr;
+ size_t bioLen = BIO_get_mem_data(bio.get(), &bioData);
+ return std::string(bioData, bioLen);
}
+
+folly::Optional<std::string> OpenSSLCertUtils::toString(X509& x509) {
+ auto in = BioUniquePtr(BIO_new(BIO_s_mem()));
+ if (in == nullptr) {
+ throw std::runtime_error("Cannot allocate bio");
+ }
+
+ if (X509_print_ex(
+ in.get(),
+ &x509,
+ XN_FLAG_ONELINE,
+ X509_FLAG_NO_HEADER | /* A few bytes of cert and data */
+ X509_FLAG_NO_PUBKEY | /* Public key */
+ X509_FLAG_NO_IDS | /* Issuer/subject IDs */
+ X509_FLAG_NO_AUX | /* Auxiliary info? */
+ X509_FLAG_NO_SIGDUMP | /* Prints the signature */
+ X509_FLAG_NO_SIGNAME /* Signature algorithms */
+ ) > 0) {
+ char* bioData = nullptr;
+ size_t bioLen = BIO_get_mem_data(in.get(), &bioData);
+ return std::string(bioData, bioLen);
+ } else {
+ return none;
+ }
+}
+
+std::string OpenSSLCertUtils::getNotAfterTime(X509& x509) {
+ return getDateTimeStr(X509_get_notAfter(&x509));
+}
+
+std::string OpenSSLCertUtils::getNotBeforeTime(X509& x509) {
+ return getDateTimeStr(X509_get_notBefore(&x509));
+}
+
+std::string OpenSSLCertUtils::getDateTimeStr(const ASN1_TIME* time) {
+ if (!time) {
+ return "";
+ }
+
+ std::array<char, 32> buf;
+
+ auto bio = BioUniquePtr(BIO_new(BIO_s_mem()));
+ if (bio == nullptr) {
+ throw std::runtime_error("Cannot allocate bio");
+ }
+
+ if (ASN1_TIME_print(bio.get(), time) <= 0) {
+ throw std::runtime_error("Cannot print ASN1_TIME");
+ }
+
+ char* bioData = nullptr;
+ size_t bioLen = BIO_get_mem_data(bio.get(), &bioData);
+ return std::string(bioData, bioLen);
+}
+
+} // ssl
+} // folly
static Optional<std::string> getCommonName(X509& x509);
static std::vector<std::string> getSubjectAltNames(X509& x509);
+
+ /*
+ * Return the subject name, if any, from the cert
+ * @param x509 Reference to an X509
+ * @return a folly::Optional<std::string>, or folly::none
+ */
+ static Optional<std::string> getSubject(X509& x509);
+
+ /*
+ * Return the issuer name, if any, from the cert
+ * @param x509 Reference to an X509
+ * @return a folly::Optional<std::string>, or folly::none
+ */
+ static Optional<std::string> getIssuer(X509& x509);
+
+ /*
+ * Get a string representation of the not-before time on the certificate
+ */
+ static std::string getNotBeforeTime(X509& x509);
+
+ /*
+ * Get a string representation of the not-after (expiration) time
+ */
+ static std::string getNotAfterTime(X509& x509);
+
+ /*
+ * Summarize the CN, Subject, Issuer, Validity, and extensions as a string
+ */
+ static folly::Optional<std::string> toString(X509& x509);
+
+ private:
+ static std::string getDateTimeStr(const ASN1_TIME* time);
};
}
}
EXPECT_EQ(altNames[0], "anotherexample.com");
EXPECT_EQ(altNames[1], "*.thirdexample.com");
}
+
+TEST(OpenSSLCertUtilsTest, TestX509IssuerAndSubject) {
+ OpenSSL_add_all_algorithms();
+
+ auto x509 = readCertFromData(kTestCertWithSan);
+ EXPECT_NE(x509, nullptr);
+ auto issuer = folly::ssl::OpenSSLCertUtils::getIssuer(*x509);
+ EXPECT_EQ(
+ issuer.value(),
+ "C = US, ST = CA, O = Asox, CN = Asox Certification Authority");
+ auto subj = folly::ssl::OpenSSLCertUtils::getSubject(*x509);
+ EXPECT_EQ(subj.value(), "C = US, O = Asox, CN = 127.0.0.1");
+}
+
+TEST(OpenSSLCertUtilsTest, TestX509Dates) {
+ OpenSSL_add_all_algorithms();
+
+ auto x509 = readCertFromData(kTestCertWithSan);
+ EXPECT_NE(x509, nullptr);
+ auto notBefore = folly::ssl::OpenSSLCertUtils::getNotBeforeTime(*x509);
+ EXPECT_EQ(notBefore, "Feb 13 23:21:03 2017 GMT");
+ auto notAfter = folly::ssl::OpenSSLCertUtils::getNotAfterTime(*x509);
+ EXPECT_EQ(notAfter, "Jul 1 23:21:03 2044 GMT");
+}
+
+TEST(OpenSSLCertUtilsTest, TestX509Summary) {
+ OpenSSL_add_all_algorithms();
+
+ auto x509 = readCertFromData(kTestCertWithSan);
+ EXPECT_NE(x509, nullptr);
+ auto summary = folly::ssl::OpenSSLCertUtils::toString(*x509);
+ EXPECT_EQ(
+ summary.value(),
+ " Version: 3 (0x2)\n Serial Number: 2 (0x2)\n"
+ " Issuer: C = US, ST = CA, O = Asox, CN = Asox Certification Authority\n"
+ " Validity\n Not Before: Feb 13 23:21:03 2017 GMT\n"
+ " Not After : Jul 1 23:21:03 2044 GMT\n"
+ " Subject: C = US, O = Asox, CN = 127.0.0.1\n"
+ " X509v3 extensions:\n"
+ " X509v3 Basic Constraints: \n"
+ " CA:FALSE\n"
+ " Netscape Comment: \n"
+ " OpenSSL Generated Certificate\n"
+ " X509v3 Subject Key Identifier: \n"
+ " 71:D6:49:9D:64:47:D7:1E:65:8B:1E:94:83:23:42:E1:F2:19:9F:C3\n"
+ " X509v3 Authority Key Identifier: \n"
+ " keyid:17:DF:29:09:29:BF:7B:9F:1A:7F:E9:46:49:C8:3B:ED:B3:B9:E8:7B\n\n"
+ " X509v3 Subject Alternative Name: \n"
+ " DNS:anotherexample.com, DNS:*.thirdexample.com\n"
+ " Authority Information Access: \n"
+ " CA Issuers - URI:https://phabricator.fb.com/diffusion/FBCODE/browse/master/ti/test_certs/ca_cert.pem?view=raw\n\n");
+}