| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "bin/secure_socket.h" | 5 #include "bin/secure_socket.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 #include <stdio.h> | 10 #include <stdio.h> |
| 11 #include <string.h> | 11 #include <string.h> |
| 12 | 12 |
| 13 #include <key.h> | 13 #include <openssl/bio.h> |
| 14 #include <keyt.h> | 14 #include <openssl/err.h> |
| 15 #include <nss.h> | 15 #include <openssl/safestack.h> |
| 16 #include <pk11pub.h> | 16 #include <openssl/ssl.h> |
| 17 #include <prerror.h> | 17 #include <openssl/tls1.h> |
| 18 #include <prinit.h> | 18 #include <openssl/x509.h> |
| 19 #include <prnetdb.h> | |
| 20 #include <secmod.h> | |
| 21 #include <ssl.h> | |
| 22 #include <sslproto.h> | |
| 23 | 19 |
| 24 #include "bin/builtin.h" | 20 #include "bin/builtin.h" |
| 25 #include "bin/dartutils.h" | 21 #include "bin/dartutils.h" |
| 26 #include "bin/lockers.h" | 22 #include "bin/lockers.h" |
| 27 #include "bin/net/nss_memio.h" | 23 #include "bin/log.h" |
| 28 #include "bin/socket.h" | 24 #include "bin/socket.h" |
| 29 #include "bin/thread.h" | 25 #include "bin/thread.h" |
| 30 #include "bin/utils.h" | 26 #include "bin/utils.h" |
| 31 #include "platform/utils.h" | 27 #include "platform/utils.h" |
| 32 | 28 |
| 33 #include "include/dart_api.h" | 29 #include "include/dart_api.h" |
| 34 | 30 |
| 35 | |
| 36 namespace dart { | 31 namespace dart { |
| 37 namespace bin { | 32 namespace bin { |
| 38 | 33 |
| 39 bool SSLFilter::library_initialized_ = false; | 34 bool SSLFilter::library_initialized_ = false; |
| 40 // To protect library initialization. | 35 // To protect library initialization. |
| 41 Mutex* SSLFilter::mutex_ = new Mutex(); | 36 Mutex* SSLFilter::mutex_ = new Mutex(); |
| 42 // The password is needed when creating secure server sockets. It can | 37 int SSLFilter::filter_ssl_index; |
| 43 // be null if only secure client sockets are used. | |
| 44 const char* SSLFilter::password_ = NULL; | |
| 45 | 38 |
| 46 static const int kSSLFilterNativeFieldIndex = 0; | 39 static const int kSSLFilterNativeFieldIndex = 0; |
| 40 static const int kSecurityContextNativeFieldIndex = 0; |
| 41 static const int kX509NativeFieldIndex = 0; |
| 47 | 42 |
| 43 static const bool SSL_LOG_STATUS = false; |
| 44 static const bool SSL_LOG_DATA = false; |
| 48 | 45 |
| 49 /* Handle an error reported from the NSS library. */ | 46 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 200; |
| 50 static void ThrowPRException(const char* exception_type, | 47 |
| 48 /* Handle an error reported from the BoringSSL library. */ |
| 49 static void ThrowIOException(const char* exception_type, |
| 51 const char* message, | 50 const char* message, |
| 52 bool free_message = false) { | 51 bool free_message = false) { |
| 53 PRErrorCode error_code = PR_GetError(); | 52 // TODO(24068): Get the error code and message from the error stack. |
| 54 const char* error_message = PR_ErrorToString(error_code, PR_LANGUAGE_EN); | 53 // There may be more than one error on the stack - should we |
| 55 OSError os_error_struct(error_code, error_message, OSError::kNSS); | 54 // concatenate the error messages? |
| 55 int error_code = 0; |
| 56 const char* error_message = "Unknown error from BoringSSL library"; |
| 57 OSError os_error_struct(error_code, error_message, OSError::kBoringSSL); |
| 56 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); | 58 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); |
| 57 Dart_Handle exception = | 59 Dart_Handle exception = |
| 58 DartUtils::NewDartIOException(exception_type, message, os_error); | 60 DartUtils::NewDartIOException(exception_type, message, os_error); |
| 59 if (free_message) { | 61 if (free_message) { |
| 60 free(const_cast<char*>(message)); | 62 free(const_cast<char*>(message)); |
| 61 } | 63 } |
| 62 Dart_ThrowException(exception); | 64 Dart_ThrowException(exception); |
| 63 UNREACHABLE(); | 65 UNREACHABLE(); |
| 64 } | 66 } |
| 65 | 67 |
| 66 | 68 |
| 67 static void ThrowCertificateException(const char* format, | |
| 68 const char* certificate_name) { | |
| 69 int length = strlen(certificate_name); | |
| 70 length += strlen(format); | |
| 71 char* message = reinterpret_cast<char*>(malloc(length + 1)); | |
| 72 if (message == NULL) { | |
| 73 FATAL("Out of memory formatting CertificateException for throwing"); | |
| 74 } | |
| 75 snprintf(message, length + 1, format, certificate_name); | |
| 76 message[length] = '\0'; | |
| 77 ThrowPRException("CertificateException", message, true); | |
| 78 } | |
| 79 | |
| 80 | |
| 81 static SSLFilter* GetFilter(Dart_NativeArguments args) { | 69 static SSLFilter* GetFilter(Dart_NativeArguments args) { |
| 82 SSLFilter* filter; | 70 SSLFilter* filter; |
| 83 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 71 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 84 ASSERT(Dart_IsInstance(dart_this)); | 72 ASSERT(Dart_IsInstance(dart_this)); |
| 85 ThrowIfError(Dart_GetNativeInstanceField( | 73 ThrowIfError(Dart_GetNativeInstanceField( |
| 86 dart_this, | 74 dart_this, |
| 87 kSSLFilterNativeFieldIndex, | 75 kSSLFilterNativeFieldIndex, |
| 88 reinterpret_cast<intptr_t*>(&filter))); | 76 reinterpret_cast<intptr_t*>(&filter))); |
| 89 return filter; | 77 return filter; |
| 90 } | 78 } |
| 91 | 79 |
| 92 | 80 |
| 93 static void SetFilter(Dart_NativeArguments args, SSLFilter* filter) { | 81 static void SetFilter(Dart_NativeArguments args, SSLFilter* filter) { |
| 94 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 82 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 95 ASSERT(Dart_IsInstance(dart_this)); | 83 ASSERT(Dart_IsInstance(dart_this)); |
| 96 ThrowIfError(Dart_SetNativeInstanceField( | 84 ThrowIfError(Dart_SetNativeInstanceField( |
| 97 dart_this, | 85 dart_this, |
| 98 kSSLFilterNativeFieldIndex, | 86 kSSLFilterNativeFieldIndex, |
| 99 reinterpret_cast<intptr_t>(filter))); | 87 reinterpret_cast<intptr_t>(filter))); |
| 100 } | 88 } |
| 101 | 89 |
| 102 | 90 |
| 91 static SSL_CTX* GetSecurityContext(Dart_NativeArguments args) { |
| 92 SSL_CTX* context; |
| 93 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 94 ASSERT(Dart_IsInstance(dart_this)); |
| 95 ThrowIfError(Dart_GetNativeInstanceField( |
| 96 dart_this, |
| 97 kSecurityContextNativeFieldIndex, |
| 98 reinterpret_cast<intptr_t*>(&context))); |
| 99 return context; |
| 100 } |
| 101 |
| 102 |
| 103 static void SetSecurityContext(Dart_NativeArguments args, |
| 104 SSL_CTX* context) { |
| 105 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 106 ASSERT(Dart_IsInstance(dart_this)); |
| 107 ThrowIfError(Dart_SetNativeInstanceField( |
| 108 dart_this, |
| 109 kSecurityContextNativeFieldIndex, |
| 110 reinterpret_cast<intptr_t>(context))); |
| 111 } |
| 112 |
| 113 |
| 114 static X509* GetX509Certificate(Dart_NativeArguments args) { |
| 115 X509* certificate; |
| 116 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 117 ASSERT(Dart_IsInstance(dart_this)); |
| 118 ThrowIfError(Dart_GetNativeInstanceField( |
| 119 dart_this, |
| 120 kX509NativeFieldIndex, |
| 121 reinterpret_cast<intptr_t*>(&certificate))); |
| 122 return certificate; |
| 123 } |
| 124 |
| 125 |
| 126 // Forward declaration. |
| 127 static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
| 128 SSL* ssl, |
| 129 SSL_CTX* context, |
| 130 bool is_server); |
| 131 |
| 132 |
| 103 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { | 133 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { |
| 104 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 134 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
| 105 SSLFilter* filter = new SSLFilter; | 135 SSLFilter* filter = new SSLFilter; |
| 106 SetFilter(args, filter); | 136 SetFilter(args, filter); |
| 107 filter->Init(dart_this); | 137 filter->Init(dart_this); |
| 108 } | 138 } |
| 109 | 139 |
| 110 | 140 |
| 111 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { | 141 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { |
| 112 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | 142 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 113 Dart_Handle host_sockaddr_storage_object = | 143 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| 114 ThrowIfError(Dart_GetNativeArgument(args, 2)); | 144 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); |
| 115 Dart_Handle port_object = ThrowIfError(Dart_GetNativeArgument(args, 3)); | |
| 116 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); | |
| 117 Dart_Handle certificate_name_object = | |
| 118 ThrowIfError(Dart_GetNativeArgument(args, 5)); | |
| 119 bool request_client_certificate = | 145 bool request_client_certificate = |
| 146 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); |
| 147 bool require_client_certificate = |
| 148 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); |
| 149 bool send_client_certificate = |
| 120 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 6)); | 150 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 6)); |
| 121 bool require_client_certificate = | |
| 122 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 7)); | |
| 123 bool send_client_certificate = | |
| 124 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 8)); | |
| 125 Dart_Handle protocols_handle = | 151 Dart_Handle protocols_handle = |
| 126 ThrowIfError(Dart_GetNativeArgument(args, 9)); | 152 ThrowIfError(Dart_GetNativeArgument(args, 7)); |
| 127 | 153 |
| 128 const char* host_name = NULL; | 154 const char* host_name = NULL; |
| 129 // TODO(whesse): Is truncating a Dart string containing \0 what we want? | 155 // TODO(whesse): Is truncating a Dart string containing \0 what we want? |
| 130 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); | 156 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); |
| 131 | 157 |
| 132 RawAddr raw_addr; | 158 SSL_CTX* context = NULL; |
| 133 SocketAddress::GetSockAddr(host_sockaddr_storage_object, &raw_addr); | 159 if (!Dart_IsNull(context_object)) { |
| 134 | 160 ThrowIfError(Dart_GetNativeInstanceField( |
| 135 int64_t port; | 161 context_object, |
| 136 if (!DartUtils::GetInt64Value(port_object, &port)) { | 162 kSecurityContextNativeFieldIndex, |
| 137 FATAL("The range of port_object was checked in Dart - it cannot fail here"); | 163 reinterpret_cast<intptr_t*>(&context))); |
| 138 } | 164 } |
| 139 | 165 |
| 140 const char* certificate_name = NULL; | |
| 141 if (Dart_IsString(certificate_name_object)) { | |
| 142 ThrowIfError(Dart_StringToCString(certificate_name_object, | |
| 143 &certificate_name)); | |
| 144 } | |
| 145 // If this is a server connection, it must have a certificate to connect with. | |
| 146 ASSERT(!is_server || certificate_name != NULL); | |
| 147 | |
| 148 // The protocols_handle is guaranteed to be a valid Uint8List. | 166 // The protocols_handle is guaranteed to be a valid Uint8List. |
| 149 // It will have the correct length encoding of the protocols array. | 167 // It will have the correct length encoding of the protocols array. |
| 150 ASSERT(!Dart_IsNull(protocols_handle)); | 168 ASSERT(!Dart_IsNull(protocols_handle)); |
| 151 | 169 |
| 152 GetFilter(args)->Connect(host_name, | 170 GetFilter(args)->Connect(host_name, |
| 153 raw_addr, | 171 context, |
| 154 static_cast<int>(port), | |
| 155 is_server, | 172 is_server, |
| 156 certificate_name, | |
| 157 request_client_certificate, | 173 request_client_certificate, |
| 158 require_client_certificate, | 174 require_client_certificate, |
| 159 send_client_certificate, | 175 send_client_certificate, |
| 160 protocols_handle); | 176 protocols_handle); |
| 161 } | 177 } |
| 162 | 178 |
| 163 | 179 |
| 164 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { | 180 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { |
| 165 SSLFilter* filter = GetFilter(args); | 181 SSLFilter* filter = GetFilter(args); |
| 166 SetFilter(args, NULL); | 182 SetFilter(args, NULL); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 Dart_Handle callback = | 226 Dart_Handle callback = |
| 211 ThrowIfError(Dart_GetNativeArgument(args, 1)); | 227 ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 212 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) { | 228 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) { |
| 213 Dart_ThrowException(DartUtils::NewDartArgumentError( | 229 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 214 "Illegal argument to RegisterBadCertificateCallback")); | 230 "Illegal argument to RegisterBadCertificateCallback")); |
| 215 } | 231 } |
| 216 GetFilter(args)->RegisterBadCertificateCallback(callback); | 232 GetFilter(args)->RegisterBadCertificateCallback(callback); |
| 217 } | 233 } |
| 218 | 234 |
| 219 | 235 |
| 220 void FUNCTION_NAME(SecureSocket_InitializeLibrary) | 236 void FUNCTION_NAME(SecureSocket_PeerCertificate) |
| 221 (Dart_NativeArguments args) { | 237 (Dart_NativeArguments args) { |
| 222 Dart_Handle certificate_database_object = | 238 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate()); |
| 223 ThrowIfError(Dart_GetNativeArgument(args, 0)); | 239 } |
| 224 // Check that the type is string, and get the UTF-8 C string value from it. | 240 |
| 225 const char* certificate_database = NULL; | 241 |
| 226 if (Dart_IsString(certificate_database_object)) { | 242 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { |
| 227 ThrowIfError(Dart_StringToCString(certificate_database_object, | 243 intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args)); |
| 228 &certificate_database)); | 244 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); |
| 229 } else if (!Dart_IsNull(certificate_database_object)) { | 245 } |
| 230 Dart_ThrowException(DartUtils::NewDartArgumentError( | 246 |
| 231 "Non-String certificate directory argument to SetCertificateDatabase")); | 247 |
| 232 } | 248 static Dart_Handle WrappedX509Certificate(X509* certificate) { |
| 233 // Leave certificate_database as NULL if no value was provided. | 249 if (certificate == NULL) return Dart_Null(); |
| 234 | 250 Dart_Handle x509_type = |
| 235 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | 251 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); |
| 236 // Check that the type is string or null, | 252 if (Dart_IsError(x509_type)) { |
| 237 // and get the UTF-8 C string value from it. | 253 return x509_type; |
| 254 } |
| 255 Dart_Handle arguments[] = { NULL }; |
| 256 Dart_Handle result = |
| 257 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments); |
| 258 if (Dart_IsError(result)) { |
| 259 return result; |
| 260 } |
| 261 ASSERT(Dart_IsInstance(result)); |
| 262 Dart_Handle status = Dart_SetNativeInstanceField( |
| 263 result, |
| 264 kX509NativeFieldIndex, |
| 265 reinterpret_cast<intptr_t>(certificate)); |
| 266 if (Dart_IsError(status)) { |
| 267 return status; |
| 268 } |
| 269 return result; |
| 270 } |
| 271 |
| 272 |
| 273 int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) { |
| 274 if (preverify_ok == 1) return 1; |
| 275 Dart_Isolate isolate = Dart_CurrentIsolate(); |
| 276 if (isolate == NULL) { |
| 277 FATAL("CertificateCallback called with no current isolate\n"); |
| 278 } |
| 279 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx); |
| 280 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx(); |
| 281 SSL* ssl = static_cast<SSL*>( |
| 282 X509_STORE_CTX_get_ex_data(store_ctx, ssl_index)); |
| 283 SSLFilter* filter = static_cast<SSLFilter*>( |
| 284 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index)); |
| 285 Dart_Handle callback = filter->bad_certificate_callback(); |
| 286 if (Dart_IsNull(callback)) return 0; |
| 287 Dart_Handle args[1]; |
| 288 args[0] = WrappedX509Certificate(certificate); |
| 289 if (Dart_IsError(args[0])) { |
| 290 filter->callback_error = args[0]; |
| 291 return 0; |
| 292 } |
| 293 Dart_Handle result = Dart_InvokeClosure(callback, 1, args); |
| 294 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) { |
| 295 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException( |
| 296 "HandshakeException", |
| 297 "BadCertificateCallback returned a value that was not a boolean", |
| 298 Dart_Null())); |
| 299 } |
| 300 if (Dart_IsError(result)) { |
| 301 filter->callback_error = result; |
| 302 return 0; |
| 303 } |
| 304 return DartUtils::GetBooleanValue(result); |
| 305 } |
| 306 |
| 307 |
| 308 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) { |
| 309 SSLFilter::InitializeLibrary(); |
| 310 SSL_CTX* context = SSL_CTX_new(TLS_method()); |
| 311 SSL_CTX_set_verify(context, SSL_VERIFY_PEER, CertificateCallback); |
| 312 SSL_CTX_set_min_version(context, TLS1_VERSION); |
| 313 SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM"); |
| 314 SSL_CTX_set_cipher_list_tls11(context, "HIGH:MEDIUM"); |
| 315 SetSecurityContext(args, context); |
| 316 // TODO(whesse): Use WeakPersistentHandle to free the SSL_CTX |
| 317 // when the object is GC'd. Also free the alpn_select_cb data pointer, |
| 318 // if non-null (allocated in SetAlpnProtocolList). |
| 319 } |
| 320 |
| 321 |
| 322 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) { |
| 323 char* password = static_cast<char*>(userdata); |
| 324 if (static_cast<size_t>(size) < strlen(password) + 1) { |
| 325 Log::PrintErr("Password buffer too small.\n"); |
| 326 exit(1); |
| 327 // TODO(24182): Find the actual value of size passed in here, and |
| 328 // check for password length longer than this in the Dart function |
| 329 // that passes in the password, so we never have this problem. |
| 330 } |
| 331 strncpy(buf, static_cast<char*>(userdata), size); |
| 332 return strlen(static_cast<char*>(userdata)); |
| 333 } |
| 334 |
| 335 |
| 336 void CheckStatus(int status, const char* message, int line) { |
| 337 // TODO(24183): Take appropriate action on failed calls, |
| 338 // throw exception that includes all messages from the error stack. |
| 339 if (status != 1 && SSL_LOG_STATUS) { |
| 340 int error = ERR_get_error(); |
| 341 Log::PrintErr("Failed: %s line %d\n", message, line); |
| 342 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; |
| 343 ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); |
| 344 Log::PrintErr("ERROR: %d %s\n", error, error_string); |
| 345 } |
| 346 } |
| 347 |
| 348 |
| 349 void FUNCTION_NAME(SecurityContext_UsePrivateKey)(Dart_NativeArguments args) { |
| 350 SSL_CTX* context = GetSecurityContext(args); |
| 351 Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 352 const char* filename = NULL; |
| 353 if (Dart_IsString(filename_object)) { |
| 354 ThrowIfError(Dart_StringToCString(filename_object, &filename)); |
| 355 } else { |
| 356 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 357 "File argument to SecurityContext.usePrivateKey is not a String")); |
| 358 } |
| 359 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| 238 const char* password = NULL; | 360 const char* password = NULL; |
| 239 if (Dart_IsString(password_object)) { | 361 if (Dart_IsString(password_object)) { |
| 240 ThrowIfError(Dart_StringToCString(password_object, &password)); | 362 ThrowIfError(Dart_StringToCString(password_object, &password)); |
| 241 } else if (Dart_IsNull(password_object)) { | 363 } else if (Dart_IsNull(password_object)) { |
| 242 // Pass the empty string as the password. | |
| 243 password = ""; | 364 password = ""; |
| 244 } else { | 365 } else { |
| 245 Dart_ThrowException(DartUtils::NewDartArgumentError( | 366 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 246 "Password argument to SetCertificateDatabase is not a String or null")); | 367 "Password argument to SecurityContext.usePrivateKey is not " |
| 247 } | 368 "a String or null")); |
| 248 | 369 } |
| 249 Dart_Handle builtin_roots_object = | 370 |
| 371 SSL_CTX_set_default_passwd_cb(context, PasswordCallback); |
| 372 SSL_CTX_set_default_passwd_cb_userdata(context, const_cast<char*>(password)); |
| 373 int status = SSL_CTX_use_PrivateKey_file(context, |
| 374 filename, |
| 375 SSL_FILETYPE_PEM); |
| 376 // TODO(24184): Handle different expected errors here - file missing, |
| 377 // incorrect password, file not a PEM, and throw exceptions. |
| 378 // CheckStatus should also throw an exception in uncaught cases. |
| 379 CheckStatus(status, "SSL_CTX_use_PrivateKey_file", __LINE__); |
| 380 SSL_CTX_set_default_passwd_cb_userdata(context, NULL); |
| 381 } |
| 382 |
| 383 |
| 384 void FUNCTION_NAME(SecurityContext_SetTrustedCertificates)( |
| 385 Dart_NativeArguments args) { |
| 386 SSL_CTX* context = GetSecurityContext(args); |
| 387 Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 388 const char* filename = NULL; |
| 389 if (Dart_IsString(filename_object)) { |
| 390 ThrowIfError(Dart_StringToCString(filename_object, &filename)); |
| 391 } |
| 392 Dart_Handle directory_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| 393 const char* directory = NULL; |
| 394 if (Dart_IsString(directory_object)) { |
| 395 ThrowIfError(Dart_StringToCString(directory_object, &directory)); |
| 396 } else if (Dart_IsNull(directory_object)) { |
| 397 directory = NULL; |
| 398 } else { |
| 399 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 400 "Directory argument to SecurityContext.usePrivateKey is not " |
| 401 "a String or null")); |
| 402 } |
| 403 |
| 404 int status = SSL_CTX_load_verify_locations(context, filename, directory); |
| 405 CheckStatus(status, "SSL_CTX_load_verify_locations", __LINE__); |
| 406 } |
| 407 |
| 408 |
| 409 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( |
| 410 Dart_NativeArguments args) { |
| 411 SSL_CTX* context = GetSecurityContext(args); |
| 412 X509_STORE* store = SSL_CTX_get_cert_store(context); |
| 413 BIO* roots_bio = |
| 414 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), |
| 415 root_certificates_pem_length); |
| 416 X509* root_cert; |
| 417 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, |
| 418 // backed by a memory buffer), and returns X509 objects, one by one. |
| 419 // When the end of the bio is reached, it returns null. |
| 420 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) { |
| 421 X509_STORE_add_cert(store, root_cert); |
| 422 } |
| 423 BIO_free(roots_bio); |
| 424 } |
| 425 |
| 426 |
| 427 void FUNCTION_NAME(SecurityContext_UseCertificateChain)( |
| 428 Dart_NativeArguments args) { |
| 429 SSL_CTX* context = GetSecurityContext(args); |
| 430 Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 431 const char* filename = NULL; |
| 432 if (Dart_IsString(filename_object)) { |
| 433 ThrowIfError(Dart_StringToCString(filename_object, &filename)); |
| 434 } else { |
| 435 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 436 "file argument in SecurityContext.useCertificateChain" |
| 437 " is not a String")); |
| 438 } |
| 439 int status = SSL_CTX_use_certificate_chain_file(context, filename); |
| 440 CheckStatus(status, "SSL_CTX_use_certificate_chain_file", __LINE__); |
| 441 } |
| 442 |
| 443 |
| 444 void FUNCTION_NAME(SecurityContext_SetClientAuthorities)( |
| 445 Dart_NativeArguments args) { |
| 446 SSL_CTX* context = GetSecurityContext(args); |
| 447 Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 448 const char* filename = NULL; |
| 449 if (Dart_IsString(filename_object)) { |
| 450 ThrowIfError(Dart_StringToCString(filename_object, &filename)); |
| 451 } else { |
| 452 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 453 "file argument in SecurityContext.setClientAuthorities" |
| 454 " is not a String")); |
| 455 } |
| 456 STACK_OF(X509_NAME)* certificate_names; |
| 457 certificate_names = SSL_load_client_CA_file(filename); |
| 458 if (certificate_names != NULL) { |
| 459 SSL_CTX_set_client_CA_list(context, certificate_names); |
| 460 } else { |
| 461 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 462 "Could not load certificate names from file in SetClientAuthorities")); |
| 463 } |
| 464 } |
| 465 |
| 466 |
| 467 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( |
| 468 Dart_NativeArguments args) { |
| 469 SSL_CTX* context = GetSecurityContext(args); |
| 470 Dart_Handle protocols_handle = |
| 471 ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| 472 Dart_Handle is_server_handle = |
| 250 ThrowIfError(Dart_GetNativeArgument(args, 2)); | 473 ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| 251 // Check that the type is boolean, and get the boolean value from it. | 474 if (Dart_IsBoolean(is_server_handle)) { |
| 252 bool builtin_roots = true; | 475 bool is_server = DartUtils::GetBooleanValue(is_server_handle); |
| 253 if (Dart_IsBoolean(builtin_roots_object)) { | 476 SetAlpnProtocolList(protocols_handle, NULL, context, is_server); |
| 254 ThrowIfError(Dart_BooleanValue(builtin_roots_object, &builtin_roots)); | 477 } else { |
| 255 } else { | 478 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 256 Dart_ThrowException(DartUtils::NewDartArgumentError( | 479 "Non-boolean is_server argument passed to SetAlpnProtocols")); |
| 257 "UseBuiltinRoots argument to SetCertificateDatabase is not a bool")); | 480 } |
| 258 } | 481 } |
| 259 | 482 |
| 260 SSLFilter::InitializeLibrary(certificate_database, password, builtin_roots); | 483 |
| 261 } | 484 void FUNCTION_NAME(X509_Subject)( |
| 262 | 485 Dart_NativeArguments args) { |
| 263 | 486 X509* certificate = GetX509Certificate(args); |
| 264 void FUNCTION_NAME(SecureSocket_PeerCertificate) | 487 X509_NAME* subject = X509_get_subject_name(certificate); |
| 265 (Dart_NativeArguments args) { | 488 char* subject_string = X509_NAME_oneline(subject, NULL, 0); |
| 266 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate()); | 489 Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_string)); |
| 267 } | 490 OPENSSL_free(subject_string); |
| 268 | 491 } |
| 269 | 492 |
| 270 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { | 493 |
| 271 intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args)); | 494 void FUNCTION_NAME(X509_Issuer)( |
| 272 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); | 495 Dart_NativeArguments args) { |
| 273 } | 496 X509* certificate = GetX509Certificate(args); |
| 274 | 497 X509_NAME* issuer = X509_get_issuer_name(certificate); |
| 275 | 498 char* issuer_string = X509_NAME_oneline(issuer, NULL, 0); |
| 499 Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_string)); |
| 500 OPENSSL_free(issuer_string); |
| 501 } |
| 502 |
| 503 static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME* aTime) { |
| 504 ASN1_UTCTIME* epoch_start = M_ASN1_UTCTIME_new(); |
| 505 ASN1_UTCTIME_set_string(epoch_start, "700101000000Z"); |
| 506 int days; |
| 507 int seconds; |
| 508 int result = ASN1_TIME_diff(&days, &seconds, epoch_start, aTime); |
| 509 M_ASN1_UTCTIME_free(epoch_start); |
| 510 if (result != 1) { |
| 511 // TODO(whesse): Propagate an error to Dart. |
| 512 Log::PrintErr("ASN1Time error %d\n", result); |
| 513 } |
| 514 return Dart_NewInteger((86400LL * days + seconds) * 1000LL); |
| 515 } |
| 516 |
| 517 void FUNCTION_NAME(X509_StartValidity)( |
| 518 Dart_NativeArguments args) { |
| 519 X509* certificate = GetX509Certificate(args); |
| 520 ASN1_TIME* not_before = X509_get_notBefore(certificate); |
| 521 Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_before)); |
| 522 } |
| 523 |
| 524 |
| 525 void FUNCTION_NAME(X509_EndValidity)( |
| 526 Dart_NativeArguments args) { |
| 527 X509* certificate = GetX509Certificate(args); |
| 528 ASN1_TIME* not_after = X509_get_notAfter(certificate); |
| 529 Dart_SetReturnValue(args, ASN1TimeToMilliseconds(not_after)); |
| 530 } |
| 531 |
| 532 |
| 276 /** | 533 /** |
| 277 * Pushes data through the SSL filter, reading and writing from circular | 534 * Pushes data through the SSL filter, reading and writing from circular |
| 278 * buffers shared with Dart. | 535 * buffers shared with Dart. |
| 279 * | 536 * |
| 280 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to | 537 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to |
| 281 * pass encrypted and plaintext data to and from the C++ SSLFilter object. | 538 * pass encrypted and plaintext data to and from the C++ SSLFilter object. |
| 282 * | 539 * |
| 283 * ProcessFilter is called with a CObject array containing the pointer to | 540 * ProcessFilter is called with a CObject array containing the pointer to |
| 284 * the SSLFilter, encoded as an int, and the start and end positions of the | 541 * the SSLFilter, encoded as an int, and the start and end positions of the |
| 285 * valid data in the four circular buffers. The function only reads from | 542 * valid data in the four circular buffers. The function only reads from |
| (...skipping 21 matching lines...) Expand all Loading... |
| 307 | 564 |
| 308 if (filter->ProcessAllBuffers(starts, ends, in_handshake)) { | 565 if (filter->ProcessAllBuffers(starts, ends, in_handshake)) { |
| 309 CObjectArray* result = new CObjectArray( | 566 CObjectArray* result = new CObjectArray( |
| 310 CObject::NewArray(SSLFilter::kNumBuffers * 2)); | 567 CObject::NewArray(SSLFilter::kNumBuffers * 2)); |
| 311 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { | 568 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { |
| 312 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i]))); | 569 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i]))); |
| 313 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i]))); | 570 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i]))); |
| 314 } | 571 } |
| 315 return result; | 572 return result; |
| 316 } else { | 573 } else { |
| 317 PRErrorCode error_code = PR_GetError(); | 574 // TODO(24185): Extract the BoringSSL OS error here and return it. |
| 318 const char* error_message = PR_ErrorToString(error_code, PR_LANGUAGE_EN); | 575 int error_code = 1; |
| 576 const char* error_message = "Obsolete PR Error message"; |
| 319 CObjectArray* result = new CObjectArray(CObject::NewArray(2)); | 577 CObjectArray* result = new CObjectArray(CObject::NewArray(2)); |
| 320 result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code))); | 578 result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code))); |
| 321 result->SetAt(1, new CObjectString(CObject::NewString(error_message))); | 579 result->SetAt(1, new CObjectString(CObject::NewString(error_message))); |
| 322 return result; | 580 return result; |
| 323 } | 581 } |
| 324 } | 582 } |
| 325 | 583 |
| 326 | 584 |
| 327 bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], | 585 bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], |
| 328 int ends[kNumBuffers], | 586 int ends[kNumBuffers], |
| (...skipping 29 matching lines...) Expand all Loading... |
| 358 int bytes = (i == kReadPlaintext) ? | 616 int bytes = (i == kReadPlaintext) ? |
| 359 ProcessReadPlaintextBuffer(end, start - 1) : | 617 ProcessReadPlaintextBuffer(end, start - 1) : |
| 360 ProcessWriteEncryptedBuffer(end, start - 1); | 618 ProcessWriteEncryptedBuffer(end, start - 1); |
| 361 if (bytes < 0) return false; | 619 if (bytes < 0) return false; |
| 362 end += bytes; | 620 end += bytes; |
| 363 ASSERT(end < start); | 621 ASSERT(end < start); |
| 364 } | 622 } |
| 365 ends[i] = end; | 623 ends[i] = end; |
| 366 break; | 624 break; |
| 367 case kReadEncrypted: | 625 case kReadEncrypted: |
| 368 // Read data from circular buffer. | 626 case kWritePlaintext: |
| 627 // Read/Write data from circular buffer. If the buffer is empty, |
| 628 // neither if statement's condition is true. |
| 369 if (end < start) { | 629 if (end < start) { |
| 370 // Data may be split into two segments. In this case, | 630 // Data may be split into two segments. In this case, |
| 371 // the first is [start, size). | 631 // the first is [start, size). |
| 372 int bytes = ProcessReadEncryptedBuffer(start, size); | 632 int bytes = (i == kReadEncrypted) ? |
| 633 ProcessReadEncryptedBuffer(start, size) : |
| 634 ProcessWritePlaintextBuffer(start, size); |
| 373 if (bytes < 0) return false; | 635 if (bytes < 0) return false; |
| 374 start += bytes; | 636 start += bytes; |
| 375 ASSERT(start <= size); | 637 ASSERT(start <= size); |
| 376 if (start == size) start = 0; | 638 if (start == size) start = 0; |
| 377 } | 639 } |
| 378 if (start < end) { | 640 if (start < end) { |
| 379 int bytes = ProcessReadEncryptedBuffer(start, end); | 641 int bytes = (i == kReadEncrypted) ? |
| 642 ProcessReadEncryptedBuffer(start, end) : |
| 643 ProcessWritePlaintextBuffer(start, end); |
| 380 if (bytes < 0) return false; | 644 if (bytes < 0) return false; |
| 381 start += bytes; | 645 start += bytes; |
| 382 ASSERT(start <= end); | 646 ASSERT(start <= end); |
| 383 } | |
| 384 starts[i] = start; | |
| 385 break; | |
| 386 case kWritePlaintext: | |
| 387 if (end < start) { | |
| 388 // Data is split into two segments, [start, size) and [0, end). | |
| 389 int bytes = ProcessWritePlaintextBuffer(start, size, 0, end); | |
| 390 if (bytes < 0) return false; | |
| 391 start += bytes; | |
| 392 if (start >= size) start -= size; | |
| 393 } else { | |
| 394 int bytes = ProcessWritePlaintextBuffer(start, end, 0, 0); | |
| 395 if (bytes < 0) return false; | |
| 396 start += bytes; | |
| 397 ASSERT(start <= end); | |
| 398 } | 647 } |
| 399 starts[i] = start; | 648 starts[i] = start; |
| 400 break; | 649 break; |
| 401 default: | 650 default: |
| 402 UNREACHABLE(); | 651 UNREACHABLE(); |
| 403 } | 652 } |
| 404 } | 653 } |
| 405 return true; | 654 return true; |
| 406 } | 655 } |
| 407 | 656 |
| 408 | 657 |
| 409 static Dart_Handle X509FromCertificate(CERTCertificate* certificate) { | |
| 410 PRTime start_validity; | |
| 411 PRTime end_validity; | |
| 412 SECStatus status = | |
| 413 CERT_GetCertTimes(certificate, &start_validity, &end_validity); | |
| 414 if (status != SECSuccess) { | |
| 415 ThrowPRException("CertificateException", | |
| 416 "Cannot get validity times from certificate"); | |
| 417 } | |
| 418 int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC; | |
| 419 int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC; | |
| 420 Dart_Handle subject_name_object = | |
| 421 DartUtils::NewString(certificate->subjectName); | |
| 422 Dart_Handle issuer_name_object = | |
| 423 DartUtils::NewString(certificate->issuerName); | |
| 424 Dart_Handle start_epoch_ms_int = Dart_NewInteger(start_epoch_ms); | |
| 425 Dart_Handle end_epoch_ms_int = Dart_NewInteger(end_epoch_ms); | |
| 426 | |
| 427 Dart_Handle date_type = | |
| 428 DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime"); | |
| 429 Dart_Handle from_milliseconds = | |
| 430 DartUtils::NewString("fromMillisecondsSinceEpoch"); | |
| 431 | |
| 432 Dart_Handle start_validity_date = | |
| 433 Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int); | |
| 434 Dart_Handle end_validity_date = | |
| 435 Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int); | |
| 436 | |
| 437 Dart_Handle x509_type = | |
| 438 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); | |
| 439 Dart_Handle arguments[] = { subject_name_object, | |
| 440 issuer_name_object, | |
| 441 start_validity_date, | |
| 442 end_validity_date }; | |
| 443 return Dart_New(x509_type, Dart_Null(), 4, arguments); | |
| 444 } | |
| 445 | |
| 446 | |
| 447 void SSLFilter::Init(Dart_Handle dart_this) { | 658 void SSLFilter::Init(Dart_Handle dart_this) { |
| 448 if (!library_initialized_) { | 659 if (!library_initialized_) { |
| 449 InitializeLibrary(NULL, "", true, false); | 660 InitializeLibrary(); |
| 450 } | 661 } |
| 451 ASSERT(string_start_ == NULL); | 662 ASSERT(string_start_ == NULL); |
| 452 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); | 663 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); |
| 453 ASSERT(string_start_ != NULL); | 664 ASSERT(string_start_ != NULL); |
| 454 ASSERT(string_length_ == NULL); | 665 ASSERT(string_length_ == NULL); |
| 455 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); | 666 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); |
| 456 ASSERT(string_length_ != NULL); | 667 ASSERT(string_length_ != NULL); |
| 457 ASSERT(bad_certificate_callback_ == NULL); | 668 ASSERT(bad_certificate_callback_ == NULL); |
| 458 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); | 669 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); |
| 459 ASSERT(bad_certificate_callback_ != NULL); | 670 ASSERT(bad_certificate_callback_ != NULL); |
| 460 | 671 |
| 461 InitializeBuffers(dart_this); | 672 InitializeBuffers(dart_this); |
| 462 filter_ = memio_CreateIOLayer(kMemioBufferSize, kMemioBufferSize); | |
| 463 } | 673 } |
| 464 | 674 |
| 465 | 675 |
| 466 void SSLFilter::InitializeBuffers(Dart_Handle dart_this) { | 676 void SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
| 467 // Create SSLFilter buffers as ExternalUint8Array objects. | 677 // Create SSLFilter buffers as ExternalUint8Array objects. |
| 468 Dart_Handle dart_buffers_object = ThrowIfError( | 678 Dart_Handle dart_buffers_object = ThrowIfError( |
| 469 Dart_GetField(dart_this, DartUtils::NewString("buffers"))); | 679 Dart_GetField(dart_this, DartUtils::NewString("buffers"))); |
| 470 Dart_Handle secure_filter_impl_type = | 680 Dart_Handle secure_filter_impl_type = |
| 471 Dart_InstanceGetType(dart_this); | 681 Dart_InstanceGetType(dart_this); |
| 472 Dart_Handle dart_buffer_size = ThrowIfError( | 682 Dart_Handle dart_buffer_size = ThrowIfError( |
| (...skipping 27 matching lines...) Expand all Loading... |
| 500 Dart_SetField(Dart_HandleFromPersistent(dart_buffer_objects_[i]), | 710 Dart_SetField(Dart_HandleFromPersistent(dart_buffer_objects_[i]), |
| 501 data_identifier, | 711 data_identifier, |
| 502 data)); | 712 data)); |
| 503 } | 713 } |
| 504 } | 714 } |
| 505 | 715 |
| 506 | 716 |
| 507 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) { | 717 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) { |
| 508 ASSERT(NULL == handshake_complete_); | 718 ASSERT(NULL == handshake_complete_); |
| 509 handshake_complete_ = Dart_NewPersistentHandle(complete); | 719 handshake_complete_ = Dart_NewPersistentHandle(complete); |
| 720 |
| 510 ASSERT(handshake_complete_ != NULL); | 721 ASSERT(handshake_complete_ != NULL); |
| 511 } | 722 } |
| 512 | 723 |
| 513 | 724 |
| 514 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) { | 725 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) { |
| 515 ASSERT(bad_certificate_callback_ != NULL); | 726 ASSERT(bad_certificate_callback_ != NULL); |
| 516 Dart_DeletePersistentHandle(bad_certificate_callback_); | 727 Dart_DeletePersistentHandle(bad_certificate_callback_); |
| 517 bad_certificate_callback_ = Dart_NewPersistentHandle(callback); | 728 bad_certificate_callback_ = Dart_NewPersistentHandle(callback); |
| 518 ASSERT(bad_certificate_callback_ != NULL); | 729 ASSERT(bad_certificate_callback_ != NULL); |
| 519 } | 730 } |
| 520 | 731 |
| 521 | 732 |
| 522 char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) { | 733 void SSLFilter::InitializeLibrary() { |
| 523 if (!retry) { | |
| 524 return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals. | |
| 525 } | |
| 526 return NULL; | |
| 527 } | |
| 528 | |
| 529 | |
| 530 static const char* builtin_roots_module = | |
| 531 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) | |
| 532 "name=\"Root Certs\" library=\"libnssckbi.so\""; | |
| 533 #elif defined(TARGET_OS_MACOS) | |
| 534 "name=\"Root Certs\" library=\"libnssckbi.dylib\""; | |
| 535 #elif defined(TARGET_OS_WINDOWS) | |
| 536 "name=\"Root Certs\" library=\"nssckbi.dll\""; | |
| 537 #else | |
| 538 #error Automatic target os detection failed. | |
| 539 #endif | |
| 540 | |
| 541 | |
| 542 | |
| 543 void SSLFilter::InitializeLibrary(const char* certificate_database, | |
| 544 const char* password, | |
| 545 bool use_builtin_root_certificates, | |
| 546 bool report_duplicate_initialization) { | |
| 547 MutexLocker locker(mutex_); | 734 MutexLocker locker(mutex_); |
| 548 SECStatus status; | |
| 549 if (!library_initialized_) { | 735 if (!library_initialized_) { |
| 550 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); | 736 SSL_library_init(); |
| 551 // TODO(whesse): Verify there are no UTF-8 issues here. | 737 filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); |
| 552 if (certificate_database == NULL || certificate_database[0] == '\0') { | 738 ASSERT(filter_ssl_index >= 0); |
| 553 status = NSS_NoDB_Init(NULL); | |
| 554 if (status != SECSuccess) { | |
| 555 mutex_->Unlock(); // MutexLocker destructor not called when throwing. | |
| 556 ThrowPRException("TlsException", | |
| 557 "Failed NSS_NoDB_Init call."); | |
| 558 } | |
| 559 if (use_builtin_root_certificates) { | |
| 560 SECMODModule* module = SECMOD_LoadUserModule( | |
| 561 const_cast<char*>(builtin_roots_module), NULL, PR_FALSE); | |
| 562 if (!module) { | |
| 563 mutex_->Unlock(); // MutexLocker destructor not called when throwing. | |
| 564 ThrowPRException("TlsException", | |
| 565 "Failed to load builtin root certificates."); | |
| 566 } | |
| 567 } | |
| 568 } else { | |
| 569 PRUint32 init_flags = NSS_INIT_READONLY; | |
| 570 if (!use_builtin_root_certificates) { | |
| 571 init_flags |= NSS_INIT_NOMODDB; | |
| 572 } | |
| 573 status = NSS_Initialize(certificate_database, | |
| 574 "", | |
| 575 "", | |
| 576 SECMOD_DB, | |
| 577 init_flags); | |
| 578 if (status != SECSuccess) { | |
| 579 mutex_->Unlock(); // MutexLocker destructor not called when throwing. | |
| 580 ThrowPRException("TlsException", | |
| 581 "Failed NSS_Init call."); | |
| 582 } | |
| 583 password_ = strdup(password); // This one copy persists until Dart exits. | |
| 584 PK11_SetPasswordFunc(PasswordCallback); | |
| 585 } | |
| 586 library_initialized_ = true; | 739 library_initialized_ = true; |
| 587 | |
| 588 status = NSS_SetDomesticPolicy(); | |
| 589 if (status != SECSuccess) { | |
| 590 mutex_->Unlock(); // MutexLocker destructor not called when throwing. | |
| 591 ThrowPRException("TlsException", | |
| 592 "Failed NSS_SetDomesticPolicy call."); | |
| 593 } | |
| 594 | |
| 595 // Enable the same additional ciphers that Chromium does. | |
| 596 // See NSSSSLInitSingleton() in Chromium's net/socket/nss_ssl_util.cc. | |
| 597 // Explicitly enable exactly those ciphers with keys of at least 80 bits. | |
| 598 const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers(); | |
| 599 const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers(); | |
| 600 for (int i = 0; i < num_ciphers; i++) { | |
| 601 SSLCipherSuiteInfo info; | |
| 602 if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) == | |
| 603 SECSuccess) { | |
| 604 bool enabled = (info.effectiveKeyBits >= 80); | |
| 605 // Trim the list of cipher suites in order to keep the size of the | |
| 606 // ClientHello down. DSS, ECDH, CAMELLIA, SEED, ECC+3DES, and | |
| 607 // HMAC-SHA256 cipher suites are disabled. | |
| 608 if (info.symCipher == ssl_calg_camellia || | |
| 609 info.symCipher == ssl_calg_seed || | |
| 610 (info.symCipher == ssl_calg_3des && info.keaType != ssl_kea_rsa) || | |
| 611 info.authAlgorithm == ssl_auth_dsa || | |
| 612 info.macAlgorithm == ssl_hmac_sha256 || | |
| 613 info.nonStandard || | |
| 614 strcmp(info.keaTypeName, "ECDH") == 0) { | |
| 615 enabled = false; | |
| 616 } | |
| 617 | |
| 618 if (ssl_ciphers[i] == TLS_DHE_DSS_WITH_AES_128_CBC_SHA) { | |
| 619 // Enabled to allow servers with only a DSA certificate to function. | |
| 620 enabled = true; | |
| 621 } | |
| 622 SSL_CipherPrefSetDefault(ssl_ciphers[i], enabled); | |
| 623 } | |
| 624 } | |
| 625 | |
| 626 status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL); | |
| 627 if (status != SECSuccess) { | |
| 628 mutex_->Unlock(); // MutexLocker destructor not called when throwing. | |
| 629 ThrowPRException("TlsException", | |
| 630 "Failed SSL_ConfigServerSessionIDCache call."); | |
| 631 } | |
| 632 | |
| 633 } else if (report_duplicate_initialization) { | |
| 634 mutex_->Unlock(); // MutexLocker destructor not called when throwing. | |
| 635 // Like ThrowPRException, without adding an OSError. | |
| 636 Dart_ThrowException(DartUtils::NewDartIOException("TlsException", | |
| 637 "Called SecureSocket.initialize more than once", | |
| 638 Dart_Null())); | |
| 639 } | 740 } |
| 640 } | 741 } |
| 641 | 742 |
| 642 | 743 |
| 643 SECStatus BadCertificateCallback(void* filter, PRFileDesc* fd) { | 744 Dart_Handle SSLFilter::PeerCertificate() { |
| 644 SSLFilter* ssl_filter = static_cast<SSLFilter*>(filter); | 745 X509* certificate = SSL_get_peer_certificate(ssl_); |
| 645 Dart_Handle callback = ssl_filter->bad_certificate_callback(); | 746 Dart_Handle x509_object = WrappedX509Certificate(certificate); |
| 646 if (Dart_IsNull(callback)) return SECFailure; | 747 if (Dart_IsError(x509_object)) { |
| 647 Dart_Handle x509_object = ssl_filter->PeerCertificate(); | 748 Dart_PropagateError(x509_object); |
| 648 Dart_Handle result = Dart_InvokeClosure(callback, 1, &x509_object); | |
| 649 if (Dart_IsError(result)) { | |
| 650 ssl_filter->callback_error = result; | |
| 651 return SECFailure; | |
| 652 } | 749 } |
| 653 // Our wrapper is guaranteed to return a boolean. | |
| 654 bool c_result = DartUtils::GetBooleanValue(result); | |
| 655 return c_result ? SECSuccess : SECFailure; | |
| 656 } | |
| 657 | |
| 658 | |
| 659 Dart_Handle SSLFilter::PeerCertificate() { | |
| 660 CERTCertificate* certificate = SSL_PeerCertificate(filter_); | |
| 661 if (certificate == NULL) return Dart_Null(); | |
| 662 Dart_Handle x509_object = X509FromCertificate(certificate); | |
| 663 CERT_DestroyCertificate(certificate); | |
| 664 return x509_object; | 750 return x509_object; |
| 665 } | 751 } |
| 666 | 752 |
| 667 | 753 |
| 668 void SSLFilter::Connect(const char* host_name, | 754 int AlpnCallback(SSL *ssl, |
| 669 const RawAddr& raw_addr, | 755 const uint8_t **out, |
| 670 int port, | 756 uint8_t *outlen, |
| 757 const uint8_t *in, |
| 758 unsigned int inlen, |
| 759 void *arg) { |
| 760 // 'in' and 'arg' are sequences of (length, data) strings with 1-byte lengths. |
| 761 // 'arg' is 0-terminated. Finds the first string in 'arg' that is in 'in'. |
| 762 uint8_t* server_list = static_cast<uint8_t*>(arg); |
| 763 while (*server_list != 0) { |
| 764 uint8_t protocol_length = *server_list++; |
| 765 const uint8_t* client_list = in; |
| 766 while (client_list < in + inlen) { |
| 767 uint8_t client_protocol_length = *client_list++; |
| 768 if (client_protocol_length == protocol_length) { |
| 769 if (0 == memcmp(server_list, client_list, protocol_length)) { |
| 770 *out = client_list; |
| 771 *outlen = client_protocol_length; |
| 772 return SSL_TLSEXT_ERR_OK; // Success |
| 773 } |
| 774 } |
| 775 client_list += client_protocol_length; |
| 776 } |
| 777 server_list += protocol_length; |
| 778 } |
| 779 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN. |
| 780 return SSL_TLSEXT_ERR_NOACK; |
| 781 } |
| 782 |
| 783 |
| 784 // Sets the protocol list for ALPN on a SSL object or a context. |
| 785 static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
| 786 SSL* ssl, |
| 787 SSL_CTX* context, |
| 788 bool is_server) { |
| 789 // Enable ALPN (application layer protocol negotiation) if the caller provides |
| 790 // a valid list of supported protocols. |
| 791 Dart_TypedData_Type protocols_type; |
| 792 uint8_t* protocol_string = NULL; |
| 793 uint8_t* protocol_string_copy = NULL; |
| 794 intptr_t protocol_string_len = 0; |
| 795 int status; |
| 796 |
| 797 Dart_Handle result = Dart_TypedDataAcquireData( |
| 798 protocols_handle, |
| 799 &protocols_type, |
| 800 reinterpret_cast<void**>(&protocol_string), |
| 801 &protocol_string_len); |
| 802 if (Dart_IsError(result)) { |
| 803 Dart_PropagateError(result); |
| 804 } |
| 805 |
| 806 if (protocols_type != Dart_TypedData_kUint8) { |
| 807 Dart_TypedDataReleaseData(protocols_handle); |
| 808 Dart_PropagateError(Dart_NewApiError( |
| 809 "Unexpected type for protocols (expected valid Uint8List).")); |
| 810 } |
| 811 |
| 812 if (protocol_string_len > 0) { |
| 813 if (is_server) { |
| 814 // ALPN on server connections must be set on an SSL_CTX object, |
| 815 // not on the SSL object of the individual connection. |
| 816 ASSERT(context != NULL); |
| 817 ASSERT(ssl == NULL); |
| 818 // Because it must be passed as a single void*, terminate |
| 819 // the list of (length, data) strings with a length 0 string. |
| 820 protocol_string_copy = |
| 821 static_cast<uint8_t*>(malloc(protocol_string_len + 1)); |
| 822 memmove(protocol_string_copy, protocol_string, protocol_string_len); |
| 823 protocol_string_copy[protocol_string_len] = '\0'; |
| 824 SSL_CTX_set_alpn_select_cb(context, AlpnCallback, protocol_string_copy); |
| 825 // TODO(whesse): If this function is called again, free the previous |
| 826 // protocol_string_copy. It may be better to keep this as a native |
| 827 // field on the Dart object, since fetching it from the structure is |
| 828 // not in the public api. Also free this when the context is destroyed. |
| 829 } else { |
| 830 // The function makes a local copy of protocol_string, which it owns. |
| 831 if (ssl != NULL) { |
| 832 ASSERT(context == NULL); |
| 833 status = SSL_set_alpn_protos(ssl, protocol_string, protocol_string_len); |
| 834 } else { |
| 835 ASSERT(context != NULL); |
| 836 ASSERT(ssl == NULL); |
| 837 status = SSL_CTX_set_alpn_protos( |
| 838 context, protocol_string, protocol_string_len); |
| 839 } |
| 840 ASSERT(status == 0); // The function returns a non-standard status. |
| 841 } |
| 842 } |
| 843 Dart_TypedDataReleaseData(protocols_handle); |
| 844 } |
| 845 |
| 846 |
| 847 void SSLFilter::Connect(const char* hostname, |
| 848 SSL_CTX* context, |
| 671 bool is_server, | 849 bool is_server, |
| 672 const char* certificate_name, | |
| 673 bool request_client_certificate, | 850 bool request_client_certificate, |
| 674 bool require_client_certificate, | 851 bool require_client_certificate, |
| 675 bool send_client_certificate, | 852 bool send_client_certificate, |
| 676 Dart_Handle protocols_handle) { | 853 Dart_Handle protocols_handle) { |
| 677 is_server_ = is_server; | 854 is_server_ = is_server; |
| 678 if (in_handshake_) { | 855 if (in_handshake_) { |
| 679 FATAL("Connect called twice on the same _SecureFilter."); | 856 FATAL("Connect called twice on the same _SecureFilter."); |
| 680 } | 857 } |
| 681 | 858 |
| 682 if (!is_server && certificate_name != NULL) { | 859 int status; |
| 683 client_certificate_name_ = strdup(certificate_name); | 860 int error; |
| 861 BIO* ssl_side; |
| 862 status = BIO_new_bio_pair(&ssl_side, 10000, &socket_side_, 10000); |
| 863 CheckStatus(status, "BIO_new_bio_pair", __LINE__); |
| 864 |
| 865 if (context == NULL) { |
| 866 DART_CHECK_VALID(Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 867 "Default SecurityContext not implemented, context cannot be null."))); |
| 684 } | 868 } |
| 685 | 869 |
| 686 filter_ = SSL_ImportFD(NULL, filter_); | 870 ssl_ = SSL_new(context); |
| 687 if (filter_ == NULL) { | 871 SSL_set_bio(ssl_, ssl_side, ssl_side); |
| 688 ThrowPRException("TlsException", "Failed SSL_ImportFD call"); | 872 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right? |
| 873 SSL_set_ex_data(ssl_, filter_ssl_index, this); |
| 874 |
| 875 if (!is_server_) { |
| 876 SetAlpnProtocolList(protocols_handle, ssl_, NULL, false); |
| 877 // Sets the hostname in the certificate-checking object, so it is checked |
| 878 // against the certificate presented by the server. |
| 879 X509_VERIFY_PARAM* certificate_checking_parameters_ = SSL_get0_param(ssl_); |
| 880 hostname_ = strdup(hostname); |
| 881 X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters_, 0); |
| 882 X509_VERIFY_PARAM_set1_host(certificate_checking_parameters_, |
| 883 hostname_, 0); |
| 884 // TODO(24186) free hostname_ if it is not freed when SSL is destroyed. |
| 885 // otherwise, make it a local variable, not a instance field. |
| 689 } | 886 } |
| 690 | 887 if (is_server_) { |
| 691 | 888 status = SSL_accept(ssl_); |
| 692 SECStatus status; | 889 if (SSL_LOG_STATUS) Log::Print("SSL_accept status: %d\n", status); |
| 693 | 890 if (status != 1) { |
| 694 // Enable ALPN (application layer protocol negogiation) if the caller provides | 891 // TODO(whesse): expect a needs-data error here. Handle other errors. |
| 695 // a valid list of supported protocols. | 892 error = SSL_get_error(ssl_, status); |
| 696 { | 893 if (SSL_LOG_STATUS) Log::Print("SSL_accept error: %d\n", error); |
| 697 Dart_TypedData_Type protocols_type; | |
| 698 uint8_t* protocol_string = NULL; | |
| 699 intptr_t protocol_string_len = 0; | |
| 700 | |
| 701 Dart_Handle result = Dart_TypedDataAcquireData( | |
| 702 protocols_handle, | |
| 703 &protocols_type, | |
| 704 reinterpret_cast<void**>(&protocol_string), | |
| 705 &protocol_string_len); | |
| 706 if (Dart_IsError(result)) { | |
| 707 Dart_PropagateError(result); | |
| 708 } | 894 } |
| 709 | 895 } else { |
| 710 if (protocols_type != Dart_TypedData_kUint8) { | 896 status = SSL_connect(ssl_); |
| 711 Dart_TypedDataReleaseData(protocols_handle); | 897 if (SSL_LOG_STATUS) Log::Print("SSL_connect status: %d\n", status); |
| 712 Dart_PropagateError(Dart_NewApiError( | 898 if (status != 1) { |
| 713 "Unexpected type for protocols (expected valid Uint8List).")); | 899 // TODO(whesse): expect a needs-data error here. Handle other errors. |
| 900 error = SSL_get_error(ssl_, status); |
| 901 if (SSL_LOG_STATUS) Log::Print("SSL_connect error: %d\n", error); |
| 714 } | 902 } |
| 715 | |
| 716 if (protocol_string_len > 0) { | |
| 717 status = SSL_OptionSet(filter_, SSL_ENABLE_ALPN, PR_TRUE); | |
| 718 ASSERT(status == SECSuccess); | |
| 719 | |
| 720 status = SSL_SetNextProtoNego(filter_, | |
| 721 protocol_string, | |
| 722 protocol_string_len); | |
| 723 ASSERT(status == SECSuccess); | |
| 724 } | |
| 725 | |
| 726 Dart_TypedDataReleaseData(protocols_handle); | |
| 727 } | 903 } |
| 728 | 904 if (is_server_) { |
| 729 SSLVersionRange vrange; | |
| 730 vrange.min = SSL_LIBRARY_VERSION_3_0; | |
| 731 vrange.max = SSL_LIBRARY_VERSION_TLS_1_2; | |
| 732 SSL_VersionRangeSet(filter_, &vrange); | |
| 733 | |
| 734 if (is_server) { | |
| 735 CERTCertificate* certificate = NULL; | |
| 736 if (strstr(certificate_name, "CN=") != NULL) { | |
| 737 // Look up certificate using the distinguished name (DN) certificate_name. | |
| 738 CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB(); | |
| 739 if (certificate_database == NULL) { | |
| 740 ThrowPRException("CertificateException", | |
| 741 "Certificate database cannot be loaded"); | |
| 742 } | |
| 743 certificate = CERT_FindCertByNameString(certificate_database, | |
| 744 const_cast<char*>(certificate_name)); | |
| 745 if (certificate == NULL) { | |
| 746 ThrowCertificateException( | |
| 747 "Cannot find server certificate by distinguished name: %s", | |
| 748 certificate_name); | |
| 749 } | |
| 750 } else { | |
| 751 // Look up certificate using the nickname certificate_name. | |
| 752 certificate = PK11_FindCertFromNickname( | |
| 753 const_cast<char*>(certificate_name), | |
| 754 static_cast<void*>(const_cast<char*>(password_))); | |
| 755 if (certificate == NULL) { | |
| 756 ThrowCertificateException( | |
| 757 "Cannot find server certificate by nickname: %s", | |
| 758 certificate_name); | |
| 759 } | |
| 760 } | |
| 761 SECKEYPrivateKey* key = PK11_FindKeyByAnyCert( | |
| 762 certificate, | |
| 763 static_cast<void*>(const_cast<char*>(password_))); | |
| 764 if (key == NULL) { | |
| 765 CERT_DestroyCertificate(certificate); | |
| 766 if (PR_GetError() == -8177) { | |
| 767 ThrowPRException("CertificateException", | |
| 768 "Certificate database password incorrect"); | |
| 769 } else { | |
| 770 ThrowCertificateException( | |
| 771 "Cannot find private key for certificate %s", | |
| 772 certificate_name); | |
| 773 } | |
| 774 } | |
| 775 | |
| 776 // kt_rsa (key type RSA) is an enum constant from the NSS libraries. | |
| 777 // TODO(whesse): Allow different key types. | |
| 778 status = SSL_ConfigSecureServer(filter_, certificate, key, kt_rsa); | |
| 779 CERT_DestroyCertificate(certificate); | |
| 780 SECKEY_DestroyPrivateKey(key); | |
| 781 if (status != SECSuccess) { | |
| 782 ThrowCertificateException( | |
| 783 "Failed SSL_ConfigSecureServer call with certificate %s", | |
| 784 certificate_name); | |
| 785 } | |
| 786 | |
| 787 if (request_client_certificate) { | 905 if (request_client_certificate) { |
| 788 status = SSL_OptionSet(filter_, SSL_REQUEST_CERTIFICATE, PR_TRUE); | 906 // TODO(24069): Handle client certificates on server side. |
| 789 if (status != SECSuccess) { | 907 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 790 ThrowPRException("TlsException", | 908 "requestClientCertificate not implemented.")); |
| 791 "Failed SSL_OptionSet(REQUEST_CERTIFICATE) call"); | |
| 792 } | |
| 793 status = SSL_OptionSet(filter_, | |
| 794 SSL_REQUIRE_CERTIFICATE, | |
| 795 require_client_certificate); | |
| 796 if (status != SECSuccess) { | |
| 797 ThrowPRException("TlsException", | |
| 798 "Failed SSL_OptionSet(REQUIRE_CERTIFICATE) call"); | |
| 799 } | |
| 800 } | 909 } |
| 801 } else { // Client. | 910 } else { // Client. |
| 802 if (SSL_SetURL(filter_, host_name) == -1) { | |
| 803 ThrowPRException("TlsException", "Failed SetURL call"); | |
| 804 } | |
| 805 if (send_client_certificate) { | 911 if (send_client_certificate) { |
| 806 SSL_SetPKCS11PinArg(filter_, const_cast<char*>(password_)); | 912 // TODO(24070): Handle client certificates on client side. |
| 807 status = SSL_GetClientAuthDataHook( | 913 Dart_ThrowException(DartUtils::NewDartArgumentError( |
| 808 filter_, | 914 "sendClientCertificate not implemented.")); |
| 809 NSS_GetClientAuthData, | |
| 810 static_cast<void*>(client_certificate_name_)); | |
| 811 if (status != SECSuccess) { | |
| 812 ThrowPRException("TlsException", | |
| 813 "Failed SSL_GetClientAuthDataHook call"); | |
| 814 } | |
| 815 } | 915 } |
| 816 } | 916 } |
| 817 | 917 Handshake(); |
| 818 // Install bad certificate callback, and pass 'this' to it if it is called. | |
| 819 status = SSL_BadCertHook(filter_, | |
| 820 BadCertificateCallback, | |
| 821 static_cast<void*>(this)); | |
| 822 | |
| 823 status = SSL_ResetHandshake(filter_, is_server); | |
| 824 if (status != SECSuccess) { | |
| 825 ThrowPRException("TlsException", | |
| 826 "Failed SSL_ResetHandshake call"); | |
| 827 } | |
| 828 | |
| 829 // Set the peer address from the address passed. The DNS has already | |
| 830 // been done in Dart code, so just use that address. This relies on | |
| 831 // following about PRNetAddr: "The raw member of the union is | |
| 832 // equivalent to struct sockaddr", which is stated in the NSS | |
| 833 // documentation. | |
| 834 PRNetAddr peername; | |
| 835 memset(&peername, 0, sizeof(peername)); | |
| 836 intptr_t len = SocketAddress::GetAddrLength(raw_addr); | |
| 837 ASSERT(static_cast<size_t>(len) <= sizeof(peername)); | |
| 838 memmove(&peername, &raw_addr.addr, len); | |
| 839 | |
| 840 // Adjust the address family field for BSD, whose sockaddr | |
| 841 // structure has a one-byte length and one-byte address family | |
| 842 // field at the beginning. PRNetAddr has a two-byte address | |
| 843 // family field at the beginning. | |
| 844 peername.raw.family = raw_addr.addr.sa_family; | |
| 845 | |
| 846 memio_SetPeerName(filter_, &peername); | |
| 847 } | 918 } |
| 848 | 919 |
| 849 | 920 |
| 921 int printErrorCallback(const char *str, size_t len, void *ctx) { |
| 922 Log::PrintErr("%.*s\n", static_cast<int>(len), str); |
| 923 return 1; |
| 924 } |
| 925 |
| 850 void SSLFilter::Handshake() { | 926 void SSLFilter::Handshake() { |
| 851 SECStatus status = SSL_ForceHandshake(filter_); | 927 // Try and push handshake along. |
| 852 if (status == SECSuccess) { | 928 int status; |
| 929 int error; |
| 930 status = SSL_do_handshake(ssl_); |
| 931 if (callback_error != NULL) { |
| 932 // The SSL_do_handshake will try performing a handshake and might call |
| 933 // a CertificateCallback. If the certificate validation |
| 934 // failed the 'callback_error" will be set by the certificateCallback |
| 935 // logic and we propagate the error" |
| 936 Dart_PropagateError(callback_error); |
| 937 } |
| 938 if (SSL_LOG_STATUS) Log::Print("SSL_handshake status: %d\n", status); |
| 939 if (status != 1) { |
| 940 error = SSL_get_error(ssl_, status); |
| 941 if (SSL_LOG_STATUS) Log::Print("ERROR: %d\n", error); |
| 942 ERR_print_errors_cb(printErrorCallback, NULL); |
| 943 } |
| 944 if (status == 1) { |
| 853 if (in_handshake_) { | 945 if (in_handshake_) { |
| 946 // TODO(24071): Check return value of SSL_get_verify_result, this |
| 947 // should give us the hostname check. |
| 948 int result = SSL_get_verify_result(ssl_); |
| 949 if (SSL_LOG_STATUS) { |
| 950 Log::Print("Handshake verification status: %d\n", result); |
| 951 X509* peer_certificate = SSL_get_peer_certificate(ssl_); |
| 952 if (peer_certificate == NULL) { |
| 953 Log::Print("No peer certificate received\n"); |
| 954 } else { |
| 955 X509_NAME* s_name = X509_get_subject_name(peer_certificate); |
| 956 printf("Peer certificate SN: "); |
| 957 X509_NAME_print_ex_fp(stdout, s_name, 4, 0); |
| 958 printf("\n"); |
| 959 } |
| 960 } |
| 854 ThrowIfError(Dart_InvokeClosure( | 961 ThrowIfError(Dart_InvokeClosure( |
| 855 Dart_HandleFromPersistent(handshake_complete_), 0, NULL)); | 962 Dart_HandleFromPersistent(handshake_complete_), 0, NULL)); |
| 856 in_handshake_ = false; | 963 in_handshake_ = false; |
| 857 } | 964 } |
| 858 } else { | 965 } else if (status == 0) { |
| 859 if (callback_error != NULL) { | 966 if (is_server_) { |
| 860 Dart_PropagateError(callback_error); | 967 ThrowIOException("HandshakeException", |
| 968 "Handshake error in server"); |
| 969 } else { |
| 970 ThrowIOException("HandshakeException", |
| 971 "Handshake error in client"); |
| 861 } | 972 } |
| 862 PRErrorCode error = PR_GetError(); | 973 } else if (status < 0) { |
| 863 if (error == PR_WOULD_BLOCK_ERROR) { | 974 if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) { |
| 864 if (!in_handshake_) { | 975 if (!in_handshake_) { |
| 865 in_handshake_ = true; | 976 in_handshake_ = true; |
| 866 } | 977 } |
| 867 } else { | 978 } else { |
| 868 if (is_server_) { | 979 if (is_server_) { |
| 869 ThrowPRException("HandshakeException", | 980 ThrowIOException("HandshakeException", |
| 870 "Handshake error in server"); | 981 "Handshake error in server"); |
| 871 } else { | 982 } else { |
| 872 ThrowPRException("HandshakeException", | 983 ThrowIOException("HandshakeException", |
| 873 "Handshake error in client"); | 984 "Handshake error in client"); |
| 874 } | 985 } |
| 875 } | 986 } |
| 876 } | 987 } |
| 877 } | 988 } |
| 878 | 989 |
| 879 void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) { | 990 void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) { |
| 880 // Space for the selected protocol. | 991 const uint8_t* protocol; |
| 881 const unsigned int kBufferSize = 256; | 992 unsigned length; |
| 882 unsigned char buffer[kBufferSize + 1]; | 993 SSL_get0_alpn_selected(ssl_, &protocol, &length); |
| 883 | 994 if (length == 0) { |
| 884 unsigned int outLength = 0; | 995 Dart_SetReturnValue(args, Dart_Null()); |
| 885 SSLNextProtoState outState; | |
| 886 | |
| 887 SECStatus status = SSL_GetNextProto( | |
| 888 filter_, &outState, buffer, &outLength, kBufferSize); | |
| 889 if (status == SECSuccess) { | |
| 890 if (outState == SSL_NEXT_PROTO_SELECTED || | |
| 891 outState == SSL_NEXT_PROTO_NEGOTIATED) { | |
| 892 ASSERT(outLength <= kBufferSize); | |
| 893 buffer[outLength] = '\0'; | |
| 894 Dart_Handle protocol_string = DartUtils::NewString( | |
| 895 reinterpret_cast<const char *>(&buffer[0])); | |
| 896 if (Dart_IsError(protocol_string)) { | |
| 897 ThrowPRException("HandshakeException", | |
| 898 "Protocol selected via ALPN, unable to get protocol " | |
| 899 "string."); | |
| 900 } else { | |
| 901 Dart_SetReturnValue(args, protocol_string); | |
| 902 } | |
| 903 } else if (outState == SSL_NEXT_PROTO_NO_OVERLAP) { | |
| 904 ThrowPRException("HandshakeException", | |
| 905 "Client and Server could not agree upon a protocol"); | |
| 906 } else if (outState == SSL_NEXT_PROTO_NO_SUPPORT) { | |
| 907 // A value of `null` denotes that the client did not support protocol | |
| 908 // negogiation. | |
| 909 Dart_SetReturnValue(args, Dart_Null()); | |
| 910 } else { | |
| 911 UNREACHABLE(); | |
| 912 } | |
| 913 } else { | 996 } else { |
| 914 ThrowPRException("HandshakeException", | 997 Dart_SetReturnValue(args, Dart_NewStringFromUTF8(protocol, length)); |
| 915 "Could not retrieve selected protocol via ALPN"); | |
| 916 } | 998 } |
| 917 } | 999 } |
| 918 | 1000 |
| 919 | 1001 |
| 920 void SSLFilter::Renegotiate(bool use_session_cache, | 1002 void SSLFilter::Renegotiate(bool use_session_cache, |
| 921 bool request_client_certificate, | 1003 bool request_client_certificate, |
| 922 bool require_client_certificate) { | 1004 bool require_client_certificate) { |
| 923 SECStatus status; | |
| 924 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the | 1005 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the |
| 925 // SSL_REQUEST_CERTIFICATE option is also set, so set it. | 1006 // SSL_REQUEST_CERTIFICATE option is also set, so set it. |
| 926 request_client_certificate = | 1007 request_client_certificate = |
| 927 request_client_certificate || require_client_certificate; | 1008 request_client_certificate || require_client_certificate; |
| 928 | 1009 // TODO(24070, 24069): Implement setting the client certificate parameters, |
| 929 status = SSL_OptionSet(filter_, | 1010 // and triggering rehandshake. |
| 930 SSL_REQUEST_CERTIFICATE, | |
| 931 request_client_certificate); | |
| 932 if (status != SECSuccess) { | |
| 933 ThrowPRException("TlsException", | |
| 934 "Failure in (Raw)SecureSocket.renegotiate request_client_certificate"); | |
| 935 } | |
| 936 status = SSL_OptionSet(filter_, | |
| 937 SSL_REQUIRE_CERTIFICATE, | |
| 938 require_client_certificate); | |
| 939 if (status != SECSuccess) { | |
| 940 ThrowPRException("TlsException", | |
| 941 "Failure in (Raw)SecureSocket.renegotiate require_client_certificate"); | |
| 942 } | |
| 943 bool flush_cache = !use_session_cache; | |
| 944 status = SSL_ReHandshake(filter_, flush_cache); | |
| 945 if (status != SECSuccess) { | |
| 946 if (is_server_) { | |
| 947 ThrowPRException("HandshakeException", | |
| 948 "Failure in (Raw)SecureSocket.renegotiate in server"); | |
| 949 } else { | |
| 950 ThrowPRException("HandshakeException", | |
| 951 "Failure in (Raw)SecureSocket.renegotiate in client"); | |
| 952 } | |
| 953 } | |
| 954 } | 1011 } |
| 955 | 1012 |
| 956 | 1013 |
| 957 void SSLFilter::Destroy() { | 1014 void SSLFilter::Destroy() { |
| 1015 if (ssl_ != NULL) { |
| 1016 SSL_free(ssl_); |
| 1017 ssl_ = NULL; |
| 1018 } |
| 958 for (int i = 0; i < kNumBuffers; ++i) { | 1019 for (int i = 0; i < kNumBuffers; ++i) { |
| 959 Dart_DeletePersistentHandle(dart_buffer_objects_[i]); | 1020 Dart_DeletePersistentHandle(dart_buffer_objects_[i]); |
| 960 delete[] buffers_[i]; | 1021 delete[] buffers_[i]; |
| 961 } | 1022 } |
| 962 Dart_DeletePersistentHandle(string_start_); | 1023 Dart_DeletePersistentHandle(string_start_); |
| 963 Dart_DeletePersistentHandle(string_length_); | 1024 Dart_DeletePersistentHandle(string_length_); |
| 964 Dart_DeletePersistentHandle(handshake_complete_); | 1025 Dart_DeletePersistentHandle(handshake_complete_); |
| 965 Dart_DeletePersistentHandle(bad_certificate_callback_); | 1026 Dart_DeletePersistentHandle(bad_certificate_callback_); |
| 966 free(client_certificate_name_); | |
| 967 | |
| 968 PR_Close(filter_); | |
| 969 } | 1027 } |
| 970 | 1028 |
| 971 | 1029 |
| 972 intptr_t SSLFilter::ProcessReadPlaintextBuffer(int start, int end) { | 1030 /* Read decrypted data from the filter to the circular buffer */ |
| 1031 int SSLFilter::ProcessReadPlaintextBuffer(int start, int end) { |
| 973 int length = end - start; | 1032 int length = end - start; |
| 974 int bytes_processed = 0; | 1033 int bytes_processed = 0; |
| 975 if (length > 0) { | 1034 if (length > 0) { |
| 976 bytes_processed = PR_Read(filter_, | 1035 bytes_processed = SSL_read( |
| 977 buffers_[kReadPlaintext] + start, | 1036 ssl_, |
| 978 length); | 1037 reinterpret_cast<char*>((buffers_[kReadPlaintext] + start)), |
| 1038 length); |
| 979 if (bytes_processed < 0) { | 1039 if (bytes_processed < 0) { |
| 980 ASSERT(bytes_processed == -1); | 1040 int error = SSL_get_error(ssl_, bytes_processed); |
| 981 PRErrorCode pr_error = PR_GetError(); | 1041 USE(error); |
| 982 if (PR_WOULD_BLOCK_ERROR != pr_error) { | |
| 983 return -1; | |
| 984 } | |
| 985 bytes_processed = 0; | 1042 bytes_processed = 0; |
| 986 } | 1043 } |
| 987 } | 1044 } |
| 988 return bytes_processed; | 1045 return bytes_processed; |
| 989 } | 1046 } |
| 990 | 1047 |
| 991 | 1048 |
| 992 intptr_t SSLFilter::ProcessWritePlaintextBuffer(int start1, int end1, | 1049 int SSLFilter::ProcessWritePlaintextBuffer(int start, int end) { |
| 993 int start2, int end2) { | 1050 int length = end - start; |
| 994 PRIOVec ranges[2]; | 1051 int bytes_processed = SSL_write( |
| 995 uint8_t* buffer = buffers_[kWritePlaintext]; | 1052 ssl_, buffers_[kWritePlaintext] + start, length); |
| 996 ranges[0].iov_base = reinterpret_cast<char*>(buffer + start1); | |
| 997 ranges[0].iov_len = end1 - start1; | |
| 998 ranges[1].iov_base = reinterpret_cast<char*>(buffer + start2); | |
| 999 ranges[1].iov_len = end2 - start2; | |
| 1000 int bytes_processed = PR_Writev(filter_, ranges, 2, PR_INTERVAL_NO_TIMEOUT); | |
| 1001 if (bytes_processed < 0) { | 1053 if (bytes_processed < 0) { |
| 1002 ASSERT(bytes_processed == -1); | 1054 if (SSL_LOG_DATA) { |
| 1003 PRErrorCode pr_error = PR_GetError(); | 1055 Log::Print("SSL_write returned error %d\n", bytes_processed); |
| 1004 if (PR_WOULD_BLOCK_ERROR != pr_error) { | |
| 1005 return -1; | |
| 1006 } | 1056 } |
| 1007 bytes_processed = 0; | 1057 return 0; |
| 1008 } | 1058 } |
| 1009 return bytes_processed; | 1059 return bytes_processed; |
| 1010 } | 1060 } |
| 1011 | 1061 |
| 1012 | 1062 |
| 1013 intptr_t SSLFilter::ProcessReadEncryptedBuffer(int start, int end) { | 1063 /* Read encrypted data from the circular buffer to the filter */ |
| 1064 int SSLFilter::ProcessReadEncryptedBuffer(int start, int end) { |
| 1014 int length = end - start; | 1065 int length = end - start; |
| 1066 if (SSL_LOG_DATA) Log::Print( |
| 1067 "Entering ProcessReadEncryptedBuffer with %d bytes\n", length); |
| 1015 int bytes_processed = 0; | 1068 int bytes_processed = 0; |
| 1016 if (length > 0) { | 1069 if (length > 0) { |
| 1017 memio_Private* secret = memio_GetSecret(filter_); | 1070 bytes_processed = |
| 1018 uint8_t* filter_buf; | 1071 BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length); |
| 1019 int free_bytes = memio_GetReadParams(secret, &filter_buf); | 1072 if (bytes_processed <= 0) { |
| 1020 bytes_processed = dart::Utils::Minimum(length, free_bytes); | 1073 bool retry = BIO_should_retry(socket_side_); |
| 1021 memmove(filter_buf, buffers_[kReadEncrypted] + start, bytes_processed); | 1074 if (!retry) { |
| 1022 memio_PutReadResult(secret, bytes_processed); | 1075 if (SSL_LOG_DATA) Log::Print( |
| 1076 "BIO_write failed in ReadEncryptedBuffer\n"); |
| 1077 } |
| 1078 bytes_processed = 0; |
| 1079 } |
| 1023 } | 1080 } |
| 1081 if (SSL_LOG_DATA) Log::Print( |
| 1082 "Leaving ProcessReadEncryptedBuffer wrote %d bytes\n", bytes_processed); |
| 1024 return bytes_processed; | 1083 return bytes_processed; |
| 1025 } | 1084 } |
| 1026 | 1085 |
| 1027 | 1086 |
| 1028 intptr_t SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) { | 1087 int SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) { |
| 1029 int length = end - start; | 1088 int length = end - start; |
| 1030 int bytes_processed = 0; | 1089 int bytes_processed = 0; |
| 1031 if (length > 0) { | 1090 if (length > 0) { |
| 1032 uint8_t* buffer = buffers_[kWriteEncrypted]; | 1091 bytes_processed = BIO_read(socket_side_, |
| 1033 const uint8_t* buf1; | 1092 buffers_[kWriteEncrypted] + start, |
| 1034 const uint8_t* buf2; | 1093 length); |
| 1035 unsigned int len1; | 1094 if (bytes_processed < 0) { |
| 1036 unsigned int len2; | 1095 if (SSL_LOG_DATA) Log::Print( |
| 1037 memio_Private* secret = memio_GetSecret(filter_); | 1096 "WriteEncrypted BIO_read returned error %d\n", bytes_processed); |
| 1038 int status = memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2); | 1097 return 0; |
| 1039 if (status != 0) { | 1098 } else { |
| 1040 return -1; | 1099 if (SSL_LOG_DATA) Log::Print( |
| 1041 } | 1100 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); |
| 1042 int bytes_to_send = | |
| 1043 dart::Utils::Minimum(len1, static_cast<unsigned>(length)); | |
| 1044 if (bytes_to_send > 0) { | |
| 1045 memmove(buffer + start, buf1, bytes_to_send); | |
| 1046 bytes_processed = bytes_to_send; | |
| 1047 } | |
| 1048 bytes_to_send = dart::Utils::Minimum(len2, | |
| 1049 static_cast<unsigned>(length - bytes_processed)); | |
| 1050 if (bytes_to_send > 0) { | |
| 1051 memmove(buffer + start + bytes_processed, buf2, bytes_to_send); | |
| 1052 bytes_processed += bytes_to_send; | |
| 1053 } | |
| 1054 if (bytes_processed > 0) { | |
| 1055 memio_PutWriteResult(secret, bytes_processed); | |
| 1056 } | 1101 } |
| 1057 } | 1102 } |
| 1058 return bytes_processed; | 1103 return bytes_processed; |
| 1059 } | 1104 } |
| 1060 | 1105 |
| 1061 } // namespace bin | 1106 } // namespace bin |
| 1062 } // namespace dart | 1107 } // namespace dart |
| OLD | NEW |