Index: dart/runtime/bin/secure_socket.cc |
diff --git a/dart/runtime/bin/secure_socket.cc b/dart/runtime/bin/secure_socket.cc |
index 350bc64afa395e1ca399f5441a3b524712b3ceaf..24c7ba43194db24c8a1675e877d5f679bf4c24ea 100644 |
--- a/dart/runtime/bin/secure_socket.cc |
+++ b/dart/runtime/bin/secure_socket.cc |
@@ -121,6 +121,8 @@ void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { |
DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 7)); |
bool send_client_certificate = |
DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 8)); |
+ Dart_Handle client_protocols_handle = |
+ ThrowIfError(Dart_GetNativeArgument(args, 9)); |
const char* host_name = NULL; |
// TODO(whesse): Is truncating a Dart string containing \0 what we want? |
@@ -142,6 +144,28 @@ void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { |
// If this is a server connection, it must have a certificate to connect with. |
ASSERT(!is_server || certificate_name != NULL); |
+ |
+ |
+ Dart_TypedData_Type protocols_type; |
+ uint8_t* protocol_string = NULL; |
+ intptr_t protocol_string_len = 0; |
+ |
+ ASSERT(!Dart_IsNull(client_protocols_handle)); |
+ Dart_Handle result = Dart_TypedDataAcquireData( |
+ client_protocols_handle, |
+ &protocols_type, |
+ reinterpret_cast<void**>(&protocol_string), |
+ &protocol_string_len); |
+ if (Dart_IsError(result)) { |
+ Dart_PropagateError(result); |
+ } |
+ |
+ if (protocols_type != Dart_TypedData_kUint8) { |
+ Dart_TypedDataReleaseData(client_protocols_handle); |
+ Dart_PropagateError( |
+ Dart_NewApiError("Unexpected type for protocols")); |
+ } |
+ |
GetFilter(args)->Connect(host_name, |
&raw_addr, |
static_cast<int>(port), |
@@ -149,7 +173,10 @@ void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) { |
certificate_name, |
request_client_certificate, |
require_client_certificate, |
- send_client_certificate); |
+ send_client_certificate, |
+ protocol_string, |
+ protocol_string_len); |
kustermann
2014/10/03 13:25:26
If GetFilter(args)->Connect() fails, can it unwind
Søren Gjesse
2014/10/03 15:47:04
As discussed off-line you need to release it befor
kustermann
2014/11/07 16:20:03
Instead of making more calls into the VM & copying
|
+ Dart_TypedDataReleaseData(client_protocols_handle); |
} |
@@ -166,6 +193,12 @@ void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) { |
} |
+void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)( |
+ Dart_NativeArguments args) { |
+ GetFilter(args)->GetSelectedProtocol(args); |
+} |
+ |
+ |
void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) { |
bool use_session_cache = |
DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1)); |
@@ -658,7 +691,9 @@ void SSLFilter::Connect(const char* host_name, |
const char* certificate_name, |
bool request_client_certificate, |
bool require_client_certificate, |
- bool send_client_certificate) { |
+ bool send_client_certificate, |
+ uint8_t *protocols, |
+ intptr_t protocols_len) { |
is_server_ = is_server; |
if (in_handshake_) { |
FATAL("Connect called twice on the same _SecureFilter."); |
@@ -673,12 +708,22 @@ void SSLFilter::Connect(const char* host_name, |
ThrowPRException("TlsException", "Failed SSL_ImportFD call"); |
} |
+ |
+ SECStatus status; |
+ |
+ if (protocols_len > 0) { |
+ status = SSL_OptionSet(filter_, SSL_ENABLE_ALPN, PR_TRUE); |
+ ASSERT(status == SECSuccess); |
+ |
+ status = SSL_SetNextProtoNego(filter_, protocols, protocols_len); |
+ ASSERT(status == SECSuccess); |
+ } |
+ |
SSLVersionRange vrange; |
vrange.min = SSL_LIBRARY_VERSION_3_0; |
vrange.max = SSL_LIBRARY_VERSION_TLS_1_2; |
SSL_VersionRangeSet(filter_, &vrange); |
- SECStatus status; |
if (is_server) { |
CERTCertificate* certificate = NULL; |
if (strstr(certificate_name, "CN=") != NULL) { |
@@ -823,6 +868,45 @@ void SSLFilter::Handshake() { |
} |
} |
+void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) { |
+ // Space for the selected protocol. |
+ const intptr_t kBufferSize = 256; |
+ unsigned char buffer[kBufferSize + 1]; |
+ |
+ unsigned int outLength = 0; |
+ SSLNextProtoState outState; |
+ |
+ SECStatus status = SSL_GetNextProto( |
+ filter_, &outState, buffer, &outLength, kBufferSize); |
+ if (status == SECSuccess) { |
+ if (outState == SSL_NEXT_PROTO_SELECTED || |
+ outState == SSL_NEXT_PROTO_NEGOTIATED) { |
+ ASSERT(outLength <= kBufferSize); |
+ buffer[outLength] = '\0'; |
+ Dart_Handle protocol_string = DartUtils::NewString( |
+ reinterpret_cast<const char *>(&buffer[0])); |
+ if (Dart_IsError(protocol_string)) { |
+ ThrowPRException("HandshakeException", |
+ "Protocol selected via ALPN was non-UTF8"); |
Søren Gjesse
2014/10/03 15:47:04
In principle this could also be an OOM i think, or
kustermann
2014/11/07 16:20:02
Rephrased message.
|
+ } else { |
+ Dart_SetReturnValue(args, protocol_string); |
+ } |
+ } else if (outState == SSL_NEXT_PROTO_NO_OVERLAP) { |
+ ThrowPRException("HandshakeException", |
+ "Client and Server could not agree upon a protocol"); |
+ } else if (outState == SSL_NEXT_PROTO_NO_SUPPORT) { |
+ // A value of `null` denotes that the client did not support protocol |
+ // negogiation. |
+ Dart_SetReturnValue(args, Dart_Null()); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ } else { |
+ ThrowPRException("HandshakeException", |
+ "Could not retrieve selected protocol via ALPN"); |
+ } |
+} |
+ |
void SSLFilter::Renegotiate(bool use_session_cache, |
bool request_client_certificate, |