return chain_pem;
}
-void
+bool
WebTokenEngine::validate_signature_using_n_e(const DoutPrefixProvider* dpp, const jwt::decoded_jwt& decoded, const std::string &algorithm, const std::string& n, const std::string& e) const
{
try {
}
} catch (const std::exception& e) {
ldpp_dout(dpp, 10) << std::string("Signature validation using n, e failed: ") + e.what() << dendl;
- throw std::system_error(EACCES, std::system_category(), std::string("Signature validation using n, e failed: ") + e.what());
+ return false;
}
ldpp_dout(dpp, 10) << "Verified signature using n and e"<< dendl;
- return;
+ return true;
+}
+
+bool WebTokenEngine::validate_cert_url(const DoutPrefixProvider* dpp, const std::string& cert_url,
+ const std::vector<std::string>& thumbprints) const
+{
+ // Fetch and verify cert according to https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html
+ const auto hostname = get_top_level_domain_from_host(dpp, cert_url);
+ ldpp_dout(dpp, 20) << "Validating hostname: " << hostname << dendl;
+ const auto cert_chain = connect_to_host_get_cert_chain(dpp, hostname, 443);
+ std::string cert;
+ try {
+ cert = extract_last_certificate(dpp, cert_chain);
+ ldpp_dout(dpp, 20) << "last cert: " << cert << dendl;
+ } catch(const std::exception& e) {
+ ldpp_dout(dpp, 20) << "Extracting last cert of jwks uri failed with: " << e.what() << dendl;
+ return false;
+ }
+
+ if (!is_cert_valid(thumbprints, cert)) {
+ ldpp_dout(dpp, 20) << "Cert doesn't match that with the thumbprints registered with oidc provider: " << cert.c_str() << dendl;
+ return false;
+ }
+
+ return true;
}
void
WebTokenEngine::validate_signature(const DoutPrefixProvider* dpp, const jwt::decoded_jwt& decoded, const string& algorithm, const string& iss, const vector<string>& thumbprints, optional_yield y) const
{
if (algorithm != "HS256" && algorithm != "HS384" && algorithm != "HS512") {
- string cert_url = get_cert_url(iss, dpp, y);
- if (cert_url.empty()) {
+ const auto cert_url = get_cert_url(iss, dpp, y);
+ if (cert_url.empty() || !validate_cert_url(dpp, cert_url, thumbprints)) {
+ ldpp_dout(dpp, 5) << "Not able to validate JWKS url with registered thumbprints" << dendl;
throw std::system_error(EINVAL, std::system_category());
}
for (auto &key : keys) {
JSONParser k_parser;
vector<string> x5c;
- std::string use;
- bool skip{false};
+ std::string use, kid;
if (k_parser.parse(key.c_str(), key.size())) {
- if (JSONDecoder::decode_json("use", use, &k_parser)) {
- if (use == "enc") { //if key is for encryption then don't use x5c or n and e for signature validation
- skip = true;
- } else if (use == "sig") {
- skip = false;
- }
+ if (JSONDecoder::decode_json("kid", kid, &k_parser)) {
+ ldpp_dout(dpp, 20) << "Checking key id: " << kid << dendl;
}
- if (JSONDecoder::decode_json("x5c", x5c, &k_parser)) {
- if (skip == true) {
+ if (JSONDecoder::decode_json("use", use, &k_parser) && use != "sig") {
continue;
- }
+ }
+
+ if (JSONDecoder::decode_json("x5c", x5c, &k_parser)) {
string cert;
bool found_valid_cert = false;
for (auto& it : x5c) {
break;
}
}
- if (! found_valid_cert) {
- ldpp_dout(dpp, 0) << "Cert doesn't match that with the thumbprints registered with oidc provider: " << cert.c_str() << dendl;
- throw std::system_error(EINVAL, std::system_category());
+ if (!found_valid_cert) {
+ ldpp_dout(dpp, 10) << "Cert doesn't match that with the thumbprints registered with oidc provider: " << cert.c_str() << dendl;
+ continue;
}
try {
//verify method takes care of expired tokens also
verifier.verify(decoded);
return;
} else {
- ldpp_dout(dpp, 0) << "Unsupported algorithm: " << algorithm << dendl;
- throw std::system_error(EINVAL, std::system_category());
+ ldpp_dout(dpp, 5) << "Unsupported algorithm: " << algorithm << dendl;
}
}
catch (const std::exception& e) {
- ldpp_dout(dpp, 0) << "Signature validation using x5c failed" << e.what() << dendl;
- throw std::system_error(EACCES, std::system_category());
+ ldpp_dout(dpp, 10) << "Signature validation using x5c failed" << e.what() << dendl;
}
} else {
+ // Try bare key validation
+ ldpp_dout(dpp, 20) << "Trying bare key validation" << dendl;
+ std::string kty;
+ if (JSONDecoder::decode_json("kty", kty, &k_parser) && kty != "RSA") {
+ ldpp_dout(dpp, 10) << "Only RSA bare key validation is currently supported" << dendl;
+ continue;
+ }
+
if (algorithm == "RS256" || algorithm == "RS384" || algorithm == "RS512") {
- string n, e; //modulus and exponent
+ std::string n, e; //modulus and exponent
if (JSONDecoder::decode_json("n", n, &k_parser) && JSONDecoder::decode_json("e", e, &k_parser)) {
- if (skip == true) {
- continue;
- }
- //Fetch and verify cert according to https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html
- //and the same must be installed as part of create oidc provider in rgw
- //this can be made common to all types of keys(x5c, n&e), making thumbprint validation similar to
- //AWS
- std::string hostname = get_top_level_domain_from_host(dpp, cert_url);
- //connect to host and get back cert chain from it
- std::string cert_chain = connect_to_host_get_cert_chain(dpp, hostname, 443);
- std::string cert;
- try {
- cert = extract_last_certificate(dpp, cert_chain);
- ldpp_dout(dpp, 20) << "last cert: " << cert << dendl;
- } catch(const std::exception& e) {
- ldpp_dout(dpp, 20) << "Extracting last cert of jwks uri failed with: " << e.what() << dendl;
- throw std::system_error(EINVAL, std::system_category());
+ if (validate_signature_using_n_e(dpp, decoded, algorithm, n, e)) {
+ return;
}
- if (!is_cert_valid(thumbprints, cert)) {
- ldpp_dout(dpp, 20) << "Cert doesn't match that with the thumbprints registered with oidc provider: " << cert.c_str() << dendl;
- throw std::system_error(EINVAL, std::system_category());
- }
- validate_signature_using_n_e(dpp, decoded, algorithm, n, e);
- return;
}
- ldpp_dout(dpp, 0) << "x5c not present or n, e not present" << dendl;
- throw std::system_error(EINVAL, std::system_category());
- } else {
- throw std::system_error(EINVAL, std::system_category(), "Invalid algorithm: " + algorithm);
+ ldpp_dout(dpp, 10) << "Bare key parameters are not present for key" << dendl;
}
}
- ldpp_dout(dpp, 0) << "Signature can not be validated with the input given in keys: "<< dendl;
- throw std::system_error(EINVAL, std::system_category());
} //end k_parser.parse
- }//end for iterate through keys
+ } //end for iterate through keys
+ ldpp_dout(dpp, 0) << "Signature can not be validated with the JWKS present." << dendl;
+ throw std::system_error(EINVAL, std::system_category());
} else { //end val->is_array
ldpp_dout(dpp, 0) << "keys not present in JSON" << dendl;
throw std::system_error(EINVAL, std::system_category());