Skip to content

Commit 8d9d026

Browse files
authored
Merge pull request ceph#63051 from pritha-srivastava/wip-71108-tentacle
tentacle: rgw/sts: Implementation of validating JWT using modulus and exponent Reviewed-by: Casey Bodley <[email protected]>
2 parents 0a7cdcb + ae374de commit 8d9d026

File tree

4 files changed

+487
-110
lines changed

4 files changed

+487
-110
lines changed

src/rgw/jwt-cpp/jwt.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include <openssl/pem.h>
1212
#include <openssl/ec.h>
1313
#include <openssl/err.h>
14+
#include <openssl/bn.h>
15+
#include <openssl/rsa.h>
16+
17+
#include "rgw/rgw_b64.h"
1418

1519
//If openssl version less than 1.1
1620
#if OPENSSL_VERSION_NUMBER < 269484032
@@ -233,6 +237,17 @@ namespace jwt {
233237
} else
234238
throw rsa_exception("at least one of public or private key need to be present");
235239
}
240+
241+
rsa(const EVP_MD*(*md)(), const std::string& name) : md(md), alg_name(name)
242+
{}
243+
244+
void setModulusExponentCalcPublicKey(const std::string& modulus, const std::string& exponent)
245+
{
246+
this->modulus = modulus;
247+
this->exponent = exponent;
248+
calculatePublicKey();
249+
}
250+
236251
/**
237252
* Sign jwt data
238253
* \param data The data to sign
@@ -296,8 +311,43 @@ namespace jwt {
296311
std::shared_ptr<EVP_PKEY> pkey;
297312
/// Hash generator
298313
const EVP_MD*(*md)();
314+
/// Modulus
315+
std::string modulus;
316+
/// Exponent
317+
std::string exponent;
299318
/// Algorithmname
300319
const std::string alg_name;
320+
321+
void calculatePublicKey()
322+
{
323+
std::string n_str = base64_decode_url(modulus);
324+
std::string e_str = base64_decode_url(exponent);
325+
unsigned char* u_n = (unsigned char *)n_str.c_str();
326+
unsigned char* u_e = (unsigned char *)e_str.c_str();
327+
BIGNUM *n = BN_bin2bn(u_n, n_str.size(), NULL);
328+
BIGNUM *e = BN_bin2bn(u_e, e_str.size(), NULL);
329+
330+
if (e && n) {
331+
EVP_PKEY* pRsaKey = EVP_PKEY_new();
332+
RSA* rsa = RSA_new();
333+
RSA_set0_key(rsa, n, e, nullptr);
334+
EVP_PKEY_assign_RSA(pRsaKey, rsa);
335+
std::shared_ptr<EVP_PKEY> p(pRsaKey, EVP_PKEY_free);
336+
pkey = p;
337+
} else {
338+
if (n) BN_free(n);
339+
if (e) BN_free(e);
340+
throw rsa_exception("Invalid encoding for modulus or exponent\n");
341+
}
342+
}
343+
344+
std::string base64_decode_url(const std::string& str) const {
345+
std::string s = "====";
346+
std::string padded_str = str.length() % 4 == 0 ? str : str + s.substr(0, str.length() % 4);
347+
std::replace(padded_str.begin(), padded_str.end(), '_', '/');
348+
std::replace(padded_str.begin(), padded_str.end(), '-', '+');
349+
return rgw::from_base64(padded_str);
350+
}
301351
};
302352
/**
303353
* Base class for ECDSA family of algorithms
@@ -629,6 +679,15 @@ namespace jwt {
629679
explicit rs256(const std::string& public_key, const std::string& private_key = "", const std::string& public_key_password = "", const std::string& private_key_password = "")
630680
: rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "RS256")
631681
{}
682+
683+
rs256() : rsa(EVP_sha256, "RS256")
684+
{}
685+
686+
rs256& setModulusAndExponent(const std::string& modulus, const std::string& exponent)
687+
{
688+
rsa::setModulusExponentCalcPublicKey(modulus, exponent);
689+
return *this;
690+
}
632691
};
633692
/**
634693
* RS384 algorithm
@@ -644,6 +703,15 @@ namespace jwt {
644703
explicit rs384(const std::string& public_key, const std::string& private_key = "", const std::string& public_key_password = "", const std::string& private_key_password = "")
645704
: rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha384, "RS384")
646705
{}
706+
707+
rs384() : rsa(EVP_sha384, "RS384")
708+
{}
709+
710+
rs384& setModulusAndExponent(const std::string& modulus, const std::string& exponent)
711+
{
712+
rsa::setModulusExponentCalcPublicKey(modulus, exponent);
713+
return *this;
714+
}
647715
};
648716
/**
649717
* RS512 algorithm
@@ -659,6 +727,15 @@ namespace jwt {
659727
explicit rs512(const std::string& public_key, const std::string& private_key = "", const std::string& public_key_password = "", const std::string& private_key_password = "")
660728
: rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha512, "RS512")
661729
{}
730+
731+
rs512() : rsa(EVP_sha512, "RS512")
732+
{}
733+
734+
rs512& setModulusAndExponent(const std::string& modulus, const std::string& exponent)
735+
{
736+
rsa::setModulusExponentCalcPublicKey(modulus, exponent);
737+
return *this;
738+
}
662739
};
663740
/**
664741
* ES256 algorithm

src/rgw/rgw_auth.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,15 @@ auto rgw::auth::WebIdentityApplier::load_acct_info(const DoutPrefixProvider* dpp
701701
void rgw::auth::WebIdentityApplier::modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const
702702
{
703703
s->info.args.append("sub", this->sub);
704-
s->info.args.append("aud", this->aud);
704+
//this is needed for AssumeRoleWithWebIdentityResponse
705+
//but if aud is not present in the token, client id can be used
706+
//from AWS docs - "The intended audience (also known as client ID) of the web identity token."
707+
//https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html
708+
if (this->aud.empty() && !this->client_id.empty()) {
709+
s->info.args.append("aud", this->client_id);
710+
} else {
711+
s->info.args.append("aud", this->aud);
712+
}
705713
s->info.args.append("provider_id", this->iss);
706714
s->info.args.append("client_id", this->client_id);
707715

0 commit comments

Comments
 (0)