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

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

Issue 1689873003: Fix PEM error checking (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Remove unused field from SSLFilter Created 4 years, 10 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 | « runtime/bin/secure_socket.h ('k') | 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 490 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); 501 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType);
502 }; 502 };
503 503
504 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; 504 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12;
505 typedef ScopedSSLType<X509, X509_free> ScopedX509; 505 typedef ScopedSSLType<X509, X509_free> ScopedX509;
506 506
507 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; 507 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack;
508 typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free> 508 typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free>
509 ScopedX509NAMEStack; 509 ScopedX509NAMEStack;
510 510
511
512 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and
513 // if there is no indication that the data is malformed PEM. We assume the data
514 // is malformed PEM if it contains the start line, i.e. a line with ----- BEGIN.
515 static bool TryPKCS12(bool pem_success) {
516 uint32_t last_error = ERR_peek_last_error();
517 return !pem_success &&
518 (ERR_GET_LIB(last_error) == ERR_LIB_PEM) &&
519 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE);
520 }
521
522
511 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { 523 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) {
512 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); 524 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
513 if (p12.get() == NULL) { 525 if (p12.get() == NULL) {
514 return NULL; 526 return NULL;
515 } 527 }
516 528
517 EVP_PKEY* key = NULL; 529 EVP_PKEY* key = NULL;
518 X509 *cert = NULL; 530 X509 *cert = NULL;
519 STACK_OF(X509) *ca_certs = NULL; 531 STACK_OF(X509) *ca_certs = NULL;
520 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); 532 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
521 if (status == 0) { 533 if (status == 0) {
522 return NULL; 534 return NULL;
523 } 535 }
524 536
525 // We only care about the private key. 537 // We only care about the private key.
526 ScopedX509 delete_cert(cert); 538 ScopedX509 delete_cert(cert);
527 ScopedX509Stack delete_ca_certs(ca_certs); 539 ScopedX509Stack delete_ca_certs(ca_certs);
528 return key; 540 return key;
529 } 541 }
530 542
531 543
532 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { 544 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) {
533 EVP_PKEY *key = PEM_read_bio_PrivateKey( 545 EVP_PKEY *key = PEM_read_bio_PrivateKey(
534 bio, NULL, PasswordCallback, const_cast<char*>(password)); 546 bio, NULL, PasswordCallback, const_cast<char*>(password));
535 547 if (TryPKCS12(key != NULL)) {
536 // If the data doesn't contain the PEM start line, try reading as PKCS12.
537 uint32_t err = ERR_peek_last_error();
538 if ((key == NULL) &&
539 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
540 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
541 // Reset the bio, and clear the error from trying to read as PEM. 548 // Reset the bio, and clear the error from trying to read as PEM.
542 ERR_clear_error(); 549 ERR_clear_error();
543 BIO_reset(bio); 550 BIO_reset(bio);
544 551
545 // Try to decode as PKCS12 552 // Try to decode as PKCS12
546 key = GetPrivateKeyPKCS12(bio, password); 553 key = GetPrivateKeyPKCS12(bio, password);
547 } 554 }
548 return key; 555 return key;
549 } 556 }
550 557
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 int status = 0; 641 int status = 0;
635 X509* cert = NULL; 642 X509* cert = NULL;
636 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { 643 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
637 status = X509_STORE_add_cert(store, cert); 644 status = X509_STORE_add_cert(store, cert);
638 if (status == 0) { 645 if (status == 0) {
639 X509_free(cert); 646 X509_free(cert);
640 return status; 647 return status;
641 } 648 }
642 } 649 }
643 650
651 // If bio does not contain PEM data, the first call to PEM_read_bio_X509 will
652 // return NULL, and the while-loop will exit while status is still 0.
644 uint32_t err = ERR_peek_last_error(); 653 uint32_t err = ERR_peek_last_error();
645 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || 654 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
646 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { 655 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
647 // Some real error happened. 656 // If bio contains data that is trying to be PEM but is malformed, then
657 // this case will be triggered.
648 status = 0; 658 status = 0;
649 } 659 }
650 660
651 return status; 661 return status;
652 } 662 }
653 663
654 664
655 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) { 665 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
656 int status = SetTrustedCertificatesBytesPEM(context, bio); 666 int status = SetTrustedCertificatesBytesPEM(context, bio);
657 uint32_t err = ERR_peek_last_error(); 667 if (TryPKCS12(status != 0)) {
658 if ((status == 0) &&
659 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
660 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
661 ERR_clear_error(); 668 ERR_clear_error();
662 BIO_reset(bio); 669 BIO_reset(bio);
663 status = SetTrustedCertificatesBytesPKCS12(context, bio); 670 status = SetTrustedCertificatesBytesPKCS12(context, bio);
664 } else if (status != 0) { 671 } else if (status != 0) {
665 // The PEM file was successfully parsed. 672 // The PEM file was successfully parsed.
666 ERR_clear_error(); 673 ERR_clear_error();
667 } 674 }
668 return status; 675 return status;
669 } 676 }
670 677
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
773 status = SSL_CTX_add0_chain_cert(context, ca); 780 status = SSL_CTX_add0_chain_cert(context, ca);
774 if (status == 0) { 781 if (status == 0) {
775 X509_free(ca); 782 X509_free(ca);
776 return status; 783 return status;
777 } 784 }
778 // Note that we must not free `ca` if it was successfully added to the 785 // Note that we must not free `ca` if it was successfully added to the
779 // chain. We must free the main certificate x509, though since its reference 786 // chain. We must free the main certificate x509, though since its reference
780 // count is increased by SSL_CTX_use_certificate. 787 // count is increased by SSL_CTX_use_certificate.
781 } 788 }
782 789
790 // If bio does not contain PEM data, the first call to PEM_read_bio_X509 will
791 // return NULL, and the while-loop will exit while status is still 0.
783 uint32_t err = ERR_peek_last_error(); 792 uint32_t err = ERR_peek_last_error();
784 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || 793 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
785 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { 794 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
786 // Some real error happened. 795 // If bio contains data that is trying to be PEM but is malformed, then
796 // this case will be triggered.
787 status = 0; 797 status = 0;
788 } 798 }
789 799
790 return status; 800 return status;
791 } 801 }
792 802
793 803
794 static int UseChainBytes(SSL_CTX* context, BIO* bio) { 804 static int UseChainBytes(SSL_CTX* context, BIO* bio) {
795 int status = UseChainBytesPEM(context, bio); 805 int status = UseChainBytesPEM(context, bio);
796 uint32_t err = ERR_peek_last_error(); 806 if (TryPKCS12(status != 0)) {
797 if ((status == 0) &&
798 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
799 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
800 ERR_clear_error(); 807 ERR_clear_error();
801 BIO_reset(bio); 808 BIO_reset(bio);
802 status = UseChainBytesPKCS12(context, bio); 809 status = UseChainBytesPKCS12(context, bio);
803 } else if (status != 0) { 810 } else if (status != 0) {
804 // The PEM file was successfully parsed. 811 // The PEM file was successfully read.
805 ERR_clear_error(); 812 ERR_clear_error();
806 } 813 }
807 return status; 814 return status;
808 } 815 }
809 816
810 817
811 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( 818 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
812 Dart_NativeArguments args) { 819 Dart_NativeArguments args) {
813 SSL_CTX* context = GetSecurityContext(args); 820 SSL_CTX* context = GetSecurityContext(args);
814 int status; 821 int status;
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 } 912 }
906 913
907 // Duplicate the name to put it on the stack. 914 // Duplicate the name to put it on the stack.
908 x509_name = X509_NAME_dup(x509_name); 915 x509_name = X509_NAME_dup(x509_name);
909 if (x509_name == NULL) { 916 if (x509_name == NULL) {
910 return NULL; 917 return NULL;
911 } 918 }
912 sk_X509_NAME_push(result.get(), x509_name); 919 sk_X509_NAME_push(result.get(), x509_name);
913 } 920 }
914 921
922 if (sk_X509_NAME_num(result.get()) == 0) {
923 // The data was not PEM.
924 return NULL;
925 }
926
915 uint32_t err = ERR_peek_last_error(); 927 uint32_t err = ERR_peek_last_error();
916 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) || 928 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
917 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) { 929 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
918 // Some real error happened. 930 // The data was trying to be PEM, but was malformed.
919 return NULL; 931 return NULL;
920 } 932 }
921 933
922 return result.release(); 934 return result.release();
923 } 935 }
924 936
925 937
926 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) { 938 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) {
927 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio); 939 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio);
928 uint32_t err = ERR_peek_last_error(); 940 if (TryPKCS12(result != NULL)) {
929 if ((result == NULL) &&
930 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
931 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
932 ERR_clear_error(); 941 ERR_clear_error();
933 BIO_reset(bio); 942 BIO_reset(bio);
934 result = GetCertificateNamesPKCS12(bio); 943 result = GetCertificateNamesPKCS12(bio);
935 } else if (result != NULL) { 944 } else if (result != NULL) {
936 // The PEM file was successfully parsed. 945 // The PEM file was successfully parsed.
937 ERR_clear_error(); 946 ERR_clear_error();
938 } 947 }
939 return result; 948 return result;
940 } 949 }
941 950
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after
1575 } else { 1584 } else {
1576 if (SSL_LOG_DATA) Log::Print( 1585 if (SSL_LOG_DATA) Log::Print(
1577 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); 1586 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed);
1578 } 1587 }
1579 } 1588 }
1580 return bytes_processed; 1589 return bytes_processed;
1581 } 1590 }
1582 1591
1583 } // namespace bin 1592 } // namespace bin
1584 } // namespace dart 1593 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/bin/secure_socket.h ('k') | tests/standalone/io/security_context_argument_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698