1 |
|
|
/** |
2 |
|
|
* This file is part of the CernVM File System |
3 |
|
|
*/ |
4 |
|
|
|
5 |
|
|
#ifndef CVMFS_WEBAPI_MACAROON_H_ |
6 |
|
|
#define CVMFS_WEBAPI_MACAROON_H_ |
7 |
|
|
|
8 |
|
|
#include <ctime> |
9 |
|
|
#include <string> |
10 |
|
|
|
11 |
|
|
#include "hash.h" |
12 |
|
|
#include "json_document.h" |
13 |
|
|
#include "util/single_copy.h" |
14 |
|
|
|
15 |
|
|
namespace cipher { |
16 |
|
|
class AbstractKeyDatabase; |
17 |
|
|
class Key; |
18 |
|
|
} |
19 |
|
|
|
20 |
|
|
|
21 |
|
|
/** |
22 |
|
|
* An implementation of Macaroons: http://research.google.com/pubs/pub41892.html |
23 |
|
|
* Macaroons are tamper-proof authorization tokens with attenuations and |
24 |
|
|
* third-party caveats. |
25 |
|
|
* |
26 |
|
|
* Macaroons are issued by the octopus lease server in form of a lease. The |
27 |
|
|
* lease server shares separate keys with each of the release manager machines |
28 |
|
|
* and with the storage relay. Leases are targeted for the storage relay. The |
29 |
|
|
* release manager machine is seen as a third party that signs off the hash of |
30 |
|
|
* the change packs. |
31 |
|
|
* |
32 |
|
|
* The following caveats are supported for the octopus server: |
33 |
|
|
* - expiry time |
34 |
|
|
* - fully qualified repository name |
35 |
|
|
* - cvmfs sub tree |
36 |
|
|
* - Required 3rd party (release manager magine) caveat: hash of change pack, |
37 |
|
|
* request type (transaction start, new data packet, commit). |
38 |
|
|
* |
39 |
|
|
* Note that the in-memory representation does not fully mirror the JSON |
40 |
|
|
* representation. The availability of the cryptographic keys depends on the |
41 |
|
|
* lifecycle of the macaroon. As for the lifecyclt, a macaroon is |
42 |
|
|
* -# created at the lease server ("ExportPrimary") that has access to both |
43 |
|
|
* the shared secret key of the storage gateway and the shared secret key |
44 |
|
|
* of the release manager machine; |
45 |
|
|
* -# parsed on the release manager machine (publisher) that decrypts the |
46 |
|
|
* "cld" field containing the random key used for 3rd-party caveats; |
47 |
|
|
* -# attenuated on the release manager machin by 3rd-party caveats (begin |
48 |
|
|
* transaction, change set hash, another change set hash, ..., publish |
49 |
|
|
* transaction); multiple macaroons with different 3rd-party caveats are |
50 |
|
|
* created here ("ExportDerived"); |
51 |
|
|
* -# parsed and verified on the storage relay using the private key from step |
52 |
|
|
* 1 and the "vld" field with the encrypted random key used for 3rd-party |
53 |
|
|
* caveats. |
54 |
|
|
*/ |
55 |
|
|
class Macaroon : SingleCopy { |
56 |
|
|
public: |
57 |
|
|
enum VerifyFailures { |
58 |
|
|
kFailOk = 0, |
59 |
|
|
kFailBadJson, |
60 |
|
|
kFailBadMacaroon, |
61 |
|
|
kFailBadPrimarySignature, |
62 |
|
|
kFailBad3rdPartySignature, |
63 |
|
|
kFailUnknownKey, |
64 |
|
|
kFailDecrypt, |
65 |
|
|
kFailExpired, |
66 |
|
|
kFailBadRootPath, |
67 |
|
|
kFailReplay, |
68 |
|
|
kFailUnknown, |
69 |
|
|
}; |
70 |
|
|
|
71 |
|
|
enum PublishOperation { |
72 |
|
|
kPublishNoop = 0, |
73 |
|
|
kPublishTransaction, |
74 |
|
|
kPublishChangePack, |
75 |
|
|
kPublishCommit, |
76 |
|
|
}; |
77 |
|
|
|
78 |
|
|
Macaroon(const std::string &key_id_storage, |
79 |
|
|
const cipher::Key *secret_key_storage, |
80 |
|
|
const std::string &key_id_publisher, |
81 |
|
|
const cipher::Key *secret_key_publisher); |
82 |
|
|
static Macaroon *ParseOnPublisher(const std::string &json, |
83 |
|
|
cipher::AbstractKeyDatabase *key_db, |
84 |
|
|
VerifyFailures *failure_code); |
85 |
|
|
static Macaroon *ParseOnStorage(const std::string &json, |
86 |
|
|
cipher::AbstractKeyDatabase *key_db, |
87 |
|
|
VerifyFailures *failure_code); |
88 |
|
|
~Macaroon(); |
89 |
|
|
|
90 |
|
14 |
void set_ttl(const unsigned ttl_s) { |
91 |
|
14 |
expiry_utc_ = time(NULL) + ttl_s; |
92 |
|
14 |
} |
93 |
|
|
void set_root_path(const std::string &root_path) { root_path_ = root_path; } |
94 |
|
|
void set_fqrn(const std::string &fqrn) { fqrn_ = fqrn; } |
95 |
|
|
void set_origin(const std::string &origin) { origin_ = origin; } |
96 |
|
|
void set_target(const std::string &target) { target_hint_ = target; } |
97 |
|
|
void set_publisher_hint(const std::string &hint) { publisher_hint_ = hint; } |
98 |
|
|
|
99 |
|
|
void set_payload_hash(const shash::Any &hash) { payload_hash_ = hash; } |
100 |
|
14 |
void set_publish_operation(PublishOperation op) { publish_operation_ = op; } |
101 |
|
14 |
void set_ttl_operation(const unsigned ttl_s) { |
102 |
|
14 |
expiry_utc_operation_ = time(NULL) + ttl_s; |
103 |
|
14 |
} |
104 |
|
|
|
105 |
|
|
std::string ExportPrimary(); |
106 |
|
|
std::string ExportAttenuated(); |
107 |
|
|
|
108 |
|
|
private: |
109 |
|
|
Macaroon(); |
110 |
|
|
void ComputePrimaryHmac(); |
111 |
|
|
void Compute3rdPartyHmac(); |
112 |
|
|
std::string ExportPrimaryFields(); |
113 |
|
|
std::string Export3rdPartyFields(); |
114 |
|
|
bool CreateFromJson(JSON *json); |
115 |
|
|
bool Create3rdPartyFromJson(JSON *json); |
116 |
|
|
VerifyFailures ExtractOnetimeKey(const std::string &key_onetime4me, |
117 |
|
|
const cipher::Key &my_secret_key); |
118 |
|
|
|
119 |
|
|
/** |
120 |
|
|
* The unique identifier of the macaroon. Serves also as transaction id: this |
121 |
|
|
* macaroon can only be used for a single transaction - change set - publish |
122 |
|
|
* cycle. |
123 |
|
|
*/ |
124 |
|
|
std::string random_nonce_; |
125 |
|
|
|
126 |
|
|
/** |
127 |
|
|
* The signing key used for the initial HMAC. This is a key shared by the |
128 |
|
|
* lease service and the storage gateway (target service). |
129 |
|
|
*/ |
130 |
|
|
std::string key_id_storage_; |
131 |
|
|
|
132 |
|
|
/** |
133 |
|
|
* The key shared between the lease server and the release manager machine. |
134 |
|
|
* Used by the release manager machine to sign the 3rd party caveats. |
135 |
|
|
*/ |
136 |
|
|
std::string key_id_publisher_; |
137 |
|
|
|
138 |
|
|
/** |
139 |
|
|
* The key shared with the target service (storage relay). Should match the |
140 |
|
|
* key_id_storage_. NULL if created from JSON document. |
141 |
|
|
*/ |
142 |
|
|
const cipher::Key *secret_key_storage_; |
143 |
|
|
|
144 |
|
|
/** |
145 |
|
|
* The key shared with the release manager machine. Should match the |
146 |
|
|
* key_id_publisher_. NULL if created from JSON document. |
147 |
|
|
*/ |
148 |
|
|
const cipher::Key *secret_key_publisher_; |
149 |
|
|
|
150 |
|
|
/** |
151 |
|
|
* The machine that issued the macaroon |
152 |
|
|
*/ |
153 |
|
|
std::string origin_; |
154 |
|
|
|
155 |
|
|
/** |
156 |
|
|
* Location hint to the target service: storage relay or lease service. |
157 |
|
|
*/ |
158 |
|
|
std::string target_hint_; |
159 |
|
|
|
160 |
|
|
/** |
161 |
|
|
* If the macaroon is created from a JSON snippet, the hmac_ is stored here. |
162 |
|
|
* Otherwise the macaroon was created from scratch with the secret key and |
163 |
|
|
* hmac_ is empty. |
164 |
|
|
*/ |
165 |
|
|
shash::Any hmac_primary_; |
166 |
|
|
|
167 |
|
|
// Caveats |
168 |
|
|
|
169 |
|
|
/** |
170 |
|
|
* Time to live for this macaroon |
171 |
|
|
*/ |
172 |
|
|
time_t expiry_utc_; |
173 |
|
|
|
174 |
|
|
/** |
175 |
|
|
* Repository name |
176 |
|
|
*/ |
177 |
|
|
std::string fqrn_; |
178 |
|
|
|
179 |
|
|
/** |
180 |
|
|
* Sub part of the name space |
181 |
|
|
*/ |
182 |
|
|
std::string root_path_; |
183 |
|
|
|
184 |
|
|
|
185 |
|
|
// 3rd-party caveat, slightly simplified: no target hint, no assertion |
186 |
|
|
|
187 |
|
|
/** |
188 |
|
|
* Hint to the release manager machine. |
189 |
|
|
*/ |
190 |
|
|
std::string publisher_hint_; |
191 |
|
|
|
192 |
|
|
/** |
193 |
|
|
* The root key for the 3rd party caveats. Random and unique to a macaroon. |
194 |
|
|
* The macaroon owns this key. |
195 |
|
|
*/ |
196 |
|
|
cipher::Key *key_onetime_; |
197 |
|
|
|
198 |
|
|
/** |
199 |
|
|
* The random key specific to this macaroon encrypted for the publisher. |
200 |
|
|
*/ |
201 |
|
|
std::string key_onetime4storage_; |
202 |
|
|
|
203 |
|
|
/** |
204 |
|
|
* The random key specific to this macaroon encrypted for the publisher. |
205 |
|
|
*/ |
206 |
|
|
std::string key_onetime4publisher_; |
207 |
|
|
|
208 |
|
|
/** |
209 |
|
|
* A message from the release manager machine to the storage relay about the |
210 |
|
|
* the operation that this macaroon discharges. |
211 |
|
|
*/ |
212 |
|
|
PublishOperation publish_operation_; |
213 |
|
|
|
214 |
|
|
/** |
215 |
|
|
* The time to live for the specific operation discharged by the macaroon. |
216 |
|
|
* This should be shorter than the macaroon's life time in expiry_utc_. |
217 |
|
|
*/ |
218 |
|
|
time_t expiry_utc_operation_; |
219 |
|
|
|
220 |
|
|
/** |
221 |
|
|
* Empty unless sent from release manager machine to the storage relay. In |
222 |
|
|
* the latter case it is the hash of the change pack signed off by the release |
223 |
|
|
* manager machine. Note that the release manager machine and the storage |
224 |
|
|
* relay do not share a key. Only the lease service and the storage relay |
225 |
|
|
* share a key. |
226 |
|
|
*/ |
227 |
|
|
shash::Any payload_hash_; |
228 |
|
|
|
229 |
|
|
/** |
230 |
|
|
* The hmac protecting the caveats set by the release manager machine. |
231 |
|
|
*/ |
232 |
|
|
shash::Any hmac_3rd_party_; |
233 |
|
|
}; |
234 |
|
|
|
235 |
|
|
#endif // CVMFS_WEBAPI_MACAROON_H_ |