Commit ba690cad authored by Kyle Nekritz's avatar Kyle Nekritz Committed by Facebook Github Bot

Add OpenSSLCertUtils functions for DER encoding/decoding.

Reviewed By: anirudhvr

Differential Revision: D5193205

fbshipit-source-id: 5b427ee4f31008518078f5e54e85c0f0f2201da5
parent 7dc11fbd
...@@ -173,5 +173,28 @@ std::string OpenSSLCertUtils::getDateTimeStr(const ASN1_TIME* time) { ...@@ -173,5 +173,28 @@ std::string OpenSSLCertUtils::getDateTimeStr(const ASN1_TIME* time) {
return std::string(bioData, bioLen); return std::string(bioData, bioLen);
} }
X509UniquePtr OpenSSLCertUtils::derDecode(ByteRange range) {
auto begin = range.data();
X509UniquePtr cert(d2i_X509(nullptr, &begin, range.size()));
if (!cert) {
throw std::runtime_error("could not read cert");
}
return cert;
}
std::unique_ptr<IOBuf> OpenSSLCertUtils::derEncode(X509& x509) {
auto len = i2d_X509(&x509, nullptr);
if (len < 0) {
throw std::runtime_error("Error computing length");
}
auto buf = IOBuf::create(len);
auto dataPtr = buf->writableData();
len = i2d_X509(&x509, &dataPtr);
if (len < 0) {
throw std::runtime_error("Error converting cert to DER");
}
buf->append(len);
return buf;
}
} // ssl } // ssl
} // folly } // folly
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
#include <vector> #include <vector>
#include <folly/Optional.h> #include <folly/Optional.h>
#include <folly/io/IOBuf.h>
#include <folly/portability/OpenSSL.h> #include <folly/portability/OpenSSL.h>
#include <folly/ssl/OpenSSLPtrTypes.h>
namespace folly { namespace folly {
namespace ssl { namespace ssl {
...@@ -60,6 +62,20 @@ class OpenSSLCertUtils { ...@@ -60,6 +62,20 @@ class OpenSSLCertUtils {
*/ */
static folly::Optional<std::string> toString(X509& x509); static folly::Optional<std::string> toString(X509& x509);
/**
* Decodes the DER representation of an X509 certificate.
*
* Throws on error (if a valid certificate can't be decoded).
*/
static X509UniquePtr derDecode(ByteRange);
/**
* DER encodes an X509 certificate.
*
* Throws on error.
*/
static std::unique_ptr<IOBuf> derEncode(X509&);
private: private:
static std::string getDateTimeStr(const ASN1_TIME* time); static std::string getDateTimeStr(const ASN1_TIME* time);
}; };
......
...@@ -18,9 +18,10 @@ ...@@ -18,9 +18,10 @@
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/String.h> #include <folly/String.h>
#include <folly/ssl/OpenSSLPtrTypes.h> #include <folly/io/async/SSLContext.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/portability/OpenSSL.h> #include <folly/portability/OpenSSL.h>
#include <folly/ssl/OpenSSLPtrTypes.h>
using namespace testing; using namespace testing;
using namespace folly; using namespace folly;
...@@ -56,6 +57,13 @@ const std::string kTestCertWithSan = folly::stripLeftMargin(R"( ...@@ -56,6 +57,13 @@ const std::string kTestCertWithSan = folly::stripLeftMargin(R"(
-----END CERTIFICATE----- -----END CERTIFICATE-----
)"); )");
class OpenSSLCertUtilsTest : public Test {
public:
void SetUp() override {
SSLContext::initializeOpenSSL();
}
};
static folly::ssl::X509UniquePtr readCertFromFile(const std::string& filename) { static folly::ssl::X509UniquePtr readCertFromFile(const std::string& filename) {
folly::ssl::BioUniquePtr bio(BIO_new(BIO_s_file())); folly::ssl::BioUniquePtr bio(BIO_new(BIO_s_file()));
if (!bio) { if (!bio) {
...@@ -79,9 +87,7 @@ static folly::ssl::X509UniquePtr readCertFromData( ...@@ -79,9 +87,7 @@ static folly::ssl::X509UniquePtr readCertFromData(
PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
} }
TEST(OpenSSLCertUtilsTest, TestX509CN) { TEST_F(OpenSSLCertUtilsTest, TestX509CN) {
OpenSSL_add_all_algorithms();
auto x509 = readCertFromFile(kTestCertWithoutSan); auto x509 = readCertFromFile(kTestCertWithoutSan);
EXPECT_NE(x509, nullptr); EXPECT_NE(x509, nullptr);
auto identity = folly::ssl::OpenSSLCertUtils::getCommonName(*x509); auto identity = folly::ssl::OpenSSLCertUtils::getCommonName(*x509);
...@@ -90,9 +96,7 @@ TEST(OpenSSLCertUtilsTest, TestX509CN) { ...@@ -90,9 +96,7 @@ TEST(OpenSSLCertUtilsTest, TestX509CN) {
EXPECT_EQ(sans.size(), 0); EXPECT_EQ(sans.size(), 0);
} }
TEST(OpenSSLCertUtilsTest, TestX509Sans) { TEST_F(OpenSSLCertUtilsTest, TestX509Sans) {
OpenSSL_add_all_algorithms();
auto x509 = readCertFromData(kTestCertWithSan); auto x509 = readCertFromData(kTestCertWithSan);
EXPECT_NE(x509, nullptr); EXPECT_NE(x509, nullptr);
auto identity = folly::ssl::OpenSSLCertUtils::getCommonName(*x509); auto identity = folly::ssl::OpenSSLCertUtils::getCommonName(*x509);
...@@ -103,9 +107,7 @@ TEST(OpenSSLCertUtilsTest, TestX509Sans) { ...@@ -103,9 +107,7 @@ TEST(OpenSSLCertUtilsTest, TestX509Sans) {
EXPECT_EQ(altNames[1], "*.thirdexample.com"); EXPECT_EQ(altNames[1], "*.thirdexample.com");
} }
TEST(OpenSSLCertUtilsTest, TestX509IssuerAndSubject) { TEST_F(OpenSSLCertUtilsTest, TestX509IssuerAndSubject) {
OpenSSL_add_all_algorithms();
auto x509 = readCertFromData(kTestCertWithSan); auto x509 = readCertFromData(kTestCertWithSan);
EXPECT_NE(x509, nullptr); EXPECT_NE(x509, nullptr);
auto issuer = folly::ssl::OpenSSLCertUtils::getIssuer(*x509); auto issuer = folly::ssl::OpenSSLCertUtils::getIssuer(*x509);
...@@ -116,9 +118,7 @@ TEST(OpenSSLCertUtilsTest, TestX509IssuerAndSubject) { ...@@ -116,9 +118,7 @@ TEST(OpenSSLCertUtilsTest, TestX509IssuerAndSubject) {
EXPECT_EQ(subj.value(), "C = US, O = Asox, CN = 127.0.0.1"); EXPECT_EQ(subj.value(), "C = US, O = Asox, CN = 127.0.0.1");
} }
TEST(OpenSSLCertUtilsTest, TestX509Dates) { TEST_F(OpenSSLCertUtilsTest, TestX509Dates) {
OpenSSL_add_all_algorithms();
auto x509 = readCertFromData(kTestCertWithSan); auto x509 = readCertFromData(kTestCertWithSan);
EXPECT_NE(x509, nullptr); EXPECT_NE(x509, nullptr);
auto notBefore = folly::ssl::OpenSSLCertUtils::getNotBeforeTime(*x509); auto notBefore = folly::ssl::OpenSSLCertUtils::getNotBeforeTime(*x509);
...@@ -127,9 +127,7 @@ TEST(OpenSSLCertUtilsTest, TestX509Dates) { ...@@ -127,9 +127,7 @@ TEST(OpenSSLCertUtilsTest, TestX509Dates) {
EXPECT_EQ(notAfter, "Jul 1 23:21:03 2044 GMT"); EXPECT_EQ(notAfter, "Jul 1 23:21:03 2044 GMT");
} }
TEST(OpenSSLCertUtilsTest, TestX509Summary) { TEST_F(OpenSSLCertUtilsTest, TestX509Summary) {
OpenSSL_add_all_algorithms();
auto x509 = readCertFromData(kTestCertWithSan); auto x509 = readCertFromData(kTestCertWithSan);
EXPECT_NE(x509, nullptr); EXPECT_NE(x509, nullptr);
auto summary = folly::ssl::OpenSSLCertUtils::toString(*x509); auto summary = folly::ssl::OpenSSLCertUtils::toString(*x509);
...@@ -154,3 +152,30 @@ TEST(OpenSSLCertUtilsTest, TestX509Summary) { ...@@ -154,3 +152,30 @@ TEST(OpenSSLCertUtilsTest, TestX509Summary) {
" Authority Information Access: \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"); " CA Issuers - URI:https://phabricator.fb.com/diffusion/FBCODE/browse/master/ti/test_certs/ca_cert.pem?view=raw\n\n");
} }
TEST_F(OpenSSLCertUtilsTest, TestDerEncodeDecode) {
auto x509 = readCertFromData(kTestCertWithSan);
auto der = folly::ssl::OpenSSLCertUtils::derEncode(*x509);
auto decoded = folly::ssl::OpenSSLCertUtils::derDecode(der->coalesce());
EXPECT_EQ(
folly::ssl::OpenSSLCertUtils::toString(*x509),
folly::ssl::OpenSSLCertUtils::toString(*decoded));
}
TEST_F(OpenSSLCertUtilsTest, TestDerDecodeJunkData) {
StringPiece junk{"MyFakeCertificate"};
EXPECT_THROW(
folly::ssl::OpenSSLCertUtils::derDecode(junk), std::runtime_error);
}
TEST_F(OpenSSLCertUtilsTest, TestDerDecodeTooShort) {
auto x509 = readCertFromData(kTestCertWithSan);
auto der = folly::ssl::OpenSSLCertUtils::derEncode(*x509);
der->trimEnd(1);
EXPECT_THROW(
folly::ssl::OpenSSLCertUtils::derDecode(der->coalesce()),
std::runtime_error);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment