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

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

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