Chromium Code Reviews| Index: runtime/bin/secure_socket.cc |
| diff --git a/runtime/bin/secure_socket_boringssl.cc b/runtime/bin/secure_socket.cc |
| similarity index 58% |
| copy from runtime/bin/secure_socket_boringssl.cc |
| copy to runtime/bin/secure_socket.cc |
| index a3740a84a3af54282e6afd402d4af37a05661bf2..816e8aa8852bc46abdae992d51869eea60773668 100644 |
| --- a/runtime/bin/secure_socket_boringssl.cc |
| +++ b/runtime/bin/secure_socket.cc |
| @@ -4,12 +4,8 @@ |
| #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) |
| -#include "platform/globals.h" |
| -#if defined(HOST_OS_ANDROID) || defined(HOST_OS_LINUX) || \ |
| - defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA) |
| - |
| #include "bin/secure_socket.h" |
| -#include "bin/secure_socket_boringssl.h" |
| +#include "bin/secure_socket_utils.h" |
| #include <errno.h> |
| #include <fcntl.h> |
| @@ -26,6 +22,8 @@ |
| #include <openssl/tls1.h> |
| #include <openssl/x509.h> |
| +#include "platform/globals.h" |
| + |
| #include "bin/builtin.h" |
| #include "bin/dartutils.h" |
| #include "bin/directory.h" |
| @@ -37,9 +35,6 @@ |
| #include "bin/utils.h" |
| #include "platform/text_buffer.h" |
| #include "platform/utils.h" |
| - |
| -#include "include/dart_api.h" |
| - |
| // Return the error from the containing function if handle is an error handle. |
| #define RETURN_IF_ERROR(handle) \ |
| { \ |
| @@ -61,25 +56,8 @@ const intptr_t SSLFilter::kInternalBIOSize = 10 * KB; |
| const intptr_t SSLFilter::kApproximateSize = |
| sizeof(SSLFilter) + (2 * SSLFilter::kInternalBIOSize); |
| -// The security context won't necessarily use the compiled-in root certificates, |
| -// but since there is no way to update the size of the allocation after creating |
| -// the weak persistent handle, we assume that it will. Note that when the |
| -// root certs aren't compiled in, |root_certificates_pem_length| is 0. |
| -const intptr_t SSLContext::kApproximateSize = |
| - sizeof(SSLContext) + root_certificates_pem_length; |
| - |
| -static const int kSSLFilterNativeFieldIndex = 0; |
| -static const int kSecurityContextNativeFieldIndex = 0; |
| -static const int kX509NativeFieldIndex = 0; |
| - |
| -static const bool SSL_LOG_STATUS = false; |
| -static const bool SSL_LOG_DATA = false; |
| - |
| static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000; |
| -const char* commandline_root_certs_file = NULL; |
| -const char* commandline_root_certs_cache = NULL; |
| - |
| // Get the error messages from BoringSSL, and put them in buffer as a |
| // null-terminated string. |
| static void FetchErrorString(const SSL* ssl, TextBuffer* text_buffer) { |
| @@ -107,10 +85,10 @@ static void FetchErrorString(const SSL* ssl, TextBuffer* text_buffer) { |
| // Handle an error reported from the BoringSSL library. |
| -static void ThrowIOException(int status, |
| - const char* exception_type, |
| - const char* message, |
| - const SSL* ssl) { |
| +void SecureSocketUtils::ThrowIOException(int status, |
|
zra
2017/05/30 16:15:36
Please keep the SecureSocketUtils methods all toge
|
| + const char* exception_type, |
| + const char* message, |
| + const SSL* ssl) { |
| Dart_Handle exception; |
| { |
| TextBuffer error_string(SSL_ERROR_MESSAGE_BUFFER_SIZE); |
| @@ -130,9 +108,9 @@ static SSLFilter* GetFilter(Dart_NativeArguments args) { |
| SSLFilter* filter; |
| Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| ASSERT(Dart_IsInstance(dart_this)); |
| - ThrowIfError( |
| - Dart_GetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex, |
| - reinterpret_cast<intptr_t*>(&filter))); |
| + ThrowIfError(Dart_GetNativeInstanceField( |
| + dart_this, SSLFilter::kSSLFilterNativeFieldIndex, |
| + reinterpret_cast<intptr_t*>(&filter))); |
| return filter; |
| } |
| @@ -150,9 +128,9 @@ static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) { |
| Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); |
| RETURN_IF_ERROR(dart_this); |
| ASSERT(Dart_IsInstance(dart_this)); |
| - Dart_Handle err = |
| - Dart_SetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex, |
| - reinterpret_cast<intptr_t>(filter)); |
| + Dart_Handle err = Dart_SetNativeInstanceField( |
| + dart_this, SSLFilter::kSSLFilterNativeFieldIndex, |
| + reinterpret_cast<intptr_t>(filter)); |
| RETURN_IF_ERROR(err); |
| Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter), |
| SSLFilter::kApproximateSize, DeleteFilter); |
| @@ -160,13 +138,13 @@ static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) { |
| } |
| -static SSLContext* GetSecurityContext(Dart_NativeArguments args) { |
| - SSLContext* context; |
| +SSLCertContext* SSLCertContext::GetSecurityContext(Dart_NativeArguments args) { |
| + SSLCertContext* context; |
| Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| ASSERT(Dart_IsInstance(dart_this)); |
| - ThrowIfError( |
| - Dart_GetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex, |
| - reinterpret_cast<intptr_t*>(&context))); |
| + ThrowIfError(Dart_GetNativeInstanceField( |
| + dart_this, SSLCertContext::kSecurityContextNativeFieldIndex, |
| + reinterpret_cast<intptr_t*>(&context))); |
| return context; |
| } |
| @@ -174,41 +152,31 @@ static SSLContext* GetSecurityContext(Dart_NativeArguments args) { |
| static void DeleteSecurityContext(void* isolate_data, |
| Dart_WeakPersistentHandle handle, |
| void* context_pointer) { |
| - SSLContext* context = static_cast<SSLContext*>(context_pointer); |
| - delete context; |
| + SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer); |
| + context->Release(); |
| } |
| static Dart_Handle SetSecurityContext(Dart_NativeArguments args, |
| - SSLContext* context) { |
| + SSLCertContext* context) { |
| Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); |
| RETURN_IF_ERROR(dart_this); |
| ASSERT(Dart_IsInstance(dart_this)); |
| - Dart_Handle err = |
| - Dart_SetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex, |
| - reinterpret_cast<intptr_t>(context)); |
| + Dart_Handle err = Dart_SetNativeInstanceField( |
| + dart_this, SSLCertContext::kSecurityContextNativeFieldIndex, |
| + reinterpret_cast<intptr_t>(context)); |
| RETURN_IF_ERROR(err); |
| - Dart_NewWeakPersistentHandle(dart_this, context, SSLContext::kApproximateSize, |
| + Dart_NewWeakPersistentHandle(dart_this, context, |
| + SSLCertContext::kApproximateSize, |
| DeleteSecurityContext); |
| return Dart_Null(); |
| } |
| -static X509* GetX509Certificate(Dart_NativeArguments args) { |
| - X509* certificate; |
| - Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| - ASSERT(Dart_IsInstance(dart_this)); |
| - ThrowIfError( |
| - Dart_GetNativeInstanceField(dart_this, kX509NativeFieldIndex, |
| - reinterpret_cast<intptr_t*>(&certificate))); |
| - return certificate; |
| -} |
| - |
| - |
| // Forward declaration. |
| static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
| SSL* ssl, |
| - SSLContext* context, |
| + SSLCertContext* context, |
| bool is_server); |
| @@ -244,10 +212,10 @@ void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { |
| // TODO(whesse): Is truncating a Dart string containing \0 what we want? |
| ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); |
| - SSLContext* context = NULL; |
| + SSLCertContext* context = NULL; |
| if (!Dart_IsNull(context_object)) { |
| ThrowIfError(Dart_GetNativeInstanceField( |
| - context_object, kSecurityContextNativeFieldIndex, |
| + context_object, SSLCertContext::kSecurityContextNativeFieldIndex, |
| reinterpret_cast<intptr_t*>(&context))); |
| } |
| @@ -255,7 +223,7 @@ void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { |
| // It will have the correct length encoding of the protocols array. |
| ASSERT(!Dart_IsNull(protocols_handle)); |
| - GetFilter(args)->Connect(host_name, context->context(), is_server, |
| + GetFilter(args)->Connect(host_name, context, is_server, |
| request_client_certificate, |
| require_client_certificate, protocols_handle); |
| } |
| @@ -339,108 +307,13 @@ void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { |
| } |
| -static void ReleaseCertificate(void* isolate_data, |
| - Dart_WeakPersistentHandle handle, |
| - void* context_pointer) { |
| - X509* cert = reinterpret_cast<X509*>(context_pointer); |
| - X509_free(cert); |
| -} |
| - |
| - |
| -static intptr_t EstimateX509Size(X509* certificate) { |
| - intptr_t length = i2d_X509(certificate, NULL); |
| - return length > 0 ? length : 0; |
| -} |
| - |
| - |
| -// Returns the handle for a Dart object wrapping the X509 certificate object. |
| -// The caller should own a reference to the X509 object whose reference count |
| -// won't drop to zero before the ReleaseCertificate finalizer runs. |
| -static Dart_Handle WrappedX509Certificate(X509* certificate) { |
| - if (certificate == NULL) { |
| - return Dart_Null(); |
| - } |
| - Dart_Handle x509_type = |
| - DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); |
| - if (Dart_IsError(x509_type)) { |
| - X509_free(certificate); |
| - return x509_type; |
| - } |
| - Dart_Handle arguments[] = {NULL}; |
| - Dart_Handle result = |
| - Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments); |
| - if (Dart_IsError(result)) { |
| - X509_free(certificate); |
| - return result; |
| - } |
| - ASSERT(Dart_IsInstance(result)); |
| - Dart_Handle status = Dart_SetNativeInstanceField( |
| - result, kX509NativeFieldIndex, reinterpret_cast<intptr_t>(certificate)); |
| - if (Dart_IsError(status)) { |
| - X509_free(certificate); |
| - return status; |
| - } |
| - const intptr_t approximate_size_of_certificate = |
| - sizeof(*certificate) + EstimateX509Size(certificate); |
| - ASSERT(approximate_size_of_certificate > 0); |
| - Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate), |
| - approximate_size_of_certificate, |
| - ReleaseCertificate); |
| - return result; |
| -} |
| - |
| - |
| -int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) { |
| - if (preverify_ok == 1) { |
| - return 1; |
| - } |
| - Dart_Isolate isolate = Dart_CurrentIsolate(); |
| - if (isolate == NULL) { |
| - FATAL("CertificateCallback called with no current isolate\n"); |
| - } |
| - X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx); |
| - int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx(); |
| - SSL* ssl = |
| - static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index)); |
| - SSLFilter* filter = static_cast<SSLFilter*>( |
| - SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index)); |
| - Dart_Handle callback = filter->bad_certificate_callback(); |
| - if (Dart_IsNull(callback)) { |
| - return 0; |
| - } |
| - |
| - // Upref since the Dart X509 object may outlive the SecurityContext. |
| - if (certificate != NULL) { |
| - X509_up_ref(certificate); |
| - } |
| - Dart_Handle args[1]; |
| - args[0] = WrappedX509Certificate(certificate); |
| - if (Dart_IsError(args[0])) { |
| - filter->callback_error = args[0]; |
| - return 0; |
| - } |
| - Dart_Handle result = Dart_InvokeClosure(callback, 1, args); |
| - if (!Dart_IsError(result) && !Dart_IsBoolean(result)) { |
| - result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException( |
| - "HandshakeException", |
| - "BadCertificateCallback returned a value that was not a boolean", |
| - Dart_Null())); |
| - } |
| - if (Dart_IsError(result)) { |
| - filter->callback_error = result; |
| - return 0; |
| - } |
| - return DartUtils::GetBooleanValue(result); |
| -} |
| - |
| - |
| void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) { |
| SSLFilter::InitializeLibrary(); |
| SSL_CTX* ctx = SSL_CTX_new(TLS_method()); |
| SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, CertificateCallback); |
| SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); |
| SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM"); |
| - SSLContext* context = new SSLContext(ctx); |
| + SSLCertContext* context = new SSLCertContext(ctx); |
| Dart_Handle err = SetSecurityContext(args, context); |
| if (Dart_IsError(err)) { |
| delete context; |
| @@ -457,10 +330,10 @@ int PasswordCallback(char* buf, int size, int rwflag, void* userdata) { |
| } |
| -void CheckStatusSSL(int status, |
| - const char* type, |
| - const char* message, |
| - const SSL* ssl) { |
| +void SecureSocketUtils::CheckStatusSSL(int status, |
| + const char* type, |
| + const char* message, |
| + const SSL* ssl) { |
| // TODO(24183): Take appropriate action on failed calls, |
| // throw exception that includes all messages from the error stack. |
| if (status == 1) { |
| @@ -473,143 +346,14 @@ void CheckStatusSSL(int status, |
| ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); |
| Log::PrintErr("ERROR: %d %s\n", error, error_string); |
| } |
| - ThrowIOException(status, type, message, ssl); |
| + SecureSocketUtils::ThrowIOException(status, type, message, ssl); |
| } |
| -void CheckStatus(int status, const char* type, const char* message) { |
| - CheckStatusSSL(status, type, message, NULL); |
| -} |
| - |
| - |
| -// Where the argument to the constructor is the handle for an object |
| -// implementing List<int>, this class creates a scope in which a memory-backed |
| -// BIO is allocated. Leaving the scope cleans up the BIO and the buffer that |
| -// was used to create it. |
| -// |
| -// Do not make Dart_ API calls while in a ScopedMemBIO. |
| -// Do not call Dart_PropagateError while in a ScopedMemBIO. |
| -class ScopedMemBIO { |
| - public: |
| - explicit ScopedMemBIO(Dart_Handle object) { |
| - if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { |
| - Dart_ThrowException( |
| - DartUtils::NewDartArgumentError("Argument is not a List<int>")); |
| - } |
| - |
| - uint8_t* bytes = NULL; |
| - intptr_t bytes_len = 0; |
| - bool is_typed_data = false; |
| - if (Dart_IsTypedData(object)) { |
| - is_typed_data = true; |
| - Dart_TypedData_Type typ; |
| - ThrowIfError(Dart_TypedDataAcquireData( |
| - object, &typ, reinterpret_cast<void**>(&bytes), &bytes_len)); |
| - } else { |
| - ASSERT(Dart_IsList(object)); |
| - ThrowIfError(Dart_ListLength(object, &bytes_len)); |
| - bytes = Dart_ScopeAllocate(bytes_len); |
| - ASSERT(bytes != NULL); |
| - ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len)); |
| - } |
| - |
| - object_ = object; |
| - bytes_ = bytes; |
| - bytes_len_ = bytes_len; |
| - bio_ = BIO_new_mem_buf(bytes, bytes_len); |
| - ASSERT(bio_ != NULL); |
| - is_typed_data_ = is_typed_data; |
| - } |
| - |
| - ~ScopedMemBIO() { |
| - ASSERT(bio_ != NULL); |
| - if (is_typed_data_) { |
| - BIO_free(bio_); |
| - ThrowIfError(Dart_TypedDataReleaseData(object_)); |
| - } else { |
| - BIO_free(bio_); |
| - } |
| - } |
| - |
| - BIO* bio() { |
| - ASSERT(bio_ != NULL); |
| - return bio_; |
| - } |
| - |
| - private: |
| - Dart_Handle object_; |
| - uint8_t* bytes_; |
| - intptr_t bytes_len_; |
| - BIO* bio_; |
| - bool is_typed_data_; |
| - |
| - DISALLOW_ALLOCATION(); |
| - DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO); |
| -}; |
| - |
| -template <typename T, void (*free_func)(T*)> |
| -class ScopedSSLType { |
| - public: |
| - explicit ScopedSSLType(T* obj) : obj_(obj) {} |
| - |
| - ~ScopedSSLType() { |
| - if (obj_ != NULL) { |
| - free_func(obj_); |
| - } |
| - } |
| - |
| - T* get() { return obj_; } |
| - const T* get() const { return obj_; } |
| - |
| - T* release() { |
| - T* result = obj_; |
| - obj_ = NULL; |
| - return result; |
| - } |
| - |
| - private: |
| - T* obj_; |
| - |
| - DISALLOW_ALLOCATION(); |
| - DISALLOW_COPY_AND_ASSIGN(ScopedSSLType); |
| -}; |
| - |
| -template <typename T, typename E, void (*func)(E*)> |
| -class ScopedSSLStackType { |
| - public: |
| - explicit ScopedSSLStackType(T* obj) : obj_(obj) {} |
| - |
| - ~ScopedSSLStackType() { |
| - if (obj_ != NULL) { |
| - sk_pop_free(reinterpret_cast<_STACK*>(obj_), |
| - reinterpret_cast<void (*)(void*)>(func)); |
| - } |
| - } |
| - |
| - T* get() { return obj_; } |
| - const T* get() const { return obj_; } |
| - |
| - T* release() { |
| - T* result = obj_; |
| - obj_ = NULL; |
| - return result; |
| - } |
| - |
| - private: |
| - T* obj_; |
| - |
| - DISALLOW_ALLOCATION(); |
| - DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); |
| -}; |
| - |
| -typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; |
| -typedef ScopedSSLType<X509, X509_free> ScopedX509; |
| -typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; |
| - |
| -static bool NoPEMStartLine() { |
| - uint32_t last_error = ERR_peek_last_error(); |
| - return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && |
| - (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); |
| +void SecureSocketUtils::CheckStatus(int status, |
| + const char* type, |
| + const char* message) { |
| + SecureSocketUtils::CheckStatusSSL(status, type, message, NULL); |
| } |
| @@ -642,7 +386,7 @@ static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { |
| // if there is no indication that the data is malformed PEM. We assume the |
| // data is malformed PEM if it contains the start line, i.e. a line |
| // with ----- BEGIN. |
| - if (NoPEMStartLine()) { |
| + if (SecureSocketUtils::NoPEMStartLine()) { |
| // Reset the bio, and clear the error from trying to read as PEM. |
| ERR_clear_error(); |
| BIO_reset(bio); |
| @@ -655,8 +399,8 @@ static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { |
| } |
| -static const char* GetPasswordArgument(Dart_NativeArguments args, |
| - intptr_t index) { |
| +const char* SSLCertContext::GetPasswordArgument(Dart_NativeArguments args, |
| + intptr_t index) { |
| Dart_Handle password_object = |
| ThrowIfError(Dart_GetNativeArgument(args, index)); |
| const char* password = NULL; |
| @@ -678,8 +422,8 @@ static const char* GetPasswordArgument(Dart_NativeArguments args, |
| void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
| Dart_NativeArguments args) { |
| - SSLContext* context = GetSecurityContext(args); |
| - const char* password = GetPasswordArgument(args, 2); |
| + SSLCertContext* context = SSLCertContext::GetSecurityContext(args); |
| + const char* password = SSLCertContext::GetPasswordArgument(args, 2); |
| int status; |
| { |
| @@ -693,423 +437,16 @@ void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
| // TODO(24184): Handle different expected errors here - file missing, |
| // incorrect password, file not a PEM, and throw exceptions. |
| - // CheckStatus should also throw an exception in uncaught cases. |
| - CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); |
| -} |
| - |
| - |
| -static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, |
| - BIO* bio, |
| - const char* password) { |
| - ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
| - if (p12.get() == NULL) { |
| - return 0; |
| - } |
| - |
| - EVP_PKEY* key = NULL; |
| - X509* cert = NULL; |
| - STACK_OF(X509)* ca_certs = NULL; |
| - int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
| - if (status == 0) { |
| - return status; |
| - } |
| - |
| - ScopedX509Stack cert_stack(ca_certs); |
| - X509_STORE* store = SSL_CTX_get_cert_store(context); |
| - status = X509_STORE_add_cert(store, cert); |
| - // X509_STORE_add_cert increments the reference count of cert on success. |
| - X509_free(cert); |
| - if (status == 0) { |
| - return status; |
| - } |
| - |
| - X509* ca; |
| - while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { |
| - status = X509_STORE_add_cert(store, ca); |
| - // X509_STORE_add_cert increments the reference count of cert on success. |
| - X509_free(ca); |
| - if (status == 0) { |
| - return status; |
| - } |
| - } |
| - |
| - return status; |
| -} |
| - |
| - |
| -static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) { |
| - X509_STORE* store = SSL_CTX_get_cert_store(context); |
| - |
| - int status = 0; |
| - X509* cert = NULL; |
| - while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
| - status = X509_STORE_add_cert(store, cert); |
| - // X509_STORE_add_cert increments the reference count of cert on success. |
| - X509_free(cert); |
| - if (status == 0) { |
| - return status; |
| - } |
| - } |
| - |
| - // If no PEM start line is found, it means that we read to the end of the |
| - // file, or that the file isn't PEM. In the first case, status will be |
| - // non-zero indicating success. In the second case, status will be 0, |
| - // indicating that we should try to read as PKCS12. If there is some other |
| - // error, we return it up to the caller. |
| - return NoPEMStartLine() ? status : 0; |
| -} |
| - |
| - |
| -static int SetTrustedCertificatesBytes(SSL_CTX* context, |
| - BIO* bio, |
| - const char* password) { |
| - int status = SetTrustedCertificatesBytesPEM(context, bio); |
| - if (status == 0) { |
| - if (NoPEMStartLine()) { |
| - ERR_clear_error(); |
| - BIO_reset(bio); |
| - status = SetTrustedCertificatesBytesPKCS12(context, bio, password); |
| - } |
| - } else { |
| - // The PEM file was successfully parsed. |
| - ERR_clear_error(); |
| - } |
| - return status; |
| -} |
| - |
| - |
| -void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( |
|
zra
2017/05/30 16:15:36
To be consistent with other parts of the dart:io i
|
| - Dart_NativeArguments args) { |
| - SSLContext* context = GetSecurityContext(args); |
| - const char* password = GetPasswordArgument(args, 2); |
| - int status; |
| - { |
| - ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| - status = |
| - SetTrustedCertificatesBytes(context->context(), bio.bio(), password); |
| - } |
| - CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes"); |
| -} |
| - |
| - |
| -void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) { |
| - Dart_SetReturnValue(args, Dart_NewBoolean(true)); |
| -} |
| - |
| - |
| -static void AddCompiledInCerts(SSLContext* context) { |
| - if (root_certificates_pem == NULL) { |
| - if (SSL_LOG_STATUS) { |
| - Log::Print("Missing compiled-in roots\n"); |
| - } |
| - return; |
| - } |
| - X509_STORE* store = SSL_CTX_get_cert_store(context->context()); |
| - BIO* roots_bio = |
| - BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), |
| - root_certificates_pem_length); |
| - X509* root_cert; |
| - // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, |
| - // backed by a memory buffer), and returns X509 objects, one by one. |
| - // When the end of the bio is reached, it returns null. |
| - while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL)) != NULL) { |
| - int status = X509_STORE_add_cert(store, root_cert); |
| - // X509_STORE_add_cert increments the reference count of cert on success. |
| - X509_free(root_cert); |
| - if (status == 0) { |
| - break; |
| - } |
| - } |
| - BIO_free(roots_bio); |
| - // If there is an error here, it must be the error indicating that we are done |
| - // reading PEM certificates. |
| - ASSERT((ERR_peek_error() == 0) || NoPEMStartLine()); |
| - ERR_clear_error(); |
| -} |
| - |
| - |
| -static void LoadRootCertFile(SSLContext* context, const char* file) { |
| - if (SSL_LOG_STATUS) { |
| - Log::Print("Looking for trusted roots in %s\n", file); |
| - } |
| - if (!File::Exists(file)) { |
| - ThrowIOException(-1, "TlsException", "Failed to find root cert file", NULL); |
| - } |
| - int status = SSL_CTX_load_verify_locations(context->context(), file, NULL); |
| - CheckStatus(status, "TlsException", "Failure trusting builtin roots"); |
| - if (SSL_LOG_STATUS) { |
| - Log::Print("Trusting roots from: %s\n", file); |
| - } |
| -} |
| - |
| - |
| -static void LoadRootCertCache(SSLContext* context, const char* cache) { |
| - if (SSL_LOG_STATUS) { |
| - Log::Print("Looking for trusted roots in %s\n", cache); |
| - } |
| - if (Directory::Exists(cache) != Directory::EXISTS) { |
| - ThrowIOException(-1, "TlsException", "Failed to find root cert cache", |
| - NULL); |
| - } |
| - int status = SSL_CTX_load_verify_locations(context->context(), NULL, cache); |
| - CheckStatus(status, "TlsException", "Failure trusting builtin roots"); |
| - if (SSL_LOG_STATUS) { |
| - Log::Print("Trusting roots from: %s\n", cache); |
| - } |
| -} |
| - |
| - |
| -void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( |
| - Dart_NativeArguments args) { |
| - SSLContext* context = GetSecurityContext(args); |
| - |
| - // First, try to use locations specified on the command line. |
| - if (commandline_root_certs_file != NULL) { |
| - LoadRootCertFile(context, commandline_root_certs_file); |
| - return; |
| - } |
| - |
| - if (commandline_root_certs_cache != NULL) { |
| - LoadRootCertCache(context, commandline_root_certs_cache); |
| - return; |
| - } |
| - |
| -#if defined(HOST_OS_ANDROID) |
| - // On Android, we don't compile in the trusted root certificates. Insead, |
| - // we use the directory of trusted certificates already present on the device. |
| - // This saves ~240KB from the size of the binary. This has the drawback that |
| - // SSL_do_handshake will synchronously hit the filesystem looking for root |
| - // certs during its trust evaluation. We call SSL_do_handshake directly from |
| - // the Dart thread so that Dart code can be invoked from the "bad certificate" |
| - // callback called by SSL_do_handshake. |
| - const char* android_cacerts = "/system/etc/security/cacerts"; |
| - LoadRootCertCache(context, android_cacerts); |
| - return; |
| -#elif defined(HOST_OS_LINUX) |
| - // On Linux, we use the compiled-in trusted certs as a last resort. First, |
| - // we try to find the trusted certs in various standard locations. A good |
| - // discussion of the complexities of this endeavor can be found here: |
| - // |
| - // https://www.happyassassin.net/2015/01/12/a-note-about-ssltls-trusted-certificate-stores-and-platforms/ |
| - const char* bundle = "/etc/pki/tls/certs/ca-bundle.crt"; |
| - const char* cachedir = "/etc/ssl/certs"; |
| - if (File::Exists(bundle)) { |
| - LoadRootCertFile(context, bundle); |
| - return; |
| - } |
| - |
| - if (Directory::Exists(cachedir) == Directory::EXISTS) { |
| - LoadRootCertCache(context, cachedir); |
| - return; |
| - } |
| -#endif // defined(HOST_OS_ANDROID) |
| - |
| - // Fall back on the compiled-in certs if the standard locations don't exist, |
| - // or we aren't on Linux. |
| - if (SSL_LOG_STATUS) { |
| - Log::Print("Trusting compiled-in roots\n"); |
| - } |
| - AddCompiledInCerts(context); |
| -} |
| - |
| - |
| -static int UseChainBytesPKCS12(SSL_CTX* context, |
| - BIO* bio, |
| - const char* password) { |
| - ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
| - if (p12.get() == NULL) { |
| - return 0; |
| - } |
| - |
| - EVP_PKEY* key = NULL; |
| - X509* cert = NULL; |
| - STACK_OF(X509)* ca_certs = NULL; |
| - int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
| - if (status == 0) { |
| - return status; |
| - } |
| - |
| - ScopedX509 x509(cert); |
| - ScopedX509Stack certs(ca_certs); |
| - status = SSL_CTX_use_certificate(context, x509.get()); |
| - if (ERR_peek_error() != 0) { |
| - // Key/certificate mismatch doesn't imply status is 0. |
| - status = 0; |
| - } |
| - if (status == 0) { |
| - return status; |
| - } |
| - |
| - SSL_CTX_clear_chain_certs(context); |
| - |
| - X509* ca; |
| - while ((ca = sk_X509_shift(certs.get())) != NULL) { |
| - status = SSL_CTX_add0_chain_cert(context, ca); |
| - // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the |
| - // call fails. |
| - if (status == 0) { |
| - X509_free(ca); |
| - return status; |
| - } |
| - } |
| - |
| - return status; |
| -} |
| - |
| - |
| -static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) { |
| - int status = 0; |
| - ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL)); |
| - if (x509.get() == NULL) { |
| - return 0; |
| - } |
| - |
| - status = SSL_CTX_use_certificate(context, x509.get()); |
| - if (ERR_peek_error() != 0) { |
| - // Key/certificate mismatch doesn't imply status is 0. |
| - status = 0; |
| - } |
| - if (status == 0) { |
| - return status; |
| - } |
| - |
| - SSL_CTX_clear_chain_certs(context); |
| - |
| - X509* ca; |
| - while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
| - status = SSL_CTX_add0_chain_cert(context, ca); |
| - // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the |
| - // call fails. |
| - if (status == 0) { |
| - X509_free(ca); |
| - return status; |
| - } |
| - // Note that we must not free `ca` if it was successfully added to the |
| - // chain. We must free the main certificate x509, though since its reference |
| - // count is increased by SSL_CTX_use_certificate. |
| - } |
| - |
| - return NoPEMStartLine() ? status : 0; |
| -} |
| - |
| - |
| -static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) { |
| - int status = UseChainBytesPEM(context, bio); |
| - if (status == 0) { |
| - if (NoPEMStartLine()) { |
| - ERR_clear_error(); |
| - BIO_reset(bio); |
| - status = UseChainBytesPKCS12(context, bio, password); |
| - } |
| - } else { |
| - // The PEM file was successfully read. |
| - ERR_clear_error(); |
| - } |
| - return status; |
| -} |
| - |
| - |
| -void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( |
| - Dart_NativeArguments args) { |
| - SSLContext* context = GetSecurityContext(args); |
| - const char* password = GetPasswordArgument(args, 2); |
| - int status; |
| - { |
| - ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| - status = UseChainBytes(context->context(), bio.bio(), password); |
| - } |
| - CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes"); |
| -} |
| - |
| - |
| -static int SetClientAuthoritiesPKCS12(SSL_CTX* context, |
| - BIO* bio, |
| - const char* password) { |
| - ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
| - if (p12.get() == NULL) { |
| - return 0; |
| - } |
| - |
| - EVP_PKEY* key = NULL; |
| - X509* cert = NULL; |
| - STACK_OF(X509)* ca_certs = NULL; |
| - int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
| - if (status == 0) { |
| - return status; |
| - } |
| - |
| - ScopedX509Stack cert_stack(ca_certs); |
| - status = SSL_CTX_add_client_CA(context, cert); |
| - // SSL_CTX_add_client_CA increments the reference count of cert on success. |
| - X509_free(cert); |
| - if (status == 0) { |
| - return status; |
| - } |
| - |
| - X509* ca; |
| - while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { |
| - status = SSL_CTX_add_client_CA(context, ca); |
| - // SSL_CTX_add_client_CA increments the reference count of ca on success. |
| - X509_free(ca); // The name has been extracted. |
| - if (status == 0) { |
| - return status; |
| - } |
| - } |
| - |
| - return status; |
| -} |
| - |
| - |
| -static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) { |
| - int status = 0; |
| - X509* cert = NULL; |
| - while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
| - status = SSL_CTX_add_client_CA(context, cert); |
| - X509_free(cert); // The name has been extracted. |
| - if (status == 0) { |
| - return status; |
| - } |
| - } |
| - return NoPEMStartLine() ? status : 0; |
| -} |
| - |
| - |
| -static int SetClientAuthorities(SSL_CTX* context, |
| - BIO* bio, |
| - const char* password) { |
| - int status = SetClientAuthoritiesPEM(context, bio); |
| - if (status == 0) { |
| - if (NoPEMStartLine()) { |
| - ERR_clear_error(); |
| - BIO_reset(bio); |
| - status = SetClientAuthoritiesPKCS12(context, bio, password); |
| - } |
| - } else { |
| - // The PEM file was successfully parsed. |
| - ERR_clear_error(); |
| - } |
| - return status; |
| -} |
| - |
| - |
| -void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( |
| - Dart_NativeArguments args) { |
| - SSLContext* context = GetSecurityContext(args); |
| - const char* password = GetPasswordArgument(args, 2); |
| - |
| - int status; |
| - { |
| - ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| - status = SetClientAuthorities(context->context(), bio.bio(), password); |
| - } |
| - |
| - CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes"); |
| + // SecureSocketUtils::CheckStatus should also throw an exception in uncaught |
| + // cases. |
| + SecureSocketUtils::CheckStatus(status, "TlsException", |
| + "Failure in usePrivateKeyBytes"); |
| } |
| void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( |
| Dart_NativeArguments args) { |
| - SSLContext* context = GetSecurityContext(args); |
| + SSLCertContext* context = SSLCertContext::GetSecurityContext(args); |
| Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| Dart_Handle is_server_handle = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| if (Dart_IsBoolean(is_server_handle)) { |
| @@ -1122,51 +459,6 @@ void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( |
| } |
| -void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) { |
| - X509* certificate = GetX509Certificate(args); |
| - X509_NAME* subject = X509_get_subject_name(certificate); |
| - char* subject_string = X509_NAME_oneline(subject, NULL, 0); |
| - Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_string)); |
| - OPENSSL_free(subject_string); |
| -} |
| - |
| - |
| -void FUNCTION_NAME(X509_Issuer)(Dart_NativeArguments args) { |
| - X509* certificate = GetX509Certificate(args); |
| - X509_NAME* issuer = X509_get_issuer_name(certificate); |
| - char* issuer_string = X509_NAME_oneline(issuer, NULL, 0); |
| - Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_string)); |
| - OPENSSL_free(issuer_string); |
| -} |
| - |
| -static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME* aTime) { |
| - ASN1_UTCTIME* epoch_start = M_ASN1_UTCTIME_new(); |
| - ASN1_UTCTIME_set_string(epoch_start, "700101000000Z"); |
| - int days; |
| - int seconds; |
| - int result = ASN1_TIME_diff(&days, &seconds, epoch_start, aTime); |
| - M_ASN1_UTCTIME_free(epoch_start); |
| - if (result != 1) { |
| - // TODO(whesse): Propagate an error to Dart. |
| - Log::PrintErr("ASN1Time error %d\n", result); |
| - } |
| - return Dart_NewInteger((86400LL * days + seconds) * 1000LL); |
| -} |
| - |
| -void FUNCTION_NAME(X509_StartValidity)(Dart_NativeArguments args) { |
| - X509* certificate = GetX509Certificate(args); |
| - ASN1_TIME* not_before = X509_get_notBefore(certificate); |
| - Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_before)); |
| -} |
| - |
| - |
| -void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) { |
| - X509* certificate = GetX509Certificate(args); |
| - ASN1_TIME* not_after = X509_get_notAfter(certificate); |
| - Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_after)); |
| -} |
| - |
| - |
| /** |
| * Pushes data through the SSL filter, reading and writing from circular |
| * buffers shared with Dart. |
| @@ -1228,7 +520,7 @@ bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], |
| if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue; |
| int start = starts[i]; |
| int end = ends[i]; |
| - int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| + int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| if (start < 0 || end < 0 || start >= size || end >= size) { |
| FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket"); |
| } |
| @@ -1307,7 +599,6 @@ Dart_Handle SSLFilter::Init(Dart_Handle dart_this) { |
| ASSERT(bad_certificate_callback_ == NULL); |
| bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); |
| ASSERT(bad_certificate_callback_ != NULL); |
| - |
| // Caller handles cleanup on an error. |
| return InitializeBuffers(dart_this); |
| } |
| @@ -1355,7 +646,7 @@ Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
| RETURN_IF_ERROR(data_identifier); |
| for (int i = 0; i < kNumBuffers; i++) { |
| - int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| + int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| buffers_[i] = new uint8_t[size]; |
| ASSERT(buffers_[i] != NULL); |
| dart_buffer_objects_[i] = NULL; |
| @@ -1363,7 +654,7 @@ Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
| Dart_Handle result = Dart_Null(); |
| for (int i = 0; i < kNumBuffers; ++i) { |
| - int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| + int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| result = Dart_ListGetAt(dart_buffers_object, i); |
| if (Dart_IsError(result)) { |
| break; |
| @@ -1419,14 +710,6 @@ void SSLFilter::InitializeLibrary() { |
| } |
| -Dart_Handle SSLFilter::PeerCertificate() { |
| - // SSL_get_peer_certificate incs the refcount of certificate. X509_free is |
| - // called by the finalizer set up by WrappedX509Certificate. |
| - X509* certificate = SSL_get_peer_certificate(ssl_); |
| - return WrappedX509Certificate(certificate); |
| -} |
| - |
| - |
| int AlpnCallback(SSL* ssl, |
| const uint8_t** out, |
| uint8_t* outlen, |
| @@ -1460,7 +743,7 @@ int AlpnCallback(SSL* ssl, |
| // Sets the protocol list for ALPN on a SSL object or a context. |
| static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
| SSL* ssl, |
| - SSLContext* context, |
| + SSLCertContext* context, |
| bool is_server) { |
| // Enable ALPN (application layer protocol negotiation) if the caller provides |
| // a valid list of supported protocols. |
| @@ -1517,7 +800,7 @@ static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
| void SSLFilter::Connect(const char* hostname, |
| - SSL_CTX* context, |
| + SSLCertContext* context, |
| bool is_server, |
| bool request_client_certificate, |
| bool require_client_certificate, |
| @@ -1532,13 +815,16 @@ void SSLFilter::Connect(const char* hostname, |
| BIO* ssl_side; |
| status = BIO_new_bio_pair(&ssl_side, kInternalBIOSize, &socket_side_, |
| kInternalBIOSize); |
| - CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair", ssl_); |
| + SecureSocketUtils::CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair", |
| + ssl_); |
| - assert(context != NULL); |
| - ssl_ = SSL_new(context); |
| + ASSERT(context != NULL); |
| + ASSERT(context->context() != NULL); |
| + ssl_ = SSL_new(context->context()); |
| SSL_set_bio(ssl_, ssl_side, ssl_side); |
| SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right? |
| SSL_set_ex_data(ssl_, filter_ssl_index, this); |
| + RegisterCallbacks(context); |
| if (is_server_) { |
| int certificate_mode = |
| @@ -1550,7 +836,8 @@ void SSLFilter::Connect(const char* hostname, |
| } else { |
| SetAlpnProtocolList(protocols_handle, ssl_, NULL, false); |
| status = SSL_set_tlsext_host_name(ssl_, hostname); |
| - CheckStatusSSL(status, "TlsException", "Set SNI host name", ssl_); |
| + SecureSocketUtils::CheckStatusSSL(status, "TlsException", |
| + "Set SNI host name", ssl_); |
| // Sets the hostname in the certificate-checking object, so it is checked |
| // against the certificate presented by the server. |
| X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_); |
| @@ -1561,8 +848,8 @@ void SSLFilter::Connect(const char* hostname, |
| X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0); |
| status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters, |
| hostname_, strlen(hostname_)); |
| - CheckStatusSSL(status, "TlsException", |
| - "Set hostname for certificate checking", ssl_); |
| + SecureSocketUtils::CheckStatusSSL( |
| + status, "TlsException", "Set hostname for certificate checking", ssl_); |
| } |
| // Make the connection: |
| if (is_server_) { |
| @@ -1615,7 +902,7 @@ void SSLFilter::Handshake() { |
| in_handshake_ = true; |
| return; |
| } |
| - CheckStatusSSL( |
| + SecureSocketUtils::CheckStatusSSL( |
| status, "HandshakeException", |
| is_server_ ? "Handshake error in server" : "Handshake error in client", |
| ssl_); |
| @@ -1801,7 +1088,5 @@ int SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) { |
| } // namespace bin |
| } // namespace dart |
| -#endif // defined(HOST_OS_LINUX) |
| - |
| #endif // !defined(DART_IO_DISABLED) && |
| // !defined(DART_IO_SECURE_SOCKET_DISABLED) |