|
20 | 20 | #include <openssl/core_names.h> |
21 | 21 | #include <openssl/params.h> |
22 | 22 | #include <openssl/provider.h> |
| 23 | +#include <openssl/store.h> |
23 | 24 | #if OPENSSL_WITH_ARGON2 |
24 | 25 | #include <openssl/thread.h> |
25 | 26 | #endif |
@@ -618,6 +619,26 @@ int PasswordCallback(char* buf, int size, int rwflag, void* u) { |
618 | 619 | return -1; |
619 | 620 | } |
620 | 621 |
|
| 622 | +struct StorePassphraseData { |
| 623 | + Buffer<char> passphrase{.data = nullptr, .len = 0}; |
| 624 | + bool has_passphrase = false; |
| 625 | + bool missing_passphrase = false; |
| 626 | +}; |
| 627 | + |
| 628 | +int StorePasswordCallback(char* buf, int size, int rwflag, void* u) { |
| 629 | + auto data = static_cast<StorePassphraseData*>(u); |
| 630 | + if (data == nullptr || !data->has_passphrase) { |
| 631 | + if (data != nullptr) data->missing_passphrase = true; |
| 632 | + return -1; |
| 633 | + } |
| 634 | + |
| 635 | + size_t buflen = static_cast<size_t>(size); |
| 636 | + size_t len = data->passphrase.len; |
| 637 | + if (buflen < len) return -1; |
| 638 | + memcpy(buf, reinterpret_cast<const char*>(data->passphrase.data), len); |
| 639 | + return len; |
| 640 | +} |
| 641 | + |
621 | 642 | // Algorithm: http://howardhinnant.github.io/date_algorithms.html |
622 | 643 | constexpr int days_from_epoch(int y, unsigned m, unsigned d) { |
623 | 644 | y -= m <= 2; |
@@ -2613,6 +2634,102 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey( |
2613 | 2634 | }; |
2614 | 2635 | } |
2615 | 2636 |
|
| 2637 | +EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryLoadPrivateKeyFromStore( |
| 2638 | + const StorePrivateKeyConfig& config) { |
| 2639 | +#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_MAJOR < 3 |
| 2640 | + return ParseKeyResult(PKParseError::FAILED); |
| 2641 | +#else |
| 2642 | + ClearErrorOnReturn clear_error_on_return; |
| 2643 | + std::string uri_str(config.uri); |
| 2644 | + std::string properties_str; |
| 2645 | + const char* properties = nullptr; |
| 2646 | + if (config.properties.has_value()) { |
| 2647 | + properties_str.assign(config.properties->data(), config.properties->size()); |
| 2648 | + properties = properties_str.c_str(); |
| 2649 | + } |
| 2650 | + |
| 2651 | + std::string passphrase_str; |
| 2652 | + Buffer<char> passbuf{.data = nullptr, .len = 0}; |
| 2653 | + if (config.passphrase.has_value()) { |
| 2654 | + passphrase_str.assign(config.passphrase->data, config.passphrase->len); |
| 2655 | + passbuf.data = passphrase_str.data(); |
| 2656 | + passbuf.len = passphrase_str.size(); |
| 2657 | + } |
| 2658 | + StorePassphraseData passphrase_data{ |
| 2659 | + .passphrase = passbuf, |
| 2660 | + .has_passphrase = config.passphrase.has_value(), |
| 2661 | + }; |
| 2662 | + UI_METHOD* ui_method = |
| 2663 | + UI_UTIL_wrap_read_pem_callback(StorePasswordCallback, 0); |
| 2664 | + if (ui_method == nullptr) return ParseKeyResult(PKParseError::FAILED); |
| 2665 | + |
| 2666 | + const OSSL_PARAM store_params[] = {OSSL_PARAM_END}; |
| 2667 | + OSSL_STORE_CTX* ctx = OSSL_STORE_open_ex(uri_str.c_str(), |
| 2668 | + nullptr, |
| 2669 | + properties, |
| 2670 | + ui_method, |
| 2671 | + &passphrase_data, |
| 2672 | + store_params, |
| 2673 | + nullptr, |
| 2674 | + nullptr); |
| 2675 | + if (ctx == nullptr) { |
| 2676 | + bool missing_passphrase = passphrase_data.missing_passphrase; |
| 2677 | + int err = ERR_peek_error(); |
| 2678 | + UI_destroy_method(ui_method); |
| 2679 | + if (missing_passphrase) { |
| 2680 | + return ParseKeyResult(PKParseError::NEED_PASSPHRASE); |
| 2681 | + } |
| 2682 | + return ParseKeyResult(PKParseError::FAILED, err); |
| 2683 | + } |
| 2684 | + |
| 2685 | + if (!OSSL_STORE_expect(ctx, OSSL_STORE_INFO_PKEY)) { |
| 2686 | + bool missing_passphrase = passphrase_data.missing_passphrase; |
| 2687 | + int err = ERR_peek_error(); |
| 2688 | + OSSL_STORE_close(ctx); |
| 2689 | + UI_destroy_method(ui_method); |
| 2690 | + if (missing_passphrase) { |
| 2691 | + return ParseKeyResult(PKParseError::NEED_PASSPHRASE); |
| 2692 | + } |
| 2693 | + return ParseKeyResult(PKParseError::FAILED, err); |
| 2694 | + } |
| 2695 | + |
| 2696 | + EVPKeyPointer pkey; |
| 2697 | + int store_error = 0; |
| 2698 | + while (!OSSL_STORE_eof(ctx)) { |
| 2699 | + OSSL_STORE_INFO* info = OSSL_STORE_load(ctx); |
| 2700 | + if (info == nullptr) { |
| 2701 | + if (OSSL_STORE_error(ctx)) { |
| 2702 | + store_error = ERR_peek_error(); |
| 2703 | + break; |
| 2704 | + } |
| 2705 | + continue; |
| 2706 | + } |
| 2707 | + if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY) { |
| 2708 | + EVP_PKEY* raw_pkey = OSSL_STORE_INFO_get1_PKEY(info); |
| 2709 | + if (raw_pkey != nullptr) { |
| 2710 | + pkey = EVPKeyPointer(raw_pkey); |
| 2711 | + } else { |
| 2712 | + store_error = ERR_peek_error(); |
| 2713 | + } |
| 2714 | + } |
| 2715 | + OSSL_STORE_INFO_free(info); |
| 2716 | + if (pkey || store_error != 0) break; |
| 2717 | + } |
| 2718 | + |
| 2719 | + OSSL_STORE_close(ctx); |
| 2720 | + UI_destroy_method(ui_method); |
| 2721 | + |
| 2722 | + if (passphrase_data.missing_passphrase) { |
| 2723 | + return ParseKeyResult(PKParseError::NEED_PASSPHRASE); |
| 2724 | + } |
| 2725 | + if (store_error != 0) { |
| 2726 | + return ParseKeyResult(PKParseError::FAILED, store_error); |
| 2727 | + } |
| 2728 | + if (!pkey) return ParseKeyResult(PKParseError::NOT_RECOGNIZED); |
| 2729 | + return ParseKeyResult(std::move(pkey)); |
| 2730 | +#endif |
| 2731 | +} |
| 2732 | + |
2616 | 2733 | Result<BIOPointer, bool> EVPKeyPointer::writePrivateKey( |
2617 | 2734 | const PrivateKeyEncodingConfig& config) const { |
2618 | 2735 | if (config.format == PKFormatType::JWK) { |
|
0 commit comments