aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/x509
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/x509')
-rw-r--r--src/lib/x509/x509_obj.cpp93
-rw-r--r--src/lib/x509/x509cert.cpp47
-rw-r--r--src/lib/x509/x509path.h4
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