Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1219)

Side by Side Diff: runtime/bin/secure_socket_macos.cc

Issue 2903743002: Porting SecureSocket to use BoringSSL on OSX (Closed)
Patch Set: Moved CertificateCallback into SSLCertContext Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED)
6
7 #include "platform/globals.h"
8 #if defined(HOST_OS_MACOS) && !HOST_OS_IOS
9
10 #include "bin/secure_socket.h"
11 #include "bin/secure_socket_macos.h"
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <sys/stat.h>
16 #include <sys/syslimits.h>
17 #include <stdio.h>
18 #include <string.h>
19
20 #include <CoreFoundation/CoreFoundation.h>
21 #include <Security/SecureTransport.h>
22 #include <Security/Security.h>
23
24 #include "bin/builtin.h"
25 #include "bin/dartutils.h"
26 #include "bin/lockers.h"
27 #include "bin/log.h"
28 #include "bin/socket.h"
29 #include "bin/thread.h"
30 #include "bin/utils.h"
31
32 #include "platform/text_buffer.h"
33 #include "platform/utils.h"
34
35 #include "include/dart_api.h"
36
37 // Return the error from the containing function if handle is an error handle.
38 #define RETURN_IF_ERROR(handle) \
39 { \
40 Dart_Handle __handle = handle; \
41 if (Dart_IsError((__handle))) { \
42 return __handle; \
43 } \
44 }
45
46 // We need to access this private API function to create a SecIdentityRef
47 // without writing a custom keychain to the filesystem. This is the approach
48 // taken in WebKit:
49 // https://webkit.googlesource.com/WebKit/+/master/Source/WebKit2/Shared/cf/Argu mentCodersCF.cpp
50 extern "C" {
51 SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator,
52 SecCertificateRef certificate,
53 SecKeyRef private_key);
54 }
55
56 namespace dart {
57 namespace bin {
58
59 static const int kSSLFilterNativeFieldIndex = 0;
60 static const int kSecurityContextNativeFieldIndex = 0;
61 static const int kX509NativeFieldIndex = 0;
62
63 static const bool SSL_LOG_STATUS = false;
64 static const bool SSL_LOG_DATA = false;
65 static const bool SSL_LOG_CERTS = false;
66 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
67 static const intptr_t PEM_BUFSIZE = 1024;
68
69 static char* CFStringRefToCString(CFStringRef cfstring) {
70 CFIndex len = CFStringGetLength(cfstring);
71 CFIndex max_len =
72 CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
73 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
74 ASSERT(result != NULL);
75 bool success =
76 CFStringGetCString(cfstring, result, max_len, kCFStringEncodingUTF8);
77 return success ? result : NULL;
78 }
79
80
81 // Handle an error reported from the SecureTransport library.
82 static void ThrowIOException(OSStatus status,
83 const char* exception_type,
84 const char* message) {
85 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
86 CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
87 if (error_string == NULL) {
88 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
89 static_cast<intptr_t>(status));
90 } else {
91 char* error = CFStringRefToCString(error_string);
92 status_message.Printf("OSStatus = %ld: %s", static_cast<intptr_t>(status),
93 error);
94 CFRelease(error_string);
95 }
96 OSError os_error_struct(status, status_message.buf(), OSError::kBoringSSL);
97 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
98 Dart_Handle exception =
99 DartUtils::NewDartIOException(exception_type, message, os_error);
100 ASSERT(!Dart_IsError(exception));
101 Dart_ThrowException(exception);
102 UNREACHABLE();
103 }
104
105
106 static void CheckStatus(OSStatus status,
107 const char* type,
108 const char* message) {
109 if (status == noErr) {
110 return;
111 }
112 ThrowIOException(status, type, message);
113 }
114
115
116 static SSLFilter* GetFilter(Dart_NativeArguments args) {
117 SSLFilter* filter;
118 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
119 ASSERT(Dart_IsInstance(dart_this));
120 ThrowIfError(
121 Dart_GetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
122 reinterpret_cast<intptr_t*>(&filter)));
123 return filter;
124 }
125
126
127 static void DeleteFilter(void* isolate_data,
128 Dart_WeakPersistentHandle handle,
129 void* context_pointer) {
130 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
131 filter->Release();
132 }
133
134
135 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
136 ASSERT(filter != NULL);
137 const int approximate_size_of_filter = 1500;
138 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
139 RETURN_IF_ERROR(dart_this);
140 ASSERT(Dart_IsInstance(dart_this));
141 Dart_Handle err =
142 Dart_SetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
143 reinterpret_cast<intptr_t>(filter));
144 RETURN_IF_ERROR(err);
145 Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter),
146 approximate_size_of_filter, DeleteFilter);
147 return Dart_Null();
148 }
149
150
151 static SSLCertContext* GetSecurityContext(Dart_NativeArguments args) {
152 SSLCertContext* context;
153 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
154 ASSERT(Dart_IsInstance(dart_this));
155 ThrowIfError(
156 Dart_GetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
157 reinterpret_cast<intptr_t*>(&context)));
158 return context;
159 }
160
161
162 static void DeleteCertContext(void* isolate_data,
163 Dart_WeakPersistentHandle handle,
164 void* context_pointer) {
165 SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
166 context->Release();
167 }
168
169
170 static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
171 SSLCertContext* context) {
172 const int approximate_size_of_context = 1500;
173 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
174 RETURN_IF_ERROR(dart_this);
175 ASSERT(Dart_IsInstance(dart_this));
176 Dart_Handle err =
177 Dart_SetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
178 reinterpret_cast<intptr_t>(context));
179 RETURN_IF_ERROR(err);
180 Dart_NewWeakPersistentHandle(dart_this, context, approximate_size_of_context,
181 DeleteCertContext);
182 return Dart_Null();
183 }
184
185
186 static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
187 SecCertificateRef certificate;
188 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
189 ASSERT(Dart_IsInstance(dart_this));
190 ThrowIfError(
191 Dart_GetNativeInstanceField(dart_this, kX509NativeFieldIndex,
192 reinterpret_cast<intptr_t*>(&certificate)));
193 return certificate;
194 }
195
196
197 static void ReleaseCertificate(void* isolate_data,
198 Dart_WeakPersistentHandle handle,
199 void* context_pointer) {
200 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(context_pointer);
201 CFRelease(cert);
202 }
203
204
205 static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) {
206 const intptr_t approximate_size_of_certificate = 1500;
207 if (certificate == NULL) {
208 return Dart_Null();
209 }
210 Dart_Handle x509_type =
211 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
212 if (Dart_IsError(x509_type)) {
213 return x509_type;
214 }
215 Dart_Handle arguments[] = {NULL};
216
217 Dart_Handle result =
218 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
219 if (Dart_IsError(result)) {
220 return result;
221 }
222 ASSERT(Dart_IsInstance(result));
223
224 // CFRetain in case the returned Dart object outlives the SecurityContext.
225 // CFRelease is in the Dart object's finalizer
226 CFRetain(certificate);
227 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate),
228 approximate_size_of_certificate,
229 ReleaseCertificate);
230
231 Dart_Handle status = Dart_SetNativeInstanceField(
232 result, kX509NativeFieldIndex, reinterpret_cast<intptr_t>(certificate));
233 if (Dart_IsError(status)) {
234 return status;
235 }
236 return result;
237 }
238
239
240 static const char* GetPasswordArgument(Dart_NativeArguments args,
241 intptr_t index) {
242 Dart_Handle password_object =
243 ThrowIfError(Dart_GetNativeArgument(args, index));
244 const char* password = NULL;
245 if (Dart_IsString(password_object)) {
246 ThrowIfError(Dart_StringToCString(password_object, &password));
247 if (strlen(password) > PEM_BUFSIZE - 1) {
248 Dart_ThrowException(DartUtils::NewDartArgumentError(
249 "Password length is greater than 1023 bytes."));
250 }
251 } else if (Dart_IsNull(password_object)) {
252 password = "";
253 } else {
254 Dart_ThrowException(
255 DartUtils::NewDartArgumentError("Password is not a String or null"));
256 }
257 return password;
258 }
259
260
261 static OSStatus GetKeyAndCerts(CFArrayRef items,
262 CFIndex items_length,
263 CFArrayRef* out_certs,
264 SecKeyRef* out_key) {
265 OSStatus status = noErr;
266
267 // Loop through the items, take only the first private key/identity, ignore
268 // any others, populate out_certs.
269 CFMutableArrayRef certs =
270 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
271 SecKeyRef key = NULL;
272
273 for (CFIndex i = 0; i < items_length; ++i) {
274 CFTypeRef item =
275 reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(items, i));
276 CFTypeID item_type = CFGetTypeID(item);
277 if (item_type == SecCertificateGetTypeID()) {
278 if (SSL_LOG_CERTS) {
279 Log::Print("\titem %ld: Certificate\n", i);
280 }
281 CFArrayAppendValue(certs, item);
282 } else if ((item_type == SecKeyGetTypeID()) && (key == NULL)) {
283 if (SSL_LOG_CERTS) {
284 Log::Print("\titem %ld: Key\n", i);
285 }
286 key = reinterpret_cast<SecKeyRef>(const_cast<void*>(item));
287 CFRetain(key);
288 } else if ((item_type == SecIdentityGetTypeID()) && (key == NULL)) {
289 if (SSL_LOG_CERTS) {
290 Log::Print("\titem %ld: Identity\n", i);
291 }
292 SecIdentityRef identity =
293 reinterpret_cast<SecIdentityRef>(const_cast<void*>(item));
294 SecCertificateRef cert = NULL;
295
296 status = SecIdentityCopyPrivateKey(identity, &key);
297 if (status != noErr) {
298 CFRelease(certs);
299 return status;
300 }
301
302 status = SecIdentityCopyCertificate(identity, &cert);
303 if (status != noErr) {
304 CFRelease(key);
305 CFRelease(certs);
306 return status;
307 }
308 CFArrayAppendValue(certs, cert);
309 CFRelease(cert);
310 }
311 // Other item types are ignored.
312 }
313
314 if (out_key == NULL) {
315 if (key != NULL) {
316 CFRelease(key);
317 }
318 } else {
319 *out_key = key;
320 }
321
322 if (out_certs == NULL) {
323 if (certs != NULL) {
324 CFRelease(certs);
325 }
326 } else {
327 *out_certs = certs;
328 }
329 return status;
330 }
331
332
333 static OSStatus TryPEMImport(CFDataRef cfdata,
334 CFStringRef password,
335 CFArrayRef* out_certs,
336 SecKeyRef* out_key) {
337 OSStatus status = noErr;
338
339 SecExternalFormat format = kSecFormatPEMSequence;
340 SecExternalItemType sitem_type = kSecItemTypeAggregate;
341
342 SecItemImportExportKeyParameters params;
343 memset(&params, 0, sizeof(params));
344 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
345 params.flags = kSecKeyNoAccessControl;
346 params.passphrase = password;
347
348 CFArrayRef items = NULL;
349 status = SecItemImport(cfdata, NULL, &format, &sitem_type, 0, &params, NULL,
350 &items);
351
352 if (status != noErr) {
353 if (SSL_LOG_CERTS) {
354 Log::Print("TrySecItemImport failed with: %ld, type = %d, format = %d\n",
355 static_cast<intptr_t>(status), sitem_type, format);
356 }
357 return status;
358 }
359
360 CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
361 if (SSL_LOG_CERTS) {
362 Log::Print(
363 "TrySecItemImport succeeded, type = %d, format = %d, count = %ld\n",
364 sitem_type, format, items_length);
365 }
366
367 // Empty list indicates a decoding failure of some sort.
368 if ((items != NULL) && (items_length == 0)) {
369 CFRelease(items);
370 return errSSLBadCert;
371 }
372
373 status = GetKeyAndCerts(items, items_length, out_certs, out_key);
374 CFRelease(items);
375 return status;
376 }
377
378
379 static char* TempKeychainPath() {
380 const char* exes = "keychaindir.XXXX";
381 const char* fname = "keychain";
382 const char* temp_dir = getenv("TMPDIR");
383 if (temp_dir == NULL) {
384 temp_dir = getenv("TMP");
385 }
386 if (temp_dir == NULL) {
387 temp_dir = "/tmp/";
388 }
389 ASSERT(temp_dir != NULL);
390
391 TextBuffer path(PATH_MAX);
392 path.Printf("%s/%s", temp_dir, exes);
393 char* ret = mkdtemp(path.buf());
394 ASSERT(ret != NULL);
395 path.Printf("/%s", fname);
396
397 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(path.length() + 1));
398 return strncpy(result, path.buf(), path.length() + 1);
399 }
400
401
402 static OSStatus CreateKeychain(SecKeychainRef* keychain) {
403 ASSERT(keychain != NULL);
404 OSStatus status = noErr;
405 const char* temp_keychain_pwd = "dartdart";
406 char* temp_file_path = TempKeychainPath();
407 ASSERT(temp_file_path != NULL);
408 if (SSL_LOG_CERTS) {
409 Log::Print("Temporary keychain at: '%s'\n", temp_file_path);
410 }
411 status = SecKeychainCreate(temp_file_path, strlen(temp_keychain_pwd) + 1,
412 reinterpret_cast<const void*>(temp_keychain_pwd),
413 FALSE, // Prompt user? Definitely no.
414 NULL, // Default access rights.
415 keychain);
416 if (status != noErr) {
417 return status;
418 }
419 ASSERT(*keychain != NULL);
420 return status;
421 }
422
423
424 static OSStatus TryPKCS12Import(CFDataRef cfdata,
425 CFStringRef password,
426 CFArrayRef* out_certs,
427 SecKeyRef* out_key,
428 SecKeychainRef* out_keychain) {
429 OSStatus status = noErr;
430
431 SecExternalFormat format = kSecFormatPKCS12;
432 SecExternalItemType sitem_type = kSecItemTypeAggregate;
433
434 SecItemImportExportKeyParameters params;
435 memset(&params, 0, sizeof(params));
436 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
437 params.flags = kSecKeyNoAccessControl;
438 params.passphrase = password;
439
440 CFArrayRef items = NULL;
441 if (SSL_LOG_CERTS) {
442 Log::Print("Trying PKCS12 import with: type = %d, format = %d\n",
443 sitem_type, format);
444 }
445
446 // The documentation for SecKeychainItemImport here:
447 //
448 // https://developer.apple.com/library/mac/documentation/Security/Reference/ke ychainservices/index.html
449 //
450 // states that when the SecKeychainRef argument is NULL, the CFArrayRef*
451 // argument will be populated by an array containing all keys, identities,
452 // and certificates from the data in the CFDataRef argument.
453 //
454 // Unfortunately, this is not true. The code to populate the CFArrayRef with
455 // keys and identities from PKCS12 data has been skipped and/or commented out,
456 // here:
457 //
458 // https://github.com/Apple-FOSS-Mirror/Security/blob/master/libsecurity_keych ain/lib/SecImportExportAgg.cpp#L636
459 //
460 // as "floating" SecKeyRefs from the PKCS12 decoder haven't been implemented.
461 // That is, each private key instance coming from the PKCS12 decoder has to be
462 // associated with a keychain instance. Thus, as a workaround, we create a
463 // temporary keychain here if one is needed, and stash it below in a
464 // SecurityContext. This has the drawbacks:
465 // 1.) We need to make a temporary directory to hold the keychain file, and
466 // 2.) SecKeychainItemImport() probably does blocking IO to create and
467 // manipulate the keychain file.
468 // So if the API is updated, this keychain should not be used.
469 SecKeychainRef keychain = NULL;
470 if (out_key != NULL) {
471 ASSERT(out_keychain != NULL);
472 status = CreateKeychain(&keychain);
473 if (status != noErr) {
474 return status;
475 }
476 *out_keychain = keychain;
477 }
478
479 status = SecItemImport(cfdata, NULL, &format, &sitem_type, 0, &params,
480 keychain, &items);
481 if (status != noErr) {
482 if (SSL_LOG_CERTS) {
483 Log::Print("TrySecItemImport failed with: %ld, it = %d, format = %d\n",
484 static_cast<intptr_t>(status), sitem_type, format);
485 }
486 return status;
487 }
488
489 CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
490 if (SSL_LOG_CERTS) {
491 Log::Print("TrySecItemImport succeeded, count = %ld\n", items_length);
492 }
493
494 // Empty list indicates a decoding failure of some sort.
495 if ((items != NULL) && (items_length == 0)) {
496 CFRelease(items);
497 return errSSLBadCert;
498 }
499
500 status = GetKeyAndCerts(items, items_length, out_certs, out_key);
501 CFRelease(items);
502 return status;
503 }
504
505
506 static OSStatus ExtractSecItems(uint8_t* buffer,
507 intptr_t length,
508 const char* password,
509 CFArrayRef* out_certs,
510 SecKeyRef* out_key,
511 SecKeychainRef* out_keychain) {
512 ASSERT(buffer != NULL);
513 ASSERT(password != NULL);
514 OSStatus status = noErr;
515
516 CFDataRef cfdata =
517 CFDataCreateWithBytesNoCopy(NULL, buffer, length, kCFAllocatorNull);
518 CFStringRef cfpassword = CFStringCreateWithCStringNoCopy(
519 NULL, password, kCFStringEncodingUTF8, kCFAllocatorNull);
520 ASSERT(cfdata != NULL);
521 ASSERT(cfpassword != NULL);
522
523 status = TryPEMImport(cfdata, cfpassword, out_certs, out_key);
524 if (status != noErr) {
525 status =
526 TryPKCS12Import(cfdata, cfpassword, out_certs, out_key, out_keychain);
527 }
528
529 CFRelease(cfdata);
530 CFRelease(cfpassword);
531 return status;
532 }
533
534
535 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
536 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
537 SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer.
538 Dart_Handle err = SetFilter(args, filter);
539 if (Dart_IsError(err)) {
540 filter->Release();
541 Dart_PropagateError(err);
542 }
543 err = filter->Init(dart_this);
544 if (Dart_IsError(err)) {
545 // The finalizer was set up by SetFilter. It will delete `filter` if there
546 // is an error.
547 filter->Destroy();
548 Dart_PropagateError(err);
549 }
550 }
551
552
553 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
554 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
555 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
556 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
557 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
558 bool request_client_certificate =
559 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
560 bool require_client_certificate =
561 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
562
563 const char* host_name = NULL;
564 // TODO(whesse): Is truncating a Dart string containing \0 what we want?
565 ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
566
567 SSLCertContext* context = NULL;
568 if (!Dart_IsNull(context_object)) {
569 ThrowIfError(Dart_GetNativeInstanceField(
570 context_object, kSecurityContextNativeFieldIndex,
571 reinterpret_cast<intptr_t*>(&context)));
572 }
573
574 GetFilter(args)->Connect(dart_this, host_name, context, is_server,
575 request_client_certificate,
576 require_client_certificate);
577 }
578
579
580 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
581 SSLFilter* filter = GetFilter(args);
582 // The SSLFilter is deleted in the finalizer for the Dart object created by
583 // SetFilter. There is no need to NULL-out the native field for the SSLFilter
584 // here because the SSLFilter won't be deleted until the finalizer for the
585 // Dart object runs while the Dart object is being GCd. This approach avoids a
586 // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is
587 // called more than once.
588 filter->Destroy();
589 }
590
591
592 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
593 OSStatus status = GetFilter(args)->CheckHandshake();
594 CheckStatus(status, "HandshakeException", "Handshake error");
595 }
596
597
598 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)(
599 Dart_NativeArguments args) {
600 Dart_SetReturnValue(args, Dart_Null());
601 }
602
603
604 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
605 bool use_session_cache =
606 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1));
607 bool request_client_certificate =
608 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
609 bool require_client_certificate =
610 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
611 GetFilter(args)->Renegotiate(use_session_cache, request_client_certificate,
612 require_client_certificate);
613 }
614
615
616 void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
617 Dart_NativeArguments args) {
618 Dart_Handle handshake_complete =
619 ThrowIfError(Dart_GetNativeArgument(args, 1));
620 if (!Dart_IsClosure(handshake_complete)) {
621 Dart_ThrowException(DartUtils::NewDartArgumentError(
622 "Illegal argument to RegisterHandshakeCompleteCallback"));
623 }
624 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
625 }
626
627
628 void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
629 Dart_NativeArguments args) {
630 Dart_Handle callback = ThrowIfError(Dart_GetNativeArgument(args, 1));
631 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
632 Dart_ThrowException(DartUtils::NewDartArgumentError(
633 "Illegal argument to RegisterBadCertificateCallback"));
634 }
635 GetFilter(args)->RegisterBadCertificateCallback(callback);
636 }
637
638
639 void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) {
640 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
641 }
642
643
644 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
645 SSLFilter* filter = GetFilter(args);
646 // This filter pointer is passed to the IO Service thread. The IO Service
647 // thread must Release() the pointer when it is done with it.
648 filter->Retain();
649 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
650 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
651 }
652
653
654 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
655 SSLCertContext* cert_context = new SSLCertContext();
656 // cert_context deleted in DeleteCertContext finalizer.
657 Dart_Handle err = SetSecurityContext(args, cert_context);
658 if (Dart_IsError(err)) {
659 cert_context->Release();
660 Dart_PropagateError(err);
661 }
662 }
663
664
665 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
666 Dart_NativeArguments args) {
667 SSLCertContext* context = GetSecurityContext(args);
668 const char* password = GetPasswordArgument(args, 2);
669
670 OSStatus status;
671 SecKeyRef key = NULL;
672 SecKeychainRef keychain = NULL;
673 {
674 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
675 status = ExtractSecItems(buffer.get(), buffer.length(), password, NULL,
676 &key, &keychain);
677 }
678
679 // Set the context fields. If there's a failure, release the items.
680 bool set_failure = false;
681 if ((key != NULL) && !context->set_private_key(key)) {
682 CFRelease(key);
683 SecKeychainDelete(keychain);
684 CFRelease(keychain);
685 set_failure = true;
686 }
687 if (!set_failure && (keychain != NULL) && !context->set_keychain(keychain)) {
688 SecKeychainDelete(keychain);
689 CFRelease(keychain);
690 }
691
692 if (set_failure) {
693 Dart_ThrowException(DartUtils::NewDartArgumentError(
694 "usePrivateKeyBytes has already been called on the given context."));
695 }
696 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
697 }
698
699
700 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
701 Dart_NativeArguments args) {
702 SSLCertContext* context = GetSecurityContext(args);
703 const char* password = GetPasswordArgument(args, 2);
704
705 OSStatus status;
706 CFArrayRef certs = NULL;
707 {
708 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
709 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs,
710 NULL, NULL);
711 }
712
713 // Set the field in the context. If there's a failure, release the certs,
714 // and throw an exception.
715 if ((certs != NULL) && !context->set_trusted_certs(certs)) {
716 CFRelease(certs);
717 Dart_ThrowException(DartUtils::NewDartArgumentError(
718 "setTrustedCertificatesBytes has already been called "
719 "on the given context."));
720 }
721
722 CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes");
723 }
724
725
726 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
727 Dart_SetReturnValue(args, Dart_NewBoolean(false));
728 }
729
730
731 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
732 Dart_NativeArguments args) {
733 SSLCertContext* context = GetSecurityContext(args);
734 context->set_trust_builtin(true);
735 }
736
737
738 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
739 Dart_NativeArguments args) {
740 SSLCertContext* context = GetSecurityContext(args);
741
742 const char* password = GetPasswordArgument(args, 2);
743 OSStatus status;
744 CFArrayRef certs = NULL;
745 {
746 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
747 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs,
748 NULL, NULL);
749 }
750
751 // Set the field in the context. If there's a failure, release the certs,
752 // and throw an exception.
753 if ((certs != NULL) && !context->set_cert_chain(certs)) {
754 CFRelease(certs);
755 Dart_ThrowException(DartUtils::NewDartArgumentError(
756 "useCertificateChainBytes has already been called "
757 "on the given context."));
758 }
759
760 CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes");
761 }
762
763
764 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
765 Dart_NativeArguments args) {
766 SSLCertContext* context = GetSecurityContext(args);
767 const char* password = GetPasswordArgument(args, 2);
768
769 OSStatus status;
770 CFArrayRef certs = NULL;
771 {
772 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
773 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs,
774 NULL, NULL);
775 }
776
777 // Set the field in the context. If there's a failure, release the certs,
778 // and throw an exception.
779 if ((certs != NULL) && !context->set_cert_authorities(certs)) {
780 CFRelease(certs);
781 Dart_ThrowException(DartUtils::NewDartArgumentError(
782 "setClientAuthoritiesBytes has already been called "
783 "on the given context."));
784 }
785
786 CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes");
787 }
788
789
790 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
791 Dart_NativeArguments args) {
792 Dart_ThrowException(DartUtils::NewDartUnsupportedError(
793 "ALPN is not supported on this platform"));
794 }
795
796
797 static char* GetNameFromCert(SecCertificateRef certificate,
798 CFTypeRef field,
799 CFStringRef name) {
800 char* issuer_name = NULL;
801
802 CFTypeRef keys[] = {field};
803 CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks);
804 CFErrorRef error = NULL;
805 CFDictionaryRef cert_dict =
806 SecCertificateCopyValues(certificate, key_array, &error);
807 if (cert_dict == NULL) {
808 CFRelease(key_array);
809 Dart_ThrowException(DartUtils::NewDartArgumentError(
810 "X509.issuer failed to copy issuer field out of certificate"));
811 }
812
813 CFTypeRef item = CFDictionaryGetValue(cert_dict, keys[0]);
814 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
815 CFDictionaryRef val_dict = reinterpret_cast<CFDictionaryRef>(item);
816
817 item = CFDictionaryGetValue(val_dict, kSecPropertyKeyValue);
818 ASSERT(CFGetTypeID(item) == CFArrayGetTypeID());
819 CFArrayRef val_array = reinterpret_cast<CFArrayRef>(item);
820
821 for (intptr_t i = 0; i < CFArrayGetCount(val_array); i++) {
822 item = CFArrayGetValueAtIndex(val_array, i);
823 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
824 CFDictionaryRef val_dict2 = reinterpret_cast<CFDictionaryRef>(item);
825
826 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyLabel);
827 ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
828 CFStringRef label = reinterpret_cast<CFStringRef>(item);
829
830 if (CFStringCompare(label, name, 0) == kCFCompareEqualTo) {
831 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyValue);
832 ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
833 CFStringRef value = reinterpret_cast<CFStringRef>(item);
834 issuer_name = CFStringRefToCString(value);
835 break;
836 }
837 }
838
839 CFRelease(cert_dict);
840 CFRelease(key_array);
841 return issuer_name;
842 }
843
844
845 void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
846 SecCertificateRef certificate = GetX509Certificate(args);
847 char* subject_name =
848 GetNameFromCert(certificate, kSecOIDX509V1SubjectName,
849 reinterpret_cast<CFStringRef>(kSecOIDCommonName));
850 if (subject_name == NULL) {
851 Dart_ThrowException(DartUtils::NewDartArgumentError(
852 "X509.subject failed to find subject's common name."));
853 } else {
854 Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_name));
855 }
856 }
857
858
859 void FUNCTION_NAME(X509_Issuer)(Dart_NativeArguments args) {
860 SecCertificateRef certificate = GetX509Certificate(args);
861 char* issuer_name =
862 GetNameFromCert(certificate, kSecOIDX509V1IssuerName,
863 reinterpret_cast<CFStringRef>(kSecOIDCommonName));
864 if (issuer_name == NULL) {
865 Dart_ThrowException(DartUtils::NewDartArgumentError(
866 "X509.issuer failed to find issuer's common name."));
867 } else {
868 Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_name));
869 }
870 }
871
872
873 // Returns the number of seconds since the epoch from 'field'.
874 static int64_t GetTimeFromCert(SecCertificateRef certificate, CFTypeRef field) {
875 CFTypeRef keys[] = {field};
876 CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks);
877 CFErrorRef error = NULL;
878 CFDictionaryRef cert_dict =
879 SecCertificateCopyValues(certificate, key_array, &error);
880 if (cert_dict == NULL) {
881 CFRelease(key_array);
882 Dart_ThrowException(DartUtils::NewDartArgumentError(
883 "X509.startValidity: failed to copy issuer field out of certificate"));
884 }
885
886 CFTypeRef item = CFDictionaryGetValue(cert_dict, keys[0]);
887 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
888 CFDictionaryRef val_dict = reinterpret_cast<CFDictionaryRef>(item);
889
890 item = CFDictionaryGetValue(val_dict, kSecPropertyKeyValue);
891 ASSERT(CFGetTypeID(item) == CFNumberGetTypeID());
892 CFNumberRef date_number = reinterpret_cast<CFNumberRef>(item);
893
894 CFAbsoluteTime date_abs_time;
895 CFNumberGetValue(date_number, kCFNumberDoubleType, &date_abs_time);
896 CFAbsoluteTime seconds_since_epoch =
897 date_abs_time + kCFAbsoluteTimeIntervalSince1970;
898 return static_cast<int64_t>(seconds_since_epoch) * 1000LL;
899 }
900
901
902 void FUNCTION_NAME(X509_StartValidity)(Dart_NativeArguments args) {
903 SecCertificateRef certificate = GetX509Certificate(args);
904 int64_t seconds_since_epoch =
905 GetTimeFromCert(certificate, kSecOIDX509V1ValidityNotBefore);
906 Dart_SetReturnValue(
907 args,
908 Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
909 }
910
911
912 void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
913 SecCertificateRef certificate = GetX509Certificate(args);
914 int64_t seconds_since_epoch =
915 GetTimeFromCert(certificate, kSecOIDX509V1ValidityNotAfter);
916 Dart_SetReturnValue(
917 args,
918 Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
919 }
920
921
922 // Pushes data through the SSL filter, reading and writing from circular
923 // buffers shared with Dart. Called from the IOService thread.
924 //
925 // The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
926 // pass encrypted and plaintext data to and from the C++ SSLFilter object.
927 //
928 // ProcessFilter is called with a CObject array containing the pointer to
929 // the SSLFilter, encoded as an int, and the start and end positions of the
930 // valid data in the four circular buffers. The function only reads from
931 // the valid data area of the input buffers, and only writes to the free
932 // area of the output buffers. The function returns the new start and end
933 // positions in the buffers, but it only updates start for input buffers, and
934 // end for output buffers. Therefore, the Dart thread can simultaneously
935 // write to the free space and end pointer of input buffers, and read from
936 // the data space of output buffers, and modify the start pointer.
937 //
938 // When ProcessFilter returns, the Dart thread is responsible for combining
939 // the updated pointers from Dart and C++, to make the new valid state of
940 // the circular buffer.
941 CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
942 CObjectIntptr filter_object(request[0]);
943 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
944 RefCntReleaseScope<SSLFilter> rs(filter);
945
946 bool in_handshake = CObjectBool(request[1]).Value();
947 intptr_t starts[SSLFilter::kNumBuffers];
948 intptr_t ends[SSLFilter::kNumBuffers];
949 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
950 starts[i] = CObjectInt32(request[2 * i + 2]).Value();
951 ends[i] = CObjectInt32(request[2 * i + 3]).Value();
952 }
953
954 OSStatus status = filter->ProcessAllBuffers(starts, ends, in_handshake);
955 if (status == noErr) {
956 CObjectArray* result =
957 new CObjectArray(CObject::NewArray(SSLFilter::kNumBuffers * 2));
958 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
959 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i])));
960 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i])));
961 }
962 return result;
963 } else {
964 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
965 CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
966 if (error_string == NULL) {
967 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
968 static_cast<intptr_t>(status));
969 } else {
970 char* error = CFStringRefToCString(error_string);
971 status_message.Printf("OSStatus = %ld: %s", static_cast<intptr_t>(status),
972 error);
973 CFRelease(error_string);
974 }
975 CObjectArray* result = new CObjectArray(CObject::NewArray(2));
976 result->SetAt(0, new CObjectInt32(CObject::NewInt32(status)));
977 result->SetAt(1,
978 new CObjectString(CObject::NewString(status_message.buf())));
979 return result;
980 }
981 }
982
983
984 // Usually buffer_starts_ and buffer_ends_ are populated by ProcessAllBuffers,
985 // called from ProcessFilterRequest, called from the IOService thread.
986 // However, the first call to SSLHandshake comes from the Dart thread, and so
987 // doesn't go through there. This results in calls to SSLReadCallback and
988 // SSLWriteCallback in which buffer_starts_ and buffer_ends_ haven't been set
989 // up. In that case, since we're coming from Dart anyway, we can access the
990 // fieds directly from the Dart objects.
991 intptr_t SSLFilter::GetBufferStart(intptr_t idx) const {
992 if (buffer_starts_[idx] != NULL) {
993 return *buffer_starts_[idx];
994 }
995 Dart_Handle buffer_handle =
996 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
997 Dart_Handle start_handle =
998 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("start")));
999 int64_t start = DartUtils::GetIntegerValue(start_handle);
1000 return static_cast<intptr_t>(start);
1001 }
1002
1003
1004 intptr_t SSLFilter::GetBufferEnd(intptr_t idx) const {
1005 if (buffer_ends_[idx] != NULL) {
1006 return *buffer_ends_[idx];
1007 }
1008 Dart_Handle buffer_handle =
1009 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1010 Dart_Handle end_handle =
1011 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("end")));
1012 int64_t end = DartUtils::GetIntegerValue(end_handle);
1013 return static_cast<intptr_t>(end);
1014 }
1015
1016
1017 void SSLFilter::SetBufferStart(intptr_t idx, intptr_t value) {
1018 if (buffer_starts_[idx] != NULL) {
1019 *buffer_starts_[idx] = value;
1020 return;
1021 }
1022 Dart_Handle buffer_handle =
1023 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1024 ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "start",
1025 static_cast<int64_t>(value)));
1026 }
1027
1028
1029 void SSLFilter::SetBufferEnd(intptr_t idx, intptr_t value) {
1030 if (buffer_ends_[idx] != NULL) {
1031 *buffer_ends_[idx] = value;
1032 return;
1033 }
1034 Dart_Handle buffer_handle =
1035 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1036 ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "end",
1037 static_cast<int64_t>(value)));
1038 }
1039
1040
1041 OSStatus SSLFilter::ProcessAllBuffers(intptr_t starts[kNumBuffers],
1042 intptr_t ends[kNumBuffers],
1043 bool in_handshake) {
1044 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1045 buffer_starts_[i] = &starts[i];
1046 buffer_ends_[i] = &ends[i];
1047 }
1048
1049 if (in_handshake) {
1050 OSStatus status = Handshake();
1051 if (status != noErr) {
1052 return status;
1053 }
1054 } else {
1055 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1056 intptr_t start = starts[i];
1057 intptr_t end = ends[i];
1058 intptr_t size =
1059 isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1060 if (start < 0 || end < 0 || start >= size || end >= size) {
1061 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket");
1062 }
1063 switch (i) {
1064 case kReadPlaintext:
1065 // Write data to the circular buffer's free space. If the buffer
1066 // is full, neither if statement is executed and nothing happens.
1067 if (start <= end) {
1068 // If the free space may be split into two segments,
1069 // then the first is [end, size), unless start == 0.
1070 // Then, since the last free byte is at position start - 2,
1071 // the interval is [end, size - 1).
1072 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1073 intptr_t bytes = 0;
1074 OSStatus status =
1075 ProcessReadPlaintextBuffer(end, buffer_end, &bytes);
1076 if ((status != noErr) && (status != errSSLWouldBlock)) {
1077 return status;
1078 }
1079 end += bytes;
1080 ASSERT(end <= size);
1081 if (end == size) {
1082 end = 0;
1083 }
1084 }
1085 if (start > end + 1) {
1086 intptr_t bytes = 0;
1087 OSStatus status =
1088 ProcessReadPlaintextBuffer(end, start - 1, &bytes);
1089 if ((status != noErr) && (status != errSSLWouldBlock)) {
1090 return status;
1091 }
1092 end += bytes;
1093 ASSERT(end < start);
1094 }
1095 ends[i] = end;
1096 break;
1097 case kWritePlaintext:
1098 // Read/Write data from circular buffer. If the buffer is empty,
1099 // neither if statement's condition is true.
1100 if (end < start) {
1101 // Data may be split into two segments. In this case,
1102 // the first is [start, size).
1103 intptr_t bytes = 0;
1104 OSStatus status = ProcessWritePlaintextBuffer(start, size, &bytes);
1105 if ((status != noErr) && (status != errSSLWouldBlock)) {
1106 return status;
1107 }
1108 start += bytes;
1109 ASSERT(start <= size);
1110 if (start == size) {
1111 start = 0;
1112 }
1113 }
1114 if (start < end) {
1115 intptr_t bytes = 0;
1116 OSStatus status = ProcessWritePlaintextBuffer(start, end, &bytes);
1117 if ((status != noErr) && (status != errSSLWouldBlock)) {
1118 return status;
1119 }
1120 start += bytes;
1121 ASSERT(start <= end);
1122 }
1123 starts[i] = start;
1124 break;
1125 case kReadEncrypted:
1126 case kWriteEncrypted:
1127 // These buffers are advanced through SSLReadCallback and
1128 // SSLWriteCallback, which are called from SSLRead, SSLWrite, and
1129 // SSLHandshake.
1130 break;
1131 default:
1132 UNREACHABLE();
1133 }
1134 }
1135 }
1136
1137 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1138 buffer_starts_[i] = NULL;
1139 buffer_ends_[i] = NULL;
1140 }
1141 return noErr;
1142 }
1143
1144
1145 Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
1146 ASSERT(string_start_ == NULL);
1147 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
1148 ASSERT(string_start_ != NULL);
1149 ASSERT(string_length_ == NULL);
1150 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
1151 ASSERT(string_length_ != NULL);
1152 ASSERT(bad_certificate_callback_ == NULL);
1153 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
1154 ASSERT(bad_certificate_callback_ != NULL);
1155
1156 // Caller handles cleanup on an error.
1157 return InitializeBuffers(dart_this);
1158 }
1159
1160
1161 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
1162 // Create SSLFilter buffers as ExternalUint8Array objects.
1163 Dart_Handle buffers_string = DartUtils::NewString("buffers");
1164 RETURN_IF_ERROR(buffers_string);
1165 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
1166 RETURN_IF_ERROR(dart_buffers_object);
1167 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
1168 RETURN_IF_ERROR(secure_filter_impl_type);
1169 Dart_Handle size_string = DartUtils::NewString("SIZE");
1170 RETURN_IF_ERROR(size_string);
1171 Dart_Handle dart_buffer_size =
1172 Dart_GetField(secure_filter_impl_type, size_string);
1173 RETURN_IF_ERROR(dart_buffer_size);
1174
1175 int64_t buffer_size = 0;
1176 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
1177 RETURN_IF_ERROR(err);
1178
1179 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
1180 RETURN_IF_ERROR(encrypted_size_string);
1181
1182 Dart_Handle dart_encrypted_buffer_size =
1183 Dart_GetField(secure_filter_impl_type, encrypted_size_string);
1184 RETURN_IF_ERROR(dart_encrypted_buffer_size);
1185
1186 int64_t encrypted_buffer_size = 0;
1187 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
1188 RETURN_IF_ERROR(err);
1189
1190 if (buffer_size <= 0 || buffer_size > 1 * MB) {
1191 FATAL("Invalid buffer size in _ExternalBuffer");
1192 }
1193 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) {
1194 FATAL("Invalid encrypted buffer size in _ExternalBuffer");
1195 }
1196 buffer_size_ = static_cast<intptr_t>(buffer_size);
1197 encrypted_buffer_size_ = static_cast<intptr_t>(encrypted_buffer_size);
1198
1199 Dart_Handle data_identifier = DartUtils::NewString("data");
1200 RETURN_IF_ERROR(data_identifier);
1201
1202 for (int i = 0; i < kNumBuffers; i++) {
1203 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1204 buffers_[i] = new uint8_t[size];
1205 ASSERT(buffers_[i] != NULL);
1206 buffer_starts_[i] = NULL;
1207 buffer_ends_[i] = NULL;
1208 dart_buffer_objects_[i] = NULL;
1209 }
1210
1211 Dart_Handle result = Dart_Null();
1212 for (int i = 0; i < kNumBuffers; ++i) {
1213 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1214 result = Dart_ListGetAt(dart_buffers_object, i);
1215 if (Dart_IsError(result)) {
1216 break;
1217 }
1218
1219 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
1220 ASSERT(dart_buffer_objects_[i] != NULL);
1221 Dart_Handle data =
1222 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
1223 if (Dart_IsError(data)) {
1224 result = data;
1225 break;
1226 }
1227 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
1228 if (Dart_IsError(result)) {
1229 break;
1230 }
1231 result = Dart_SetField(result, data_identifier, data);
1232 if (Dart_IsError(result)) {
1233 break;
1234 }
1235 }
1236
1237 // Caller handles cleanup on an error.
1238 return result;
1239 }
1240
1241
1242 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
1243 ASSERT(NULL == handshake_complete_);
1244 handshake_complete_ = Dart_NewPersistentHandle(complete);
1245 ASSERT(handshake_complete_ != NULL);
1246 }
1247
1248
1249 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
1250 ASSERT(bad_certificate_callback_ != NULL);
1251 Dart_DeletePersistentHandle(bad_certificate_callback_);
1252 bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
1253 ASSERT(bad_certificate_callback_ != NULL);
1254 }
1255
1256
1257 Dart_Handle SSLFilter::PeerCertificate() {
1258 if (peer_certs_ == NULL) {
1259 return Dart_Null();
1260 }
1261
1262 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, 0);
1263 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1264 SecCertificateRef cert =
1265 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1266 if (cert == NULL) {
1267 return Dart_Null();
1268 }
1269
1270 return WrappedX509Certificate(cert);
1271 }
1272
1273
1274 void SSLFilter::Connect(Dart_Handle dart_this,
1275 const char* hostname,
1276 SSLCertContext* context,
1277 bool is_server,
1278 bool request_client_certificate,
1279 bool require_client_certificate) {
1280 if (in_handshake_) {
1281 FATAL("Connect called twice on the same _SecureFilter.");
1282 }
1283
1284 // Create the underlying context
1285 SSLContextRef ssl_context = SSLCreateContext(
1286 NULL, is_server ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
1287
1288 // Configure the context.
1289 OSStatus status;
1290 status = SSLSetPeerDomainName(ssl_context, hostname, strlen(hostname));
1291 CheckStatus(status, "TlsException", "Failed to set peer domain name");
1292
1293 status = SSLSetIOFuncs(ssl_context, SSLFilter::SSLReadCallback,
1294 SSLFilter::SSLWriteCallback);
1295 CheckStatus(status, "TlsException", "Failed to set IO Callbacks");
1296
1297 status =
1298 SSLSetConnection(ssl_context, reinterpret_cast<SSLConnectionRef>(this));
1299 CheckStatus(status, "TlsException", "Failed to set connection object");
1300
1301 // Always evaluate the certs manually so that we can cache the peer
1302 // certificates in the context for calls to peerCertificate.
1303 status = SSLSetSessionOption(ssl_context, kSSLSessionOptionBreakOnServerAuth,
1304 true);
1305 CheckStatus(status, "TlsException", "Failed to set BreakOnServerAuth option");
1306
1307 status = SSLSetProtocolVersionMin(ssl_context, kTLSProtocol1);
1308 CheckStatus(status, "TlsException",
1309 "Failed to set minimum protocol version to kTLSProtocol1");
1310
1311 // If the context has a private key and certificate chain, combine the
1312 // private key and first certificate into a SecIdentityRef, and place that
1313 // and the remaining certs in an array to pass to SSLSetCertificate().
1314 if ((context->private_key() != NULL) && (context->cert_chain() != NULL)) {
1315 CFIndex chain_length = CFArrayGetCount(context->cert_chain());
1316 CFMutableArrayRef certs =
1317 CFArrayCreateMutable(NULL, chain_length, &kCFTypeArrayCallBacks);
1318 CFTypeRef item = CFArrayGetValueAtIndex(context->cert_chain(), 0);
1319 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1320 SecCertificateRef first_cert =
1321 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1322 SecIdentityRef identity =
1323 SecIdentityCreate(NULL, first_cert, context->private_key());
1324 CFArrayAppendValue(certs, identity);
1325 for (CFIndex i = 0; i < chain_length; i++) {
1326 CFArrayAppendValue(certs,
1327 CFArrayGetValueAtIndex(context->cert_chain(), i));
1328 }
1329 CFRelease(identity);
1330 status = SSLSetCertificate(ssl_context, certs);
1331 CFRelease(certs);
1332 CheckStatus(status, "TlsException", "SSLSetCertificate failed");
1333 }
1334
1335 if (context->cert_authorities() != NULL) {
1336 status = SSLSetCertificateAuthorities(ssl_context,
1337 context->cert_authorities(), true);
1338 CheckStatus(status, "TlsException",
1339 "Failed to set certificate authorities");
1340 }
1341
1342 if (is_server) {
1343 SSLAuthenticate auth =
1344 require_client_certificate
1345 ? kAlwaysAuthenticate
1346 : (request_client_certificate ? kTryAuthenticate
1347 : kNeverAuthenticate);
1348 status = SSLSetClientSideAuthenticate(ssl_context, auth);
1349 CheckStatus(status, "TlsException",
1350 "Failed to set client authentication mode");
1351
1352 // If we're at least trying client authentication, then break handshake
1353 // for client authentication.
1354 if (auth != kNeverAuthenticate) {
1355 status = SSLSetSessionOption(ssl_context,
1356 kSSLSessionOptionBreakOnClientAuth, true);
1357 CheckStatus(status, "TlsException",
1358 "Failed to set client authentication mode");
1359 }
1360 }
1361
1362 // Add the contexts to our wrapper.
1363 cert_context_.set(context);
1364 ssl_context_ = ssl_context;
1365 is_server_ = is_server;
1366
1367 // Kick-off the handshake. Expect the handshake to need more data.
1368 // SSLHandshake calls our SSLReadCallback and SSLWriteCallback.
1369 status = SSLHandshake(ssl_context);
1370 ASSERT(status != noErr);
1371 if (status == errSSLWouldBlock) {
1372 status = noErr;
1373 in_handshake_ = true;
1374 }
1375 CheckStatus(status, "HandshakeException", is_server_
1376 ? "Handshake error in server"
1377 : "Handshake error in client");
1378 }
1379
1380
1381 OSStatus SSLFilter::EvaluatePeerTrust() {
1382 OSStatus status = noErr;
1383
1384 if (SSL_LOG_STATUS) {
1385 Log::Print("Handshake evaluating trust.\n");
1386 }
1387 SecTrustRef peer_trust = NULL;
1388 status = SSLCopyPeerTrust(ssl_context_, &peer_trust);
1389 if (status != noErr) {
1390 if (is_server_ && (status == errSSLBadCert)) {
1391 // A client certificate was requested, but not required, and wasn't sent.
1392 return noErr;
1393 }
1394 if (SSL_LOG_STATUS) {
1395 Log::Print("Handshake error from SSLCopyPeerTrust(): %ld.\n",
1396 static_cast<intptr_t>(status));
1397 }
1398 return status;
1399 }
1400
1401 CFArrayRef trusted_certs = NULL;
1402 if (cert_context_.get()->trusted_certs() != NULL) {
1403 trusted_certs =
1404 CFArrayCreateCopy(NULL, cert_context_.get()->trusted_certs());
1405 } else {
1406 trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
1407 }
1408
1409 status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs);
1410 if (status != noErr) {
1411 if (SSL_LOG_STATUS) {
1412 Log::Print("Handshake error from SecTrustSetAnchorCertificates: %ld\n",
1413 static_cast<intptr_t>(status));
1414 }
1415 CFRelease(trusted_certs);
1416 CFRelease(peer_trust);
1417 return status;
1418 }
1419
1420 if (SSL_LOG_STATUS) {
1421 Log::Print(
1422 "Handshake %s built in root certs\n",
1423 cert_context_.get()->trust_builtin() ? "trusting" : "not trusting");
1424 }
1425
1426 status = SecTrustSetAnchorCertificatesOnly(
1427 peer_trust, !cert_context_.get()->trust_builtin());
1428 if (status != noErr) {
1429 CFRelease(trusted_certs);
1430 CFRelease(peer_trust);
1431 return status;
1432 }
1433
1434 SecTrustResultType trust_result;
1435 status = SecTrustEvaluate(peer_trust, &trust_result);
1436 if (status != noErr) {
1437 CFRelease(trusted_certs);
1438 CFRelease(peer_trust);
1439 return status;
1440 }
1441
1442 // Grab the peer's certificate chain.
1443 CFIndex peer_chain_length = SecTrustGetCertificateCount(peer_trust);
1444 CFMutableArrayRef peer_certs =
1445 CFArrayCreateMutable(NULL, peer_chain_length, &kCFTypeArrayCallBacks);
1446 for (CFIndex i = 0; i < peer_chain_length; ++i) {
1447 CFArrayAppendValue(peer_certs,
1448 SecTrustGetCertificateAtIndex(peer_trust, i));
1449 }
1450 peer_certs_ = peer_certs;
1451
1452 CFRelease(trusted_certs);
1453 CFRelease(peer_trust);
1454
1455 if ((trust_result == kSecTrustResultProceed) ||
1456 (trust_result == kSecTrustResultUnspecified)) {
1457 // Trusted.
1458 return noErr;
1459 } else {
1460 if (SSL_LOG_STATUS) {
1461 Log::Print("Trust eval failed: trust_restul = %d\n", trust_result);
1462 }
1463 bad_cert_ = true;
1464 return errSSLBadCert;
1465 }
1466 }
1467
1468
1469 OSStatus SSLFilter::Handshake() {
1470 ASSERT(cert_context_.get() != NULL);
1471 ASSERT(ssl_context_ != NULL);
1472 // Try and push handshake along.
1473 if (SSL_LOG_STATUS) {
1474 Log::Print("Doing SSLHandshake\n");
1475 }
1476 OSStatus status = SSLHandshake(ssl_context_);
1477 if (SSL_LOG_STATUS) {
1478 Log::Print("SSLHandshake returned %ld\n", static_cast<intptr_t>(status));
1479 }
1480
1481 if ((status == errSSLServerAuthCompleted) ||
1482 (status == errSSLClientAuthCompleted)) {
1483 status = EvaluatePeerTrust();
1484 if (status == errSSLBadCert) {
1485 // Need to invoke the bad certificate callback.
1486 return noErr;
1487 } else if (status != noErr) {
1488 return status;
1489 }
1490 // When trust evaluation succeeds, we can call SSLHandshake again
1491 // immediately.
1492 status = SSLHandshake(ssl_context_);
1493 }
1494
1495 if (status == errSSLWouldBlock) {
1496 in_handshake_ = true;
1497 return noErr;
1498 }
1499
1500 // Handshake succeeded.
1501 if ((in_handshake_) && (status == noErr)) {
1502 if (SSL_LOG_STATUS) {
1503 Log::Print("Finished with the Handshake\n");
1504 }
1505 connected_ = true;
1506 }
1507 return status;
1508 }
1509
1510
1511 // Returns false if Handshake should fail, and true if Handshake should
1512 // proceed.
1513 Dart_Handle SSLFilter::InvokeBadCertCallback(SecCertificateRef peer_cert) {
1514 Dart_Handle callback = bad_certificate_callback_;
1515 if (Dart_IsNull(callback)) {
1516 return callback;
1517 }
1518 Dart_Handle args[1];
1519 args[0] = WrappedX509Certificate(peer_cert);
1520 if (Dart_IsError(args[0])) {
1521 return args[0];
1522 }
1523 Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
1524 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
1525 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
1526 "HandshakeException",
1527 "BadCertificateCallback returned a value that was not a boolean",
1528 Dart_Null()));
1529 }
1530 return result;
1531 }
1532
1533
1534 OSStatus SSLFilter::CheckHandshake() {
1535 if (bad_cert_ && in_handshake_) {
1536 if (SSL_LOG_STATUS) {
1537 Log::Print("Invoking bad certificate callback\n");
1538 }
1539 ASSERT(peer_certs_ != NULL);
1540 CFIndex peer_certs_len = CFArrayGetCount(peer_certs_);
1541 ASSERT(peer_certs_len > 0);
1542 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, peer_certs_len - 1);
1543 ASSERT(item != NULL);
1544 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1545 SecCertificateRef peer_cert =
1546 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1547 Dart_Handle result = InvokeBadCertCallback(peer_cert);
1548 ThrowIfError(result);
1549 if (Dart_IsNull(result)) {
1550 return errSSLBadCert;
1551 } else {
1552 bool good_cert = DartUtils::GetBooleanValue(result);
1553 bad_cert_ = !good_cert;
1554 return good_cert ? noErr : errSSLBadCert;
1555 }
1556 }
1557
1558 if (connected_ && in_handshake_) {
1559 if (SSL_LOG_STATUS) {
1560 Log::Print("Invoking handshake complete callback\n");
1561 }
1562 ThrowIfError(Dart_InvokeClosure(
1563 Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
1564 in_handshake_ = false;
1565 }
1566 return noErr;
1567 }
1568
1569
1570 void SSLFilter::Renegotiate(bool use_session_cache,
1571 bool request_client_certificate,
1572 bool require_client_certificate) {
1573 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the
1574 // SSL_REQUEST_CERTIFICATE option is also set, so set it.
1575 request_client_certificate =
1576 request_client_certificate || require_client_certificate;
1577 // TODO(24070, 24069): Implement setting the client certificate parameters,
1578 // and triggering rehandshake.
1579 }
1580
1581
1582 SSLFilter::~SSLFilter() {
1583 if (ssl_context_ != NULL) {
1584 CFRelease(ssl_context_);
1585 ssl_context_ = NULL;
1586 }
1587 if (peer_certs_ != NULL) {
1588 CFRelease(peer_certs_);
1589 peer_certs_ = NULL;
1590 }
1591 if (hostname_ != NULL) {
1592 free(hostname_);
1593 hostname_ = NULL;
1594 }
1595 for (int i = 0; i < kNumBuffers; ++i) {
1596 if (buffers_[i] != NULL) {
1597 delete[] buffers_[i];
1598 buffers_[i] = NULL;
1599 }
1600 }
1601 }
1602
1603
1604 void SSLFilter::Destroy() {
1605 if (ssl_context_ != NULL) {
1606 SSLClose(ssl_context_);
1607 }
1608 for (int i = 0; i < kNumBuffers; ++i) {
1609 if (dart_buffer_objects_[i] != NULL) {
1610 Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
1611 dart_buffer_objects_[i] = NULL;
1612 }
1613 }
1614 if (string_start_ != NULL) {
1615 Dart_DeletePersistentHandle(string_start_);
1616 string_start_ = NULL;
1617 }
1618 if (string_length_ != NULL) {
1619 Dart_DeletePersistentHandle(string_length_);
1620 string_length_ = NULL;
1621 }
1622 if (handshake_complete_ != NULL) {
1623 Dart_DeletePersistentHandle(handshake_complete_);
1624 handshake_complete_ = NULL;
1625 }
1626 if (bad_certificate_callback_ != NULL) {
1627 Dart_DeletePersistentHandle(bad_certificate_callback_);
1628 bad_certificate_callback_ = NULL;
1629 }
1630 }
1631
1632
1633 OSStatus SSLFilter::SSLReadCallback(SSLConnectionRef connection,
1634 void* data,
1635 size_t* data_requested) {
1636 // Copy at most `data_requested` bytes from `buffers_[kReadEncrypted]` into
1637 // `data`
1638 ASSERT(connection != NULL);
1639 ASSERT(data != NULL);
1640 ASSERT(data_requested != NULL);
1641
1642 SSLFilter* filter =
1643 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1644 uint8_t* datap = reinterpret_cast<uint8_t*>(data);
1645 uint8_t* buffer = filter->buffers_[kReadEncrypted];
1646 intptr_t start = filter->GetBufferStart(kReadEncrypted);
1647 intptr_t end = filter->GetBufferEnd(kReadEncrypted);
1648 intptr_t size = filter->encrypted_buffer_size_;
1649 intptr_t requested = static_cast<intptr_t>(*data_requested);
1650 intptr_t data_read = 0;
1651
1652 if (end < start) {
1653 // Data may be split into two segments. In this case,
1654 // the first is [start, size).
1655 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1656 intptr_t available = buffer_end - start;
1657 intptr_t bytes = requested < available ? requested : available;
1658 memmove(datap, &buffer[start], bytes);
1659 start += bytes;
1660 datap += bytes;
1661 data_read += bytes;
1662 requested -= bytes;
1663 ASSERT(start <= size);
1664 if (start == size) {
1665 start = 0;
1666 }
1667 }
1668 if ((requested > 0) && (start < end)) {
1669 intptr_t available = end - start;
1670 intptr_t bytes = requested < available ? requested : available;
1671 memmove(datap, &buffer[start], bytes);
1672 start += bytes;
1673 datap += bytes;
1674 data_read += bytes;
1675 requested -= bytes;
1676 ASSERT(start <= end);
1677 }
1678
1679 if (SSL_LOG_DATA) {
1680 Log::Print("SSLReadCallback: requested: %ld, read %ld bytes\n",
1681 *data_requested, data_read);
1682 }
1683
1684 filter->SetBufferStart(kReadEncrypted, start);
1685 bool short_read = data_read < static_cast<intptr_t>(*data_requested);
1686 *data_requested = data_read;
1687 return short_read ? errSSLWouldBlock : noErr;
1688 }
1689
1690
1691 // Read decrypted data from the filter to the circular buffer.
1692 OSStatus SSLFilter::ProcessReadPlaintextBuffer(intptr_t start,
1693 intptr_t end,
1694 intptr_t* bytes_processed) {
1695 ASSERT(bytes_processed != NULL);
1696 intptr_t length = end - start;
1697 OSStatus status = noErr;
1698 size_t bytes = 0;
1699 if (length > 0) {
1700 status =
1701 SSLRead(ssl_context_,
1702 reinterpret_cast<void*>((buffers_[kReadPlaintext] + start)),
1703 length, &bytes);
1704 if (SSL_LOG_STATUS) {
1705 Log::Print("SSLRead: status = %ld\n", static_cast<intptr_t>(status));
1706 }
1707 if ((status != noErr) && (status != errSSLWouldBlock)) {
1708 *bytes_processed = 0;
1709 return status;
1710 }
1711 }
1712 if (SSL_LOG_DATA) {
1713 Log::Print("ProcessReadPlaintextBuffer: requested: %ld, read %ld bytes\n",
1714 length, bytes);
1715 }
1716 *bytes_processed = static_cast<intptr_t>(bytes);
1717 return status;
1718 }
1719
1720
1721 OSStatus SSLFilter::SSLWriteCallback(SSLConnectionRef connection,
1722 const void* data,
1723 size_t* data_provided) {
1724 // Copy at most `data_provided` bytes from data into
1725 // `buffers_[kWriteEncrypted]`.
1726 ASSERT(connection != NULL);
1727 ASSERT(data != NULL);
1728 ASSERT(data_provided != NULL);
1729
1730 SSLFilter* filter =
1731 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1732 const uint8_t* datap = reinterpret_cast<const uint8_t*>(data);
1733 uint8_t* buffer = filter->buffers_[kWriteEncrypted];
1734 intptr_t start = filter->GetBufferStart(kWriteEncrypted);
1735 intptr_t end = filter->GetBufferEnd(kWriteEncrypted);
1736 intptr_t size = filter->encrypted_buffer_size_;
1737 intptr_t provided = static_cast<intptr_t>(*data_provided);
1738 intptr_t data_written = 0;
1739
1740 // is full, neither if statement is executed and nothing happens.
1741 if (start <= end) {
1742 // If the free space may be split into two segments,
1743 // then the first is [end, size), unless start == 0.
1744 // Then, since the last free byte is at position start - 2,
1745 // the interval is [end, size - 1).
1746 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1747 intptr_t available = buffer_end - end;
1748 intptr_t bytes = provided < available ? provided : available;
1749 memmove(&buffer[end], datap, bytes);
1750 end += bytes;
1751 datap += bytes;
1752 data_written += bytes;
1753 provided -= bytes;
1754 ASSERT(end <= size);
1755 if (end == size) {
1756 end = 0;
1757 }
1758 }
1759 if ((provided > 0) && (start > end + 1)) {
1760 intptr_t available = (start - 1) - end;
1761 intptr_t bytes = provided < available ? provided : available;
1762 memmove(&buffer[end], datap, bytes);
1763 end += bytes;
1764 datap += bytes;
1765 data_written += bytes;
1766 provided -= bytes;
1767 ASSERT(end < start);
1768 }
1769
1770 if (SSL_LOG_DATA) {
1771 Log::Print("SSLWriteCallback: provided: %ld, written %ld bytes\n",
1772 *data_provided, data_written);
1773 }
1774
1775 filter->SetBufferEnd(kWriteEncrypted, end);
1776 *data_provided = data_written;
1777 return (data_written == 0) ? errSSLWouldBlock : noErr;
1778 }
1779
1780
1781 OSStatus SSLFilter::ProcessWritePlaintextBuffer(intptr_t start,
1782 intptr_t end,
1783 intptr_t* bytes_processed) {
1784 ASSERT(bytes_processed != NULL);
1785 intptr_t length = end - start;
1786 OSStatus status = noErr;
1787 size_t bytes = 0;
1788 if (length > 0) {
1789 status =
1790 SSLWrite(ssl_context_,
1791 reinterpret_cast<void*>(buffers_[kWritePlaintext] + start),
1792 length, &bytes);
1793 if (SSL_LOG_STATUS) {
1794 Log::Print("SSLWrite: status = %ld\n", static_cast<intptr_t>(status));
1795 }
1796 if ((status != noErr) && (status != errSSLWouldBlock)) {
1797 *bytes_processed = 0;
1798 return status;
1799 }
1800 }
1801 if (SSL_LOG_DATA) {
1802 Log::Print("ProcessWritePlaintextBuffer: requested: %ld, written: %ld\n",
1803 length, bytes);
1804 }
1805 *bytes_processed = static_cast<intptr_t>(bytes);
1806 return status;
1807 }
1808
1809 } // namespace bin
1810 } // namespace dart
1811
1812 #endif // defined(HOST_OS_MACOS) && !HOST_OS_IOS
1813
1814 #endif // !defined(DART_IO_DISABLED) &&
1815 // !defined(DART_IO_SECURE_SOCKET_DISABLED)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698