OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "bin/secure_socket.h" | 5 #include "bin/secure_socket.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
10 #include <stdio.h> | 10 #include <stdio.h> |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 PRErrorCode error_code = PR_GetError(); | 53 PRErrorCode error_code = PR_GetError(); |
54 const char* error_message = PR_ErrorToString(error_code, PR_LANGUAGE_EN); | 54 const char* error_message = PR_ErrorToString(error_code, PR_LANGUAGE_EN); |
55 OSError os_error_struct(error_code, error_message, OSError::kNSS); | 55 OSError os_error_struct(error_code, error_message, OSError::kNSS); |
56 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); | 56 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); |
57 Dart_Handle exception = | 57 Dart_Handle exception = |
58 DartUtils::NewDartIOException(exception_type, message, os_error); | 58 DartUtils::NewDartIOException(exception_type, message, os_error); |
59 if (free_message) { | 59 if (free_message) { |
60 free(const_cast<char*>(message)); | 60 free(const_cast<char*>(message)); |
61 } | 61 } |
62 Dart_ThrowException(exception); | 62 Dart_ThrowException(exception); |
| 63 UNREACHABLE(); |
63 } | 64 } |
64 | 65 |
65 | 66 |
66 static void ThrowCertificateException(const char* format, | 67 static void ThrowCertificateException(const char* format, |
67 const char* certificate_name) { | 68 const char* certificate_name) { |
68 int length = strlen(certificate_name); | 69 int length = strlen(certificate_name); |
69 length += strlen(format); | 70 length += strlen(format); |
70 char* message = reinterpret_cast<char*>(malloc(length + 1)); | 71 char* message = reinterpret_cast<char*>(malloc(length + 1)); |
71 if (message == NULL) { | 72 if (message == NULL) { |
72 FATAL("Out of memory formatting CertificateException for throwing"); | 73 FATAL("Out of memory formatting CertificateException for throwing"); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 Dart_Handle port_object = ThrowIfError(Dart_GetNativeArgument(args, 3)); | 115 Dart_Handle port_object = ThrowIfError(Dart_GetNativeArgument(args, 3)); |
115 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); | 116 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); |
116 Dart_Handle certificate_name_object = | 117 Dart_Handle certificate_name_object = |
117 ThrowIfError(Dart_GetNativeArgument(args, 5)); | 118 ThrowIfError(Dart_GetNativeArgument(args, 5)); |
118 bool request_client_certificate = | 119 bool request_client_certificate = |
119 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 6)); | 120 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 6)); |
120 bool require_client_certificate = | 121 bool require_client_certificate = |
121 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 7)); | 122 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 7)); |
122 bool send_client_certificate = | 123 bool send_client_certificate = |
123 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 8)); | 124 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 8)); |
| 125 Dart_Handle protocols_handle = |
| 126 ThrowIfError(Dart_GetNativeArgument(args, 9)); |
124 | 127 |
125 const char* host_name = NULL; | 128 const char* host_name = NULL; |
126 // TODO(whesse): Is truncating a Dart string containing \0 what we want? | 129 // TODO(whesse): Is truncating a Dart string containing \0 what we want? |
127 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); | 130 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); |
128 | 131 |
129 RawAddr raw_addr; | 132 RawAddr raw_addr; |
130 SocketAddress::GetSockAddr(host_sockaddr_storage_object, &raw_addr); | 133 SocketAddress::GetSockAddr(host_sockaddr_storage_object, &raw_addr); |
131 | 134 |
132 int64_t port; | 135 int64_t port; |
133 if (!DartUtils::GetInt64Value(port_object, &port)) { | 136 if (!DartUtils::GetInt64Value(port_object, &port)) { |
134 FATAL("The range of port_object was checked in Dart - it cannot fail here"); | 137 FATAL("The range of port_object was checked in Dart - it cannot fail here"); |
135 } | 138 } |
136 | 139 |
137 const char* certificate_name = NULL; | 140 const char* certificate_name = NULL; |
138 if (Dart_IsString(certificate_name_object)) { | 141 if (Dart_IsString(certificate_name_object)) { |
139 ThrowIfError(Dart_StringToCString(certificate_name_object, | 142 ThrowIfError(Dart_StringToCString(certificate_name_object, |
140 &certificate_name)); | 143 &certificate_name)); |
141 } | 144 } |
142 // If this is a server connection, it must have a certificate to connect with. | 145 // If this is a server connection, it must have a certificate to connect with. |
143 ASSERT(!is_server || certificate_name != NULL); | 146 ASSERT(!is_server || certificate_name != NULL); |
144 | 147 |
| 148 // The protocols_handle is guaranteed to be a valid Uint8List. |
| 149 // It will have the correct length encoding of the protocols array. |
| 150 ASSERT(!Dart_IsNull(protocols_handle)); |
| 151 |
145 GetFilter(args)->Connect(host_name, | 152 GetFilter(args)->Connect(host_name, |
146 &raw_addr, | 153 &raw_addr, |
147 static_cast<int>(port), | 154 static_cast<int>(port), |
148 is_server, | 155 is_server, |
149 certificate_name, | 156 certificate_name, |
150 request_client_certificate, | 157 request_client_certificate, |
151 require_client_certificate, | 158 require_client_certificate, |
152 send_client_certificate); | 159 send_client_certificate, |
| 160 protocols_handle); |
153 } | 161 } |
154 | 162 |
155 | 163 |
156 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { | 164 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { |
157 SSLFilter* filter = GetFilter(args); | 165 SSLFilter* filter = GetFilter(args); |
158 SetFilter(args, NULL); | 166 SetFilter(args, NULL); |
159 filter->Destroy(); | 167 filter->Destroy(); |
160 delete filter; | 168 delete filter; |
161 } | 169 } |
162 | 170 |
163 | 171 |
164 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) { | 172 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) { |
165 GetFilter(args)->Handshake(); | 173 GetFilter(args)->Handshake(); |
166 } | 174 } |
167 | 175 |
168 | 176 |
| 177 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)( |
| 178 Dart_NativeArguments args) { |
| 179 GetFilter(args)->GetSelectedProtocol(args); |
| 180 } |
| 181 |
| 182 |
169 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) { | 183 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) { |
170 bool use_session_cache = | 184 bool use_session_cache = |
171 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1)); | 185 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1)); |
172 bool request_client_certificate = | 186 bool request_client_certificate = |
173 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2)); | 187 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2)); |
174 bool require_client_certificate = | 188 bool require_client_certificate = |
175 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); | 189 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); |
176 GetFilter(args)->Renegotiate(use_session_cache, | 190 GetFilter(args)->Renegotiate(use_session_cache, |
177 request_client_certificate, | 191 request_client_certificate, |
178 require_client_certificate); | 192 require_client_certificate); |
(...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 } | 665 } |
652 | 666 |
653 | 667 |
654 void SSLFilter::Connect(const char* host_name, | 668 void SSLFilter::Connect(const char* host_name, |
655 RawAddr* raw_addr, | 669 RawAddr* raw_addr, |
656 int port, | 670 int port, |
657 bool is_server, | 671 bool is_server, |
658 const char* certificate_name, | 672 const char* certificate_name, |
659 bool request_client_certificate, | 673 bool request_client_certificate, |
660 bool require_client_certificate, | 674 bool require_client_certificate, |
661 bool send_client_certificate) { | 675 bool send_client_certificate, |
| 676 Dart_Handle protocols_handle) { |
662 is_server_ = is_server; | 677 is_server_ = is_server; |
663 if (in_handshake_) { | 678 if (in_handshake_) { |
664 FATAL("Connect called twice on the same _SecureFilter."); | 679 FATAL("Connect called twice on the same _SecureFilter."); |
665 } | 680 } |
666 | 681 |
667 if (!is_server && certificate_name != NULL) { | 682 if (!is_server && certificate_name != NULL) { |
668 client_certificate_name_ = strdup(certificate_name); | 683 client_certificate_name_ = strdup(certificate_name); |
669 } | 684 } |
670 | 685 |
671 filter_ = SSL_ImportFD(NULL, filter_); | 686 filter_ = SSL_ImportFD(NULL, filter_); |
672 if (filter_ == NULL) { | 687 if (filter_ == NULL) { |
673 ThrowPRException("TlsException", "Failed SSL_ImportFD call"); | 688 ThrowPRException("TlsException", "Failed SSL_ImportFD call"); |
674 } | 689 } |
675 | 690 |
| 691 |
| 692 SECStatus status; |
| 693 |
| 694 // Enable ALPN (application layer protocol negogiation) if the caller provides |
| 695 // a valid list of supported protocols. |
| 696 { |
| 697 Dart_TypedData_Type protocols_type; |
| 698 uint8_t* protocol_string = NULL; |
| 699 intptr_t protocol_string_len = 0; |
| 700 |
| 701 Dart_Handle result = Dart_TypedDataAcquireData( |
| 702 protocols_handle, |
| 703 &protocols_type, |
| 704 reinterpret_cast<void**>(&protocol_string), |
| 705 &protocol_string_len); |
| 706 if (Dart_IsError(result)) { |
| 707 Dart_PropagateError(result); |
| 708 } |
| 709 |
| 710 if (protocols_type != Dart_TypedData_kUint8) { |
| 711 Dart_TypedDataReleaseData(protocols_handle); |
| 712 Dart_PropagateError(Dart_NewApiError( |
| 713 "Unexpected type for protocols (expected valid Uint8List).")); |
| 714 } |
| 715 |
| 716 if (protocol_string_len > 0) { |
| 717 status = SSL_OptionSet(filter_, SSL_ENABLE_ALPN, PR_TRUE); |
| 718 ASSERT(status == SECSuccess); |
| 719 |
| 720 status = SSL_SetNextProtoNego(filter_, |
| 721 protocol_string, |
| 722 protocol_string_len); |
| 723 ASSERT(status == SECSuccess); |
| 724 } |
| 725 |
| 726 Dart_TypedDataReleaseData(protocols_handle); |
| 727 } |
| 728 |
676 SSLVersionRange vrange; | 729 SSLVersionRange vrange; |
677 vrange.min = SSL_LIBRARY_VERSION_3_0; | 730 vrange.min = SSL_LIBRARY_VERSION_3_0; |
678 vrange.max = SSL_LIBRARY_VERSION_TLS_1_2; | 731 vrange.max = SSL_LIBRARY_VERSION_TLS_1_2; |
679 SSL_VersionRangeSet(filter_, &vrange); | 732 SSL_VersionRangeSet(filter_, &vrange); |
680 | 733 |
681 SECStatus status; | |
682 if (is_server) { | 734 if (is_server) { |
683 CERTCertificate* certificate = NULL; | 735 CERTCertificate* certificate = NULL; |
684 if (strstr(certificate_name, "CN=") != NULL) { | 736 if (strstr(certificate_name, "CN=") != NULL) { |
685 // Look up certificate using the distinguished name (DN) certificate_name. | 737 // Look up certificate using the distinguished name (DN) certificate_name. |
686 CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB(); | 738 CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB(); |
687 if (certificate_database == NULL) { | 739 if (certificate_database == NULL) { |
688 ThrowPRException("CertificateException", | 740 ThrowPRException("CertificateException", |
689 "Certificate database cannot be loaded"); | 741 "Certificate database cannot be loaded"); |
690 } | 742 } |
691 certificate = CERT_FindCertByNameString(certificate_database, | 743 certificate = CERT_FindCertByNameString(certificate_database, |
(...skipping 21 matching lines...) Expand all Loading... |
713 CERT_DestroyCertificate(certificate); | 765 CERT_DestroyCertificate(certificate); |
714 if (PR_GetError() == -8177) { | 766 if (PR_GetError() == -8177) { |
715 ThrowPRException("CertificateException", | 767 ThrowPRException("CertificateException", |
716 "Certificate database password incorrect"); | 768 "Certificate database password incorrect"); |
717 } else { | 769 } else { |
718 ThrowCertificateException( | 770 ThrowCertificateException( |
719 "Cannot find private key for certificate %s", | 771 "Cannot find private key for certificate %s", |
720 certificate_name); | 772 certificate_name); |
721 } | 773 } |
722 } | 774 } |
| 775 |
723 // kt_rsa (key type RSA) is an enum constant from the NSS libraries. | 776 // kt_rsa (key type RSA) is an enum constant from the NSS libraries. |
724 // TODO(whesse): Allow different key types. | 777 // TODO(whesse): Allow different key types. |
725 status = SSL_ConfigSecureServer(filter_, certificate, key, kt_rsa); | 778 status = SSL_ConfigSecureServer(filter_, certificate, key, kt_rsa); |
726 CERT_DestroyCertificate(certificate); | 779 CERT_DestroyCertificate(certificate); |
727 SECKEY_DestroyPrivateKey(key); | 780 SECKEY_DestroyPrivateKey(key); |
728 if (status != SECSuccess) { | 781 if (status != SECSuccess) { |
729 ThrowCertificateException( | 782 ThrowCertificateException( |
730 "Failed SSL_ConfigSecureServer call with certificate %s", | 783 "Failed SSL_ConfigSecureServer call with certificate %s", |
731 certificate_name); | 784 certificate_name); |
732 } | 785 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
816 ThrowPRException("HandshakeException", | 869 ThrowPRException("HandshakeException", |
817 "Handshake error in server"); | 870 "Handshake error in server"); |
818 } else { | 871 } else { |
819 ThrowPRException("HandshakeException", | 872 ThrowPRException("HandshakeException", |
820 "Handshake error in client"); | 873 "Handshake error in client"); |
821 } | 874 } |
822 } | 875 } |
823 } | 876 } |
824 } | 877 } |
825 | 878 |
| 879 void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) { |
| 880 // Space for the selected protocol. |
| 881 const unsigned int kBufferSize = 256; |
| 882 unsigned char buffer[kBufferSize + 1]; |
| 883 |
| 884 unsigned int outLength = 0; |
| 885 SSLNextProtoState outState; |
| 886 |
| 887 SECStatus status = SSL_GetNextProto( |
| 888 filter_, &outState, buffer, &outLength, kBufferSize); |
| 889 if (status == SECSuccess) { |
| 890 if (outState == SSL_NEXT_PROTO_SELECTED || |
| 891 outState == SSL_NEXT_PROTO_NEGOTIATED) { |
| 892 ASSERT(outLength <= kBufferSize); |
| 893 buffer[outLength] = '\0'; |
| 894 Dart_Handle protocol_string = DartUtils::NewString( |
| 895 reinterpret_cast<const char *>(&buffer[0])); |
| 896 if (Dart_IsError(protocol_string)) { |
| 897 ThrowPRException("HandshakeException", |
| 898 "Protocol selected via ALPN, unable to get protocol " |
| 899 "string."); |
| 900 } else { |
| 901 Dart_SetReturnValue(args, protocol_string); |
| 902 } |
| 903 } else if (outState == SSL_NEXT_PROTO_NO_OVERLAP) { |
| 904 ThrowPRException("HandshakeException", |
| 905 "Client and Server could not agree upon a protocol"); |
| 906 } else if (outState == SSL_NEXT_PROTO_NO_SUPPORT) { |
| 907 // A value of `null` denotes that the client did not support protocol |
| 908 // negogiation. |
| 909 Dart_SetReturnValue(args, Dart_Null()); |
| 910 } else { |
| 911 UNREACHABLE(); |
| 912 } |
| 913 } else { |
| 914 ThrowPRException("HandshakeException", |
| 915 "Could not retrieve selected protocol via ALPN"); |
| 916 } |
| 917 } |
| 918 |
826 | 919 |
827 void SSLFilter::Renegotiate(bool use_session_cache, | 920 void SSLFilter::Renegotiate(bool use_session_cache, |
828 bool request_client_certificate, | 921 bool request_client_certificate, |
829 bool require_client_certificate) { | 922 bool require_client_certificate) { |
830 SECStatus status; | 923 SECStatus status; |
831 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the | 924 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the |
832 // SSL_REQUEST_CERTIFICATE option is also set, so set it. | 925 // SSL_REQUEST_CERTIFICATE option is also set, so set it. |
833 request_client_certificate = | 926 request_client_certificate = |
834 request_client_certificate || require_client_certificate; | 927 request_client_certificate || require_client_certificate; |
835 | 928 |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
960 } | 1053 } |
961 if (bytes_processed > 0) { | 1054 if (bytes_processed > 0) { |
962 memio_PutWriteResult(secret, bytes_processed); | 1055 memio_PutWriteResult(secret, bytes_processed); |
963 } | 1056 } |
964 } | 1057 } |
965 return bytes_processed; | 1058 return bytes_processed; |
966 } | 1059 } |
967 | 1060 |
968 } // namespace bin | 1061 } // namespace bin |
969 } // namespace dart | 1062 } // namespace dart |
OLD | NEW |