@@ -33,7 +33,7 @@ ClearErrorOnReturn::~ClearErrorOnReturn() {
3333 ERR_clear_error ();
3434}
3535
36- int ClearErrorOnReturn::peeKError () { return ERR_peek_error (); }
36+ int ClearErrorOnReturn::peekError () { return ERR_peek_error (); }
3737
3838MarkPopErrorOnReturn::MarkPopErrorOnReturn (CryptoErrorList* errors) : errors_(errors) {
3939 ERR_set_mark ();
@@ -1570,11 +1570,66 @@ EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner(
15701570 return EVPKeyPointer::ParseKeyResult (std::move (pkey));
15711571}
15721572
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 (
15741629 const Buffer<const unsigned char >& buffer) {
15751630 auto bp = BIOPointer::New (buffer.data , buffer.len );
15761631 if (!bp)
1577- return EVPKeyPointer:: ParseKeyResult (EVPKeyPointer:: PKParseError::FAILED);
1632+ return ParseKeyResult (PKParseError::FAILED);
15781633
15791634 // Try parsing as SubjectPublicKeyInfo (SPKI) first.
15801635 if (auto ret = TryParsePublicKeyInner (bp, " PUBLIC KEY" ,
@@ -1601,9 +1656,8 @@ EVPKeyPointer::ParseKeyResult TryParsePublicKeyPEM(
16011656 return ret;
16021657 };
16031658
1604- return EVPKeyPointer:: ParseKeyResult (EVPKeyPointer:: PKParseError::NOT_RECOGNIZED);
1659+ return ParseKeyResult (PKParseError::NOT_RECOGNIZED);
16051660}
1606- } // namespace
16071661
16081662EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey (
16091663 PKFormatType format,
@@ -1634,4 +1688,70 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey(
16341688 return ParseKeyResult (PKParseError::FAILED);
16351689}
16361690
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+
16371757} // namespace ncrypto
0 commit comments