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

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

Issue 2903743002: Porting SecureSocket to use BoringSSL on OSX (Closed)
Patch Set: Addressed missed comment from last patch set 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 HOST_OS_IOS
9
10 #include "bin/secure_socket.h"
11 #include "bin/secure_socket_ios.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 namespace dart {
47 namespace bin {
48
49 static const int kSSLFilterNativeFieldIndex = 0;
50 static const int kSecurityContextNativeFieldIndex = 0;
51 static const int kX509NativeFieldIndex = 0;
52
53 static const bool SSL_LOG_STATUS = false;
54 static const bool SSL_LOG_DATA = false;
55 static const bool SSL_LOG_CERTS = false;
56 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
57 static const intptr_t PEM_BUFSIZE = 1024;
58
59 static char* CFStringRefToCString(CFStringRef cfstring) {
60 CFIndex len = CFStringGetLength(cfstring);
61 CFIndex max_len =
62 CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
63 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
64 ASSERT(result != NULL);
65 bool success =
66 CFStringGetCString(cfstring, result, max_len, kCFStringEncodingUTF8);
67 return success ? result : NULL;
68 }
69
70
71 // Handle an error reported from the SecureTransport library.
72 static void ThrowIOException(OSStatus status,
73 const char* exception_type,
74 const char* message) {
75 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
76 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
77 static_cast<intptr_t>(status));
78 OSError os_error_struct(status, status_message.buf(), OSError::kBoringSSL);
79 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
80 Dart_Handle exception =
81 DartUtils::NewDartIOException(exception_type, message, os_error);
82 ASSERT(!Dart_IsError(exception));
83 Dart_ThrowException(exception);
84 UNREACHABLE();
85 }
86
87
88 static void CheckStatus(OSStatus status,
89 const char* type,
90 const char* message) {
91 if (status == noErr) {
92 return;
93 }
94 ThrowIOException(status, type, message);
95 }
96
97
98 static SSLFilter* GetFilter(Dart_NativeArguments args) {
99 SSLFilter* filter;
100 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
101 ASSERT(Dart_IsInstance(dart_this));
102 ThrowIfError(
103 Dart_GetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
104 reinterpret_cast<intptr_t*>(&filter)));
105 return filter;
106 }
107
108
109 static void DeleteFilter(void* isolate_data,
110 Dart_WeakPersistentHandle handle,
111 void* context_pointer) {
112 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
113 filter->Release();
114 }
115
116
117 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
118 ASSERT(filter != NULL);
119 const int approximate_size_of_filter = 1500;
120 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
121 RETURN_IF_ERROR(dart_this);
122 ASSERT(Dart_IsInstance(dart_this));
123 Dart_Handle err =
124 Dart_SetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
125 reinterpret_cast<intptr_t>(filter));
126 RETURN_IF_ERROR(err);
127 Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter),
128 approximate_size_of_filter, DeleteFilter);
129 return Dart_Null();
130 }
131
132
133 static SSLCertContext* GetSecurityContext(Dart_NativeArguments args) {
134 SSLCertContext* context;
135 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
136 ASSERT(Dart_IsInstance(dart_this));
137 ThrowIfError(
138 Dart_GetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
139 reinterpret_cast<intptr_t*>(&context)));
140 return context;
141 }
142
143
144 static void DeleteCertContext(void* isolate_data,
145 Dart_WeakPersistentHandle handle,
146 void* context_pointer) {
147 SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
148 context->Release();
149 }
150
151
152 static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
153 SSLCertContext* context) {
154 const int approximate_size_of_context = 1500;
155 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
156 RETURN_IF_ERROR(dart_this);
157 ASSERT(Dart_IsInstance(dart_this));
158 Dart_Handle err =
159 Dart_SetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
160 reinterpret_cast<intptr_t>(context));
161 RETURN_IF_ERROR(err);
162 Dart_NewWeakPersistentHandle(dart_this, context, approximate_size_of_context,
163 DeleteCertContext);
164 return Dart_Null();
165 }
166
167
168 static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
169 SecCertificateRef certificate;
170 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
171 ASSERT(Dart_IsInstance(dart_this));
172 ThrowIfError(
173 Dart_GetNativeInstanceField(dart_this, kX509NativeFieldIndex,
174 reinterpret_cast<intptr_t*>(&certificate)));
175 return certificate;
176 }
177
178
179 static void ReleaseCertificate(void* isolate_data,
180 Dart_WeakPersistentHandle handle,
181 void* context_pointer) {
182 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(context_pointer);
183 CFRelease(cert);
184 }
185
186
187 static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) {
188 const intptr_t approximate_size_of_certificate = 1500;
189 if (certificate == NULL) {
190 return Dart_Null();
191 }
192 Dart_Handle x509_type =
193 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
194 if (Dart_IsError(x509_type)) {
195 return x509_type;
196 }
197 Dart_Handle arguments[] = {NULL};
198
199 Dart_Handle result =
200 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
201 if (Dart_IsError(result)) {
202 return result;
203 }
204 ASSERT(Dart_IsInstance(result));
205
206 // CFRetain in case the returned Dart object outlives the SecurityContext.
207 // CFRelease is in the Dart object's finalizer
208 CFRetain(certificate);
209 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate),
210 approximate_size_of_certificate,
211 ReleaseCertificate);
212
213 Dart_Handle status = Dart_SetNativeInstanceField(
214 result, kX509NativeFieldIndex, reinterpret_cast<intptr_t>(certificate));
215 if (Dart_IsError(status)) {
216 return status;
217 }
218 return result;
219 }
220
221
222 static const char* GetPasswordArgument(Dart_NativeArguments args,
223 intptr_t index) {
224 Dart_Handle password_object =
225 ThrowIfError(Dart_GetNativeArgument(args, index));
226 const char* password = NULL;
227 if (Dart_IsString(password_object)) {
228 ThrowIfError(Dart_StringToCString(password_object, &password));
229 if (strlen(password) > PEM_BUFSIZE - 1) {
230 Dart_ThrowException(DartUtils::NewDartArgumentError(
231 "Password length is greater than 1023 bytes."));
232 }
233 } else if (Dart_IsNull(password_object)) {
234 password = "";
235 } else {
236 Dart_ThrowException(
237 DartUtils::NewDartArgumentError("Password is not a String or null"));
238 }
239 return password;
240 }
241
242
243 static OSStatus TryPKCS12Import(CFDataRef cfdata,
244 CFStringRef password,
245 CFArrayRef* out_certs,
246 SecIdentityRef* out_identity) {
247 const void* keys[] = {kSecImportExportPassphrase};
248 const void* values[] = {password};
249 CFDictionaryRef params =
250 CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
251 CFArrayRef items = NULL;
252 OSStatus status = SecPKCS12Import(cfdata, params, &items);
253 CFRelease(params);
254
255 if (status != noErr) {
256 if (SSL_LOG_STATUS) {
257 Log::PrintErr("SecPKCS12Import: status = %ld",
258 static_cast<intptr_t>(status));
259 return status;
260 }
261 }
262
263 CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
264 if (SSL_LOG_CERTS) {
265 Log::PrintErr("TryPKCS12Import succeeded, count = %ld\n", items_length);
266 }
267
268 // Empty list indicates a decoding failure of some sort.
269 if ((items != NULL) && (items_length == 0)) {
270 CFRelease(items);
271 return errSSLBadCert;
272 }
273
274 CFMutableArrayRef result_certs =
275 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
276 SecIdentityRef result_identity = NULL;
277
278 for (CFIndex i = 0; i < items_length; i++) {
279 CFTypeRef item =
280 reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(items, i));
281 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
282 CFDictionaryRef dict = reinterpret_cast<CFDictionaryRef>(item);
283
284 // Trust.
285 CFTypeRef trust_item = CFDictionaryGetValue(dict, kSecImportItemTrust);
286 if (trust_item != NULL) {
287 ASSERT(CFGetTypeID(trust_item) == SecTrustGetTypeID());
288 if (SSL_LOG_CERTS) {
289 Log::PrintErr("\titem %ld has a trust object\n", i);
290 }
291 // TODO(zra): Is this useful for anything?
292 }
293
294 // Identity.
295 CFTypeRef identity_item =
296 CFDictionaryGetValue(dict, kSecImportItemIdentity);
297 if (identity_item != NULL) {
298 ASSERT(CFGetTypeID(identity_item) == SecIdentityGetTypeID());
299 if (SSL_LOG_CERTS) {
300 Log::PrintErr("\titem %ld has an identity object\n", i);
301 }
302 // Only extract the first identity we find.
303 if (result_identity == NULL) {
304 result_identity =
305 reinterpret_cast<SecIdentityRef>(const_cast<void*>(identity_item));
306 CFRetain(result_identity);
307 }
308 }
309
310 // Certificates.
311 CFTypeRef cert_items = CFDictionaryGetValue(dict, kSecImportItemCertChain);
312 if (cert_items != NULL) {
313 ASSERT(CFGetTypeID(cert_items) == CFArrayGetTypeID());
314 CFArrayRef certs = reinterpret_cast<CFArrayRef>(cert_items);
315 if (SSL_LOG_CERTS) {
316 CFIndex count = CFArrayGetCount(certs);
317 Log::PrintErr("\titem %ld has a cert chain %ld certs long\n", i, count);
318 }
319 CFArrayAppendArray(result_certs, certs,
320 CFRangeMake(0, CFArrayGetCount(certs)));
321 }
322 }
323
324 if (out_certs == NULL) {
325 if (result_certs != NULL) {
326 CFRelease(result_certs);
327 }
328 } else {
329 *out_certs = result_certs;
330 }
331
332 if (out_identity == NULL) {
333 if (result_identity != NULL) {
334 CFRelease(result_identity);
335 }
336 } else {
337 *out_identity = result_identity;
338 }
339
340 // On failure, don't return any objects.
341 ASSERT((status == noErr) ||
342 ((result_certs == NULL) && (result_identity == NULL)));
343 return status;
344 }
345
346
347 static OSStatus ExtractSecItems(uint8_t* buffer,
348 intptr_t length,
349 const char* password,
350 CFArrayRef* out_certs,
351 SecIdentityRef* out_identity) {
352 ASSERT(buffer != NULL);
353 ASSERT(password != NULL);
354 OSStatus status = noErr;
355
356 CFDataRef cfdata =
357 CFDataCreateWithBytesNoCopy(NULL, buffer, length, kCFAllocatorNull);
358 CFStringRef cfpassword = CFStringCreateWithCStringNoCopy(
359 NULL, password, kCFStringEncodingUTF8, kCFAllocatorNull);
360 ASSERT(cfdata != NULL);
361 ASSERT(cfpassword != NULL);
362
363 status = TryPKCS12Import(cfdata, cfpassword, out_certs, out_identity);
364
365 CFRelease(cfdata);
366 CFRelease(cfpassword);
367 return status;
368 }
369
370
371 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
372 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
373 SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer.
374 Dart_Handle err = SetFilter(args, filter);
375 if (Dart_IsError(err)) {
376 filter->Release();
377 Dart_PropagateError(err);
378 }
379 err = filter->Init(dart_this);
380 if (Dart_IsError(err)) {
381 // The finalizer was set up by SetFilter. It will delete `filter` if there
382 // is an error.
383 filter->Destroy();
384 Dart_PropagateError(err);
385 }
386 }
387
388
389 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
390 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
391 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
392 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
393 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
394 bool request_client_certificate =
395 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
396 bool require_client_certificate =
397 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
398
399 const char* host_name = NULL;
400 // TODO(whesse): Is truncating a Dart string containing \0 what we want?
401 ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
402
403 SSLCertContext* context = NULL;
404 if (!Dart_IsNull(context_object)) {
405 ThrowIfError(Dart_GetNativeInstanceField(
406 context_object, kSecurityContextNativeFieldIndex,
407 reinterpret_cast<intptr_t*>(&context)));
408 }
409
410 GetFilter(args)->Connect(dart_this, host_name, context, is_server,
411 request_client_certificate,
412 require_client_certificate);
413 }
414
415
416 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
417 SSLFilter* filter = GetFilter(args);
418 // The SSLFilter is deleted in the finalizer for the Dart object created by
419 // SetFilter. There is no need to NULL-out the native field for the SSLFilter
420 // here because the SSLFilter won't be deleted until the finalizer for the
421 // Dart object runs while the Dart object is being GCd. This approach avoids a
422 // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is
423 // called more than once.
424 filter->Destroy();
425 }
426
427
428 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
429 OSStatus status = GetFilter(args)->CheckHandshake();
430 CheckStatus(status, "HandshakeException", "Handshake error");
431 }
432
433
434 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)(
435 Dart_NativeArguments args) {
436 Dart_SetReturnValue(args, Dart_Null());
437 }
438
439
440 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
441 bool use_session_cache =
442 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1));
443 bool request_client_certificate =
444 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
445 bool require_client_certificate =
446 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
447 GetFilter(args)->Renegotiate(use_session_cache, request_client_certificate,
448 require_client_certificate);
449 }
450
451
452 void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
453 Dart_NativeArguments args) {
454 Dart_Handle handshake_complete =
455 ThrowIfError(Dart_GetNativeArgument(args, 1));
456 if (!Dart_IsClosure(handshake_complete)) {
457 Dart_ThrowException(DartUtils::NewDartArgumentError(
458 "Illegal argument to RegisterHandshakeCompleteCallback"));
459 }
460 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
461 }
462
463
464 void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
465 Dart_NativeArguments args) {
466 Dart_Handle callback = ThrowIfError(Dart_GetNativeArgument(args, 1));
467 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
468 Dart_ThrowException(DartUtils::NewDartArgumentError(
469 "Illegal argument to RegisterBadCertificateCallback"));
470 }
471 GetFilter(args)->RegisterBadCertificateCallback(callback);
472 }
473
474
475 void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) {
476 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
477 }
478
479
480 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
481 SSLFilter* filter = GetFilter(args);
482 // This filter pointer is passed to the IO Service thread. The IO Service
483 // thread must Release() the pointer when it is done with it.
484 filter->Retain();
485 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
486 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
487 }
488
489
490 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
491 SSLCertContext* cert_context = new SSLCertContext();
492 // cert_context deleted in DeleteCertContext finalizer.
493 Dart_Handle err = SetSecurityContext(args, cert_context);
494 if (Dart_IsError(err)) {
495 cert_context->Release();
496 Dart_PropagateError(err);
497 }
498 }
499
500
501 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
502 Dart_NativeArguments args) {
503 SSLCertContext* context = GetSecurityContext(args);
504 const char* password = GetPasswordArgument(args, 2);
505
506 OSStatus status;
507 CFArrayRef cert_chain = NULL;
508 SecIdentityRef identity = NULL;
509 {
510 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
511 status = ExtractSecItems(buffer.get(), buffer.length(), password,
512 &cert_chain, &identity);
513 }
514
515 // Set the context fields. Repeated calls to usePrivateKeyBytes are an error.
516 bool set_failure = false;
517 if ((identity != NULL) && !context->set_identity(identity)) {
518 CFRelease(identity);
519 if (cert_chain != NULL) {
520 CFRelease(cert_chain);
521 }
522 set_failure = true;
523 }
524
525 // We can't have set a cert_chain without also having set an identity.
526 // That is, if context->set_identity() succeeds, then it is impossible for
527 // context->set_cert_chain() to fail. This is because SecPKCS12Import never
528 // returns a cert chain without also returning a private key.
529 ASSERT(set_failure || (context->cert_chain() == NULL));
530 if (!set_failure && (cert_chain != NULL)) {
531 context->set_cert_chain(cert_chain);
532 }
533
534 if (set_failure) {
535 Dart_ThrowException(DartUtils::NewDartArgumentError(
536 "usePrivateKeyBytes has already been called on the given context."));
537 }
538 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
539 }
540
541
542 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
543 Dart_NativeArguments args) {
544 SSLCertContext* context = GetSecurityContext(args);
545
546 OSStatus status = noErr;
547 SecCertificateRef cert = NULL;
548 {
549 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
550 CFDataRef cfdata = CFDataCreateWithBytesNoCopy(
551 NULL, buffer.get(), buffer.length(), kCFAllocatorNull);
552 cert = SecCertificateCreateWithData(NULL, cfdata);
553 CFRelease(cfdata);
554 }
555
556 // Add the certs to the context.
557 if (cert != NULL) {
558 context->add_trusted_cert(cert);
559 } else {
560 status = errSSLBadCert;
561 }
562 CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes");
563 }
564
565
566 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
567 Dart_SetReturnValue(args, Dart_NewBoolean(false));
568 }
569
570
571 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
572 Dart_NativeArguments args) {
573 SSLCertContext* context = GetSecurityContext(args);
574 context->set_trust_builtin(true);
575 }
576
577
578 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
579 Dart_NativeArguments args) {
580 // This is a no-op on iOS. We get the cert chain along with the private key
581 // in UsePrivateyKeyBytes().
582 }
583
584
585 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
586 Dart_NativeArguments args) {
587 Dart_ThrowException(DartUtils::NewDartUnsupportedError(
588 "SecurityContext.setClientAuthoritiesBytes is not supported on this "
589 "platform."));
590 }
591
592
593 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
594 Dart_NativeArguments args) {
595 Dart_ThrowException(DartUtils::NewDartUnsupportedError(
596 "ALPN is not supported on this platform"));
597 }
598
599
600 void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
601 SecCertificateRef certificate = GetX509Certificate(args);
602 CFStringRef cfsubject = SecCertificateCopySubjectSummary(certificate);
603 if (cfsubject != NULL) {
604 char* csubject = CFStringRefToCString(cfsubject);
605 CFRelease(cfsubject);
606 Dart_SetReturnValue(args, Dart_NewStringFromCString(csubject));
607 } else {
608 Dart_ThrowException(DartUtils::NewDartArgumentError(
609 "X509.subject failed to find subject's common name."));
610 }
611 }
612
613
614 void FUNCTION_NAME(X509_Issuer)(Dart_NativeArguments args) {
615 Dart_ThrowException(DartUtils::NewDartUnsupportedError(
616 "X509Certificate.issuer is not supported on this platform."));
617 }
618
619
620 void FUNCTION_NAME(X509_StartValidity)(Dart_NativeArguments args) {
621 Dart_ThrowException(DartUtils::NewDartUnsupportedError(
622 "X509Certificate.startValidity is not supported on this platform."));
623 }
624
625
626 void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
627 Dart_ThrowException(DartUtils::NewDartUnsupportedError(
628 "X509Certificate.endValidity is not supported on this platform."));
629 }
630
631
632 // Pushes data through the SSL filter, reading and writing from circular
633 // buffers shared with Dart. Called from the IOService thread.
634 //
635 // The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
636 // pass encrypted and plaintext data to and from the C++ SSLFilter object.
637 //
638 // ProcessFilter is called with a CObject array containing the pointer to
639 // the SSLFilter, encoded as an int, and the start and end positions of the
640 // valid data in the four circular buffers. The function only reads from
641 // the valid data area of the input buffers, and only writes to the free
642 // area of the output buffers. The function returns the new start and end
643 // positions in the buffers, but it only updates start for input buffers, and
644 // end for output buffers. Therefore, the Dart thread can simultaneously
645 // write to the free space and end pointer of input buffers, and read from
646 // the data space of output buffers, and modify the start pointer.
647 //
648 // When ProcessFilter returns, the Dart thread is responsible for combining
649 // the updated pointers from Dart and C++, to make the new valid state of
650 // the circular buffer.
651 CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
652 CObjectIntptr filter_object(request[0]);
653 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
654 RefCntReleaseScope<SSLFilter> rs(filter);
655
656 bool in_handshake = CObjectBool(request[1]).Value();
657 intptr_t starts[SSLFilter::kNumBuffers];
658 intptr_t ends[SSLFilter::kNumBuffers];
659 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
660 starts[i] = CObjectInt32(request[2 * i + 2]).Value();
661 ends[i] = CObjectInt32(request[2 * i + 3]).Value();
662 }
663
664 OSStatus status = filter->ProcessAllBuffers(starts, ends, in_handshake);
665 if (status == noErr) {
666 CObjectArray* result =
667 new CObjectArray(CObject::NewArray(SSLFilter::kNumBuffers * 2));
668 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
669 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i])));
670 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i])));
671 }
672 return result;
673 } else {
674 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
675 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
676 static_cast<intptr_t>(status));
677 CObjectArray* result = new CObjectArray(CObject::NewArray(2));
678 result->SetAt(0, new CObjectInt32(CObject::NewInt32(status)));
679 result->SetAt(1,
680 new CObjectString(CObject::NewString(status_message.buf())));
681 return result;
682 }
683 }
684
685
686 // Usually buffer_starts_ and buffer_ends_ are populated by ProcessAllBuffers,
687 // called from ProcessFilterRequest, called from the IOService thread.
688 // However, the first call to SSLHandshake comes from the Dart thread, and so
689 // doesn't go through there. This results in calls to SSLReadCallback and
690 // SSLWriteCallback in which buffer_starts_ and buffer_ends_ haven't been set
691 // up. In that case, since we're coming from Dart anyway, we can access the
692 // fieds directly from the Dart objects.
693 intptr_t SSLFilter::GetBufferStart(intptr_t idx) const {
694 if (buffer_starts_[idx] != NULL) {
695 return *buffer_starts_[idx];
696 }
697 Dart_Handle buffer_handle =
698 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
699 Dart_Handle start_handle =
700 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("start")));
701 int64_t start = DartUtils::GetIntegerValue(start_handle);
702 return static_cast<intptr_t>(start);
703 }
704
705
706 intptr_t SSLFilter::GetBufferEnd(intptr_t idx) const {
707 if (buffer_ends_[idx] != NULL) {
708 return *buffer_ends_[idx];
709 }
710 Dart_Handle buffer_handle =
711 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
712 Dart_Handle end_handle =
713 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("end")));
714 int64_t end = DartUtils::GetIntegerValue(end_handle);
715 return static_cast<intptr_t>(end);
716 }
717
718
719 void SSLFilter::SetBufferStart(intptr_t idx, intptr_t value) {
720 if (buffer_starts_[idx] != NULL) {
721 *buffer_starts_[idx] = value;
722 return;
723 }
724 Dart_Handle buffer_handle =
725 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
726 ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "start",
727 static_cast<int64_t>(value)));
728 }
729
730
731 void SSLFilter::SetBufferEnd(intptr_t idx, intptr_t value) {
732 if (buffer_ends_[idx] != NULL) {
733 *buffer_ends_[idx] = value;
734 return;
735 }
736 Dart_Handle buffer_handle =
737 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
738 ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "end",
739 static_cast<int64_t>(value)));
740 }
741
742
743 OSStatus SSLFilter::ProcessAllBuffers(intptr_t starts[kNumBuffers],
744 intptr_t ends[kNumBuffers],
745 bool in_handshake) {
746 for (intptr_t i = 0; i < kNumBuffers; ++i) {
747 buffer_starts_[i] = &starts[i];
748 buffer_ends_[i] = &ends[i];
749 }
750
751 if (in_handshake) {
752 OSStatus status = Handshake();
753 if (status != noErr) {
754 return status;
755 }
756 } else {
757 for (intptr_t i = 0; i < kNumBuffers; ++i) {
758 intptr_t start = starts[i];
759 intptr_t end = ends[i];
760 intptr_t size =
761 isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
762 if (start < 0 || end < 0 || start >= size || end >= size) {
763 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket");
764 }
765 switch (i) {
766 case kReadPlaintext:
767 // Write data to the circular buffer's free space. If the buffer
768 // is full, neither if statement is executed and nothing happens.
769 if (start <= end) {
770 // If the free space may be split into two segments,
771 // then the first is [end, size), unless start == 0.
772 // Then, since the last free byte is at position start - 2,
773 // the interval is [end, size - 1).
774 intptr_t buffer_end = (start == 0) ? size - 1 : size;
775 intptr_t bytes = 0;
776 OSStatus status =
777 ProcessReadPlaintextBuffer(end, buffer_end, &bytes);
778 if ((status != noErr) && (status != errSSLWouldBlock)) {
779 return status;
780 }
781 end += bytes;
782 ASSERT(end <= size);
783 if (end == size) {
784 end = 0;
785 }
786 }
787 if (start > end + 1) {
788 intptr_t bytes = 0;
789 OSStatus status =
790 ProcessReadPlaintextBuffer(end, start - 1, &bytes);
791 if ((status != noErr) && (status != errSSLWouldBlock)) {
792 return status;
793 }
794 end += bytes;
795 ASSERT(end < start);
796 }
797 ends[i] = end;
798 break;
799 case kWritePlaintext:
800 // Read/Write data from circular buffer. If the buffer is empty,
801 // neither if statement's condition is true.
802 if (end < start) {
803 // Data may be split into two segments. In this case,
804 // the first is [start, size).
805 intptr_t bytes = 0;
806 OSStatus status = ProcessWritePlaintextBuffer(start, size, &bytes);
807 if ((status != noErr) && (status != errSSLWouldBlock)) {
808 return status;
809 }
810 start += bytes;
811 ASSERT(start <= size);
812 if (start == size) {
813 start = 0;
814 }
815 }
816 if (start < end) {
817 intptr_t bytes = 0;
818 OSStatus status = ProcessWritePlaintextBuffer(start, end, &bytes);
819 if ((status != noErr) && (status != errSSLWouldBlock)) {
820 return status;
821 }
822 start += bytes;
823 ASSERT(start <= end);
824 }
825 starts[i] = start;
826 break;
827 case kReadEncrypted:
828 case kWriteEncrypted:
829 // These buffers are advanced through SSLReadCallback and
830 // SSLWriteCallback, which are called from SSLRead, SSLWrite, and
831 // SSLHandshake.
832 break;
833 default:
834 UNREACHABLE();
835 }
836 }
837 }
838
839 for (intptr_t i = 0; i < kNumBuffers; ++i) {
840 buffer_starts_[i] = NULL;
841 buffer_ends_[i] = NULL;
842 }
843 return noErr;
844 }
845
846
847 Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
848 ASSERT(string_start_ == NULL);
849 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
850 ASSERT(string_start_ != NULL);
851 ASSERT(string_length_ == NULL);
852 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
853 ASSERT(string_length_ != NULL);
854 ASSERT(bad_certificate_callback_ == NULL);
855 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
856 ASSERT(bad_certificate_callback_ != NULL);
857
858 // Caller handles cleanup on an error.
859 return InitializeBuffers(dart_this);
860 }
861
862
863 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
864 // Create SSLFilter buffers as ExternalUint8Array objects.
865 Dart_Handle buffers_string = DartUtils::NewString("buffers");
866 RETURN_IF_ERROR(buffers_string);
867 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
868 RETURN_IF_ERROR(dart_buffers_object);
869 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
870 RETURN_IF_ERROR(secure_filter_impl_type);
871 Dart_Handle size_string = DartUtils::NewString("SIZE");
872 RETURN_IF_ERROR(size_string);
873 Dart_Handle dart_buffer_size =
874 Dart_GetField(secure_filter_impl_type, size_string);
875 RETURN_IF_ERROR(dart_buffer_size);
876
877 int64_t buffer_size = 0;
878 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
879 RETURN_IF_ERROR(err);
880
881 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
882 RETURN_IF_ERROR(encrypted_size_string);
883
884 Dart_Handle dart_encrypted_buffer_size =
885 Dart_GetField(secure_filter_impl_type, encrypted_size_string);
886 RETURN_IF_ERROR(dart_encrypted_buffer_size);
887
888 int64_t encrypted_buffer_size = 0;
889 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
890 RETURN_IF_ERROR(err);
891
892 if (buffer_size <= 0 || buffer_size > 1 * MB) {
893 FATAL("Invalid buffer size in _ExternalBuffer");
894 }
895 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) {
896 FATAL("Invalid encrypted buffer size in _ExternalBuffer");
897 }
898 buffer_size_ = static_cast<intptr_t>(buffer_size);
899 encrypted_buffer_size_ = static_cast<intptr_t>(encrypted_buffer_size);
900
901 Dart_Handle data_identifier = DartUtils::NewString("data");
902 RETURN_IF_ERROR(data_identifier);
903
904 for (int i = 0; i < kNumBuffers; i++) {
905 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
906 buffers_[i] = new uint8_t[size];
907 ASSERT(buffers_[i] != NULL);
908 buffer_starts_[i] = NULL;
909 buffer_ends_[i] = NULL;
910 dart_buffer_objects_[i] = NULL;
911 }
912
913 Dart_Handle result = Dart_Null();
914 for (int i = 0; i < kNumBuffers; ++i) {
915 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
916 result = Dart_ListGetAt(dart_buffers_object, i);
917 if (Dart_IsError(result)) {
918 break;
919 }
920
921 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
922 ASSERT(dart_buffer_objects_[i] != NULL);
923 Dart_Handle data =
924 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
925 if (Dart_IsError(data)) {
926 result = data;
927 break;
928 }
929 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
930 if (Dart_IsError(result)) {
931 break;
932 }
933 result = Dart_SetField(result, data_identifier, data);
934 if (Dart_IsError(result)) {
935 break;
936 }
937 }
938
939 // Caller handles cleanup on an error.
940 return result;
941 }
942
943
944 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
945 ASSERT(NULL == handshake_complete_);
946 handshake_complete_ = Dart_NewPersistentHandle(complete);
947 ASSERT(handshake_complete_ != NULL);
948 }
949
950
951 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
952 ASSERT(bad_certificate_callback_ != NULL);
953 Dart_DeletePersistentHandle(bad_certificate_callback_);
954 bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
955 ASSERT(bad_certificate_callback_ != NULL);
956 }
957
958
959 Dart_Handle SSLFilter::PeerCertificate() {
960 if (peer_certs_ == NULL) {
961 return Dart_Null();
962 }
963
964 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, 0);
965 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
966 SecCertificateRef cert =
967 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
968 if (cert == NULL) {
969 return Dart_Null();
970 }
971
972 return WrappedX509Certificate(cert);
973 }
974
975
976 void SSLFilter::Connect(Dart_Handle dart_this,
977 const char* hostname,
978 SSLCertContext* context,
979 bool is_server,
980 bool request_client_certificate,
981 bool require_client_certificate) {
982 if (in_handshake_) {
983 FATAL("Connect called twice on the same _SecureFilter.");
984 }
985
986 // Create the underlying context
987 SSLContextRef ssl_context = SSLCreateContext(
988 NULL, is_server ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
989
990 // Configure the context.
991 OSStatus status;
992 status = SSLSetPeerDomainName(ssl_context, hostname, strlen(hostname));
993 CheckStatus(status, "TlsException", "Failed to set peer domain name");
994
995 status = SSLSetIOFuncs(ssl_context, SSLFilter::SSLReadCallback,
996 SSLFilter::SSLWriteCallback);
997 CheckStatus(status, "TlsException", "Failed to set IO Callbacks");
998
999 status =
1000 SSLSetConnection(ssl_context, reinterpret_cast<SSLConnectionRef>(this));
1001 CheckStatus(status, "TlsException", "Failed to set connection object");
1002
1003 // Always evaluate the certs manually so that we can cache the peer
1004 // certificates in the context for calls to peerCertificate.
1005 status = SSLSetSessionOption(ssl_context, kSSLSessionOptionBreakOnServerAuth,
1006 true);
1007 CheckStatus(status, "TlsException", "Failed to set BreakOnServerAuth option");
1008
1009 status = SSLSetProtocolVersionMin(ssl_context, kTLSProtocol1);
1010 CheckStatus(status, "TlsException",
1011 "Failed to set minimum protocol version to kTLSProtocol1");
1012
1013 // If the context has an identity pass it to SSLSetCertificate().
1014 if (context->identity() != NULL) {
1015 CFMutableArrayRef chain =
1016 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1017 CFArrayAppendValue(chain, context->identity());
1018
1019 // Append the certificate chain if there is one.
1020 if (context->cert_chain() != NULL) {
1021 // Skip the first one, it's already included in the identity.
1022 CFIndex chain_length = CFArrayGetCount(context->cert_chain());
1023 if (chain_length > 1) {
1024 CFArrayAppendArray(chain, context->cert_chain(),
1025 CFRangeMake(1, chain_length));
1026 }
1027 }
1028
1029 status = SSLSetCertificate(ssl_context, chain);
1030 CFRelease(chain);
1031 CheckStatus(status, "TlsException", "SSLSetCertificate failed");
1032 }
1033
1034 if (is_server) {
1035 SSLAuthenticate auth =
1036 require_client_certificate
1037 ? kAlwaysAuthenticate
1038 : (request_client_certificate ? kTryAuthenticate
1039 : kNeverAuthenticate);
1040 status = SSLSetClientSideAuthenticate(ssl_context, auth);
1041 CheckStatus(status, "TlsException",
1042 "Failed to set client authentication mode");
1043
1044 // If we're at least trying client authentication, then break handshake
1045 // for client authentication.
1046 if (auth != kNeverAuthenticate) {
1047 status = SSLSetSessionOption(ssl_context,
1048 kSSLSessionOptionBreakOnClientAuth, true);
1049 CheckStatus(status, "TlsException",
1050 "Failed to set client authentication mode");
1051 }
1052 }
1053
1054 // Add the contexts to our wrapper.
1055 cert_context_.set(context);
1056 ssl_context_ = ssl_context;
1057 is_server_ = is_server;
1058
1059 // Kick-off the handshake. Expect the handshake to need more data.
1060 // SSLHandshake calls our SSLReadCallback and SSLWriteCallback.
1061 status = SSLHandshake(ssl_context);
1062 ASSERT(status != noErr);
1063 if (status == errSSLWouldBlock) {
1064 status = noErr;
1065 in_handshake_ = true;
1066 }
1067 CheckStatus(status, "HandshakeException", is_server_
1068 ? "Handshake error in server"
1069 : "Handshake error in client");
1070 }
1071
1072
1073 OSStatus SSLFilter::EvaluatePeerTrust() {
1074 OSStatus status = noErr;
1075
1076 if (SSL_LOG_STATUS) {
1077 Log::PrintErr("Handshake evaluating trust.\n");
1078 }
1079 SecTrustRef peer_trust = NULL;
1080 status = SSLCopyPeerTrust(ssl_context_, &peer_trust);
1081 if (status != noErr) {
1082 if (is_server_ && (status == errSSLBadCert)) {
1083 // A client certificate was requested, but not required, and wasn't sent.
1084 return noErr;
1085 }
1086 if (SSL_LOG_STATUS) {
1087 Log::PrintErr("Handshake error from SSLCopyPeerTrust(): %ld.\n",
1088 static_cast<intptr_t>(status));
1089 }
1090 return status;
1091 }
1092
1093 CFArrayRef trusted_certs = NULL;
1094 if (cert_context_.get()->trusted_certs() != NULL) {
1095 trusted_certs =
1096 CFArrayCreateCopy(NULL, cert_context_.get()->trusted_certs());
1097 } else {
1098 trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
1099 }
1100
1101 status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs);
1102 if (status != noErr) {
1103 if (SSL_LOG_STATUS) {
1104 Log::PrintErr("Handshake error from SecTrustSetAnchorCertificates: %ld\n",
1105 static_cast<intptr_t>(status));
1106 }
1107 CFRelease(trusted_certs);
1108 CFRelease(peer_trust);
1109 return status;
1110 }
1111
1112 if (SSL_LOG_STATUS) {
1113 Log::PrintErr(
1114 "Handshake %s built in root certs\n",
1115 cert_context_.get()->trust_builtin() ? "trusting" : "not trusting");
1116 }
1117
1118 status = SecTrustSetAnchorCertificatesOnly(
1119 peer_trust, !cert_context_.get()->trust_builtin());
1120 if (status != noErr) {
1121 CFRelease(trusted_certs);
1122 CFRelease(peer_trust);
1123 return status;
1124 }
1125
1126 SecTrustResultType trust_result;
1127 status = SecTrustEvaluate(peer_trust, &trust_result);
1128 if (status != noErr) {
1129 CFRelease(trusted_certs);
1130 CFRelease(peer_trust);
1131 return status;
1132 }
1133
1134 // Grab the peer's certificate chain.
1135 CFIndex peer_chain_length = SecTrustGetCertificateCount(peer_trust);
1136 CFMutableArrayRef peer_certs =
1137 CFArrayCreateMutable(NULL, peer_chain_length, &kCFTypeArrayCallBacks);
1138 for (CFIndex i = 0; i < peer_chain_length; ++i) {
1139 CFArrayAppendValue(peer_certs,
1140 SecTrustGetCertificateAtIndex(peer_trust, i));
1141 }
1142 peer_certs_ = peer_certs;
1143
1144 CFRelease(trusted_certs);
1145 CFRelease(peer_trust);
1146
1147 if ((trust_result == kSecTrustResultProceed) ||
1148 (trust_result == kSecTrustResultUnspecified)) {
1149 // Trusted.
1150 return noErr;
1151 } else {
1152 if (SSL_LOG_STATUS) {
1153 Log::PrintErr("Trust eval failed: trust_result = %d\n", trust_result);
1154 }
1155 bad_cert_ = true;
1156 return errSSLBadCert;
1157 }
1158 }
1159
1160
1161 OSStatus SSLFilter::Handshake() {
1162 ASSERT(cert_context_.get() != NULL);
1163 ASSERT(ssl_context_ != NULL);
1164 // Try and push handshake along.
1165 if (SSL_LOG_STATUS) {
1166 Log::PrintErr("Doing SSLHandshake\n");
1167 }
1168 OSStatus status = SSLHandshake(ssl_context_);
1169 if (SSL_LOG_STATUS) {
1170 Log::PrintErr("SSLHandshake returned %ld\n", static_cast<intptr_t>(status));
1171 }
1172
1173 if ((status == errSSLServerAuthCompleted) ||
1174 (status == errSSLClientAuthCompleted)) {
1175 status = EvaluatePeerTrust();
1176 if (status == errSSLBadCert) {
1177 // Need to invoke the bad certificate callback.
1178 return noErr;
1179 } else if (status != noErr) {
1180 return status;
1181 }
1182 // When trust evaluation succeeds, we can call SSLHandshake again
1183 // immediately.
1184 status = SSLHandshake(ssl_context_);
1185 }
1186
1187 if (status == errSSLWouldBlock) {
1188 in_handshake_ = true;
1189 return noErr;
1190 }
1191
1192 // Handshake succeeded.
1193 if ((in_handshake_) && (status == noErr)) {
1194 if (SSL_LOG_STATUS) {
1195 Log::PrintErr("Finished with the Handshake\n");
1196 }
1197 connected_ = true;
1198 }
1199 return status;
1200 }
1201
1202
1203 // Returns false if Handshake should fail, and true if Handshake should
1204 // proceed.
1205 Dart_Handle SSLFilter::InvokeBadCertCallback(SecCertificateRef peer_cert) {
1206 Dart_Handle callback = bad_certificate_callback_;
1207 if (Dart_IsNull(callback)) {
1208 return callback;
1209 }
1210 Dart_Handle args[1];
1211 args[0] = WrappedX509Certificate(peer_cert);
1212 if (Dart_IsError(args[0])) {
1213 return args[0];
1214 }
1215 Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
1216 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
1217 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
1218 "HandshakeException",
1219 "BadCertificateCallback returned a value that was not a boolean",
1220 Dart_Null()));
1221 }
1222 return result;
1223 }
1224
1225
1226 OSStatus SSLFilter::CheckHandshake() {
1227 if (bad_cert_ && in_handshake_) {
1228 if (SSL_LOG_STATUS) {
1229 Log::PrintErr("Invoking bad certificate callback\n");
1230 }
1231 ASSERT(peer_certs_ != NULL);
1232 CFIndex peer_certs_len = CFArrayGetCount(peer_certs_);
1233 ASSERT(peer_certs_len > 0);
1234 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, peer_certs_len - 1);
1235 ASSERT(item != NULL);
1236 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1237 SecCertificateRef peer_cert =
1238 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1239 Dart_Handle result = InvokeBadCertCallback(peer_cert);
1240 ThrowIfError(result);
1241 if (Dart_IsNull(result)) {
1242 return errSSLBadCert;
1243 } else {
1244 bool good_cert = DartUtils::GetBooleanValue(result);
1245 bad_cert_ = !good_cert;
1246 return good_cert ? noErr : errSSLBadCert;
1247 }
1248 }
1249
1250 if (connected_ && in_handshake_) {
1251 if (SSL_LOG_STATUS) {
1252 Log::PrintErr("Invoking handshake complete callback\n");
1253 }
1254 ThrowIfError(Dart_InvokeClosure(
1255 Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
1256 in_handshake_ = false;
1257 }
1258 return noErr;
1259 }
1260
1261
1262 void SSLFilter::Renegotiate(bool use_session_cache,
1263 bool request_client_certificate,
1264 bool require_client_certificate) {
1265 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the
1266 // SSL_REQUEST_CERTIFICATE option is also set, so set it.
1267 request_client_certificate =
1268 request_client_certificate || require_client_certificate;
1269 // TODO(24070, 24069): Implement setting the client certificate parameters,
1270 // and triggering rehandshake.
1271 }
1272
1273
1274 SSLFilter::~SSLFilter() {
1275 if (ssl_context_ != NULL) {
1276 CFRelease(ssl_context_);
1277 ssl_context_ = NULL;
1278 }
1279 if (peer_certs_ != NULL) {
1280 CFRelease(peer_certs_);
1281 peer_certs_ = NULL;
1282 }
1283 if (hostname_ != NULL) {
1284 free(hostname_);
1285 hostname_ = NULL;
1286 }
1287 for (int i = 0; i < kNumBuffers; ++i) {
1288 if (buffers_[i] != NULL) {
1289 delete[] buffers_[i];
1290 buffers_[i] = NULL;
1291 }
1292 }
1293 }
1294
1295
1296 void SSLFilter::Destroy() {
1297 if (ssl_context_ != NULL) {
1298 SSLClose(ssl_context_);
1299 }
1300 for (int i = 0; i < kNumBuffers; ++i) {
1301 if (dart_buffer_objects_[i] != NULL) {
1302 Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
1303 dart_buffer_objects_[i] = NULL;
1304 }
1305 }
1306 if (string_start_ != NULL) {
1307 Dart_DeletePersistentHandle(string_start_);
1308 string_start_ = NULL;
1309 }
1310 if (string_length_ != NULL) {
1311 Dart_DeletePersistentHandle(string_length_);
1312 string_length_ = NULL;
1313 }
1314 if (handshake_complete_ != NULL) {
1315 Dart_DeletePersistentHandle(handshake_complete_);
1316 handshake_complete_ = NULL;
1317 }
1318 if (bad_certificate_callback_ != NULL) {
1319 Dart_DeletePersistentHandle(bad_certificate_callback_);
1320 bad_certificate_callback_ = NULL;
1321 }
1322 }
1323
1324
1325 OSStatus SSLFilter::SSLReadCallback(SSLConnectionRef connection,
1326 void* data,
1327 size_t* data_requested) {
1328 // Copy at most `data_requested` bytes from `buffers_[kReadEncrypted]` into
1329 // `data`
1330 ASSERT(connection != NULL);
1331 ASSERT(data != NULL);
1332 ASSERT(data_requested != NULL);
1333
1334 SSLFilter* filter =
1335 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1336 uint8_t* datap = reinterpret_cast<uint8_t*>(data);
1337 uint8_t* buffer = filter->buffers_[kReadEncrypted];
1338 intptr_t start = filter->GetBufferStart(kReadEncrypted);
1339 intptr_t end = filter->GetBufferEnd(kReadEncrypted);
1340 intptr_t size = filter->encrypted_buffer_size_;
1341 intptr_t requested = static_cast<intptr_t>(*data_requested);
1342 intptr_t data_read = 0;
1343
1344 if (end < start) {
1345 // Data may be split into two segments. In this case,
1346 // the first is [start, size).
1347 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1348 intptr_t available = buffer_end - start;
1349 intptr_t bytes = requested < available ? requested : available;
1350 memmove(datap, &buffer[start], bytes);
1351 start += bytes;
1352 datap += bytes;
1353 data_read += bytes;
1354 requested -= bytes;
1355 ASSERT(start <= size);
1356 if (start == size) {
1357 start = 0;
1358 }
1359 }
1360 if ((requested > 0) && (start < end)) {
1361 intptr_t available = end - start;
1362 intptr_t bytes = requested < available ? requested : available;
1363 memmove(datap, &buffer[start], bytes);
1364 start += bytes;
1365 datap += bytes;
1366 data_read += bytes;
1367 requested -= bytes;
1368 ASSERT(start <= end);
1369 }
1370
1371 if (SSL_LOG_DATA) {
1372 Log::PrintErr("SSLReadCallback: requested: %ld, read %ld bytes\n",
1373 *data_requested, data_read);
1374 }
1375
1376 filter->SetBufferStart(kReadEncrypted, start);
1377 bool short_read = data_read < static_cast<intptr_t>(*data_requested);
1378 *data_requested = data_read;
1379 return short_read ? errSSLWouldBlock : noErr;
1380 }
1381
1382
1383 // Read decrypted data from the filter to the circular buffer.
1384 OSStatus SSLFilter::ProcessReadPlaintextBuffer(intptr_t start,
1385 intptr_t end,
1386 intptr_t* bytes_processed) {
1387 ASSERT(bytes_processed != NULL);
1388 intptr_t length = end - start;
1389 OSStatus status = noErr;
1390 size_t bytes = 0;
1391 if (length > 0) {
1392 status =
1393 SSLRead(ssl_context_,
1394 reinterpret_cast<void*>((buffers_[kReadPlaintext] + start)),
1395 length, &bytes);
1396 if (SSL_LOG_STATUS) {
1397 Log::PrintErr("SSLRead: status = %ld\n", static_cast<intptr_t>(status));
1398 }
1399 if ((status != noErr) && (status != errSSLWouldBlock)) {
1400 *bytes_processed = 0;
1401 return status;
1402 }
1403 }
1404 if (SSL_LOG_DATA) {
1405 Log::PrintErr(
1406 "ProcessReadPlaintextBuffer: requested: %ld, read %ld bytes\n", length,
1407 bytes);
1408 }
1409 *bytes_processed = static_cast<intptr_t>(bytes);
1410 return status;
1411 }
1412
1413
1414 OSStatus SSLFilter::SSLWriteCallback(SSLConnectionRef connection,
1415 const void* data,
1416 size_t* data_provided) {
1417 // Copy at most `data_provided` bytes from data into
1418 // `buffers_[kWriteEncrypted]`.
1419 ASSERT(connection != NULL);
1420 ASSERT(data != NULL);
1421 ASSERT(data_provided != NULL);
1422
1423 SSLFilter* filter =
1424 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1425 const uint8_t* datap = reinterpret_cast<const uint8_t*>(data);
1426 uint8_t* buffer = filter->buffers_[kWriteEncrypted];
1427 intptr_t start = filter->GetBufferStart(kWriteEncrypted);
1428 intptr_t end = filter->GetBufferEnd(kWriteEncrypted);
1429 intptr_t size = filter->encrypted_buffer_size_;
1430 intptr_t provided = static_cast<intptr_t>(*data_provided);
1431 intptr_t data_written = 0;
1432
1433 // is full, neither if statement is executed and nothing happens.
1434 if (start <= end) {
1435 // If the free space may be split into two segments,
1436 // then the first is [end, size), unless start == 0.
1437 // Then, since the last free byte is at position start - 2,
1438 // the interval is [end, size - 1).
1439 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1440 intptr_t available = buffer_end - end;
1441 intptr_t bytes = provided < available ? provided : available;
1442 memmove(&buffer[end], datap, bytes);
1443 end += bytes;
1444 datap += bytes;
1445 data_written += bytes;
1446 provided -= bytes;
1447 ASSERT(end <= size);
1448 if (end == size) {
1449 end = 0;
1450 }
1451 }
1452 if ((provided > 0) && (start > end + 1)) {
1453 intptr_t available = (start - 1) - end;
1454 intptr_t bytes = provided < available ? provided : available;
1455 memmove(&buffer[end], datap, bytes);
1456 end += bytes;
1457 datap += bytes;
1458 data_written += bytes;
1459 provided -= bytes;
1460 ASSERT(end < start);
1461 }
1462
1463 if (SSL_LOG_DATA) {
1464 Log::PrintErr("SSLWriteCallback: provided: %ld, written %ld bytes\n",
1465 *data_provided, data_written);
1466 }
1467
1468 filter->SetBufferEnd(kWriteEncrypted, end);
1469 *data_provided = data_written;
1470 return (data_written == 0) ? errSSLWouldBlock : noErr;
1471 }
1472
1473
1474 OSStatus SSLFilter::ProcessWritePlaintextBuffer(intptr_t start,
1475 intptr_t end,
1476 intptr_t* bytes_processed) {
1477 ASSERT(bytes_processed != NULL);
1478 intptr_t length = end - start;
1479 OSStatus status = noErr;
1480 size_t bytes = 0;
1481 if (length > 0) {
1482 status =
1483 SSLWrite(ssl_context_,
1484 reinterpret_cast<void*>(buffers_[kWritePlaintext] + start),
1485 length, &bytes);
1486 if (SSL_LOG_STATUS) {
1487 Log::PrintErr("SSLWrite: status = %ld\n", static_cast<intptr_t>(status));
1488 }
1489 if ((status != noErr) && (status != errSSLWouldBlock)) {
1490 *bytes_processed = 0;
1491 return status;
1492 }
1493 }
1494 if (SSL_LOG_DATA) {
1495 Log::PrintErr("ProcessWritePlaintextBuffer: requested: %ld, written: %ld\n",
1496 length, bytes);
1497 }
1498 *bytes_processed = static_cast<intptr_t>(bytes);
1499 return status;
1500 }
1501
1502 } // namespace bin
1503 } // namespace dart
1504
1505 #endif // HOST_OS_IOS
1506
1507 #endif // !defined(DART_IO_SECURE_SOCKET_DISABLED)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698