@@ -146,7 +146,8 @@ namespace jwt {
146
146
create_mem_bio_failed,
147
147
no_key_provided,
148
148
invalid_key_size,
149
- invalid_key
149
+ invalid_key,
150
+ create_context_failed
150
151
};
151
152
/* *
152
153
* \brief Error category for ECDSA errors
@@ -165,6 +166,7 @@ namespace jwt {
165
166
return " at least one of public or private key need to be present" ;
166
167
case ecdsa_error::invalid_key_size: return " invalid key size" ;
167
168
case ecdsa_error::invalid_key: return " invalid key" ;
169
+ case ecdsa_error::create_context_failed: return " failed to create context" ;
168
170
default : return " unknown ECDSA error" ;
169
171
}
170
172
}
@@ -186,7 +188,8 @@ namespace jwt {
186
188
verifyupdate_failed,
187
189
verifyfinal_failed,
188
190
get_key_failed,
189
- set_rsa_pss_saltlen_failed
191
+ set_rsa_pss_saltlen_failed,
192
+ signature_encoding_failed
190
193
};
191
194
/* *
192
195
* \brief Error category for verification errors
@@ -211,6 +214,8 @@ namespace jwt {
211
214
return " failed to verify signature: Could not get key" ;
212
215
case signature_verification_error::set_rsa_pss_saltlen_failed:
213
216
return " failed to verify signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed" ;
217
+ case signature_verification_error::signature_encoding_failed:
218
+ return " failed to verify signature: i2d_ECDSA_SIG failed" ;
214
219
default : return " unknown signature verification error" ;
215
220
}
216
221
}
@@ -241,6 +246,7 @@ namespace jwt {
241
246
rsa_private_encrypt_failed,
242
247
get_key_failed,
243
248
set_rsa_pss_saltlen_failed,
249
+ signature_decoding_failed
244
250
};
245
251
/* *
246
252
* \brief Error category for signature generation errors
@@ -276,6 +282,8 @@ namespace jwt {
276
282
return " failed to generate signature: Could not get key" ;
277
283
case signature_generation_error::set_rsa_pss_saltlen_failed:
278
284
return " failed to create signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed" ;
285
+ case signature_generation_error::signature_decoding_failed:
286
+ return " failed to create signature: d2i_ECDSA_SIG failed" ;
279
287
default : return " unknown signature generation error" ;
280
288
}
281
289
}
@@ -995,21 +1003,21 @@ namespace jwt {
995
1003
const std::string& private_key_password, const EVP_MD* (*md)(), std::string name, size_t siglen)
996
1004
: md(md), alg_name(std::move(name)), signature_length(siglen) {
997
1005
if (!private_key.empty ()) {
998
- auto epkey = helper::load_private_ec_key_from_string (private_key, private_key_password);
999
- pkey.reset ( EVP_PKEY_get1_EC_KEY (epkey. get ()), EC_KEY_free );
1006
+ pkey = helper::load_private_ec_key_from_string (private_key, private_key_password);
1007
+ check_private_key ( pkey.get ());
1000
1008
} else if (!public_key.empty ()) {
1001
- auto epkey = helper::load_public_ec_key_from_string (public_key, public_key_password);
1002
- pkey.reset ( EVP_PKEY_get1_EC_KEY (epkey. get ()), EC_KEY_free );
1009
+ pkey = helper::load_public_ec_key_from_string (public_key, public_key_password);
1010
+ check_public_key ( pkey.get ());
1003
1011
} else {
1004
1012
throw ecdsa_exception (error::ecdsa_error::no_key_provided);
1005
1013
}
1006
1014
if (!pkey) throw ecdsa_exception (error::ecdsa_error::invalid_key);
1007
- size_t keysize = EC_GROUP_get_degree (EC_KEY_get0_group (pkey.get ()));
1015
+
1016
+ size_t keysize = EVP_PKEY_bits (pkey.get ());
1008
1017
if (keysize != signature_length * 4 && (signature_length != 132 || keysize != 521 ))
1009
1018
throw ecdsa_exception (error::ecdsa_error::invalid_key_size);
1010
-
1011
- if (EC_KEY_check_key (pkey.get ()) == 0 ) throw ecdsa_exception (error::ecdsa_error::invalid_key);
1012
1019
}
1020
+
1013
1021
/* *
1014
1022
* Sign jwt data
1015
1023
* \param data The data to sign
@@ -1018,17 +1026,122 @@ namespace jwt {
1018
1026
*/
1019
1027
std::string sign (const std::string& data, std::error_code& ec) const {
1020
1028
ec.clear ();
1021
- const std::string hash = generate_hash (data, ec);
1022
- if (ec) return {};
1029
+ #ifdef JWT_OPENSSL_1_0_0
1030
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_destroy)> ctx (EVP_MD_CTX_create (), EVP_MD_CTX_destroy);
1031
+ #else
1032
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_free)> ctx (EVP_MD_CTX_create (), EVP_MD_CTX_free);
1033
+ #endif
1034
+ if (!ctx) {
1035
+ ec = error::signature_generation_error::create_context_failed;
1036
+ return {};
1037
+ }
1038
+ if (!EVP_DigestSignInit (ctx.get (), nullptr , md (), nullptr , pkey.get ())) {
1039
+ ec = error::signature_generation_error::signinit_failed;
1040
+ return {};
1041
+ }
1042
+ if (!EVP_DigestUpdate (ctx.get (), data.data (), data.size ())) {
1043
+ ec = error::signature_generation_error::digestupdate_failed;
1044
+ return {};
1045
+ }
1046
+
1047
+ size_t len = 0 ;
1048
+ if (!EVP_DigestSignFinal (ctx.get (), nullptr , &len)) {
1049
+ ec = error::signature_generation_error::signfinal_failed;
1050
+ return {};
1051
+ }
1052
+ std::string res (len, ' \0 ' );
1053
+ if (!EVP_DigestSignFinal (ctx.get (), (unsigned char *)res.data (), &len)) {
1054
+ ec = error::signature_generation_error::signfinal_failed;
1055
+ return {};
1056
+ }
1023
1057
1058
+ res.resize (len);
1059
+ return der_to_p1363_signature (res, ec);
1060
+ }
1061
+
1062
+ /* *
1063
+ * Check if signature is valid
1064
+ * \param data The data to check signature against
1065
+ * \param signature Signature provided by the jwt
1066
+ * \param ec Filled with details on error
1067
+ */
1068
+ void verify (const std::string& data, const std::string& signature, std::error_code& ec) const {
1069
+ ec.clear ();
1070
+ std::string der_signature = p1363_to_der_signature (signature, ec);
1071
+ if (ec) { return ; }
1072
+
1073
+ #ifdef JWT_OPENSSL_1_0_0
1074
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_destroy)> ctx (EVP_MD_CTX_create (), EVP_MD_CTX_destroy);
1075
+ #else
1076
+ std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_free)> ctx (EVP_MD_CTX_create (), EVP_MD_CTX_free);
1077
+ #endif
1078
+ if (!ctx) {
1079
+ ec = error::signature_verification_error::create_context_failed;
1080
+ return ;
1081
+ }
1082
+ if (!EVP_DigestVerifyInit (ctx.get (), nullptr , md (), nullptr , pkey.get ())) {
1083
+ ec = error::signature_verification_error::verifyinit_failed;
1084
+ return ;
1085
+ }
1086
+ if (!EVP_DigestUpdate (ctx.get (), data.data (), data.size ())) {
1087
+ ec = error::signature_verification_error::verifyupdate_failed;
1088
+ return ;
1089
+ }
1090
+
1091
+ auto res =
1092
+ EVP_DigestVerifyFinal (ctx.get (), reinterpret_cast <const unsigned char *>(der_signature.data ()),
1093
+ static_cast <unsigned int >(der_signature.length ()));
1094
+ if (res == 0 ) {
1095
+ ec = error::signature_verification_error::invalid_signature;
1096
+ return ;
1097
+ }
1098
+ if (res == -1 ) {
1099
+ ec = error::signature_verification_error::verifyfinal_failed;
1100
+ return ;
1101
+ }
1102
+ }
1103
+ /* *
1104
+ * Returns the algorithm name provided to the constructor
1105
+ * \return algorithm's name
1106
+ */
1107
+ std::string name () const { return alg_name; }
1108
+
1109
+ private:
1110
+ static void check_public_key (EVP_PKEY* pkey) {
1111
+ #ifdef JWT_OPENSSL_3_0
1112
+ std::unique_ptr<EVP_PKEY_CTX, decltype (&EVP_PKEY_CTX_free)> ctx (
1113
+ EVP_PKEY_CTX_new_from_pkey (nullptr , pkey, nullptr ), EVP_PKEY_CTX_free);
1114
+ if (!ctx) { throw ecdsa_exception (error::ecdsa_error::create_context_failed); }
1115
+ if (EVP_PKEY_public_check (ctx.get ()) != 1 ) { throw ecdsa_exception (error::ecdsa_error::invalid_key); }
1116
+ #else
1117
+ std::unique_ptr<EC_KEY, decltype (&EC_KEY_free)> eckey (EVP_PKEY_get1_EC_KEY (pkey), EC_KEY_free);
1118
+ if (!eckey) { throw ecdsa_exception (error::ecdsa_error::invalid_key); }
1119
+ if (EC_KEY_check_key (eckey.get ()) == 0 ) throw ecdsa_exception (error::ecdsa_error::invalid_key);
1120
+ #endif
1121
+ }
1122
+
1123
+ static void check_private_key (EVP_PKEY* pkey) {
1124
+ #ifdef JWT_OPENSSL_3_0
1125
+ std::unique_ptr<EVP_PKEY_CTX, decltype (&EVP_PKEY_CTX_free)> ctx (
1126
+ EVP_PKEY_CTX_new_from_pkey (nullptr , pkey, nullptr ), EVP_PKEY_CTX_free);
1127
+ if (!ctx) { throw ecdsa_exception (error::ecdsa_error::create_context_failed); }
1128
+ if (EVP_PKEY_private_check (ctx.get ()) != 1 ) { throw ecdsa_exception (error::ecdsa_error::invalid_key); }
1129
+ #else
1130
+ std::unique_ptr<EC_KEY, decltype (&EC_KEY_free)> eckey (EVP_PKEY_get1_EC_KEY (pkey), EC_KEY_free);
1131
+ if (!eckey) { throw ecdsa_exception (error::ecdsa_error::invalid_key); }
1132
+ if (EC_KEY_check_key (eckey.get ()) == 0 ) throw ecdsa_exception (error::ecdsa_error::invalid_key);
1133
+ #endif
1134
+ }
1135
+
1136
+ std::string der_to_p1363_signature (const std::string& der_signature, std::error_code& ec) const {
1137
+ const unsigned char * possl_signature = reinterpret_cast <const unsigned char *>(der_signature.data ());
1024
1138
std::unique_ptr<ECDSA_SIG, decltype (&ECDSA_SIG_free)> sig (
1025
- ECDSA_do_sign (reinterpret_cast <const unsigned char *>(hash.data ()), static_cast <int >(hash.size ()),
1026
- pkey.get ()),
1027
- ECDSA_SIG_free);
1139
+ d2i_ECDSA_SIG (nullptr , &possl_signature, der_signature.length ()), ECDSA_SIG_free);
1028
1140
if (!sig) {
1029
- ec = error::signature_generation_error::ecdsa_do_sign_failed ;
1141
+ ec = error::signature_generation_error::signature_decoding_failed ;
1030
1142
return {};
1031
1143
}
1144
+
1032
1145
#ifdef JWT_OPENSSL_1_0_0
1033
1146
1034
1147
auto rr = helper::bn2raw (sig->r );
@@ -1047,91 +1160,45 @@ namespace jwt {
1047
1160
return rr + rs;
1048
1161
}
1049
1162
1050
- /* *
1051
- * Check if signature is valid
1052
- * \param data The data to check signature against
1053
- * \param signature Signature provided by the jwt
1054
- * \param ec Filled with details on error
1055
- */
1056
- void verify (const std::string& data, const std::string& signature, std::error_code& ec) const {
1163
+ std::string p1363_to_der_signature (const std::string& signature, std::error_code& ec) const {
1057
1164
ec.clear ();
1058
- const std::string hash = generate_hash (data, ec);
1059
- if (ec) return ;
1060
1165
auto r = helper::raw2bn (signature.substr (0 , signature.size () / 2 ));
1061
1166
auto s = helper::raw2bn (signature.substr (signature.size () / 2 ));
1062
1167
1168
+ ECDSA_SIG* psig;
1063
1169
#ifdef JWT_OPENSSL_1_0_0
1064
1170
ECDSA_SIG sig;
1065
1171
sig.r = r.get ();
1066
1172
sig.s = s.get ();
1067
-
1068
- if (ECDSA_do_verify ((const unsigned char *)hash.data (), static_cast <int >(hash.size ()), &sig,
1069
- pkey.get ()) != 1 ) {
1070
- ec = error::signature_verification_error::invalid_signature;
1071
- return ;
1072
- }
1173
+ psig = &sig;
1073
1174
#else
1074
1175
std::unique_ptr<ECDSA_SIG, decltype (&ECDSA_SIG_free)> sig (ECDSA_SIG_new (), ECDSA_SIG_free);
1075
1176
if (!sig) {
1076
1177
ec = error::signature_verification_error::create_context_failed;
1077
- return ;
1178
+ return {} ;
1078
1179
}
1079
-
1080
1180
ECDSA_SIG_set0 (sig.get (), r.release (), s.release ());
1081
-
1082
- if (ECDSA_do_verify (reinterpret_cast <const unsigned char *>(hash.data ()), static_cast <int >(hash.size ()),
1083
- sig.get (), pkey.get ()) != 1 ) {
1084
- ec = error::signature_verification_error::invalid_signature;
1085
- return ;
1086
- }
1181
+ psig = sig.get ();
1087
1182
#endif
1088
- }
1089
- /* *
1090
- * Returns the algorithm name provided to the constructor
1091
- * \return algorithm's name
1092
- */
1093
- std::string name () const { return alg_name; }
1094
1183
1095
- private:
1096
- /* *
1097
- * Hash the provided data using the hash function specified in constructor
1098
- * \param data Data to hash
1099
- * \return Hash of data
1100
- */
1101
- std::string generate_hash (const std::string& data, std::error_code& ec) const {
1102
- #ifdef JWT_OPENSSL_1_0_0
1103
- std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_destroy)> ctx (EVP_MD_CTX_create (),
1104
- &EVP_MD_CTX_destroy);
1105
- #else
1106
- std::unique_ptr<EVP_MD_CTX, decltype (&EVP_MD_CTX_free)> ctx (EVP_MD_CTX_new (), EVP_MD_CTX_free);
1107
- #endif
1108
- if (!ctx) {
1109
- ec = error::signature_generation_error::create_context_failed;
1110
- return {};
1111
- }
1112
- if (EVP_DigestInit (ctx.get (), md ()) == 0 ) {
1113
- ec = error::signature_generation_error::digestinit_failed;
1184
+ int length = i2d_ECDSA_SIG (psig, nullptr );
1185
+ if (length < 0 ) {
1186
+ ec = error::signature_verification_error::signature_encoding_failed;
1114
1187
return {};
1115
1188
}
1116
- if (EVP_DigestUpdate (ctx.get (), data.data (), data.size ()) == 0 ) {
1117
- ec = error::signature_generation_error::digestupdate_failed;
1189
+ std::string der_signature (length, ' \0 ' );
1190
+ unsigned char * psbuffer = (unsigned char *)der_signature.data ();
1191
+ length = i2d_ECDSA_SIG (psig, &psbuffer);
1192
+ if (length < 0 ) {
1193
+ ec = error::signature_verification_error::signature_encoding_failed;
1118
1194
return {};
1119
1195
}
1120
- unsigned int len = 0 ;
1121
- std::string res (EVP_MD_CTX_size (ctx.get ()), ' \0 ' );
1122
- if (EVP_DigestFinal (
1123
- ctx.get (),
1124
- (unsigned char *)res.data (), // NOLINT(google-readability-casting) requires `const_cast`
1125
- &len) == 0 ) {
1126
- ec = error::signature_generation_error::digestfinal_failed;
1127
- return {};
1128
- }
1129
- res.resize (len);
1130
- return res;
1196
+ der_signature.resize (length);
1197
+ return der_signature;
1131
1198
}
1132
1199
1133
1200
// / OpenSSL struct containing keys
1134
- std::shared_ptr<EC_KEY > pkey;
1201
+ std::shared_ptr<EVP_PKEY > pkey;
1135
1202
// / Hash generator function
1136
1203
const EVP_MD* (*md)();
1137
1204
// / algorithm's name
0 commit comments