| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #include "bin/secure_socket.h" | |
| 6 | |
| 7 #include <errno.h> | |
| 8 #include <fcntl.h> | |
| 9 #include <stdio.h> | |
| 10 #include <string.h> | |
| 11 #include <sys/stat.h> | |
| 12 | |
| 13 #include <openssl/bio.h> | |
| 14 #include <openssl/err.h> | |
| 15 #include <openssl/pkcs12.h> | |
| 16 #include <openssl/safestack.h> | |
| 17 #include <openssl/ssl.h> | |
| 18 #include <openssl/tls1.h> | |
| 19 #include <openssl/x509.h> | |
| 20 | |
| 21 #include "bin/builtin.h" | |
| 22 #include "bin/dartutils.h" | |
| 23 #include "bin/lockers.h" | |
| 24 #include "bin/log.h" | |
| 25 #include "bin/socket.h" | |
| 26 #include "bin/thread.h" | |
| 27 #include "bin/utils.h" | |
| 28 #include "platform/utils.h" | |
| 29 | |
| 30 #include "include/dart_api.h" | |
| 31 | |
| 32 // Return the error from the containing function if handle is an error handle. | |
| 33 #define RETURN_IF_ERROR(handle) \ | |
| 34 { \ | |
| 35 Dart_Handle __handle = handle; \ | |
| 36 if (Dart_IsError((__handle))) { \ | |
| 37 return __handle; \ | |
| 38 } \ | |
| 39 } | |
| 40 | |
| 41 namespace dart { | |
| 42 namespace bin { | |
| 43 | |
| 44 bool SSLFilter::library_initialized_ = false; | |
| 45 // To protect library initialization. | |
| 46 Mutex* SSLFilter::mutex_ = new Mutex(); | |
| 47 int SSLFilter::filter_ssl_index; | |
| 48 | |
| 49 static const int kSSLFilterNativeFieldIndex = 0; | |
| 50 static const int kSecurityContextNativeFieldIndex = 0; | |
| 51 static const int kX509NativeFieldIndex = 0; | |
| 52 | |
| 53 static const bool SSL_LOG_STATUS = false; | |
| 54 static const bool SSL_LOG_DATA = false; | |
| 55 | |
| 56 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000; | |
| 57 | |
| 58 | |
| 59 /* Get the error messages from BoringSSL, and put them in buffer as a | |
| 60 * null-terminated string. */ | |
| 61 static void FetchErrorString(char* buffer, int length) { | |
| 62 buffer[0] = '\0'; | |
| 63 int error = ERR_get_error(); | |
| 64 while (error != 0) { | |
| 65 int used = strlen(buffer); | |
| 66 int free_length = length - used; | |
| 67 if (free_length > 16) { | |
| 68 // Enough room for error code at least. | |
| 69 if (used > 0) { | |
| 70 buffer[used] = '\n'; | |
| 71 buffer[used + 1] = '\0'; | |
| 72 used++; | |
| 73 free_length--; | |
| 74 } | |
| 75 ERR_error_string_n(error, buffer + used, free_length); | |
| 76 // ERR_error_string_n is guaranteed to leave a null-terminated string. | |
| 77 } | |
| 78 error = ERR_get_error(); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 | |
| 83 /* Handle an error reported from the BoringSSL library. */ | |
| 84 static void ThrowIOException(int status, | |
| 85 const char* exception_type, | |
| 86 const char* message) { | |
| 87 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; | |
| 88 FetchErrorString(error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); | |
| 89 OSError os_error_struct(status, error_string, OSError::kBoringSSL); | |
| 90 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); | |
| 91 Dart_Handle exception = | |
| 92 DartUtils::NewDartIOException(exception_type, message, os_error); | |
| 93 ASSERT(!Dart_IsError(exception)); | |
| 94 Dart_ThrowException(exception); | |
| 95 UNREACHABLE(); | |
| 96 } | |
| 97 | |
| 98 | |
| 99 static SSLFilter* GetFilter(Dart_NativeArguments args) { | |
| 100 SSLFilter* filter; | |
| 101 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
| 102 ASSERT(Dart_IsInstance(dart_this)); | |
| 103 ThrowIfError(Dart_GetNativeInstanceField( | |
| 104 dart_this, | |
| 105 kSSLFilterNativeFieldIndex, | |
| 106 reinterpret_cast<intptr_t*>(&filter))); | |
| 107 return filter; | |
| 108 } | |
| 109 | |
| 110 | |
| 111 static void DeleteFilter( | |
| 112 void* isolate_data, | |
| 113 Dart_WeakPersistentHandle handle, | |
| 114 void* context_pointer) { | |
| 115 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer); | |
| 116 delete filter; | |
| 117 } | |
| 118 | |
| 119 | |
| 120 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) { | |
| 121 ASSERT(filter != NULL); | |
| 122 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); | |
| 123 RETURN_IF_ERROR(dart_this); | |
| 124 ASSERT(Dart_IsInstance(dart_this)); | |
| 125 Dart_Handle err = Dart_SetNativeInstanceField( | |
| 126 dart_this, | |
| 127 kSSLFilterNativeFieldIndex, | |
| 128 reinterpret_cast<intptr_t>(filter)); | |
| 129 RETURN_IF_ERROR(err); | |
| 130 Dart_NewWeakPersistentHandle(dart_this, | |
| 131 reinterpret_cast<void*>(filter), | |
| 132 sizeof(*filter), | |
| 133 DeleteFilter); | |
| 134 return Dart_Null(); | |
| 135 } | |
| 136 | |
| 137 | |
| 138 static SSL_CTX* GetSecurityContext(Dart_NativeArguments args) { | |
| 139 SSL_CTX* context; | |
| 140 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
| 141 ASSERT(Dart_IsInstance(dart_this)); | |
| 142 ThrowIfError(Dart_GetNativeInstanceField( | |
| 143 dart_this, | |
| 144 kSecurityContextNativeFieldIndex, | |
| 145 reinterpret_cast<intptr_t*>(&context))); | |
| 146 return context; | |
| 147 } | |
| 148 | |
| 149 | |
| 150 static void FreeSecurityContext( | |
| 151 void* isolate_data, | |
| 152 Dart_WeakPersistentHandle handle, | |
| 153 void* context_pointer) { | |
| 154 SSL_CTX* context = static_cast<SSL_CTX*>(context_pointer); | |
| 155 SSL_CTX_free(context); | |
| 156 } | |
| 157 | |
| 158 | |
| 159 static Dart_Handle SetSecurityContext(Dart_NativeArguments args, | |
| 160 SSL_CTX* context) { | |
| 161 const int approximate_size_of_context = 1500; | |
| 162 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); | |
| 163 RETURN_IF_ERROR(dart_this); | |
| 164 ASSERT(Dart_IsInstance(dart_this)); | |
| 165 Dart_Handle err = Dart_SetNativeInstanceField( | |
| 166 dart_this, | |
| 167 kSecurityContextNativeFieldIndex, | |
| 168 reinterpret_cast<intptr_t>(context)); | |
| 169 RETURN_IF_ERROR(err); | |
| 170 Dart_NewWeakPersistentHandle(dart_this, | |
| 171 context, | |
| 172 approximate_size_of_context, | |
| 173 FreeSecurityContext); | |
| 174 return Dart_Null(); | |
| 175 } | |
| 176 | |
| 177 | |
| 178 static X509* GetX509Certificate(Dart_NativeArguments args) { | |
| 179 X509* certificate; | |
| 180 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
| 181 ASSERT(Dart_IsInstance(dart_this)); | |
| 182 ThrowIfError(Dart_GetNativeInstanceField( | |
| 183 dart_this, | |
| 184 kX509NativeFieldIndex, | |
| 185 reinterpret_cast<intptr_t*>(&certificate))); | |
| 186 return certificate; | |
| 187 } | |
| 188 | |
| 189 | |
| 190 // Forward declaration. | |
| 191 static void SetAlpnProtocolList(Dart_Handle protocols_handle, | |
| 192 SSL* ssl, | |
| 193 SSL_CTX* context, | |
| 194 bool is_server); | |
| 195 | |
| 196 | |
| 197 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { | |
| 198 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
| 199 SSLFilter* filter = new SSLFilter(); | |
| 200 Dart_Handle err = SetFilter(args, filter); | |
| 201 if (Dart_IsError(err)) { | |
| 202 delete filter; | |
| 203 Dart_PropagateError(err); | |
| 204 } | |
| 205 err = filter->Init(dart_this); | |
| 206 if (Dart_IsError(err)) { | |
| 207 // The finalizer was set up by SetFilter. It will delete `filter` if there | |
| 208 // is an error. | |
| 209 filter->Destroy(); | |
| 210 Dart_PropagateError(err); | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 | |
| 215 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { | |
| 216 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
| 217 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); | |
| 218 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); | |
| 219 bool request_client_certificate = | |
| 220 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); | |
| 221 bool require_client_certificate = | |
| 222 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); | |
| 223 Dart_Handle protocols_handle = | |
| 224 ThrowIfError(Dart_GetNativeArgument(args, 6)); | |
| 225 | |
| 226 const char* host_name = NULL; | |
| 227 // TODO(whesse): Is truncating a Dart string containing \0 what we want? | |
| 228 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); | |
| 229 | |
| 230 SSL_CTX* context = NULL; | |
| 231 if (!Dart_IsNull(context_object)) { | |
| 232 ThrowIfError(Dart_GetNativeInstanceField( | |
| 233 context_object, | |
| 234 kSecurityContextNativeFieldIndex, | |
| 235 reinterpret_cast<intptr_t*>(&context))); | |
| 236 } | |
| 237 | |
| 238 // The protocols_handle is guaranteed to be a valid Uint8List. | |
| 239 // It will have the correct length encoding of the protocols array. | |
| 240 ASSERT(!Dart_IsNull(protocols_handle)); | |
| 241 | |
| 242 GetFilter(args)->Connect(host_name, | |
| 243 context, | |
| 244 is_server, | |
| 245 request_client_certificate, | |
| 246 require_client_certificate, | |
| 247 protocols_handle); | |
| 248 } | |
| 249 | |
| 250 | |
| 251 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { | |
| 252 SSLFilter* filter = GetFilter(args); | |
| 253 // The SSLFilter is deleted in the finalizer for the Dart object created by | |
| 254 // SetFilter. There is no need to NULL-out the native field for the SSLFilter | |
| 255 // here because the SSLFilter won't be deleted until the finalizer for the | |
| 256 // Dart object runs while the Dart object is being GCd. This approach avoids a | |
| 257 // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is | |
| 258 // called more than once. | |
| 259 filter->Destroy(); | |
| 260 } | |
| 261 | |
| 262 | |
| 263 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) { | |
| 264 GetFilter(args)->Handshake(); | |
| 265 } | |
| 266 | |
| 267 | |
| 268 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)( | |
| 269 Dart_NativeArguments args) { | |
| 270 GetFilter(args)->GetSelectedProtocol(args); | |
| 271 } | |
| 272 | |
| 273 | |
| 274 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) { | |
| 275 bool use_session_cache = | |
| 276 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1)); | |
| 277 bool request_client_certificate = | |
| 278 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2)); | |
| 279 bool require_client_certificate = | |
| 280 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); | |
| 281 GetFilter(args)->Renegotiate(use_session_cache, | |
| 282 request_client_certificate, | |
| 283 require_client_certificate); | |
| 284 } | |
| 285 | |
| 286 | |
| 287 void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)( | |
| 288 Dart_NativeArguments args) { | |
| 289 Dart_Handle handshake_complete = | |
| 290 ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
| 291 if (!Dart_IsClosure(handshake_complete)) { | |
| 292 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 293 "Illegal argument to RegisterHandshakeCompleteCallback")); | |
| 294 } | |
| 295 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete); | |
| 296 } | |
| 297 | |
| 298 | |
| 299 void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)( | |
| 300 Dart_NativeArguments args) { | |
| 301 Dart_Handle callback = | |
| 302 ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
| 303 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) { | |
| 304 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 305 "Illegal argument to RegisterBadCertificateCallback")); | |
| 306 } | |
| 307 GetFilter(args)->RegisterBadCertificateCallback(callback); | |
| 308 } | |
| 309 | |
| 310 | |
| 311 void FUNCTION_NAME(SecureSocket_PeerCertificate) | |
| 312 (Dart_NativeArguments args) { | |
| 313 Dart_Handle cert = ThrowIfError(GetFilter(args)->PeerCertificate()); | |
| 314 Dart_SetReturnValue(args, cert); | |
| 315 } | |
| 316 | |
| 317 | |
| 318 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { | |
| 319 intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args)); | |
| 320 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); | |
| 321 } | |
| 322 | |
| 323 | |
| 324 static void ReleaseCertificate( | |
| 325 void* isolate_data, | |
| 326 Dart_WeakPersistentHandle handle, | |
| 327 void* context_pointer) { | |
| 328 X509* cert = reinterpret_cast<X509*>(context_pointer); | |
| 329 X509_free(cert); | |
| 330 } | |
| 331 | |
| 332 | |
| 333 // Returns the handle for a Dart object wrapping the X509 certificate object. | |
| 334 // The caller should own a reference to the X509 object whose reference count | |
| 335 // won't drop to zero before the ReleaseCertificate finalizer runs. | |
| 336 static Dart_Handle WrappedX509Certificate(X509* certificate) { | |
| 337 const intptr_t approximate_size_of_certificate = 1500; | |
| 338 if (certificate == NULL) { | |
| 339 return Dart_Null(); | |
| 340 } | |
| 341 Dart_Handle x509_type = | |
| 342 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); | |
| 343 if (Dart_IsError(x509_type)) { | |
| 344 X509_free(certificate); | |
| 345 return x509_type; | |
| 346 } | |
| 347 Dart_Handle arguments[] = { NULL }; | |
| 348 Dart_Handle result = | |
| 349 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments); | |
| 350 if (Dart_IsError(result)) { | |
| 351 X509_free(certificate); | |
| 352 return result; | |
| 353 } | |
| 354 ASSERT(Dart_IsInstance(result)); | |
| 355 Dart_Handle status = Dart_SetNativeInstanceField( | |
| 356 result, | |
| 357 kX509NativeFieldIndex, | |
| 358 reinterpret_cast<intptr_t>(certificate)); | |
| 359 if (Dart_IsError(status)) { | |
| 360 X509_free(certificate); | |
| 361 return status; | |
| 362 } | |
| 363 Dart_NewWeakPersistentHandle(result, | |
| 364 reinterpret_cast<void*>(certificate), | |
| 365 approximate_size_of_certificate, | |
| 366 ReleaseCertificate); | |
| 367 return result; | |
| 368 } | |
| 369 | |
| 370 | |
| 371 int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) { | |
| 372 if (preverify_ok == 1) { | |
| 373 return 1; | |
| 374 } | |
| 375 Dart_Isolate isolate = Dart_CurrentIsolate(); | |
| 376 if (isolate == NULL) { | |
| 377 FATAL("CertificateCallback called with no current isolate\n"); | |
| 378 } | |
| 379 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx); | |
| 380 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx(); | |
| 381 SSL* ssl = static_cast<SSL*>( | |
| 382 X509_STORE_CTX_get_ex_data(store_ctx, ssl_index)); | |
| 383 SSLFilter* filter = static_cast<SSLFilter*>( | |
| 384 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index)); | |
| 385 Dart_Handle callback = filter->bad_certificate_callback(); | |
| 386 if (Dart_IsNull(callback)) { | |
| 387 return 0; | |
| 388 } | |
| 389 | |
| 390 // Upref since the Dart X509 object may outlive the SecurityContext. | |
| 391 if (certificate != NULL) { | |
| 392 X509_up_ref(certificate); | |
| 393 } | |
| 394 Dart_Handle args[1]; | |
| 395 args[0] = WrappedX509Certificate(certificate); | |
| 396 if (Dart_IsError(args[0])) { | |
| 397 filter->callback_error = args[0]; | |
| 398 return 0; | |
| 399 } | |
| 400 Dart_Handle result = Dart_InvokeClosure(callback, 1, args); | |
| 401 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) { | |
| 402 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException( | |
| 403 "HandshakeException", | |
| 404 "BadCertificateCallback returned a value that was not a boolean", | |
| 405 Dart_Null())); | |
| 406 } | |
| 407 if (Dart_IsError(result)) { | |
| 408 filter->callback_error = result; | |
| 409 return 0; | |
| 410 } | |
| 411 return DartUtils::GetBooleanValue(result); | |
| 412 } | |
| 413 | |
| 414 | |
| 415 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) { | |
| 416 SSLFilter::InitializeLibrary(); | |
| 417 SSL_CTX* context = SSL_CTX_new(TLS_method()); | |
| 418 SSL_CTX_set_verify(context, SSL_VERIFY_PEER, CertificateCallback); | |
| 419 SSL_CTX_set_min_version(context, TLS1_VERSION); | |
| 420 SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM"); | |
| 421 SSL_CTX_set_cipher_list_tls11(context, "HIGH:MEDIUM"); | |
| 422 Dart_Handle err = SetSecurityContext(args, context); | |
| 423 if (Dart_IsError(err)) { | |
| 424 SSL_CTX_free(context); | |
| 425 Dart_PropagateError(err); | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 | |
| 430 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) { | |
| 431 char* password = static_cast<char*>(userdata); | |
| 432 ASSERT(size == PEM_BUFSIZE); | |
| 433 strncpy(buf, password, size); | |
| 434 return strlen(password); | |
| 435 } | |
| 436 | |
| 437 | |
| 438 void CheckStatus(int status, const char* type, const char* message) { | |
| 439 // TODO(24183): Take appropriate action on failed calls, | |
| 440 // throw exception that includes all messages from the error stack. | |
| 441 if (status == 1) { | |
| 442 return; | |
| 443 } | |
| 444 if (SSL_LOG_STATUS) { | |
| 445 int error = ERR_get_error(); | |
| 446 Log::PrintErr("Failed: %s status %d", message, status); | |
| 447 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; | |
| 448 ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); | |
| 449 Log::PrintErr("ERROR: %d %s\n", error, error_string); | |
| 450 } | |
| 451 ThrowIOException(status, type, message); | |
| 452 } | |
| 453 | |
| 454 | |
| 455 // Where the argument to the constructor is the handle for an object | |
| 456 // implementing List<int>, this class creates a scope in which a memory-backed | |
| 457 // BIO is allocated. Leaving the scope cleans up the BIO and the buffer that | |
| 458 // was used to create it. | |
| 459 // | |
| 460 // Do not make Dart_ API calls while in a ScopedMemBIO. | |
| 461 // Do not call Dart_PropagateError while in a ScopedMemBIO. | |
| 462 class ScopedMemBIO { | |
| 463 public: | |
| 464 explicit ScopedMemBIO(Dart_Handle object) { | |
| 465 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { | |
| 466 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 467 "Argument is not a List<int>")); | |
| 468 } | |
| 469 | |
| 470 uint8_t* bytes = NULL; | |
| 471 intptr_t bytes_len = 0; | |
| 472 bool is_typed_data = false; | |
| 473 if (Dart_IsTypedData(object)) { | |
| 474 is_typed_data = true; | |
| 475 Dart_TypedData_Type typ; | |
| 476 ThrowIfError(Dart_TypedDataAcquireData( | |
| 477 object, | |
| 478 &typ, | |
| 479 reinterpret_cast<void**>(&bytes), | |
| 480 &bytes_len)); | |
| 481 } else { | |
| 482 ASSERT(Dart_IsList(object)); | |
| 483 ThrowIfError(Dart_ListLength(object, &bytes_len)); | |
| 484 bytes = Dart_ScopeAllocate(bytes_len); | |
| 485 ASSERT(bytes != NULL); | |
| 486 ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len)); | |
| 487 } | |
| 488 | |
| 489 object_ = object; | |
| 490 bytes_ = bytes; | |
| 491 bytes_len_ = bytes_len; | |
| 492 bio_ = BIO_new_mem_buf(bytes, bytes_len); | |
| 493 ASSERT(bio_ != NULL); | |
| 494 is_typed_data_ = is_typed_data; | |
| 495 } | |
| 496 | |
| 497 ~ScopedMemBIO() { | |
| 498 ASSERT(bio_ != NULL); | |
| 499 if (is_typed_data_) { | |
| 500 BIO_free(bio_); | |
| 501 ThrowIfError(Dart_TypedDataReleaseData(object_)); | |
| 502 } else { | |
| 503 BIO_free(bio_); | |
| 504 } | |
| 505 } | |
| 506 | |
| 507 BIO* bio() { | |
| 508 ASSERT(bio_ != NULL); | |
| 509 return bio_; | |
| 510 } | |
| 511 | |
| 512 private: | |
| 513 Dart_Handle object_; | |
| 514 uint8_t* bytes_; | |
| 515 intptr_t bytes_len_; | |
| 516 BIO* bio_; | |
| 517 bool is_typed_data_; | |
| 518 | |
| 519 DISALLOW_ALLOCATION(); | |
| 520 DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO); | |
| 521 }; | |
| 522 | |
| 523 template<typename T, void (*free_func)(T*)> | |
| 524 class ScopedSSLType { | |
| 525 public: | |
| 526 explicit ScopedSSLType(T* obj) : obj_(obj) {} | |
| 527 | |
| 528 ~ScopedSSLType() { | |
| 529 if (obj_ != NULL) { | |
| 530 free_func(obj_); | |
| 531 } | |
| 532 } | |
| 533 | |
| 534 T* get() { return obj_; } | |
| 535 const T* get() const { return obj_; } | |
| 536 | |
| 537 T* release() { | |
| 538 T* result = obj_; | |
| 539 obj_ = NULL; | |
| 540 return result; | |
| 541 } | |
| 542 | |
| 543 private: | |
| 544 T* obj_; | |
| 545 | |
| 546 DISALLOW_ALLOCATION(); | |
| 547 DISALLOW_COPY_AND_ASSIGN(ScopedSSLType); | |
| 548 }; | |
| 549 | |
| 550 template<typename T, typename E, void (*func)(E*)> | |
| 551 class ScopedSSLStackType { | |
| 552 public: | |
| 553 explicit ScopedSSLStackType(T* obj) : obj_(obj) {} | |
| 554 | |
| 555 ~ScopedSSLStackType() { | |
| 556 if (obj_ != NULL) { | |
| 557 sk_pop_free(reinterpret_cast<_STACK*>(obj_), | |
| 558 reinterpret_cast<void (*)(void *)>(func)); | |
| 559 } | |
| 560 } | |
| 561 | |
| 562 T* get() { return obj_; } | |
| 563 const T* get() const { return obj_; } | |
| 564 | |
| 565 T* release() { | |
| 566 T* result = obj_; | |
| 567 obj_ = NULL; | |
| 568 return result; | |
| 569 } | |
| 570 | |
| 571 private: | |
| 572 T* obj_; | |
| 573 | |
| 574 DISALLOW_ALLOCATION(); | |
| 575 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); | |
| 576 }; | |
| 577 | |
| 578 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; | |
| 579 typedef ScopedSSLType<X509, X509_free> ScopedX509; | |
| 580 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; | |
| 581 | |
| 582 static bool NoPEMStartLine() { | |
| 583 uint32_t last_error = ERR_peek_last_error(); | |
| 584 return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && | |
| 585 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); | |
| 586 } | |
| 587 | |
| 588 | |
| 589 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { | |
| 590 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
| 591 if (p12.get() == NULL) { | |
| 592 return NULL; | |
| 593 } | |
| 594 | |
| 595 EVP_PKEY* key = NULL; | |
| 596 X509 *cert = NULL; | |
| 597 STACK_OF(X509) *ca_certs = NULL; | |
| 598 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
| 599 if (status == 0) { | |
| 600 return NULL; | |
| 601 } | |
| 602 | |
| 603 // We only care about the private key. | |
| 604 ScopedX509 delete_cert(cert); | |
| 605 ScopedX509Stack delete_ca_certs(ca_certs); | |
| 606 return key; | |
| 607 } | |
| 608 | |
| 609 | |
| 610 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { | |
| 611 EVP_PKEY *key = PEM_read_bio_PrivateKey( | |
| 612 bio, NULL, PasswordCallback, const_cast<char*>(password)); | |
| 613 if (key == NULL) { | |
| 614 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and | |
| 615 // if there is no indication that the data is malformed PEM. We assume the | |
| 616 // data is malformed PEM if it contains the start line, i.e. a line | |
| 617 // with ----- BEGIN. | |
| 618 if (NoPEMStartLine()) { | |
| 619 // Reset the bio, and clear the error from trying to read as PEM. | |
| 620 ERR_clear_error(); | |
| 621 BIO_reset(bio); | |
| 622 | |
| 623 // Try to decode as PKCS12. | |
| 624 key = GetPrivateKeyPKCS12(bio, password); | |
| 625 } | |
| 626 } | |
| 627 return key; | |
| 628 } | |
| 629 | |
| 630 | |
| 631 static const char* GetPasswordArgument(Dart_NativeArguments args, | |
| 632 intptr_t index) { | |
| 633 Dart_Handle password_object = | |
| 634 ThrowIfError(Dart_GetNativeArgument(args, index)); | |
| 635 const char* password = NULL; | |
| 636 if (Dart_IsString(password_object)) { | |
| 637 ThrowIfError(Dart_StringToCString(password_object, &password)); | |
| 638 if (strlen(password) > PEM_BUFSIZE - 1) { | |
| 639 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 640 "Password length is greater than 1023 (PEM_BUFSIZE)")); | |
| 641 } | |
| 642 } else if (Dart_IsNull(password_object)) { | |
| 643 password = ""; | |
| 644 } else { | |
| 645 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 646 "Password is not a String or null")); | |
| 647 } | |
| 648 return password; | |
| 649 } | |
| 650 | |
| 651 | |
| 652 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( | |
| 653 Dart_NativeArguments args) { | |
| 654 SSL_CTX* context = GetSecurityContext(args); | |
| 655 const char* password = GetPasswordArgument(args, 2); | |
| 656 | |
| 657 int status; | |
| 658 { | |
| 659 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | |
| 660 EVP_PKEY *key = GetPrivateKey(bio.bio(), password); | |
| 661 status = SSL_CTX_use_PrivateKey(context, key); | |
| 662 } | |
| 663 | |
| 664 // TODO(24184): Handle different expected errors here - file missing, | |
| 665 // incorrect password, file not a PEM, and throw exceptions. | |
| 666 // CheckStatus should also throw an exception in uncaught cases. | |
| 667 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); | |
| 668 } | |
| 669 | |
| 670 | |
| 671 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, | |
| 672 BIO* bio, | |
| 673 const char* password) { | |
| 674 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
| 675 if (p12.get() == NULL) { | |
| 676 return 0; | |
| 677 } | |
| 678 | |
| 679 EVP_PKEY* key = NULL; | |
| 680 X509 *cert = NULL; | |
| 681 STACK_OF(X509) *ca_certs = NULL; | |
| 682 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
| 683 if (status == 0) { | |
| 684 return status; | |
| 685 } | |
| 686 | |
| 687 ScopedX509Stack cert_stack(ca_certs); | |
| 688 X509_STORE* store = SSL_CTX_get_cert_store(context); | |
| 689 status = X509_STORE_add_cert(store, cert); | |
| 690 if (status == 0) { | |
| 691 X509_free(cert); | |
| 692 return status; | |
| 693 } | |
| 694 | |
| 695 X509* ca; | |
| 696 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { | |
| 697 status = X509_STORE_add_cert(store, ca); | |
| 698 if (status == 0) { | |
| 699 X509_free(ca); | |
| 700 return status; | |
| 701 } | |
| 702 } | |
| 703 | |
| 704 return status; | |
| 705 } | |
| 706 | |
| 707 | |
| 708 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) { | |
| 709 X509_STORE* store = SSL_CTX_get_cert_store(context); | |
| 710 | |
| 711 int status = 0; | |
| 712 X509* cert = NULL; | |
| 713 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | |
| 714 status = X509_STORE_add_cert(store, cert); | |
| 715 if (status == 0) { | |
| 716 X509_free(cert); | |
| 717 return status; | |
| 718 } | |
| 719 } | |
| 720 | |
| 721 // If no PEM start line is found, it means that we read to the end of the | |
| 722 // file, or that the file isn't PEM. In the first case, status will be | |
| 723 // non-zero indicating success. In the second case, status will be 0, | |
| 724 // indicating that we should try to read as PKCS12. If there is some other | |
| 725 // error, we return it up to the caller. | |
| 726 return NoPEMStartLine() ? status : 0; | |
| 727 } | |
| 728 | |
| 729 | |
| 730 static int SetTrustedCertificatesBytes(SSL_CTX* context, | |
| 731 BIO* bio, | |
| 732 const char* password) { | |
| 733 int status = SetTrustedCertificatesBytesPEM(context, bio); | |
| 734 if (status == 0) { | |
| 735 if (NoPEMStartLine()) { | |
| 736 ERR_clear_error(); | |
| 737 BIO_reset(bio); | |
| 738 status = SetTrustedCertificatesBytesPKCS12(context, bio, password); | |
| 739 } | |
| 740 } else { | |
| 741 // The PEM file was successfully parsed. | |
| 742 ERR_clear_error(); | |
| 743 } | |
| 744 return status; | |
| 745 } | |
| 746 | |
| 747 | |
| 748 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( | |
| 749 Dart_NativeArguments args) { | |
| 750 SSL_CTX* context = GetSecurityContext(args); | |
| 751 const char* password = GetPasswordArgument(args, 2); | |
| 752 int status; | |
| 753 { | |
| 754 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | |
| 755 status = SetTrustedCertificatesBytes(context, bio.bio(), password); | |
| 756 } | |
| 757 CheckStatus(status, | |
| 758 "TlsException", | |
| 759 "Failure in setTrustedCertificatesBytes"); | |
| 760 } | |
| 761 | |
| 762 | |
| 763 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( | |
| 764 Dart_NativeArguments args) { | |
| 765 SSL_CTX* context = GetSecurityContext(args); | |
| 766 X509_STORE* store = SSL_CTX_get_cert_store(context); | |
| 767 BIO* roots_bio = | |
| 768 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), | |
| 769 root_certificates_pem_length); | |
| 770 X509* root_cert; | |
| 771 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, | |
| 772 // backed by a memory buffer), and returns X509 objects, one by one. | |
| 773 // When the end of the bio is reached, it returns null. | |
| 774 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) { | |
| 775 X509_STORE_add_cert(store, root_cert); | |
| 776 } | |
| 777 BIO_free(roots_bio); | |
| 778 } | |
| 779 | |
| 780 | |
| 781 static int UseChainBytesPKCS12(SSL_CTX* context, | |
| 782 BIO* bio, | |
| 783 const char* password) { | |
| 784 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
| 785 if (p12.get() == NULL) { | |
| 786 return 0; | |
| 787 } | |
| 788 | |
| 789 EVP_PKEY* key = NULL; | |
| 790 X509 *cert = NULL; | |
| 791 STACK_OF(X509) *ca_certs = NULL; | |
| 792 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
| 793 if (status == 0) { | |
| 794 return status; | |
| 795 } | |
| 796 | |
| 797 ScopedX509 x509(cert); | |
| 798 ScopedX509Stack certs(ca_certs); | |
| 799 status = SSL_CTX_use_certificate(context, x509.get()); | |
| 800 if (ERR_peek_error() != 0) { | |
| 801 // Key/certificate mismatch doesn't imply status is 0. | |
| 802 status = 0; | |
| 803 } | |
| 804 if (status == 0) { | |
| 805 return status; | |
| 806 } | |
| 807 | |
| 808 SSL_CTX_clear_chain_certs(context); | |
| 809 | |
| 810 X509* ca; | |
| 811 while ((ca = sk_X509_shift(certs.get())) != NULL) { | |
| 812 status = SSL_CTX_add0_chain_cert(context, ca); | |
| 813 if (status == 0) { | |
| 814 X509_free(ca); | |
| 815 return status; | |
| 816 } | |
| 817 } | |
| 818 | |
| 819 return status; | |
| 820 } | |
| 821 | |
| 822 | |
| 823 static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) { | |
| 824 int status = 0; | |
| 825 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL)); | |
| 826 if (x509.get() == NULL) { | |
| 827 return 0; | |
| 828 } | |
| 829 | |
| 830 status = SSL_CTX_use_certificate(context, x509.get()); | |
| 831 if (ERR_peek_error() != 0) { | |
| 832 // Key/certificate mismatch doesn't imply status is 0. | |
| 833 status = 0; | |
| 834 } | |
| 835 if (status == 0) { | |
| 836 return status; | |
| 837 } | |
| 838 | |
| 839 SSL_CTX_clear_chain_certs(context); | |
| 840 | |
| 841 X509* ca; | |
| 842 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | |
| 843 status = SSL_CTX_add0_chain_cert(context, ca); | |
| 844 if (status == 0) { | |
| 845 X509_free(ca); | |
| 846 return status; | |
| 847 } | |
| 848 // Note that we must not free `ca` if it was successfully added to the | |
| 849 // chain. We must free the main certificate x509, though since its reference | |
| 850 // count is increased by SSL_CTX_use_certificate. | |
| 851 } | |
| 852 | |
| 853 return NoPEMStartLine() ? status : 0; | |
| 854 } | |
| 855 | |
| 856 | |
| 857 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) { | |
| 858 int status = UseChainBytesPEM(context, bio); | |
| 859 if (status == 0) { | |
| 860 if (NoPEMStartLine()) { | |
| 861 ERR_clear_error(); | |
| 862 BIO_reset(bio); | |
| 863 status = UseChainBytesPKCS12(context, bio, password); | |
| 864 } | |
| 865 } else { | |
| 866 // The PEM file was successfully read. | |
| 867 ERR_clear_error(); | |
| 868 } | |
| 869 return status; | |
| 870 } | |
| 871 | |
| 872 | |
| 873 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( | |
| 874 Dart_NativeArguments args) { | |
| 875 SSL_CTX* context = GetSecurityContext(args); | |
| 876 const char* password = GetPasswordArgument(args, 2); | |
| 877 int status; | |
| 878 { | |
| 879 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | |
| 880 status = UseChainBytes(context, bio.bio(), password); | |
| 881 } | |
| 882 CheckStatus(status, | |
| 883 "TlsException", | |
| 884 "Failure in useCertificateChainBytes"); | |
| 885 } | |
| 886 | |
| 887 | |
| 888 static int SetClientAuthoritiesPKCS12(SSL_CTX* context, | |
| 889 BIO* bio, | |
| 890 const char* password) { | |
| 891 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
| 892 if (p12.get() == NULL) { | |
| 893 return 0; | |
| 894 } | |
| 895 | |
| 896 EVP_PKEY* key = NULL; | |
| 897 X509 *cert = NULL; | |
| 898 STACK_OF(X509) *ca_certs = NULL; | |
| 899 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
| 900 if (status == 0) { | |
| 901 return status; | |
| 902 } | |
| 903 | |
| 904 ScopedX509Stack cert_stack(ca_certs); | |
| 905 status = SSL_CTX_add_client_CA(context, cert); | |
| 906 if (status == 0) { | |
| 907 X509_free(cert); | |
| 908 return status; | |
| 909 } | |
| 910 | |
| 911 X509* ca; | |
| 912 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { | |
| 913 status = SSL_CTX_add_client_CA(context, ca); | |
| 914 X509_free(ca); // The name has been extracted. | |
| 915 if (status == 0) { | |
| 916 return status; | |
| 917 } | |
| 918 } | |
| 919 | |
| 920 return status; | |
| 921 } | |
| 922 | |
| 923 | |
| 924 static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) { | |
| 925 int status = 0; | |
| 926 X509* cert = NULL; | |
| 927 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | |
| 928 status = SSL_CTX_add_client_CA(context, cert); | |
| 929 X509_free(cert); // The name has been extracted. | |
| 930 if (status == 0) { | |
| 931 return status; | |
| 932 } | |
| 933 } | |
| 934 return NoPEMStartLine() ? status : 0; | |
| 935 } | |
| 936 | |
| 937 | |
| 938 static int SetClientAuthorities(SSL_CTX* context, | |
| 939 BIO* bio, | |
| 940 const char* password) { | |
| 941 int status = SetClientAuthoritiesPEM(context, bio); | |
| 942 if (status == 0) { | |
| 943 if (NoPEMStartLine()) { | |
| 944 ERR_clear_error(); | |
| 945 BIO_reset(bio); | |
| 946 status = SetClientAuthoritiesPKCS12(context, bio, password); | |
| 947 } | |
| 948 } else { | |
| 949 // The PEM file was successfully parsed. | |
| 950 ERR_clear_error(); | |
| 951 } | |
| 952 return status; | |
| 953 } | |
| 954 | |
| 955 | |
| 956 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( | |
| 957 Dart_NativeArguments args) { | |
| 958 SSL_CTX* context = GetSecurityContext(args); | |
| 959 const char* password = GetPasswordArgument(args, 2); | |
| 960 | |
| 961 int status; | |
| 962 { | |
| 963 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | |
| 964 status = SetClientAuthorities(context, bio.bio(), password); | |
| 965 } | |
| 966 | |
| 967 CheckStatus(status, | |
| 968 "TlsException", | |
| 969 "Failure in setClientAuthoritiesBytes"); | |
| 970 } | |
| 971 | |
| 972 | |
| 973 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( | |
| 974 Dart_NativeArguments args) { | |
| 975 SSL_CTX* context = GetSecurityContext(args); | |
| 976 Dart_Handle protocols_handle = | |
| 977 ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
| 978 Dart_Handle is_server_handle = | |
| 979 ThrowIfError(Dart_GetNativeArgument(args, 2)); | |
| 980 if (Dart_IsBoolean(is_server_handle)) { | |
| 981 bool is_server = DartUtils::GetBooleanValue(is_server_handle); | |
| 982 SetAlpnProtocolList(protocols_handle, NULL, context, is_server); | |
| 983 } else { | |
| 984 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
| 985 "Non-boolean is_server argument passed to SetAlpnProtocols")); | |
| 986 } | |
| 987 } | |
| 988 | |
| 989 | |
| 990 void FUNCTION_NAME(X509_Subject)( | |
| 991 Dart_NativeArguments args) { | |
| 992 X509* certificate = GetX509Certificate(args); | |
| 993 X509_NAME* subject = X509_get_subject_name(certificate); | |
| 994 char* subject_string = X509_NAME_oneline(subject, NULL, 0); | |
| 995 Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_string)); | |
| 996 OPENSSL_free(subject_string); | |
| 997 } | |
| 998 | |
| 999 | |
| 1000 void FUNCTION_NAME(X509_Issuer)( | |
| 1001 Dart_NativeArguments args) { | |
| 1002 X509* certificate = GetX509Certificate(args); | |
| 1003 X509_NAME* issuer = X509_get_issuer_name(certificate); | |
| 1004 char* issuer_string = X509_NAME_oneline(issuer, NULL, 0); | |
| 1005 Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_string)); | |
| 1006 OPENSSL_free(issuer_string); | |
| 1007 } | |
| 1008 | |
| 1009 static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME* aTime) { | |
| 1010 ASN1_UTCTIME* epoch_start = M_ASN1_UTCTIME_new(); | |
| 1011 ASN1_UTCTIME_set_string(epoch_start, "700101000000Z"); | |
| 1012 int days; | |
| 1013 int seconds; | |
| 1014 int result = ASN1_TIME_diff(&days, &seconds, epoch_start, aTime); | |
| 1015 M_ASN1_UTCTIME_free(epoch_start); | |
| 1016 if (result != 1) { | |
| 1017 // TODO(whesse): Propagate an error to Dart. | |
| 1018 Log::PrintErr("ASN1Time error %d\n", result); | |
| 1019 } | |
| 1020 return Dart_NewInteger((86400LL * days + seconds) * 1000LL); | |
| 1021 } | |
| 1022 | |
| 1023 void FUNCTION_NAME(X509_StartValidity)( | |
| 1024 Dart_NativeArguments args) { | |
| 1025 X509* certificate = GetX509Certificate(args); | |
| 1026 ASN1_TIME* not_before = X509_get_notBefore(certificate); | |
| 1027 Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_before)); | |
| 1028 } | |
| 1029 | |
| 1030 | |
| 1031 void FUNCTION_NAME(X509_EndValidity)( | |
| 1032 Dart_NativeArguments args) { | |
| 1033 X509* certificate = GetX509Certificate(args); | |
| 1034 ASN1_TIME* not_after = X509_get_notAfter(certificate); | |
| 1035 Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_after)); | |
| 1036 } | |
| 1037 | |
| 1038 | |
| 1039 /** | |
| 1040 * Pushes data through the SSL filter, reading and writing from circular | |
| 1041 * buffers shared with Dart. | |
| 1042 * | |
| 1043 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to | |
| 1044 * pass encrypted and plaintext data to and from the C++ SSLFilter object. | |
| 1045 * | |
| 1046 * ProcessFilter is called with a CObject array containing the pointer to | |
| 1047 * the SSLFilter, encoded as an int, and the start and end positions of the | |
| 1048 * valid data in the four circular buffers. The function only reads from | |
| 1049 * the valid data area of the input buffers, and only writes to the free | |
| 1050 * area of the output buffers. The function returns the new start and end | |
| 1051 * positions in the buffers, but it only updates start for input buffers, and | |
| 1052 * end for output buffers. Therefore, the Dart thread can simultaneously | |
| 1053 * write to the free space and end pointer of input buffers, and read from | |
| 1054 * the data space of output buffers, and modify the start pointer. | |
| 1055 * | |
| 1056 * When ProcessFilter returns, the Dart thread is responsible for combining | |
| 1057 * the updated pointers from Dart and C++, to make the new valid state of | |
| 1058 * the circular buffer. | |
| 1059 */ | |
| 1060 CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) { | |
| 1061 CObjectIntptr filter_object(request[0]); | |
| 1062 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value()); | |
| 1063 bool in_handshake = CObjectBool(request[1]).Value(); | |
| 1064 int starts[SSLFilter::kNumBuffers]; | |
| 1065 int ends[SSLFilter::kNumBuffers]; | |
| 1066 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { | |
| 1067 starts[i] = CObjectInt32(request[2 * i + 2]).Value(); | |
| 1068 ends[i] = CObjectInt32(request[2 * i + 3]).Value(); | |
| 1069 } | |
| 1070 | |
| 1071 if (filter->ProcessAllBuffers(starts, ends, in_handshake)) { | |
| 1072 CObjectArray* result = new CObjectArray( | |
| 1073 CObject::NewArray(SSLFilter::kNumBuffers * 2)); | |
| 1074 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { | |
| 1075 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i]))); | |
| 1076 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i]))); | |
| 1077 } | |
| 1078 return result; | |
| 1079 } else { | |
| 1080 int32_t error_code = static_cast<int32_t>(ERR_peek_error()); | |
| 1081 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; | |
| 1082 FetchErrorString(error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); | |
| 1083 CObjectArray* result = new CObjectArray(CObject::NewArray(2)); | |
| 1084 result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code))); | |
| 1085 result->SetAt(1, new CObjectString(CObject::NewString(error_string))); | |
| 1086 return result; | |
| 1087 } | |
| 1088 } | |
| 1089 | |
| 1090 | |
| 1091 bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], | |
| 1092 int ends[kNumBuffers], | |
| 1093 bool in_handshake) { | |
| 1094 for (int i = 0; i < kNumBuffers; ++i) { | |
| 1095 if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue; | |
| 1096 int start = starts[i]; | |
| 1097 int end = ends[i]; | |
| 1098 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | |
| 1099 if (start < 0 || end < 0 || start >= size || end >= size) { | |
| 1100 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket"); | |
| 1101 } | |
| 1102 switch (i) { | |
| 1103 case kReadPlaintext: | |
| 1104 case kWriteEncrypted: | |
| 1105 // Write data to the circular buffer's free space. If the buffer | |
| 1106 // is full, neither if statement is executed and nothing happens. | |
| 1107 if (start <= end) { | |
| 1108 // If the free space may be split into two segments, | |
| 1109 // then the first is [end, size), unless start == 0. | |
| 1110 // Then, since the last free byte is at position start - 2, | |
| 1111 // the interval is [end, size - 1). | |
| 1112 int buffer_end = (start == 0) ? size - 1 : size; | |
| 1113 int bytes = (i == kReadPlaintext) ? | |
| 1114 ProcessReadPlaintextBuffer(end, buffer_end) : | |
| 1115 ProcessWriteEncryptedBuffer(end, buffer_end); | |
| 1116 if (bytes < 0) return false; | |
| 1117 end += bytes; | |
| 1118 ASSERT(end <= size); | |
| 1119 if (end == size) end = 0; | |
| 1120 } | |
| 1121 if (start > end + 1) { | |
| 1122 int bytes = (i == kReadPlaintext) ? | |
| 1123 ProcessReadPlaintextBuffer(end, start - 1) : | |
| 1124 ProcessWriteEncryptedBuffer(end, start - 1); | |
| 1125 if (bytes < 0) return false; | |
| 1126 end += bytes; | |
| 1127 ASSERT(end < start); | |
| 1128 } | |
| 1129 ends[i] = end; | |
| 1130 break; | |
| 1131 case kReadEncrypted: | |
| 1132 case kWritePlaintext: | |
| 1133 // Read/Write data from circular buffer. If the buffer is empty, | |
| 1134 // neither if statement's condition is true. | |
| 1135 if (end < start) { | |
| 1136 // Data may be split into two segments. In this case, | |
| 1137 // the first is [start, size). | |
| 1138 int bytes = (i == kReadEncrypted) ? | |
| 1139 ProcessReadEncryptedBuffer(start, size) : | |
| 1140 ProcessWritePlaintextBuffer(start, size); | |
| 1141 if (bytes < 0) return false; | |
| 1142 start += bytes; | |
| 1143 ASSERT(start <= size); | |
| 1144 if (start == size) start = 0; | |
| 1145 } | |
| 1146 if (start < end) { | |
| 1147 int bytes = (i == kReadEncrypted) ? | |
| 1148 ProcessReadEncryptedBuffer(start, end) : | |
| 1149 ProcessWritePlaintextBuffer(start, end); | |
| 1150 if (bytes < 0) return false; | |
| 1151 start += bytes; | |
| 1152 ASSERT(start <= end); | |
| 1153 } | |
| 1154 starts[i] = start; | |
| 1155 break; | |
| 1156 default: | |
| 1157 UNREACHABLE(); | |
| 1158 } | |
| 1159 } | |
| 1160 return true; | |
| 1161 } | |
| 1162 | |
| 1163 | |
| 1164 Dart_Handle SSLFilter::Init(Dart_Handle dart_this) { | |
| 1165 if (!library_initialized_) { | |
| 1166 InitializeLibrary(); | |
| 1167 } | |
| 1168 ASSERT(string_start_ == NULL); | |
| 1169 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); | |
| 1170 ASSERT(string_start_ != NULL); | |
| 1171 ASSERT(string_length_ == NULL); | |
| 1172 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); | |
| 1173 ASSERT(string_length_ != NULL); | |
| 1174 ASSERT(bad_certificate_callback_ == NULL); | |
| 1175 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); | |
| 1176 ASSERT(bad_certificate_callback_ != NULL); | |
| 1177 | |
| 1178 // Caller handles cleanup on an error. | |
| 1179 return InitializeBuffers(dart_this); | |
| 1180 } | |
| 1181 | |
| 1182 | |
| 1183 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) { | |
| 1184 // Create SSLFilter buffers as ExternalUint8Array objects. | |
| 1185 Dart_Handle buffers_string = DartUtils::NewString("buffers"); | |
| 1186 RETURN_IF_ERROR(buffers_string); | |
| 1187 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string); | |
| 1188 RETURN_IF_ERROR(dart_buffers_object); | |
| 1189 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this); | |
| 1190 RETURN_IF_ERROR(secure_filter_impl_type); | |
| 1191 Dart_Handle size_string = DartUtils::NewString("SIZE"); | |
| 1192 RETURN_IF_ERROR(size_string); | |
| 1193 Dart_Handle dart_buffer_size = Dart_GetField( | |
| 1194 secure_filter_impl_type, size_string); | |
| 1195 RETURN_IF_ERROR(dart_buffer_size); | |
| 1196 | |
| 1197 int64_t buffer_size = 0; | |
| 1198 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size); | |
| 1199 RETURN_IF_ERROR(err); | |
| 1200 | |
| 1201 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE"); | |
| 1202 RETURN_IF_ERROR(encrypted_size_string); | |
| 1203 | |
| 1204 Dart_Handle dart_encrypted_buffer_size = Dart_GetField( | |
| 1205 secure_filter_impl_type, encrypted_size_string); | |
| 1206 RETURN_IF_ERROR(dart_encrypted_buffer_size); | |
| 1207 | |
| 1208 int64_t encrypted_buffer_size = 0; | |
| 1209 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size); | |
| 1210 RETURN_IF_ERROR(err); | |
| 1211 | |
| 1212 if (buffer_size <= 0 || buffer_size > 1 * MB) { | |
| 1213 FATAL("Invalid buffer size in _ExternalBuffer"); | |
| 1214 } | |
| 1215 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) { | |
| 1216 FATAL("Invalid encrypted buffer size in _ExternalBuffer"); | |
| 1217 } | |
| 1218 buffer_size_ = static_cast<int>(buffer_size); | |
| 1219 encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size); | |
| 1220 | |
| 1221 Dart_Handle data_identifier = DartUtils::NewString("data"); | |
| 1222 RETURN_IF_ERROR(data_identifier); | |
| 1223 | |
| 1224 for (int i = 0; i < kNumBuffers; i++) { | |
| 1225 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | |
| 1226 buffers_[i] = new uint8_t[size]; | |
| 1227 ASSERT(buffers_[i] != NULL); | |
| 1228 dart_buffer_objects_[i] = NULL; | |
| 1229 } | |
| 1230 | |
| 1231 Dart_Handle result = Dart_Null(); | |
| 1232 for (int i = 0; i < kNumBuffers; ++i) { | |
| 1233 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; | |
| 1234 result = Dart_ListGetAt(dart_buffers_object, i); | |
| 1235 if (Dart_IsError(result)) { | |
| 1236 break; | |
| 1237 } | |
| 1238 | |
| 1239 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result); | |
| 1240 ASSERT(dart_buffer_objects_[i] != NULL); | |
| 1241 Dart_Handle data = | |
| 1242 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size); | |
| 1243 if (Dart_IsError(data)) { | |
| 1244 result = data; | |
| 1245 break; | |
| 1246 } | |
| 1247 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]); | |
| 1248 if (Dart_IsError(result)) { | |
| 1249 break; | |
| 1250 } | |
| 1251 result = Dart_SetField(result, data_identifier, data); | |
| 1252 if (Dart_IsError(result)) { | |
| 1253 break; | |
| 1254 } | |
| 1255 } | |
| 1256 | |
| 1257 // Caller handles cleanup on an error. | |
| 1258 return result; | |
| 1259 } | |
| 1260 | |
| 1261 | |
| 1262 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) { | |
| 1263 ASSERT(NULL == handshake_complete_); | |
| 1264 handshake_complete_ = Dart_NewPersistentHandle(complete); | |
| 1265 | |
| 1266 ASSERT(handshake_complete_ != NULL); | |
| 1267 } | |
| 1268 | |
| 1269 | |
| 1270 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) { | |
| 1271 ASSERT(bad_certificate_callback_ != NULL); | |
| 1272 Dart_DeletePersistentHandle(bad_certificate_callback_); | |
| 1273 bad_certificate_callback_ = Dart_NewPersistentHandle(callback); | |
| 1274 ASSERT(bad_certificate_callback_ != NULL); | |
| 1275 } | |
| 1276 | |
| 1277 | |
| 1278 void SSLFilter::InitializeLibrary() { | |
| 1279 MutexLocker locker(mutex_); | |
| 1280 if (!library_initialized_) { | |
| 1281 SSL_library_init(); | |
| 1282 filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); | |
| 1283 ASSERT(filter_ssl_index >= 0); | |
| 1284 library_initialized_ = true; | |
| 1285 } | |
| 1286 } | |
| 1287 | |
| 1288 | |
| 1289 Dart_Handle SSLFilter::PeerCertificate() { | |
| 1290 // SSL_get_peer_certificate incs the refcount of certificate. X509_free is | |
| 1291 // called by the finalizer set up by WrappedX509Certificate. | |
| 1292 X509* certificate = SSL_get_peer_certificate(ssl_); | |
| 1293 return WrappedX509Certificate(certificate); | |
| 1294 } | |
| 1295 | |
| 1296 | |
| 1297 int AlpnCallback(SSL *ssl, | |
| 1298 const uint8_t **out, | |
| 1299 uint8_t *outlen, | |
| 1300 const uint8_t *in, | |
| 1301 unsigned int inlen, | |
| 1302 void *arg) { | |
| 1303 // 'in' and 'arg' are sequences of (length, data) strings with 1-byte lengths. | |
| 1304 // 'arg' is 0-terminated. Finds the first string in 'arg' that is in 'in'. | |
| 1305 uint8_t* server_list = static_cast<uint8_t*>(arg); | |
| 1306 while (*server_list != 0) { | |
| 1307 uint8_t protocol_length = *server_list++; | |
| 1308 const uint8_t* client_list = in; | |
| 1309 while (client_list < in + inlen) { | |
| 1310 uint8_t client_protocol_length = *client_list++; | |
| 1311 if (client_protocol_length == protocol_length) { | |
| 1312 if (0 == memcmp(server_list, client_list, protocol_length)) { | |
| 1313 *out = client_list; | |
| 1314 *outlen = client_protocol_length; | |
| 1315 return SSL_TLSEXT_ERR_OK; // Success | |
| 1316 } | |
| 1317 } | |
| 1318 client_list += client_protocol_length; | |
| 1319 } | |
| 1320 server_list += protocol_length; | |
| 1321 } | |
| 1322 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN. | |
| 1323 return SSL_TLSEXT_ERR_NOACK; | |
| 1324 } | |
| 1325 | |
| 1326 | |
| 1327 // Sets the protocol list for ALPN on a SSL object or a context. | |
| 1328 static void SetAlpnProtocolList(Dart_Handle protocols_handle, | |
| 1329 SSL* ssl, | |
| 1330 SSL_CTX* context, | |
| 1331 bool is_server) { | |
| 1332 // Enable ALPN (application layer protocol negotiation) if the caller provides | |
| 1333 // a valid list of supported protocols. | |
| 1334 Dart_TypedData_Type protocols_type; | |
| 1335 uint8_t* protocol_string = NULL; | |
| 1336 uint8_t* protocol_string_copy = NULL; | |
| 1337 intptr_t protocol_string_len = 0; | |
| 1338 int status; | |
| 1339 | |
| 1340 Dart_Handle result = Dart_TypedDataAcquireData( | |
| 1341 protocols_handle, | |
| 1342 &protocols_type, | |
| 1343 reinterpret_cast<void**>(&protocol_string), | |
| 1344 &protocol_string_len); | |
| 1345 if (Dart_IsError(result)) { | |
| 1346 Dart_PropagateError(result); | |
| 1347 } | |
| 1348 | |
| 1349 if (protocols_type != Dart_TypedData_kUint8) { | |
| 1350 Dart_TypedDataReleaseData(protocols_handle); | |
| 1351 Dart_PropagateError(Dart_NewApiError( | |
| 1352 "Unexpected type for protocols (expected valid Uint8List).")); | |
| 1353 } | |
| 1354 | |
| 1355 if (protocol_string_len > 0) { | |
| 1356 if (is_server) { | |
| 1357 // ALPN on server connections must be set on an SSL_CTX object, | |
| 1358 // not on the SSL object of the individual connection. | |
| 1359 ASSERT(context != NULL); | |
| 1360 ASSERT(ssl == NULL); | |
| 1361 // Because it must be passed as a single void*, terminate | |
| 1362 // the list of (length, data) strings with a length 0 string. | |
| 1363 protocol_string_copy = | |
| 1364 static_cast<uint8_t*>(malloc(protocol_string_len + 1)); | |
| 1365 memmove(protocol_string_copy, protocol_string, protocol_string_len); | |
| 1366 protocol_string_copy[protocol_string_len] = '\0'; | |
| 1367 SSL_CTX_set_alpn_select_cb(context, AlpnCallback, protocol_string_copy); | |
| 1368 // TODO(whesse): If this function is called again, free the previous | |
| 1369 // protocol_string_copy. It may be better to keep this as a native | |
| 1370 // field on the Dart object, since fetching it from the structure is | |
| 1371 // not in the public api. | |
| 1372 // Also free protocol_string_copy when the context is destroyed, | |
| 1373 // in FreeSecurityContext() | |
| 1374 } else { | |
| 1375 // The function makes a local copy of protocol_string, which it owns. | |
| 1376 if (ssl != NULL) { | |
| 1377 ASSERT(context == NULL); | |
| 1378 status = SSL_set_alpn_protos(ssl, protocol_string, protocol_string_len); | |
| 1379 } else { | |
| 1380 ASSERT(context != NULL); | |
| 1381 ASSERT(ssl == NULL); | |
| 1382 status = SSL_CTX_set_alpn_protos( | |
| 1383 context, protocol_string, protocol_string_len); | |
| 1384 } | |
| 1385 ASSERT(status == 0); // The function returns a non-standard status. | |
| 1386 } | |
| 1387 } | |
| 1388 Dart_TypedDataReleaseData(protocols_handle); | |
| 1389 } | |
| 1390 | |
| 1391 | |
| 1392 void SSLFilter::Connect(const char* hostname, | |
| 1393 SSL_CTX* context, | |
| 1394 bool is_server, | |
| 1395 bool request_client_certificate, | |
| 1396 bool require_client_certificate, | |
| 1397 Dart_Handle protocols_handle) { | |
| 1398 is_server_ = is_server; | |
| 1399 if (in_handshake_) { | |
| 1400 FATAL("Connect called twice on the same _SecureFilter."); | |
| 1401 } | |
| 1402 | |
| 1403 int status; | |
| 1404 int error; | |
| 1405 BIO* ssl_side; | |
| 1406 status = BIO_new_bio_pair(&ssl_side, 10000, &socket_side_, 10000); | |
| 1407 CheckStatus(status, "TlsException", "BIO_new_bio_pair"); | |
| 1408 | |
| 1409 assert(context != NULL); | |
| 1410 ssl_ = SSL_new(context); | |
| 1411 SSL_set_bio(ssl_, ssl_side, ssl_side); | |
| 1412 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right? | |
| 1413 SSL_set_ex_data(ssl_, filter_ssl_index, this); | |
| 1414 | |
| 1415 if (is_server_) { | |
| 1416 int certificate_mode = | |
| 1417 request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE; | |
| 1418 if (require_client_certificate) { | |
| 1419 certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; | |
| 1420 } | |
| 1421 SSL_set_verify(ssl_, certificate_mode, NULL); | |
| 1422 } else { | |
| 1423 SetAlpnProtocolList(protocols_handle, ssl_, NULL, false); | |
| 1424 status = SSL_set_tlsext_host_name(ssl_, hostname); | |
| 1425 CheckStatus(status, "TlsException", "Set SNI host name"); | |
| 1426 // Sets the hostname in the certificate-checking object, so it is checked | |
| 1427 // against the certificate presented by the server. | |
| 1428 X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_); | |
| 1429 hostname_ = strdup(hostname); | |
| 1430 X509_VERIFY_PARAM_set_flags(certificate_checking_parameters, | |
| 1431 X509_V_FLAG_PARTIAL_CHAIN | | |
| 1432 X509_V_FLAG_TRUSTED_FIRST); | |
| 1433 X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0); | |
| 1434 status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters, | |
| 1435 hostname_, strlen(hostname_)); | |
| 1436 CheckStatus(status, "TlsException", | |
| 1437 "Set hostname for certificate checking"); | |
| 1438 } | |
| 1439 // Make the connection: | |
| 1440 if (is_server_) { | |
| 1441 status = SSL_accept(ssl_); | |
| 1442 if (SSL_LOG_STATUS) Log::Print("SSL_accept status: %d\n", status); | |
| 1443 if (status != 1) { | |
| 1444 // TODO(whesse): expect a needs-data error here. Handle other errors. | |
| 1445 error = SSL_get_error(ssl_, status); | |
| 1446 if (SSL_LOG_STATUS) Log::Print("SSL_accept error: %d\n", error); | |
| 1447 } | |
| 1448 } else { | |
| 1449 status = SSL_connect(ssl_); | |
| 1450 if (SSL_LOG_STATUS) Log::Print("SSL_connect status: %d\n", status); | |
| 1451 if (status != 1) { | |
| 1452 // TODO(whesse): expect a needs-data error here. Handle other errors. | |
| 1453 error = SSL_get_error(ssl_, status); | |
| 1454 if (SSL_LOG_STATUS) Log::Print("SSL_connect error: %d\n", error); | |
| 1455 } | |
| 1456 } | |
| 1457 Handshake(); | |
| 1458 } | |
| 1459 | |
| 1460 | |
| 1461 int printErrorCallback(const char *str, size_t len, void *ctx) { | |
| 1462 Log::PrintErr("%.*s\n", static_cast<int>(len), str); | |
| 1463 return 1; | |
| 1464 } | |
| 1465 | |
| 1466 void SSLFilter::Handshake() { | |
| 1467 // Try and push handshake along. | |
| 1468 int status; | |
| 1469 status = SSL_do_handshake(ssl_); | |
| 1470 if (callback_error != NULL) { | |
| 1471 // The SSL_do_handshake will try performing a handshake and might call | |
| 1472 // a CertificateCallback. If the certificate validation | |
| 1473 // failed the 'callback_error" will be set by the certificateCallback | |
| 1474 // logic and we propagate the error" | |
| 1475 Dart_PropagateError(callback_error); | |
| 1476 } | |
| 1477 if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) { | |
| 1478 in_handshake_ = true; | |
| 1479 return; | |
| 1480 } | |
| 1481 CheckStatus(status, | |
| 1482 "HandshakeException", | |
| 1483 is_server_ ? "Handshake error in server" : "Handshake error in client"); | |
| 1484 // Handshake succeeded. | |
| 1485 if (in_handshake_) { | |
| 1486 // TODO(24071): Check return value of SSL_get_verify_result, this | |
| 1487 // should give us the hostname check. | |
| 1488 int result = SSL_get_verify_result(ssl_); | |
| 1489 if (SSL_LOG_STATUS) { | |
| 1490 Log::Print("Handshake verification status: %d\n", result); | |
| 1491 X509* peer_certificate = SSL_get_peer_certificate(ssl_); | |
| 1492 if (peer_certificate == NULL) { | |
| 1493 Log::Print("No peer certificate received\n"); | |
| 1494 } else { | |
| 1495 X509_NAME* s_name = X509_get_subject_name(peer_certificate); | |
| 1496 printf("Peer certificate SN: "); | |
| 1497 X509_NAME_print_ex_fp(stdout, s_name, 4, 0); | |
| 1498 printf("\n"); | |
| 1499 } | |
| 1500 } | |
| 1501 ThrowIfError(Dart_InvokeClosure( | |
| 1502 Dart_HandleFromPersistent(handshake_complete_), 0, NULL)); | |
| 1503 in_handshake_ = false; | |
| 1504 } | |
| 1505 } | |
| 1506 | |
| 1507 void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) { | |
| 1508 const uint8_t* protocol; | |
| 1509 unsigned length; | |
| 1510 SSL_get0_alpn_selected(ssl_, &protocol, &length); | |
| 1511 if (length == 0) { | |
| 1512 Dart_SetReturnValue(args, Dart_Null()); | |
| 1513 } else { | |
| 1514 Dart_SetReturnValue(args, Dart_NewStringFromUTF8(protocol, length)); | |
| 1515 } | |
| 1516 } | |
| 1517 | |
| 1518 | |
| 1519 void SSLFilter::Renegotiate(bool use_session_cache, | |
| 1520 bool request_client_certificate, | |
| 1521 bool require_client_certificate) { | |
| 1522 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the | |
| 1523 // SSL_REQUEST_CERTIFICATE option is also set, so set it. | |
| 1524 request_client_certificate = | |
| 1525 request_client_certificate || require_client_certificate; | |
| 1526 // TODO(24070, 24069): Implement setting the client certificate parameters, | |
| 1527 // and triggering rehandshake. | |
| 1528 } | |
| 1529 | |
| 1530 | |
| 1531 SSLFilter::~SSLFilter() { | |
| 1532 if (ssl_ != NULL) { | |
| 1533 SSL_free(ssl_); | |
| 1534 ssl_ = NULL; | |
| 1535 } | |
| 1536 if (socket_side_ != NULL) { | |
| 1537 BIO_free(socket_side_); | |
| 1538 socket_side_ = NULL; | |
| 1539 } | |
| 1540 if (hostname_ != NULL) { | |
| 1541 free(hostname_); | |
| 1542 hostname_ = NULL; | |
| 1543 } | |
| 1544 for (int i = 0; i < kNumBuffers; ++i) { | |
| 1545 if (buffers_[i] != NULL) { | |
| 1546 delete[] buffers_[i]; | |
| 1547 buffers_[i] = NULL; | |
| 1548 } | |
| 1549 } | |
| 1550 } | |
| 1551 | |
| 1552 | |
| 1553 void SSLFilter::Destroy() { | |
| 1554 for (int i = 0; i < kNumBuffers; ++i) { | |
| 1555 if (dart_buffer_objects_[i] != NULL) { | |
| 1556 Dart_DeletePersistentHandle(dart_buffer_objects_[i]); | |
| 1557 dart_buffer_objects_[i] = NULL; | |
| 1558 } | |
| 1559 } | |
| 1560 if (string_start_ != NULL) { | |
| 1561 Dart_DeletePersistentHandle(string_start_); | |
| 1562 string_start_ = NULL; | |
| 1563 } | |
| 1564 if (string_length_ != NULL) { | |
| 1565 Dart_DeletePersistentHandle(string_length_); | |
| 1566 string_length_ = NULL; | |
| 1567 } | |
| 1568 if (handshake_complete_ != NULL) { | |
| 1569 Dart_DeletePersistentHandle(handshake_complete_); | |
| 1570 handshake_complete_ = NULL; | |
| 1571 } | |
| 1572 if (bad_certificate_callback_ != NULL) { | |
| 1573 Dart_DeletePersistentHandle(bad_certificate_callback_); | |
| 1574 bad_certificate_callback_ = NULL; | |
| 1575 } | |
| 1576 } | |
| 1577 | |
| 1578 | |
| 1579 /* Read decrypted data from the filter to the circular buffer */ | |
| 1580 int SSLFilter::ProcessReadPlaintextBuffer(int start, int end) { | |
| 1581 int length = end - start; | |
| 1582 int bytes_processed = 0; | |
| 1583 if (length > 0) { | |
| 1584 bytes_processed = SSL_read( | |
| 1585 ssl_, | |
| 1586 reinterpret_cast<char*>((buffers_[kReadPlaintext] + start)), | |
| 1587 length); | |
| 1588 if (bytes_processed < 0) { | |
| 1589 int error = SSL_get_error(ssl_, bytes_processed); | |
| 1590 USE(error); | |
| 1591 bytes_processed = 0; | |
| 1592 } | |
| 1593 } | |
| 1594 return bytes_processed; | |
| 1595 } | |
| 1596 | |
| 1597 | |
| 1598 int SSLFilter::ProcessWritePlaintextBuffer(int start, int end) { | |
| 1599 int length = end - start; | |
| 1600 int bytes_processed = SSL_write( | |
| 1601 ssl_, buffers_[kWritePlaintext] + start, length); | |
| 1602 if (bytes_processed < 0) { | |
| 1603 if (SSL_LOG_DATA) { | |
| 1604 Log::Print("SSL_write returned error %d\n", bytes_processed); | |
| 1605 } | |
| 1606 return 0; | |
| 1607 } | |
| 1608 return bytes_processed; | |
| 1609 } | |
| 1610 | |
| 1611 | |
| 1612 /* Read encrypted data from the circular buffer to the filter */ | |
| 1613 int SSLFilter::ProcessReadEncryptedBuffer(int start, int end) { | |
| 1614 int length = end - start; | |
| 1615 if (SSL_LOG_DATA) Log::Print( | |
| 1616 "Entering ProcessReadEncryptedBuffer with %d bytes\n", length); | |
| 1617 int bytes_processed = 0; | |
| 1618 if (length > 0) { | |
| 1619 bytes_processed = | |
| 1620 BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length); | |
| 1621 if (bytes_processed <= 0) { | |
| 1622 bool retry = BIO_should_retry(socket_side_); | |
| 1623 if (!retry) { | |
| 1624 if (SSL_LOG_DATA) Log::Print( | |
| 1625 "BIO_write failed in ReadEncryptedBuffer\n"); | |
| 1626 } | |
| 1627 bytes_processed = 0; | |
| 1628 } | |
| 1629 } | |
| 1630 if (SSL_LOG_DATA) Log::Print( | |
| 1631 "Leaving ProcessReadEncryptedBuffer wrote %d bytes\n", bytes_processed); | |
| 1632 return bytes_processed; | |
| 1633 } | |
| 1634 | |
| 1635 | |
| 1636 int SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) { | |
| 1637 int length = end - start; | |
| 1638 int bytes_processed = 0; | |
| 1639 if (length > 0) { | |
| 1640 bytes_processed = BIO_read(socket_side_, | |
| 1641 buffers_[kWriteEncrypted] + start, | |
| 1642 length); | |
| 1643 if (bytes_processed < 0) { | |
| 1644 if (SSL_LOG_DATA) Log::Print( | |
| 1645 "WriteEncrypted BIO_read returned error %d\n", bytes_processed); | |
| 1646 return 0; | |
| 1647 } else { | |
| 1648 if (SSL_LOG_DATA) Log::Print( | |
| 1649 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); | |
| 1650 } | |
| 1651 } | |
| 1652 return bytes_processed; | |
| 1653 } | |
| 1654 | |
| 1655 } // namespace bin | |
| 1656 } // namespace dart | |
| OLD | NEW |