/proc/self/cwd/src/verify.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2018 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include "jwt_verify_lib/verify.h" |
16 | | |
17 | | #include "absl/strings/string_view.h" |
18 | | #include "absl/time/clock.h" |
19 | | #include "jwt_verify_lib/check_audience.h" |
20 | | #include "openssl/bn.h" |
21 | | #include "openssl/curve25519.h" |
22 | | #include "openssl/ecdsa.h" |
23 | | #include "openssl/err.h" |
24 | | #include "openssl/evp.h" |
25 | | #include "openssl/hmac.h" |
26 | | #include "openssl/mem.h" |
27 | | #include "openssl/rsa.h" |
28 | | #include "openssl/sha.h" |
29 | | |
30 | | namespace google { |
31 | | namespace jwt_verify { |
32 | | namespace { |
33 | | |
34 | | // A convenience inline cast function. |
35 | 80.7k | inline const uint8_t* castToUChar(const absl::string_view& str) { |
36 | 80.7k | return reinterpret_cast<const uint8_t*>(str.data()); |
37 | 80.7k | } |
38 | | |
39 | | bool verifySignatureRSA(RSA* key, const EVP_MD* md, const uint8_t* signature, |
40 | | size_t signature_len, const uint8_t* signed_data, |
41 | 4.86k | size_t signed_data_len) { |
42 | 4.86k | if (key == nullptr || md == nullptr || signature == nullptr || |
43 | 4.86k | signed_data == nullptr) { |
44 | 0 | return false; |
45 | 0 | } |
46 | 4.86k | bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new()); |
47 | 4.86k | if (EVP_PKEY_set1_RSA(evp_pkey.get(), key) != 1) { |
48 | 0 | return false; |
49 | 0 | } |
50 | | |
51 | 4.86k | bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_create()); |
52 | 4.86k | if (EVP_DigestVerifyInit(md_ctx.get(), nullptr, md, nullptr, |
53 | 4.86k | evp_pkey.get()) == 1) { |
54 | 4.86k | if (EVP_DigestVerifyUpdate(md_ctx.get(), signed_data, signed_data_len) == |
55 | 4.86k | 1) { |
56 | 4.86k | if (EVP_DigestVerifyFinal(md_ctx.get(), signature, signature_len) == 1) { |
57 | 2 | return true; |
58 | 2 | } |
59 | 4.86k | } |
60 | 4.86k | } |
61 | 4.85k | ERR_clear_error(); |
62 | 4.85k | return false; |
63 | 4.86k | } |
64 | | |
65 | | bool verifySignatureRSA(RSA* key, const EVP_MD* md, absl::string_view signature, |
66 | 4.86k | absl::string_view signed_data) { |
67 | 4.86k | return verifySignatureRSA(key, md, castToUChar(signature), signature.length(), |
68 | 4.86k | castToUChar(signed_data), signed_data.length()); |
69 | 4.86k | } |
70 | | |
71 | | bool verifySignatureRSAPSS(RSA* key, const EVP_MD* md, const uint8_t* signature, |
72 | | size_t signature_len, const uint8_t* signed_data, |
73 | 7.21k | size_t signed_data_len) { |
74 | 7.21k | if (key == nullptr || md == nullptr || signature == nullptr || |
75 | 7.21k | signed_data == nullptr) { |
76 | 0 | return false; |
77 | 0 | } |
78 | 7.21k | bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new()); |
79 | 7.21k | if (EVP_PKEY_set1_RSA(evp_pkey.get(), key) != 1) { |
80 | 0 | return false; |
81 | 0 | } |
82 | | |
83 | 7.21k | bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_create()); |
84 | | // pctx is owned by md_ctx, no need to free it separately. |
85 | 7.21k | EVP_PKEY_CTX* pctx; |
86 | 7.21k | if (EVP_DigestVerifyInit(md_ctx.get(), &pctx, md, nullptr, evp_pkey.get()) == |
87 | 7.21k | 1 && |
88 | 7.21k | EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) == 1 && |
89 | 7.21k | EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, md) == 1 && |
90 | 7.21k | EVP_DigestVerify(md_ctx.get(), signature, signature_len, signed_data, |
91 | 7.21k | signed_data_len) == 1) { |
92 | 0 | return true; |
93 | 0 | } |
94 | | |
95 | 7.21k | ERR_clear_error(); |
96 | 7.21k | return false; |
97 | 7.21k | } |
98 | | |
99 | | bool verifySignatureRSAPSS(RSA* key, const EVP_MD* md, |
100 | | absl::string_view signature, |
101 | 7.21k | absl::string_view signed_data) { |
102 | 7.21k | return verifySignatureRSAPSS(key, md, castToUChar(signature), |
103 | 7.21k | signature.length(), castToUChar(signed_data), |
104 | 7.21k | signed_data.length()); |
105 | 7.21k | } |
106 | | |
107 | | bool verifySignatureEC(EC_KEY* key, const EVP_MD* md, const uint8_t* signature, |
108 | | size_t signature_len, const uint8_t* signed_data, |
109 | 9.54k | size_t signed_data_len) { |
110 | 9.54k | if (key == nullptr || md == nullptr || signature == nullptr || |
111 | 9.54k | signed_data == nullptr) { |
112 | 0 | return false; |
113 | 0 | } |
114 | 9.54k | bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_create()); |
115 | 9.54k | std::vector<uint8_t> digest(EVP_MAX_MD_SIZE); |
116 | 9.54k | unsigned int digest_len = 0; |
117 | | |
118 | 9.54k | if (EVP_DigestInit(md_ctx.get(), md) == 0) { |
119 | 0 | return false; |
120 | 0 | } |
121 | | |
122 | 9.54k | if (EVP_DigestUpdate(md_ctx.get(), signed_data, signed_data_len) == 0) { |
123 | 0 | return false; |
124 | 0 | } |
125 | | |
126 | 9.54k | if (EVP_DigestFinal(md_ctx.get(), digest.data(), &digest_len) == 0) { |
127 | 0 | return false; |
128 | 0 | } |
129 | | |
130 | 9.54k | bssl::UniquePtr<ECDSA_SIG> ecdsa_sig(ECDSA_SIG_new()); |
131 | 9.54k | if (!ecdsa_sig) { |
132 | 0 | return false; |
133 | 0 | } |
134 | | |
135 | 9.54k | if (BN_bin2bn(signature, signature_len / 2, ecdsa_sig->r) == nullptr || |
136 | 9.54k | BN_bin2bn(signature + (signature_len / 2), signature_len / 2, |
137 | 9.54k | ecdsa_sig->s) == nullptr) { |
138 | 0 | return false; |
139 | 0 | } |
140 | | |
141 | 9.54k | if (ECDSA_do_verify(digest.data(), digest_len, ecdsa_sig.get(), key) == 1) { |
142 | 3 | return true; |
143 | 3 | } |
144 | | |
145 | 9.53k | ERR_clear_error(); |
146 | 9.53k | return false; |
147 | 9.54k | } |
148 | | |
149 | | bool verifySignatureEC(EC_KEY* key, const EVP_MD* md, |
150 | | absl::string_view signature, |
151 | 9.54k | absl::string_view signed_data) { |
152 | 9.54k | return verifySignatureEC(key, md, castToUChar(signature), signature.length(), |
153 | 9.54k | castToUChar(signed_data), signed_data.length()); |
154 | 9.54k | } |
155 | | |
156 | | bool verifySignatureOct(const uint8_t* key, size_t key_len, const EVP_MD* md, |
157 | | const uint8_t* signature, size_t signature_len, |
158 | 4.95k | const uint8_t* signed_data, size_t signed_data_len) { |
159 | 4.95k | if (key == nullptr || md == nullptr || signature == nullptr || |
160 | 4.95k | signed_data == nullptr) { |
161 | 0 | return false; |
162 | 0 | } |
163 | | |
164 | 4.95k | std::vector<uint8_t> out(EVP_MAX_MD_SIZE); |
165 | 4.95k | unsigned int out_len = 0; |
166 | 4.95k | if (HMAC(md, key, key_len, signed_data, signed_data_len, out.data(), |
167 | 4.95k | &out_len) == nullptr) { |
168 | 0 | ERR_clear_error(); |
169 | 0 | return false; |
170 | 0 | } |
171 | | |
172 | 4.95k | if (out_len != signature_len) { |
173 | 4.61k | return false; |
174 | 4.61k | } |
175 | | |
176 | 342 | if (CRYPTO_memcmp(out.data(), signature, signature_len) == 0) { |
177 | 1 | return true; |
178 | 1 | } |
179 | | |
180 | 341 | ERR_clear_error(); |
181 | 341 | return false; |
182 | 342 | } |
183 | | |
184 | | bool verifySignatureOct(absl::string_view key, const EVP_MD* md, |
185 | | absl::string_view signature, |
186 | 4.95k | absl::string_view signed_data) { |
187 | 4.95k | return verifySignatureOct(castToUChar(key), key.length(), md, |
188 | 4.95k | castToUChar(signature), signature.length(), |
189 | 4.95k | castToUChar(signed_data), signed_data.length()); |
190 | 4.95k | } |
191 | | |
192 | | Status verifySignatureEd25519(absl::string_view key, |
193 | | absl::string_view signature, |
194 | 7.56k | absl::string_view signed_data) { |
195 | 7.56k | if (signature.length() != ED25519_SIGNATURE_LEN) { |
196 | 17 | return Status::JwtEd25519SignatureWrongLength; |
197 | 17 | } |
198 | | |
199 | 7.54k | if (ED25519_verify(castToUChar(signed_data), signed_data.length(), |
200 | 7.54k | castToUChar(signature), castToUChar(key.data())) == 1) { |
201 | 1 | return Status::Ok; |
202 | 1 | } |
203 | | |
204 | 7.54k | ERR_clear_error(); |
205 | 7.54k | return Status::JwtVerificationFail; |
206 | 7.54k | } |
207 | | |
208 | | } // namespace |
209 | | |
210 | 2.37k | Status verifyJwtWithoutTimeChecking(const Jwt& jwt, const Jwks& jwks) { |
211 | | // Verify signature |
212 | 2.37k | std::string signed_data = |
213 | 2.37k | jwt.header_str_base64url_ + '.' + jwt.payload_str_base64url_; |
214 | 2.37k | bool kid_alg_matched = false; |
215 | 37.3k | for (const auto& jwk : jwks.keys()) { |
216 | | // If kid is specified in JWT, JWK with the same kid is used for |
217 | | // verification. |
218 | | // If kid is not specified in JWT, try all JWK. |
219 | 37.3k | if (!jwt.kid_.empty() && !jwk->kid_.empty() && jwk->kid_ != jwt.kid_) { |
220 | 1.67k | continue; |
221 | 1.67k | } |
222 | | |
223 | | // The same alg must be used. |
224 | 35.6k | if (!jwk->alg_.empty() && jwk->alg_ != jwt.alg_) { |
225 | 1.35k | continue; |
226 | 1.35k | } |
227 | 34.3k | kid_alg_matched = true; |
228 | | |
229 | 34.3k | if (jwk->kty_ == "EC") { |
230 | 9.54k | const EVP_MD* md; |
231 | 9.54k | if (jwt.alg_ == "ES384") { |
232 | 0 | md = EVP_sha384(); |
233 | 9.54k | } else if (jwt.alg_ == "ES512") { |
234 | 1.63k | md = EVP_sha512(); |
235 | 7.90k | } else { |
236 | | // default to SHA256 |
237 | 7.90k | md = EVP_sha256(); |
238 | 7.90k | } |
239 | | |
240 | 9.54k | if (verifySignatureEC(jwk->ec_key_.get(), md, jwt.signature_, |
241 | 9.54k | signed_data)) { |
242 | | // Verification succeeded. |
243 | 3 | return Status::Ok; |
244 | 3 | } |
245 | 24.7k | } else if (jwk->kty_ == "RSA") { |
246 | 12.2k | const EVP_MD* md; |
247 | 12.2k | if (jwt.alg_ == "RS384" || jwt.alg_ == "PS384") { |
248 | 0 | md = EVP_sha384(); |
249 | 12.2k | } else if (jwt.alg_ == "RS512" || jwt.alg_ == "PS512") { |
250 | 721 | md = EVP_sha512(); |
251 | 11.5k | } else { |
252 | | // default to SHA256 |
253 | 11.5k | md = EVP_sha256(); |
254 | 11.5k | } |
255 | | |
256 | 12.2k | if (jwt.alg_.compare(0, 2, "RS") == 0) { |
257 | 4.86k | if (verifySignatureRSA(jwk->rsa_.get(), md, jwt.signature_, |
258 | 4.86k | signed_data)) { |
259 | | // Verification succeeded. |
260 | 2 | return Status::Ok; |
261 | 2 | } |
262 | 7.41k | } else if (jwt.alg_.compare(0, 2, "PS") == 0) { |
263 | 7.21k | if (verifySignatureRSAPSS(jwk->rsa_.get(), md, jwt.signature_, |
264 | 7.21k | signed_data)) { |
265 | | // Verification succeeded. |
266 | 0 | return Status::Ok; |
267 | 0 | } |
268 | 7.21k | } |
269 | 12.5k | } else if (jwk->kty_ == "oct") { |
270 | 4.95k | const EVP_MD* md; |
271 | 4.95k | if (jwt.alg_ == "HS384") { |
272 | 0 | md = EVP_sha384(); |
273 | 4.95k | } else if (jwt.alg_ == "HS512") { |
274 | 1.40k | md = EVP_sha512(); |
275 | 3.54k | } else { |
276 | | // default to SHA256 |
277 | 3.54k | md = EVP_sha256(); |
278 | 3.54k | } |
279 | | |
280 | 4.95k | if (verifySignatureOct(jwk->hmac_key_, md, jwt.signature_, signed_data)) { |
281 | | // Verification succeeded. |
282 | 1 | return Status::Ok; |
283 | 1 | } |
284 | 7.56k | } else if (jwk->kty_ == "OKP" && jwk->crv_ == "Ed25519") { |
285 | 7.56k | Status status = verifySignatureEd25519(jwk->okp_key_raw_, jwt.signature_, |
286 | 7.56k | signed_data); |
287 | | // For verification failures keep going and try the rest of the keys in |
288 | | // the JWKS. Otherwise status is either OK or an error with the JWT and we |
289 | | // can return immediately. |
290 | 7.56k | if (status == Status::Ok || |
291 | 7.56k | status == Status::JwtEd25519SignatureWrongLength) { |
292 | 18 | return status; |
293 | 18 | } |
294 | 7.56k | } |
295 | 34.3k | } |
296 | | |
297 | | // Verification failed. |
298 | 2.35k | return kid_alg_matched ? Status::JwtVerificationFail |
299 | 2.35k | : Status::JwksKidAlgMismatch; |
300 | 2.37k | } |
301 | | |
302 | 2.39k | Status verifyJwt(const Jwt& jwt, const Jwks& jwks) { |
303 | 2.39k | return verifyJwt(jwt, jwks, absl::ToUnixSeconds(absl::Now())); |
304 | 2.39k | } |
305 | | |
306 | | Status verifyJwt(const Jwt& jwt, const Jwks& jwks, uint64_t now, |
307 | 2.39k | uint64_t clock_skew) { |
308 | 2.39k | Status time_status = jwt.verifyTimeConstraint(now, clock_skew); |
309 | 2.39k | if (time_status != Status::Ok) { |
310 | 11 | return time_status; |
311 | 11 | } |
312 | | |
313 | 2.37k | return verifyJwtWithoutTimeChecking(jwt, jwks); |
314 | 2.39k | } |
315 | | |
316 | | Status verifyJwt(const Jwt& jwt, const Jwks& jwks, |
317 | 0 | const std::vector<std::string>& audiences) { |
318 | 0 | return verifyJwt(jwt, jwks, audiences, absl::ToUnixSeconds(absl::Now())); |
319 | 0 | } |
320 | | |
321 | | Status verifyJwt(const Jwt& jwt, const Jwks& jwks, |
322 | 0 | const std::vector<std::string>& audiences, uint64_t now) { |
323 | 0 | CheckAudience checker(audiences); |
324 | 0 | if (!checker.areAudiencesAllowed(jwt.audiences_)) { |
325 | 0 | return Status::JwtAudienceNotAllowed; |
326 | 0 | } |
327 | 0 | return verifyJwt(jwt, jwks, now); |
328 | 0 | } |
329 | | |
330 | | } // namespace jwt_verify |
331 | | } // namespace google |