Skip to content

Commit d4a022a

Browse files
committed
add interfaces to test JWK with jwt::algorithm::rsa
wrap asymmetric and symmetric keys in a single class
1 parent 7767b6f commit d4a022a

File tree

2 files changed

+111
-9
lines changed

2 files changed

+111
-9
lines changed

include/jwt-cpp/jwt.h

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,9 @@ namespace jwt {
909909
} else
910910
throw rsa_exception(error::rsa_error::no_key_provided);
911911
}
912+
913+
rsa(std::shared_ptr<EVP_PKEY> pkey, const EVP_MD* (*md)(), std::string name)
914+
: pkey(pkey), md(md), alg_name(std::move(name)) {}
912915
/**
913916
* Sign jwt data
914917
* \param data The data to sign
@@ -3069,8 +3072,8 @@ namespace jwt {
30693072

30703073
JWT_CLAIM_EXPLICIT jwk(const typename json_traits::value_type& json) : jwk(json_traits::as_object(json)) {}
30713074

3072-
JWT_CLAIM_EXPLICIT jwk(const typename json_traits::object_type& json) : jwk_claims(json) {
3073-
this->key = build_key(jwk_claims);
3075+
JWT_CLAIM_EXPLICIT jwk(const typename json_traits::object_type& json)
3076+
: jwk_claims(json), key(build_key(jwk_claims)) {
30743077
// https://datatracker.ietf.org/doc/html/rfc7518#section-6.1
30753078
// * indicate required params
30763079
// "kty"* : "EC", "RSA", "oct"
@@ -3266,7 +3269,45 @@ namespace jwt {
32663269

32673270
bool empty() const noexcept { return jwk_claims.empty(); }
32683271

3272+
std::shared_ptr<EVP_PKEY> get_pkey() const { return key.get_asymmetric_key(); }
3273+
3274+
std::string get_oct_key() const { return key.get_symmetric_key(); }
3275+
32693276
private:
3277+
class key {
3278+
public:
3279+
static key symmetric(const std::string& bytes) { return key(bytes); }
3280+
3281+
static key asymmetric(std::shared_ptr<EVP_PKEY> pkey) { return key(pkey); }
3282+
3283+
std::string get_symmetric_key() const {
3284+
if (!is_symmetric) { throw std::logic_error("not a symmetric key"); }
3285+
3286+
return oct_key;
3287+
}
3288+
3289+
std::shared_ptr<EVP_PKEY> get_asymmetric_key() const {
3290+
if (is_symmetric) { throw std::logic_error("not an asymmetric key"); }
3291+
3292+
return pkey;
3293+
}
3294+
3295+
private:
3296+
key(const std::string& key) {
3297+
is_symmetric = true;
3298+
oct_key = key;
3299+
}
3300+
3301+
key(std::shared_ptr<EVP_PKEY> key) {
3302+
is_symmetric = false;
3303+
pkey = key;
3304+
}
3305+
3306+
bool is_symmetric;
3307+
std::shared_ptr<EVP_PKEY> pkey;
3308+
std::string oct_key;
3309+
};
3310+
32703311
static std::shared_ptr<EVP_PKEY> build_rsa_key(const details::map_of_claims<json_traits>& claims) {
32713312
EVP_PKEY* evp_key = nullptr;
32723313
auto n = jwt::helper::raw2bn(
@@ -3305,7 +3346,7 @@ namespace jwt {
33053346
#endif
33063347
}
33073348

3308-
static std::shared_ptr<EVP_PKEY> build_key(const details::map_of_claims<json_traits>& claims) {
3349+
static key build_key(const details::map_of_claims<json_traits>& claims) {
33093350
if (!claims.has_claim("kty")) {
33103351
// TODO: custom exception or error code
33113352
throw std::runtime_error("missing required claim \"kty\"");
@@ -3317,21 +3358,19 @@ namespace jwt {
33173358
}
33183359

33193360
if (claims.get_claim("kty").as_string() == "RSA") {
3320-
// TODO: build RSA key
3321-
return build_rsa_key(claims);
3361+
return key::asymmetric(build_rsa_key(claims));
33223362
} else if (claims.get_claim("kty").as_string() == "EC") {
33233363
// TODO: build EC key
3364+
throw std::runtime_error("not implemented");
33243365
} else if (claims.get_claim("kty").as_string() == "oct") {
3325-
// TODO: store in std::string or something more unsigned-ish?
3366+
return key::symmetric(base::decode<alphabet::base64url>(claims.get_claim("k").as_string()));
33263367
} else {
33273368
// TODO: do not build error messages like this
33283369
throw std::runtime_error("unknown key type (\"kty\"):" + claims.get_claim("kty").as_string());
33293370
}
3330-
3331-
return nullptr;
33323371
}
33333372

3334-
std::shared_ptr<EVP_PKEY> key;
3373+
key key;
33353374
};
33363375

33373376
/**

tests/JwkTest.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "jwt-cpp/jwt.h"
2+
#include <gtest/gtest.h>
3+
4+
/*
5+
-----BEGIN RSA PRIVATE KEY-----
6+
MIIEpAIBAAKCAQEA2KvGTTxorqX2rvLOASWcBOqevGo5eIFFUVSlQIWe8x/a19mT
7+
XbYz6l3FYZ0s2W172nBpzJggi6PLK3397JsjjrzXb1pgXCVjIjM4hs5HDNtoWmC3
8+
/+O1jWknfrUHS95KWJkKg77B3ShGO1n8drfXCL4lWdo8F3UtVjHgfYEHI1xLSv3n
9+
v8QfGpOnWh4MAdmXhcankZQNuip6pwKlF+3y2WfukHN3rAmMx1MyID77srgPW7A3
10+
f0FTiGUz5gfUdp+5MMSQbhSZTM9fXu0buU4cmL35W9GoExjfjXlixpl70HWdyeLY
11+
SNyZKaw/Tqjwq769xf5sJZBe5UP6hL/dbLYhvQIDAQABAoIBACtorsAGnEpxQazn
12+
RFKCgHGTt92zwnPcIlEbDkiQ/Llk5mlcU+PwfxIzWzolTTj6cFfhMbElwU94r1m1
13+
Ukw3ALa2KstKZgfQDb5qWKbZaO6wfoWs3vBLZLJCIQGHr0CJ9octkie27gwq53c4
14+
nhYC2vgLcFxCFsv0U/Ly5zD9yrpQgv3DElKbc2zal/Z+kBt9MAN+2S4Fh2LaEUUl
15+
8QXjxdxbe3PHvX4nO5TWM3ztcfANzPDAWFJDeOgciUK6wEqTxkmgjh4uMaDG5X3V
16+
5xQRLBnFVXYzdwAVjzJVk9RvIDSQnEgYyHLBX6d190F85G8zQMVEwvs2VD1qJO+0
17+
BppwloECgYEA7T2xC7xGtxn/Tg9lhItZzE371mTffZDNbhL2YDQt6jBHq40cmmBi
18+
MzAYhV0Z7nky3bVHQUdaDLnJYIsqIrqqxGUZjcnkajhsSd1YGBwTHAv1njr+BX9a
19+
zY15u/pNb+OYY6naFHuTmen/NKSha+s+kHmQGCEKzErhfZ4yXhrPETECgYEA6c2y
20+
3iojU/P73RyUcoWQnDdOuQ8YNMAqoGwh/FzkG9futAiyhB3mGPmn7nw79rIO02Og
21+
Rjk7t1qSSL5DX1oAP3Fq/G1HE9epgM4j82Sa9vpUZpoLBefD2wUDjD4QmzKcFuYv
22+
M/Wl6dMLURllL24IdsEctR1p76Y7Spm251k/1k0CgYBpMxMAFjPxW6jXb4JfvP9L
23+
1kTXNBHad0xxBB2WWW0GzPPrAX7ugdDpy+kDsl4eXkYNBCadrssim3vNwMglcErr
24+
Hb2wHxeXdn+mXW2D+2cJ58+5o4Ui4O9d+N9DWOHfvLfFcfsPXCD+fkG5kUs3NLCg
25+
lhcsa/KC1q2Y636ANjkd8QKBgQCP882AilNMGnnljvY7eM8rz8XRnWCbAgJ82Xcn
26+
aY4tMotPH9fCDqKgl/50kNterg0AzGNfOVfyMXrF/ReAOurSJSPpHeNYbT15B/MM
27+
pdHf5QtYTNoinatyS6j+jSwuUj/WvY0sob+wsvdRzKAHTuk5LPde8ChMnH3/FZuO
28+
3921NQKBgQCSJf1kVFuxoWtdxqII0QJv6jSMaftK5xNkWCiLpmdttDpOdLRnMrYb
29+
XXkgbME3NheApU1oXIehLyXG46DmFXCNKME98NuJ5ENvLVkOsGyPhZDtQtQT099J
30+
z8gE19JF3RSmwvcaNpsLRg24BId/GmrZKgz9TEQMm+5wt93XcKtj6w==
31+
-----END RSA PRIVATE KEY-----
32+
-----BEGIN PUBLIC KEY-----
33+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2KvGTTxorqX2rvLOASWc
34+
BOqevGo5eIFFUVSlQIWe8x/a19mTXbYz6l3FYZ0s2W172nBpzJggi6PLK3397Jsj
35+
jrzXb1pgXCVjIjM4hs5HDNtoWmC3/+O1jWknfrUHS95KWJkKg77B3ShGO1n8drfX
36+
CL4lWdo8F3UtVjHgfYEHI1xLSv3nv8QfGpOnWh4MAdmXhcankZQNuip6pwKlF+3y
37+
2WfukHN3rAmMx1MyID77srgPW7A3f0FTiGUz5gfUdp+5MMSQbhSZTM9fXu0buU4c
38+
mL35W9GoExjfjXlixpl70HWdyeLYSNyZKaw/Tqjwq769xf5sJZBe5UP6hL/dbLYh
39+
vQIDAQAB
40+
-----END PUBLIC KEY-----
41+
*/
42+
43+
TEST(JwkTest, ParseKey) {
44+
std::string token =
45+
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.IzM0dgbhU1CsRbjmwyPHXkc8LagqFtsZD6p1ls_"
46+
"WBugkEKNfFmZmhOM1YYiFg59xId_KtzNdp4puzGIafut15U06DL2ZGH_H4xE7ONy6WLA_i5z5H8gPxD3ui2W4nHEEf-mvqKSn-"
47+
"bU8YPUydrwK3dVRfP5JA9XJT0KhssSCnty99y853xvuTh0484atxMjIk2LvnIWlYXFgoggC8TMY-4AtAJDfF8aVJXT0m-"
48+
"90oNevJbxMsuf5XFKo30TWxlnRw-y-QsYr9pxj2sA0BdwqRKVRRg5KF-"
49+
"p6rIEbAv3A6UuzLORvtixp5AASS7nrBlZ1BB8q2hYFCPtOv6UETIIkaQ";
50+
std::string public_key = R"({
51+
"kty": "RSA",
52+
"n": "2KvGTTxorqX2rvLOASWcBOqevGo5eIFFUVSlQIWe8x_a19mTXbYz6l3FYZ0s2W172nBpzJggi6PLK3397JsjjrzXb1pgXCVjIjM4hs5HDNtoWmC3_-O1jWknfrUHS95KWJkKg77B3ShGO1n8drfXCL4lWdo8F3UtVjHgfYEHI1xLSv3nv8QfGpOnWh4MAdmXhcankZQNuip6pwKlF-3y2WfukHN3rAmMx1MyID77srgPW7A3f0FTiGUz5gfUdp-5MMSQbhSZTM9fXu0buU4cmL35W9GoExjfjXlixpl70HWdyeLYSNyZKaw_Tqjwq769xf5sJZBe5UP6hL_dbLYhvQ",
53+
"e": "AQAB"
54+
})";
55+
56+
auto jwk = jwt::parse_jwk(public_key);
57+
ASSERT_EQ("RSA", jwk.get_key_type());
58+
auto alg = jwt::algorithm::rsa(jwk.get_pkey(), EVP_sha256, "RS256");
59+
auto verify = jwt::verify();
60+
auto decoded_token = jwt::decode(token);
61+
62+
ASSERT_NO_THROW(verify.do_verify(jwk, decoded_token));
63+
}

0 commit comments

Comments
 (0)