@@ -185,7 +185,8 @@ namespace jwt {
185
185
verifyinit_failed,
186
186
verifyupdate_failed,
187
187
verifyfinal_failed,
188
- get_key_failed
188
+ get_key_failed,
189
+ set_rsa_pss_saltlen_failed
189
190
};
190
191
/* *
191
192
* \brief Error category for verification errors
@@ -208,6 +209,8 @@ namespace jwt {
208
209
return " failed to verify signature: VerifyFinal failed" ;
209
210
case signature_verification_error::get_key_failed:
210
211
return " failed to verify signature: Could not get key" ;
212
+ case signature_verification_error::set_rsa_pss_saltlen_failed:
213
+ return " failed to verify signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed" ;
211
214
default : return " unknown signature verification error" ;
212
215
}
213
216
}
@@ -236,7 +239,8 @@ namespace jwt {
236
239
digestfinal_failed,
237
240
rsa_padding_failed,
238
241
rsa_private_encrypt_failed,
239
- get_key_failed
242
+ get_key_failed,
243
+ set_rsa_pss_saltlen_failed,
240
244
};
241
245
/* *
242
246
* \brief Error category for signature generation errors
@@ -265,11 +269,13 @@ namespace jwt {
265
269
case signature_generation_error::digestfinal_failed:
266
270
return " failed to create signature: DigestFinal failed" ;
267
271
case signature_generation_error::rsa_padding_failed:
268
- return " failed to create signature: RSA_padding_add_PKCS1_PSS failed" ;
272
+ return " failed to create signature: EVP_PKEY_CTX_set_rsa_padding failed" ;
269
273
case signature_generation_error::rsa_private_encrypt_failed:
270
274
return " failed to create signature: RSA_private_encrypt failed" ;
271
275
case signature_generation_error::get_key_failed:
272
276
return " failed to generate signature: Could not get key" ;
277
+ case signature_generation_error::set_rsa_pss_saltlen_failed:
278
+ return " failed to create signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed" ;
273
279
default : return " unknown signature generation error" ;
274
280
}
275
281
}
@@ -1308,31 +1314,48 @@ namespace jwt {
1308
1314
*/
1309
1315
std::string sign (const std::string& data, std::error_code& ec) const {
1310
1316
ec.clear ();
1311
- auto hash = this ->generate_hash (data, ec);
1312
- if (ec) return {};
1313
-
1314
- std::unique_ptr<RSA, decltype (&RSA_free)> key (EVP_PKEY_get1_RSA (pkey.get ()), RSA_free);
1315
- if (!key) {
1316
- ec = error::signature_generation_error::get_key_failed;
1317
+ #ifdef JWT_OPENSSL_1_0_0
1318
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_destroy)> md_ctx (EVP_MD_CTX_create (),
1319
+ &EVP_MD_CTX_destroy);
1320
+ #else
1321
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_free)> md_ctx (EVP_MD_CTX_new (), EVP_MD_CTX_free);
1322
+ #endif
1323
+ if (!md_ctx) {
1324
+ ec = error::signature_generation_error::create_context_failed;
1317
1325
return {};
1318
1326
}
1319
- const int size = RSA_size (key. get ()) ;
1320
-
1321
- std::string padded (size, 0x00 ) ;
1322
- if ( RSA_padding_add_PKCS1_PSS (key. get (), ( unsigned char *)padded. data (),
1323
- reinterpret_cast < const unsigned char *>(hash. data ()), md (),
1324
- - 1 ) == 0 ) { // NOLINT(google-readability-casting) requires `const_cast`
1327
+ EVP_PKEY_CTX* ctx = nullptr ;
1328
+ if ( EVP_DigestSignInit (md_ctx. get (), &ctx, md (), nullptr , pkey. get ()) != 1 ) {
1329
+ ec = error::signature_generation_error::signinit_failed ;
1330
+ return {};
1331
+ }
1332
+ if ( EVP_PKEY_CTX_set_rsa_padding (ctx, RSA_PKCS1_PSS_PADDING) <= 0 ) {
1325
1333
ec = error::signature_generation_error::rsa_padding_failed;
1326
1334
return {};
1327
1335
}
1336
+ // wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
1337
+ // sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
1338
+ #ifndef LIBWOLFSSL_VERSION_HEX
1339
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen (ctx, -1 ) <= 0 ) {
1340
+ ec = error::signature_generation_error::set_rsa_pss_saltlen_failed;
1341
+ return {};
1342
+ }
1343
+ #endif
1344
+ if (EVP_DigestUpdate (md_ctx.get (), data.data (), data.size ()) != 1 ) {
1345
+ ec = error::signature_generation_error::digestupdate_failed;
1346
+ return {};
1347
+ }
1328
1348
1349
+ size_t size = EVP_PKEY_size (pkey.get ());
1329
1350
std::string res (size, 0x00 );
1330
- if (RSA_private_encrypt (size, reinterpret_cast <const unsigned char *>(padded.data ()),
1331
- (unsigned char *)res.data (), key.get (), RSA_NO_PADDING) <
1332
- 0 ) { // NOLINT(google-readability-casting) requires `const_cast`
1333
- ec = error::signature_generation_error::rsa_private_encrypt_failed;
1351
+ if (EVP_DigestSignFinal (
1352
+ md_ctx.get (),
1353
+ (unsigned char *)res.data (), // NOLINT(google-readability-casting) requires `const_cast`
1354
+ &size) <= 0 ) {
1355
+ ec = error::signature_generation_error::signfinal_failed;
1334
1356
return {};
1335
1357
}
1358
+
1336
1359
return res;
1337
1360
}
1338
1361
@@ -1344,28 +1367,41 @@ namespace jwt {
1344
1367
*/
1345
1368
void verify (const std::string& data, const std::string& signature, std::error_code& ec) const {
1346
1369
ec.clear ();
1347
- auto hash = this ->generate_hash (data, ec);
1348
- if (ec) return ;
1349
1370
1350
- std::unique_ptr<RSA, decltype (&RSA_free)> key (EVP_PKEY_get1_RSA (pkey.get ()), RSA_free);
1351
- if (!key) {
1352
- ec = error::signature_verification_error::get_key_failed;
1371
+ #ifdef JWT_OPENSSL_1_0_0
1372
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_destroy)> md_ctx (EVP_MD_CTX_create (),
1373
+ &EVP_MD_CTX_destroy);
1374
+ #else
1375
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_free)> md_ctx (EVP_MD_CTX_new (), EVP_MD_CTX_free);
1376
+ #endif
1377
+ if (!md_ctx) {
1378
+ ec = error::signature_verification_error::create_context_failed;
1353
1379
return ;
1354
1380
}
1355
- const int size = RSA_size (key.get ());
1356
-
1357
- std::string sig (size, 0x00 );
1358
- if (RSA_public_decrypt (
1359
- static_cast <int >(signature.size ()), reinterpret_cast <const unsigned char *>(signature.data ()),
1360
- (unsigned char *)sig.data (), // NOLINT(google-readability-casting) requires `const_cast`
1361
- key.get (), RSA_NO_PADDING) == 0 ) {
1362
- ec = error::signature_verification_error::invalid_signature;
1381
+ EVP_PKEY_CTX* ctx = nullptr ;
1382
+ if (EVP_DigestVerifyInit (md_ctx.get (), &ctx, md (), nullptr , pkey.get ()) != 1 ) {
1383
+ ec = error::signature_verification_error::verifyinit_failed;
1384
+ return ;
1385
+ }
1386
+ if (EVP_PKEY_CTX_set_rsa_padding (ctx, RSA_PKCS1_PSS_PADDING) <= 0 ) {
1387
+ ec = error::signature_generation_error::rsa_padding_failed;
1388
+ return ;
1389
+ }
1390
+ // wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
1391
+ // sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
1392
+ #ifndef LIBWOLFSSL_VERSION_HEX
1393
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen (ctx, -1 ) <= 0 ) {
1394
+ ec = error::signature_verification_error::set_rsa_pss_saltlen_failed;
1395
+ return ;
1396
+ }
1397
+ #endif
1398
+ if (EVP_DigestUpdate (md_ctx.get (), data.data (), data.size ()) != 1 ) {
1399
+ ec = error::signature_verification_error::verifyupdate_failed;
1363
1400
return ;
1364
1401
}
1365
1402
1366
- if (RSA_verify_PKCS1_PSS (key.get (), reinterpret_cast <const unsigned char *>(hash.data ()), md (),
1367
- reinterpret_cast <const unsigned char *>(sig.data ()), -1 ) == 0 ) {
1368
- ec = error::signature_verification_error::invalid_signature;
1403
+ if (EVP_DigestVerifyFinal (md_ctx.get (), (unsigned char *)signature.data (), signature.size ()) <= 0 ) {
1404
+ ec = error::signature_verification_error::verifyfinal_failed;
1369
1405
return ;
1370
1406
}
1371
1407
}
@@ -1376,41 +1412,6 @@ namespace jwt {
1376
1412
std::string name () const { return alg_name; }
1377
1413
1378
1414
private:
1379
- /* *
1380
- * Hash the provided data using the hash function specified in constructor
1381
- * \param data Data to hash
1382
- * \return Hash of data
1383
- */
1384
- std::string generate_hash (const std::string& data, std::error_code& ec) const {
1385
- #ifdef JWT_OPENSSL_1_0_0
1386
- std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_destroy)> ctx (EVP_MD_CTX_create (),
1387
- &EVP_MD_CTX_destroy);
1388
- #else
1389
- std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_free)> ctx (EVP_MD_CTX_new (), EVP_MD_CTX_free);
1390
- #endif
1391
- if (!ctx) {
1392
- ec = error::signature_generation_error::create_context_failed;
1393
- return {};
1394
- }
1395
- if (EVP_DigestInit (ctx.get (), md ()) == 0 ) {
1396
- ec = error::signature_generation_error::digestinit_failed;
1397
- return {};
1398
- }
1399
- if (EVP_DigestUpdate (ctx.get (), data.data (), data.size ()) == 0 ) {
1400
- ec = error::signature_generation_error::digestupdate_failed;
1401
- return {};
1402
- }
1403
- unsigned int len = 0 ;
1404
- std::string res (EVP_MD_CTX_size (ctx.get ()), ' \0 ' );
1405
- if (EVP_DigestFinal (ctx.get (), (unsigned char *)res.data (), &len) ==
1406
- 0 ) { // NOLINT(google-readability-casting) requires `const_cast`
1407
- ec = error::signature_generation_error::digestfinal_failed;
1408
- return {};
1409
- }
1410
- res.resize (len);
1411
- return res;
1412
- }
1413
-
1414
1415
// / OpenSSL structure containing keys
1415
1416
std::shared_ptr<EVP_PKEY> pkey;
1416
1417
// / Hash generator function
0 commit comments