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