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_filter.cc

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

Powered by Google App Engine
This is Rietveld 408576698