Add wrapper for getting X509_digest from a cert
authorAnirudh Ramachandran <avr@fb.com>
Mon, 4 Dec 2017 07:56:21 +0000 (23:56 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Mon, 4 Dec 2017 08:07:27 +0000 (00:07 -0800)
Summary:
X509_digest, or the "fingerprint" of the cert, is useful to identify
certificates with the same CN/SANs. This adds an API to get the SHA1 or SHA256
digest of a cert.

Reviewed By: yfeldblum

Differential Revision: D6457917

fbshipit-source-id: 148a5a2270e938b39065e00d7947c2fc57cd7f75

folly/ssl/OpenSSLCertUtils.cpp
folly/ssl/OpenSSLCertUtils.h
folly/ssl/test/OpenSSLCertUtilsTest.cpp

index 9b9efa3eb3f89401f2e303a485dbda7efb00f207..ac7cd7414f2159e68be9ce587e0624080cd9aa2e 100644 (file)
@@ -216,5 +216,30 @@ std::vector<X509UniquePtr> OpenSSLCertUtils::readCertsFromBuffer(
   return certs;
 }
 
+std::array<uint8_t, SHA_DIGEST_LENGTH> OpenSSLCertUtils::getDigestSha1(
+    X509& x509) {
+  unsigned int len;
+  std::array<uint8_t, SHA_DIGEST_LENGTH> md;
+  int rc = X509_digest(&x509, EVP_sha1(), md.data(), &len);
+
+  if (rc <= 0) {
+    throw std::runtime_error("Could not calculate SHA1 digest for cert");
+  }
+  return md;
+}
+
+std::array<uint8_t, SHA256_DIGEST_LENGTH> OpenSSLCertUtils::getDigestSha256(
+    X509& x509) {
+  unsigned int len;
+  std::array<uint8_t, SHA256_DIGEST_LENGTH> md;
+  int rc = X509_digest(&x509, EVP_sha256(), md.data(), &len);
+
+  if (rc <= 0) {
+    throw std::runtime_error("Could not calculate SHA256 digest for cert");
+  }
+  return md;
+}
+
+
 } // namespace ssl
 } // namespace folly
index 1f5f63d22c6bf3155af84a991c188f6786b02af6..31273d02ae797814d643ad0ca99b6802bf0ebd6b 100644 (file)
@@ -82,6 +82,14 @@ class OpenSSLCertUtils {
    */
   static std::vector<X509UniquePtr> readCertsFromBuffer(ByteRange);
 
+  /**
+   * Return the output of the X509_digest for chosen message-digest algo
+   * NOTE: The returned digest will be in binary, and may need to be
+   * hex-encoded
+   */
+  static std::array<uint8_t, SHA_DIGEST_LENGTH> getDigestSha1(X509& x509);
+  static std::array<uint8_t, SHA256_DIGEST_LENGTH> getDigestSha256(X509& x509);
+
  private:
   static std::string getDateTimeStr(const ASN1_TIME* time);
 };
index 41af7dc19ea69d5aebaffa3a7fe055f711d97f42..ac747b3321b9487415108b08ce1d3d31a1c5dd9a 100644 (file)
@@ -258,3 +258,18 @@ TEST_F(OpenSSLCertUtilsTest, TestReadCertsFromBuffer) {
     EXPECT_EQ(*identity, folly::sformat("test cert {}", i.index + 1));
   }
 }
+
+TEST_F(OpenSSLCertUtilsTest, TestX509Digest) {
+  auto x509 = readCertFromFile(kTestCertWithoutSan);
+  EXPECT_NE(x509, nullptr);
+
+  auto sha1Digest = folly::ssl::OpenSSLCertUtils::getDigestSha1(*x509);
+  EXPECT_EQ(
+      folly::hexlify(folly::range(sha1Digest)),
+      "b84e951d6c4e6cc70346357fab43d7ed73a07b0f");
+
+  auto sha2Digest = folly::ssl::OpenSSLCertUtils::getDigestSha256(*x509);
+  EXPECT_EQ(
+      folly::hexlify(folly::range(sha2Digest)),
+      "364d3a6a0b10d0635ce59b40c0b7f505ab2cd9fd0a06661cdc61d9cb8c9c9821");
+}