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

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

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

Powered by Google App Engine
This is Rietveld 408576698