| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -58,7 +58,7 @@ EnginePointer EnginePointer::getEngineByName(const std::string_view name, | |||
| 58 | 58 | } | |
| 59 | 59 | } | |
| 60 | 60 | } | |
| 61 | - return std::move(engine); | ||
| 61 | + return engine; | ||
| 62 | 62 | } | |
| 63 | 63 | ||
| 64 | 64 | bool EnginePointer::setAsDefault(uint32_t flags, CryptoErrorList* errors) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,12 +1,12 @@ | |||
| 1 | 1 | #include "ncrypto.h" | |
| 2 | 2 | #include <algorithm> | |
| 3 | 3 | #include <cstring> | |
| 4 | - #include "openssl/bn.h" | ||
| 5 | - #include "openssl/evp.h" | ||
| 6 | - #include "openssl/pkcs12.h" | ||
| 7 | - #include "openssl/x509v3.h" | ||
| 4 | + #include <openssl/bn.h> | ||
| 5 | + #include <openssl/evp.h> | ||
| 6 | + #include <openssl/pkcs12.h> | ||
| 7 | + #include <openssl/x509v3.h> | ||
| 8 | 8 | #if OPENSSL_VERSION_MAJOR >= 3 | |
| 9 | - #include "openssl/provider.h" | ||
| 9 | + #include <openssl/provider.h> | ||
| 10 | 10 | #endif | |
| 11 | 11 | ||
| 12 | 12 | namespace ncrypto { | |
@@ -703,4 +703,223 @@ bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) { | |||
| 703 | 703 | return ok; | |
| 704 | 704 | } | |
| 705 | 705 | ||
| 706 | + // ============================================================================ | ||
| 707 | + // X509Pointer | ||
| 708 | + | ||
| 709 | + X509Pointer::X509Pointer(X509* x509) : cert_(x509) {} | ||
| 710 | + | ||
| 711 | + X509Pointer::X509Pointer(X509Pointer&& other) noexcept | ||
| 712 | + : cert_(other.release()) {} | ||
| 713 | + | ||
| 714 | + X509Pointer& X509Pointer::operator=(X509Pointer&& other) noexcept { | ||
| 715 | + if (this == &other) return *this; | ||
| 716 | + this->~X509Pointer(); | ||
| 717 | + return *new (this) X509Pointer(std::move(other)); | ||
| 718 | + } | ||
| 719 | + | ||
| 720 | + X509Pointer::~X509Pointer() { reset(); } | ||
| 721 | + | ||
| 722 | + void X509Pointer::reset(X509* x509) { | ||
| 723 | + cert_.reset(x509); | ||
| 724 | + } | ||
| 725 | + | ||
| 726 | + X509* X509Pointer::release() { | ||
| 727 | + return cert_.release(); | ||
| 728 | + } | ||
| 729 | + | ||
| 730 | + X509View X509Pointer::view() const { | ||
| 731 | + return X509View(cert_.get()); | ||
| 732 | + } | ||
| 733 | + | ||
| 734 | + BIOPointer X509View::toPEM() const { | ||
| 735 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 736 | + if (cert_ == nullptr) return {}; | ||
| 737 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 738 | + if (!bio) return {}; | ||
| 739 | + if (PEM_write_bio_X509(bio.get(), const_cast<X509*>(cert_)) <= 0) return {}; | ||
| 740 | + return bio; | ||
| 741 | + } | ||
| 742 | + | ||
| 743 | + BIOPointer X509View::toDER() const { | ||
| 744 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 745 | + if (cert_ == nullptr) return {}; | ||
| 746 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 747 | + if (!bio) return {}; | ||
| 748 | + if (i2d_X509_bio(bio.get(), const_cast<X509*>(cert_)) <= 0) return {}; | ||
| 749 | + return bio; | ||
| 750 | + } | ||
| 751 | + | ||
| 752 | + BIOPointer X509View::getSubject() const { | ||
| 753 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 754 | + if (cert_ == nullptr) return {}; | ||
| 755 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 756 | + if (!bio) return {}; | ||
| 757 | + if (X509_NAME_print_ex(bio.get(), X509_get_subject_name(cert_), | ||
| 758 | + 0, kX509NameFlagsMultiline) <= 0) { | ||
| 759 | + return {}; | ||
| 760 | + } | ||
| 761 | + return bio; | ||
| 762 | + } | ||
| 763 | + | ||
| 764 | + BIOPointer X509View::getSubjectAltName() const { | ||
| 765 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 766 | + if (cert_ == nullptr) return {}; | ||
| 767 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 768 | + if (!bio) return {}; | ||
| 769 | + int index = X509_get_ext_by_NID(cert_, NID_subject_alt_name, -1); | ||
| 770 | + if (index < 0 || !SafeX509SubjectAltNamePrint(bio, X509_get_ext(cert_, index))) { | ||
| 771 | + return {}; | ||
| 772 | + } | ||
| 773 | + return bio; | ||
| 774 | + } | ||
| 775 | + | ||
| 776 | + BIOPointer X509View::getIssuer() const { | ||
| 777 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 778 | + if (cert_ == nullptr) return {}; | ||
| 779 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 780 | + if (!bio) return {}; | ||
| 781 | + if (X509_NAME_print_ex(bio.get(), X509_get_issuer_name(cert_), 0, | ||
| 782 | + kX509NameFlagsMultiline) <= 0) { | ||
| 783 | + return {}; | ||
| 784 | + } | ||
| 785 | + return bio; | ||
| 786 | + } | ||
| 787 | + | ||
| 788 | + BIOPointer X509View::getInfoAccess() const { | ||
| 789 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 790 | + if (cert_ == nullptr) return {}; | ||
| 791 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 792 | + if (!bio) return {}; | ||
| 793 | + int index = X509_get_ext_by_NID(cert_, NID_info_access, -1); | ||
| 794 | + if (index < 0) return {}; | ||
| 795 | + if (!SafeX509InfoAccessPrint(bio, X509_get_ext(cert_, index))) { | ||
| 796 | + return {}; | ||
| 797 | + } | ||
| 798 | + return bio; | ||
| 799 | + } | ||
| 800 | + | ||
| 801 | + BIOPointer X509View::getValidFrom() const { | ||
| 802 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 803 | + if (cert_ == nullptr) return {}; | ||
| 804 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 805 | + if (!bio) return {}; | ||
| 806 | + ASN1_TIME_print(bio.get(), X509_get_notBefore(cert_)); | ||
| 807 | + return bio; | ||
| 808 | + } | ||
| 809 | + | ||
| 810 | + BIOPointer X509View::getValidTo() const { | ||
| 811 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 812 | + if (cert_ == nullptr) return {}; | ||
| 813 | + BIOPointer bio(BIO_new(BIO_s_mem())); | ||
| 814 | + if (!bio) return {}; | ||
| 815 | + ASN1_TIME_print(bio.get(), X509_get_notAfter(cert_)); | ||
| 816 | + return bio; | ||
| 817 | + } | ||
| 818 | + | ||
| 819 | + DataPointer X509View::getSerialNumber() const { | ||
| 820 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 821 | + if (cert_ == nullptr) return {}; | ||
| 822 | + if (ASN1_INTEGER* serial_number = X509_get_serialNumber(const_cast<X509*>(cert_))) { | ||
| 823 | + if (auto bn = BignumPointer(ASN1_INTEGER_to_BN(serial_number, nullptr))) { | ||
| 824 | + return bn.toHex(); | ||
| 825 | + } | ||
| 826 | + } | ||
| 827 | + return {}; | ||
| 828 | + } | ||
| 829 | + | ||
| 830 | + Result<EVPKeyPointer, int> X509View::getPublicKey() const { | ||
| 831 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 832 | + if (cert_ == nullptr) return Result<EVPKeyPointer, int>(EVPKeyPointer {}); | ||
| 833 | + auto pkey = EVPKeyPointer(X509_get_pubkey(const_cast<X509*>(cert_))); | ||
| 834 | + if (!pkey) return Result<EVPKeyPointer, int>(ERR_get_error()); | ||
| 835 | + return pkey; | ||
| 836 | + } | ||
| 837 | + | ||
| 838 | + StackOfASN1 X509View::getKeyUsage() const { | ||
| 839 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 840 | + if (cert_ == nullptr) return {}; | ||
| 841 | + return StackOfASN1(static_cast<STACK_OF(ASN1_OBJECT)*>( | ||
| 842 | + X509_get_ext_d2i(cert_, NID_ext_key_usage, nullptr, nullptr))); | ||
| 843 | + } | ||
| 844 | + | ||
| 845 | + bool X509View::isCA() const { | ||
| 846 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 847 | + if (cert_ == nullptr) return false; | ||
| 848 | + return X509_check_ca(const_cast<X509*>(cert_)) == 1; | ||
| 849 | + } | ||
| 850 | + | ||
| 851 | + bool X509View::isIssuedBy(const X509View& issuer) const { | ||
| 852 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 853 | + if (cert_ == nullptr || issuer.cert_ == nullptr) return false; | ||
| 854 | + return X509_check_issued(const_cast<X509*>(issuer.cert_), | ||
| 855 | + const_cast<X509*>(cert_)) == X509_V_OK; | ||
| 856 | + } | ||
| 857 | + | ||
| 858 | + bool X509View::checkPrivateKey(const EVPKeyPointer& pkey) const { | ||
| 859 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 860 | + if (cert_ == nullptr || pkey == nullptr) return false; | ||
| 861 | + return X509_check_private_key(const_cast<X509*>(cert_), pkey.get()) == 1; | ||
| 862 | + } | ||
| 863 | + | ||
| 864 | + bool X509View::checkPublicKey(const EVPKeyPointer& pkey) const { | ||
| 865 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 866 | + if (cert_ == nullptr || pkey == nullptr) return false; | ||
| 867 | + return X509_verify(const_cast<X509*>(cert_), pkey.get()) == 1; | ||
| 868 | + } | ||
| 869 | + | ||
| 870 | + X509View::CheckMatch X509View::checkHost(const std::string_view host, int flags, | ||
| 871 | + DataPointer* peerName) const { | ||
| 872 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 873 | + if (cert_ == nullptr) return CheckMatch::NO_MATCH; | ||
| 874 | + char* peername; | ||
| 875 | + switch (X509_check_host(const_cast<X509*>(cert_), host.data(), host.size(), flags, &peername)) { | ||
| 876 | + case 0: return CheckMatch::NO_MATCH; | ||
| 877 | + case 1: { | ||
| 878 | + if (peername != nullptr) { | ||
| 879 | + DataPointer name(peername, strlen(peername)); | ||
| 880 | + if (peerName != nullptr) *peerName = std::move(name); | ||
| 881 | + } | ||
| 882 | + return CheckMatch::MATCH; | ||
| 883 | + } | ||
| 884 | + case -2: return CheckMatch::INVALID_NAME; | ||
| 885 | + default: return CheckMatch::OPERATION_FAILED; | ||
| 886 | + } | ||
| 887 | + } | ||
| 888 | + | ||
| 889 | + X509View::CheckMatch X509View::checkEmail(const std::string_view email, int flags) const { | ||
| 890 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 891 | + if (cert_ == nullptr) return CheckMatch::NO_MATCH; | ||
| 892 | + switch (X509_check_email(const_cast<X509*>(cert_), email.data(), email.size(), flags)) { | ||
| 893 | + case 0: return CheckMatch::NO_MATCH; | ||
| 894 | + case 1: return CheckMatch::MATCH; | ||
| 895 | + case -2: return CheckMatch::INVALID_NAME; | ||
| 896 | + default: return CheckMatch::OPERATION_FAILED; | ||
| 897 | + } | ||
| 898 | + } | ||
| 899 | + | ||
| 900 | + X509View::CheckMatch X509View::checkIp(const std::string_view ip, int flags) const { | ||
| 901 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 902 | + if (cert_ == nullptr) return CheckMatch::NO_MATCH; | ||
| 903 | + switch (X509_check_ip_asc(const_cast<X509*>(cert_), ip.data(), flags)) { | ||
| 904 | + case 0: return CheckMatch::NO_MATCH; | ||
| 905 | + case 1: return CheckMatch::MATCH; | ||
| 906 | + case -2: return CheckMatch::INVALID_NAME; | ||
| 907 | + default: return CheckMatch::OPERATION_FAILED; | ||
| 908 | + } | ||
| 909 | + } | ||
| 910 | + | ||
| 911 | + Result<X509Pointer, int> X509Pointer::Parse(Buffer<const unsigned char> buffer) { | ||
| 912 | + ClearErrorOnReturn clearErrorOnReturn; | ||
| 913 | + BIOPointer bio(BIO_new_mem_buf(buffer.data, buffer.len)); | ||
| 914 | + if (!bio) return Result<X509Pointer, int>(ERR_get_error()); | ||
| 915 | + | ||
| 916 | + X509Pointer pem(PEM_read_bio_X509_AUX(bio.get(), nullptr, NoPasswordCallback, nullptr)); | ||
| 917 | + if (pem) return Result<X509Pointer, int>(std::move(pem)); | ||
| 918 | + BIO_reset(bio.get()); | ||
| 919 | + | ||
| 920 | + X509Pointer der(d2i_X509_bio(bio.get(), nullptr)); | ||
| 921 | + if (der) return Result<X509Pointer, int>(std::move(der)); | ||
| 922 | + | ||
| 923 | + return Result<X509Pointer, int>(ERR_get_error()); | ||
| 924 | + } | ||
| 706 | 925 | } // namespace ncrypto | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,7 +6,7 @@ | |||
| 6 | 6 | #include <optional> | |
| 7 | 7 | #include <string> | |
| 8 | 8 | #include <string_view> | |
| 9 | - #include "openssl/bn.h" | ||
| 9 | + #include <openssl/bn.h> | ||
| 10 | 10 | #include <openssl/x509.h> | |
| 11 | 11 | #include <openssl/dh.h> | |
| 12 | 12 | #include <openssl/dsa.h> | |
@@ -91,6 +91,13 @@ namespace ncrypto { | |||
| 91 | 91 | #endif | |
| 92 | 92 | } | |
| 93 | 93 | ||
| 94 | + static constexpr int kX509NameFlagsMultiline = | ||
| 95 | + ASN1_STRFLGS_ESC_2253 | | ||
| 96 | + ASN1_STRFLGS_ESC_CTRL | | ||
| 97 | + ASN1_STRFLGS_UTF8_CONVERT | | ||
| 98 | + XN_FLAG_SEP_MULTILINE | | ||
| 99 | + XN_FLAG_FN_SN; | ||
| 100 | + | ||
| 94 | 101 | // ============================================================================ | |
| 95 | 102 | // Error handling utilities | |
| 96 | 103 | ||
@@ -164,6 +171,14 @@ class MarkPopErrorOnReturn final { | |||
| 164 | 171 | CryptoErrorList* errors_; | |
| 165 | 172 | }; | |
| 166 | 173 | ||
| 174 | + template <typename T, typename E> | ||
| 175 | + struct Result final { | ||
| 176 | + T value; | ||
| 177 | + std::optional<E> error; | ||
| 178 | + Result(T&& value) : value(std::move(value)) {} | ||
| 179 | + Result(E&& error) : error(std::move(error)) {} | ||
| 180 | + }; | ||
| 181 | + | ||
| 167 | 182 | // ============================================================================ | |
| 168 | 183 | // Various smart pointer aliases for OpenSSL types. | |
| 169 | 184 | ||
@@ -197,7 +212,13 @@ using RSAPointer = DeleteFnPtr<RSA, RSA_free>; | |||
| 197 | 212 | using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>; | |
| 198 | 213 | using SSLPointer = DeleteFnPtr<SSL, SSL_free>; | |
| 199 | 214 | using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>; | |
| 200 | - using X509Pointer = DeleteFnPtr<X509, X509_free>; | ||
| 215 | + | ||
| 216 | + struct StackOfXASN1Deleter { | ||
| 217 | + void operator()(STACK_OF(ASN1_OBJECT)* p) const { | ||
| 218 | + sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free); | ||
| 219 | + } | ||
| 220 | + }; | ||
| 221 | + using StackOfASN1 = std::unique_ptr<STACK_OF(ASN1_OBJECT), StackOfXASN1Deleter>; | ||
| 201 | 222 | ||
| 202 | 223 | // An unowned, unmanaged pointer to a buffer of data. | |
| 203 | 224 | template <typename T> | |
@@ -290,6 +311,74 @@ class BignumPointer final { | |||
| 290 | 311 | DeleteFnPtr<BIGNUM, BN_clear_free> bn_; | |
| 291 | 312 | }; | |
| 292 | 313 | ||
| 314 | + class X509View final { | ||
| 315 | + public: | ||
| 316 | + X509View() = default; | ||
| 317 | + inline explicit X509View(const X509* cert) : cert_(cert) {} | ||
| 318 | + X509View(const X509View& other) = default; | ||
| 319 | + X509View& operator=(const X509View& other) = default; | ||
| 320 | + NCRYPTO_DISALLOW_MOVE(X509View) | ||
| 321 | + | ||
| 322 | + inline bool operator==(std::nullptr_t) noexcept { return cert_ == nullptr; } | ||
| 323 | + inline operator bool() const { return cert_ != nullptr; } | ||
| 324 | + | ||
| 325 | + BIOPointer toPEM() const; | ||
| 326 | + BIOPointer toDER() const; | ||
| 327 | + | ||
| 328 | + BIOPointer getSubject() const; | ||
| 329 | + BIOPointer getSubjectAltName() const; | ||
| 330 | + BIOPointer getIssuer() const; | ||
| 331 | + BIOPointer getInfoAccess() const; | ||
| 332 | + BIOPointer getValidFrom() const; | ||
| 333 | + BIOPointer getValidTo() const; | ||
| 334 | + DataPointer getSerialNumber() const; | ||
| 335 | + Result<EVPKeyPointer, int> getPublicKey() const; | ||
| 336 | + StackOfASN1 getKeyUsage() const; | ||
| 337 | + | ||
| 338 | + bool isCA() const; | ||
| 339 | + bool isIssuedBy(const X509View& other) const; | ||
| 340 | + bool checkPrivateKey(const EVPKeyPointer& pkey) const; | ||
| 341 | + bool checkPublicKey(const EVPKeyPointer& pkey) const; | ||
| 342 | + | ||
| 343 | + enum class CheckMatch { | ||
| 344 | + NO_MATCH, | ||
| 345 | + MATCH, | ||
| 346 | + INVALID_NAME, | ||
| 347 | + OPERATION_FAILED, | ||
| 348 | + }; | ||
| 349 | + CheckMatch checkHost(const std::string_view host, int flags, | ||
| 350 | + DataPointer* peerName = nullptr) const; | ||
| 351 | + CheckMatch checkEmail(const std::string_view email, int flags) const; | ||
| 352 | + CheckMatch checkIp(const std::string_view ip, int flags) const; | ||
| 353 | + | ||
| 354 | + private: | ||
| 355 | + const X509* cert_ = nullptr; | ||
| 356 | + }; | ||
| 357 | + | ||
| 358 | + class X509Pointer final { | ||
| 359 | + public: | ||
| 360 | + static Result<X509Pointer, int> Parse(Buffer<const unsigned char> buffer); | ||
| 361 | + | ||
| 362 | + X509Pointer() = default; | ||
| 363 | + explicit X509Pointer(X509* cert); | ||
| 364 | + X509Pointer(X509Pointer&& other) noexcept; | ||
| 365 | + X509Pointer& operator=(X509Pointer&& other) noexcept; | ||
| 366 | + NCRYPTO_DISALLOW_COPY(X509Pointer) | ||
| 367 | + ~X509Pointer(); | ||
| 368 | + | ||
| 369 | + inline bool operator==(std::nullptr_t) noexcept { return cert_ == nullptr; } | ||
| 370 | + inline operator bool() const { return cert_ != nullptr; } | ||
| 371 | + inline X509* get() const { return cert_.get(); } | ||
| 372 | + void reset(X509* cert = nullptr); | ||
| 373 | + X509* release(); | ||
| 374 | + | ||
| 375 | + X509View view() const; | ||
| 376 | + operator X509View() const { return view(); } | ||
| 377 | + | ||
| 378 | + private: | ||
| 379 | + DeleteFnPtr<X509, X509_free> cert_; | ||
| 380 | + }; | ||
| 381 | + | ||
| 293 | 382 | #ifndef OPENSSL_NO_ENGINE | |
| 294 | 383 | class EnginePointer final { | |
| 295 | 384 | public: | |
| Back | FazBrowse Home | New Git URL |
0 commit comments