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 |