Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) | |
| 6 | |
| 7 #include "bin/secure_socket_filter.h" | |
| 8 | |
| 9 #include <openssl/bio.h> | |
| 10 #include <openssl/ssl.h> | |
| 11 #include <openssl/x509.h> | |
| 12 | |
| 13 #include "platform/globals.h" | |
|
zra
2017/06/02 22:56:24
Is this needed?
bkonyi
2017/06/05 20:25:51
Nope. Removed.
| |
| 14 | |
| 15 #include "bin/lockers.h" | |
| 16 #include "bin/log.h" | |
| 17 #include "bin/secure_socket.h" | |
| 18 #include "bin/secure_socket_utils.h" | |
| 19 #include "platform/text_buffer.h" | |
| 20 | |
| 21 | |
| 22 // Return the error from the containing function if handle is an error handle. | |
| 23 #define RETURN_IF_ERROR(handle) \ | |
| 24 { \ | |
| 25 Dart_Handle __handle = handle; \ | |
| 26 if (Dart_IsError((__handle))) { \ | |
| 27 return __handle; \ | |
| 28 } \ | |
| 29 } | |
| 30 | |
| 31 namespace dart { | |
| 32 namespace bin { | |
| 33 | |
| 34 bool SSLFilter::library_initialized_ = false; | |
| 35 // To protect library initialization. | |
| 36 Mutex* SSLFilter::mutex_ = new Mutex(); | |
| 37 int SSLFilter::filter_ssl_index; | |
| 38 | |
| 39 const intptr_t SSLFilter::kInternalBIOSize = 10 * KB; | |
| 40 const intptr_t SSLFilter::kApproximateSize = | |
| 41 sizeof(SSLFilter) + (2 * SSLFilter::kInternalBIOSize); | |
| 42 | |
| 43 static SSLFilter* GetFilter(Dart_NativeArguments args) { | |
| 44 SSLFilter* filter; | |
| 45 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
| 46 ASSERT(Dart_IsInstance(dart_this)); | |
| 47 ThrowIfError(Dart_GetNativeInstanceField( | |
| 48 dart_this, SSLFilter::kSSLFilterNativeFieldIndex, | |
| 49 reinterpret_cast<intptr_t*>(&filter))); | |
| 50 return filter; | |
| 51 } | |
| 52 | |
| 53 | |
| 54 static void DeleteFilter(void* isolate_data, | |
| 55 Dart_WeakPersistentHandle handle, | |
| 56 void* context_pointer) { | |
| 57 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer); | |
| 58 filter->Release(); | |
| 59 } | |
| 60 | |
| 61 | |
| 62 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) { | |
| 63 ASSERT(filter != NULL); | |
| 64 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); | |
| 65 RETURN_IF_ERROR(dart_this); | |
| 66 ASSERT(Dart_IsInstance(dart_this)); | |
| 67 Dart_Handle err = Dart_SetNativeInstanceField( | |
| 68 dart_this, SSLFilter::kSSLFilterNativeFieldIndex, | |
| 69 reinterpret_cast<intptr_t>(filter)); | |
| 70 RETURN_IF_ERROR(err); | |
| 71 Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter), | |
| 72 SSLFilter::kApproximateSize, DeleteFilter); | |
| 73 return Dart_Null(); | |
| 74 } | |
| 75 | |
| 76 | |
| 77 int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) { | |
| 78 if (preverify_ok == 1) { | |
| 79 return 1; | |
| 80 } | |
| 81 Dart_Isolate isolate = Dart_CurrentIsolate(); | |
| 82 if (isolate == NULL) { | |
| 83 FATAL("CertificateCallback called with no current isolate\n"); | |
| 84 } | |
| 85 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx); | |
| 86 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx(); | |
| 87 SSL* ssl = | |
| 88 static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index)); | |
| 89 SSLFilter* filter = static_cast<SSLFilter*>( | |
| 90 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index)); | |
| 91 Dart_Handle callback = filter->bad_certificate_callback(); | |
| 92 if (Dart_IsNull(callback)) { | |
| 93 return 0; | |
| 94 } | |
| 95 | |
| 96 // Upref since the Dart X509 object may outlive the SecurityContext. | |
| 97 if (certificate != NULL) { | |
| 98 X509_up_ref(certificate); | |
| 99 } | |
| 100 Dart_Handle args[1]; | |
| 101 args[0] = SSLFilter::WrappedX509Certificate(certificate); | |
| 102 if (Dart_IsError(args[0])) { | |
| 103 filter->callback_error = args[0]; | |
| 104 return 0; | |
| 105 } | |
| 106 Dart_Handle result = Dart_InvokeClosure(callback, 1, args); | |
| 107 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) { | |
| 108 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException( | |
| 109 "HandshakeException", | |
| 110 "BadCertificateCallback returned a value that was not a boolean", | |
| 111 Dart_Null())); | |
| 112 } | |
| 113 if (Dart_IsError(result)) { | |
| 114 filter->callback_error = result; | |
| 115 return 0; | |
| 116 } | |
| 117 return DartUtils::GetBooleanValue(result); | |
| 118 } | |
| 119 | |
| 120 | |
| 121 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { | |
| 122 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
| 123 SSLFilter* filter = new SSLFilter(); | |
| 124 Dart_Handle err = SetFilter(args, filter); | |
| 125 if (Dart_IsError(err)) { | |
| 126 filter->Release(); | |
| 127 Dart_PropagateError(err); | |
| 128 } | |
| 129 err = filter->Init(dart_this); | |
| 130 if (Dart_IsError(err)) { | |
| 131 // The finalizer was set up by SetFilter. It will delete `filter` if there | |
| 132 // is an error. | |
| 133 filter->Destroy(); | |
| 134 Dart_PropagateError(err); | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 | |
| 139 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { | |
| 140 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
| 141 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); | |
| 142 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); | |
| 143 bool request_client_certificate = | |
| 144 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); | |
| 145 bool require_client_certificate = | |
| 146 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); | |
| 147 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 6)); | |
| 148 | |
| 149 const char* host_name = NULL; | |
| 150 // TODO(whesse): Is truncating a Dart string containing \0 what we want? | |
| 151 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); | |
| 152 | |
| 153 SSLCertContext* context = NULL; | |
| 154 if (!Dart_IsNull(context_object)) { | |
| 155 ThrowIfError(Dart_GetNativeInstanceField( | |
| 156 context_object, SSLCertContext::kSecurityContextNativeFieldIndex, | |
| 157 reinterpret_cast<intptr_t*>(&context))); | |
| 158 } | |
| 159 | |
| 160 // The protocols_handle is guaranteed to be a valid Uint8List. | |
| 161 // It will have the correct length encoding of the protocols array. | |
| 162 ASSERT(!Dart_IsNull(protocols_handle)); | |
| 163 GetFilter(args)->Connect(host_name, context, is_server, | |
| 164 request_client_certificate, | |
| 165 require_client_certificate, protocols_handle); | |
| 166 } | |
| 167 | |
| 168 | |
| 169 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { | |
| 170 SSLFilter* filter = GetFilter(args); | |
| 171 // There are two paths that can clean up an SSLFilter object. First, | |
| 172 // there is this explicit call to Destroy(), called from | |
| 173 // _SecureFilter.destroy() in Dart code. After a call to destroy(), the Dart | |
| 174 // code maintains the invariant that there will be no futher SSLFilter | |
| 175 // requests sent to the IO Service. Therefore, the internals of the SSLFilter | |
| 176 // are safe to deallocate, but not the SSLFilter itself, which is already | |
| 177 // set up to be cleaned up by the finalizer. | |
| 178 // | |
| 179 // The second path is through the finalizer, which we have to do in case | |
| 180 // some mishap prevents a call to _SecureFilter.destroy(). | |
| 181 filter->Destroy(); | |
| 182 } | |
| 183 | |
| 184 | |
| 185 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) { | |
| 186 GetFilter(args)->Handshake(); | |
| 187 } | |
| 188 | |
| 189 | |
| 190 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)( | |
| 191 Dart_NativeArguments args) { | |
| 192 GetFilter(args)->GetSelectedProtocol(args); | |
| 193 } | |
| 194 | |
| 195 | |
| 196 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) { | |
| 197 bool use_session_cache = | |
| 198 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1)); | |
| 199 bool request_client_certificate = | |
| 200 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2)); | |
| 201 bool require_client_certificate = | |
| 202 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); | |
| 203 GetFilter(args)->Renegotiate(use_session_cache, request_client_certificate, | |
| 204 require_client_certificate); | |
| 205 } | |
| 206 | |
| 207 | |
| 208 void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)( | |
| 209 Dart_NativeArguments args) { | |
| 210 Dart_Handle handshake_complete = | |
| 211 ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
| 212 if (!Dart_IsClosure(handshake_complete)) { | |
| 213 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 214 "Illegal argument to RegisterHandshakeCompleteCallback")); | |
| 215 } | |
| 216 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete); | |
| 217 } | |
| 218 | |
| 219 | |
| 220 void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)( | |
| 221 Dart_NativeArguments args) { | |
| 222 Dart_Handle callback = ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
| 223 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) { | |
| 224 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 225 "Illegal argument to RegisterBadCertificateCallback")); | |
| 226 } | |
| 227 GetFilter(args)->RegisterBadCertificateCallback(callback); | |
| 228 } | |
| 229 | |
| 230 | |
| 231 void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) { | |
| 232 Dart_Handle cert = ThrowIfError(GetFilter(args)->PeerCertificate()); | |
| 233 Dart_SetReturnValue(args, cert); | |
| 234 } | |
| 235 | |
| 236 | |
| 237 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { | |
| 238 SSLFilter* filter = GetFilter(args); | |
| 239 // This filter pointer is passed to the IO Service thread. The IO Service | |
| 240 // thread must Release() the pointer when it is done with it. | |
| 241 filter->Retain(); | |
| 242 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter); | |
| 243 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); | |
| 244 } | |
| 245 | |
| 246 | |
| 247 /** | |
| 248 * Pushes data through the SSL filter, reading and writing from circular | |
| 249 * buffers shared with Dart. | |
| 250 * | |
| 251 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to | |
| 252 * pass encrypted and plaintext data to and from the C++ SSLFilter object. | |
| 253 * | |
| 254 * ProcessFilter is called with a CObject array containing the pointer to | |
| 255 * the SSLFilter, encoded as an int, and the start and end positions of the | |
| 256 * valid data in the four circular buffers. The function only reads from | |
| 257 * the valid data area of the input buffers, and only writes to the free | |
| 258 * area of the output buffers. The function returns the new start and end | |
| 259 * positions in the buffers, but it only updates start for input buffers, and | |
| 260 * end for output buffers. Therefore, the Dart thread can simultaneously | |
| 261 * write to the free space and end pointer of input buffers, and read from | |
| 262 * the data space of output buffers, and modify the start pointer. | |
| 263 * | |
| 264 * When ProcessFilter returns, the Dart thread is responsible for combining | |
| 265 * the updated pointers from Dart and C++, to make the new valid state of | |
| 266 * the circular buffer. | |
| 267 */ | |
| 268 CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) { | |
| 269 CObjectIntptr filter_object(request[0]); | |
| 270 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value()); | |
| 271 RefCntReleaseScope<SSLFilter> rs(filter); | |
| 272 | |
| 273 bool in_handshake = CObjectBool(request[1]).Value(); | |
| 274 int starts[SSLFilter::kNumBuffers]; | |
| 275 int ends[SSLFilter::kNumBuffers]; | |
| 276 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { | |
| 277 starts[i] = CObjectInt32(request[2 * i + 2]).Value(); | |
| 278 ends[i] = CObjectInt32(request[2 * i + 3]).Value(); | |
| 279 } | |
| 280 | |
| 281 if (filter->ProcessAllBuffers(starts, ends, in_handshake)) { | |
| 282 CObjectArray* result = | |
| 283 new CObjectArray(CObject::NewArray(SSLFilter::kNumBuffers * 2)); | |
| 284 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { | |
| 285 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i]))); | |
| 286 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i]))); | |
| 287 } | |
| 288 return result; | |
| 289 } else { | |
| 290 int32_t error_code = static_cast<int32_t>(ERR_peek_error()); | |
| 291 TextBuffer error_string(SecureSocketUtils::SSL_ERROR_MESSAGE_BUFFER_SIZE); | |
| 292 SecureSocketUtils::FetchErrorString(filter->ssl_, &error_string); | |
| 293 CObjectArray* result = new CObjectArray(CObject::NewArray(2)); | |
| 294 result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code))); | |
| 295 result->SetAt(1, new CObjectString(CObject::NewString(error_string.buf()))); | |
| 296 return result; | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 | |
| 301 bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], | |
| 302 int ends[kNumBuffers], | |
| 303 bool in_handshake) { | |
| 304 for (int i = 0; i < kNumBuffers; ++i) { | |
| 305 if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue; | |
| 306 int start = starts[i]; | |
| 307 int end = ends[i]; | |
| 308 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | |
| 309 if (start < 0 || end < 0 || start >= size || end >= size) { | |
| 310 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket"); | |
| 311 } | |
| 312 switch (i) { | |
| 313 case kReadPlaintext: | |
| 314 case kWriteEncrypted: | |
| 315 // Write data to the circular buffer's free space. If the buffer | |
| 316 // is full, neither if statement is executed and nothing happens. | |
| 317 if (start <= end) { | |
| 318 // If the free space may be split into two segments, | |
| 319 // then the first is [end, size), unless start == 0. | |
| 320 // Then, since the last free byte is at position start - 2, | |
| 321 // the interval is [end, size - 1). | |
| 322 int buffer_end = (start == 0) ? size - 1 : size; | |
| 323 int bytes = (i == kReadPlaintext) | |
| 324 ? ProcessReadPlaintextBuffer(end, buffer_end) | |
| 325 : ProcessWriteEncryptedBuffer(end, buffer_end); | |
| 326 if (bytes < 0) return false; | |
| 327 end += bytes; | |
| 328 ASSERT(end <= size); | |
| 329 if (end == size) end = 0; | |
| 330 } | |
| 331 if (start > end + 1) { | |
| 332 int bytes = (i == kReadPlaintext) | |
| 333 ? ProcessReadPlaintextBuffer(end, start - 1) | |
| 334 : ProcessWriteEncryptedBuffer(end, start - 1); | |
| 335 if (bytes < 0) return false; | |
| 336 end += bytes; | |
| 337 ASSERT(end < start); | |
| 338 } | |
| 339 ends[i] = end; | |
| 340 break; | |
| 341 case kReadEncrypted: | |
| 342 case kWritePlaintext: | |
| 343 // Read/Write data from circular buffer. If the buffer is empty, | |
| 344 // neither if statement's condition is true. | |
| 345 if (end < start) { | |
| 346 // Data may be split into two segments. In this case, | |
| 347 // the first is [start, size). | |
| 348 int bytes = (i == kReadEncrypted) | |
| 349 ? ProcessReadEncryptedBuffer(start, size) | |
| 350 : ProcessWritePlaintextBuffer(start, size); | |
| 351 if (bytes < 0) return false; | |
| 352 start += bytes; | |
| 353 ASSERT(start <= size); | |
| 354 if (start == size) start = 0; | |
| 355 } | |
| 356 if (start < end) { | |
| 357 int bytes = (i == kReadEncrypted) | |
| 358 ? ProcessReadEncryptedBuffer(start, end) | |
| 359 : ProcessWritePlaintextBuffer(start, end); | |
| 360 if (bytes < 0) return false; | |
| 361 start += bytes; | |
| 362 ASSERT(start <= end); | |
| 363 } | |
| 364 starts[i] = start; | |
| 365 break; | |
| 366 default: | |
| 367 UNREACHABLE(); | |
| 368 } | |
| 369 } | |
| 370 return true; | |
| 371 } | |
| 372 | |
| 373 | |
| 374 Dart_Handle SSLFilter::Init(Dart_Handle dart_this) { | |
| 375 if (!library_initialized_) { | |
| 376 InitializeLibrary(); | |
| 377 } | |
| 378 ASSERT(string_start_ == NULL); | |
| 379 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); | |
| 380 ASSERT(string_start_ != NULL); | |
| 381 ASSERT(string_length_ == NULL); | |
| 382 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); | |
| 383 ASSERT(string_length_ != NULL); | |
| 384 ASSERT(bad_certificate_callback_ == NULL); | |
| 385 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); | |
| 386 ASSERT(bad_certificate_callback_ != NULL); | |
| 387 // Caller handles cleanup on an error. | |
| 388 return InitializeBuffers(dart_this); | |
| 389 } | |
| 390 | |
| 391 | |
| 392 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) { | |
| 393 // Create SSLFilter buffers as ExternalUint8Array objects. | |
| 394 Dart_Handle buffers_string = DartUtils::NewString("buffers"); | |
| 395 RETURN_IF_ERROR(buffers_string); | |
| 396 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string); | |
| 397 RETURN_IF_ERROR(dart_buffers_object); | |
| 398 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this); | |
| 399 RETURN_IF_ERROR(secure_filter_impl_type); | |
| 400 Dart_Handle size_string = DartUtils::NewString("SIZE"); | |
| 401 RETURN_IF_ERROR(size_string); | |
| 402 Dart_Handle dart_buffer_size = | |
| 403 Dart_GetField(secure_filter_impl_type, size_string); | |
| 404 RETURN_IF_ERROR(dart_buffer_size); | |
| 405 | |
| 406 int64_t buffer_size = 0; | |
| 407 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size); | |
| 408 RETURN_IF_ERROR(err); | |
| 409 | |
| 410 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE"); | |
| 411 RETURN_IF_ERROR(encrypted_size_string); | |
| 412 | |
| 413 Dart_Handle dart_encrypted_buffer_size = | |
| 414 Dart_GetField(secure_filter_impl_type, encrypted_size_string); | |
| 415 RETURN_IF_ERROR(dart_encrypted_buffer_size); | |
| 416 | |
| 417 int64_t encrypted_buffer_size = 0; | |
| 418 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size); | |
| 419 RETURN_IF_ERROR(err); | |
| 420 | |
| 421 if (buffer_size <= 0 || buffer_size > 1 * MB) { | |
| 422 FATAL("Invalid buffer size in _ExternalBuffer"); | |
| 423 } | |
| 424 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) { | |
| 425 FATAL("Invalid encrypted buffer size in _ExternalBuffer"); | |
| 426 } | |
| 427 buffer_size_ = static_cast<int>(buffer_size); | |
| 428 encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size); | |
| 429 | |
| 430 Dart_Handle data_identifier = DartUtils::NewString("data"); | |
| 431 RETURN_IF_ERROR(data_identifier); | |
| 432 | |
| 433 for (int i = 0; i < kNumBuffers; i++) { | |
| 434 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | |
| 435 buffers_[i] = new uint8_t[size]; | |
| 436 ASSERT(buffers_[i] != NULL); | |
| 437 dart_buffer_objects_[i] = NULL; | |
| 438 } | |
| 439 | |
| 440 Dart_Handle result = Dart_Null(); | |
| 441 for (int i = 0; i < kNumBuffers; ++i) { | |
| 442 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | |
| 443 result = Dart_ListGetAt(dart_buffers_object, i); | |
| 444 if (Dart_IsError(result)) { | |
| 445 break; | |
| 446 } | |
| 447 | |
| 448 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result); | |
| 449 ASSERT(dart_buffer_objects_[i] != NULL); | |
| 450 Dart_Handle data = | |
| 451 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size); | |
| 452 if (Dart_IsError(data)) { | |
| 453 result = data; | |
| 454 break; | |
| 455 } | |
| 456 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]); | |
| 457 if (Dart_IsError(result)) { | |
| 458 break; | |
| 459 } | |
| 460 result = Dart_SetField(result, data_identifier, data); | |
| 461 if (Dart_IsError(result)) { | |
| 462 break; | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 // Caller handles cleanup on an error. | |
| 467 return result; | |
| 468 } | |
| 469 | |
| 470 | |
| 471 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) { | |
| 472 ASSERT(NULL == handshake_complete_); | |
| 473 handshake_complete_ = Dart_NewPersistentHandle(complete); | |
| 474 | |
| 475 ASSERT(handshake_complete_ != NULL); | |
| 476 } | |
| 477 | |
| 478 | |
| 479 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) { | |
| 480 ASSERT(bad_certificate_callback_ != NULL); | |
| 481 Dart_DeletePersistentHandle(bad_certificate_callback_); | |
| 482 bad_certificate_callback_ = Dart_NewPersistentHandle(callback); | |
| 483 ASSERT(bad_certificate_callback_ != NULL); | |
| 484 } | |
| 485 | |
| 486 | |
| 487 Dart_Handle SSLFilter::PeerCertificate() { | |
| 488 X509* ca = SSL_get_peer_certificate(ssl_); | |
| 489 if (ca == NULL) { | |
| 490 return Dart_Null(); | |
| 491 } | |
| 492 return SSLFilter::WrappedX509Certificate(ca); | |
| 493 } | |
| 494 | |
| 495 | |
| 496 void SSLFilter::InitializeLibrary() { | |
| 497 MutexLocker locker(mutex_); | |
| 498 if (!library_initialized_) { | |
| 499 SSL_library_init(); | |
| 500 filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); | |
| 501 ASSERT(filter_ssl_index >= 0); | |
| 502 library_initialized_ = true; | |
| 503 } | |
| 504 } | |
| 505 | |
| 506 | |
| 507 void SSLFilter::Connect(const char* hostname, | |
| 508 SSLCertContext* context, | |
| 509 bool is_server, | |
| 510 bool request_client_certificate, | |
| 511 bool require_client_certificate, | |
| 512 Dart_Handle protocols_handle) { | |
| 513 is_server_ = is_server; | |
| 514 if (in_handshake_) { | |
| 515 FATAL("Connect called twice on the same _SecureFilter."); | |
| 516 } | |
| 517 | |
| 518 int status; | |
| 519 int error; | |
| 520 BIO* ssl_side; | |
| 521 status = BIO_new_bio_pair(&ssl_side, kInternalBIOSize, &socket_side_, | |
| 522 kInternalBIOSize); | |
| 523 SecureSocketUtils::CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair", | |
| 524 ssl_); | |
| 525 | |
| 526 ASSERT(context != NULL); | |
| 527 ASSERT(context->context() != NULL); | |
| 528 ssl_ = SSL_new(context->context()); | |
| 529 SSL_set_bio(ssl_, ssl_side, ssl_side); | |
| 530 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right? | |
| 531 SSL_set_ex_data(ssl_, filter_ssl_index, this); | |
| 532 RegisterCallbacks(context); | |
| 533 | |
| 534 if (is_server_) { | |
| 535 int certificate_mode = | |
| 536 request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE; | |
| 537 if (require_client_certificate) { | |
| 538 certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; | |
| 539 } | |
| 540 SSL_set_verify(ssl_, certificate_mode, NULL); | |
| 541 } else { | |
| 542 SSLCertContext::SetAlpnProtocolList(protocols_handle, ssl_, NULL, false); | |
| 543 status = SSL_set_tlsext_host_name(ssl_, hostname); | |
| 544 SecureSocketUtils::CheckStatusSSL(status, "TlsException", | |
| 545 "Set SNI host name", ssl_); | |
| 546 // Sets the hostname in the certificate-checking object, so it is checked | |
| 547 // against the certificate presented by the server. | |
| 548 X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_); | |
| 549 hostname_ = strdup(hostname); | |
| 550 X509_VERIFY_PARAM_set_flags( | |
| 551 certificate_checking_parameters, | |
| 552 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_TRUSTED_FIRST); | |
| 553 X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0); | |
| 554 status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters, | |
| 555 hostname_, strlen(hostname_)); | |
| 556 SecureSocketUtils::CheckStatusSSL( | |
| 557 status, "TlsException", "Set hostname for certificate checking", ssl_); | |
| 558 } | |
| 559 // Make the connection: | |
| 560 if (is_server_) { | |
| 561 status = SSL_accept(ssl_); | |
| 562 if (SSL_LOG_STATUS) { | |
| 563 Log::Print("SSL_accept status: %d\n", status); | |
| 564 } | |
| 565 if (status != 1) { | |
| 566 // TODO(whesse): expect a needs-data error here. Handle other errors. | |
| 567 error = SSL_get_error(ssl_, status); | |
| 568 if (SSL_LOG_STATUS) { | |
| 569 Log::Print("SSL_accept error: %d\n", error); | |
| 570 } | |
| 571 } | |
| 572 } else { | |
| 573 status = SSL_connect(ssl_); | |
| 574 if (SSL_LOG_STATUS) { | |
| 575 Log::Print("SSL_connect status: %d\n", status); | |
| 576 } | |
| 577 if (status != 1) { | |
| 578 // TODO(whesse): expect a needs-data error here. Handle other errors. | |
| 579 error = SSL_get_error(ssl_, status); | |
| 580 if (SSL_LOG_STATUS) { | |
| 581 Log::Print("SSL_connect error: %d\n", error); | |
| 582 } | |
| 583 } | |
| 584 } | |
| 585 Handshake(); | |
| 586 } | |
| 587 | |
| 588 | |
| 589 int printErrorCallback(const char* str, size_t len, void* ctx) { | |
|
zra
2017/06/02 22:56:24
Is this used?
bkonyi
2017/06/05 20:25:51
Nope. Removed.
| |
| 590 Log::PrintErr("%.*s\n", static_cast<int>(len), str); | |
| 591 return 1; | |
| 592 } | |
| 593 | |
| 594 | |
| 595 void SSLFilter::Handshake() { | |
| 596 // Try and push handshake along. | |
| 597 int status; | |
| 598 status = SSL_do_handshake(ssl_); | |
| 599 if (callback_error != NULL) { | |
| 600 // The SSL_do_handshake will try performing a handshake and might call | |
| 601 // a CertificateCallback. If the certificate validation | |
| 602 // failed the 'callback_error" will be set by the certificateCallback | |
| 603 // logic and we propagate the error" | |
| 604 Dart_PropagateError(callback_error); | |
| 605 } | |
| 606 if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) { | |
| 607 in_handshake_ = true; | |
| 608 return; | |
| 609 } | |
| 610 SecureSocketUtils::CheckStatusSSL( | |
| 611 status, "HandshakeException", | |
| 612 is_server_ ? "Handshake error in server" : "Handshake error in client", | |
| 613 ssl_); | |
| 614 // Handshake succeeded. | |
| 615 if (in_handshake_) { | |
| 616 // TODO(24071): Check return value of SSL_get_verify_result, this | |
| 617 // should give us the hostname check. | |
| 618 int result = SSL_get_verify_result(ssl_); | |
| 619 if (SSL_LOG_STATUS) { | |
| 620 Log::Print("Handshake verification status: %d\n", result); | |
| 621 X509* peer_certificate = SSL_get_peer_certificate(ssl_); | |
| 622 if (peer_certificate == NULL) { | |
| 623 Log::Print("No peer certificate received\n"); | |
| 624 } else { | |
| 625 X509_NAME* s_name = X509_get_subject_name(peer_certificate); | |
| 626 printf("Peer certificate SN: "); | |
| 627 X509_NAME_print_ex_fp(stdout, s_name, 4, 0); | |
| 628 printf("\n"); | |
| 629 } | |
| 630 } | |
| 631 ThrowIfError(Dart_InvokeClosure( | |
| 632 Dart_HandleFromPersistent(handshake_complete_), 0, NULL)); | |
| 633 in_handshake_ = false; | |
| 634 } | |
| 635 } | |
| 636 | |
| 637 | |
| 638 void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) { | |
| 639 const uint8_t* protocol; | |
| 640 unsigned length; | |
| 641 SSL_get0_alpn_selected(ssl_, &protocol, &length); | |
| 642 if (length == 0) { | |
| 643 Dart_SetReturnValue(args, Dart_Null()); | |
| 644 } else { | |
| 645 Dart_SetReturnValue(args, Dart_NewStringFromUTF8(protocol, length)); | |
| 646 } | |
| 647 } | |
| 648 | |
| 649 | |
| 650 void SSLFilter::Renegotiate(bool use_session_cache, | |
| 651 bool request_client_certificate, | |
| 652 bool require_client_certificate) { | |
| 653 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the | |
| 654 // SSL_REQUEST_CERTIFICATE option is also set, so set it. | |
| 655 request_client_certificate = | |
| 656 request_client_certificate || require_client_certificate; | |
| 657 // TODO(24070, 24069): Implement setting the client certificate parameters, | |
| 658 // and triggering rehandshake. | |
| 659 } | |
| 660 | |
| 661 | |
| 662 static void ReleaseCertificate(void* isolate_data, | |
| 663 Dart_WeakPersistentHandle handle, | |
| 664 void* context_pointer) { | |
| 665 X509* cert = reinterpret_cast<X509*>(context_pointer); | |
| 666 X509_free(cert); | |
| 667 } | |
| 668 | |
| 669 | |
| 670 static intptr_t EstimateX509Size(X509* certificate) { | |
| 671 intptr_t length = i2d_X509(certificate, NULL); | |
| 672 return length > 0 ? length : 0; | |
| 673 } | |
| 674 | |
| 675 | |
| 676 // Returns the handle for a Dart object wrapping the X509 certificate object. | |
| 677 // The caller should own a reference to the X509 object whose reference count | |
| 678 // won't drop to zero before the ReleaseCertificate finalizer runs. | |
| 679 Dart_Handle SSLFilter::WrappedX509Certificate(X509* certificate) { | |
| 680 if (certificate == NULL) { | |
| 681 return Dart_Null(); | |
| 682 } | |
| 683 Dart_Handle x509_type = | |
| 684 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); | |
| 685 if (Dart_IsError(x509_type)) { | |
| 686 X509_free(certificate); | |
| 687 return x509_type; | |
| 688 } | |
| 689 Dart_Handle arguments[] = {NULL}; | |
| 690 Dart_Handle result = | |
| 691 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments); | |
| 692 if (Dart_IsError(result)) { | |
| 693 X509_free(certificate); | |
| 694 return result; | |
| 695 } | |
| 696 ASSERT(Dart_IsInstance(result)); | |
| 697 Dart_Handle status = | |
| 698 Dart_SetNativeInstanceField(result, SSLCertContext::kX509NativeFieldIndex, | |
| 699 reinterpret_cast<intptr_t>(certificate)); | |
| 700 if (Dart_IsError(status)) { | |
| 701 X509_free(certificate); | |
| 702 return status; | |
| 703 } | |
| 704 const intptr_t approximate_size_of_certificate = | |
| 705 sizeof(*certificate) + EstimateX509Size(certificate); | |
| 706 ASSERT(approximate_size_of_certificate > 0); | |
| 707 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate), | |
| 708 approximate_size_of_certificate, | |
| 709 ReleaseCertificate); | |
| 710 return result; | |
| 711 } | |
| 712 | |
| 713 | |
| 714 void SSLFilter::FreeResources() { | |
| 715 if (ssl_ != NULL) { | |
| 716 SSL_free(ssl_); | |
| 717 ssl_ = NULL; | |
| 718 } | |
| 719 if (socket_side_ != NULL) { | |
| 720 BIO_free(socket_side_); | |
| 721 socket_side_ = NULL; | |
| 722 } | |
| 723 if (hostname_ != NULL) { | |
| 724 free(hostname_); | |
| 725 hostname_ = NULL; | |
| 726 } | |
| 727 for (int i = 0; i < kNumBuffers; ++i) { | |
| 728 if (buffers_[i] != NULL) { | |
| 729 delete[] buffers_[i]; | |
| 730 buffers_[i] = NULL; | |
| 731 } | |
| 732 } | |
| 733 } | |
| 734 | |
| 735 | |
| 736 SSLFilter::~SSLFilter() { | |
| 737 FreeResources(); | |
| 738 } | |
| 739 | |
| 740 | |
| 741 void SSLFilter::Destroy() { | |
| 742 for (int i = 0; i < kNumBuffers; ++i) { | |
| 743 if (dart_buffer_objects_[i] != NULL) { | |
| 744 Dart_DeletePersistentHandle(dart_buffer_objects_[i]); | |
| 745 dart_buffer_objects_[i] = NULL; | |
| 746 } | |
| 747 } | |
| 748 if (string_start_ != NULL) { | |
| 749 Dart_DeletePersistentHandle(string_start_); | |
| 750 string_start_ = NULL; | |
| 751 } | |
| 752 if (string_length_ != NULL) { | |
| 753 Dart_DeletePersistentHandle(string_length_); | |
| 754 string_length_ = NULL; | |
| 755 } | |
| 756 if (handshake_complete_ != NULL) { | |
| 757 Dart_DeletePersistentHandle(handshake_complete_); | |
| 758 handshake_complete_ = NULL; | |
| 759 } | |
| 760 if (bad_certificate_callback_ != NULL) { | |
| 761 Dart_DeletePersistentHandle(bad_certificate_callback_); | |
| 762 bad_certificate_callback_ = NULL; | |
| 763 } | |
| 764 FreeResources(); | |
| 765 } | |
| 766 | |
| 767 | |
| 768 /* Read decrypted data from the filter to the circular buffer */ | |
| 769 int SSLFilter::ProcessReadPlaintextBuffer(int start, int end) { | |
| 770 int length = end - start; | |
| 771 int bytes_processed = 0; | |
| 772 if (length > 0) { | |
| 773 bytes_processed = SSL_read( | |
| 774 ssl_, reinterpret_cast<char*>((buffers_[kReadPlaintext] + start)), | |
| 775 length); | |
| 776 if (bytes_processed < 0) { | |
| 777 int error = SSL_get_error(ssl_, bytes_processed); | |
| 778 USE(error); | |
| 779 bytes_processed = 0; | |
| 780 } | |
| 781 } | |
| 782 return bytes_processed; | |
| 783 } | |
| 784 | |
| 785 | |
| 786 int SSLFilter::ProcessWritePlaintextBuffer(int start, int end) { | |
| 787 int length = end - start; | |
| 788 int bytes_processed = | |
| 789 SSL_write(ssl_, buffers_[kWritePlaintext] + start, length); | |
| 790 if (bytes_processed < 0) { | |
| 791 if (SSL_LOG_DATA) { | |
| 792 Log::Print("SSL_write returned error %d\n", bytes_processed); | |
| 793 } | |
| 794 return 0; | |
| 795 } | |
| 796 return bytes_processed; | |
| 797 } | |
| 798 | |
| 799 | |
| 800 /* Read encrypted data from the circular buffer to the filter */ | |
| 801 int SSLFilter::ProcessReadEncryptedBuffer(int start, int end) { | |
| 802 int length = end - start; | |
| 803 if (SSL_LOG_DATA) | |
| 804 Log::Print("Entering ProcessReadEncryptedBuffer with %d bytes\n", length); | |
| 805 int bytes_processed = 0; | |
| 806 if (length > 0) { | |
| 807 bytes_processed = | |
| 808 BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length); | |
| 809 if (bytes_processed <= 0) { | |
| 810 bool retry = BIO_should_retry(socket_side_); | |
| 811 if (!retry) { | |
| 812 if (SSL_LOG_DATA) | |
| 813 Log::Print("BIO_write failed in ReadEncryptedBuffer\n"); | |
| 814 } | |
| 815 bytes_processed = 0; | |
| 816 } | |
| 817 } | |
| 818 if (SSL_LOG_DATA) | |
| 819 Log::Print("Leaving ProcessReadEncryptedBuffer wrote %d bytes\n", | |
| 820 bytes_processed); | |
| 821 return bytes_processed; | |
| 822 } | |
| 823 | |
| 824 | |
| 825 int SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) { | |
| 826 int length = end - start; | |
| 827 int bytes_processed = 0; | |
| 828 if (length > 0) { | |
| 829 bytes_processed = | |
| 830 BIO_read(socket_side_, buffers_[kWriteEncrypted] + start, length); | |
| 831 if (bytes_processed < 0) { | |
| 832 if (SSL_LOG_DATA) | |
| 833 Log::Print("WriteEncrypted BIO_read returned error %d\n", | |
| 834 bytes_processed); | |
| 835 return 0; | |
| 836 } else { | |
| 837 if (SSL_LOG_DATA) | |
| 838 Log::Print("WriteEncrypted BIO_read wrote %d bytes\n", | |
| 839 bytes_processed); | |
| 840 } | |
| 841 } | |
| 842 return bytes_processed; | |
| 843 } | |
| 844 | |
| 845 } // namespace bin | |
| 846 } // namespace dart | |
| 847 | |
| 848 #endif // !defined(DART_IO_DISABLED) && | |
| 849 // !defined(DART_IO_SECURE_SOCKET_DISABLED) | |
| OLD | NEW |