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

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

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

Powered by Google App Engine
This is Rietveld 408576698