GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/** |
||
2 |
* This file is part of the CernVM File System |
||
3 |
*/ |
||
4 |
|||
5 |
#include "cvmfs_config.h" |
||
6 |
#include "macaroon.h" |
||
7 |
|||
8 |
#include <ctime> |
||
9 |
|||
10 |
#include "encrypt.h" |
||
11 |
#include "hash.h" |
||
12 |
#include "sanitizer.h" |
||
13 |
#include "util/pointer.h" |
||
14 |
#include "util/string.h" |
||
15 |
#include "uuid.h" |
||
16 |
|||
17 |
using namespace std; // NOLINT |
||
18 |
|||
19 |
28 |
Macaroon::Macaroon() |
|
20 |
: secret_key_storage_(NULL) |
||
21 |
, secret_key_publisher_(NULL) |
||
22 |
, expiry_utc_(0) |
||
23 |
, key_onetime_(NULL) |
||
24 |
, publish_operation_(kPublishNoop) |
||
25 |
28 |
, expiry_utc_operation_(0) |
|
26 |
{ |
||
27 |
28 |
hmac_primary_.algorithm = shash::kSha1; |
|
28 |
28 |
hmac_3rd_party_.algorithm = shash::kSha1; |
|
29 |
28 |
payload_hash_.algorithm = shash::kShake128; |
|
30 |
28 |
} |
|
31 |
|||
32 |
|||
33 |
/** |
||
34 |
* Used on the lease server where both keys are known. |
||
35 |
*/ |
||
36 |
28 |
Macaroon::Macaroon( |
|
37 |
const string &key_id_storage, |
||
38 |
const cipher::Key *secret_key_storage, |
||
39 |
const string &key_id_publisher, |
||
40 |
const cipher::Key *secret_key_publisher) |
||
41 |
: random_nonce_(cvmfs::Uuid::CreateOneTime()) |
||
42 |
, key_id_storage_(key_id_storage) |
||
43 |
, key_id_publisher_(key_id_publisher) |
||
44 |
, secret_key_storage_(secret_key_storage) |
||
45 |
, secret_key_publisher_(secret_key_publisher) |
||
46 |
, expiry_utc_(0) |
||
47 |
, key_onetime_(NULL) |
||
48 |
, publish_operation_(kPublishNoop) |
||
49 |
28 |
, expiry_utc_operation_(0) |
|
50 |
{ |
||
51 |
28 |
hmac_primary_.algorithm = shash::kSha1; |
|
52 |
|||
53 |
UniquePtr<cipher::Cipher> cipher_aes( |
||
54 |
28 |
cipher::Cipher::Create(cipher::kAes256Cbc)); |
|
55 |
✗✓ | 28 |
assert(cipher_aes.IsValid()); |
56 |
28 |
key_onetime_ = cipher::Key::CreateRandomly(cipher_aes->key_size()); |
|
57 |
✗✓ | 28 |
assert(key_onetime_ != NULL); |
58 |
|||
59 |
28 |
string cipher_text; |
|
60 |
bool retval = cipher_aes->Encrypt( |
||
61 |
28 |
key_onetime_->ToBase64(), *secret_key_storage_, &cipher_text); |
|
62 |
✗✓ | 28 |
assert(retval); |
63 |
28 |
key_onetime4storage_ = Base64(cipher_text); |
|
64 |
retval = cipher_aes->Encrypt( |
||
65 |
28 |
key_onetime_->ToBase64(), *secret_key_publisher_, &cipher_text); |
|
66 |
✗✓ | 28 |
assert(retval); |
67 |
28 |
key_onetime4publisher_ = Base64(cipher_text); |
|
68 |
} |
||
69 |
|||
70 |
|||
71 |
56 |
Macaroon::~Macaroon() { |
|
72 |
✓✗ | 56 |
delete key_onetime_; |
73 |
} |
||
74 |
|||
75 |
|||
76 |
/** |
||
77 |
* Creates the HMAC chain for the 3rd party caveats of the macaroon. Uses the |
||
78 |
* one time key as a starting point of the HMAC chain. |
||
79 |
*/ |
||
80 |
28 |
void Macaroon::Compute3rdPartyHmac() { |
|
81 |
✗✓ | 28 |
assert(key_onetime_ != NULL); |
82 |
|||
83 |
// Start with a base64 version of the secret key and the random nonce of the |
||
84 |
// primary macaroon, thereby binding the two together |
||
85 |
28 |
HmacString(key_onetime_->ToBase64(), random_nonce_, &hmac_3rd_party_); |
|
86 |
|||
87 |
// Always the latest hmac_3rd_party_.ToString() |
||
88 |
28 |
string key_walker; |
|
89 |
|||
90 |
28 |
key_walker = hmac_3rd_party_.ToString(); |
|
91 |
28 |
int operation = publish_operation_; |
|
92 |
28 |
HmacString(key_walker, StringifyInt(operation), &hmac_3rd_party_); |
|
93 |
|||
94 |
28 |
key_walker = hmac_3rd_party_.ToString(); |
|
95 |
28 |
HmacString(key_walker, StringifyInt(expiry_utc_operation_), &hmac_3rd_party_); |
|
96 |
|||
97 |
✗✓ | 28 |
if (!payload_hash_.IsNull()) { |
98 |
key_walker = hmac_3rd_party_.ToString(); |
||
99 |
HmacString(key_walker, payload_hash_.ToString(), &hmac_3rd_party_); |
||
100 |
} |
||
101 |
|||
102 |
// Seal the HMAC |
||
103 |
28 |
key_walker = hmac_3rd_party_.ToString(); |
|
104 |
28 |
HashString(key_walker, &hmac_3rd_party_); |
|
105 |
28 |
} |
|
106 |
|||
107 |
|||
108 |
/** |
||
109 |
* Creates the HMAC chain for the macaroon. Computation from scratch can only |
||
110 |
* be done by the origin service and the taget service because only they possess |
||
111 |
* the secret key that starts the chain. |
||
112 |
*/ |
||
113 |
56 |
void Macaroon::ComputePrimaryHmac() { |
|
114 |
✗✓ | 56 |
assert(secret_key_storage_ != NULL); |
115 |
|||
116 |
// Start with a base64 version of the secret key and the random nonce |
||
117 |
56 |
HmacString(secret_key_storage_->ToBase64(), random_nonce_, &hmac_primary_); |
|
118 |
|||
119 |
// Always the latest hmac_.ToString() |
||
120 |
56 |
string key_walker; |
|
121 |
|||
122 |
56 |
key_walker = hmac_primary_.ToString(); |
|
123 |
56 |
HmacString(key_walker, key_id_storage_, &hmac_primary_); |
|
124 |
|||
125 |
56 |
key_walker = hmac_primary_.ToString(); |
|
126 |
56 |
HmacString(key_walker, key_id_publisher_, &hmac_primary_); |
|
127 |
|||
128 |
56 |
key_walker = hmac_primary_.ToString(); |
|
129 |
56 |
HmacString(key_walker, origin_, &hmac_primary_); |
|
130 |
|||
131 |
56 |
key_walker = hmac_primary_.ToString(); |
|
132 |
56 |
HmacString(key_walker, target_hint_, &hmac_primary_); |
|
133 |
|||
134 |
56 |
key_walker = hmac_primary_.ToString(); |
|
135 |
56 |
HmacString(key_walker, StringifyInt(expiry_utc_), &hmac_primary_); |
|
136 |
|||
137 |
56 |
key_walker = hmac_primary_.ToString(); |
|
138 |
56 |
HmacString(key_walker, fqrn_, &hmac_primary_); |
|
139 |
|||
140 |
56 |
key_walker = hmac_primary_.ToString(); |
|
141 |
56 |
HmacString(key_walker, root_path_, &hmac_primary_); |
|
142 |
|||
143 |
56 |
key_walker = hmac_primary_.ToString(); |
|
144 |
56 |
HmacString(key_walker, publisher_hint_, &hmac_primary_); |
|
145 |
|||
146 |
56 |
key_walker = hmac_primary_.ToString(); |
|
147 |
56 |
HmacString(key_walker, key_onetime4storage_, &hmac_primary_); |
|
148 |
|||
149 |
56 |
key_walker = hmac_primary_.ToString(); |
|
150 |
56 |
HmacString(key_walker, key_onetime4publisher_, &hmac_primary_); |
|
151 |
|||
152 |
// Seal the HMAC |
||
153 |
56 |
key_walker = hmac_primary_.ToString(); |
|
154 |
56 |
HashString(key_walker, &hmac_primary_); |
|
155 |
56 |
} |
|
156 |
|||
157 |
|||
158 |
14 |
bool Macaroon::Create3rdPartyFromJson(JSON *json) { |
|
159 |
14 |
JSON *walker = json; |
|
160 |
✓✗✓✓ |
14 |
while (walker != NULL) { |
161 |
✗✓ | 42 |
if (walker->name == NULL) |
162 |
return false; |
||
163 |
42 |
string name = walker->name; |
|
164 |
42 |
json_type type = walker->type; |
|
165 |
|||
166 |
// Known field types |
||
167 |
✓✓ | 42 |
if (name == "publish_operation") { |
168 |
✗✓ | 14 |
if (type != JSON_INT) return false; |
169 |
✗✓ | 14 |
if (walker->int_value < kPublishTransaction) return false; |
170 |
✗✓ | 14 |
if (walker->int_value > kPublishCommit) return false; |
171 |
14 |
publish_operation_ = PublishOperation(walker->int_value); |
|
172 |
✓✓ | 28 |
} else if (name == "expiry_utc_operation") { |
173 |
✗✓ | 14 |
if (type != JSON_INT) return false; |
174 |
✗✓ | 14 |
if (walker->int_value < 0) return false; |
175 |
14 |
expiry_utc_operation_ = walker->int_value; |
|
176 |
✗✓ | 14 |
} else if (name == "payload_hash") { |
177 |
if (type != JSON_STRING) return false; |
||
178 |
if (walker->string_value == NULL) return false; |
||
179 |
payload_hash_ = |
||
180 |
shash::MkFromHexPtr(shash::HexPtr(string(walker->string_value))); |
||
181 |
✓✗ | 14 |
} else if (name == "hmac") { |
182 |
✗✓ | 14 |
if (type != JSON_STRING) return false; |
183 |
✗✓ | 14 |
if (walker->string_value == NULL) return false; |
184 |
hmac_3rd_party_ = |
||
185 |
✗✓ | 14 |
shash::MkFromHexPtr(shash::HexPtr(string(walker->string_value))); |
186 |
} |
||
187 |
|||
188 |
42 |
walker = walker->next_sibling; |
|
189 |
} |
||
190 |
14 |
return true; |
|
191 |
} |
||
192 |
|||
193 |
|||
194 |
28 |
bool Macaroon::CreateFromJson(JSON *json) { |
|
195 |
// Search "cvmfs_macaroon_v1 sub structure" |
||
196 |
28 |
JSON *walker = json; |
|
197 |
✓✗ | 56 |
while (walker) { |
198 |
✓✗✓✗ ✓✗✗✗ ✗✗✓✗ ✓✗ |
28 |
if ((string(walker->name) == "cvmfs_macaroon_v1") && |
199 |
(walker->type == JSON_OBJECT)) |
||
200 |
{ |
||
201 |
28 |
walker = walker->first_child; |
|
202 |
28 |
break; |
|
203 |
} |
||
204 |
walker = walker->next_sibling; |
||
205 |
} |
||
206 |
✗✓ | 28 |
if (walker == NULL) |
207 |
return false; |
||
208 |
|||
209 |
// We are now in the cvmfs_macaroon_v1 sub structure |
||
210 |
28 |
sanitizer::UuidSanitizer uuid_sanitizer; |
|
211 |
28 |
sanitizer::UriSanitizer uri_sanitizer; |
|
212 |
28 |
sanitizer::RepositorySanitizer repo_sanitizer; |
|
213 |
28 |
sanitizer::Base64Sanitizer base64_sanitizer; |
|
214 |
✓✓ | 350 |
do { |
215 |
✗✓ | 350 |
if (walker->name == NULL) |
216 |
return false; |
||
217 |
350 |
string name = walker->name; |
|
218 |
350 |
json_type type = walker->type; |
|
219 |
|||
220 |
// Known field types |
||
221 |
✓✓ | 350 |
if (name == "random_nonce") { |
222 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
223 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
224 |
✓✗ | 28 |
if (!uuid_sanitizer.IsValid(walker->string_value)) return false; |
225 |
28 |
random_nonce_ = walker->string_value; |
|
226 |
✓✓ | 322 |
} else if (name == "key_id_storage") { |
227 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
228 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
229 |
✓✗ | 28 |
if (!uri_sanitizer.IsValid(walker->string_value)) return false; |
230 |
28 |
key_id_storage_ = walker->string_value; |
|
231 |
✗✓ | 294 |
} else if (name == "key_id_storage") { |
232 |
if (type != JSON_STRING) return false; |
||
233 |
if (walker->string_value == NULL) return false; |
||
234 |
if (!uri_sanitizer.IsValid(walker->string_value)) return false; |
||
235 |
key_id_storage_ = walker->string_value; |
||
236 |
✓✓ | 294 |
} else if (name == "key_id_publisher") { |
237 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
238 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
239 |
✓✗ | 28 |
if (!uri_sanitizer.IsValid(walker->string_value)) return false; |
240 |
28 |
key_id_publisher_ = walker->string_value; |
|
241 |
✓✓ | 266 |
} else if (name == "origin") { |
242 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
243 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
244 |
✓✗ | 28 |
if (!uri_sanitizer.IsValid(walker->string_value)) return false; |
245 |
28 |
origin_ = walker->string_value; |
|
246 |
✓✓ | 238 |
} else if (name == "target_hint") { |
247 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
248 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
249 |
✓✗ | 28 |
if (!uri_sanitizer.IsValid(walker->string_value)) return false; |
250 |
28 |
target_hint_ = walker->string_value; |
|
251 |
✓✓ | 210 |
} else if (name == "expiry_utc") { |
252 |
✗✓ | 28 |
if (type != JSON_INT) return false; |
253 |
✗✓ | 28 |
if (walker->int_value < 0) return false; |
254 |
28 |
expiry_utc_ = walker->int_value; |
|
255 |
✓✓ | 182 |
} else if (name == "fqrn") { |
256 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
257 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
258 |
✓✗ | 28 |
if (!repo_sanitizer.IsValid(walker->string_value)) return false; |
259 |
28 |
fqrn_ = walker->string_value; |
|
260 |
✓✓ | 154 |
} else if (name == "root_path") { |
261 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
262 |
✗✓ | 28 |
if (walker->name == NULL) return false; |
263 |
28 |
root_path_ = walker->string_value; |
|
264 |
✓✓ | 126 |
} else if (name == "publisher_hint") { |
265 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
266 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
267 |
✓✗ | 28 |
if (!uri_sanitizer.IsValid(walker->string_value)) return false; |
268 |
28 |
publisher_hint_ = walker->string_value; |
|
269 |
✓✓ | 98 |
} else if (name == "vid") { |
270 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
271 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
272 |
✓✗ | 28 |
if (!base64_sanitizer.IsValid(walker->string_value)) return false; |
273 |
28 |
key_onetime4storage_ = walker->string_value; |
|
274 |
✓✓ | 70 |
} else if (name == "cid") { |
275 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
276 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
277 |
✓✗ | 28 |
if (!base64_sanitizer.IsValid(walker->string_value)) return false; |
278 |
28 |
key_onetime4publisher_ = walker->string_value; |
|
279 |
✓✓ | 42 |
} else if (name == "hmac") { |
280 |
✗✓ | 28 |
if (type != JSON_STRING) return false; |
281 |
✗✓ | 28 |
if (walker->string_value == NULL) return false; |
282 |
hmac_primary_ = |
||
283 |
✗✓ | 28 |
shash::MkFromHexPtr(shash::HexPtr(string(walker->string_value))); |
284 |
✓✗✓✗ ✓✗ |
14 |
} else if ((name == "publisher_caveats") && (type == JSON_OBJECT)) { |
285 |
14 |
walker = walker->first_child; |
|
286 |
✗✓ | 14 |
if (!Create3rdPartyFromJson(walker)) return false; |
287 |
14 |
walker = walker->parent; |
|
288 |
} |
||
289 |
|||
290 |
✓✗ | 350 |
walker = walker->next_sibling; |
291 |
} while (walker); |
||
292 |
|||
293 |
28 |
return true; |
|
294 |
} |
||
295 |
|||
296 |
|||
297 |
/** |
||
298 |
* Used on the release manager machine. The primary macaroon is taken as is, |
||
299 |
* only the 3rd party caveats are added. |
||
300 |
*/ |
||
301 |
14 |
std::string Macaroon::ExportAttenuated() { |
|
302 |
14 |
Compute3rdPartyHmac(); |
|
303 |
string json_text = string("{\"cvmfs_macaroon_v1\":{") + |
||
304 |
ExportPrimaryFields() + |
||
305 |
",\"hmac\":\"" + hmac_primary_.ToString() + "\"" + |
||
306 |
"\"publisher_caveats\":{" + |
||
307 |
Export3rdPartyFields() + |
||
308 |
",\"hmac\":\"" + hmac_3rd_party_.ToString() + "\"" + |
||
309 |
14 |
"}}}"; |
|
310 |
|||
311 |
14 |
UniquePtr<JsonDocument> json_document(JsonDocument::Create(json_text)); |
|
312 |
✗✓ | 14 |
assert(json_document.IsValid()); |
313 |
14 |
return json_document->PrintCanonical(); |
|
314 |
} |
||
315 |
|||
316 |
|||
317 |
/** |
||
318 |
* The order of the JSON fields matters because the HMAC is constructed |
||
319 |
* field-by-field. Requires knowledge of the secret storage key. Used by the |
||
320 |
* lease server. |
||
321 |
*/ |
||
322 |
42 |
string Macaroon::ExportPrimary() { |
|
323 |
42 |
ComputePrimaryHmac(); |
|
324 |
string json_text = string("{\"cvmfs_macaroon_v1\":{") + |
||
325 |
ExportPrimaryFields() + |
||
326 |
",\"hmac\":\"" + hmac_primary_.ToString() + "\"" + |
||
327 |
42 |
"}}"; |
|
328 |
42 |
UniquePtr<JsonDocument> json_document(JsonDocument::Create(json_text)); |
|
329 |
✗✓ | 42 |
assert(json_document.IsValid()); |
330 |
42 |
return json_document->PrintCanonical(); |
|
331 |
} |
||
332 |
|||
333 |
|||
334 |
/** |
||
335 |
* Export the inner guts of the 3rd party caveats without hmac. |
||
336 |
*/ |
||
337 |
14 |
std::string Macaroon::Export3rdPartyFields() { |
|
338 |
return "\"publish_operation\":" + StringifyInt(publish_operation_) + |
||
339 |
",\"expiry_utc_operation\":" + StringifyInt(expiry_utc_operation_) + |
||
340 |
(payload_hash_.IsNull() |
||
341 |
? "" |
||
342 |
✓✗✗✓ ✗✗✗✓ ✗✗✗✗ ✗✓ |
14 |
: ("\"payload_hash\":\"" + payload_hash_.ToString() + "\"")); |
343 |
} |
||
344 |
|||
345 |
|||
346 |
|||
347 |
/** |
||
348 |
* Export the inner guts of the primary macaroon without hmac. |
||
349 |
*/ |
||
350 |
56 |
std::string Macaroon::ExportPrimaryFields() { |
|
351 |
return "\"random_nonce\":\"" + random_nonce_ + "\"" + |
||
352 |
"\"key_id_storage\":\"" + key_id_storage_ + "\"" + |
||
353 |
"\"key_id_publisher\":\"" + key_id_publisher_ + "\"" + |
||
354 |
",\"origin\":\"" + origin_ + "\"" + |
||
355 |
",\"target_hint\":\"" + target_hint_ + "\"" + |
||
356 |
",\"expiry_utc\":" + StringifyInt(expiry_utc_) + |
||
357 |
",\"fqrn\":\"" + fqrn_ + "\"" + |
||
358 |
",\"root_path\":\"" + root_path_ + "\"" + |
||
359 |
",\"publisher_hint\":\"" + publisher_hint_ + "\"" + |
||
360 |
",\"vid\":\"" + key_onetime4storage_ + "\"" + |
||
361 |
56 |
",\"cid\":\"" + key_onetime4publisher_ + "\""; |
|
362 |
} |
||
363 |
|||
364 |
|||
365 |
/** |
||
366 |
* The secret_key is either the publisher's one or the storage's one, depending |
||
367 |
* on where the method is called. |
||
368 |
*/ |
||
369 |
28 |
Macaroon::VerifyFailures Macaroon::ExtractOnetimeKey( |
|
370 |
const string &key_onetime4me, |
||
371 |
const cipher::Key &my_secret_key) |
||
372 |
{ |
||
373 |
28 |
string ciphertext; |
|
374 |
28 |
string plaintext; |
|
375 |
28 |
string key_raw; |
|
376 |
28 |
bool retval = Debase64(key_onetime4me, &ciphertext); |
|
377 |
✗✓ | 28 |
if (!retval) { |
378 |
return kFailBadMacaroon; |
||
379 |
} |
||
380 |
retval = cipher::Cipher::Decrypt( |
||
381 |
28 |
ciphertext, my_secret_key, &plaintext); |
|
382 |
✓✗✗✓ ✗✓ |
28 |
if (!retval || (plaintext == "")) { |
383 |
return kFailDecrypt; |
||
384 |
} |
||
385 |
28 |
retval = Debase64(plaintext, &key_raw); |
|
386 |
✓✗✗✓ ✗✓ |
28 |
if (!retval || (key_raw.size() != cipher::CipherAes256Cbc::kKeySize)) { |
387 |
return kFailDecrypt; |
||
388 |
} |
||
389 |
28 |
key_onetime_ = cipher::Key::CreateFromString(key_raw); |
|
390 |
✗✓ | 28 |
assert(key_onetime_); |
391 |
28 |
return kFailOk; |
|
392 |
} |
||
393 |
|||
394 |
|||
395 |
/** |
||
396 |
* Creates a macaroon based on the JSON object that the lease server produced. |
||
397 |
*/ |
||
398 |
14 |
Macaroon *Macaroon::ParseOnPublisher( |
|
399 |
const string &json, |
||
400 |
cipher::AbstractKeyDatabase *key_db, |
||
401 |
VerifyFailures *failure_code) |
||
402 |
{ |
||
403 |
✗✓ | 14 |
assert(key_db != NULL); |
404 |
✗✓ | 14 |
assert(failure_code != NULL); |
405 |
14 |
*failure_code = kFailUnknown; |
|
406 |
|||
407 |
14 |
UniquePtr<JsonDocument> json_document(JsonDocument::Create(json)); |
|
408 |
✗✓ | 14 |
if (!json_document.IsValid()) { |
409 |
*failure_code = kFailBadJson; |
||
410 |
return NULL; |
||
411 |
} |
||
412 |
|||
413 |
14 |
UniquePtr<Macaroon> macaroon(new Macaroon()); |
|
414 |
14 |
bool retval = macaroon->CreateFromJson(json_document->root()->first_child); |
|
415 |
✗✓ | 14 |
if (!retval) { |
416 |
*failure_code = kFailBadMacaroon; |
||
417 |
return NULL; |
||
418 |
} |
||
419 |
✗✓ | 14 |
if (macaroon->expiry_utc_ < time(NULL)) { |
420 |
*failure_code = kFailExpired; |
||
421 |
return NULL; |
||
422 |
} |
||
423 |
|||
424 |
// Extract the random root key for 3rd party caveats |
||
425 |
14 |
macaroon->secret_key_publisher_ = key_db->Find(macaroon->key_id_publisher_); |
|
426 |
✗✓ | 14 |
if (macaroon->secret_key_publisher_ == NULL) { |
427 |
*failure_code = kFailUnknownKey; |
||
428 |
return NULL; |
||
429 |
} |
||
430 |
*failure_code = macaroon->ExtractOnetimeKey(macaroon->key_onetime4publisher_, |
||
431 |
14 |
*macaroon->secret_key_publisher_); |
|
432 |
✗✓ | 14 |
if (*failure_code != kFailOk) |
433 |
return NULL; |
||
434 |
14 |
return macaroon.Release(); |
|
435 |
} |
||
436 |
|||
437 |
|||
438 |
/** |
||
439 |
* Creates a macaroon based on the JSON object that the lease server produced |
||
440 |
* and the release manager machine attenuated. |
||
441 |
*/ |
||
442 |
14 |
Macaroon *Macaroon::ParseOnStorage( |
|
443 |
const string &json, |
||
444 |
cipher::AbstractKeyDatabase *key_db, |
||
445 |
VerifyFailures *failure_code) |
||
446 |
{ |
||
447 |
✗✓ | 14 |
assert(key_db != NULL); |
448 |
✗✓ | 14 |
assert(failure_code != NULL); |
449 |
14 |
*failure_code = kFailUnknown; |
|
450 |
|||
451 |
14 |
UniquePtr<JsonDocument> json_document(JsonDocument::Create(json)); |
|
452 |
✗✓ | 14 |
if (!json_document.IsValid()) { |
453 |
*failure_code = kFailBadJson; |
||
454 |
return NULL; |
||
455 |
} |
||
456 |
|||
457 |
14 |
UniquePtr<Macaroon> macaroon(new Macaroon()); |
|
458 |
bool retval = |
||
459 |
14 |
macaroon->CreateFromJson(json_document->root()->first_child); |
|
460 |
✗✓ | 14 |
if (!retval) { |
461 |
*failure_code = kFailBadMacaroon; |
||
462 |
return NULL; |
||
463 |
} |
||
464 |
14 |
time_t now = time(NULL); |
|
465 |
✓✗✗✓ ✗✓ |
14 |
if ((macaroon->expiry_utc_ < now) || (macaroon->expiry_utc_operation_ < now)) |
466 |
{ |
||
467 |
*failure_code = kFailExpired; |
||
468 |
return NULL; |
||
469 |
} |
||
470 |
|||
471 |
// Extract the random root key for 3rd party caveats |
||
472 |
14 |
macaroon->secret_key_storage_ = key_db->Find(macaroon->key_id_storage_); |
|
473 |
✗✓ | 14 |
if (macaroon->secret_key_storage_ == NULL) { |
474 |
*failure_code = kFailUnknownKey; |
||
475 |
return NULL; |
||
476 |
} |
||
477 |
*failure_code = macaroon->ExtractOnetimeKey(macaroon->key_onetime4storage_, |
||
478 |
14 |
*macaroon->secret_key_storage_); |
|
479 |
✗✓ | 14 |
if (*failure_code != kFailOk) |
480 |
return NULL; |
||
481 |
|||
482 |
14 |
shash::Any retrieved_primary_hmac(macaroon->hmac_primary_); |
|
483 |
14 |
macaroon->ComputePrimaryHmac(); |
|
484 |
✗✓ | 14 |
if (retrieved_primary_hmac != macaroon->hmac_primary_) { |
485 |
*failure_code = kFailBadPrimarySignature; |
||
486 |
return NULL; |
||
487 |
} |
||
488 |
|||
489 |
14 |
shash::Any retrieved_3rdparty_hmac(macaroon->hmac_3rd_party_); |
|
490 |
14 |
macaroon->Compute3rdPartyHmac(); |
|
491 |
✗✓ | 14 |
if (retrieved_3rdparty_hmac != macaroon->hmac_3rd_party_) { |
492 |
*failure_code = kFailBad3rdPartySignature; |
||
493 |
return NULL; |
||
494 |
} |
||
495 |
|||
496 |
14 |
return macaroon.Release(); |
|
497 |
} |
Generated by: GCOVR (Version 4.1) |