@@ -61,6 +61,60 @@ struct PKCS8Key {
6161 bool rsa_pss_restricted{false };
6262};
6363
64+ // Whether a PKCS#1 RSAPrivateKey carries usable components (RFC 8017 Appendix
65+ // A.1.2). The modulus and both exponents are decoded as canonical non-negative
66+ // DER INTEGERs, so a negative or non-canonically encoded one cannot be silently
67+ // reinterpreted as a different positive number and signed with, and the public
68+ // exponent is range-checked per RFC 8017 Section 3.1. The version is required
69+ // to be present as an INTEGER but its value is left to the backends, which
70+ // differ on whether they accept the multi-prime form. Checked here rather than
71+ // in each backend, since only the reference one reads these components itself
72+ // and the rest hand the blob straight to a platform that does not apply the
73+ // rule
74+ inline auto rsa_private_key_acceptable (const std::string_view key) -> bool {
75+ // A canonical RSAPrivateKey is exactly one SEQUENCE, so bytes trailing it
76+ // mark a malformed encoding (X.690 Section 10.1), the same rule the enclosing
77+ // PrivateKeyInfo is held to
78+ const auto sequence{der_read (key)};
79+ if (!sequence.has_value () || sequence->tag != 0x30 ||
80+ !sequence->rest .empty ()) {
81+ return false ;
82+ }
83+
84+ const auto version{der_read (sequence->content )};
85+ if (!version.has_value () || version->tag != 0x02 ) {
86+ return false ;
87+ }
88+
89+ const auto modulus{der_read (version->rest )};
90+ if (!modulus.has_value () || modulus->tag != 0x02 ) {
91+ return false ;
92+ }
93+
94+ const auto public_exponent{der_read (modulus->rest )};
95+ if (!public_exponent.has_value () || public_exponent->tag != 0x02 ) {
96+ return false ;
97+ }
98+
99+ const auto private_exponent{der_read (public_exponent->rest )};
100+ if (!private_exponent.has_value () || private_exponent->tag != 0x02 ) {
101+ return false ;
102+ }
103+
104+ const auto modulus_value{der_unsigned_integer (modulus->content )};
105+ const auto public_exponent_value{
106+ der_unsigned_integer (public_exponent->content )};
107+ const auto private_exponent_value{
108+ der_unsigned_integer (private_exponent->content )};
109+ return modulus_value.has_value () && public_exponent_value.has_value () &&
110+ private_exponent_value.has_value () && !modulus_value->empty () &&
111+ !private_exponent_value->empty () &&
112+ modulus_value->size () <= MAXIMUM_KEY_BYTES &&
113+ private_exponent_value->size () <= MAXIMUM_KEY_BYTES &&
114+ rsa_public_exponent_acceptable (public_exponent_value.value (),
115+ modulus_value.value ());
116+ }
117+
64118// Parse an RFC 5958 PrivateKeyInfo, identifying the algorithm from its object
65119// identifier and returning the raw privateKey octets
66120inline auto parse_pkcs8 (const std::string_view der) -> std::optional<PKCS8Key> {
@@ -106,6 +160,10 @@ inline auto parse_pkcs8(const std::string_view der) -> std::optional<PKCS8Key> {
106160 // NOLINTEND(modernize-raw-string-literal)
107161
108162 if (oid->content == rsa || oid->content == rsa_pss) {
163+ if (!rsa_private_key_acceptable (private_key->content )) {
164+ return std::nullopt ;
165+ }
166+
109167 return PKCS8Key{.kind = PKCS8KeyKind::RSA ,
110168 .curve = {},
111169 .edwards_curve = {},
0 commit comments