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 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
517 Dart_Handle object_; | 517 Dart_Handle object_; |
518 uint8_t* bytes_; | 518 uint8_t* bytes_; |
519 intptr_t bytes_len_; | 519 intptr_t bytes_len_; |
520 BIO* bio_; | 520 BIO* bio_; |
521 bool is_typed_data_; | 521 bool is_typed_data_; |
522 | 522 |
523 DISALLOW_ALLOCATION(); | 523 DISALLOW_ALLOCATION(); |
524 DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO); | 524 DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO); |
525 }; | 525 }; |
526 | 526 |
527 | |
528 template<typename T, void (*free_func)(T*)> | 527 template<typename T, void (*free_func)(T*)> |
529 class ScopedSSLType { | 528 class ScopedSSLType { |
530 public: | 529 public: |
531 explicit ScopedSSLType(T* obj) : obj_(obj) {} | 530 explicit ScopedSSLType(T* obj) : obj_(obj) {} |
532 | 531 |
533 ~ScopedSSLType() { | 532 ~ScopedSSLType() { |
534 if (obj_ != NULL) { | 533 if (obj_ != NULL) { |
535 free_func(obj_); | 534 free_func(obj_); |
536 } | 535 } |
537 } | 536 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
575 | 574 |
576 private: | 575 private: |
577 T* obj_; | 576 T* obj_; |
578 | 577 |
579 DISALLOW_ALLOCATION(); | 578 DISALLOW_ALLOCATION(); |
580 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); | 579 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); |
581 }; | 580 }; |
582 | 581 |
583 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; | 582 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; |
584 typedef ScopedSSLType<X509, X509_free> ScopedX509; | 583 typedef ScopedSSLType<X509, X509_free> ScopedX509; |
585 | |
586 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; | 584 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; |
587 typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free> | |
588 ScopedX509NAMEStack; | |
589 | |
590 | 585 |
591 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and | 586 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and |
592 // if there is no indication that the data is malformed PEM. We assume the data | 587 // if there is no indication that the data is malformed PEM. We assume the data |
593 // is malformed PEM if it contains the start line, i.e. a line with ----- BEGIN. | 588 // is malformed PEM if it contains the start line, i.e. a line with ----- BEGIN. |
594 static bool TryPKCS12(bool pem_success) { | 589 static bool TryPKCS12(bool pem_success) { |
595 uint32_t last_error = ERR_peek_last_error(); | 590 uint32_t last_error = ERR_peek_last_error(); |
596 return !pem_success && | 591 return !pem_success && |
597 (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && | 592 (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && |
598 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); | 593 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); |
599 } | 594 } |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
896 { | 891 { |
897 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 892 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
898 status = UseChainBytes(context, bio.bio(), password); | 893 status = UseChainBytes(context, bio.bio(), password); |
899 } | 894 } |
900 CheckStatus(status, | 895 CheckStatus(status, |
901 "TlsException", | 896 "TlsException", |
902 "Failure in useCertificateChainBytes"); | 897 "Failure in useCertificateChainBytes"); |
903 } | 898 } |
904 | 899 |
905 | 900 |
906 static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio, | 901 static int SetClientAuthoritiesPKCS12(SSL_CTX* context, |
907 const char* password) { | 902 BIO* bio, |
903 const char* password) { | |
908 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | 904 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
909 if (p12.get() == NULL) { | 905 if (p12.get() == NULL) { |
910 return NULL; | 906 return NULL; |
911 } | 907 } |
912 | 908 |
913 ScopedX509NAMEStack result(sk_X509_NAME_new_null()); | |
914 if (result.get() == NULL) { | |
915 return NULL; | |
916 } | |
917 | |
918 EVP_PKEY* key = NULL; | 909 EVP_PKEY* key = NULL; |
919 X509 *cert = NULL; | 910 X509 *cert = NULL; |
920 STACK_OF(X509) *ca_certs = NULL; | 911 STACK_OF(X509) *ca_certs = NULL; |
921 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | 912 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
922 if (status == 0) { | 913 if (status == 0) { |
923 return NULL; | 914 return status; |
924 } | 915 } |
925 | 916 |
926 ScopedX509 x509(cert); | 917 ScopedX509Stack cert_stack(ca_certs); |
927 ScopedX509Stack certs(ca_certs); | 918 status = SSL_CTX_add_client_CA(context, cert); |
928 X509_NAME* x509_name = X509_get_subject_name(x509.get()); | 919 if (status == 0) { |
929 if (x509_name == NULL) { | 920 X509_free(cert); |
930 return NULL; | 921 return status; |
931 } | 922 } |
932 | 923 |
933 x509_name = X509_NAME_dup(x509_name); | 924 X509* ca; |
934 if (x509_name == NULL) { | 925 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { |
935 return NULL; | 926 status = SSL_CTX_add_client_CA(context, ca); |
927 X509_free(ca); // The name has been extracted. | |
928 if (status == 0) { | |
929 return status; | |
930 } | |
936 } | 931 } |
937 | 932 |
938 sk_X509_NAME_push(result.get(), x509_name); | 933 return status; |
939 | |
940 while (true) { | |
941 ScopedX509 ca(sk_X509_shift(certs.get())); | |
942 if (ca.get() == NULL) { | |
943 break; | |
944 } | |
945 | |
946 X509_NAME* x509_name = X509_get_subject_name(ca.get()); | |
947 if (x509_name == NULL) { | |
948 return NULL; | |
949 } | |
950 | |
951 x509_name = X509_NAME_dup(x509_name); | |
952 if (x509_name == NULL) { | |
953 return NULL; | |
954 } | |
955 | |
956 sk_X509_NAME_push(result.get(), x509_name); | |
957 } | |
958 | |
959 return result.release(); | |
960 } | 934 } |
961 | 935 |
962 | 936 |
963 static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) { | 937 static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) { |
964 ScopedX509NAMEStack result(sk_X509_NAME_new_null()); | 938 int status = 0; |
965 if (result.get() == NULL) { | 939 X509* cert = NULL; |
966 return NULL; | 940 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
941 status = SSL_CTX_add_client_CA(context, cert); | |
942 X509_free(cert); // The name has been extracted. | |
943 if (status == 0) { | |
944 return status; | |
945 } | |
967 } | 946 } |
968 | 947 |
969 while (true) { | 948 // If bio does not contain PEM data, the first call to PEM_read_bio_X509 will |
970 ScopedX509 x509(PEM_read_bio_X509(bio, NULL, NULL, NULL)); | 949 // return NULL, and the while-loop will exit while status is still 0. |
971 if (x509.get() == NULL) { | |
972 break; | |
973 } | |
974 | |
975 X509_NAME* x509_name = X509_get_subject_name(x509.get()); | |
976 if (x509_name == NULL) { | |
977 return NULL; | |
978 } | |
979 | |
980 // Duplicate the name to put it on the stack. | |
981 x509_name = X509_NAME_dup(x509_name); | |
982 if (x509_name == NULL) { | |
983 return NULL; | |
984 } | |
985 sk_X509_NAME_push(result.get(), x509_name); | |
986 } | |
987 | |
988 if (sk_X509_NAME_num(result.get()) == 0) { | |
989 // The data was not PEM. | |
990 return NULL; | |
991 } | |
992 | |
993 uint32_t err = ERR_peek_last_error(); | 950 uint32_t err = ERR_peek_last_error(); |
994 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || | 951 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || |
995 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { | 952 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { |
996 // The data was trying to be PEM, but was malformed. | 953 // If bio contains data that is trying to be PEM but is malformed, then |
997 return NULL; | 954 // this case will be triggered. |
955 status = 0; | |
998 } | 956 } |
999 | 957 |
1000 return result.release(); | 958 return status; |
1001 } | 959 } |
1002 | 960 |
1003 | 961 |
1004 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio, | 962 static int SetClientAuthorities(SSL_CTX* context, |
1005 const char* password) { | 963 BIO* bio, |
1006 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio); | 964 const char* password) { |
1007 if (TryPKCS12(result != NULL)) { | 965 int status = SetClientAuthoritiesPEM(context, bio); |
966 if (TryPKCS12(status != 0)) { | |
Ivan Posva
2016/03/02 21:56:50
Can we please rewrite this to be less backwards to
zra
2016/03/02 23:12:34
Done.
| |
1008 ERR_clear_error(); | 967 ERR_clear_error(); |
1009 BIO_reset(bio); | 968 BIO_reset(bio); |
1010 result = GetCertificateNamesPKCS12(bio, password); | 969 status = SetClientAuthoritiesPKCS12(context, bio, password); |
1011 } else if (result != NULL) { | 970 } else if (status != 0) { |
1012 // The PEM file was successfully parsed. | 971 // The PEM file was successfully parsed. |
1013 ERR_clear_error(); | 972 ERR_clear_error(); |
1014 } | 973 } |
1015 return result; | 974 return status; |
1016 } | 975 } |
1017 | 976 |
1018 | 977 |
1019 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( | 978 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( |
1020 Dart_NativeArguments args) { | 979 Dart_NativeArguments args) { |
1021 SSL_CTX* context = GetSecurityContext(args); | 980 SSL_CTX* context = GetSecurityContext(args); |
1022 const char* password = GetPasswordArgument(args, 2); | 981 const char* password = GetPasswordArgument(args, 2); |
1023 STACK_OF(X509_NAME)* certificate_names; | |
1024 | 982 |
983 int status; | |
1025 { | 984 { |
1026 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 985 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
1027 certificate_names = GetCertificateNames(bio.bio(), password); | 986 status = SetClientAuthorities(context, bio.bio(), password); |
1028 } | 987 } |
1029 | 988 |
1030 if (certificate_names != NULL) { | 989 CheckStatus(status, |
1031 SSL_CTX_set_client_CA_list(context, certificate_names); | 990 "TlsException", |
1032 } else { | 991 "Failure in setClientAuthoritiesBytes"); |
1033 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
1034 "Could not load certificate names from file in SetClientAuthorities")); | |
1035 } | |
1036 } | 992 } |
1037 | 993 |
1038 | 994 |
1039 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( | 995 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( |
1040 Dart_NativeArguments args) { | 996 Dart_NativeArguments args) { |
1041 SSL_CTX* context = GetSecurityContext(args); | 997 SSL_CTX* context = GetSecurityContext(args); |
1042 Dart_Handle protocols_handle = | 998 Dart_Handle protocols_handle = |
1043 ThrowIfError(Dart_GetNativeArgument(args, 1)); | 999 ThrowIfError(Dart_GetNativeArgument(args, 1)); |
1044 Dart_Handle is_server_handle = | 1000 Dart_Handle is_server_handle = |
1045 ThrowIfError(Dart_GetNativeArgument(args, 2)); | 1001 ThrowIfError(Dart_GetNativeArgument(args, 2)); |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1713 } else { | 1669 } else { |
1714 if (SSL_LOG_DATA) Log::Print( | 1670 if (SSL_LOG_DATA) Log::Print( |
1715 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); | 1671 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); |
1716 } | 1672 } |
1717 } | 1673 } |
1718 return bytes_processed; | 1674 return bytes_processed; |
1719 } | 1675 } |
1720 | 1676 |
1721 } // namespace bin | 1677 } // namespace bin |
1722 } // namespace dart | 1678 } // namespace dart |
OLD | NEW |