diff --git a/folly/io/async/AsyncTransportCertificate.h b/folly/io/async/AsyncTransportCertificate.h index ea45c051e39..86df6157d1f 100644 --- a/folly/io/async/AsyncTransportCertificate.h +++ b/folly/io/async/AsyncTransportCertificate.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace folly { @@ -37,5 +38,16 @@ class AsyncTransportCertificate { * implementations of AsyncTransport. */ virtual std::string getIdentity() const = 0; + + /** + * Returns the DER representation of this certificate, if available. + * + * NOTE: Not every AsyncTransportCertificate implementation will + * have a DER representation. Whenever possible, applications should + * prefer to structure logic around the _identity_ that the + * certificate conveys (with `getIdentity()`), rather than + * certificate itself. + */ + virtual std::optional getDER() const = 0; }; } // namespace folly diff --git a/folly/io/async/ssl/OpenSSLTransportCertificate.h b/folly/io/async/ssl/OpenSSLTransportCertificate.h index 3901415eda7..433ab2efe5d 100644 --- a/folly/io/async/ssl/OpenSSLTransportCertificate.h +++ b/folly/io/async/ssl/OpenSSLTransportCertificate.h @@ -36,6 +36,27 @@ class OpenSSLTransportCertificate : virtual public AsyncTransportCertificate { */ virtual folly::ssl::X509UniquePtr getX509() const = 0; + virtual std::optional getDER() const override { + auto x509 = getX509(); + if (!x509) { + return std::nullopt; + } + + int len = i2d_X509(x509.get(), nullptr); + if (len < 0) { + return std::nullopt; + } + + std::string der(len, '\0'); + auto derPtr = reinterpret_cast(der.data()); + + if (i2d_X509(x509.get(), &derPtr) < 0) { + return std::nullopt; + } + + return der; + } + static ssl::X509UniquePtr tryExtractX509( const AsyncTransportCertificate* cert) { auto opensslCert = dynamic_cast(cert);