| 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 |