/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 | 72.0k | inline const uint8_t* castToUChar(const absl::string_view& str) { |
36 | 72.0k | return reinterpret_cast<const uint8_t*>(str.data()); |
37 | 72.0k | } |
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.94k | size_t signed_data_len) { |
42 | 4.94k | if (key == nullptr || md == nullptr || signature == nullptr || |
43 | 4.94k | signed_data == nullptr) { |
44 | 0 | return false; |
45 | 0 | } |
46 | 4.94k | bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new()); |
47 | 4.94k | if (EVP_PKEY_set1_RSA(evp_pkey.get(), key) != 1) { |
48 | 0 | return false; |
49 | 0 | } |
50 | | |
51 | 4.94k | bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_create()); |
52 | 4.94k | if (EVP_DigestVerifyInit(md_ctx.get(), nullptr, md, nullptr, |
53 | 4.94k | evp_pkey.get()) == 1) { |
54 | 4.94k | if (EVP_DigestVerifyUpdate(md_ctx.get(), signed_data, signed_data_len) == |
55 | 4.94k | 1) { |
56 | 4.94k | if (EVP_DigestVerifyFinal(md_ctx.get(), signature, signature_len) == 1) { |
57 | 1 | return true; |
58 | 1 | } |
59 | 4.94k | } |
60 | 4.94k | } |
61 | 4.94k | ERR_clear_error(); |
62 | 4.94k | return false; |
63 | 4.94k | } |
64 | | |
65 | | bool verifySignatureRSA(RSA* key, const EVP_MD* md, absl::string_view signature, |
66 | 4.94k | absl::string_view signed_data) { |
67 | 4.94k | return verifySignatureRSA(key, md, castToUChar(signature), signature.length(), |
68 | 4.94k | castToUChar(signed_data), signed_data.length()); |
69 | 4.94k | } |
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 | 4.60k | size_t signed_data_len) { |
74 | 4.60k | if (key == nullptr || md == nullptr || signature == nullptr || |
75 | 4.60k | signed_data == nullptr) { |
76 | 0 | return false; |
77 | 0 | } |
78 | 4.60k | bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new()); |
79 | 4.60k | if (EVP_PKEY_set1_RSA(evp_pkey.get(), key) != 1) { |
80 | 0 | return false; |
81 | 0 | } |
82 | | |
83 | 4.60k | 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 | 4.60k | EVP_PKEY_CTX* pctx; |
86 | 4.60k | if (EVP_DigestVerifyInit(md_ctx.get(), &pctx, md, nullptr, evp_pkey.get()) == |
87 | 4.60k | 1 && |
88 | 4.60k | EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) == 1 && |
89 | 4.60k | EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, md) == 1 && |
90 | 4.60k | EVP_DigestVerify(md_ctx.get(), signature, signature_len, signed_data, |
91 | 4.60k | signed_data_len) == 1) { |
92 | 0 | return true; |
93 | 0 | } |
94 | | |
95 | 4.60k | ERR_clear_error(); |
96 | 4.60k | return false; |
97 | 4.60k | } |
98 | | |
99 | | bool verifySignatureRSAPSS(RSA* key, const EVP_MD* md, |
100 | | absl::string_view signature, |
101 | 4.60k | absl::string_view signed_data) { |
102 | 4.60k | return verifySignatureRSAPSS(key, md, castToUChar(signature), |
103 | 4.60k | signature.length(), castToUChar(signed_data), |
104 | 4.60k | signed_data.length()); |
105 | 4.60k | } |
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 | 8.21k | size_t signed_data_len) { |
110 | 8.21k | if (key == nullptr || md == nullptr || signature == nullptr || |
111 | 8.21k | signed_data == nullptr) { |
112 | 0 | return false; |
113 | 0 | } |
114 | 8.21k | bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_create()); |
115 | 8.21k | std::vector<uint8_t> digest(EVP_MAX_MD_SIZE); |
116 | 8.21k | unsigned int digest_len = 0; |
117 | | |
118 | 8.21k | if (EVP_DigestInit(md_ctx.get(), md) == 0) { |
119 | 0 | return false; |
120 | 0 | } |
121 | | |
122 | 8.21k | if (EVP_DigestUpdate(md_ctx.get(), signed_data, signed_data_len) == 0) { |
123 | 0 | return false; |
124 | 0 | } |
125 | | |
126 | 8.21k | if (EVP_DigestFinal(md_ctx.get(), digest.data(), &digest_len) == 0) { |
127 | 0 | return false; |
128 | 0 | } |
129 | | |
130 | 8.21k | bssl::UniquePtr<ECDSA_SIG> ecdsa_sig(ECDSA_SIG_new()); |
131 | 8.21k | if (!ecdsa_sig) { |
132 | 0 | return false; |
133 | 0 | } |
134 | | |
135 | 8.21k | if (BN_bin2bn(signature, signature_len / 2, ecdsa_sig->r) == nullptr || |
136 | 8.21k | BN_bin2bn(signature + (signature_len / 2), signature_len / 2, |
137 | 8.21k | ecdsa_sig->s) == nullptr) { |
138 | 0 | return false; |
139 | 0 | } |
140 | | |
141 | 8.21k | if (ECDSA_do_verify(digest.data(), digest_len, ecdsa_sig.get(), key) == 1) { |
142 | 3 | return true; |
143 | 3 | } |
144 | | |
145 | 8.20k | ERR_clear_error(); |
146 | 8.20k | return false; |
147 | 8.21k | } |
148 | | |
149 | | bool verifySignatureEC(EC_KEY* key, const EVP_MD* md, |
150 | | absl::string_view signature, |
151 | 8.21k | absl::string_view signed_data) { |
152 | 8.21k | return verifySignatureEC(key, md, castToUChar(signature), signature.length(), |
153 | 8.21k | castToUChar(signed_data), signed_data.length()); |
154 | 8.21k | } |
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 | 5.07k | const uint8_t* signed_data, size_t signed_data_len) { |
159 | 5.07k | if (key == nullptr || md == nullptr || signature == nullptr || |
160 | 5.07k | signed_data == nullptr) { |
161 | 0 | return false; |
162 | 0 | } |
163 | | |
164 | 5.07k | std::vector<uint8_t> out(EVP_MAX_MD_SIZE); |
165 | 5.07k | unsigned int out_len = 0; |
166 | 5.07k | if (HMAC(md, key, key_len, signed_data, signed_data_len, out.data(), |
167 | 5.07k | &out_len) == nullptr) { |
168 | 0 | ERR_clear_error(); |
169 | 0 | return false; |
170 | 0 | } |
171 | | |
172 | 5.07k | if (out_len != signature_len) { |
173 | 4.86k | return false; |
174 | 4.86k | } |
175 | | |
176 | 205 | if (CRYPTO_memcmp(out.data(), signature, signature_len) == 0) { |
177 | 1 | return true; |
178 | 1 | } |
179 | | |
180 | 204 | ERR_clear_error(); |
181 | 204 | return false; |
182 | 205 | } |
183 | | |
184 | | bool verifySignatureOct(absl::string_view key, const EVP_MD* md, |
185 | | absl::string_view signature, |
186 | 5.07k | absl::string_view signed_data) { |
187 | 5.07k | return verifySignatureOct(castToUChar(key), key.length(), md, |
188 | 5.07k | castToUChar(signature), signature.length(), |
189 | 5.07k | castToUChar(signed_data), signed_data.length()); |
190 | 5.07k | } |
191 | | |
192 | | Status verifySignatureEd25519(absl::string_view key, |
193 | | absl::string_view signature, |
194 | 7.12k | absl::string_view signed_data) { |
195 | 7.12k | if (signature.length() != ED25519_SIGNATURE_LEN) { |
196 | 13 | return Status::JwtEd25519SignatureWrongLength; |
197 | 13 | } |
198 | | |
199 | 7.10k | if (ED25519_verify(castToUChar(signed_data), signed_data.length(), |
200 | 7.10k | castToUChar(signature), castToUChar(key.data())) == 1) { |
201 | 1 | return Status::Ok; |
202 | 1 | } |
203 | | |
204 | 7.10k | ERR_clear_error(); |
205 | 7.10k | return Status::JwtVerificationFail; |
206 | 7.10k | } |
207 | | |
208 | | } // namespace |
209 | | |
210 | 1.73k | Status verifyJwtWithoutTimeChecking(const Jwt& jwt, const Jwks& jwks) { |
211 | | // Verify signature |
212 | 1.73k | std::string signed_data = |
213 | 1.73k | jwt.header_str_base64url_ + '.' + jwt.payload_str_base64url_; |
214 | 1.73k | bool kid_alg_matched = false; |
215 | 33.0k | 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 | 33.0k | if (!jwt.kid_.empty() && !jwk->kid_.empty() && jwk->kid_ != jwt.kid_) { |
220 | 1.64k | continue; |
221 | 1.64k | } |
222 | | |
223 | | // The same alg must be used. |
224 | 31.3k | if (!jwk->alg_.empty() && jwk->alg_ != jwt.alg_) { |
225 | 1.23k | continue; |
226 | 1.23k | } |
227 | 30.1k | kid_alg_matched = true; |
228 | | |
229 | 30.1k | if (jwk->kty_ == "EC") { |
230 | 8.21k | const EVP_MD* md; |
231 | 8.21k | if (jwt.alg_ == "ES384") { |
232 | 0 | md = EVP_sha384(); |
233 | 8.21k | } else if (jwt.alg_ == "ES512") { |
234 | 1.29k | md = EVP_sha512(); |
235 | 6.91k | } else { |
236 | | // default to SHA256 |
237 | 6.91k | md = EVP_sha256(); |
238 | 6.91k | } |
239 | | |
240 | 8.21k | if (verifySignatureEC(jwk->ec_key_.get(), md, jwt.signature_, |
241 | 8.21k | signed_data)) { |
242 | | // Verification succeeded. |
243 | 3 | return Status::Ok; |
244 | 3 | } |
245 | 21.9k | } else if (jwk->kty_ == "RSA") { |
246 | 9.74k | const EVP_MD* md; |
247 | 9.74k | if (jwt.alg_ == "RS384" || jwt.alg_ == "PS384") { |
248 | 0 | md = EVP_sha384(); |
249 | 9.74k | } else if (jwt.alg_ == "RS512" || jwt.alg_ == "PS512") { |
250 | 1.09k | md = EVP_sha512(); |
251 | 8.65k | } else { |
252 | | // default to SHA256 |
253 | 8.65k | md = EVP_sha256(); |
254 | 8.65k | } |
255 | | |
256 | 9.74k | if (jwt.alg_.compare(0, 2, "RS") == 0) { |
257 | 4.94k | if (verifySignatureRSA(jwk->rsa_.get(), md, jwt.signature_, |
258 | 4.94k | signed_data)) { |
259 | | // Verification succeeded. |
260 | 1 | return Status::Ok; |
261 | 1 | } |
262 | 4.94k | } else if (jwt.alg_.compare(0, 2, "PS") == 0) { |
263 | 4.60k | if (verifySignatureRSAPSS(jwk->rsa_.get(), md, jwt.signature_, |
264 | 4.60k | signed_data)) { |
265 | | // Verification succeeded. |
266 | 0 | return Status::Ok; |
267 | 0 | } |
268 | 4.60k | } |
269 | 12.1k | } else if (jwk->kty_ == "oct") { |
270 | 5.07k | const EVP_MD* md; |
271 | 5.07k | if (jwt.alg_ == "HS384") { |
272 | 0 | md = EVP_sha384(); |
273 | 5.07k | } else if (jwt.alg_ == "HS512") { |
274 | 1.45k | md = EVP_sha512(); |
275 | 3.61k | } else { |
276 | | // default to SHA256 |
277 | 3.61k | md = EVP_sha256(); |
278 | 3.61k | } |
279 | | |
280 | 5.07k | if (verifySignatureOct(jwk->hmac_key_, md, jwt.signature_, signed_data)) { |
281 | | // Verification succeeded. |
282 | 1 | return Status::Ok; |
283 | 1 | } |
284 | 7.12k | } else if (jwk->kty_ == "OKP" && jwk->crv_ == "Ed25519") { |
285 | 7.12k | Status status = verifySignatureEd25519(jwk->okp_key_raw_, jwt.signature_, |
286 | 7.12k | 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.12k | if (status == Status::Ok || |
291 | 7.12k | status == Status::JwtEd25519SignatureWrongLength) { |
292 | 14 | return status; |
293 | 14 | } |
294 | 7.12k | } |
295 | 30.1k | } |
296 | | |
297 | | // Verification failed. |
298 | 1.72k | return kid_alg_matched ? Status::JwtVerificationFail |
299 | 1.72k | : Status::JwksKidAlgMismatch; |
300 | 1.73k | } |
301 | | |
302 | 1.75k | Status verifyJwt(const Jwt& jwt, const Jwks& jwks) { |
303 | 1.75k | return verifyJwt(jwt, jwks, absl::ToUnixSeconds(absl::Now())); |
304 | 1.75k | } |
305 | | |
306 | | Status verifyJwt(const Jwt& jwt, const Jwks& jwks, uint64_t now, |
307 | 1.75k | uint64_t clock_skew) { |
308 | 1.75k | Status time_status = jwt.verifyTimeConstraint(now, clock_skew); |
309 | 1.75k | if (time_status != Status::Ok) { |
310 | 12 | return time_status; |
311 | 12 | } |
312 | | |
313 | 1.73k | return verifyJwtWithoutTimeChecking(jwt, jwks); |
314 | 1.75k | } |
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 |