@@ -3406,34 +3406,6 @@ constexpr bool IsASN1Sequence(const unsigned char* data,
34063406 return true ;
34073407}
34083408
3409- constexpr bool ReadASN1Element (const unsigned char * data,
3410- size_t size,
3411- unsigned char tag,
3412- size_t * header_size,
3413- size_t * content_size,
3414- size_t * total_size) {
3415- if (size < 2 || data[0 ] != tag) return false ;
3416-
3417- size_t offset;
3418- size_t length;
3419- if (data[1 ] & 0x80 ) {
3420- size_t n_bytes = data[1 ] & ~0x80 ;
3421- if (n_bytes + 2 > size || n_bytes > sizeof (size_t )) return false ;
3422- length = 0 ;
3423- for (size_t i = 0 ; i < n_bytes; i++) length = (length << 8 ) | data[i + 2 ];
3424- offset = 2 + n_bytes;
3425- } else {
3426- offset = 2 ;
3427- length = data[1 ];
3428- }
3429-
3430- if (offset > size || length > size - offset) return false ;
3431- *header_size = offset;
3432- *content_size = length;
3433- *total_size = offset + length;
3434- return true ;
3435- }
3436-
34373409constexpr bool IsEncryptedPrivateKeyInfo (
34383410 const Buffer<const unsigned char >& buffer) {
34393411 // Both PrivateKeyInfo and EncryptedPrivateKeyInfo start with a SEQUENCE.
@@ -6177,147 +6149,48 @@ Rsa::OtherPrimeInfoPointer::OtherPrimeInfoPointer(BignumPointer&& r,
61776149
61786150#if NCRYPTO_USE_OPENSSL3_PROVIDER
61796151namespace {
6180- int DigestAlgorithmIdentifierToNid (const unsigned char * data, size_t size) {
6181- size_t sequence_header;
6182- size_t sequence_len;
6183- size_t sequence_total;
6184- if (!ReadASN1Element (
6185- data, size, 0x30 , &sequence_header, &sequence_len, &sequence_total)) {
6186- return NID_undef;
6187- }
6188-
6189- size_t oid_header;
6190- size_t oid_len;
6191- size_t oid_total;
6192- const unsigned char * oid = data + sequence_header;
6193- if (!ReadASN1Element (
6194- oid, sequence_len, 0x06 , &oid_header, &oid_len, &oid_total)) {
6195- return NID_undef;
6196- }
6197-
6198- const unsigned char * oid_data = oid;
6199- DeleteFnPtr<ASN1_OBJECT , ASN1_OBJECT_free> obj (
6200- d2i_ASN1_OBJECT (nullptr , &oid_data, oid_total));
6201- if (!obj) return NID_undef;
6202- return OBJ_obj2nid (obj.get ());
6152+ // Normalizes a provider digest name such as "SHA2-256" to the long name the
6153+ // rest of the key details use ("sha256"). The returned storage has static
6154+ // lifetime, which the string_view fields of PssParams require.
6155+ const char * RsaPssDigestLongName (const char * name) {
6156+ const EVP_MD * md = EVP_get_digestbyname (name);
6157+ if (md == nullptr ) return nullptr ;
6158+ const int nid = EVP_MD_get_type (md);
6159+ return nid != NID_undef ? OBJ_nid2ln (nid) : nullptr ;
62036160}
62046161
62056162bool ReadRsaPssParams (const EVP_PKEY * pkey, Rsa::PssParams* params) {
6206- const int der_len = i2d_PUBKEY (pkey, nullptr );
6207- if (der_len <= 0 ) return false ;
6208-
6209- auto der = DataPointer::Alloc (der_len);
6210- if (!der) return false ;
6211-
6212- auto serialized = static_cast <unsigned char *>(der.get ());
6213- if (i2d_PUBKEY (pkey, &serialized) != der_len) return false ;
6214-
6215- size_t outer_header;
6216- size_t outer_len;
6217- size_t outer_total;
6218- const auto * data = static_cast <const unsigned char *>(der.get ());
6219- if (!ReadASN1Element (
6220- data, der.size (), 0x30 , &outer_header, &outer_len, &outer_total)) {
6221- return false ;
6222- }
6223-
6224- size_t alg_header;
6225- size_t alg_len;
6226- size_t alg_total;
6227- const unsigned char * alg = data + outer_header;
6228- if (!ReadASN1Element (
6229- alg, outer_len, 0x30 , &alg_header, &alg_len, &alg_total)) {
6230- return false ;
6231- }
6232-
6233- size_t oid_header;
6234- size_t oid_len;
6235- size_t oid_total;
6236- const unsigned char * oid = alg + alg_header;
6237- if (!ReadASN1Element (oid, alg_len, 0x06 , &oid_header, &oid_len, &oid_total) ||
6238- oid_total == alg_len) {
6239- return false ;
6240- }
6241-
6242- size_t pss_header;
6243- size_t pss_len;
6244- size_t pss_total;
6245- const unsigned char * pss = oid + oid_total;
6246- if (!ReadASN1Element (
6247- pss, alg_len - oid_total, 0x30 , &pss_header, &pss_len, &pss_total)) {
6163+ // The RSASSA-PSS-params sequence is exposed as a unit. The salt length is
6164+ // readable whenever the sequence is present, including when it is empty
6165+ // because every field carried its default, and unreadable when the algorithm
6166+ // identifier has no parameters at all. That is the distinction between a
6167+ // restricted key and an unrestricted one.
6168+ int salt_length = 0 ;
6169+ // TODO(panva): In a semver-major, reject malformed RSA-PSS parameters
6170+ // at key import instead of omitting asymmetricKeyDetails fields.
6171+ if (EVP_PKEY_get_int_param (
6172+ pkey, OSSL_PKEY_PARAM_RSA_PSS_SALTLEN , &salt_length) != 1 ||
6173+ salt_length < 0 ) {
62486174 return false ;
62496175 }
6176+ params->salt_length = salt_length;
62506177
6251- const unsigned char * cursor = pss + pss_header;
6252- size_t remaining = pss_len;
6253- while (remaining > 0 ) {
6254- const unsigned char tag = cursor[0 ];
6255- size_t item_header;
6256- size_t item_len;
6257- size_t item_total;
6258- if (!ReadASN1Element (
6259- cursor, remaining, tag, &item_header, &item_len, &item_total)) {
6260- return false ;
6178+ // The provider may omit default SHA-1 digest parameters. Keep the initialized
6179+ // defaults when a digest name is absent or cannot be resolved.
6180+ char name[80 ];
6181+ if (EVP_PKEY_get_utf8_string_param (
6182+ pkey, OSSL_PKEY_PARAM_RSA_DIGEST , name, sizeof (name), nullptr ) == 1 ) {
6183+ if (const char * long_name = RsaPssDigestLongName (name)) {
6184+ params->digest = long_name;
62616185 }
6186+ }
62626187
6263- const unsigned char * item = cursor + item_header;
6264- switch (tag) {
6265- case 0xa0 : {
6266- const int nid = DigestAlgorithmIdentifierToNid (item, item_len);
6267- if (nid != NID_undef) params->digest = OBJ_nid2ln (nid);
6268- break ;
6269- }
6270- case 0xa1 : {
6271- size_t mgf_header;
6272- size_t mgf_len;
6273- size_t mgf_total;
6274- if (!ReadASN1Element (
6275- item, item_len, 0x30 , &mgf_header, &mgf_len, &mgf_total)) {
6276- return false ;
6277- }
6278- const unsigned char * mgf = item + mgf_header;
6279- size_t mgf_oid_header;
6280- size_t mgf_oid_len;
6281- size_t mgf_oid_total;
6282- if (!ReadASN1Element (mgf,
6283- mgf_len,
6284- 0x06 ,
6285- &mgf_oid_header,
6286- &mgf_oid_len,
6287- &mgf_oid_total) ||
6288- mgf_oid_total == mgf_len) {
6289- return false ;
6290- }
6291- const int nid = DigestAlgorithmIdentifierToNid (mgf + mgf_oid_total,
6292- mgf_len - mgf_oid_total);
6293- if (nid != NID_undef) params->mgf1_digest = OBJ_nid2ln (nid);
6294- break ;
6295- }
6296- case 0xa2 : {
6297- size_t int_header;
6298- size_t int_len;
6299- size_t int_total;
6300- if (!ReadASN1Element (
6301- item, item_len, 0x02 , &int_header, &int_len, &int_total)) {
6302- return false ;
6303- }
6304- // TODO(panva): In a semver-major, reject malformed RSA-PSS parameters
6305- // at key import instead of omitting asymmetricKeyDetails fields.
6306- if (int_len == 0 || int_len > sizeof (uint64_t ) ||
6307- (item[int_header] & 0x80 ) != 0 ) {
6308- return false ;
6309- }
6310- uint64_t salt_length = 0 ;
6311- for (size_t n = 0 ; n < int_len; n++) {
6312- salt_length = (salt_length << 8 ) | item[int_header + n];
6313- }
6314- params->salt_length = static_cast <int64_t >(salt_length);
6315- break ;
6316- }
6188+ if (EVP_PKEY_get_utf8_string_param (
6189+ pkey, OSSL_PKEY_PARAM_RSA_MGF1_DIGEST , name, sizeof (name), nullptr ) ==
6190+ 1 ) {
6191+ if (const char * long_name = RsaPssDigestLongName (name)) {
6192+ params->mgf1_digest = long_name;
63176193 }
6318-
6319- cursor += item_total;
6320- remaining -= item_total;
63216194 }
63226195
63236196 return true ;
0 commit comments