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() { |
595 uint32_t last_error = ERR_peek_last_error(); | 590 uint32_t last_error = ERR_peek_last_error(); |
596 return !pem_success && | 591 return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && |
597 (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && | 592 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); |
598 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); | |
599 } | 593 } |
600 | 594 |
601 | 595 |
602 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { | 596 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { |
603 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | 597 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
604 if (p12.get() == NULL) { | 598 if (p12.get() == NULL) { |
605 return NULL; | 599 return NULL; |
606 } | 600 } |
607 | 601 |
608 EVP_PKEY* key = NULL; | 602 EVP_PKEY* key = NULL; |
609 X509 *cert = NULL; | 603 X509 *cert = NULL; |
610 STACK_OF(X509) *ca_certs = NULL; | 604 STACK_OF(X509) *ca_certs = NULL; |
611 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | 605 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
612 if (status == 0) { | 606 if (status == 0) { |
613 return NULL; | 607 return NULL; |
614 } | 608 } |
615 | 609 |
616 // We only care about the private key. | 610 // We only care about the private key. |
617 ScopedX509 delete_cert(cert); | 611 ScopedX509 delete_cert(cert); |
618 ScopedX509Stack delete_ca_certs(ca_certs); | 612 ScopedX509Stack delete_ca_certs(ca_certs); |
619 return key; | 613 return key; |
620 } | 614 } |
621 | 615 |
622 | 616 |
623 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { | 617 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { |
624 EVP_PKEY *key = PEM_read_bio_PrivateKey( | 618 EVP_PKEY *key = PEM_read_bio_PrivateKey( |
625 bio, NULL, PasswordCallback, const_cast<char*>(password)); | 619 bio, NULL, PasswordCallback, const_cast<char*>(password)); |
626 if (TryPKCS12(key != NULL)) { | 620 if ((key == NULL) && TryPKCS12()) { |
627 // Reset the bio, and clear the error from trying to read as PEM. | 621 // Reset the bio, and clear the error from trying to read as PEM. |
628 ERR_clear_error(); | 622 ERR_clear_error(); |
629 BIO_reset(bio); | 623 BIO_reset(bio); |
630 | 624 |
631 // Try to decode as PKCS12 | 625 // Try to decode as PKCS12 |
632 key = GetPrivateKeyPKCS12(bio, password); | 626 key = GetPrivateKeyPKCS12(bio, password); |
633 } | 627 } |
634 return key; | 628 return key; |
635 } | 629 } |
636 | 630 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 } | 730 } |
737 | 731 |
738 return status; | 732 return status; |
739 } | 733 } |
740 | 734 |
741 | 735 |
742 static int SetTrustedCertificatesBytes(SSL_CTX* context, | 736 static int SetTrustedCertificatesBytes(SSL_CTX* context, |
743 BIO* bio, | 737 BIO* bio, |
744 const char* password) { | 738 const char* password) { |
745 int status = SetTrustedCertificatesBytesPEM(context, bio); | 739 int status = SetTrustedCertificatesBytesPEM(context, bio); |
746 if (TryPKCS12(status != 0)) { | 740 if ((status == 0) && TryPKCS12()) { |
Ivan Posva
2016/03/02 23:22:15
This would read even better (at least for me) and
zra
2016/03/03 00:06:24
Done.
| |
747 ERR_clear_error(); | 741 ERR_clear_error(); |
748 BIO_reset(bio); | 742 BIO_reset(bio); |
749 status = SetTrustedCertificatesBytesPKCS12(context, bio, password); | 743 status = SetTrustedCertificatesBytesPKCS12(context, bio, password); |
750 } else if (status != 0) { | 744 } else if (status != 0) { |
751 // The PEM file was successfully parsed. | 745 // The PEM file was successfully parsed. |
752 ERR_clear_error(); | 746 ERR_clear_error(); |
753 } | 747 } |
754 return status; | 748 return status; |
755 } | 749 } |
756 | 750 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
869 // this case will be triggered. | 863 // this case will be triggered. |
870 status = 0; | 864 status = 0; |
871 } | 865 } |
872 | 866 |
873 return status; | 867 return status; |
874 } | 868 } |
875 | 869 |
876 | 870 |
877 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) { | 871 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) { |
878 int status = UseChainBytesPEM(context, bio); | 872 int status = UseChainBytesPEM(context, bio); |
879 if (TryPKCS12(status != 0)) { | 873 if ((status == 0) && TryPKCS12()) { |
880 ERR_clear_error(); | 874 ERR_clear_error(); |
881 BIO_reset(bio); | 875 BIO_reset(bio); |
882 status = UseChainBytesPKCS12(context, bio, password); | 876 status = UseChainBytesPKCS12(context, bio, password); |
883 } else if (status != 0) { | 877 } else if (status != 0) { |
884 // The PEM file was successfully read. | 878 // The PEM file was successfully read. |
885 ERR_clear_error(); | 879 ERR_clear_error(); |
886 } | 880 } |
887 return status; | 881 return status; |
888 } | 882 } |
889 | 883 |
890 | 884 |
891 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( | 885 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( |
892 Dart_NativeArguments args) { | 886 Dart_NativeArguments args) { |
893 SSL_CTX* context = GetSecurityContext(args); | 887 SSL_CTX* context = GetSecurityContext(args); |
894 const char* password = GetPasswordArgument(args, 2); | 888 const char* password = GetPasswordArgument(args, 2); |
895 int status; | 889 int status; |
896 { | 890 { |
897 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 891 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
898 status = UseChainBytes(context, bio.bio(), password); | 892 status = UseChainBytes(context, bio.bio(), password); |
899 } | 893 } |
900 CheckStatus(status, | 894 CheckStatus(status, |
901 "TlsException", | 895 "TlsException", |
902 "Failure in useCertificateChainBytes"); | 896 "Failure in useCertificateChainBytes"); |
903 } | 897 } |
904 | 898 |
905 | 899 |
906 static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio, | 900 static int SetClientAuthoritiesPKCS12(SSL_CTX* context, |
907 const char* password) { | 901 BIO* bio, |
902 const char* password) { | |
908 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | 903 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
909 if (p12.get() == NULL) { | 904 if (p12.get() == NULL) { |
910 return NULL; | 905 return NULL; |
Ivan Posva
2016/03/02 23:22:15
Returning NULL in a function typed as returning an
zra
2016/03/03 00:06:24
Done.
| |
911 } | 906 } |
912 | 907 |
913 ScopedX509NAMEStack result(sk_X509_NAME_new_null()); | |
914 if (result.get() == NULL) { | |
915 return NULL; | |
916 } | |
917 | |
918 EVP_PKEY* key = NULL; | 908 EVP_PKEY* key = NULL; |
919 X509 *cert = NULL; | 909 X509 *cert = NULL; |
920 STACK_OF(X509) *ca_certs = NULL; | 910 STACK_OF(X509) *ca_certs = NULL; |
921 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | 911 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
922 if (status == 0) { | 912 if (status == 0) { |
923 return NULL; | 913 return status; |
924 } | 914 } |
925 | 915 |
926 ScopedX509 x509(cert); | 916 ScopedX509Stack cert_stack(ca_certs); |
927 ScopedX509Stack certs(ca_certs); | 917 status = SSL_CTX_add_client_CA(context, cert); |
928 X509_NAME* x509_name = X509_get_subject_name(x509.get()); | 918 if (status == 0) { |
929 if (x509_name == NULL) { | 919 X509_free(cert); |
930 return NULL; | 920 return status; |
931 } | 921 } |
932 | 922 |
933 x509_name = X509_NAME_dup(x509_name); | 923 X509* ca; |
934 if (x509_name == NULL) { | 924 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { |
935 return NULL; | 925 status = SSL_CTX_add_client_CA(context, ca); |
926 X509_free(ca); // The name has been extracted. | |
927 if (status == 0) { | |
928 return status; | |
929 } | |
936 } | 930 } |
937 | 931 |
938 sk_X509_NAME_push(result.get(), x509_name); | 932 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 } | 933 } |
961 | 934 |
962 | 935 |
963 static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) { | 936 static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) { |
964 ScopedX509NAMEStack result(sk_X509_NAME_new_null()); | 937 int status = 0; |
965 if (result.get() == NULL) { | 938 X509* cert = NULL; |
966 return NULL; | 939 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
940 status = SSL_CTX_add_client_CA(context, cert); | |
941 X509_free(cert); // The name has been extracted. | |
942 if (status == 0) { | |
943 return status; | |
944 } | |
967 } | 945 } |
968 | 946 |
969 while (true) { | 947 // 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)); | 948 // 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(); | 949 uint32_t err = ERR_peek_last_error(); |
994 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || | 950 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || |
Ivan Posva
2016/03/02 23:22:15
Isn't this essemtially TryPKCS12()?
zra
2016/03/03 00:06:24
Renamed TryPKCS12 to NoPEMStartLine, and used it i
| |
995 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { | 951 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { |
996 // The data was trying to be PEM, but was malformed. | 952 // If bio contains data that is trying to be PEM but is malformed, then |
997 return NULL; | 953 // this case will be triggered. |
954 status = 0; | |
998 } | 955 } |
999 | 956 |
1000 return result.release(); | 957 return status; |
1001 } | 958 } |
1002 | 959 |
1003 | 960 |
1004 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio, | 961 static int SetClientAuthorities(SSL_CTX* context, |
1005 const char* password) { | 962 BIO* bio, |
1006 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio); | 963 const char* password) { |
1007 if (TryPKCS12(result != NULL)) { | 964 int status = SetClientAuthoritiesPEM(context, bio); |
965 if ((status == 0) && TryPKCS12()) { | |
1008 ERR_clear_error(); | 966 ERR_clear_error(); |
1009 BIO_reset(bio); | 967 BIO_reset(bio); |
1010 result = GetCertificateNamesPKCS12(bio, password); | 968 status = SetClientAuthoritiesPKCS12(context, bio, password); |
1011 } else if (result != NULL) { | 969 } else if (status != 0) { |
1012 // The PEM file was successfully parsed. | 970 // The PEM file was successfully parsed. |
1013 ERR_clear_error(); | 971 ERR_clear_error(); |
1014 } | 972 } |
1015 return result; | 973 return status; |
1016 } | 974 } |
1017 | 975 |
1018 | 976 |
1019 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( | 977 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( |
1020 Dart_NativeArguments args) { | 978 Dart_NativeArguments args) { |
1021 SSL_CTX* context = GetSecurityContext(args); | 979 SSL_CTX* context = GetSecurityContext(args); |
1022 const char* password = GetPasswordArgument(args, 2); | 980 const char* password = GetPasswordArgument(args, 2); |
1023 STACK_OF(X509_NAME)* certificate_names; | |
1024 | 981 |
982 int status; | |
1025 { | 983 { |
1026 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 984 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
1027 certificate_names = GetCertificateNames(bio.bio(), password); | 985 status = SetClientAuthorities(context, bio.bio(), password); |
1028 } | 986 } |
1029 | 987 |
1030 if (certificate_names != NULL) { | 988 CheckStatus(status, |
1031 SSL_CTX_set_client_CA_list(context, certificate_names); | 989 "TlsException", |
1032 } else { | 990 "Failure in setClientAuthoritiesBytes"); |
1033 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
1034 "Could not load certificate names from file in SetClientAuthorities")); | |
1035 } | |
1036 } | 991 } |
1037 | 992 |
1038 | 993 |
1039 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( | 994 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( |
1040 Dart_NativeArguments args) { | 995 Dart_NativeArguments args) { |
1041 SSL_CTX* context = GetSecurityContext(args); | 996 SSL_CTX* context = GetSecurityContext(args); |
1042 Dart_Handle protocols_handle = | 997 Dart_Handle protocols_handle = |
1043 ThrowIfError(Dart_GetNativeArgument(args, 1)); | 998 ThrowIfError(Dart_GetNativeArgument(args, 1)); |
1044 Dart_Handle is_server_handle = | 999 Dart_Handle is_server_handle = |
1045 ThrowIfError(Dart_GetNativeArgument(args, 2)); | 1000 ThrowIfError(Dart_GetNativeArgument(args, 2)); |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1713 } else { | 1668 } else { |
1714 if (SSL_LOG_DATA) Log::Print( | 1669 if (SSL_LOG_DATA) Log::Print( |
1715 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); | 1670 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); |
1716 } | 1671 } |
1717 } | 1672 } |
1718 return bytes_processed; | 1673 return bytes_processed; |
1719 } | 1674 } |
1720 | 1675 |
1721 } // namespace bin | 1676 } // namespace bin |
1722 } // namespace dart | 1677 } // namespace dart |
OLD | NEW |