Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(450)

Side by Side Diff: content/browser/experiments/api_key.cc

Issue 1522813002: Add public key and signature verification to browser-side API keys (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@keys
Patch Set: Add TODOs for future work Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/experiments/api_key.h" 5 #include "content/browser/experiments/api_key.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h" 11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h" 14 #include "base/time/time.h"
15 #include "crypto/signature_verifier.h"
16 #include "net/cert/pem_tokenizer.h"
17
18 namespace {
19
20 // This is the default public key used for validating signatures.
21 // TODO(iclelland): Move this to the embedder, and provide a mechanism to allow
22 // for multiple signing keys. https://crbug.com/543220
23 const char kPublicKeyPEM[] =
24 "-----BEGIN PUBLIC KEY-----"
25 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA38CwBHcz8YoCnPVwhH1p"
26 "jzmz/TKFu1ggI0+gzugBE+esApjm4I9N1PJ3/GLa+qpzp/VpgyzWqXiRoGM/RCZA"
27 "V5U+kDaoukxA33GdeA3BUrcYBIaspGRx6xXX36HLLPJF6YdjxbEByYprzecXhNUI"
28 "ql5VW3D0IR4frU5FzPy/XB5iblFxZAG4682IRRL5KdGL4OWFAPuzaKOMq7ojeKA9"
29 "y8Gu29huRknKALuScxqk+Jn5Qf3zWckLTpwyPoooXDQ116vs0b9ssalRSuBSRh4Q"
30 "tjzoQ6S1S5Zqw+2rvXfYhVZ65iiR1zzz6nBXIuUm9HAzIIF43LE6akG9E/F93ZYN"
31 "mwIDAQAB"
32 "-----END PUBLIC KEY-----";
davidben 2015/12/18 22:23:17 Here, use this: static const uint8_t kPublicKey[]
iclelland 2015/12/22 05:45:28 Thanks, done. I wanted something paste-able from a
33
34 /* By RFC 3447, the maximum salt length for RSAPSS is
35 * ceil((keySize-1)/8) - hashSize/8 - 2
36 */
davidben 2015/12/18 22:23:17 Nit: This can use // for comments
iclelland 2015/12/22 05:45:28 Done.
37 const size_t kSaltLength = ((2048 + 6) >> 3) - (256 >> 3) - 2;
davidben 2015/12/18 22:23:16 So, I'm not all that familiar with RSA-PSS, but I
iclelland 2015/12/22 05:45:28 I used the max length, and ensured that this was i
38
39 } // namespace
15 40
16 namespace content { 41 namespace content {
17 42
18 ApiKey::~ApiKey() {} 43 ApiKey::~ApiKey() {}
19 44
20 scoped_ptr<ApiKey> ApiKey::Parse(const std::string& keyText) { 45 scoped_ptr<ApiKey> ApiKey::Parse(const std::string& keyText) {
21 if (keyText.empty()) { 46 if (keyText.empty()) {
22 return nullptr; 47 return nullptr;
23 } 48 }
24 49
(...skipping 27 matching lines...) Expand all
52 const GURL& origin, 77 const GURL& origin,
53 const std::string& api_name, 78 const std::string& api_name,
54 uint64_t expiry_timestamp) 79 uint64_t expiry_timestamp)
55 : signature_(signature), 80 : signature_(signature),
56 data_(data), 81 data_(data),
57 origin_(origin), 82 origin_(origin),
58 api_name_(api_name), 83 api_name_(api_name),
59 expiry_timestamp_(expiry_timestamp) {} 84 expiry_timestamp_(expiry_timestamp) {}
60 85
61 bool ApiKey::IsValidNow(const base::Time& now) const { 86 bool ApiKey::IsValidNow(const base::Time& now) const {
87 return ValidateDate(now) && ValidateSignature(kPublicKeyPEM);
88 }
89
90 bool ApiKey::ValidateDate(const base::Time& now) const {
62 base::Time expiry_time = base::Time::FromDoubleT((double)expiry_timestamp_); 91 base::Time expiry_time = base::Time::FromDoubleT((double)expiry_timestamp_);
63 return expiry_time > now; 92 return expiry_time > now;
64 } 93 }
65 94
95 bool ApiKey::ValidateSignature(const char* publicKeyPEM) const {
davidben 2015/12/18 22:23:16 public_key_pem
iclelland 2015/12/22 05:45:28 Done.
96 return ValidateSignature(signature_, data_, publicKeyPEM);
97 }
98
99 // static
100 bool ApiKey::ValidateSignature(const std::string& signatureText,
101 const std::string& data,
102 const char* publicKeyPEM) {
103 std::string signature;
104 // signature is base64-encoded
105 if (!base::IsStringASCII(signatureText)) {
davidben 2015/12/18 22:23:16 Does base::Base64Decode not check this for you?
iclelland 2015/12/22 05:45:28 Yes. Yes I suppose it does, in a roundabout way (n
106 return false;
107 }
108 if (!base::Base64Decode(signatureText, &signature)) {
109 return false;
110 }
111
112 net::PEMTokenizer pem_tokenizer(publicKeyPEM, {"PUBLIC KEY"});
davidben 2015/12/18 22:23:17 I don't thiiink we get initializer lists yet? (Hop
iclelland 2015/12/22 05:45:28 Acknowledged. PEMTokenizer is gone.
113 if (!pem_tokenizer.GetNext()) {
114 NOTREACHED();
115 }
116 std::string publicKey = pem_tokenizer.data();
davidben 2015/12/18 22:23:16 public_key
iclelland 2015/12/22 05:45:28 Done.
117 std::string dataInUTF8 = data;
davidben 2015/12/18 22:23:17 data_in_utf8, but it looks like you can just data.
iclelland 2015/12/22 05:45:28 It's ported from my original attempt at this code,
118 crypto::SignatureVerifier sv;
davidben 2015/12/18 22:23:17 verifier
iclelland 2015/12/22 05:45:28 Done.
119 // TODO(iclelland): Switch to SubjectPublicKeyInfo to determine hash algorithm
120 // https://crbug.com/570684
davidben 2015/12/18 22:23:17 Commented on the bug, but this seems just fine. Al
iclelland 2015/12/22 05:45:28 Removed, thanks :)
121 sv.VerifyInitRSAPSS(
davidben 2015/12/18 22:23:17 Check for failure. Shouldn't happen, but still.
iclelland 2015/12/22 05:45:28 Done.
122 crypto::SignatureVerifier::SHA256, crypto::SignatureVerifier::SHA256,
123 kSaltLength, reinterpret_cast<const uint8*>(signature.data()),
davidben 2015/12/18 22:23:17 uint8_t for new code (I should go and fix //crypto
iclelland 2015/12/22 05:45:28 Done.
124 signature.length(), reinterpret_cast<const uint8*>(publicKey.data()),
125 publicKey.length());
126 sv.VerifyUpdate(reinterpret_cast<const uint8*>(dataInUTF8.data()),
127 dataInUTF8.length());
128 // TODO(iclelland): Support Key revocation through CRL
129 return sv.VerifyFinal();
130 }
131
66 } // namespace 132 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698