diff options
Diffstat (limited to 'src/lib/x509')
-rw-r--r-- | src/lib/x509/x509_obj.cpp | 93 | ||||
-rw-r--r-- | src/lib/x509/x509cert.cpp | 47 | ||||
-rw-r--r-- | src/lib/x509/x509path.h | 4 |
3 files changed, 136 insertions, 8 deletions
diff --git a/src/lib/x509/x509_obj.cpp b/src/lib/x509/x509_obj.cpp index 3f2aa5518..f566be00e 100644 --- a/src/lib/x509/x509_obj.cpp +++ b/src/lib/x509/x509_obj.cpp @@ -16,6 +16,36 @@ namespace Botan { +namespace { +struct Pss_params + { + AlgorithmIdentifier hash_algo; + AlgorithmIdentifier mask_gen_algo; + AlgorithmIdentifier mask_gen_hash; // redundant: decoded mask_gen_algo.parameters + size_t salt_len; + size_t trailer_field; + }; + +Pss_params decode_pss_params(const std::vector<uint8_t>& encoded_pss_params) + { + Pss_params pss_parameter; + BER_Decoder(encoded_pss_params) + .start_cons(SEQUENCE) + .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, AlgorithmIdentifier("SHA-160", + AlgorithmIdentifier::USE_NULL_PARAM)) + .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE, + AlgorithmIdentifier("MGF1", DER_Encoder().encode(AlgorithmIdentifier("SHA-160", + AlgorithmIdentifier::USE_NULL_PARAM)).get_contents_unlocked())) + .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20)) + .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1)) + .end_cons(); + + BER_Decoder(pss_parameter.mask_gen_algo.parameters).decode(pss_parameter.mask_gen_hash); + + return pss_parameter; + } +} + /* * Create a generic X.509 object */ @@ -145,13 +175,22 @@ std::string X509_Object::hash_used_for_signature() const throw Internal_Error("Invalid name format found for " + oid.as_string()); - std::vector<std::string> pad_and_hash = - parse_algorithm_name(sig_info[1]); + if(sig_info[1] == "EMSA4") + { + return OIDS::lookup(decode_pss_params(signature_algorithm().parameters).hash_algo.oid); + } + else + { + std::vector<std::string> pad_and_hash = + parse_algorithm_name(sig_info[1]); - if(pad_and_hash.size() != 2) - throw Internal_Error("Invalid name format " + sig_info[1]); + if(pad_and_hash.size() != 2) + { + throw Internal_Error("Invalid name format " + sig_info[1]); + } - return pad_and_hash[1]; + return pad_and_hash[1]; + } } /* @@ -163,7 +202,7 @@ bool X509_Object::check_signature(const Public_Key* pub_key) const throw Exception("No key provided for " + m_PEM_label_pref + " signature check"); std::unique_ptr<const Public_Key> key(pub_key); return check_signature(*key); -} + } /* * Check the signature on an object @@ -181,6 +220,48 @@ bool X509_Object::check_signature(const Public_Key& pub_key) const Signature_Format format = (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + if(padding == "EMSA4") + { + // "MUST contain RSASSA-PSS-params" + if(signature_algorithm().parameters.empty()) + { + return false; + } + + Pss_params pss_parameter = decode_pss_params(signature_algorithm().parameters); + + // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 + std::string hash_algo = OIDS::lookup(pss_parameter.hash_algo.oid); + if(hash_algo != "SHA-160" && hash_algo != "SHA-224" && hash_algo != "SHA-256" && hash_algo != "SHA-384" + && hash_algo != "SHA-512") + { + return false; + } + + std::string mgf_algo = OIDS::lookup(pss_parameter.mask_gen_algo.oid); + if(mgf_algo != "MGF1") + { + return false; + } + + // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm + // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 + if(pss_parameter.mask_gen_hash.oid != pss_parameter.hash_algo.oid) + { + return false; + } + + if(pss_parameter.trailer_field != 1) + { + return false; + } + + padding += "(" + hash_algo; + padding += "," + mgf_algo; + padding += "," + std::to_string(pss_parameter.salt_len) + + ")"; // salt_len is actually not used for verification. Length is inferred from the signature + } + PK_Verifier verifier(pub_key, padding, format); return verifier.verify_message(tbs_data(), signature()); diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp index c81f74cba..5a6588ecc 100644 --- a/src/lib/x509/x509cert.cpp +++ b/src/lib/x509/x509cert.cpp @@ -112,6 +112,53 @@ void X509_Certificate::force_decode() throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key", public_key.type_tag, public_key.class_tag); + AlgorithmIdentifier public_key_alg_id; + BER_Decoder(public_key.value).decode(public_key_alg_id).discard_remaining(); + + std::vector<std::string> public_key_info = + split_on(OIDS::lookup(public_key_alg_id.oid), '/'); + + if(!public_key_info.empty() && public_key_info[0] == "RSA") + { + // RFC4055: If PublicKeyAlgo = PSS or OAEP: limit the use of the public key exclusively to either RSASSA - PSS or RSAES - OAEP + if(public_key_info.size() >= 2) + { + if(public_key_info[1] == "EMSA4") + { + /* + When the RSA private key owner wishes to limit the use of the public + key exclusively to RSASSA-PSS, then the id-RSASSA-PSS object + identifier MUST be used in the algorithm field within the subject + public key information, and, if present, the parameters field MUST + contain RSASSA-PSS-params. + + All parameters in the signature structure algorithm identifier MUST + match the parameters in the key structure algorithm identifier + except the saltLength field. The saltLength field in the signature parameters + MUST be greater or equal to that in the key parameters field. + + ToDo: Allow salt length to be greater + */ + if(public_key_alg_id != signature_algorithm()) + { + throw Decoding_Error("Algorithm identifier mismatch"); + } + } + if(public_key_info[1] == "OAEP") + { + throw Decoding_Error("Decoding subject public keys of type RSAES-OAEP is currently not supported"); + } + } + else + { + // oid = rsaEncryption -> parameters field MUST contain NULL + if(public_key_alg_id != AlgorithmIdentifier(public_key_alg_id.oid, AlgorithmIdentifier::USE_NULL_PARAM)) + { + throw Decoding_Error("Parameters field MUST contain NULL"); + } + } + } + std::vector<uint8_t> v2_issuer_key_id, v2_subject_key_id; tbs_cert.decode_optional_string(v2_issuer_key_id, BIT_STRING, 1); diff --git a/src/lib/x509/x509path.h b/src/lib/x509/x509path.h index 2bddd62b1..17932c871 100644 --- a/src/lib/x509/x509path.h +++ b/src/lib/x509/x509path.h @@ -329,7 +329,7 @@ BOTAN_PUBLIC_API(2,0) check_ocsp(const std::vector<std::shared_ptr<const X509_Ce std::chrono::system_clock::time_point ref_time); /** -* Check CRLs for revocation infomration +* Check CRLs for revocation information * @param cert_path path already validated by check_chain * @param crls the list of CRLs to check, it is assumed that crls[i] (if not null) * is the associated CRL for the subject in cert_path[i]. @@ -343,7 +343,7 @@ BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<std::shared_ptr<const X509_Cer std::chrono::system_clock::time_point ref_time); /** -* Check CRLs for revocation infomration +* Check CRLs for revocation information * @param cert_path path already validated by check_chain * @param certstores a list of certificate stores to query for the CRL * @param ref_time whatever time you want to perform the validation against |