Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: runtime/bin/secure_socket.cc

Issue 1761583002: Regularize some errors thrown by SecureContext. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/standalone/io/security_context_argument_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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;
584 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack;
585 585
586 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; 586 static bool NoPEMStartLine() {
587 typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free>
588 ScopedX509NAMEStack;
589
590
591 // 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
593 // is malformed PEM if it contains the start line, i.e. a line with ----- BEGIN.
594 static bool TryPKCS12(bool pem_success) {
595 uint32_t last_error = ERR_peek_last_error(); 587 uint32_t last_error = ERR_peek_last_error();
596 return !pem_success && 588 return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) &&
597 (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && 589 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE);
598 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE);
599 } 590 }
600 591
601 592
602 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { 593 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) {
603 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); 594 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
604 if (p12.get() == NULL) { 595 if (p12.get() == NULL) {
605 return NULL; 596 return NULL;
606 } 597 }
607 598
608 EVP_PKEY* key = NULL; 599 EVP_PKEY* key = NULL;
609 X509 *cert = NULL; 600 X509 *cert = NULL;
610 STACK_OF(X509) *ca_certs = NULL; 601 STACK_OF(X509) *ca_certs = NULL;
611 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); 602 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
612 if (status == 0) { 603 if (status == 0) {
613 return NULL; 604 return NULL;
614 } 605 }
615 606
616 // We only care about the private key. 607 // We only care about the private key.
617 ScopedX509 delete_cert(cert); 608 ScopedX509 delete_cert(cert);
618 ScopedX509Stack delete_ca_certs(ca_certs); 609 ScopedX509Stack delete_ca_certs(ca_certs);
619 return key; 610 return key;
620 } 611 }
621 612
622 613
623 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { 614 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) {
624 EVP_PKEY *key = PEM_read_bio_PrivateKey( 615 EVP_PKEY *key = PEM_read_bio_PrivateKey(
625 bio, NULL, PasswordCallback, const_cast<char*>(password)); 616 bio, NULL, PasswordCallback, const_cast<char*>(password));
626 if (TryPKCS12(key != NULL)) { 617 if (key == NULL) {
627 // Reset the bio, and clear the error from trying to read as PEM. 618 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and
628 ERR_clear_error(); 619 // if there is no indication that the data is malformed PEM. We assume the
629 BIO_reset(bio); 620 // data is malformed PEM if it contains the start line, i.e. a line
621 // with ----- BEGIN.
622 if (NoPEMStartLine()) {
623 // Reset the bio, and clear the error from trying to read as PEM.
624 ERR_clear_error();
625 BIO_reset(bio);
630 626
631 // Try to decode as PKCS12 627 // Try to decode as PKCS12.
632 key = GetPrivateKeyPKCS12(bio, password); 628 key = GetPrivateKeyPKCS12(bio, password);
629 }
633 } 630 }
634 return key; 631 return key;
635 } 632 }
636 633
637 634
638 static const char* GetPasswordArgument(Dart_NativeArguments args, 635 static const char* GetPasswordArgument(Dart_NativeArguments args,
639 intptr_t index) { 636 intptr_t index) {
640 Dart_Handle password_object = 637 Dart_Handle password_object =
641 ThrowIfError(Dart_GetNativeArgument(args, index)); 638 ThrowIfError(Dart_GetNativeArgument(args, index));
642 const char* password = NULL; 639 const char* password = NULL;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
718 int status = 0; 715 int status = 0;
719 X509* cert = NULL; 716 X509* cert = NULL;
720 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { 717 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
721 status = X509_STORE_add_cert(store, cert); 718 status = X509_STORE_add_cert(store, cert);
722 if (status == 0) { 719 if (status == 0) {
723 X509_free(cert); 720 X509_free(cert);
724 return status; 721 return status;
725 } 722 }
726 } 723 }
727 724
728 // If bio does not contain PEM data, the first call to PEM_read_bio_X509 will 725 // If no PEM start line is found, it means that we read to the end of the
729 // return NULL, and the while-loop will exit while status is still 0. 726 // file, or that the file isn't PEM. In the first case, status will be
730 uint32_t err = ERR_peek_last_error(); 727 // non-zero indicating success. In the second case, status will be 0,
731 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || 728 // indicating that we should try to read as PKCS12. If there is some other
732 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { 729 // error, we return it up to the caller.
733 // If bio contains data that is trying to be PEM but is malformed, then 730 return NoPEMStartLine() ? status : 0;
734 // this case will be triggered.
735 status = 0;
736 }
737
738 return status;
739 } 731 }
740 732
741 733
742 static int SetTrustedCertificatesBytes(SSL_CTX* context, 734 static int SetTrustedCertificatesBytes(SSL_CTX* context,
743 BIO* bio, 735 BIO* bio,
744 const char* password) { 736 const char* password) {
745 int status = SetTrustedCertificatesBytesPEM(context, bio); 737 int status = SetTrustedCertificatesBytesPEM(context, bio);
746 if (TryPKCS12(status != 0)) { 738 if (status == 0) {
747 ERR_clear_error(); 739 if (NoPEMStartLine()) {
748 BIO_reset(bio); 740 ERR_clear_error();
749 status = SetTrustedCertificatesBytesPKCS12(context, bio, password); 741 BIO_reset(bio);
750 } else if (status != 0) { 742 status = SetTrustedCertificatesBytesPKCS12(context, bio, password);
743 }
744 } else {
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
757 751
758 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( 752 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
759 Dart_NativeArguments args) { 753 Dart_NativeArguments args) {
760 SSL_CTX* context = GetSecurityContext(args); 754 SSL_CTX* context = GetSecurityContext(args);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
853 status = SSL_CTX_add0_chain_cert(context, ca); 847 status = SSL_CTX_add0_chain_cert(context, ca);
854 if (status == 0) { 848 if (status == 0) {
855 X509_free(ca); 849 X509_free(ca);
856 return status; 850 return status;
857 } 851 }
858 // Note that we must not free `ca` if it was successfully added to the 852 // Note that we must not free `ca` if it was successfully added to the
859 // chain. We must free the main certificate x509, though since its reference 853 // chain. We must free the main certificate x509, though since its reference
860 // count is increased by SSL_CTX_use_certificate. 854 // count is increased by SSL_CTX_use_certificate.
861 } 855 }
862 856
863 // If bio does not contain PEM data, the first call to PEM_read_bio_X509 will 857 return NoPEMStartLine() ? status : 0;
864 // return NULL, and the while-loop will exit while status is still 0.
865 uint32_t err = ERR_peek_last_error();
866 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
867 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
868 // If bio contains data that is trying to be PEM but is malformed, then
869 // this case will be triggered.
870 status = 0;
871 }
872
873 return status;
874 } 858 }
875 859
876 860
877 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) { 861 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) {
878 int status = UseChainBytesPEM(context, bio); 862 int status = UseChainBytesPEM(context, bio);
879 if (TryPKCS12(status != 0)) { 863 if (status == 0) {
880 ERR_clear_error(); 864 if (NoPEMStartLine()) {
881 BIO_reset(bio); 865 ERR_clear_error();
882 status = UseChainBytesPKCS12(context, bio, password); 866 BIO_reset(bio);
883 } else if (status != 0) { 867 status = UseChainBytesPKCS12(context, bio, password);
868 }
869 } else {
884 // The PEM file was successfully read. 870 // The PEM file was successfully read.
885 ERR_clear_error(); 871 ERR_clear_error();
886 } 872 }
887 return status; 873 return status;
888 } 874 }
889 875
890 876
891 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( 877 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
892 Dart_NativeArguments args) { 878 Dart_NativeArguments args) {
893 SSL_CTX* context = GetSecurityContext(args); 879 SSL_CTX* context = GetSecurityContext(args);
894 const char* password = GetPasswordArgument(args, 2); 880 const char* password = GetPasswordArgument(args, 2);
895 int status; 881 int status;
896 { 882 {
897 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 883 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
898 status = UseChainBytes(context, bio.bio(), password); 884 status = UseChainBytes(context, bio.bio(), password);
899 } 885 }
900 CheckStatus(status, 886 CheckStatus(status,
901 "TlsException", 887 "TlsException",
902 "Failure in useCertificateChainBytes"); 888 "Failure in useCertificateChainBytes");
903 } 889 }
904 890
905 891
906 static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio, 892 static int SetClientAuthoritiesPKCS12(SSL_CTX* context,
907 const char* password) { 893 BIO* bio,
894 const char* password) {
908 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); 895 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
909 if (p12.get() == NULL) { 896 if (p12.get() == NULL) {
910 return NULL; 897 return 0;
911 }
912
913 ScopedX509NAMEStack result(sk_X509_NAME_new_null());
914 if (result.get() == NULL) {
915 return NULL;
916 } 898 }
917 899
918 EVP_PKEY* key = NULL; 900 EVP_PKEY* key = NULL;
919 X509 *cert = NULL; 901 X509 *cert = NULL;
920 STACK_OF(X509) *ca_certs = NULL; 902 STACK_OF(X509) *ca_certs = NULL;
921 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); 903 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
922 if (status == 0) { 904 if (status == 0) {
923 return NULL; 905 return status;
924 } 906 }
925 907
926 ScopedX509 x509(cert); 908 ScopedX509Stack cert_stack(ca_certs);
927 ScopedX509Stack certs(ca_certs); 909 status = SSL_CTX_add_client_CA(context, cert);
928 X509_NAME* x509_name = X509_get_subject_name(x509.get()); 910 if (status == 0) {
929 if (x509_name == NULL) { 911 X509_free(cert);
930 return NULL; 912 return status;
931 } 913 }
932 914
933 x509_name = X509_NAME_dup(x509_name); 915 X509* ca;
934 if (x509_name == NULL) { 916 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) {
935 return NULL; 917 status = SSL_CTX_add_client_CA(context, ca);
918 X509_free(ca); // The name has been extracted.
919 if (status == 0) {
920 return status;
921 }
936 } 922 }
937 923
938 sk_X509_NAME_push(result.get(), x509_name); 924 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 } 925 }
961 926
962 927
963 static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) { 928 static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) {
964 ScopedX509NAMEStack result(sk_X509_NAME_new_null()); 929 int status = 0;
965 if (result.get() == NULL) { 930 X509* cert = NULL;
966 return NULL; 931 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
932 status = SSL_CTX_add_client_CA(context, cert);
933 X509_free(cert); // The name has been extracted.
934 if (status == 0) {
935 return status;
936 }
967 } 937 }
968 938 return NoPEMStartLine() ? status : 0;
969 while (true) {
970 ScopedX509 x509(PEM_read_bio_X509(bio, NULL, NULL, NULL));
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();
994 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
995 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
996 // The data was trying to be PEM, but was malformed.
997 return NULL;
998 }
999
1000 return result.release();
1001 } 939 }
1002 940
1003 941
1004 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio, 942 static int SetClientAuthorities(SSL_CTX* context,
1005 const char* password) { 943 BIO* bio,
1006 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio); 944 const char* password) {
1007 if (TryPKCS12(result != NULL)) { 945 int status = SetClientAuthoritiesPEM(context, bio);
1008 ERR_clear_error(); 946 if (status == 0) {
1009 BIO_reset(bio); 947 if (NoPEMStartLine()) {
1010 result = GetCertificateNamesPKCS12(bio, password); 948 ERR_clear_error();
1011 } else if (result != NULL) { 949 BIO_reset(bio);
950 status = SetClientAuthoritiesPKCS12(context, bio, password);
951 }
952 } else {
1012 // The PEM file was successfully parsed. 953 // The PEM file was successfully parsed.
1013 ERR_clear_error(); 954 ERR_clear_error();
1014 } 955 }
1015 return result; 956 return status;
1016 } 957 }
1017 958
1018 959
1019 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( 960 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
1020 Dart_NativeArguments args) { 961 Dart_NativeArguments args) {
1021 SSL_CTX* context = GetSecurityContext(args); 962 SSL_CTX* context = GetSecurityContext(args);
1022 const char* password = GetPasswordArgument(args, 2); 963 const char* password = GetPasswordArgument(args, 2);
1023 STACK_OF(X509_NAME)* certificate_names;
1024 964
965 int status;
1025 { 966 {
1026 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 967 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
1027 certificate_names = GetCertificateNames(bio.bio(), password); 968 status = SetClientAuthorities(context, bio.bio(), password);
1028 } 969 }
1029 970
1030 if (certificate_names != NULL) { 971 CheckStatus(status,
1031 SSL_CTX_set_client_CA_list(context, certificate_names); 972 "TlsException",
1032 } else { 973 "Failure in setClientAuthoritiesBytes");
1033 Dart_ThrowException(DartUtils::NewDartArgumentError(
1034 "Could not load certificate names from file in SetClientAuthorities"));
1035 }
1036 } 974 }
1037 975
1038 976
1039 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( 977 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
1040 Dart_NativeArguments args) { 978 Dart_NativeArguments args) {
1041 SSL_CTX* context = GetSecurityContext(args); 979 SSL_CTX* context = GetSecurityContext(args);
1042 Dart_Handle protocols_handle = 980 Dart_Handle protocols_handle =
1043 ThrowIfError(Dart_GetNativeArgument(args, 1)); 981 ThrowIfError(Dart_GetNativeArgument(args, 1));
1044 Dart_Handle is_server_handle = 982 Dart_Handle is_server_handle =
1045 ThrowIfError(Dart_GetNativeArgument(args, 2)); 983 ThrowIfError(Dart_GetNativeArgument(args, 2));
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after
1713 } else { 1651 } else {
1714 if (SSL_LOG_DATA) Log::Print( 1652 if (SSL_LOG_DATA) Log::Print(
1715 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); 1653 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed);
1716 } 1654 }
1717 } 1655 }
1718 return bytes_processed; 1656 return bytes_processed;
1719 } 1657 }
1720 1658
1721 } // namespace bin 1659 } // namespace bin
1722 } // namespace dart 1660 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | tests/standalone/io/security_context_argument_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698