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> |
11 #include <string.h> | 11 #include <string.h> |
12 | 12 |
13 #include <openssl/bio.h> | 13 #include <openssl/bio.h> |
14 #include <openssl/err.h> | 14 #include <openssl/err.h> |
15 #include <openssl/pkcs12.h> | |
15 #include <openssl/safestack.h> | 16 #include <openssl/safestack.h> |
16 #include <openssl/ssl.h> | 17 #include <openssl/ssl.h> |
17 #include <openssl/tls1.h> | 18 #include <openssl/tls1.h> |
18 #include <openssl/x509.h> | 19 #include <openssl/x509.h> |
19 | 20 |
20 #include "bin/builtin.h" | 21 #include "bin/builtin.h" |
21 #include "bin/dartutils.h" | 22 #include "bin/dartutils.h" |
22 #include "bin/lockers.h" | 23 #include "bin/lockers.h" |
23 #include "bin/log.h" | 24 #include "bin/log.h" |
24 #include "bin/socket.h" | 25 #include "bin/socket.h" |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
374 } | 375 } |
375 ThrowIOException(status, type, message); | 376 ThrowIOException(status, type, message); |
376 } | 377 } |
377 | 378 |
378 | 379 |
379 // Where the argument to the constructor is the handle for an object | 380 // Where the argument to the constructor is the handle for an object |
380 // implementing List<int>, this class creates a scope in which a memory-backed | 381 // implementing List<int>, this class creates a scope in which a memory-backed |
381 // BIO is allocated. Leaving the scope cleans up the BIO and the buffer that | 382 // BIO is allocated. Leaving the scope cleans up the BIO and the buffer that |
382 // was used to create it. | 383 // was used to create it. |
383 // | 384 // |
384 // Do not make Dart_ API calls while in a MemBIOScope. | 385 // Do not make Dart_ API calls while in a ScopedMemBIO. |
385 // Do not call Dart_PropagateError while in a MemBIOScope. | 386 // Do not call Dart_PropagateError while in a ScopedMemBIO. |
386 class MemBIOScope { | 387 class ScopedMemBIO { |
387 public: | 388 public: |
388 explicit MemBIOScope(Dart_Handle object) { | 389 explicit ScopedMemBIO(Dart_Handle object) { |
389 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { | 390 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { |
390 Dart_ThrowException(DartUtils::NewDartArgumentError( | 391 Dart_ThrowException(DartUtils::NewDartArgumentError( |
391 "Argument is not a List<int>")); | 392 "Argument is not a List<int>")); |
392 } | 393 } |
393 | 394 |
394 uint8_t* bytes = NULL; | 395 uint8_t* bytes = NULL; |
395 intptr_t bytes_len = 0; | 396 intptr_t bytes_len = 0; |
396 bool is_typed_data = false; | 397 bool is_typed_data = false; |
397 if (Dart_IsTypedData(object)) { | 398 if (Dart_IsTypedData(object)) { |
398 is_typed_data = true; | 399 is_typed_data = true; |
(...skipping 12 matching lines...) Expand all Loading... | |
411 } | 412 } |
412 | 413 |
413 object_ = object; | 414 object_ = object; |
414 bytes_ = bytes; | 415 bytes_ = bytes; |
415 bytes_len_ = bytes_len; | 416 bytes_len_ = bytes_len; |
416 bio_ = BIO_new_mem_buf(bytes, bytes_len); | 417 bio_ = BIO_new_mem_buf(bytes, bytes_len); |
417 ASSERT(bio_ != NULL); | 418 ASSERT(bio_ != NULL); |
418 is_typed_data_ = is_typed_data; | 419 is_typed_data_ = is_typed_data; |
419 } | 420 } |
420 | 421 |
421 ~MemBIOScope() { | 422 ~ScopedMemBIO() { |
422 ASSERT(bio_ != NULL); | 423 ASSERT(bio_ != NULL); |
423 if (is_typed_data_) { | 424 if (is_typed_data_) { |
424 BIO_free(bio_); | 425 BIO_free(bio_); |
425 ThrowIfError(Dart_TypedDataReleaseData(object_)); | 426 ThrowIfError(Dart_TypedDataReleaseData(object_)); |
426 } else { | 427 } else { |
427 BIO_free(bio_); | 428 BIO_free(bio_); |
428 } | 429 } |
429 } | 430 } |
430 | 431 |
431 BIO* bio() { | 432 BIO* bio() { |
432 ASSERT(bio_ != NULL); | 433 ASSERT(bio_ != NULL); |
433 return bio_; | 434 return bio_; |
434 } | 435 } |
435 | 436 |
436 private: | 437 private: |
437 Dart_Handle object_; | 438 Dart_Handle object_; |
438 uint8_t* bytes_; | 439 uint8_t* bytes_; |
439 intptr_t bytes_len_; | 440 intptr_t bytes_len_; |
440 BIO* bio_; | 441 BIO* bio_; |
441 bool is_typed_data_; | 442 bool is_typed_data_; |
442 | 443 |
443 DISALLOW_ALLOCATION(); | 444 DISALLOW_ALLOCATION(); |
444 DISALLOW_COPY_AND_ASSIGN(MemBIOScope); | 445 DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO); |
445 }; | 446 }; |
446 | 447 |
447 | 448 |
449 template<typename T, void (*free_func)(T*)> | |
450 class ScopedSSLType { | |
451 public: | |
452 explicit ScopedSSLType(T* obj) : obj_(obj) {} | |
453 | |
454 ~ScopedSSLType() { | |
455 if (obj_ != NULL) { | |
456 free_func(obj_); | |
457 } | |
458 } | |
459 | |
460 T* get() { return obj_; } | |
461 const T* get() const { return obj_; } | |
462 | |
463 T* release() { | |
464 T* result = obj_; | |
465 obj_ = NULL; | |
466 return result; | |
467 } | |
468 | |
469 private: | |
470 T* obj_; | |
471 | |
472 DISALLOW_ALLOCATION(); | |
473 DISALLOW_COPY_AND_ASSIGN(ScopedSSLType); | |
474 }; | |
475 | |
476 template<typename T, typename E, void (*func)(E*)> | |
477 class ScopedSSLStackType { | |
478 public: | |
479 explicit ScopedSSLStackType(T* obj) : obj_(obj) {} | |
480 | |
481 ~ScopedSSLStackType() { | |
482 if (obj_ != NULL) { | |
483 sk_pop_free(reinterpret_cast<_STACK*>(obj_), | |
484 reinterpret_cast<void (*)(void *)>(func)); | |
485 } | |
486 } | |
487 | |
488 T* get() { return obj_; } | |
489 const T* get() const { return obj_; } | |
490 | |
491 T* release() { | |
492 T* result = obj_; | |
493 obj_ = NULL; | |
494 return result; | |
495 } | |
496 | |
497 private: | |
498 T* obj_; | |
499 | |
500 DISALLOW_ALLOCATION(); | |
501 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); | |
502 }; | |
503 | |
504 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; | |
505 typedef ScopedSSLType<X509, X509_free> ScopedX509; | |
506 | |
507 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; | |
508 typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free> | |
509 ScopedX509NAMEStack; | |
510 | |
511 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) { | |
512 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
513 if (p12.get() == NULL) { | |
514 return NULL; | |
515 } | |
516 | |
517 EVP_PKEY* key = NULL; | |
518 X509 *cert = NULL; | |
519 STACK_OF(X509) *ca_certs = NULL; | |
520 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | |
521 if (status == 0) { | |
522 return NULL; | |
523 } | |
524 | |
525 // We only care about the private key. | |
526 ScopedX509 delete_cert(cert); | |
527 ScopedX509Stack delete_ca_certs(ca_certs); | |
528 return key; | |
529 } | |
530 | |
531 | |
532 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) { | |
533 EVP_PKEY *key = PEM_read_bio_PrivateKey( | |
534 bio, NULL, PasswordCallback, const_cast<char*>(password)); | |
535 if (key == NULL) { | |
536 // Reset the bio, and clear the error from trying to read as PEM. | |
537 ERR_clear_error(); | |
538 BIO_reset(bio); | |
539 | |
540 // Try to decode as PKCS12 | |
541 key = GetPrivateKeyPKCS12(bio, password); | |
542 } | |
543 return key; | |
544 } | |
545 | |
546 | |
448 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( | 547 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
449 Dart_NativeArguments args) { | 548 Dart_NativeArguments args) { |
450 SSL_CTX* context = GetSecurityContext(args); | 549 SSL_CTX* context = GetSecurityContext(args); |
451 | 550 |
452 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); | 551 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
453 const char* password = NULL; | 552 const char* password = NULL; |
454 if (Dart_IsString(password_object)) { | 553 if (Dart_IsString(password_object)) { |
455 ThrowIfError(Dart_StringToCString(password_object, &password)); | 554 ThrowIfError(Dart_StringToCString(password_object, &password)); |
456 if (strlen(password) > PEM_BUFSIZE - 1) { | 555 if (strlen(password) > PEM_BUFSIZE - 1) { |
457 Dart_ThrowException(DartUtils::NewDartArgumentError( | 556 Dart_ThrowException(DartUtils::NewDartArgumentError( |
458 "SecurityContext.usePrivateKey password length is greater than" | 557 "SecurityContext.usePrivateKey password length is greater than" |
459 " 1023 (PEM_BUFSIZE)")); | 558 " 1023 (PEM_BUFSIZE)")); |
460 } | 559 } |
461 } else if (Dart_IsNull(password_object)) { | 560 } else if (Dart_IsNull(password_object)) { |
462 password = ""; | 561 password = ""; |
463 } else { | 562 } else { |
464 Dart_ThrowException(DartUtils::NewDartArgumentError( | 563 Dart_ThrowException(DartUtils::NewDartArgumentError( |
465 "SecurityContext.usePrivateKey password is not a String or null")); | 564 "SecurityContext.usePrivateKey password is not a String or null")); |
466 } | 565 } |
467 | 566 |
468 int status; | 567 int status; |
469 { | 568 { |
470 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 569 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
471 EVP_PKEY *key = PEM_read_bio_PrivateKey( | 570 EVP_PKEY *key = GetPrivateKey(bio.bio(), password); |
472 bio.bio(), NULL, PasswordCallback, const_cast<char*>(password)); | |
473 status = SSL_CTX_use_PrivateKey(context, key); | 571 status = SSL_CTX_use_PrivateKey(context, key); |
474 } | 572 } |
475 | 573 |
476 // TODO(24184): Handle different expected errors here - file missing, | 574 // TODO(24184): Handle different expected errors here - file missing, |
477 // incorrect password, file not a PEM, and throw exceptions. | 575 // incorrect password, file not a PEM, and throw exceptions. |
478 // CheckStatus should also throw an exception in uncaught cases. | 576 // CheckStatus should also throw an exception in uncaught cases. |
479 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); | 577 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); |
480 } | 578 } |
481 | 579 |
482 | 580 |
483 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) { | 581 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, BIO* bio) { |
582 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | |
583 if (p12.get() == NULL) { | |
584 return NULL; | |
585 } | |
586 | |
587 EVP_PKEY* key = NULL; | |
588 X509 *cert = NULL; | |
589 STACK_OF(X509) *ca_certs = NULL; | |
590 // There should be no private keys in this file, so we hardcode the password | |
591 // to "". | |
592 // TODO(zra): Allow passing a password anyway. | |
593 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs); | |
594 if (status == 0) { | |
595 return status; | |
596 } | |
597 | |
598 ScopedX509Stack cert_stack(ca_certs); | |
599 | |
600 // There should be no private key. | |
601 if (key != NULL) { | |
602 X509_free(cert); | |
603 return 0; | |
604 } | |
605 | |
606 X509_STORE* store = SSL_CTX_get_cert_store(context); | |
607 status = X509_STORE_add_cert(store, cert); | |
608 if (status == 0) { | |
609 X509_free(cert); | |
610 return status; | |
611 } | |
612 | |
613 X509* ca; | |
614 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { | |
615 status = X509_STORE_add_cert(store, ca); | |
616 if (status == 0) { | |
617 X509_free(ca); | |
618 return status; | |
619 } | |
620 } | |
621 | |
622 return status; | |
623 } | |
624 | |
625 | |
626 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) { | |
484 X509_STORE* store = SSL_CTX_get_cert_store(context); | 627 X509_STORE* store = SSL_CTX_get_cert_store(context); |
485 | 628 |
486 int status = 0; | 629 int status = 0; |
487 X509* cert = NULL; | 630 X509* cert = NULL; |
488 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | 631 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
489 status = X509_STORE_add_cert(store, cert); | 632 status = X509_STORE_add_cert(store, cert); |
490 if (status == 0) { | 633 if (status == 0) { |
491 X509_free(cert); | 634 X509_free(cert); |
492 return status; | 635 return status; |
493 } | 636 } |
494 } | 637 } |
495 | 638 |
496 uint32_t err = ERR_peek_last_error(); | 639 uint32_t err = ERR_peek_last_error(); |
497 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && | 640 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && |
498 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { | 641 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { |
499 // Reached the end of the buffer. | 642 // Reached the end of the buffer. |
500 ERR_clear_error(); | 643 ERR_clear_error(); |
501 } else { | 644 } else { |
502 // Some real error happened. | 645 // Some real error happened. |
503 status = 0; | 646 status = 0; |
504 } | 647 } |
505 | 648 |
506 return status; | 649 return status; |
507 } | 650 } |
508 | 651 |
509 | 652 |
653 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) { | |
654 int status = SetTrustedCertificatesBytesPEM(context, bio); | |
655 if (status == 0) { | |
656 ERR_clear_error(); | |
657 BIO_reset(bio); | |
658 status = SetTrustedCertificatesBytesPKCS12(context, bio); | |
Bill Hesse
2016/02/10 18:08:39
If someone submits a flawed PEM file, they will ne
zra
2016/02/10 22:17:14
Rearranged the logic a bit to avoid this problem.
| |
659 } | |
660 return status; | |
661 } | |
662 | |
663 | |
510 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( | 664 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( |
511 Dart_NativeArguments args) { | 665 Dart_NativeArguments args) { |
512 SSL_CTX* context = GetSecurityContext(args); | 666 SSL_CTX* context = GetSecurityContext(args); |
513 int status; | 667 int status; |
514 { | 668 { |
515 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 669 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
516 status = SetTrustedCertificatesBytes(context, bio.bio()); | 670 status = SetTrustedCertificatesBytes(context, bio.bio()); |
517 } | 671 } |
518 CheckStatus(status, | 672 CheckStatus(status, |
519 "TlsException", | 673 "TlsException", |
520 "Failure in setTrustedCertificatesBytes"); | 674 "Failure in setTrustedCertificatesBytes"); |
521 } | 675 } |
522 | 676 |
523 | 677 |
524 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( | 678 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( |
525 Dart_NativeArguments args) { | 679 Dart_NativeArguments args) { |
526 SSL_CTX* context = GetSecurityContext(args); | 680 SSL_CTX* context = GetSecurityContext(args); |
527 X509_STORE* store = SSL_CTX_get_cert_store(context); | 681 X509_STORE* store = SSL_CTX_get_cert_store(context); |
528 BIO* roots_bio = | 682 BIO* roots_bio = |
529 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), | 683 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), |
530 root_certificates_pem_length); | 684 root_certificates_pem_length); |
531 X509* root_cert; | 685 X509* root_cert; |
532 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, | 686 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, |
533 // backed by a memory buffer), and returns X509 objects, one by one. | 687 // backed by a memory buffer), and returns X509 objects, one by one. |
534 // When the end of the bio is reached, it returns null. | 688 // When the end of the bio is reached, it returns null. |
535 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) { | 689 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) { |
536 X509_STORE_add_cert(store, root_cert); | 690 X509_STORE_add_cert(store, root_cert); |
537 } | 691 } |
538 BIO_free(roots_bio); | 692 BIO_free(roots_bio); |
539 } | 693 } |
540 | 694 |
541 | 695 |
542 static int UseChainBytes(SSL_CTX* context, BIO* bio) { | 696 static int UseChainBytesPKCS12(SSL_CTX* context, BIO* bio) { |
543 int status = 0; | 697 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
544 X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); | 698 if (p12.get() == NULL) { |
545 if (x509 == NULL) { | 699 return NULL; |
700 } | |
701 | |
702 EVP_PKEY* key = NULL; | |
703 X509 *cert = NULL; | |
704 STACK_OF(X509) *ca_certs = NULL; | |
705 // There should be no private keys in this file, so we hardcode the password | |
706 // to "". | |
707 // TODO(zra): Allow passing a password anyway. | |
708 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs); | |
709 if (status == 0) { | |
710 return status; | |
711 } | |
712 | |
713 ScopedX509 x509(cert); | |
714 ScopedX509Stack certs(ca_certs); | |
715 | |
716 // There should be no private key. | |
717 if (key != NULL) { | |
546 return 0; | 718 return 0; |
547 } | 719 } |
548 | 720 |
549 status = SSL_CTX_use_certificate(context, x509); | 721 status = SSL_CTX_use_certificate(context, x509.get()); |
550 if (ERR_peek_error() != 0) { | 722 if (ERR_peek_error() != 0) { |
551 // Key/certificate mismatch doesn't imply status is 0. | 723 // Key/certificate mismatch doesn't imply status is 0. |
552 status = 0; | 724 status = 0; |
553 } | 725 } |
554 if (status == 0) { | 726 if (status == 0) { |
555 X509_free(x509); | |
556 return status; | 727 return status; |
557 } | 728 } |
558 | 729 |
559 SSL_CTX_clear_chain_certs(context); | 730 SSL_CTX_clear_chain_certs(context); |
560 | 731 |
561 while (true) { | 732 X509* ca; |
562 X509* ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); | 733 while ((ca = sk_X509_shift(certs.get())) != NULL) { |
563 if (ca == NULL) { | |
564 break; | |
565 } | |
566 status = SSL_CTX_add0_chain_cert(context, ca); | 734 status = SSL_CTX_add0_chain_cert(context, ca); |
567 if (status == 0) { | 735 if (status == 0) { |
568 X509_free(ca); | 736 X509_free(ca); |
569 X509_free(x509); | 737 return status; |
738 } | |
739 } | |
740 | |
741 return status; | |
742 } | |
743 | |
744 | |
745 static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) { | |
746 int status = 0; | |
747 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL)); | |
748 if (x509.get() == NULL) { | |
749 return 0; | |
750 } | |
751 | |
752 status = SSL_CTX_use_certificate(context, x509.get()); | |
753 if (ERR_peek_error() != 0) { | |
754 // Key/certificate mismatch doesn't imply status is 0. | |
Bill Hesse
2016/02/10 18:08:39
Is this implying that we need to add the key to th
zra
2016/02/10 22:17:14
This only fires with a non-null key. This is extra
| |
755 status = 0; | |
756 } | |
757 if (status == 0) { | |
758 return status; | |
759 } | |
760 | |
761 SSL_CTX_clear_chain_certs(context); | |
762 | |
763 X509* ca; | |
764 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | |
765 status = SSL_CTX_add0_chain_cert(context, ca); | |
766 if (status == 0) { | |
767 X509_free(ca); | |
570 return status; | 768 return status; |
571 } | 769 } |
572 // Note that we must not free `ca` if it was successfully added to the | 770 // Note that we must not free `ca` if it was successfully added to the |
573 // chain. We must free the main certificate x509, though since its reference | 771 // chain. We must free the main certificate x509, though since its reference |
574 // count is increased by SSL_CTX_use_certificate. | 772 // count is increased by SSL_CTX_use_certificate. |
575 } | 773 } |
576 | 774 |
577 uint32_t err = ERR_peek_last_error(); | 775 uint32_t err = ERR_peek_last_error(); |
578 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && | 776 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && |
579 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { | 777 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { |
580 // Reached the end of the buffer. | 778 // Reached the end of the buffer. |
581 ERR_clear_error(); | 779 ERR_clear_error(); |
582 } else { | 780 } else { |
583 // Some real error happened. | 781 // Some real error happened. |
584 status = 0; | 782 status = 0; |
585 } | 783 } |
586 | 784 |
587 X509_free(x509); | |
588 return status; | 785 return status; |
589 } | 786 } |
590 | 787 |
788 | |
789 static int UseChainBytes(SSL_CTX* context, BIO* bio) { | |
790 int status = UseChainBytesPEM(context, bio); | |
791 if (status == 0) { | |
792 ERR_clear_error(); | |
793 BIO_reset(bio); | |
794 status = UseChainBytesPKCS12(context, bio); | |
795 } | |
796 return status; | |
797 } | |
798 | |
591 | 799 |
592 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( | 800 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( |
593 Dart_NativeArguments args) { | 801 Dart_NativeArguments args) { |
594 SSL_CTX* context = GetSecurityContext(args); | 802 SSL_CTX* context = GetSecurityContext(args); |
595 int status; | 803 int status; |
596 { | 804 { |
597 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 805 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
598 status = UseChainBytes(context, bio.bio()); | 806 status = UseChainBytes(context, bio.bio()); |
599 } | 807 } |
600 CheckStatus(status, | 808 CheckStatus(status, |
601 "TlsException", | 809 "TlsException", |
602 "Failure in useCertificateChainBytes"); | 810 "Failure in useCertificateChainBytes"); |
603 } | 811 } |
604 | 812 |
605 | 813 |
606 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) { | 814 static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio) { |
607 STACK_OF(X509_NAME)* result = sk_X509_NAME_new_null(); | 815 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
608 if (result == NULL) { | 816 if (p12.get() == NULL) { |
817 return NULL; | |
818 } | |
819 | |
820 ScopedX509NAMEStack result(sk_X509_NAME_new_null()); | |
821 if (result.get() == NULL) { | |
822 return NULL; | |
823 } | |
824 | |
825 EVP_PKEY* key = NULL; | |
826 X509 *cert = NULL; | |
827 STACK_OF(X509) *ca_certs = NULL; | |
828 // There should be no private keys in this file, so we hardcode the password | |
829 // to "". | |
830 // TODO(zra): Allow passing a password anyway. | |
831 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs); | |
832 if (status == 0) { | |
833 return NULL; | |
834 } | |
835 | |
836 ScopedX509 x509(cert); | |
837 ScopedX509Stack certs(ca_certs); | |
838 | |
839 // There should be no private key. | |
840 if (key != NULL) { | |
841 return NULL; | |
842 } | |
843 | |
844 X509_NAME* x509_name = X509_get_subject_name(x509.get()); | |
845 if (x509_name == NULL) { | |
846 return NULL; | |
847 } | |
848 | |
849 x509_name = X509_NAME_dup(x509_name); | |
850 if (x509_name == NULL) { | |
851 return NULL; | |
852 } | |
853 | |
854 sk_X509_NAME_push(result.get(), x509_name); | |
855 | |
856 while (true) { | |
857 ScopedX509 ca(sk_X509_shift(certs.get())); | |
858 if (ca.get() == NULL) { | |
859 break; | |
860 } | |
861 | |
862 X509_NAME* x509_name = X509_get_subject_name(ca.get()); | |
863 if (x509_name == NULL) { | |
864 return NULL; | |
865 } | |
866 | |
867 x509_name = X509_NAME_dup(x509_name); | |
868 if (x509_name == NULL) { | |
869 return NULL; | |
870 } | |
871 | |
872 sk_X509_NAME_push(result.get(), x509_name); | |
873 } | |
874 | |
875 return result.release(); | |
876 } | |
877 | |
878 | |
879 static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) { | |
880 ScopedX509NAMEStack result(sk_X509_NAME_new_null()); | |
881 if (result.get() == NULL) { | |
609 return NULL; | 882 return NULL; |
610 } | 883 } |
611 | 884 |
612 while (true) { | 885 while (true) { |
613 X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); | 886 ScopedX509 x509(PEM_read_bio_X509(bio, NULL, NULL, NULL)); |
614 if (x509 == NULL) { | 887 if (x509.get() == NULL) { |
Bill Hesse
2016/02/10 18:08:39
Isn't this the result of an error reading the file
zra
2016/02/10 22:17:14
Added error checking as done in the other calls.
| |
615 break; | 888 break; |
616 } | 889 } |
617 | 890 |
618 X509_NAME* x509_name = X509_get_subject_name(x509); | 891 X509_NAME* x509_name = X509_get_subject_name(x509.get()); |
619 if (x509_name == NULL) { | 892 if (x509_name == NULL) { |
620 sk_X509_NAME_pop_free(result, X509_NAME_free); | |
621 X509_free(x509); | |
622 return NULL; | 893 return NULL; |
623 } | 894 } |
624 | 895 |
625 // Duplicate the name to put it on the stack. | 896 // Duplicate the name to put it on the stack. |
626 x509_name = X509_NAME_dup(x509_name); | 897 x509_name = X509_NAME_dup(x509_name); |
627 if (x509_name == NULL) { | 898 if (x509_name == NULL) { |
628 sk_X509_NAME_pop_free(result, X509_NAME_free); | |
629 X509_free(x509); | |
630 return NULL; | 899 return NULL; |
631 } | 900 } |
632 sk_X509_NAME_push(result, x509_name); | 901 sk_X509_NAME_push(result.get(), x509_name); |
633 X509_free(x509); | |
634 } | 902 } |
635 | 903 |
904 return result.release(); | |
905 } | |
906 | |
907 | |
908 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) { | |
909 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio); | |
910 if (result == NULL) { | |
911 ERR_clear_error(); | |
912 BIO_reset(bio); | |
913 result = GetCertificateNamesPKCS12(bio); | |
914 } | |
636 return result; | 915 return result; |
637 } | 916 } |
638 | 917 |
639 | 918 |
640 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( | 919 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( |
641 Dart_NativeArguments args) { | 920 Dart_NativeArguments args) { |
642 SSL_CTX* context = GetSecurityContext(args); | 921 SSL_CTX* context = GetSecurityContext(args); |
643 STACK_OF(X509_NAME)* certificate_names; | 922 STACK_OF(X509_NAME)* certificate_names; |
644 | 923 |
645 { | 924 { |
646 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 925 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
647 certificate_names = GetCertificateNames(bio.bio()); | 926 certificate_names = GetCertificateNames(bio.bio()); |
648 } | 927 } |
649 | 928 |
650 if (certificate_names != NULL) { | 929 if (certificate_names != NULL) { |
651 SSL_CTX_set_client_CA_list(context, certificate_names); | 930 SSL_CTX_set_client_CA_list(context, certificate_names); |
652 } else { | 931 } else { |
653 Dart_ThrowException(DartUtils::NewDartArgumentError( | 932 Dart_ThrowException(DartUtils::NewDartArgumentError( |
654 "Could not load certificate names from file in SetClientAuthorities")); | 933 "Could not load certificate names from file in SetClientAuthorities")); |
655 } | 934 } |
656 } | 935 } |
(...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1272 } else { | 1551 } else { |
1273 if (SSL_LOG_DATA) Log::Print( | 1552 if (SSL_LOG_DATA) Log::Print( |
1274 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); | 1553 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); |
1275 } | 1554 } |
1276 } | 1555 } |
1277 return bytes_processed; | 1556 return bytes_processed; |
1278 } | 1557 } |
1279 | 1558 |
1280 } // namespace bin | 1559 } // namespace bin |
1281 } // namespace dart | 1560 } // namespace dart |
OLD | NEW |