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

Unified Diff: runtime/bin/secure_socket.cc

Issue 16858011: dart:io | Enable multithreaded secure networking encryption. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address all comments Created 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/bin/secure_socket.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/secure_socket.cc
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 482f9a640cbb4e333041f481bc062c6346851e36..e4fab51ee2973a3e4e1f7e0e6c772c515bcc2253 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -41,6 +41,13 @@ dart::Mutex SSLFilter::mutex_; // To protect library initialization.
// be null if only secure client sockets are used.
const char* SSLFilter::password_ = NULL;
+// Forward declaration.
+static void ProcessFilter(Dart_Port dest_port_id,
+ Dart_Port reply_port_id,
+ Dart_CObject* message);
+
+NativeService SSLFilter::filter_service_("FilterService", ProcessFilter, 16);
+
static const int kSSLFilterNativeFieldIndex = 0;
static SSLFilter* GetFilter(Dart_NativeArguments args) {
@@ -177,22 +184,6 @@ void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
}
-void FUNCTION_NAME(SecureSocket_ProcessBuffer)(Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle buffer_id_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
- int64_t buffer_id = DartUtils::GetIntegerValue(buffer_id_object);
- if (buffer_id < 0 || buffer_id >= SSLFilter::kNumBuffers) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal argument to ProcessBuffer"));
- }
-
- intptr_t bytes_read =
- GetFilter(args)->ProcessBuffer(static_cast<int>(buffer_id));
- Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
- Dart_ExitScope();
-}
-
-
void FUNCTION_NAME(SecureSocket_InitializeLibrary)
(Dart_NativeArguments args) {
Dart_EnterScope();
@@ -247,6 +238,131 @@ void FUNCTION_NAME(SecureSocket_PeerCertificate)
}
+void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args));
+ Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
+ Dart_ExitScope();
+}
+
+
+/**
+ * Pushes data through the SSL filter, reading and writing from circular
+ * buffers shared with Dart.
+ *
+ * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
+ * pass encrypted and plaintext data to and from the C++ SSLFilter object.
+ *
+ * ProcessFilter is called with a CObject array containing the pointer to
+ * the SSLFilter, encoded as an int, and the start and end positions of the
+ * valid data in the four circular buffers. The function only reads from
+ * the valid data area of the input buffers, and only writes to the free
+ * area of the output buffers. The function returns the new start and end
+ * positions in the buffers, but it only updates start for input buffers, and
+ * end for output buffers. Therefore, the Dart thread can simultaneously
+ * write to the free space and end pointer of input buffers, and read from
+ * the data space of output buffers, and modify the start pointer.
+ *
+ * When ProcessFilter returns, the Dart thread is responsible for combining
+ * the updated pointers from Dart and C++, to make the new valid state of
+ * the circular buffer.
+ */
+static void ProcessFilter(Dart_Port dest_port_id,
+ Dart_Port reply_port_id,
+ Dart_CObject* message) {
+ CObjectArray args(message);
+ CObjectIntptr filter_object(args[0]);
+ SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
+ bool in_handshake = CObjectBool(args[1]).Value();
+ int starts[SSLFilter::kNumBuffers];
+ int ends[SSLFilter::kNumBuffers];
+ for (int i = 0; i < SSLFilter::kNumBuffers; ++i) {
+ starts[i] = CObjectInt32(args[2 * i + 2]).Value();
+ ends[i] = CObjectInt32(args[2 * i + 3]).Value();
+ }
+
+ filter->ProcessAllBuffers(starts, ends, in_handshake);
+
+ for (int i = 0; i < SSLFilter::kNumBuffers; ++i) {
+ args[2 * i + 2]->AsApiCObject()->value.as_int32 = starts[i];
+ args[2 * i + 3]->AsApiCObject()->value.as_int32 = ends[i];
+ }
+ Dart_PostCObject(reply_port_id, args.AsApiCObject());
+}
+
+
+void SSLFilter::ProcessAllBuffers(int starts[kNumBuffers],
+ int ends[kNumBuffers],
+ bool in_handshake) {
+ for (int i = 0; i < kNumBuffers; ++i) {
+ if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue;
+ int start = starts[i];
+ int end = ends[i];
+ int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
+ switch (i) {
+ case kReadPlaintext:
+ case kWriteEncrypted:
+ // Write data to the circular buffer's free space. If the buffer
+ // is full, neither if statement is executed and nothing happens.
+ if (start <= end) {
+ // If the free space may be split into two segments,
+ // then the first is [end, size), unless start == 0.
+ // Then, since the last free byte is at position start - 2,
+ // the interval is [end, size - 1).
+ int buffer_end = (start == 0) ? size - 1 : size;
+ int bytes = (i == kReadPlaintext) ?
+ ProcessReadPlaintextBuffer(end, buffer_end) :
+ ProcessWriteEncryptedBuffer(end, buffer_end);
+ end += bytes;
+ ASSERT(end <= size);
+ if (end == size) end = 0;
+ }
+ if (start > end + 1) {
+ int bytes = (i == kReadPlaintext) ?
+ ProcessReadPlaintextBuffer(end, start - 1) :
+ ProcessWriteEncryptedBuffer(end, start - 1);
+ end += bytes;
+ ASSERT(end < start);
+ }
+ ends[i] = end;
+ break;
+ case kReadEncrypted:
+ // Read data from circular buffer.
+ if (end < start) {
+ // Data may be split into two segments. In this case,
+ // the first is [start, size).
+ int bytes = ProcessReadEncryptedBuffer(start, size);
+ start += bytes;
+ ASSERT(start <= size);
+ if (start == size) start = 0;
+ }
+ if (start < end) {
+ int bytes = ProcessReadEncryptedBuffer(start, end);
+ start += bytes;
+ ASSERT(start <= end);
+ }
+ starts[i] = start;
+ break;
+ case kWritePlaintext:
+ if (end < start) {
+ // Data is split into two segments, [start, size) and [0, end).
+ int bytes = ProcessWritePlaintextBuffer(start, size, 0, end);
+ start += bytes;
+ if (start >= size) start -= size;
+ } else {
+ int bytes = ProcessWritePlaintextBuffer(start, end, 0, 0);
+ start += bytes;
+ ASSERT(start <= end);
+ }
+ starts[i] = start;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+}
+
+
static Dart_Handle X509FromCertificate(CERTCertificate* certificate) {
PRTime start_validity;
PRTime end_validity;
@@ -307,15 +423,13 @@ void SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
// Create SSLFilter buffers as ExternalUint8Array objects.
Dart_Handle dart_buffers_object = ThrowIfError(
Dart_GetField(dart_this, DartUtils::NewString("buffers")));
- Dart_Handle dart_buffer_object =
- Dart_ListGetAt(dart_buffers_object, kReadPlaintext);
- Dart_Handle external_buffer_class =
- Dart_InstanceGetClass(dart_buffer_object);
+ Dart_Handle secure_filter_impl_class =
+ Dart_InstanceGetClass(dart_this);
Dart_Handle dart_buffer_size = ThrowIfError(
- Dart_GetField(external_buffer_class, DartUtils::NewString("SIZE")));
+ Dart_GetField(secure_filter_impl_class, DartUtils::NewString("SIZE")));
int64_t buffer_size = DartUtils::GetIntegerValue(dart_buffer_size);
Dart_Handle dart_encrypted_buffer_size = ThrowIfError(
- Dart_GetField(external_buffer_class,
+ Dart_GetField(secure_filter_impl_class,
DartUtils::NewString("ENCRYPTED_SIZE")));
int64_t encrypted_buffer_size =
DartUtils::GetIntegerValue(dart_encrypted_buffer_size);
@@ -333,7 +447,7 @@ void SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
Dart_Handle data_identifier = DartUtils::NewString("data");
for (int i = 0; i < kNumBuffers; ++i) {
- int size = isEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
+ int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
dart_buffer_objects_[i] =
Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i));
ASSERT(dart_buffer_objects_[i] != NULL);
@@ -494,6 +608,11 @@ void SSLFilter::Connect(const char* host_name,
ThrowPRException("Failed SSL_ImportFD call");
}
+ SSLVersionRange vrange;
+ vrange.min = SSL_LIBRARY_VERSION_3_0;
+ vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
+ SSL_VersionRangeSet(filter_, &vrange);
+
SECStatus status;
if (is_server) {
PK11_SetPasswordFunc(PasswordCallback);
@@ -648,106 +767,112 @@ void SSLFilter::Destroy() {
}
-intptr_t SSLFilter::ProcessBuffer(int buffer_index) {
- int size = isEncrypted(buffer_index) ? encrypted_buffer_size_ : buffer_size_;
- Dart_Handle buffer_object =
- Dart_HandleFromPersistent(dart_buffer_objects_[buffer_index]);
- Dart_Handle start_object = ThrowIfError(
- Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_start_)));
- Dart_Handle length_object = ThrowIfError(
- Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_length_)));
- int64_t unsafe_start = DartUtils::GetIntegerValue(start_object);
- int64_t unsafe_length = DartUtils::GetIntegerValue(length_object);
- ASSERT(unsafe_start >= 0);
- ASSERT(unsafe_start < size);
- ASSERT(unsafe_length >= 0);
- ASSERT(unsafe_length <= size);
- int start = static_cast<int>(unsafe_start);
- int length = static_cast<int>(unsafe_length);
- uint8_t* buffer = buffers_[buffer_index];
-
+intptr_t SSLFilter::ProcessReadPlaintextBuffer(int start, int end) {
+ int length = end - start;
int bytes_processed = 0;
- switch (buffer_index) {
- case kReadPlaintext: {
- int bytes_free = size - start - length;
- bytes_processed = PR_Read(filter_,
- buffer + start + length,
- bytes_free);
- if (bytes_processed < 0) {
- ASSERT(bytes_processed == -1);
- // TODO(whesse): Handle unexpected errors here.
- PRErrorCode pr_error = PR_GetError();
- if (PR_WOULD_BLOCK_ERROR != pr_error) {
- ThrowPRException("Error reading plaintext from SSLFilter");
- }
- bytes_processed = 0;
+ if (length > 0) {
+ bytes_processed = PR_Read(filter_,
+ buffers_[kReadPlaintext] + start,
+ length);
+ if (bytes_processed < 0) {
+ ASSERT(bytes_processed == -1);
+ PRErrorCode pr_error = PR_GetError();
+ if (PR_WOULD_BLOCK_ERROR != pr_error) {
+ // TODO(11383): Handle unexpected errors here.
+ FATAL("Error reading plaintext from SSLFilter");
}
- break;
+ bytes_processed = 0;
}
+ }
+ return bytes_processed;
+}
- case kWriteEncrypted: {
- const uint8_t* buf1;
- const uint8_t* buf2;
- unsigned int len1;
- unsigned int len2;
- int bytes_free = size - start - length;
- memio_Private* secret = memio_GetSecret(filter_);
- memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2);
- int bytes_to_send =
- dart::Utils::Minimum(len1, static_cast<unsigned>(bytes_free));
- if (bytes_to_send > 0) {
- memmove(buffer + start + length, buf1, bytes_to_send);
- bytes_processed = bytes_to_send;
- }
- bytes_to_send = dart::Utils::Minimum(len2,
- static_cast<unsigned>(bytes_free - bytes_processed));
- if (bytes_to_send > 0) {
- memmove(buffer + start + length + bytes_processed, buf2,
- bytes_to_send);
- bytes_processed += bytes_to_send;
- }
- if (bytes_processed > 0) {
- memio_PutWriteResult(secret, bytes_processed);
- }
- break;
- }
- case kReadEncrypted: {
- if (length > 0) {
- bytes_processed = length;
- memio_Private* secret = memio_GetSecret(filter_);
- uint8_t* filter_buf;
- int free_bytes = memio_GetReadParams(secret, &filter_buf);
- if (free_bytes < bytes_processed) bytes_processed = free_bytes;
- memmove(filter_buf,
- buffer + start,
- bytes_processed);
- memio_PutReadResult(secret, bytes_processed);
- }
- break;
+intptr_t SSLFilter::ProcessWritePlaintextBuffer(int start1, int end1,
+ int start2, int end2) {
+ PRIOVec ranges[2];
+ uint8_t* buffer = buffers_[kWritePlaintext];
+ ranges[0].iov_base = reinterpret_cast<char*>(buffer + start1);
+ ranges[0].iov_len = end1 - start1;
+ ranges[1].iov_base = reinterpret_cast<char*>(buffer + start2);
+ ranges[1].iov_len = end2 - start2;
+ int bytes_processed = PR_Writev(filter_, ranges, 2, PR_INTERVAL_NO_TIMEOUT);
+ if (bytes_processed < 0) {
+ ASSERT(bytes_processed == -1);
+ PRErrorCode pr_error = PR_GetError();
+ if (PR_WOULD_BLOCK_ERROR != pr_error) {
+ // TODO(11383): Handle unexpected errors here.
+ FATAL("Error reading plaintext from SSLFilter");
}
+ bytes_processed = 0;
+ }
+ return bytes_processed;
+}
- case kWritePlaintext: {
- if (length > 0) {
- bytes_processed = PR_Write(filter_,
- buffer + start,
- length);
- }
- if (bytes_processed < 0) {
- ASSERT(bytes_processed == -1);
- // TODO(whesse): Handle unexpected errors here.
- PRErrorCode pr_error = PR_GetError();
- if (PR_WOULD_BLOCK_ERROR != pr_error) {
- ThrowPRException("Error reading plaintext from SSLFilter");
- }
- bytes_processed = 0;
- }
- break;
+intptr_t SSLFilter::ProcessReadEncryptedBuffer(int start, int end) {
+ int length = end - start;
+ int bytes_processed = 0;
+ if (length > 0) {
+ memio_Private* secret = memio_GetSecret(filter_);
+ uint8_t* filter_buf;
+ int free_bytes = memio_GetReadParams(secret, &filter_buf);
+ bytes_processed = dart::Utils::Minimum(length, free_bytes);
+ memmove(filter_buf, buffers_[kReadEncrypted] + start, bytes_processed);
+ memio_PutReadResult(secret, bytes_processed);
+ }
+ return bytes_processed;
+}
+
+
+intptr_t SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) {
+ int length = end - start;
+ int bytes_processed = 0;
+ if (length > 0) {
+ uint8_t* buffer = buffers_[kWriteEncrypted];
+ const uint8_t* buf1;
+ const uint8_t* buf2;
+ unsigned int len1;
+ unsigned int len2;
+ memio_Private* secret = memio_GetSecret(filter_);
+ memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2);
+ int bytes_to_send =
+ dart::Utils::Minimum(len1, static_cast<unsigned>(length));
+ if (bytes_to_send > 0) {
+ memmove(buffer + start, buf1, bytes_to_send);
+ bytes_processed = bytes_to_send;
+ }
+ bytes_to_send = dart::Utils::Minimum(len2,
+ static_cast<unsigned>(length - bytes_processed));
+ if (bytes_to_send > 0) {
+ memmove(buffer + start + bytes_processed, buf2, bytes_to_send);
+ bytes_processed += bytes_to_send;
+ }
+ if (bytes_processed > 0) {
+ memio_PutWriteResult(secret, bytes_processed);
}
}
return bytes_processed;
}
+
+Dart_Port SSLFilter::GetServicePort() {
+ return filter_service_.GetServicePort();
+}
+
+
+void FUNCTION_NAME(SecureSocket_NewServicePort)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_SetReturnValue(args, Dart_Null());
+ Dart_Port service_port = SSLFilter::GetServicePort();
+ if (service_port != ILLEGAL_PORT) {
+ // Return a send port for the service port.
+ Dart_Handle send_port = Dart_NewSendPort(service_port);
+ Dart_SetReturnValue(args, send_port);
+ }
+ Dart_ExitScope();
+}
+
+
} // namespace bin
} // namespace dart
« no previous file with comments | « runtime/bin/secure_socket.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698