1// Copyright (c) 2017, 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_SECURE_SOCKET_DISABLED)
6
7#include "bin/secure_socket_filter.h"
8
9#include <openssl/bio.h>
10#include <openssl/ssl.h>
11#include <openssl/x509.h>
12
13#include "bin/lockers.h"
14#include "bin/secure_socket_utils.h"
15#include "bin/security_context.h"
16#include "platform/syslog.h"
17#include "platform/text_buffer.h"
18
19// Return the error from the containing function if handle is an error handle.
20#define RETURN_IF_ERROR(handle) \
21 { \
22 Dart_Handle __handle = handle; \
23 if (Dart_IsError((__handle))) { \
24 return __handle; \
25 } \
26 }
27
28namespace dart {
29namespace bin {
30
31bool SSLFilter::library_initialized_ = false;
32// To protect library initialization.
33Mutex* SSLFilter::mutex_ = nullptr;
34int SSLFilter::filter_ssl_index;
35
36void SSLFilter::Init() {
37 ASSERT(SSLFilter::mutex_ == nullptr);
38 SSLFilter::mutex_ = new Mutex();
39}
40
41void SSLFilter::Cleanup() {
42 ASSERT(SSLFilter::mutex_ != nullptr);
43 delete SSLFilter::mutex_;
44 SSLFilter::mutex_ = nullptr;
45}
46
47const intptr_t SSLFilter::kInternalBIOSize = 10 * KB;
48const intptr_t SSLFilter::kApproximateSize =
49 sizeof(SSLFilter) + (2 * SSLFilter::kInternalBIOSize);
50
51static SSLFilter* GetFilter(Dart_NativeArguments args) {
52 SSLFilter* filter = NULL;
53 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
54 ASSERT(Dart_IsInstance(dart_this));
55 ThrowIfError(Dart_GetNativeInstanceField(
56 dart_this, SSLFilter::kSSLFilterNativeFieldIndex,
57 reinterpret_cast<intptr_t*>(&filter)));
58 if (filter == NULL) {
59 Dart_PropagateError(Dart_NewUnhandledExceptionError(
60 DartUtils::NewInternalError("No native peer")));
61 }
62 return filter;
63}
64
65static void DeleteFilter(void* isolate_data, void* context_pointer) {
66 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
67 filter->Release();
68}
69
70static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
71 ASSERT(filter != NULL);
72 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
73 RETURN_IF_ERROR(dart_this);
74 ASSERT(Dart_IsInstance(dart_this));
75 Dart_Handle err = Dart_SetNativeInstanceField(
76 dart_this, SSLFilter::kSSLFilterNativeFieldIndex,
77 reinterpret_cast<intptr_t>(filter));
78 RETURN_IF_ERROR(err);
79 Dart_NewFinalizableHandle(dart_this, reinterpret_cast<void*>(filter),
80 SSLFilter::kApproximateSize, DeleteFilter);
81 return Dart_Null();
82}
83
84void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
85 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
86 SSLFilter* filter = new SSLFilter();
87 Dart_Handle err = SetFilter(args, filter);
88 if (Dart_IsError(err)) {
89 filter->Release();
90 Dart_PropagateError(err);
91 }
92 err = filter->Init(dart_this);
93 if (Dart_IsError(err)) {
94 // The finalizer was set up by SetFilter. It will delete `filter` if there
95 // is an error.
96 filter->Destroy();
97 Dart_PropagateError(err);
98 }
99}
100
101void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
102 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
103 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
104 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
105 bool request_client_certificate =
106 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
107 bool require_client_certificate =
108 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
109 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 6));
110
111 const char* host_name = NULL;
112 // TODO(whesse): Is truncating a Dart string containing \0 what we want?
113 ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
114
115 SSLCertContext* context = NULL;
116 if (!Dart_IsNull(context_object)) {
117 ThrowIfError(Dart_GetNativeInstanceField(
118 context_object, SSLCertContext::kSecurityContextNativeFieldIndex,
119 reinterpret_cast<intptr_t*>(&context)));
120 }
121
122 // The protocols_handle is guaranteed to be a valid Uint8List.
123 // It will have the correct length encoding of the protocols array.
124 ASSERT(!Dart_IsNull(protocols_handle));
125 GetFilter(args)->Connect(host_name, context, is_server,
126 request_client_certificate,
127 require_client_certificate, protocols_handle);
128}
129
130void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
131 SSLFilter* filter = GetFilter(args);
132 // There are two paths that can clean up an SSLFilter object. First,
133 // there is this explicit call to Destroy(), called from
134 // _SecureFilter.destroy() in Dart code. After a call to destroy(), the Dart
135 // code maintains the invariant that there will be no futher SSLFilter
136 // requests sent to the IO Service. Therefore, the internals of the SSLFilter
137 // are safe to deallocate, but not the SSLFilter itself, which is already
138 // set up to be cleaned up by the finalizer.
139 //
140 // The second path is through the finalizer, which we have to do in case
141 // some mishap prevents a call to _SecureFilter.destroy().
142 filter->Destroy();
143}
144
145void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
146 GetFilter(args)->Handshake();
147}
148
149void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)(
150 Dart_NativeArguments args) {
151 GetFilter(args)->GetSelectedProtocol(args);
152}
153
154void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
155 bool use_session_cache =
156 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1));
157 bool request_client_certificate =
158 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
159 bool require_client_certificate =
160 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
161 GetFilter(args)->Renegotiate(use_session_cache, request_client_certificate,
162 require_client_certificate);
163}
164
165void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
166 Dart_NativeArguments args) {
167 Dart_Handle handshake_complete =
168 ThrowIfError(Dart_GetNativeArgument(args, 1));
169 if (!Dart_IsClosure(handshake_complete)) {
170 Dart_ThrowException(DartUtils::NewDartArgumentError(
171 "Illegal argument to RegisterHandshakeCompleteCallback"));
172 }
173 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
174}
175
176void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
177 Dart_NativeArguments args) {
178 Dart_Handle callback = ThrowIfError(Dart_GetNativeArgument(args, 1));
179 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
180 Dart_ThrowException(DartUtils::NewDartArgumentError(
181 "Illegal argument to RegisterBadCertificateCallback"));
182 }
183 GetFilter(args)->RegisterBadCertificateCallback(callback);
184}
185
186void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) {
187 Dart_Handle cert = ThrowIfError(GetFilter(args)->PeerCertificate());
188 Dart_SetReturnValue(args, cert);
189}
190
191void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
192 SSLFilter* filter = GetFilter(args);
193 // This filter pointer is passed to the IO Service thread. The IO Service
194 // thread must Release() the pointer when it is done with it.
195 filter->Retain();
196 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
197 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
198}
199
200/**
201 * Pushes data through the SSL filter, reading and writing from circular
202 * buffers shared with Dart.
203 *
204 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
205 * pass encrypted and plaintext data to and from the C++ SSLFilter object.
206 *
207 * ProcessFilter is called with a CObject array containing the pointer to
208 * the SSLFilter, encoded as an int, and the start and end positions of the
209 * valid data in the four circular buffers. The function only reads from
210 * the valid data area of the input buffers, and only writes to the free
211 * area of the output buffers. The function returns the new start and end
212 * positions in the buffers, but it only updates start for input buffers, and
213 * end for output buffers. Therefore, the Dart thread can simultaneously
214 * write to the free space and end pointer of input buffers, and read from
215 * the data space of output buffers, and modify the start pointer.
216 *
217 * When ProcessFilter returns, the Dart thread is responsible for combining
218 * the updated pointers from Dart and C++, to make the new valid state of
219 * the circular buffer.
220 */
221CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
222 CObjectIntptr filter_object(request[0]);
223 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
224 RefCntReleaseScope<SSLFilter> rs(filter);
225
226 bool in_handshake = CObjectBool(request[1]).Value();
227 int starts[SSLFilter::kNumBuffers];
228 int ends[SSLFilter::kNumBuffers];
229 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) {
230 starts[i] = CObjectInt32(request[2 * i + 2]).Value();
231 ends[i] = CObjectInt32(request[2 * i + 3]).Value();
232 }
233
234 if (filter->ProcessAllBuffers(starts, ends, in_handshake)) {
235 CObjectArray* result =
236 new CObjectArray(CObject::NewArray(SSLFilter::kNumBuffers * 2));
237 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) {
238 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i])));
239 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i])));
240 }
241 return result;
242 } else {
243 int32_t error_code = static_cast<int32_t>(ERR_peek_error());
244 TextBuffer error_string(SecureSocketUtils::SSL_ERROR_MESSAGE_BUFFER_SIZE);
245 SecureSocketUtils::FetchErrorString(filter->ssl_, &error_string);
246 CObjectArray* result = new CObjectArray(CObject::NewArray(2));
247 result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code)));
248 result->SetAt(1,
249 new CObjectString(CObject::NewString(error_string.buffer())));
250 return result;
251 }
252}
253
254bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers],
255 int ends[kNumBuffers],
256 bool in_handshake) {
257 for (int i = 0; i < kNumBuffers; ++i) {
258 if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue;
259 int start = starts[i];
260 int end = ends[i];
261 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
262 if (start < 0 || end < 0 || start >= size || end >= size) {
263 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket");
264 }
265 switch (i) {
266 case kReadPlaintext:
267 case kWriteEncrypted:
268 // Write data to the circular buffer's free space. If the buffer
269 // is full, neither if statement is executed and nothing happens.
270 if (start <= end) {
271 // If the free space may be split into two segments,
272 // then the first is [end, size), unless start == 0.
273 // Then, since the last free byte is at position start - 2,
274 // the interval is [end, size - 1).
275 int buffer_end = (start == 0) ? size - 1 : size;
276 int bytes = (i == kReadPlaintext)
277 ? ProcessReadPlaintextBuffer(end, buffer_end)
278 : ProcessWriteEncryptedBuffer(end, buffer_end);
279 if (bytes < 0) return false;
280 end += bytes;
281 ASSERT(end <= size);
282 if (end == size) end = 0;
283 }
284 if (start > end + 1) {
285 int bytes = (i == kReadPlaintext)
286 ? ProcessReadPlaintextBuffer(end, start - 1)
287 : ProcessWriteEncryptedBuffer(end, start - 1);
288 if (bytes < 0) return false;
289 end += bytes;
290 ASSERT(end < start);
291 }
292 ends[i] = end;
293 break;
294 case kReadEncrypted:
295 case kWritePlaintext:
296 // Read/Write data from circular buffer. If the buffer is empty,
297 // neither if statement's condition is true.
298 if (end < start) {
299 // Data may be split into two segments. In this case,
300 // the first is [start, size).
301 int bytes = (i == kReadEncrypted)
302 ? ProcessReadEncryptedBuffer(start, size)
303 : ProcessWritePlaintextBuffer(start, size);
304 if (bytes < 0) return false;
305 start += bytes;
306 ASSERT(start <= size);
307 if (start == size) start = 0;
308 }
309 if (start < end) {
310 int bytes = (i == kReadEncrypted)
311 ? ProcessReadEncryptedBuffer(start, end)
312 : ProcessWritePlaintextBuffer(start, end);
313 if (bytes < 0) return false;
314 start += bytes;
315 ASSERT(start <= end);
316 }
317 starts[i] = start;
318 break;
319 default:
320 UNREACHABLE();
321 }
322 }
323 return true;
324}
325
326Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
327 if (!library_initialized_) {
328 InitializeLibrary();
329 }
330 ASSERT(string_start_ == NULL);
331 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
332 ASSERT(string_start_ != NULL);
333 ASSERT(string_length_ == NULL);
334 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
335 ASSERT(string_length_ != NULL);
336 ASSERT(bad_certificate_callback_ == NULL);
337 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
338 ASSERT(bad_certificate_callback_ != NULL);
339 // Caller handles cleanup on an error.
340 return InitializeBuffers(dart_this);
341}
342
343Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
344 // Create SSLFilter buffers as ExternalUint8Array objects.
345 Dart_Handle buffers_string = DartUtils::NewString("buffers");
346 RETURN_IF_ERROR(buffers_string);
347 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
348 RETURN_IF_ERROR(dart_buffers_object);
349 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
350 RETURN_IF_ERROR(secure_filter_impl_type);
351 Dart_Handle size_string = DartUtils::NewString("SIZE");
352 RETURN_IF_ERROR(size_string);
353 Dart_Handle dart_buffer_size =
354 Dart_GetField(secure_filter_impl_type, size_string);
355 RETURN_IF_ERROR(dart_buffer_size);
356
357 int64_t buffer_size = 0;
358 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
359 RETURN_IF_ERROR(err);
360
361 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
362 RETURN_IF_ERROR(encrypted_size_string);
363
364 Dart_Handle dart_encrypted_buffer_size =
365 Dart_GetField(secure_filter_impl_type, encrypted_size_string);
366 RETURN_IF_ERROR(dart_encrypted_buffer_size);
367
368 int64_t encrypted_buffer_size = 0;
369 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
370 RETURN_IF_ERROR(err);
371
372 if (buffer_size <= 0 || buffer_size > 1 * MB) {
373 FATAL("Invalid buffer size in _ExternalBuffer");
374 }
375 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) {
376 FATAL("Invalid encrypted buffer size in _ExternalBuffer");
377 }
378 buffer_size_ = static_cast<int>(buffer_size);
379 encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size);
380
381 Dart_Handle data_identifier = DartUtils::NewString("data");
382 RETURN_IF_ERROR(data_identifier);
383
384 for (int i = 0; i < kNumBuffers; i++) {
385 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
386 buffers_[i] = new uint8_t[size];
387 ASSERT(buffers_[i] != NULL);
388 memset(buffers_[i], 0, size);
389 dart_buffer_objects_[i] = NULL;
390 }
391
392 Dart_Handle result = Dart_Null();
393 for (int i = 0; i < kNumBuffers; ++i) {
394 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
395 result = Dart_ListGetAt(dart_buffers_object, i);
396 if (Dart_IsError(result)) {
397 break;
398 }
399
400 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
401 ASSERT(dart_buffer_objects_[i] != NULL);
402 Dart_Handle data =
403 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
404 if (Dart_IsError(data)) {
405 result = data;
406 break;
407 }
408 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
409 if (Dart_IsError(result)) {
410 break;
411 }
412 result = Dart_SetField(result, data_identifier, data);
413 if (Dart_IsError(result)) {
414 break;
415 }
416 }
417
418 // Caller handles cleanup on an error.
419 return result;
420}
421
422void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
423 ASSERT(NULL == handshake_complete_);
424 handshake_complete_ = Dart_NewPersistentHandle(complete);
425
426 ASSERT(handshake_complete_ != NULL);
427}
428
429void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
430 ASSERT(bad_certificate_callback_ != NULL);
431 Dart_DeletePersistentHandle(bad_certificate_callback_);
432 bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
433 ASSERT(bad_certificate_callback_ != NULL);
434}
435
436Dart_Handle SSLFilter::PeerCertificate() {
437 X509* ca = SSL_get_peer_certificate(ssl_);
438 if (ca == NULL) {
439 return Dart_Null();
440 }
441 return X509Helper::WrappedX509Certificate(ca);
442}
443
444void SSLFilter::InitializeLibrary() {
445 MutexLocker locker(mutex_);
446 if (!library_initialized_) {
447 SSL_library_init();
448 filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
449 ASSERT(filter_ssl_index >= 0);
450 library_initialized_ = true;
451 }
452}
453
454void SSLFilter::Connect(const char* hostname,
455 SSLCertContext* context,
456 bool is_server,
457 bool request_client_certificate,
458 bool require_client_certificate,
459 Dart_Handle protocols_handle) {
460 is_server_ = is_server;
461 if (in_handshake_) {
462 FATAL("Connect called twice on the same _SecureFilter.");
463 }
464
465 int status;
466 int error;
467 BIO* ssl_side;
468 status = BIO_new_bio_pair(&ssl_side, kInternalBIOSize, &socket_side_,
469 kInternalBIOSize);
470 SecureSocketUtils::CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair",
471 ssl_);
472
473 ASSERT(context != NULL);
474 ASSERT(context->context() != NULL);
475 ssl_ = SSL_new(context->context());
476 SSL_set_bio(ssl_, ssl_side, ssl_side);
477 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right?
478 SSL_set_ex_data(ssl_, filter_ssl_index, this);
479 context->RegisterCallbacks(ssl_);
480
481 if (is_server_) {
482 int certificate_mode =
483 request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
484 if (require_client_certificate) {
485 certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
486 }
487 SSL_set_verify(ssl_, certificate_mode, NULL);
488 } else {
489 SSLCertContext::SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
490 status = SSL_set_tlsext_host_name(ssl_, hostname);
491 SecureSocketUtils::CheckStatusSSL(status, "TlsException",
492 "Set SNI host name", ssl_);
493 // Sets the hostname in the certificate-checking object, so it is checked
494 // against the certificate presented by the server.
495 X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_);
496 hostname_ = Utils::StrDup(hostname);
497 X509_VERIFY_PARAM_set_flags(
498 certificate_checking_parameters,
499 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_TRUSTED_FIRST);
500 X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0);
501 status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
502 hostname_, strlen(hostname_));
503 SecureSocketUtils::CheckStatusSSL(
504 status, "TlsException", "Set hostname for certificate checking", ssl_);
505 }
506 // Make the connection:
507 if (is_server_) {
508 status = SSL_accept(ssl_);
509 if (SSL_LOG_STATUS) {
510 Syslog::Print("SSL_accept status: %d\n", status);
511 }
512 if (status != 1) {
513 // TODO(whesse): expect a needs-data error here. Handle other errors.
514 error = SSL_get_error(ssl_, status);
515 if (SSL_LOG_STATUS) {
516 Syslog::Print("SSL_accept error: %d\n", error);
517 }
518 }
519 } else {
520 status = SSL_connect(ssl_);
521 if (SSL_LOG_STATUS) {
522 Syslog::Print("SSL_connect status: %d\n", status);
523 }
524 if (status != 1) {
525 // TODO(whesse): expect a needs-data error here. Handle other errors.
526 error = SSL_get_error(ssl_, status);
527 if (SSL_LOG_STATUS) {
528 Syslog::Print("SSL_connect error: %d\n", error);
529 }
530 }
531 }
532 Handshake();
533}
534
535void SSLFilter::Handshake() {
536 // Try and push handshake along.
537 int status;
538 status = SSL_do_handshake(ssl_);
539 if (callback_error != NULL) {
540 // The SSL_do_handshake will try performing a handshake and might call
541 // a CertificateCallback. If the certificate validation
542 // failed the 'callback_error" will be set by the certificateCallback
543 // logic and we propagate the error"
544 Dart_PropagateError(callback_error);
545 }
546 if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) {
547 in_handshake_ = true;
548 return;
549 }
550 SecureSocketUtils::CheckStatusSSL(
551 status, "HandshakeException",
552 is_server_ ? "Handshake error in server" : "Handshake error in client",
553 ssl_);
554 // Handshake succeeded.
555 if (in_handshake_) {
556 // TODO(24071): Check return value of SSL_get_verify_result, this
557 // should give us the hostname check.
558 int result = SSL_get_verify_result(ssl_);
559 if (SSL_LOG_STATUS) {
560 Syslog::Print("Handshake verification status: %d\n", result);
561 X509* peer_certificate = SSL_get_peer_certificate(ssl_);
562 if (peer_certificate == NULL) {
563 Syslog::Print("No peer certificate received\n");
564 } else {
565 X509_NAME* s_name = X509_get_subject_name(peer_certificate);
566 printf("Peer certificate SN: ");
567 X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
568 printf("\n");
569 }
570 }
571 ThrowIfError(Dart_InvokeClosure(
572 Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
573 in_handshake_ = false;
574 }
575}
576
577void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) {
578 const uint8_t* protocol;
579 unsigned length;
580 SSL_get0_alpn_selected(ssl_, &protocol, &length);
581 if (length == 0) {
582 Dart_SetReturnValue(args, Dart_Null());
583 } else {
584 Dart_SetReturnValue(args, Dart_NewStringFromUTF8(protocol, length));
585 }
586}
587
588void SSLFilter::Renegotiate(bool use_session_cache,
589 bool request_client_certificate,
590 bool require_client_certificate) {
591 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the
592 // SSL_REQUEST_CERTIFICATE option is also set, so set it.
593 request_client_certificate =
594 request_client_certificate || require_client_certificate;
595 // TODO(24070, 24069): Implement setting the client certificate parameters,
596 // and triggering rehandshake.
597}
598
599void SSLFilter::FreeResources() {
600 if (ssl_ != NULL) {
601 SSL_free(ssl_);
602 ssl_ = NULL;
603 }
604 if (socket_side_ != NULL) {
605 BIO_free(socket_side_);
606 socket_side_ = NULL;
607 }
608 if (hostname_ != NULL) {
609 free(hostname_);
610 hostname_ = NULL;
611 }
612 for (int i = 0; i < kNumBuffers; ++i) {
613 if (buffers_[i] != NULL) {
614 delete[] buffers_[i];
615 buffers_[i] = NULL;
616 }
617 }
618}
619
620SSLFilter::~SSLFilter() {
621 FreeResources();
622}
623
624void SSLFilter::Destroy() {
625 for (int i = 0; i < kNumBuffers; ++i) {
626 if (dart_buffer_objects_[i] != NULL) {
627 Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
628 dart_buffer_objects_[i] = NULL;
629 }
630 }
631 if (string_start_ != NULL) {
632 Dart_DeletePersistentHandle(string_start_);
633 string_start_ = NULL;
634 }
635 if (string_length_ != NULL) {
636 Dart_DeletePersistentHandle(string_length_);
637 string_length_ = NULL;
638 }
639 if (handshake_complete_ != NULL) {
640 Dart_DeletePersistentHandle(handshake_complete_);
641 handshake_complete_ = NULL;
642 }
643 if (bad_certificate_callback_ != NULL) {
644 Dart_DeletePersistentHandle(bad_certificate_callback_);
645 bad_certificate_callback_ = NULL;
646 }
647 FreeResources();
648}
649
650/* Read decrypted data from the filter to the circular buffer */
651int SSLFilter::ProcessReadPlaintextBuffer(int start, int end) {
652 int length = end - start;
653 int bytes_processed = 0;
654 if (SSL_LOG_DATA) {
655 Syslog::Print("Entering ProcessReadPlaintextBuffer with %d bytes\n",
656 length);
657 }
658 if (length > 0) {
659 bytes_processed = SSL_read(
660 ssl_, reinterpret_cast<char*>((buffers_[kReadPlaintext] + start)),
661 length);
662 if (bytes_processed < 0) {
663 int error = SSL_get_error(ssl_, bytes_processed);
664 if (SSL_LOG_DATA) {
665 Syslog::Print("SSL_read returned error %d\n", error);
666 }
667 bytes_processed = 0;
668 }
669 }
670 if (SSL_LOG_DATA) {
671 Syslog::Print("Leaving ProcessReadPlaintextBuffer read %d bytes\n",
672 bytes_processed);
673 }
674 return bytes_processed;
675}
676
677int SSLFilter::ProcessWritePlaintextBuffer(int start, int end) {
678 int length = end - start;
679 if (SSL_LOG_DATA) {
680 Syslog::Print("Entering ProcessWritePlaintextBuffer with %d bytes\n",
681 length);
682 }
683 int bytes_processed =
684 SSL_write(ssl_, buffers_[kWritePlaintext] + start, length);
685 if (bytes_processed < 0) {
686 if (SSL_LOG_DATA) {
687 Syslog::Print("SSL_write returned error %d\n", bytes_processed);
688 }
689 return 0;
690 }
691 if (SSL_LOG_DATA) {
692 Syslog::Print("Leaving ProcessWritePlaintextBuffer wrote %d bytes\n",
693 bytes_processed);
694 }
695 return bytes_processed;
696}
697
698/* Read encrypted data from the circular buffer to the filter */
699int SSLFilter::ProcessReadEncryptedBuffer(int start, int end) {
700 int length = end - start;
701 if (SSL_LOG_DATA) {
702 Syslog::Print("Entering ProcessReadEncryptedBuffer with %d bytes\n",
703 length);
704 }
705 int bytes_processed = 0;
706 if (length > 0) {
707 bytes_processed =
708 BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length);
709 if (bytes_processed <= 0) {
710 bool retry = BIO_should_retry(socket_side_) != 0;
711 if (!retry) {
712 if (SSL_LOG_DATA) {
713 Syslog::Print("BIO_write failed in ReadEncryptedBuffer\n");
714 }
715 }
716 bytes_processed = 0;
717 }
718 }
719 if (SSL_LOG_DATA) {
720 Syslog::Print("Leaving ProcessReadEncryptedBuffer read %d bytes\n",
721 bytes_processed);
722 }
723 return bytes_processed;
724}
725
726int SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) {
727 int length = end - start;
728 int bytes_processed = 0;
729 if (SSL_LOG_DATA) {
730 Syslog::Print("Entering ProcessWriteEncryptedBuffer with %d bytes\n",
731 length);
732 }
733 if (length > 0) {
734 bytes_processed =
735 BIO_read(socket_side_, buffers_[kWriteEncrypted] + start, length);
736 if (bytes_processed < 0) {
737 if (SSL_LOG_DATA) {
738 Syslog::Print("WriteEncrypted BIO_read returned error %d\n",
739 bytes_processed);
740 }
741 return 0;
742 } else {
743 if (SSL_LOG_DATA) {
744 Syslog::Print("WriteEncrypted BIO_read wrote %d bytes\n",
745 bytes_processed);
746 }
747 }
748 }
749 return bytes_processed;
750}
751
752} // namespace bin
753} // namespace dart
754
755#endif // !defined(DART_IO_SECURE_SOCKET_DISABLED)
756