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