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

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