Skip to content

Commit 9f07905

Browse files
sandro97gitThalhammerprince-chrismc
authored
Support passing ssl library key handles to algorithms (Thalhammer#369)
* Support passing ssl library key handles to algorithms * Support passing public keys too for ssl library key handles * add documentation to ecdsa constructor * Support passing ssl library rsa keys * reformat code --------- Co-authored-by: Dominik Thalhammer <dominik@thalhammer.it> Co-authored-by: Chris Mc <prince.chrismc@gmail.com>
1 parent 0ab9469 commit 9f07905

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

include/jwt-cpp/jwt.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,17 @@ namespace jwt {
14601460
} else
14611461
throw error::rsa_exception(error::rsa_error::no_key_provided);
14621462
}
1463+
/**
1464+
* Construct new rsa algorithm
1465+
*
1466+
* \param key_pair openssl EVP_PKEY structure containing RSA key pair. The private part is optional.
1467+
* \param md Pointer to hash function
1468+
* \param name Name of the algorithm
1469+
*/
1470+
rsa(helper::evp_pkey_handle key_pair, const EVP_MD* (*md)(), std::string name)
1471+
: pkey(std::move(key_pair)), md(md), alg_name(std::move(name)) {
1472+
if (!pkey) { throw error::rsa_exception(error::rsa_error::no_key_provided); }
1473+
}
14631474
/**
14641475
* Sign jwt data
14651476
* \param data The data to sign
@@ -1570,6 +1581,22 @@ namespace jwt {
15701581
throw error::ecdsa_exception(error::ecdsa_error::invalid_key_size);
15711582
}
15721583

1584+
/**
1585+
* Construct new ecdsa algorithm
1586+
*
1587+
* \param key_pair openssl EVP_PKEY structure containing ECDSA key pair. The private part is optional.
1588+
* \param md Pointer to hash function
1589+
* \param name Name of the algorithm
1590+
* \param siglen The bit length of the signature
1591+
*/
1592+
ecdsa(helper::evp_pkey_handle key_pair, const EVP_MD* (*md)(), std::string name, size_t siglen)
1593+
: pkey(std::move(key_pair)), md(md), alg_name(std::move(name)), signature_length(siglen) {
1594+
if (!pkey) { throw error::ecdsa_exception(error::ecdsa_error::no_key_provided); }
1595+
size_t keysize = EVP_PKEY_bits(pkey.get());
1596+
if (keysize != signature_length * 4 && (signature_length != 132 || keysize != 521))
1597+
throw error::ecdsa_exception(error::ecdsa_error::invalid_key_size);
1598+
}
1599+
15731600
/**
15741601
* Sign jwt data
15751602
* \param data The data to sign

tests/TokenTest.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ TEST(TokenTest, CreateTokenRS256) {
7171
token);
7272
}
7373

74+
TEST(TokenTest, CreateTokenEvpPkeyRS256) {
75+
auto token = jwt::create().set_issuer("auth0").set_type("JWS").sign(
76+
jwt::algorithm::rsa(jwt::helper::load_private_key_from_string(rsa_priv_key), EVP_sha256, "RS256"));
77+
78+
ASSERT_EQ(
79+
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
80+
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
81+
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
82+
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ",
83+
token);
84+
}
85+
7486
#if !defined(JWT_OPENSSL_1_0_0)
7587
TEST(TokenTest, CreateTokenRS256Encrypted) {
7688
// openssl genrsa -aes256 -out private.pem 2048
@@ -175,6 +187,28 @@ TEST(TokenTest, CreateTokenES256) {
175187
ASSERT_NO_THROW(jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa256_pub_key, "", "", "")).verify(decoded));
176188
}
177189

190+
TEST(TokenTest, CreateTokenEvpPkeyES256) {
191+
192+
auto token = jwt::create().set_issuer("auth0").set_type("JWS").sign(jwt::algorithm::ecdsa(
193+
jwt::helper::load_private_ec_key_from_string(ecdsa256_priv_key), EVP_sha256, "ES256", 64));
194+
195+
auto decoded = jwt::decode(token);
196+
197+
ASSERT_THROW(
198+
jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa256_pub_key_invalid, "", "", "")).verify(decoded),
199+
jwt::error::signature_verification_exception);
200+
ASSERT_NO_THROW(jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa256_pub_key, "", "", "")).verify(decoded));
201+
}
202+
203+
TEST(TokenTest, CreateTokenEvpPkeyES256NoPrivate) {
204+
ASSERT_THROW(
205+
[]() {
206+
auto token = jwt::create().set_issuer("auth0").set_type("JWS").sign(jwt::algorithm::ecdsa(
207+
jwt::helper::load_public_ec_key_from_string(ecdsa256_pub_key), EVP_sha256, "ES256", 64));
208+
}(),
209+
jwt::error::signature_generation_exception);
210+
}
211+
178212
TEST(TokenTest, CreateTokenES256NoPrivate) {
179213
ASSERT_THROW(
180214
[]() {
@@ -307,6 +341,23 @@ TEST(TokenTest, VerifyTokenRS256) {
307341
verify.verify(decoded_token);
308342
}
309343

344+
TEST(TokenTest, VerifyTokenEvpPkeyRS256) {
345+
std::string token =
346+
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
347+
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
348+
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
349+
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
350+
351+
auto verify = jwt::verify()
352+
.allow_algorithm(jwt::algorithm::rsa(jwt::helper::load_private_key_from_string(rsa_priv_key),
353+
EVP_sha256, "RS256"))
354+
.with_issuer("auth0");
355+
356+
auto decoded_token = jwt::decode(token);
357+
358+
verify.verify(decoded_token);
359+
}
360+
310361
TEST(TokenTest, VerifyTokenRS256PublicOnly) {
311362
std::string token =
312363
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
@@ -321,6 +372,23 @@ TEST(TokenTest, VerifyTokenRS256PublicOnly) {
321372
verify.verify(decoded_token);
322373
}
323374

375+
TEST(TokenTest, VerifyTokenEvpPkeyRS256PublicOnly) {
376+
std::string token =
377+
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
378+
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
379+
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
380+
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
381+
382+
auto verify = jwt::verify()
383+
.allow_algorithm(jwt::algorithm::rsa(jwt::helper::load_public_key_from_string(rsa_pub_key),
384+
EVP_sha256, "RS256"))
385+
.with_issuer("auth0");
386+
387+
auto decoded_token = jwt::decode(token);
388+
389+
verify.verify(decoded_token);
390+
}
391+
324392
TEST(TokenTest, VerifyTokenRS256PublicOnlyEncrypted) {
325393
// openssl genrsa -aes256 -out private.pem 2048
326394
// openssl rsa -in private.pem -pubout -out public.pem
@@ -548,6 +616,17 @@ TEST(TokenTest, VerifyTokenES256FailNoKey) {
548616
jwt::error::ecdsa_exception);
549617
}
550618

619+
TEST(TokenTest, VerifyTokenEvpPkeyES256FailNoKey) {
620+
ASSERT_THROW(
621+
[]() {
622+
auto verify = jwt::verify()
623+
.allow_algorithm(
624+
jwt::algorithm::ecdsa(jwt::helper::evp_pkey_handle{nullptr}, EVP_sha256, "ES256", 64))
625+
.with_issuer("auth0");
626+
}(),
627+
jwt::error::ecdsa_exception);
628+
}
629+
551630
TEST(TokenTest, VerifyTokenES256) {
552631
const std::string token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_"
553632
"4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g";
@@ -558,6 +637,17 @@ TEST(TokenTest, VerifyTokenES256) {
558637
verify.verify(decoded_token);
559638
}
560639

640+
TEST(TokenTest, VerifyTokenEvpPkeyES256) {
641+
const std::string token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_"
642+
"4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g";
643+
644+
auto verify = jwt::verify().allow_algorithm(
645+
jwt::algorithm::ecdsa(jwt::helper::load_public_ec_key_from_string(ecdsa256_pub_key), EVP_sha256, "ES256", 64));
646+
auto decoded_token = jwt::decode(token);
647+
648+
verify.verify(decoded_token);
649+
}
650+
561651
TEST(TokenTest, VerifyTokenES256Fail) {
562652
const std::string token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_"
563653
"4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g";

0 commit comments

Comments
 (0)