io/async/EventUtil.h \
io/async/NotificationQueue.h \
io/async/HHWheelTimer.h \
- io/async/OpenSSLPtrTypes.h \
+ io/async/ssl/OpenSSLPtrTypes.h \
+ io/async/ssl/OpenSSLUtils.h \
+ io/async/ssl/TLSDefinitions.h \
io/async/Request.h \
io/async/SSLContext.h \
io/async/ScopedEventBaseThread.h \
io/async/HHWheelTimer.cpp \
io/async/test/SocketPair.cpp \
io/async/test/TimeUtil.cpp \
+ io/async/ssl/OpenSSLUtils.cpp \
json.cpp \
detail/MemoryIdler.cpp \
MacAddress.cpp \
void AsyncSSLSocket::enableClientHelloParsing() {
parseClientHello_ = true;
- clientHelloInfo_.reset(new ClientHelloInfo());
+ clientHelloInfo_.reset(new ssl::ClientHelloInfo());
}
void AsyncSSLSocket::resetClientHelloParsing(SSL *ssl) {
if (cursor.totalLength() > 0) {
uint16_t extensionsLength = cursor.readBE<uint16_t>();
while (extensionsLength) {
- TLSExtension extensionType = static_cast<TLSExtension>(
- cursor.readBE<uint16_t>());
+ ssl::TLSExtension extensionType =
+ static_cast<ssl::TLSExtension>(cursor.readBE<uint16_t>());
sock->clientHelloInfo_->
clientHelloExtensions_.push_back(extensionType);
extensionsLength -= 2;
uint16_t extensionDataLength = cursor.readBE<uint16_t>();
extensionsLength -= 2;
- if (extensionType == TLSExtension::SIGNATURE_ALGORITHMS) {
+ if (extensionType == ssl::TLSExtension::SIGNATURE_ALGORITHMS) {
cursor.skip(2);
extensionDataLength -= 2;
while (extensionDataLength) {
- HashAlgorithm hashAlg = static_cast<HashAlgorithm>(
- cursor.readBE<uint8_t>());
- SignatureAlgorithm sigAlg = static_cast<SignatureAlgorithm>(
- cursor.readBE<uint8_t>());
+ ssl::HashAlgorithm hashAlg =
+ static_cast<ssl::HashAlgorithm>(cursor.readBE<uint8_t>());
+ ssl::SignatureAlgorithm sigAlg =
+ static_cast<ssl::SignatureAlgorithm>(cursor.readBE<uint8_t>());
extensionDataLength -= 2;
sock->clientHelloInfo_->
clientHelloSigAlgs_.emplace_back(hashAlg, sigAlg);
#include <folly/Optional.h>
#include <folly/String.h>
#include <folly/io/async/AsyncSocket.h>
-#include <folly/io/async/SSLContext.h>
#include <folly/io/async/AsyncTimeout.h>
-#include <folly/io/async/OpenSSLPtrTypes.h>
+#include <folly/io/async/SSLContext.h>
#include <folly/io/async/TimeoutManager.h>
+#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
+#include <folly/io/async/ssl/OpenSSLUtils.h>
+#include <folly/io/async/ssl/TLSDefinitions.h>
#include <folly/Bits.h>
#include <folly/io/IOBuf.h>
int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
static const char* getSSLServerNameFromSSL(SSL* ssl);
- // http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
- enum class TLSExtension: uint16_t {
- SERVER_NAME = 0,
- MAX_FRAGMENT_LENGTH = 1,
- CLIENT_CERTIFICATE_URL = 2,
- TRUSTED_CA_KEYS = 3,
- TRUNCATED_HMAC = 4,
- STATUS_REQUEST = 5,
- USER_MAPPING = 6,
- CLIENT_AUTHZ = 7,
- SERVER_AUTHZ = 8,
- CERT_TYPE = 9,
- SUPPORTED_GROUPS = 10,
- EC_POINT_FORMATS = 11,
- SRP = 12,
- SIGNATURE_ALGORITHMS = 13,
- USE_SRTP = 14,
- HEARTBEAT = 15,
- APPLICATION_LAYER_PROTOCOL_NEGOTIATION = 16,
- STATUS_REQUEST_V2 = 17,
- SIGNED_CERTIFICATE_TIMESTAMP = 18,
- CLIENT_CERTIFICATE_TYPE = 19,
- SERVER_CERTIFICATE_TYPE = 20,
- PADDING = 21,
- ENCRYPT_THEN_MAC = 22,
- EXTENDED_MASTER_SECRET = 23,
- SESSION_TICKET = 35,
- RENEGOTIATION_INFO = 65281
- };
-
- // http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18
- enum class HashAlgorithm: uint8_t {
- NONE = 0,
- MD5 = 1,
- SHA1 = 2,
- SHA224 = 3,
- SHA256 = 4,
- SHA384 = 5,
- SHA512 = 6
- };
-
- // http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16
- enum class SignatureAlgorithm: uint8_t {
- ANONYMOUS = 0,
- RSA = 1,
- DSA = 2,
- ECDSA = 3
- };
-
- struct ClientHelloInfo {
- folly::IOBufQueue clientHelloBuf_;
- uint8_t clientHelloMajorVersion_;
- uint8_t clientHelloMinorVersion_;
- std::vector<uint16_t> clientHelloCipherSuites_;
- std::vector<uint8_t> clientHelloCompressionMethods_;
- std::vector<TLSExtension> clientHelloExtensions_;
- std::vector<
- std::pair<HashAlgorithm, SignatureAlgorithm>> clientHelloSigAlgs_;
- };
-
// For unit-tests
- ClientHelloInfo* getClientHelloInfo() const {
+ ssl::ClientHelloInfo* getClientHelloInfo() const {
return clientHelloInfo_.get();
}
/**
* Returns the peer certificate, or nullptr if no peer certificate received.
*/
- virtual X509_UniquePtr getPeerCert() const override {
+ virtual ssl::X509UniquePtr getPeerCert() const override {
if (!ssl_) {
return nullptr;
}
X509* cert = SSL_get_peer_certificate(ssl_);
- return X509_UniquePtr(cert);
+ return ssl::X509UniquePtr(cert);
}
/**
bool parseClientHello_{false};
bool cacheAddrOnFailure_{false};
- std::unique_ptr<ClientHelloInfo> clientHelloInfo_;
+ std::unique_ptr<ssl::ClientHelloInfo> clientHelloInfo_;
// Time taken to complete the ssl handshake.
std::chrono::steady_clock::time_point handshakeStartTime_;
#include <sys/uio.h>
#include <folly/io/IOBuf.h>
+#include <folly/io/async/AsyncSocketBase.h>
#include <folly/io/async/DelayedDestruction.h>
#include <folly/io/async/EventBase.h>
-#include <folly/io/async/AsyncSocketBase.h>
-#include <folly/io/async/OpenSSLPtrTypes.h>
+#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
#include <openssl/ssl.h>
/**
* Get the certificate used to authenticate the peer.
*/
- virtual X509_UniquePtr getPeerCert() const { return nullptr; }
+ virtual ssl::X509UniquePtr getPeerCert() const { return nullptr; }
/**
* @return True iff end of record tracking is enabled
+++ /dev/null
-/*
- * Copyright 2016 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/Memory.h>
-#include <openssl/ssl.h>
-
-namespace folly {
-
-using X509_deleter = static_function_deleter<X509, &X509_free>;
-using X509_UniquePtr = std::unique_ptr<X509, X509_deleter>;
-
-using EVP_PKEY_deleter =
- folly::static_function_deleter<EVP_PKEY, &EVP_PKEY_free>;
-using EVP_PKEY_UniquePtr = std::unique_ptr<EVP_PKEY, EVP_PKEY_deleter>;
-
-using SSL_deleter = folly::static_function_deleter<SSL, &SSL_free>;
-using SSL_UniquePtr = std::unique_ptr<SSL, SSL_deleter>;
-}
#include <folly/Format.h>
#include <folly/Memory.h>
#include <folly/SpinLock.h>
-#include <folly/io/async/OpenSSLPtrTypes.h>
// ---------------------------------------------------------------------
// SSLContext implementation
return m;
}
-inline void BIO_free_fb(BIO* bio) { CHECK_EQ(1, BIO_free(bio)); }
-using BIO_deleter = folly::static_function_deleter<BIO, &BIO_free_fb>;
-
} // anonymous namespace
#ifdef OPENSSL_NPN_NEGOTIATED
throw std::invalid_argument("loadCertificate: <cert> is nullptr");
}
- std::unique_ptr<BIO, BIO_deleter> bio(BIO_new(BIO_s_mem()));
+ ssl::BioUniquePtr bio(BIO_new(BIO_s_mem()));
if (bio == nullptr) {
throw std::runtime_error("BIO_new: " + getErrors());
}
throw std::runtime_error("BIO_write: " + getErrors());
}
- X509_UniquePtr x509(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ ssl::X509UniquePtr x509(
+ PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
if (x509 == nullptr) {
throw std::runtime_error("PEM_read_bio_X509: " + getErrors());
}
throw std::invalid_argument("loadPrivateKey: <pkey> is nullptr");
}
- std::unique_ptr<BIO, BIO_deleter> bio(BIO_new(BIO_s_mem()));
+ ssl::BioUniquePtr bio(BIO_new(BIO_s_mem()));
if (bio == nullptr) {
throw std::runtime_error("BIO_new: " + getErrors());
}
throw std::runtime_error("BIO_write: " + getErrors());
}
- EVP_PKEY_UniquePtr key(
+ ssl::EvpPkeyUniquePtr key(
PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
if (key == nullptr) {
throw std::runtime_error("PEM_read_bio_PrivateKey: " + getErrors());
return os;
}
-bool OpenSSLUtils::getPeerAddressFromX509StoreCtx(X509_STORE_CTX* ctx,
- sockaddr_storage* addrStorage,
- socklen_t* addrLen) {
- // Grab the ssl idx and then the ssl object so that we can get the peer
- // name to compare against the ips in the subjectAltName
- auto sslIdx = SSL_get_ex_data_X509_STORE_CTX_idx();
- auto ssl =
- reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, sslIdx));
- int fd = SSL_get_fd(ssl);
- if (fd < 0) {
- LOG(ERROR) << "Inexplicably couldn't get fd from SSL";
- return false;
- }
-
- *addrLen = sizeof(*addrStorage);
- if (getpeername(fd, reinterpret_cast<sockaddr*>(addrStorage), addrLen) != 0) {
- PLOG(ERROR) << "Unable to get peer name";
- return false;
- }
- CHECK(*addrLen <= sizeof(*addrStorage));
- return true;
-}
-
-bool OpenSSLUtils::validatePeerCertNames(X509* cert,
- const sockaddr* addr,
- socklen_t /* addrLen */) {
- // Try to extract the names within the SAN extension from the certificate
- auto altNames =
- reinterpret_cast<STACK_OF(GENERAL_NAME)*>(
- X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
- SCOPE_EXIT {
- if (altNames != nullptr) {
- sk_GENERAL_NAME_pop_free(altNames, GENERAL_NAME_free);
- }
- };
- if (altNames == nullptr) {
- LOG(WARNING) << "No subjectAltName provided and we only support ip auth";
- return false;
- }
-
- const sockaddr_in* addr4 = nullptr;
- const sockaddr_in6* addr6 = nullptr;
- if (addr != nullptr) {
- if (addr->sa_family == AF_INET) {
- addr4 = reinterpret_cast<const sockaddr_in*>(addr);
- } else if (addr->sa_family == AF_INET6) {
- addr6 = reinterpret_cast<const sockaddr_in6*>(addr);
- } else {
- LOG(FATAL) << "Unsupported sockaddr family: " << addr->sa_family;
- }
- }
-
-
- for (int i = 0; i < sk_GENERAL_NAME_num(altNames); i++) {
- auto name = sk_GENERAL_NAME_value(altNames, i);
- if ((addr4 != nullptr || addr6 != nullptr) && name->type == GEN_IPADD) {
- // Extra const-ness for paranoia
- unsigned char const * const rawIpStr = name->d.iPAddress->data;
- int const rawIpLen = name->d.iPAddress->length;
-
- if (rawIpLen == 4 && addr4 != nullptr) {
- if (::memcmp(rawIpStr, &addr4->sin_addr, rawIpLen) == 0) {
- return true;
- }
- } else if (rawIpLen == 16 && addr6 != nullptr) {
- if (::memcmp(rawIpStr, &addr6->sin6_addr, rawIpLen) == 0) {
- return true;
- }
- } else if (rawIpLen != 4 && rawIpLen != 16) {
- LOG(WARNING) << "Unexpected IP length: " << rawIpLen;
- }
- }
- }
-
- LOG(WARNING) << "Unable to match client cert against alt name ip";
- return false;
-}
-
-
} // folly
#include <folly/Random.h>
#include <folly/Range.h>
+#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
+#include <folly/io/async/ssl/OpenSSLUtils.h>
namespace folly {
std::ostream& operator<<(std::ostream& os, const folly::PasswordCollector& collector);
-class OpenSSLUtils {
- public:
- /**
- * Validate that the peer certificate's common name or subject alt names
- * match what we expect. Currently this only checks for IPs within
- * subject alt names but it could easily be expanded to check common name
- * and hostnames as well.
- *
- * @param cert X509* peer certificate
- * @param addr sockaddr object containing sockaddr to verify
- * @param addrLen length of sockaddr as returned by getpeername or accept
- * @return true iff a subject altname IP matches addr
- */
- // TODO(agartrell): Add support for things like common name when
- // necessary.
- static bool validatePeerCertNames(X509* cert,
- const sockaddr* addr,
- socklen_t addrLen);
-
- /**
- * Get the peer socket address from an X509_STORE_CTX*. Unlike the
- * accept, getsockname, getpeername, etc family of operations, addrLen's
- * initial value is ignored and reset.
- *
- * @param ctx Context from which to retrieve peer sockaddr
- * @param addrStorage out param for address
- * @param addrLen out param for length of address
- * @return true on success, false on failure
- */
- static bool getPeerAddressFromX509StoreCtx(X509_STORE_CTX* ctx,
- sockaddr_storage* addrStorage,
- socklen_t* addrLen);
-
-};
-
} // folly
--- /dev/null
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#endif
+#include <folly/Memory.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+
+namespace folly {
+namespace ssl {
+
+// X509
+using X509Deleter = folly::static_function_deleter<X509, &X509_free>;
+using X509UniquePtr = std::unique_ptr<X509, X509Deleter>;
+using X509StoreCtxDeleter =
+ folly::static_function_deleter<X509_STORE_CTX, &X509_STORE_CTX_free>;
+using X509StoreCtxUniquePtr =
+ std::unique_ptr<X509_STORE_CTX, X509StoreCtxDeleter>;
+
+// EVP
+using EvpPkeyDel = folly::static_function_deleter<EVP_PKEY, &EVP_PKEY_free>;
+using EvpPkeyUniquePtr = std::unique_ptr<EVP_PKEY, EvpPkeyDel>;
+using EvpPkeySharedPtr = std::shared_ptr<EVP_PKEY>;
+
+// No EVP_PKEY_CTX <= 0.9.8b
+#if OPENSSL_VERSION_NUMBER >= 0x10000002L
+using EvpPkeyCtxDeleter =
+ folly::static_function_deleter<EVP_PKEY_CTX, &EVP_PKEY_CTX_free>;
+using EvpPkeyCtxUniquePtr = std::unique_ptr<EVP_PKEY_CTX, EvpPkeyCtxDeleter>;
+#else
+struct EVP_PKEY_CTX;
+#endif
+using EvpMdCtxDeleter =
+ folly::static_function_deleter<EVP_MD_CTX, &EVP_MD_CTX_destroy>;
+using EvpMdCtxUniquePtr = std::unique_ptr<EVP_MD_CTX, EvpMdCtxDeleter>;
+
+// BIO
+using BioDeleter = folly::static_function_deleter<BIO, &BIO_vfree>;
+using BioUniquePtr = std::unique_ptr<BIO, BioDeleter>;
+using BioChainDeleter = folly::static_function_deleter<BIO, &BIO_free_all>;
+using BioChainUniquePtr = std::unique_ptr<BIO, BioChainDeleter>;
+inline void BIO_free_fb(BIO* bio) { CHECK_EQ(1, BIO_free(bio)); }
+using BioDeleterFb = folly::static_function_deleter<BIO, &BIO_free_fb>;
+using BioUniquePtrFb = std::unique_ptr<BIO, BioDeleterFb>;
+
+// RSA and EC
+using RsaDeleter = folly::static_function_deleter<RSA, &RSA_free>;
+using RsaUniquePtr = std::unique_ptr<RSA, RsaDeleter>;
+#ifndef OPENSSL_NO_EC
+using EcKeyDeleter = folly::static_function_deleter<EC_KEY, &EC_KEY_free>;
+using EcKeyUniquePtr = std::unique_ptr<EC_KEY, EcKeyDeleter>;
+#endif
+
+// SSL and SSL_CTX
+using SSLDeleter = folly::static_function_deleter<SSL, &SSL_free>;
+using SSLUniquePtr = std::unique_ptr<SSL, SSLDeleter>;
+}
+}
--- /dev/null
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <folly/io/async/ssl/OpenSSLUtils.h>
+#include <folly/ScopeGuard.h>
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <glog/logging.h>
+
+namespace folly {
+namespace ssl {
+
+bool OpenSSLUtils::getPeerAddressFromX509StoreCtx(X509_STORE_CTX* ctx,
+ sockaddr_storage* addrStorage,
+ socklen_t* addrLen) {
+ // Grab the ssl idx and then the ssl object so that we can get the peer
+ // name to compare against the ips in the subjectAltName
+ auto sslIdx = SSL_get_ex_data_X509_STORE_CTX_idx();
+ auto ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, sslIdx));
+ int fd = SSL_get_fd(ssl);
+ if (fd < 0) {
+ LOG(ERROR) << "Inexplicably couldn't get fd from SSL";
+ return false;
+ }
+
+ *addrLen = sizeof(*addrStorage);
+ if (getpeername(fd, reinterpret_cast<sockaddr*>(addrStorage), addrLen) != 0) {
+ PLOG(ERROR) << "Unable to get peer name";
+ return false;
+ }
+ CHECK(*addrLen <= sizeof(*addrStorage));
+ return true;
+}
+
+bool OpenSSLUtils::validatePeerCertNames(X509* cert,
+ const sockaddr* addr,
+ socklen_t /* addrLen */) {
+ // Try to extract the names within the SAN extension from the certificate
+ auto altNames = reinterpret_cast<STACK_OF(GENERAL_NAME)*>(
+ X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
+ SCOPE_EXIT {
+ if (altNames != nullptr) {
+ sk_GENERAL_NAME_pop_free(altNames, GENERAL_NAME_free);
+ }
+ };
+ if (altNames == nullptr) {
+ LOG(WARNING) << "No subjectAltName provided and we only support ip auth";
+ return false;
+ }
+
+ const sockaddr_in* addr4 = nullptr;
+ const sockaddr_in6* addr6 = nullptr;
+ if (addr != nullptr) {
+ if (addr->sa_family == AF_INET) {
+ addr4 = reinterpret_cast<const sockaddr_in*>(addr);
+ } else if (addr->sa_family == AF_INET6) {
+ addr6 = reinterpret_cast<const sockaddr_in6*>(addr);
+ } else {
+ LOG(FATAL) << "Unsupported sockaddr family: " << addr->sa_family;
+ }
+ }
+
+ for (int i = 0; i < sk_GENERAL_NAME_num(altNames); i++) {
+ auto name = sk_GENERAL_NAME_value(altNames, i);
+ if ((addr4 != nullptr || addr6 != nullptr) && name->type == GEN_IPADD) {
+ // Extra const-ness for paranoia
+ unsigned char const* const rawIpStr = name->d.iPAddress->data;
+ int const rawIpLen = name->d.iPAddress->length;
+
+ if (rawIpLen == 4 && addr4 != nullptr) {
+ if (::memcmp(rawIpStr, &addr4->sin_addr, rawIpLen) == 0) {
+ return true;
+ }
+ } else if (rawIpLen == 16 && addr6 != nullptr) {
+ if (::memcmp(rawIpStr, &addr6->sin6_addr, rawIpLen) == 0) {
+ return true;
+ }
+ } else if (rawIpLen != 4 && rawIpLen != 16) {
+ LOG(WARNING) << "Unexpected IP length: " << rawIpLen;
+ }
+ }
+ }
+
+ LOG(WARNING) << "Unable to match client cert against alt name ip";
+ return false;
+}
+
+} // ssl
+} // folly
--- /dev/null
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <openssl/x509v3.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+namespace folly {
+namespace ssl {
+
+class OpenSSLUtils {
+ public:
+ /**
+ * Validate that the peer certificate's common name or subject alt names
+ * match what we expect. Currently this only checks for IPs within
+ * subject alt names but it could easily be expanded to check common name
+ * and hostnames as well.
+ *
+ * @param cert X509* peer certificate
+ * @param addr sockaddr object containing sockaddr to verify
+ * @param addrLen length of sockaddr as returned by getpeername or accept
+ * @return true iff a subject altname IP matches addr
+ */
+ // TODO(agartrell): Add support for things like common name when
+ // necessary.
+ static bool validatePeerCertNames(X509* cert,
+ const sockaddr* addr,
+ socklen_t addrLen);
+
+ /**
+ * Get the peer socket address from an X509_STORE_CTX*. Unlike the
+ * accept, getsockname, getpeername, etc family of operations, addrLen's
+ * initial value is ignored and reset.
+ *
+ * @param ctx Context from which to retrieve peer sockaddr
+ * @param addrStorage out param for address
+ * @param addrLen out param for length of address
+ * @return true on success, false on failure
+ */
+ static bool getPeerAddressFromX509StoreCtx(X509_STORE_CTX* ctx,
+ sockaddr_storage* addrStorage,
+ socklen_t* addrLen);
+};
+
+} // ssl
+} // folly
--- /dev/null
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/io/Cursor.h>
+#include <folly/io/IOBuf.h>
+#include <map>
+#include <openssl/ssl.h>
+#include <openssl/tls1.h>
+#include <vector>
+
+namespace folly {
+namespace ssl {
+
+// http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
+enum class TLSExtension : uint16_t {
+ SERVER_NAME = 0,
+ MAX_FRAGMENT_LENGTH = 1,
+ CLIENT_CERTIFICATE_URL = 2,
+ TRUSTED_CA_KEYS = 3,
+ TRUNCATED_HMAC = 4,
+ STATUS_REQUEST = 5,
+ USER_MAPPING = 6,
+ CLIENT_AUTHZ = 7,
+ SERVER_AUTHZ = 8,
+ CERT_TYPE = 9,
+ SUPPORTED_GROUPS = 10,
+ EC_POINT_FORMATS = 11,
+ SRP = 12,
+ SIGNATURE_ALGORITHMS = 13,
+ USE_SRTP = 14,
+ HEARTBEAT = 15,
+ APPLICATION_LAYER_PROTOCOL_NEGOTIATION = 16,
+ STATUS_REQUEST_V2 = 17,
+ SIGNED_CERTIFICATE_TIMESTAMP = 18,
+ CLIENT_CERTIFICATE_TYPE = 19,
+ SERVER_CERTIFICATE_TYPE = 20,
+ PADDING = 21,
+ ENCRYPT_THEN_MAC = 22,
+ EXTENDED_MASTER_SECRET = 23,
+ SESSION_TICKET = 35,
+ // Facebook-specific, not IANA assigned yet
+ TLS_CACHED_INFO_FB = 60001,
+ // End Facebook-specific
+ RENEGOTIATION_INFO = 65281
+};
+
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18
+enum class HashAlgorithm : uint8_t {
+ NONE = 0,
+ MD5 = 1,
+ SHA1 = 2,
+ SHA224 = 3,
+ SHA256 = 4,
+ SHA384 = 5,
+ SHA512 = 6
+};
+
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16
+enum class SignatureAlgorithm : uint8_t {
+ ANONYMOUS = 0,
+ RSA = 1,
+ DSA = 2,
+ ECDSA = 3
+};
+
+struct ClientHelloInfo {
+ folly::IOBufQueue clientHelloBuf_;
+ uint8_t clientHelloMajorVersion_;
+ uint8_t clientHelloMinorVersion_;
+ std::vector<uint16_t> clientHelloCipherSuites_;
+ std::vector<uint8_t> clientHelloCompressionMethods_;
+ std::vector<TLSExtension> clientHelloExtensions_;
+ std::vector<std::pair<HashAlgorithm, SignatureAlgorithm>> clientHelloSigAlgs_;
+};
+
+} // ssl
+} // folly
constexpr size_t SSLClient::kMaxReadBufferSz;
constexpr size_t SSLClient::kMaxReadsPerEvent;
-inline void BIO_free_fb(BIO* bio) { CHECK_EQ(1, BIO_free(bio)); }
-using BIO_deleter = folly::static_function_deleter<BIO, &BIO_free_fb>;
-
TestSSLServer::TestSSLServer(SSLServerAcceptCallbackBase* acb)
: ctx_(new folly::SSLContext),
acb_(acb),
auto cert = getFileAsBuf(testCert);
auto key = getFileAsBuf(testKey);
- std::unique_ptr<BIO, BIO_deleter> certBio(BIO_new(BIO_s_mem()));
+ ssl::BioUniquePtr certBio(BIO_new(BIO_s_mem()));
BIO_write(certBio.get(), cert.data(), cert.size());
- std::unique_ptr<BIO, BIO_deleter> keyBio(BIO_new(BIO_s_mem()));
+ ssl::BioUniquePtr keyBio(BIO_new(BIO_s_mem()));
BIO_write(keyBio.get(), key.data(), key.size());
// Create SSL structs from buffers to get properties
- X509_UniquePtr certStruct(
+ ssl::X509UniquePtr certStruct(
PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
- EVP_PKEY_UniquePtr keyStruct(
+ ssl::EvpPkeyUniquePtr keyStruct(
PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr));
certBio = nullptr;
keyBio = nullptr;
ctx->loadCertificateFromBufferPEM(cert);
ctx->loadTrustedCertificates(testCA);
- SSL_UniquePtr ssl(ctx->createSSL());
+ ssl::SSLUniquePtr ssl(ctx->createSSL());
auto newCert = SSL_get_certificate(ssl.get());
auto newKey = SSL_get_privatekey(ssl.get());