| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -33,7 +33,7 @@ ClearErrorOnReturn::~ClearErrorOnReturn() { | |||
| 33 | 33 | ERR_clear_error(); | |
| 34 | 34 | } | |
| 35 | 35 | ||
| 36 | - int ClearErrorOnReturn::peeKError() { return ERR_peek_error(); } | ||
| 36 | + int ClearErrorOnReturn::peekError() { return ERR_peek_error(); } | ||
| 37 | 37 | ||
| 38 | 38 | MarkPopErrorOnReturn::MarkPopErrorOnReturn(CryptoErrorList* errors) : errors_(errors) { | |
| 39 | 39 | ERR_set_mark(); | |
@@ -1570,11 +1570,66 @@ EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner( | |||
| 1570 | 1570 | return EVPKeyPointer::ParseKeyResult(std::move(pkey)); | |
| 1571 | 1571 | } | |
| 1572 | 1572 | ||
| 1573 | - EVPKeyPointer::ParseKeyResult TryParsePublicKeyPEM( | ||
| 1573 | + constexpr bool IsASN1Sequence(const unsigned char* data, size_t size, | ||
| 1574 | + size_t* data_offset, size_t* data_size) { | ||
| 1575 | + if (size < 2 || data[0] != 0x30) | ||
| 1576 | + return false; | ||
| 1577 | + | ||
| 1578 | + if (data[1] & 0x80) { | ||
| 1579 | + // Long form. | ||
| 1580 | + size_t n_bytes = data[1] & ~0x80; | ||
| 1581 | + if (n_bytes + 2 > size || n_bytes > sizeof(size_t)) | ||
| 1582 | + return false; | ||
| 1583 | + size_t length = 0; | ||
| 1584 | + for (size_t i = 0; i < n_bytes; i++) | ||
| 1585 | + length = (length << 8) | data[i + 2]; | ||
| 1586 | + *data_offset = 2 + n_bytes; | ||
| 1587 | + *data_size = std::min(size - 2 - n_bytes, length); | ||
| 1588 | + } else { | ||
| 1589 | + // Short form. | ||
| 1590 | + *data_offset = 2; | ||
| 1591 | + *data_size = std::min<size_t>(size - 2, data[1]); | ||
| 1592 | + } | ||
| 1593 | + | ||
| 1594 | + return true; | ||
| 1595 | + } | ||
| 1596 | + | ||
| 1597 | + constexpr bool IsEncryptedPrivateKeyInfo(const Buffer<const unsigned char>& buffer) { | ||
| 1598 | + // Both PrivateKeyInfo and EncryptedPrivateKeyInfo start with a SEQUENCE. | ||
| 1599 | + if (buffer.len == 0 || buffer.data == nullptr) return false; | ||
| 1600 | + size_t offset, len; | ||
| 1601 | + if (!IsASN1Sequence(buffer.data, buffer.len, &offset, &len)) | ||
| 1602 | + return false; | ||
| 1603 | + | ||
| 1604 | + // A PrivateKeyInfo sequence always starts with an integer whereas an | ||
| 1605 | + // EncryptedPrivateKeyInfo starts with an AlgorithmIdentifier. | ||
| 1606 | + return len >= 1 && buffer.data[offset] != 2; | ||
| 1607 | + } | ||
| 1608 | + | ||
| 1609 | + } // namespace | ||
| 1610 | + | ||
| 1611 | + bool EVPKeyPointer::IsRSAPrivateKey(const Buffer<const unsigned char>& buffer) { | ||
| 1612 | + // Both RSAPrivateKey and RSAPublicKey structures start with a SEQUENCE. | ||
| 1613 | + size_t offset, len; | ||
| 1614 | + if (!IsASN1Sequence(buffer.data, buffer.len, &offset, &len)) | ||
| 1615 | + return false; | ||
| 1616 | + | ||
| 1617 | + // An RSAPrivateKey sequence always starts with a single-byte integer whose | ||
| 1618 | + // value is either 0 or 1, whereas an RSAPublicKey starts with the modulus | ||
| 1619 | + // (which is the product of two primes and therefore at least 4), so we can | ||
| 1620 | + // decide the type of the structure based on the first three bytes of the | ||
| 1621 | + // sequence. | ||
| 1622 | + return len >= 3 && | ||
| 1623 | + buffer.data[offset] == 2 && | ||
| 1624 | + buffer.data[offset + 1] == 1 && | ||
| 1625 | + !(buffer.data[offset + 2] & 0xfe); | ||
| 1626 | + } | ||
| 1627 | + | ||
| 1628 | + EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKeyPEM( | ||
| 1574 | 1629 | const Buffer<const unsigned char>& buffer) { | |
| 1575 | 1630 | auto bp = BIOPointer::New(buffer.data, buffer.len); | |
| 1576 | 1631 | if (!bp) | |
| 1577 | - return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED); | ||
| 1632 | + return ParseKeyResult(PKParseError::FAILED); | ||
| 1578 | 1633 | ||
| 1579 | 1634 | // Try parsing as SubjectPublicKeyInfo (SPKI) first. | |
| 1580 | 1635 | if (auto ret = TryParsePublicKeyInner(bp, "PUBLIC KEY", | |
@@ -1601,9 +1656,8 @@ EVPKeyPointer::ParseKeyResult TryParsePublicKeyPEM( | |||
| 1601 | 1656 | return ret; | |
| 1602 | 1657 | }; | |
| 1603 | 1658 | ||
| 1604 | - return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED); | ||
| 1659 | + return ParseKeyResult(PKParseError::NOT_RECOGNIZED); | ||
| 1605 | 1660 | } | |
| 1606 | - } // namespace | ||
| 1607 | 1661 | ||
| 1608 | 1662 | EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey( | |
| 1609 | 1663 | PKFormatType format, | |
@@ -1634,4 +1688,70 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey( | |||
| 1634 | 1688 | return ParseKeyResult(PKParseError::FAILED); | |
| 1635 | 1689 | } | |
| 1636 | 1690 | ||
| 1691 | + EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey( | ||
| 1692 | + PKFormatType format, | ||
| 1693 | + PKEncodingType encoding, | ||
| 1694 | + std::optional<Buffer<char>> maybe_passphrase, | ||
| 1695 | + const Buffer<const unsigned char>& buffer) { | ||
| 1696 | + | ||
| 1697 | + static auto keyOrError = [&](EVPKeyPointer pkey, bool had_passphrase = false) { | ||
| 1698 | + if (int err = ERR_peek_error()) { | ||
| 1699 | + if (ERR_GET_LIB(err) == ERR_LIB_PEM && | ||
| 1700 | + ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ && | ||
| 1701 | + !had_passphrase) { | ||
| 1702 | + return ParseKeyResult(PKParseError::NEED_PASSPHRASE); | ||
| 1703 | + } | ||
| 1704 | + return ParseKeyResult(PKParseError::FAILED, err); | ||
| 1705 | + } | ||
| 1706 | + if (!pkey) return ParseKeyResult(PKParseError::FAILED); | ||
| 1707 | + return ParseKeyResult(std::move(pkey)); | ||
| 1708 | + }; | ||
| 1709 | + | ||
| 1710 | + Buffer<char>* passphrase = nullptr; | ||
| 1711 | + if (maybe_passphrase.has_value()) { | ||
| 1712 | + passphrase = &maybe_passphrase.value(); | ||
| 1713 | + } | ||
| 1714 | + | ||
| 1715 | + auto bio = BIOPointer::New(buffer); | ||
| 1716 | + if (!bio) return ParseKeyResult(PKParseError::FAILED); | ||
| 1717 | + | ||
| 1718 | + if (format == PKFormatType::PEM) { | ||
| 1719 | + auto key = PEM_read_bio_PrivateKey(bio.get(), nullptr, PasswordCallback, passphrase); | ||
| 1720 | + return keyOrError(EVPKeyPointer(key), maybe_passphrase.has_value()); | ||
| 1721 | + } | ||
| 1722 | + | ||
| 1723 | + if (format != PKFormatType::DER) { | ||
| 1724 | + return ParseKeyResult(PKParseError::FAILED); | ||
| 1725 | + } | ||
| 1726 | + | ||
| 1727 | + switch (encoding) { | ||
| 1728 | + case PKEncodingType::PKCS1: { | ||
| 1729 | + auto key = d2i_PrivateKey_bio(bio.get(), nullptr); | ||
| 1730 | + return keyOrError(EVPKeyPointer(key)); | ||
| 1731 | + } | ||
| 1732 | + case PKEncodingType::PKCS8: { | ||
| 1733 | + if (IsEncryptedPrivateKeyInfo(buffer)) { | ||
| 1734 | + auto key = d2i_PKCS8PrivateKey_bio(bio.get(), | ||
| 1735 | + nullptr, | ||
| 1736 | + PasswordCallback, | ||
| 1737 | + passphrase); | ||
| 1738 | + return keyOrError(EVPKeyPointer(key), maybe_passphrase.has_value()); | ||
| 1739 | + } | ||
| 1740 | + | ||
| 1741 | + PKCS8Pointer p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); | ||
| 1742 | + if (!p8inf) { | ||
| 1743 | + return ParseKeyResult(PKParseError::FAILED, ERR_peek_error()); | ||
| 1744 | + } | ||
| 1745 | + return keyOrError(EVPKeyPointer(EVP_PKCS82PKEY(p8inf.get()))); | ||
| 1746 | + } | ||
| 1747 | + case PKEncodingType::SEC1: { | ||
| 1748 | + auto key = d2i_PrivateKey_bio(bio.get(), nullptr); | ||
| 1749 | + return keyOrError(EVPKeyPointer(key)); | ||
| 1750 | + } | ||
| 1751 | + default: { | ||
| 1752 | + return ParseKeyResult(PKParseError::FAILED, ERR_peek_error()); | ||
| 1753 | + } | ||
| 1754 | + }; | ||
| 1755 | + } | ||
| 1756 | + | ||
| 1637 | 1757 | } // namespace ncrypto | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -148,7 +148,7 @@ class ClearErrorOnReturn final { | |||
| 148 | 148 | NCRYPTO_DISALLOW_COPY_AND_MOVE(ClearErrorOnReturn) | |
| 149 | 149 | NCRYPTO_DISALLOW_NEW_DELETE() | |
| 150 | 150 | ||
| 151 | - int peeKError(); | ||
| 151 | + int peekError(); | ||
| 152 | 152 | ||
| 153 | 153 | private: | |
| 154 | 154 | CryptoErrorList* errors_; | |
@@ -178,9 +178,13 @@ template <typename T, typename E> | |||
| 178 | 178 | struct Result final { | |
| 179 | 179 | const bool has_value; | |
| 180 | 180 | T value; | |
| 181 | - std::optional<E> error; | ||
| 181 | + std::optional<E> error = std::nullopt; | ||
| 182 | + std::optional<int> openssl_error = std::nullopt; | ||
| 182 | 183 | Result(T&& value) : has_value(true), value(std::move(value)) {} | |
| 183 | - Result(E&& error) : has_value(false), error(std::move(error)) {} | ||
| 184 | + Result(E&& error, std::optional<int> openssl_error = std::nullopt) | ||
| 185 | + : has_value(false), | ||
| 186 | + error(std::move(error)), | ||
| 187 | + openssl_error(std::move(openssl_error)) {} | ||
| 184 | 188 | inline operator bool() const { return has_value; } | |
| 185 | 189 | }; | |
| 186 | 190 | ||
@@ -277,6 +281,11 @@ class BIOPointer final { | |||
| 277 | 281 | static BIOPointer NewFile(std::string_view filename, std::string_view mode); | |
| 278 | 282 | static BIOPointer NewFp(FILE* fd, int flags); | |
| 279 | 283 | ||
| 284 | + template <typename T> | ||
| 285 | + static BIOPointer New(const Buffer<T>& buf) { | ||
| 286 | + return New(buf.data, buf.len); | ||
| 287 | + } | ||
| 288 | + | ||
| 280 | 289 | BIOPointer() = default; | |
| 281 | 290 | BIOPointer(std::nullptr_t) : bio_(nullptr) {} | |
| 282 | 291 | explicit BIOPointer(BIO* bio); | |
@@ -398,6 +407,15 @@ class EVPKeyPointer final { | |||
| 398 | 407 | PKEncodingType encoding, | |
| 399 | 408 | const Buffer<const unsigned char>& buffer); | |
| 400 | 409 | ||
| 410 | + static ParseKeyResult TryParsePublicKeyPEM( | ||
| 411 | + const Buffer<const unsigned char>& buffer); | ||
| 412 | + | ||
| 413 | + static ParseKeyResult TryParsePrivateKey( | ||
| 414 | + PKFormatType format, | ||
| 415 | + PKEncodingType encoding, | ||
| 416 | + std::optional<Buffer<char>> passphrase, | ||
| 417 | + const Buffer<const unsigned char>& buffer); | ||
| 418 | + | ||
| 401 | 419 | EVPKeyPointer() = default; | |
| 402 | 420 | explicit EVPKeyPointer(EVP_PKEY* pkey); | |
| 403 | 421 | EVPKeyPointer(EVPKeyPointer&& other) noexcept; | |
@@ -428,6 +446,8 @@ class EVPKeyPointer final { | |||
| 428 | 446 | ||
| 429 | 447 | EVPKeyCtxPointer newCtx() const; | |
| 430 | 448 | ||
| 449 | + static bool IsRSAPrivateKey(const Buffer<const unsigned char>& buffer); | ||
| 450 | + | ||
| 431 | 451 | private: | |
| 432 | 452 | DeleteFnPtr<EVP_PKEY, EVP_PKEY_free> pkey_; | |
| 433 | 453 | }; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments