Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) | 5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) |
| 6 | 6 |
| 7 #include "platform/globals.h" | |
| 8 #if defined(HOST_OS_ANDROID) || defined(HOST_OS_LINUX) || \ | |
| 9 defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA) | |
| 10 | |
| 11 #include "bin/secure_socket.h" | 7 #include "bin/secure_socket.h" |
| 12 #include "bin/secure_socket_boringssl.h" | 8 #include "bin/secure_socket_utils.h" |
| 13 | 9 |
| 14 #include <errno.h> | 10 #include <errno.h> |
| 15 #include <fcntl.h> | 11 #include <fcntl.h> |
| 16 #include <stdarg.h> | 12 #include <stdarg.h> |
| 17 #include <stdio.h> | 13 #include <stdio.h> |
| 18 #include <string.h> | 14 #include <string.h> |
| 19 #include <sys/stat.h> | 15 #include <sys/stat.h> |
| 20 | 16 |
| 21 #include <openssl/bio.h> | 17 #include <openssl/bio.h> |
| 22 #include <openssl/err.h> | 18 #include <openssl/err.h> |
| 23 #include <openssl/pkcs12.h> | 19 #include <openssl/pkcs12.h> |
| 24 #include <openssl/safestack.h> | 20 #include <openssl/safestack.h> |
| 25 #include <openssl/ssl.h> | 21 #include <openssl/ssl.h> |
| 26 #include <openssl/tls1.h> | 22 #include <openssl/tls1.h> |
| 27 #include <openssl/x509.h> | 23 #include <openssl/x509.h> |
| 28 | 24 |
| 25 #include "platform/globals.h" | |
| 26 | |
| 29 #include "bin/builtin.h" | 27 #include "bin/builtin.h" |
| 30 #include "bin/dartutils.h" | 28 #include "bin/dartutils.h" |
| 31 #include "bin/directory.h" | 29 #include "bin/directory.h" |
| 32 #include "bin/file.h" | 30 #include "bin/file.h" |
| 33 #include "bin/lockers.h" | 31 #include "bin/lockers.h" |
| 34 #include "bin/log.h" | 32 #include "bin/log.h" |
| 35 #include "bin/socket.h" | 33 #include "bin/socket.h" |
| 36 #include "bin/thread.h" | 34 #include "bin/thread.h" |
| 37 #include "bin/utils.h" | 35 #include "bin/utils.h" |
| 38 #include "platform/text_buffer.h" | 36 #include "platform/text_buffer.h" |
| 39 #include "platform/utils.h" | 37 #include "platform/utils.h" |
| 40 | |
| 41 #include "include/dart_api.h" | |
| 42 | |
| 43 // Return the error from the containing function if handle is an error handle. | 38 // Return the error from the containing function if handle is an error handle. |
| 44 #define RETURN_IF_ERROR(handle) \ | 39 #define RETURN_IF_ERROR(handle) \ |
| 45 { \ | 40 { \ |
| 46 Dart_Handle __handle = handle; \ | 41 Dart_Handle __handle = handle; \ |
| 47 if (Dart_IsError((__handle))) { \ | 42 if (Dart_IsError((__handle))) { \ |
| 48 return __handle; \ | 43 return __handle; \ |
| 49 } \ | 44 } \ |
| 50 } | 45 } |
| 51 | 46 |
| 52 namespace dart { | 47 namespace dart { |
| 53 namespace bin { | 48 namespace bin { |
| 54 | 49 |
| 55 bool SSLFilter::library_initialized_ = false; | 50 bool SSLFilter::library_initialized_ = false; |
| 56 // To protect library initialization. | 51 // To protect library initialization. |
| 57 Mutex* SSLFilter::mutex_ = new Mutex(); | 52 Mutex* SSLFilter::mutex_ = new Mutex(); |
| 58 int SSLFilter::filter_ssl_index; | 53 int SSLFilter::filter_ssl_index; |
| 59 | 54 |
| 60 const intptr_t SSLFilter::kInternalBIOSize = 10 * KB; | 55 const intptr_t SSLFilter::kInternalBIOSize = 10 * KB; |
| 61 const intptr_t SSLFilter::kApproximateSize = | 56 const intptr_t SSLFilter::kApproximateSize = |
| 62 sizeof(SSLFilter) + (2 * SSLFilter::kInternalBIOSize); | 57 sizeof(SSLFilter) + (2 * SSLFilter::kInternalBIOSize); |
| 63 | 58 |
| 64 // The security context won't necessarily use the compiled-in root certificates, | |
| 65 // but since there is no way to update the size of the allocation after creating | |
| 66 // the weak persistent handle, we assume that it will. Note that when the | |
| 67 // root certs aren't compiled in, |root_certificates_pem_length| is 0. | |
| 68 const intptr_t SSLContext::kApproximateSize = | |
| 69 sizeof(SSLContext) + root_certificates_pem_length; | |
| 70 | |
| 71 static const int kSSLFilterNativeFieldIndex = 0; | |
| 72 static const int kSecurityContextNativeFieldIndex = 0; | |
| 73 static const int kX509NativeFieldIndex = 0; | |
| 74 | |
| 75 static const bool SSL_LOG_STATUS = false; | |
| 76 static const bool SSL_LOG_DATA = false; | |
| 77 | |
| 78 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000; | 59 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000; |
| 79 | 60 |
| 80 const char* commandline_root_certs_file = NULL; | |
| 81 const char* commandline_root_certs_cache = NULL; | |
| 82 | |
| 83 // Get the error messages from BoringSSL, and put them in buffer as a | 61 // Get the error messages from BoringSSL, and put them in buffer as a |
| 84 // null-terminated string. | 62 // null-terminated string. |
| 85 static void FetchErrorString(const SSL* ssl, TextBuffer* text_buffer) { | 63 static void FetchErrorString(const SSL* ssl, TextBuffer* text_buffer) { |
| 86 const char* sep = File::PathSeparator(); | 64 const char* sep = File::PathSeparator(); |
| 87 while (true) { | 65 while (true) { |
| 88 const char* path = NULL; | 66 const char* path = NULL; |
| 89 int line = -1; | 67 int line = -1; |
| 90 uint32_t error = ERR_get_error_line(&path, &line); | 68 uint32_t error = ERR_get_error_line(&path, &line); |
| 91 if (error == 0) { | 69 if (error == 0) { |
| 92 break; | 70 break; |
| 93 } | 71 } |
| 94 text_buffer->Printf("\n\t%s", ERR_reason_error_string(error)); | 72 text_buffer->Printf("\n\t%s", ERR_reason_error_string(error)); |
| 95 if ((ssl != NULL) && (ERR_GET_LIB(error) == ERR_LIB_SSL) && | 73 if ((ssl != NULL) && (ERR_GET_LIB(error) == ERR_LIB_SSL) && |
| 96 (ERR_GET_REASON(error) == SSL_R_CERTIFICATE_VERIFY_FAILED)) { | 74 (ERR_GET_REASON(error) == SSL_R_CERTIFICATE_VERIFY_FAILED)) { |
| 97 intptr_t result = SSL_get_verify_result(ssl); | 75 intptr_t result = SSL_get_verify_result(ssl); |
| 98 text_buffer->Printf(": %s", X509_verify_cert_error_string(result)); | 76 text_buffer->Printf(": %s", X509_verify_cert_error_string(result)); |
| 99 } | 77 } |
| 100 if ((path != NULL) && (line >= 0)) { | 78 if ((path != NULL) && (line >= 0)) { |
| 101 const char* file = strrchr(path, sep[0]); | 79 const char* file = strrchr(path, sep[0]); |
| 102 path = file ? file + 1 : path; | 80 path = file ? file + 1 : path; |
| 103 text_buffer->Printf("(%s:%d)", path, line); | 81 text_buffer->Printf("(%s:%d)", path, line); |
| 104 } | 82 } |
| 105 } | 83 } |
| 106 } | 84 } |
| 107 | 85 |
| 108 | 86 |
| 109 // Handle an error reported from the BoringSSL library. | 87 // Handle an error reported from the BoringSSL library. |
| 110 static void ThrowIOException(int status, | 88 void SecureSocketUtils::ThrowIOException(int status, |
|
zra
2017/05/30 16:15:36
Please keep the SecureSocketUtils methods all toge
| |
| 111 const char* exception_type, | 89 const char* exception_type, |
| 112 const char* message, | 90 const char* message, |
| 113 const SSL* ssl) { | 91 const SSL* ssl) { |
| 114 Dart_Handle exception; | 92 Dart_Handle exception; |
| 115 { | 93 { |
| 116 TextBuffer error_string(SSL_ERROR_MESSAGE_BUFFER_SIZE); | 94 TextBuffer error_string(SSL_ERROR_MESSAGE_BUFFER_SIZE); |
| 117 FetchErrorString(ssl, &error_string); | 95 FetchErrorString(ssl, &error_string); |
| 118 OSError os_error_struct(status, error_string.buf(), OSError::kBoringSSL); | 96 OSError os_error_struct(status, error_string.buf(), OSError::kBoringSSL); |
| 119 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); | 97 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); |
| 120 exception = | 98 exception = |
| 121 DartUtils::NewDartIOException(exception_type, message, os_error); | 99 DartUtils::NewDartIOException(exception_type, message, os_error); |
| 122 ASSERT(!Dart_IsError(exception)); | 100 ASSERT(!Dart_IsError(exception)); |
| 123 } | 101 } |
| 124 Dart_ThrowException(exception); | 102 Dart_ThrowException(exception); |
| 125 UNREACHABLE(); | 103 UNREACHABLE(); |
| 126 } | 104 } |
| 127 | 105 |
| 128 | 106 |
| 129 static SSLFilter* GetFilter(Dart_NativeArguments args) { | 107 static SSLFilter* GetFilter(Dart_NativeArguments args) { |
| 130 SSLFilter* filter; | 108 SSLFilter* filter; |
| 131 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 109 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 132 ASSERT(Dart_IsInstance(dart_this)); | 110 ASSERT(Dart_IsInstance(dart_this)); |
| 133 ThrowIfError( | 111 ThrowIfError(Dart_GetNativeInstanceField( |
| 134 Dart_GetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex, | 112 dart_this, SSLFilter::kSSLFilterNativeFieldIndex, |
| 135 reinterpret_cast<intptr_t*>(&filter))); | 113 reinterpret_cast<intptr_t*>(&filter))); |
| 136 return filter; | 114 return filter; |
| 137 } | 115 } |
| 138 | 116 |
| 139 | 117 |
| 140 static void DeleteFilter(void* isolate_data, | 118 static void DeleteFilter(void* isolate_data, |
| 141 Dart_WeakPersistentHandle handle, | 119 Dart_WeakPersistentHandle handle, |
| 142 void* context_pointer) { | 120 void* context_pointer) { |
| 143 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer); | 121 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer); |
| 144 filter->Release(); | 122 filter->Release(); |
| 145 } | 123 } |
| 146 | 124 |
| 147 | 125 |
| 148 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) { | 126 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) { |
| 149 ASSERT(filter != NULL); | 127 ASSERT(filter != NULL); |
| 150 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); | 128 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); |
| 151 RETURN_IF_ERROR(dart_this); | 129 RETURN_IF_ERROR(dart_this); |
| 152 ASSERT(Dart_IsInstance(dart_this)); | 130 ASSERT(Dart_IsInstance(dart_this)); |
| 153 Dart_Handle err = | 131 Dart_Handle err = Dart_SetNativeInstanceField( |
| 154 Dart_SetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex, | 132 dart_this, SSLFilter::kSSLFilterNativeFieldIndex, |
| 155 reinterpret_cast<intptr_t>(filter)); | 133 reinterpret_cast<intptr_t>(filter)); |
| 156 RETURN_IF_ERROR(err); | 134 RETURN_IF_ERROR(err); |
| 157 Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter), | 135 Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter), |
| 158 SSLFilter::kApproximateSize, DeleteFilter); | 136 SSLFilter::kApproximateSize, DeleteFilter); |
| 159 return Dart_Null(); | 137 return Dart_Null(); |
| 160 } | 138 } |
| 161 | 139 |
| 162 | 140 |
| 163 static SSLContext* GetSecurityContext(Dart_NativeArguments args) { | 141 SSLCertContext* SSLCertContext::GetSecurityContext(Dart_NativeArguments args) { |
| 164 SSLContext* context; | 142 SSLCertContext* context; |
| 165 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 143 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 166 ASSERT(Dart_IsInstance(dart_this)); | 144 ASSERT(Dart_IsInstance(dart_this)); |
| 167 ThrowIfError( | 145 ThrowIfError(Dart_GetNativeInstanceField( |
| 168 Dart_GetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex, | 146 dart_this, SSLCertContext::kSecurityContextNativeFieldIndex, |
| 169 reinterpret_cast<intptr_t*>(&context))); | 147 reinterpret_cast<intptr_t*>(&context))); |
| 170 return context; | 148 return context; |
| 171 } | 149 } |
| 172 | 150 |
| 173 | 151 |
| 174 static void DeleteSecurityContext(void* isolate_data, | 152 static void DeleteSecurityContext(void* isolate_data, |
| 175 Dart_WeakPersistentHandle handle, | 153 Dart_WeakPersistentHandle handle, |
| 176 void* context_pointer) { | 154 void* context_pointer) { |
| 177 SSLContext* context = static_cast<SSLContext*>(context_pointer); | 155 SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer); |
| 178 delete context; | 156 context->Release(); |
| 179 } | 157 } |
| 180 | 158 |
| 181 | 159 |
| 182 static Dart_Handle SetSecurityContext(Dart_NativeArguments args, | 160 static Dart_Handle SetSecurityContext(Dart_NativeArguments args, |
| 183 SSLContext* context) { | 161 SSLCertContext* context) { |
| 184 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); | 162 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); |
| 185 RETURN_IF_ERROR(dart_this); | 163 RETURN_IF_ERROR(dart_this); |
| 186 ASSERT(Dart_IsInstance(dart_this)); | 164 ASSERT(Dart_IsInstance(dart_this)); |
| 187 Dart_Handle err = | 165 Dart_Handle err = Dart_SetNativeInstanceField( |
| 188 Dart_SetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex, | 166 dart_this, SSLCertContext::kSecurityContextNativeFieldIndex, |
| 189 reinterpret_cast<intptr_t>(context)); | 167 reinterpret_cast<intptr_t>(context)); |
| 190 RETURN_IF_ERROR(err); | 168 RETURN_IF_ERROR(err); |
| 191 Dart_NewWeakPersistentHandle(dart_this, context, SSLContext::kApproximateSize, | 169 Dart_NewWeakPersistentHandle(dart_this, context, |
| 170 SSLCertContext::kApproximateSize, | |
| 192 DeleteSecurityContext); | 171 DeleteSecurityContext); |
| 193 return Dart_Null(); | 172 return Dart_Null(); |
| 194 } | 173 } |
| 195 | 174 |
| 196 | 175 |
| 197 static X509* GetX509Certificate(Dart_NativeArguments args) { | |
| 198 X509* certificate; | |
| 199 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
| 200 ASSERT(Dart_IsInstance(dart_this)); | |
| 201 ThrowIfError( | |
| 202 Dart_GetNativeInstanceField(dart_this, kX509NativeFieldIndex, | |
| 203 reinterpret_cast<intptr_t*>(&certificate))); | |
| 204 return certificate; | |
| 205 } | |
| 206 | |
| 207 | |
| 208 // Forward declaration. | 176 // Forward declaration. |
| 209 static void SetAlpnProtocolList(Dart_Handle protocols_handle, | 177 static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
| 210 SSL* ssl, | 178 SSL* ssl, |
| 211 SSLContext* context, | 179 SSLCertContext* context, |
| 212 bool is_server); | 180 bool is_server); |
| 213 | 181 |
| 214 | 182 |
| 215 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { | 183 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { |
| 216 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 184 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 217 SSLFilter* filter = new SSLFilter(); | 185 SSLFilter* filter = new SSLFilter(); |
| 218 Dart_Handle err = SetFilter(args, filter); | 186 Dart_Handle err = SetFilter(args, filter); |
| 219 if (Dart_IsError(err)) { | 187 if (Dart_IsError(err)) { |
| 220 filter->Release(); | 188 filter->Release(); |
| 221 Dart_PropagateError(err); | 189 Dart_PropagateError(err); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 237 bool request_client_certificate = | 205 bool request_client_certificate = |
| 238 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); | 206 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); |
| 239 bool require_client_certificate = | 207 bool require_client_certificate = |
| 240 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); | 208 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); |
| 241 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 6)); | 209 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 6)); |
| 242 | 210 |
| 243 const char* host_name = NULL; | 211 const char* host_name = NULL; |
| 244 // TODO(whesse): Is truncating a Dart string containing \0 what we want? | 212 // TODO(whesse): Is truncating a Dart string containing \0 what we want? |
| 245 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); | 213 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); |
| 246 | 214 |
| 247 SSLContext* context = NULL; | 215 SSLCertContext* context = NULL; |
| 248 if (!Dart_IsNull(context_object)) { | 216 if (!Dart_IsNull(context_object)) { |
| 249 ThrowIfError(Dart_GetNativeInstanceField( | 217 ThrowIfError(Dart_GetNativeInstanceField( |
| 250 context_object, kSecurityContextNativeFieldIndex, | 218 context_object, SSLCertContext::kSecurityContextNativeFieldIndex, |
| 251 reinterpret_cast<intptr_t*>(&context))); | 219 reinterpret_cast<intptr_t*>(&context))); |
| 252 } | 220 } |
| 253 | 221 |
| 254 // The protocols_handle is guaranteed to be a valid Uint8List. | 222 // The protocols_handle is guaranteed to be a valid Uint8List. |
| 255 // It will have the correct length encoding of the protocols array. | 223 // It will have the correct length encoding of the protocols array. |
| 256 ASSERT(!Dart_IsNull(protocols_handle)); | 224 ASSERT(!Dart_IsNull(protocols_handle)); |
| 257 | 225 |
| 258 GetFilter(args)->Connect(host_name, context->context(), is_server, | 226 GetFilter(args)->Connect(host_name, context, is_server, |
| 259 request_client_certificate, | 227 request_client_certificate, |
| 260 require_client_certificate, protocols_handle); | 228 require_client_certificate, protocols_handle); |
| 261 } | 229 } |
| 262 | 230 |
| 263 | 231 |
| 264 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { | 232 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { |
| 265 SSLFilter* filter = GetFilter(args); | 233 SSLFilter* filter = GetFilter(args); |
| 266 // There are two paths that can clean up an SSLFilter object. First, | 234 // There are two paths that can clean up an SSLFilter object. First, |
| 267 // there is this explicit call to Destroy(), called from | 235 // there is this explicit call to Destroy(), called from |
| 268 // _SecureFilter.destroy() in Dart code. After a call to destroy(), the Dart | 236 // _SecureFilter.destroy() in Dart code. After a call to destroy(), the Dart |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 332 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { | 300 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { |
| 333 SSLFilter* filter = GetFilter(args); | 301 SSLFilter* filter = GetFilter(args); |
| 334 // This filter pointer is passed to the IO Service thread. The IO Service | 302 // This filter pointer is passed to the IO Service thread. The IO Service |
| 335 // thread must Release() the pointer when it is done with it. | 303 // thread must Release() the pointer when it is done with it. |
| 336 filter->Retain(); | 304 filter->Retain(); |
| 337 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter); | 305 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter); |
| 338 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); | 306 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); |
| 339 } | 307 } |
| 340 | 308 |
| 341 | 309 |
| 342 static void ReleaseCertificate(void* isolate_data, | |
| 343 Dart_WeakPersistentHandle handle, | |
| 344 void* context_pointer) { | |
| 345 X509* cert = reinterpret_cast<X509*>(context_pointer); | |
| 346 X509_free(cert); | |
| 347 } | |
| 348 | |
| 349 | |
| 350 static intptr_t EstimateX509Size(X509* certificate) { | |
| 351 intptr_t length = i2d_X509(certificate, NULL); | |
| 352 return length > 0 ? length : 0; | |
| 353 } | |
| 354 | |
| 355 | |
| 356 // Returns the handle for a Dart object wrapping the X509 certificate object. | |
| 357 // The caller should own a reference to the X509 object whose reference count | |
| 358 // won't drop to zero before the ReleaseCertificate finalizer runs. | |
| 359 static Dart_Handle WrappedX509Certificate(X509* certificate) { | |
| 360 if (certificate == NULL) { | |
| 361 return Dart_Null(); | |
| 362 } | |
| 363 Dart_Handle x509_type = | |
| 364 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); | |
| 365 if (Dart_IsError(x509_type)) { | |
| 366 X509_free(certificate); | |
| 367 return x509_type; | |
| 368 } | |
| 369 Dart_Handle arguments[] = {NULL}; | |
| 370 Dart_Handle result = | |
| 371 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments); | |
| 372 if (Dart_IsError(result)) { | |
| 373 X509_free(certificate); | |
| 374 return result; | |
| 375 } | |
| 376 ASSERT(Dart_IsInstance(result)); | |
| 377 Dart_Handle status = Dart_SetNativeInstanceField( | |
| 378 result, kX509NativeFieldIndex, reinterpret_cast<intptr_t>(certificate)); | |
| 379 if (Dart_IsError(status)) { | |
| 380 X509_free(certificate); | |
| 381 return status; | |
| 382 } | |
| 383 const intptr_t approximate_size_of_certificate = | |
| 384 sizeof(*certificate) + EstimateX509Size(certificate); | |
| 385 ASSERT(approximate_size_of_certificate > 0); | |
| 386 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate), | |
| 387 approximate_size_of_certificate, | |
| 388 ReleaseCertificate); | |
| 389 return result; | |
| 390 } | |
| 391 | |
| 392 | |
| 393 int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) { | |
| 394 if (preverify_ok == 1) { | |
| 395 return 1; | |
| 396 } | |
| 397 Dart_Isolate isolate = Dart_CurrentIsolate(); | |
| 398 if (isolate == NULL) { | |
| 399 FATAL("CertificateCallback called with no current isolate\n"); | |
| 400 } | |
| 401 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx); | |
| 402 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx(); | |
| 403 SSL* ssl = | |
| 404 static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index)); | |
| 405 SSLFilter* filter = static_cast<SSLFilter*>( | |
| 406 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index)); | |
| 407 Dart_Handle callback = filter->bad_certificate_callback(); | |
| 408 if (Dart_IsNull(callback)) { | |
| 409 return 0; | |
| 410 } | |
| 411 | |
| 412 // Upref since the Dart X509 object may outlive the SecurityContext. | |
| 413 if (certificate != NULL) { | |
| 414 X509_up_ref(certificate); | |
| 415 } | |
| 416 Dart_Handle args[1]; | |
| 417 args[0] = WrappedX509Certificate(certificate); | |
| 418 if (Dart_IsError(args[0])) { | |
| 419 filter->callback_error = args[0]; | |
| 420 return 0; | |
| 421 } | |
| 422 Dart_Handle result = Dart_InvokeClosure(callback, 1, args); | |
| 423 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) { | |
| 424 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException( | |
| 425 "HandshakeException", | |
| 426 "BadCertificateCallback returned a value that was not a boolean", | |
| 427 Dart_Null())); | |
| 428 } | |
| 429 if (Dart_IsError(result)) { | |
| 430 filter->callback_error = result; | |
| 431 return 0; | |
| 432 } | |
| 433 return DartUtils::GetBooleanValue(result); | |
| 434 } | |
| 435 | |
| 436 | |
| 437 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) { | 310 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) { |
| 438 SSLFilter::InitializeLibrary(); | 311 SSLFilter::InitializeLibrary(); |
| 439 SSL_CTX* ctx = SSL_CTX_new(TLS_method()); | 312 SSL_CTX* ctx = SSL_CTX_new(TLS_method()); |
| 440 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, CertificateCallback); | 313 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, CertificateCallback); |
| 441 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); | 314 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); |
| 442 SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM"); | 315 SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM"); |
| 443 SSLContext* context = new SSLContext(ctx); | 316 SSLCertContext* context = new SSLCertContext(ctx); |
| 444 Dart_Handle err = SetSecurityContext(args, context); | 317 Dart_Handle err = SetSecurityContext(args, context); |
| 445 if (Dart_IsError(err)) { | 318 if (Dart_IsError(err)) { |
| 446 delete context; | 319 delete context; |
| 447 Dart_PropagateError(err); | 320 Dart_PropagateError(err); |
| 448 } | 321 } |
| 449 } | 322 } |
| 450 | 323 |
| 451 | 324 |
| 452 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) { | 325 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) { |
| 453 char* password = static_cast<char*>(userdata); | 326 char* password = static_cast<char*>(userdata); |
| 454 ASSERT(size == PEM_BUFSIZE); | 327 ASSERT(size == PEM_BUFSIZE); |
| 455 strncpy(buf, password, size); | 328 strncpy(buf, password, size); |
| 456 return strlen(password); | 329 return strlen(password); |
| 457 } | 330 } |
| 458 | 331 |
| 459 | 332 |
| 460 void CheckStatusSSL(int status, | 333 void SecureSocketUtils::CheckStatusSSL(int status, |
| 461 const char* type, | 334 const char* type, |
| 462 const char* message, | 335 const char* message, |
| 463 const SSL* ssl) { | 336 const SSL* ssl) { |
| 464 // TODO(24183): Take appropriate action on failed calls, | 337 // TODO(24183): Take appropriate action on failed calls, |
| 465 // throw exception that includes all messages from the error stack. | 338 // throw exception that includes all messages from the error stack. |
| 466 if (status == 1) { | 339 if (status == 1) { |
| 467 return; | 340 return; |
| 468 } | 341 } |
| 469 if (SSL_LOG_STATUS) { | 342 if (SSL_LOG_STATUS) { |
| 470 int error = ERR_get_error(); | 343 int error = ERR_get_error(); |
| 471 Log::PrintErr("Failed: %s status %d", message, status); | 344 Log::PrintErr("Failed: %s status %d", message, status); |
| 472 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; | 345 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; |
| 473 ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); | 346 ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); |
| 474 Log::PrintErr("ERROR: %d %s\n", error, error_string); | 347 Log::PrintErr("ERROR: %d %s\n", error, error_string); |
| 475 } | 348 } |
| 476 ThrowIOException(status, type, message, ssl); | 349 SecureSocketUtils::ThrowIOException(status, type, message, ssl); |
| 477 } | 350 } |
| 478 | 351 |
| 479 | 352 |
| 480 void CheckStatus(int status, const char* type, const char* message) { | 353 void SecureSocketUtils::CheckStatus(int status, |
| 481 CheckStatusSSL(status, type, message, NULL); | 354 const char* type, |
| 355 const char* message) { | |
| 356 SecureSocketUtils::CheckStatusSSL(status, type, message, NULL); | |
| 482 } | 357 } |
| 483 | 358 |
| 484 | 359 |
| 485 // Where the argument to the constructor is the handle for an object | |
| 486 // implementing List<int>, this class creates a scope in which a memory-backed | |
| 487 // BIO is allocated. Leaving the scope cleans up the BIO and the buffer that | |
| 488 // was used to create it. | |
| 489 // | |
| 490 // Do not make Dart_ API calls while in a ScopedMemBIO. | |
| 491 // Do not call Dart_PropagateError while in a ScopedMemBIO. | |
| 492 class ScopedMemBIO { | |
| 493 public: | |
| 494 explicit ScopedMemBIO(Dart_Handle object) { | |
| 495 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { | |
| 496 Dart_ThrowException( | |
| 497 DartUtils::NewDartArgumentError("Argument is not a List<int>")); | |
| 498 } | |
| 499 | |
| 500 uint8_t* bytes = NULL; | |
| 501 intptr_t bytes_len = 0; | |
| 502 bool is_typed_data = false; | |
| 503 if (Dart_IsTypedData(object)) { | |
| 504 is_typed_data = true; | |
| 505 Dart_TypedData_Type typ; | |
| 506 ThrowIfError(Dart_TypedDataAcquireData( | |
| 507 object, &typ, reinterpret_cast<void**>(&bytes), &bytes_len)); | |
| 508 } else { | |
| 509 ASSERT(Dart_IsList(object)); | |
| 510 ThrowIfError(Dart_ListLength(object, &bytes_len)); | |
| 511 bytes = Dart_ScopeAllocate(bytes_len); | |
| 512 ASSERT(bytes != NULL); | |
| 513 ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len)); | |
| 514 } | |
| 515 | |
| 516 object_ = object; | |
| 517 bytes_ = bytes; | |
| 518 bytes_len_ = bytes_len; | |
| 519 bio_ = BIO_new_mem_buf(bytes, bytes_len); | |
| 520 ASSERT(bio_ != NULL); | |
| 521 is_typed_data_ = is_typed_data; | |
| 522 } | |
| 523 | |
| 524 ~ScopedMemBIO() { | |
| 525 ASSERT(bio_ != NULL); | |
| 526 if (is_typed_data_) { | |
| 527 BIO_free(bio_); | |
| 528 ThrowIfError(Dart_TypedDataReleaseData(object_)); | |
| 529 } else { | |
| 530 BIO_free(bio_); | |
| 531 } | |
| 532 } | |
| 533 | |
| 534 BIO* bio() { | |
| 535 ASSERT(bio_ != NULL); | |
| 536 return bio_; | |
| 537 } | |
| 538 | |
| 539 private: | |
| 540 Dart_Handle object_; | |
| 541 uint8_t* bytes_; | |
| 542 intptr_t bytes_len_; | |
| 543 BIO* bio_; | |
| 544 bool is_typed_data_; | |
| 545 | |
| 546 DISALLOW_ALLOCATION(); | |
| 547 DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO); | |
| 548 }; | |
| 549 | |
| 550 template <typename T, void (*free_func)(T*)> | |
| 551 class ScopedSSLType { | |
| 552 public: | |
| 553 explicit ScopedSSLType(T* obj) : obj_(obj) {} | |
| 554 | |
| 555 ~ScopedSSLType() { | |
| 556 if (obj_ != NULL) { | |
| 557 free_func(obj_); | |
| 558 } | |
| 559 } | |
| 560 | |
| 561 T* get() { return obj_; } | |
| 562 const T* get() const { return obj_; } | |
| 563 | |
| 564 T* release() { | |
| 565 T* result = obj_; | |
| 566 obj_ = NULL; | |
| 567 return result; | |
| 568 } | |
| 569 | |
| 570 private: | |
| 571 T* obj_; | |
| 572 | |
| 573 DISALLOW_ALLOCATION(); | |
| 574 DISALLOW_COPY_AND_ASSIGN(ScopedSSLType); | |
| 575 }; | |
| 576 | |
| 577 template <typename T, typename E, void (*func)(E*)> | |
| 578 class ScopedSSLStackType { | |
| 579 public: | |
| 580 explicit ScopedSSLStackType(T* obj) : obj_(obj) {} | |
| 581 | |
| 582 ~ScopedSSLStackType() { | |
| 583 if (obj_ != NULL) { | |
| 584 sk_pop_free(reinterpret_cast<_STACK*>(obj_), | |
| 585 reinterpret_cast<void (*)(void*)>(func)); | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 T* get() { return obj_; } | |
| 590 const T* get() const { return obj_; } | |
| 591 | |
| 592 T* release() { | |
| 593 T* result = obj_; | |
| 594 obj_ = NULL; | |
| 595 return result; | |
| 596 } | |
| 597 | |
| 598 private: | |
| 599 T* obj_; | |
| 600 | |
| 601 DISALLOW_ALLOCATION(); | |
| 602 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); | |
| 603 }; | |
| 604 | |
| 605 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; | |
| 606 typedef ScopedSSLType<X509, X509_free> ScopedX509; | |
| 607 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; | |
| 608 | |
| 609 static bool NoPEMStartLine() { | |
| 610 uint32_t last_error = ERR_peek_last_error(); | |
| 611 return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && | |
| 612 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); | |
| 613 } | |
| 614 | |
| 615 | |
| 616 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { | 360 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { |
| 617 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | 361 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
| 618 if (p12.get() == NULL) { | 362 if (p12.get() == NULL) { |
| 619 return NULL; | 363 return NULL; |
| 620 } | 364 } |
| 621 | 365 |
| 622 EVP_PKEY* key = NULL; | 366 EVP_PKEY* key = NULL; |
| 623 X509* cert = NULL; | 367 X509* cert = NULL; |
| 624 STACK_OF(X509)* ca_certs = NULL; | 368 STACK_OF(X509)* ca_certs = NULL; |
| 625 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | 369 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
| 626 if (status == 0) { | 370 if (status == 0) { |
| 627 return NULL; | 371 return NULL; |
| 628 } | 372 } |
| 629 | 373 |
| 630 // We only care about the private key. | 374 // We only care about the private key. |
| 631 ScopedX509 delete_cert(cert); | 375 ScopedX509 delete_cert(cert); |
| 632 ScopedX509Stack delete_ca_certs(ca_certs); | 376 ScopedX509Stack delete_ca_certs(ca_certs); |
| 633 return key; | 377 return key; |
| 634 } | 378 } |
| 635 | 379 |
| 636 | 380 |
| 637 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { | 381 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { |
| 638 EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, PasswordCallback, | 382 EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, PasswordCallback, |
| 639 const_cast<char*>(password)); | 383 const_cast<char*>(password)); |
| 640 if (key == NULL) { | 384 if (key == NULL) { |
| 641 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and | 385 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and |
| 642 // if there is no indication that the data is malformed PEM. We assume the | 386 // if there is no indication that the data is malformed PEM. We assume the |
| 643 // data is malformed PEM if it contains the start line, i.e. a line | 387 // data is malformed PEM if it contains the start line, i.e. a line |
| 644 // with ----- BEGIN. | 388 // with ----- BEGIN. |
| 645 if (NoPEMStartLine()) { | 389 if (SecureSocketUtils::NoPEMStartLine()) { |
| 646 // Reset the bio, and clear the error from trying to read as PEM. | 390 // Reset the bio, and clear the error from trying to read as PEM. |
| 647 ERR_clear_error(); | 391 ERR_clear_error(); |
| 648 BIO_reset(bio); | 392 BIO_reset(bio); |
| 649 | 393 |
| 650 // Try to decode as PKCS12. | 394 // Try to decode as PKCS12. |
| 651 key = GetPrivateKeyPKCS12(bio, password); | 395 key = GetPrivateKeyPKCS12(bio, password); |
| 652 } | 396 } |
| 653 } | 397 } |
| 654 return key; | 398 return key; |
| 655 } | 399 } |
| 656 | 400 |
| 657 | 401 |
| 658 static const char* GetPasswordArgument(Dart_NativeArguments args, | 402 const char* SSLCertContext::GetPasswordArgument(Dart_NativeArguments args, |
| 659 intptr_t index) { | 403 intptr_t index) { |
| 660 Dart_Handle password_object = | 404 Dart_Handle password_object = |
| 661 ThrowIfError(Dart_GetNativeArgument(args, index)); | 405 ThrowIfError(Dart_GetNativeArgument(args, index)); |
| 662 const char* password = NULL; | 406 const char* password = NULL; |
| 663 if (Dart_IsString(password_object)) { | 407 if (Dart_IsString(password_object)) { |
| 664 ThrowIfError(Dart_StringToCString(password_object, &password)); | 408 ThrowIfError(Dart_StringToCString(password_object, &password)); |
| 665 if (strlen(password) > PEM_BUFSIZE - 1) { | 409 if (strlen(password) > PEM_BUFSIZE - 1) { |
| 666 Dart_ThrowException(DartUtils::NewDartArgumentError( | 410 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 667 "Password length is greater than 1023 (PEM_BUFSIZE)")); | 411 "Password length is greater than 1023 (PEM_BUFSIZE)")); |
| 668 } | 412 } |
| 669 } else if (Dart_IsNull(password_object)) { | 413 } else if (Dart_IsNull(password_object)) { |
| 670 password = ""; | 414 password = ""; |
| 671 } else { | 415 } else { |
| 672 Dart_ThrowException( | 416 Dart_ThrowException( |
| 673 DartUtils::NewDartArgumentError("Password is not a String or null")); | 417 DartUtils::NewDartArgumentError("Password is not a String or null")); |
| 674 } | 418 } |
| 675 return password; | 419 return password; |
| 676 } | 420 } |
| 677 | 421 |
| 678 | 422 |
| 679 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( | 423 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
| 680 Dart_NativeArguments args) { | 424 Dart_NativeArguments args) { |
| 681 SSLContext* context = GetSecurityContext(args); | 425 SSLCertContext* context = SSLCertContext::GetSecurityContext(args); |
| 682 const char* password = GetPasswordArgument(args, 2); | 426 const char* password = SSLCertContext::GetPasswordArgument(args, 2); |
| 683 | 427 |
| 684 int status; | 428 int status; |
| 685 { | 429 { |
| 686 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 430 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| 687 EVP_PKEY* key = GetPrivateKey(bio.bio(), password); | 431 EVP_PKEY* key = GetPrivateKey(bio.bio(), password); |
| 688 status = SSL_CTX_use_PrivateKey(context->context(), key); | 432 status = SSL_CTX_use_PrivateKey(context->context(), key); |
| 689 // SSL_CTX_use_PrivateKey increments the reference count of key on success, | 433 // SSL_CTX_use_PrivateKey increments the reference count of key on success, |
| 690 // so we have to call EVP_PKEY_free on both success and failure. | 434 // so we have to call EVP_PKEY_free on both success and failure. |
| 691 EVP_PKEY_free(key); | 435 EVP_PKEY_free(key); |
| 692 } | 436 } |
| 693 | 437 |
| 694 // TODO(24184): Handle different expected errors here - file missing, | 438 // TODO(24184): Handle different expected errors here - file missing, |
| 695 // incorrect password, file not a PEM, and throw exceptions. | 439 // incorrect password, file not a PEM, and throw exceptions. |
| 696 // CheckStatus should also throw an exception in uncaught cases. | 440 // SecureSocketUtils::CheckStatus should also throw an exception in uncaught |
| 697 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); | 441 // cases. |
| 698 } | 442 SecureSocketUtils::CheckStatus(status, "TlsException", |
| 699 | 443 "Failure in usePrivateKeyBytes"); |
| 700 | |
| 701 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, | |
| 702 BIO* bio, | |
| 703 const char* password) { | |
| 704 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
| 705 if (p12.get() == NULL) { | |
| 706 return 0; | |
| 707 } | |
| 708 | |
| 709 EVP_PKEY* key = NULL; | |
| 710 X509* cert = NULL; | |
| 711 STACK_OF(X509)* ca_certs = NULL; | |
| 712 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
| 713 if (status == 0) { | |
| 714 return status; | |
| 715 } | |
| 716 | |
| 717 ScopedX509Stack cert_stack(ca_certs); | |
| 718 X509_STORE* store = SSL_CTX_get_cert_store(context); | |
| 719 status = X509_STORE_add_cert(store, cert); | |
| 720 // X509_STORE_add_cert increments the reference count of cert on success. | |
| 721 X509_free(cert); | |
| 722 if (status == 0) { | |
| 723 return status; | |
| 724 } | |
| 725 | |
| 726 X509* ca; | |
| 727 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { | |
| 728 status = X509_STORE_add_cert(store, ca); | |
| 729 // X509_STORE_add_cert increments the reference count of cert on success. | |
| 730 X509_free(ca); | |
| 731 if (status == 0) { | |
| 732 return status; | |
| 733 } | |
| 734 } | |
| 735 | |
| 736 return status; | |
| 737 } | |
| 738 | |
| 739 | |
| 740 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) { | |
| 741 X509_STORE* store = SSL_CTX_get_cert_store(context); | |
| 742 | |
| 743 int status = 0; | |
| 744 X509* cert = NULL; | |
| 745 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | |
| 746 status = X509_STORE_add_cert(store, cert); | |
| 747 // X509_STORE_add_cert increments the reference count of cert on success. | |
| 748 X509_free(cert); | |
| 749 if (status == 0) { | |
| 750 return status; | |
| 751 } | |
| 752 } | |
| 753 | |
| 754 // If no PEM start line is found, it means that we read to the end of the | |
| 755 // file, or that the file isn't PEM. In the first case, status will be | |
| 756 // non-zero indicating success. In the second case, status will be 0, | |
| 757 // indicating that we should try to read as PKCS12. If there is some other | |
| 758 // error, we return it up to the caller. | |
| 759 return NoPEMStartLine() ? status : 0; | |
| 760 } | |
| 761 | |
| 762 | |
| 763 static int SetTrustedCertificatesBytes(SSL_CTX* context, | |
| 764 BIO* bio, | |
| 765 const char* password) { | |
| 766 int status = SetTrustedCertificatesBytesPEM(context, bio); | |
| 767 if (status == 0) { | |
| 768 if (NoPEMStartLine()) { | |
| 769 ERR_clear_error(); | |
| 770 BIO_reset(bio); | |
| 771 status = SetTrustedCertificatesBytesPKCS12(context, bio, password); | |
| 772 } | |
| 773 } else { | |
| 774 // The PEM file was successfully parsed. | |
| 775 ERR_clear_error(); | |
| 776 } | |
| 777 return status; | |
| 778 } | |
| 779 | |
| 780 | |
| 781 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( | |
|
zra
2017/05/30 16:15:36
To be consistent with other parts of the dart:io i
| |
| 782 Dart_NativeArguments args) { | |
| 783 SSLContext* context = GetSecurityContext(args); | |
| 784 const char* password = GetPasswordArgument(args, 2); | |
| 785 int status; | |
| 786 { | |
| 787 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | |
| 788 status = | |
| 789 SetTrustedCertificatesBytes(context->context(), bio.bio(), password); | |
| 790 } | |
| 791 CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes"); | |
| 792 } | |
| 793 | |
| 794 | |
| 795 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) { | |
| 796 Dart_SetReturnValue(args, Dart_NewBoolean(true)); | |
| 797 } | |
| 798 | |
| 799 | |
| 800 static void AddCompiledInCerts(SSLContext* context) { | |
| 801 if (root_certificates_pem == NULL) { | |
| 802 if (SSL_LOG_STATUS) { | |
| 803 Log::Print("Missing compiled-in roots\n"); | |
| 804 } | |
| 805 return; | |
| 806 } | |
| 807 X509_STORE* store = SSL_CTX_get_cert_store(context->context()); | |
| 808 BIO* roots_bio = | |
| 809 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), | |
| 810 root_certificates_pem_length); | |
| 811 X509* root_cert; | |
| 812 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, | |
| 813 // backed by a memory buffer), and returns X509 objects, one by one. | |
| 814 // When the end of the bio is reached, it returns null. | |
| 815 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL)) != NULL) { | |
| 816 int status = X509_STORE_add_cert(store, root_cert); | |
| 817 // X509_STORE_add_cert increments the reference count of cert on success. | |
| 818 X509_free(root_cert); | |
| 819 if (status == 0) { | |
| 820 break; | |
| 821 } | |
| 822 } | |
| 823 BIO_free(roots_bio); | |
| 824 // If there is an error here, it must be the error indicating that we are done | |
| 825 // reading PEM certificates. | |
| 826 ASSERT((ERR_peek_error() == 0) || NoPEMStartLine()); | |
| 827 ERR_clear_error(); | |
| 828 } | |
| 829 | |
| 830 | |
| 831 static void LoadRootCertFile(SSLContext* context, const char* file) { | |
| 832 if (SSL_LOG_STATUS) { | |
| 833 Log::Print("Looking for trusted roots in %s\n", file); | |
| 834 } | |
| 835 if (!File::Exists(file)) { | |
| 836 ThrowIOException(-1, "TlsException", "Failed to find root cert file", NULL); | |
| 837 } | |
| 838 int status = SSL_CTX_load_verify_locations(context->context(), file, NULL); | |
| 839 CheckStatus(status, "TlsException", "Failure trusting builtin roots"); | |
| 840 if (SSL_LOG_STATUS) { | |
| 841 Log::Print("Trusting roots from: %s\n", file); | |
| 842 } | |
| 843 } | |
| 844 | |
| 845 | |
| 846 static void LoadRootCertCache(SSLContext* context, const char* cache) { | |
| 847 if (SSL_LOG_STATUS) { | |
| 848 Log::Print("Looking for trusted roots in %s\n", cache); | |
| 849 } | |
| 850 if (Directory::Exists(cache) != Directory::EXISTS) { | |
| 851 ThrowIOException(-1, "TlsException", "Failed to find root cert cache", | |
| 852 NULL); | |
| 853 } | |
| 854 int status = SSL_CTX_load_verify_locations(context->context(), NULL, cache); | |
| 855 CheckStatus(status, "TlsException", "Failure trusting builtin roots"); | |
| 856 if (SSL_LOG_STATUS) { | |
| 857 Log::Print("Trusting roots from: %s\n", cache); | |
| 858 } | |
| 859 } | |
| 860 | |
| 861 | |
| 862 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( | |
| 863 Dart_NativeArguments args) { | |
| 864 SSLContext* context = GetSecurityContext(args); | |
| 865 | |
| 866 // First, try to use locations specified on the command line. | |
| 867 if (commandline_root_certs_file != NULL) { | |
| 868 LoadRootCertFile(context, commandline_root_certs_file); | |
| 869 return; | |
| 870 } | |
| 871 | |
| 872 if (commandline_root_certs_cache != NULL) { | |
| 873 LoadRootCertCache(context, commandline_root_certs_cache); | |
| 874 return; | |
| 875 } | |
| 876 | |
| 877 #if defined(HOST_OS_ANDROID) | |
| 878 // On Android, we don't compile in the trusted root certificates. Insead, | |
| 879 // we use the directory of trusted certificates already present on the device. | |
| 880 // This saves ~240KB from the size of the binary. This has the drawback that | |
| 881 // SSL_do_handshake will synchronously hit the filesystem looking for root | |
| 882 // certs during its trust evaluation. We call SSL_do_handshake directly from | |
| 883 // the Dart thread so that Dart code can be invoked from the "bad certificate" | |
| 884 // callback called by SSL_do_handshake. | |
| 885 const char* android_cacerts = "/system/etc/security/cacerts"; | |
| 886 LoadRootCertCache(context, android_cacerts); | |
| 887 return; | |
| 888 #elif defined(HOST_OS_LINUX) | |
| 889 // On Linux, we use the compiled-in trusted certs as a last resort. First, | |
| 890 // we try to find the trusted certs in various standard locations. A good | |
| 891 // discussion of the complexities of this endeavor can be found here: | |
| 892 // | |
| 893 // https://www.happyassassin.net/2015/01/12/a-note-about-ssltls-trusted-certif icate-stores-and-platforms/ | |
| 894 const char* bundle = "/etc/pki/tls/certs/ca-bundle.crt"; | |
| 895 const char* cachedir = "/etc/ssl/certs"; | |
| 896 if (File::Exists(bundle)) { | |
| 897 LoadRootCertFile(context, bundle); | |
| 898 return; | |
| 899 } | |
| 900 | |
| 901 if (Directory::Exists(cachedir) == Directory::EXISTS) { | |
| 902 LoadRootCertCache(context, cachedir); | |
| 903 return; | |
| 904 } | |
| 905 #endif // defined(HOST_OS_ANDROID) | |
| 906 | |
| 907 // Fall back on the compiled-in certs if the standard locations don't exist, | |
| 908 // or we aren't on Linux. | |
| 909 if (SSL_LOG_STATUS) { | |
| 910 Log::Print("Trusting compiled-in roots\n"); | |
| 911 } | |
| 912 AddCompiledInCerts(context); | |
| 913 } | |
| 914 | |
| 915 | |
| 916 static int UseChainBytesPKCS12(SSL_CTX* context, | |
| 917 BIO* bio, | |
| 918 const char* password) { | |
| 919 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
| 920 if (p12.get() == NULL) { | |
| 921 return 0; | |
| 922 } | |
| 923 | |
| 924 EVP_PKEY* key = NULL; | |
| 925 X509* cert = NULL; | |
| 926 STACK_OF(X509)* ca_certs = NULL; | |
| 927 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
| 928 if (status == 0) { | |
| 929 return status; | |
| 930 } | |
| 931 | |
| 932 ScopedX509 x509(cert); | |
| 933 ScopedX509Stack certs(ca_certs); | |
| 934 status = SSL_CTX_use_certificate(context, x509.get()); | |
| 935 if (ERR_peek_error() != 0) { | |
| 936 // Key/certificate mismatch doesn't imply status is 0. | |
| 937 status = 0; | |
| 938 } | |
| 939 if (status == 0) { | |
| 940 return status; | |
| 941 } | |
| 942 | |
| 943 SSL_CTX_clear_chain_certs(context); | |
| 944 | |
| 945 X509* ca; | |
| 946 while ((ca = sk_X509_shift(certs.get())) != NULL) { | |
| 947 status = SSL_CTX_add0_chain_cert(context, ca); | |
| 948 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the | |
| 949 // call fails. | |
| 950 if (status == 0) { | |
| 951 X509_free(ca); | |
| 952 return status; | |
| 953 } | |
| 954 } | |
| 955 | |
| 956 return status; | |
| 957 } | |
| 958 | |
| 959 | |
| 960 static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) { | |
| 961 int status = 0; | |
| 962 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL)); | |
| 963 if (x509.get() == NULL) { | |
| 964 return 0; | |
| 965 } | |
| 966 | |
| 967 status = SSL_CTX_use_certificate(context, x509.get()); | |
| 968 if (ERR_peek_error() != 0) { | |
| 969 // Key/certificate mismatch doesn't imply status is 0. | |
| 970 status = 0; | |
| 971 } | |
| 972 if (status == 0) { | |
| 973 return status; | |
| 974 } | |
| 975 | |
| 976 SSL_CTX_clear_chain_certs(context); | |
| 977 | |
| 978 X509* ca; | |
| 979 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | |
| 980 status = SSL_CTX_add0_chain_cert(context, ca); | |
| 981 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the | |
| 982 // call fails. | |
| 983 if (status == 0) { | |
| 984 X509_free(ca); | |
| 985 return status; | |
| 986 } | |
| 987 // Note that we must not free `ca` if it was successfully added to the | |
| 988 // chain. We must free the main certificate x509, though since its reference | |
| 989 // count is increased by SSL_CTX_use_certificate. | |
| 990 } | |
| 991 | |
| 992 return NoPEMStartLine() ? status : 0; | |
| 993 } | |
| 994 | |
| 995 | |
| 996 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) { | |
| 997 int status = UseChainBytesPEM(context, bio); | |
| 998 if (status == 0) { | |
| 999 if (NoPEMStartLine()) { | |
| 1000 ERR_clear_error(); | |
| 1001 BIO_reset(bio); | |
| 1002 status = UseChainBytesPKCS12(context, bio, password); | |
| 1003 } | |
| 1004 } else { | |
| 1005 // The PEM file was successfully read. | |
| 1006 ERR_clear_error(); | |
| 1007 } | |
| 1008 return status; | |
| 1009 } | |
| 1010 | |
| 1011 | |
| 1012 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( | |
| 1013 Dart_NativeArguments args) { | |
| 1014 SSLContext* context = GetSecurityContext(args); | |
| 1015 const char* password = GetPasswordArgument(args, 2); | |
| 1016 int status; | |
| 1017 { | |
| 1018 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | |
| 1019 status = UseChainBytes(context->context(), bio.bio(), password); | |
| 1020 } | |
| 1021 CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes"); | |
| 1022 } | |
| 1023 | |
| 1024 | |
| 1025 static int SetClientAuthoritiesPKCS12(SSL_CTX* context, | |
| 1026 BIO* bio, | |
| 1027 const char* password) { | |
| 1028 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
| 1029 if (p12.get() == NULL) { | |
| 1030 return 0; | |
| 1031 } | |
| 1032 | |
| 1033 EVP_PKEY* key = NULL; | |
| 1034 X509* cert = NULL; | |
| 1035 STACK_OF(X509)* ca_certs = NULL; | |
| 1036 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
| 1037 if (status == 0) { | |
| 1038 return status; | |
| 1039 } | |
| 1040 | |
| 1041 ScopedX509Stack cert_stack(ca_certs); | |
| 1042 status = SSL_CTX_add_client_CA(context, cert); | |
| 1043 // SSL_CTX_add_client_CA increments the reference count of cert on success. | |
| 1044 X509_free(cert); | |
| 1045 if (status == 0) { | |
| 1046 return status; | |
| 1047 } | |
| 1048 | |
| 1049 X509* ca; | |
| 1050 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { | |
| 1051 status = SSL_CTX_add_client_CA(context, ca); | |
| 1052 // SSL_CTX_add_client_CA increments the reference count of ca on success. | |
| 1053 X509_free(ca); // The name has been extracted. | |
| 1054 if (status == 0) { | |
| 1055 return status; | |
| 1056 } | |
| 1057 } | |
| 1058 | |
| 1059 return status; | |
| 1060 } | |
| 1061 | |
| 1062 | |
| 1063 static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) { | |
| 1064 int status = 0; | |
| 1065 X509* cert = NULL; | |
| 1066 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | |
| 1067 status = SSL_CTX_add_client_CA(context, cert); | |
| 1068 X509_free(cert); // The name has been extracted. | |
| 1069 if (status == 0) { | |
| 1070 return status; | |
| 1071 } | |
| 1072 } | |
| 1073 return NoPEMStartLine() ? status : 0; | |
| 1074 } | |
| 1075 | |
| 1076 | |
| 1077 static int SetClientAuthorities(SSL_CTX* context, | |
| 1078 BIO* bio, | |
| 1079 const char* password) { | |
| 1080 int status = SetClientAuthoritiesPEM(context, bio); | |
| 1081 if (status == 0) { | |
| 1082 if (NoPEMStartLine()) { | |
| 1083 ERR_clear_error(); | |
| 1084 BIO_reset(bio); | |
| 1085 status = SetClientAuthoritiesPKCS12(context, bio, password); | |
| 1086 } | |
| 1087 } else { | |
| 1088 // The PEM file was successfully parsed. | |
| 1089 ERR_clear_error(); | |
| 1090 } | |
| 1091 return status; | |
| 1092 } | |
| 1093 | |
| 1094 | |
| 1095 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( | |
| 1096 Dart_NativeArguments args) { | |
| 1097 SSLContext* context = GetSecurityContext(args); | |
| 1098 const char* password = GetPasswordArgument(args, 2); | |
| 1099 | |
| 1100 int status; | |
| 1101 { | |
| 1102 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | |
| 1103 status = SetClientAuthorities(context->context(), bio.bio(), password); | |
| 1104 } | |
| 1105 | |
| 1106 CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes"); | |
| 1107 } | 444 } |
| 1108 | 445 |
| 1109 | 446 |
| 1110 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( | 447 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( |
| 1111 Dart_NativeArguments args) { | 448 Dart_NativeArguments args) { |
| 1112 SSLContext* context = GetSecurityContext(args); | 449 SSLCertContext* context = SSLCertContext::GetSecurityContext(args); |
| 1113 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 1)); | 450 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 1114 Dart_Handle is_server_handle = ThrowIfError(Dart_GetNativeArgument(args, 2)); | 451 Dart_Handle is_server_handle = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| 1115 if (Dart_IsBoolean(is_server_handle)) { | 452 if (Dart_IsBoolean(is_server_handle)) { |
| 1116 bool is_server = DartUtils::GetBooleanValue(is_server_handle); | 453 bool is_server = DartUtils::GetBooleanValue(is_server_handle); |
| 1117 SetAlpnProtocolList(protocols_handle, NULL, context, is_server); | 454 SetAlpnProtocolList(protocols_handle, NULL, context, is_server); |
| 1118 } else { | 455 } else { |
| 1119 Dart_ThrowException(DartUtils::NewDartArgumentError( | 456 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 1120 "Non-boolean is_server argument passed to SetAlpnProtocols")); | 457 "Non-boolean is_server argument passed to SetAlpnProtocols")); |
| 1121 } | 458 } |
| 1122 } | 459 } |
| 1123 | 460 |
| 1124 | 461 |
| 1125 void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) { | |
| 1126 X509* certificate = GetX509Certificate(args); | |
| 1127 X509_NAME* subject = X509_get_subject_name(certificate); | |
| 1128 char* subject_string = X509_NAME_oneline(subject, NULL, 0); | |
| 1129 Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_string)); | |
| 1130 OPENSSL_free(subject_string); | |
| 1131 } | |
| 1132 | |
| 1133 | |
| 1134 void FUNCTION_NAME(X509_Issuer)(Dart_NativeArguments args) { | |
| 1135 X509* certificate = GetX509Certificate(args); | |
| 1136 X509_NAME* issuer = X509_get_issuer_name(certificate); | |
| 1137 char* issuer_string = X509_NAME_oneline(issuer, NULL, 0); | |
| 1138 Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_string)); | |
| 1139 OPENSSL_free(issuer_string); | |
| 1140 } | |
| 1141 | |
| 1142 static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME* aTime) { | |
| 1143 ASN1_UTCTIME* epoch_start = M_ASN1_UTCTIME_new(); | |
| 1144 ASN1_UTCTIME_set_string(epoch_start, "700101000000Z"); | |
| 1145 int days; | |
| 1146 int seconds; | |
| 1147 int result = ASN1_TIME_diff(&days, &seconds, epoch_start, aTime); | |
| 1148 M_ASN1_UTCTIME_free(epoch_start); | |
| 1149 if (result != 1) { | |
| 1150 // TODO(whesse): Propagate an error to Dart. | |
| 1151 Log::PrintErr("ASN1Time error %d\n", result); | |
| 1152 } | |
| 1153 return Dart_NewInteger((86400LL * days + seconds) * 1000LL); | |
| 1154 } | |
| 1155 | |
| 1156 void FUNCTION_NAME(X509_StartValidity)(Dart_NativeArguments args) { | |
| 1157 X509* certificate = GetX509Certificate(args); | |
| 1158 ASN1_TIME* not_before = X509_get_notBefore(certificate); | |
| 1159 Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_before)); | |
| 1160 } | |
| 1161 | |
| 1162 | |
| 1163 void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) { | |
| 1164 X509* certificate = GetX509Certificate(args); | |
| 1165 ASN1_TIME* not_after = X509_get_notAfter(certificate); | |
| 1166 Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_after)); | |
| 1167 } | |
| 1168 | |
| 1169 | |
| 1170 /** | 462 /** |
| 1171 * Pushes data through the SSL filter, reading and writing from circular | 463 * Pushes data through the SSL filter, reading and writing from circular |
| 1172 * buffers shared with Dart. | 464 * buffers shared with Dart. |
| 1173 * | 465 * |
| 1174 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to | 466 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to |
| 1175 * pass encrypted and plaintext data to and from the C++ SSLFilter object. | 467 * pass encrypted and plaintext data to and from the C++ SSLFilter object. |
| 1176 * | 468 * |
| 1177 * ProcessFilter is called with a CObject array containing the pointer to | 469 * ProcessFilter is called with a CObject array containing the pointer to |
| 1178 * the SSLFilter, encoded as an int, and the start and end positions of the | 470 * the SSLFilter, encoded as an int, and the start and end positions of the |
| 1179 * valid data in the four circular buffers. The function only reads from | 471 * valid data in the four circular buffers. The function only reads from |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1221 } | 513 } |
| 1222 | 514 |
| 1223 | 515 |
| 1224 bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], | 516 bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], |
| 1225 int ends[kNumBuffers], | 517 int ends[kNumBuffers], |
| 1226 bool in_handshake) { | 518 bool in_handshake) { |
| 1227 for (int i = 0; i < kNumBuffers; ++i) { | 519 for (int i = 0; i < kNumBuffers; ++i) { |
| 1228 if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue; | 520 if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue; |
| 1229 int start = starts[i]; | 521 int start = starts[i]; |
| 1230 int end = ends[i]; | 522 int end = ends[i]; |
| 1231 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | 523 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| 1232 if (start < 0 || end < 0 || start >= size || end >= size) { | 524 if (start < 0 || end < 0 || start >= size || end >= size) { |
| 1233 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket"); | 525 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket"); |
| 1234 } | 526 } |
| 1235 switch (i) { | 527 switch (i) { |
| 1236 case kReadPlaintext: | 528 case kReadPlaintext: |
| 1237 case kWriteEncrypted: | 529 case kWriteEncrypted: |
| 1238 // Write data to the circular buffer's free space. If the buffer | 530 // Write data to the circular buffer's free space. If the buffer |
| 1239 // is full, neither if statement is executed and nothing happens. | 531 // is full, neither if statement is executed and nothing happens. |
| 1240 if (start <= end) { | 532 if (start <= end) { |
| 1241 // If the free space may be split into two segments, | 533 // If the free space may be split into two segments, |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1300 } | 592 } |
| 1301 ASSERT(string_start_ == NULL); | 593 ASSERT(string_start_ == NULL); |
| 1302 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); | 594 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); |
| 1303 ASSERT(string_start_ != NULL); | 595 ASSERT(string_start_ != NULL); |
| 1304 ASSERT(string_length_ == NULL); | 596 ASSERT(string_length_ == NULL); |
| 1305 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); | 597 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); |
| 1306 ASSERT(string_length_ != NULL); | 598 ASSERT(string_length_ != NULL); |
| 1307 ASSERT(bad_certificate_callback_ == NULL); | 599 ASSERT(bad_certificate_callback_ == NULL); |
| 1308 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); | 600 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); |
| 1309 ASSERT(bad_certificate_callback_ != NULL); | 601 ASSERT(bad_certificate_callback_ != NULL); |
| 1310 | |
| 1311 // Caller handles cleanup on an error. | 602 // Caller handles cleanup on an error. |
| 1312 return InitializeBuffers(dart_this); | 603 return InitializeBuffers(dart_this); |
| 1313 } | 604 } |
| 1314 | 605 |
| 1315 | 606 |
| 1316 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) { | 607 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
| 1317 // Create SSLFilter buffers as ExternalUint8Array objects. | 608 // Create SSLFilter buffers as ExternalUint8Array objects. |
| 1318 Dart_Handle buffers_string = DartUtils::NewString("buffers"); | 609 Dart_Handle buffers_string = DartUtils::NewString("buffers"); |
| 1319 RETURN_IF_ERROR(buffers_string); | 610 RETURN_IF_ERROR(buffers_string); |
| 1320 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string); | 611 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 1348 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) { | 639 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) { |
| 1349 FATAL("Invalid encrypted buffer size in _ExternalBuffer"); | 640 FATAL("Invalid encrypted buffer size in _ExternalBuffer"); |
| 1350 } | 641 } |
| 1351 buffer_size_ = static_cast<int>(buffer_size); | 642 buffer_size_ = static_cast<int>(buffer_size); |
| 1352 encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size); | 643 encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size); |
| 1353 | 644 |
| 1354 Dart_Handle data_identifier = DartUtils::NewString("data"); | 645 Dart_Handle data_identifier = DartUtils::NewString("data"); |
| 1355 RETURN_IF_ERROR(data_identifier); | 646 RETURN_IF_ERROR(data_identifier); |
| 1356 | 647 |
| 1357 for (int i = 0; i < kNumBuffers; i++) { | 648 for (int i = 0; i < kNumBuffers; i++) { |
| 1358 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | 649 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| 1359 buffers_[i] = new uint8_t[size]; | 650 buffers_[i] = new uint8_t[size]; |
| 1360 ASSERT(buffers_[i] != NULL); | 651 ASSERT(buffers_[i] != NULL); |
| 1361 dart_buffer_objects_[i] = NULL; | 652 dart_buffer_objects_[i] = NULL; |
| 1362 } | 653 } |
| 1363 | 654 |
| 1364 Dart_Handle result = Dart_Null(); | 655 Dart_Handle result = Dart_Null(); |
| 1365 for (int i = 0; i < kNumBuffers; ++i) { | 656 for (int i = 0; i < kNumBuffers; ++i) { |
| 1366 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | 657 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
| 1367 result = Dart_ListGetAt(dart_buffers_object, i); | 658 result = Dart_ListGetAt(dart_buffers_object, i); |
| 1368 if (Dart_IsError(result)) { | 659 if (Dart_IsError(result)) { |
| 1369 break; | 660 break; |
| 1370 } | 661 } |
| 1371 | 662 |
| 1372 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result); | 663 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result); |
| 1373 ASSERT(dart_buffer_objects_[i] != NULL); | 664 ASSERT(dart_buffer_objects_[i] != NULL); |
| 1374 Dart_Handle data = | 665 Dart_Handle data = |
| 1375 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size); | 666 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size); |
| 1376 if (Dart_IsError(data)) { | 667 if (Dart_IsError(data)) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1412 MutexLocker locker(mutex_); | 703 MutexLocker locker(mutex_); |
| 1413 if (!library_initialized_) { | 704 if (!library_initialized_) { |
| 1414 SSL_library_init(); | 705 SSL_library_init(); |
| 1415 filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); | 706 filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); |
| 1416 ASSERT(filter_ssl_index >= 0); | 707 ASSERT(filter_ssl_index >= 0); |
| 1417 library_initialized_ = true; | 708 library_initialized_ = true; |
| 1418 } | 709 } |
| 1419 } | 710 } |
| 1420 | 711 |
| 1421 | 712 |
| 1422 Dart_Handle SSLFilter::PeerCertificate() { | |
| 1423 // SSL_get_peer_certificate incs the refcount of certificate. X509_free is | |
| 1424 // called by the finalizer set up by WrappedX509Certificate. | |
| 1425 X509* certificate = SSL_get_peer_certificate(ssl_); | |
| 1426 return WrappedX509Certificate(certificate); | |
| 1427 } | |
| 1428 | |
| 1429 | |
| 1430 int AlpnCallback(SSL* ssl, | 713 int AlpnCallback(SSL* ssl, |
| 1431 const uint8_t** out, | 714 const uint8_t** out, |
| 1432 uint8_t* outlen, | 715 uint8_t* outlen, |
| 1433 const uint8_t* in, | 716 const uint8_t* in, |
| 1434 unsigned int inlen, | 717 unsigned int inlen, |
| 1435 void* arg) { | 718 void* arg) { |
| 1436 // 'in' and 'arg' are sequences of (length, data) strings with 1-byte lengths. | 719 // 'in' and 'arg' are sequences of (length, data) strings with 1-byte lengths. |
| 1437 // 'arg' is 0-terminated. Finds the first string in 'arg' that is in 'in'. | 720 // 'arg' is 0-terminated. Finds the first string in 'arg' that is in 'in'. |
| 1438 uint8_t* server_list = static_cast<uint8_t*>(arg); | 721 uint8_t* server_list = static_cast<uint8_t*>(arg); |
| 1439 while (*server_list != 0) { | 722 while (*server_list != 0) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1453 server_list += protocol_length; | 736 server_list += protocol_length; |
| 1454 } | 737 } |
| 1455 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN. | 738 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN. |
| 1456 return SSL_TLSEXT_ERR_NOACK; | 739 return SSL_TLSEXT_ERR_NOACK; |
| 1457 } | 740 } |
| 1458 | 741 |
| 1459 | 742 |
| 1460 // Sets the protocol list for ALPN on a SSL object or a context. | 743 // Sets the protocol list for ALPN on a SSL object or a context. |
| 1461 static void SetAlpnProtocolList(Dart_Handle protocols_handle, | 744 static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
| 1462 SSL* ssl, | 745 SSL* ssl, |
| 1463 SSLContext* context, | 746 SSLCertContext* context, |
| 1464 bool is_server) { | 747 bool is_server) { |
| 1465 // Enable ALPN (application layer protocol negotiation) if the caller provides | 748 // Enable ALPN (application layer protocol negotiation) if the caller provides |
| 1466 // a valid list of supported protocols. | 749 // a valid list of supported protocols. |
| 1467 Dart_TypedData_Type protocols_type; | 750 Dart_TypedData_Type protocols_type; |
| 1468 uint8_t* protocol_string = NULL; | 751 uint8_t* protocol_string = NULL; |
| 1469 uint8_t* protocol_string_copy = NULL; | 752 uint8_t* protocol_string_copy = NULL; |
| 1470 intptr_t protocol_string_len = 0; | 753 intptr_t protocol_string_len = 0; |
| 1471 int status; | 754 int status; |
| 1472 | 755 |
| 1473 Dart_Handle result = Dart_TypedDataAcquireData( | 756 Dart_Handle result = Dart_TypedDataAcquireData( |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1510 protocol_string_len); | 793 protocol_string_len); |
| 1511 } | 794 } |
| 1512 ASSERT(status == 0); // The function returns a non-standard status. | 795 ASSERT(status == 0); // The function returns a non-standard status. |
| 1513 } | 796 } |
| 1514 } | 797 } |
| 1515 Dart_TypedDataReleaseData(protocols_handle); | 798 Dart_TypedDataReleaseData(protocols_handle); |
| 1516 } | 799 } |
| 1517 | 800 |
| 1518 | 801 |
| 1519 void SSLFilter::Connect(const char* hostname, | 802 void SSLFilter::Connect(const char* hostname, |
| 1520 SSL_CTX* context, | 803 SSLCertContext* context, |
| 1521 bool is_server, | 804 bool is_server, |
| 1522 bool request_client_certificate, | 805 bool request_client_certificate, |
| 1523 bool require_client_certificate, | 806 bool require_client_certificate, |
| 1524 Dart_Handle protocols_handle) { | 807 Dart_Handle protocols_handle) { |
| 1525 is_server_ = is_server; | 808 is_server_ = is_server; |
| 1526 if (in_handshake_) { | 809 if (in_handshake_) { |
| 1527 FATAL("Connect called twice on the same _SecureFilter."); | 810 FATAL("Connect called twice on the same _SecureFilter."); |
| 1528 } | 811 } |
| 1529 | 812 |
| 1530 int status; | 813 int status; |
| 1531 int error; | 814 int error; |
| 1532 BIO* ssl_side; | 815 BIO* ssl_side; |
| 1533 status = BIO_new_bio_pair(&ssl_side, kInternalBIOSize, &socket_side_, | 816 status = BIO_new_bio_pair(&ssl_side, kInternalBIOSize, &socket_side_, |
| 1534 kInternalBIOSize); | 817 kInternalBIOSize); |
| 1535 CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair", ssl_); | 818 SecureSocketUtils::CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair", |
| 819 ssl_); | |
| 1536 | 820 |
| 1537 assert(context != NULL); | 821 ASSERT(context != NULL); |
| 1538 ssl_ = SSL_new(context); | 822 ASSERT(context->context() != NULL); |
| 823 ssl_ = SSL_new(context->context()); | |
| 1539 SSL_set_bio(ssl_, ssl_side, ssl_side); | 824 SSL_set_bio(ssl_, ssl_side, ssl_side); |
| 1540 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right? | 825 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right? |
| 1541 SSL_set_ex_data(ssl_, filter_ssl_index, this); | 826 SSL_set_ex_data(ssl_, filter_ssl_index, this); |
| 827 RegisterCallbacks(context); | |
| 1542 | 828 |
| 1543 if (is_server_) { | 829 if (is_server_) { |
| 1544 int certificate_mode = | 830 int certificate_mode = |
| 1545 request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE; | 831 request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE; |
| 1546 if (require_client_certificate) { | 832 if (require_client_certificate) { |
| 1547 certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; | 833 certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
| 1548 } | 834 } |
| 1549 SSL_set_verify(ssl_, certificate_mode, NULL); | 835 SSL_set_verify(ssl_, certificate_mode, NULL); |
| 1550 } else { | 836 } else { |
| 1551 SetAlpnProtocolList(protocols_handle, ssl_, NULL, false); | 837 SetAlpnProtocolList(protocols_handle, ssl_, NULL, false); |
| 1552 status = SSL_set_tlsext_host_name(ssl_, hostname); | 838 status = SSL_set_tlsext_host_name(ssl_, hostname); |
| 1553 CheckStatusSSL(status, "TlsException", "Set SNI host name", ssl_); | 839 SecureSocketUtils::CheckStatusSSL(status, "TlsException", |
| 840 "Set SNI host name", ssl_); | |
| 1554 // Sets the hostname in the certificate-checking object, so it is checked | 841 // Sets the hostname in the certificate-checking object, so it is checked |
| 1555 // against the certificate presented by the server. | 842 // against the certificate presented by the server. |
| 1556 X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_); | 843 X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_); |
| 1557 hostname_ = strdup(hostname); | 844 hostname_ = strdup(hostname); |
| 1558 X509_VERIFY_PARAM_set_flags( | 845 X509_VERIFY_PARAM_set_flags( |
| 1559 certificate_checking_parameters, | 846 certificate_checking_parameters, |
| 1560 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_TRUSTED_FIRST); | 847 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_TRUSTED_FIRST); |
| 1561 X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0); | 848 X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0); |
| 1562 status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters, | 849 status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters, |
| 1563 hostname_, strlen(hostname_)); | 850 hostname_, strlen(hostname_)); |
| 1564 CheckStatusSSL(status, "TlsException", | 851 SecureSocketUtils::CheckStatusSSL( |
| 1565 "Set hostname for certificate checking", ssl_); | 852 status, "TlsException", "Set hostname for certificate checking", ssl_); |
| 1566 } | 853 } |
| 1567 // Make the connection: | 854 // Make the connection: |
| 1568 if (is_server_) { | 855 if (is_server_) { |
| 1569 status = SSL_accept(ssl_); | 856 status = SSL_accept(ssl_); |
| 1570 if (SSL_LOG_STATUS) { | 857 if (SSL_LOG_STATUS) { |
| 1571 Log::Print("SSL_accept status: %d\n", status); | 858 Log::Print("SSL_accept status: %d\n", status); |
| 1572 } | 859 } |
| 1573 if (status != 1) { | 860 if (status != 1) { |
| 1574 // TODO(whesse): expect a needs-data error here. Handle other errors. | 861 // TODO(whesse): expect a needs-data error here. Handle other errors. |
| 1575 error = SSL_get_error(ssl_, status); | 862 error = SSL_get_error(ssl_, status); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1608 // The SSL_do_handshake will try performing a handshake and might call | 895 // The SSL_do_handshake will try performing a handshake and might call |
| 1609 // a CertificateCallback. If the certificate validation | 896 // a CertificateCallback. If the certificate validation |
| 1610 // failed the 'callback_error" will be set by the certificateCallback | 897 // failed the 'callback_error" will be set by the certificateCallback |
| 1611 // logic and we propagate the error" | 898 // logic and we propagate the error" |
| 1612 Dart_PropagateError(callback_error); | 899 Dart_PropagateError(callback_error); |
| 1613 } | 900 } |
| 1614 if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) { | 901 if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) { |
| 1615 in_handshake_ = true; | 902 in_handshake_ = true; |
| 1616 return; | 903 return; |
| 1617 } | 904 } |
| 1618 CheckStatusSSL( | 905 SecureSocketUtils::CheckStatusSSL( |
| 1619 status, "HandshakeException", | 906 status, "HandshakeException", |
| 1620 is_server_ ? "Handshake error in server" : "Handshake error in client", | 907 is_server_ ? "Handshake error in server" : "Handshake error in client", |
| 1621 ssl_); | 908 ssl_); |
| 1622 // Handshake succeeded. | 909 // Handshake succeeded. |
| 1623 if (in_handshake_) { | 910 if (in_handshake_) { |
| 1624 // TODO(24071): Check return value of SSL_get_verify_result, this | 911 // TODO(24071): Check return value of SSL_get_verify_result, this |
| 1625 // should give us the hostname check. | 912 // should give us the hostname check. |
| 1626 int result = SSL_get_verify_result(ssl_); | 913 int result = SSL_get_verify_result(ssl_); |
| 1627 if (SSL_LOG_STATUS) { | 914 if (SSL_LOG_STATUS) { |
| 1628 Log::Print("Handshake verification status: %d\n", result); | 915 Log::Print("Handshake verification status: %d\n", result); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1794 Log::Print("WriteEncrypted BIO_read wrote %d bytes\n", | 1081 Log::Print("WriteEncrypted BIO_read wrote %d bytes\n", |
| 1795 bytes_processed); | 1082 bytes_processed); |
| 1796 } | 1083 } |
| 1797 } | 1084 } |
| 1798 return bytes_processed; | 1085 return bytes_processed; |
| 1799 } | 1086 } |
| 1800 | 1087 |
| 1801 } // namespace bin | 1088 } // namespace bin |
| 1802 } // namespace dart | 1089 } // namespace dart |
| 1803 | 1090 |
| 1804 #endif // defined(HOST_OS_LINUX) | |
| 1805 | |
| 1806 #endif // !defined(DART_IO_DISABLED) && | 1091 #endif // !defined(DART_IO_DISABLED) && |
| 1807 // !defined(DART_IO_SECURE_SOCKET_DISABLED) | 1092 // !defined(DART_IO_SECURE_SOCKET_DISABLED) |
| OLD | NEW |