Directory: | cvmfs/ |
---|---|
File: | cvmfs/whitelist.cc |
Date: | 2025-06-22 02:36:02 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 189 | 281 | 67.3% |
Branches: | 120 | 286 | 42.0% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | |||
6 | #include "whitelist.h" | ||
7 | |||
8 | #include <algorithm> | ||
9 | #include <cassert> | ||
10 | #include <cstring> | ||
11 | #include <ctime> | ||
12 | |||
13 | #include "crypto/signature.h" | ||
14 | #include "network/download.h" | ||
15 | #include "util/logging.h" | ||
16 | #include "util/smalloc.h" | ||
17 | #include "util/string.h" | ||
18 | |||
19 | using namespace std; // NOLINT | ||
20 | |||
21 | namespace whitelist { | ||
22 | |||
23 | const int Whitelist::kFlagVerifyRsa = 0x01; | ||
24 | const int Whitelist::kFlagVerifyPkcs7 = 0x02; | ||
25 | const int Whitelist::kFlagVerifyCaChain = 0x04; | ||
26 | |||
27 | |||
28 | 882 | void Whitelist::CopyBuffers(unsigned *plain_size, unsigned char **plain_buf, | |
29 | unsigned *pkcs7_size, | ||
30 | unsigned char **pkcs7_buf) const { | ||
31 | 882 | *plain_size = plain_size_; | |
32 | 882 | *pkcs7_size = pkcs7_size_; | |
33 | 882 | *plain_buf = NULL; | |
34 | 882 | *pkcs7_buf = NULL; | |
35 |
1/2✓ Branch 0 taken 882 times.
✗ Branch 1 not taken.
|
882 | if (plain_size_ > 0) { |
36 | 882 | *plain_buf = reinterpret_cast<unsigned char *>(smalloc(plain_size_)); | |
37 | 882 | memcpy(*plain_buf, plain_buf_, plain_size_); | |
38 | } | ||
39 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 882 times.
|
882 | if (pkcs7_size_ > 0) { |
40 | ✗ | *pkcs7_buf = reinterpret_cast<unsigned char *>(smalloc(pkcs7_size_)); | |
41 | ✗ | memcpy(*pkcs7_buf, pkcs7_buf_, pkcs7_size_); | |
42 | } | ||
43 | 882 | } | |
44 | |||
45 | |||
46 | 66 | std::string Whitelist::CreateString( | |
47 | const std::string &fqrn, | ||
48 | int validity_days, | ||
49 | shash::Algorithms hash_algorithm, | ||
50 | signature::SignatureManager *signature_manager) { | ||
51 | const std::string to_sign = | ||
52 |
4/8✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 66 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 66 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 66 times.
✗ Branch 12 not taken.
|
132 | WhitelistTimestamp(time(NULL)) + "\n" + "E" + |
53 |
4/8✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 66 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 66 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 66 times.
✗ Branch 12 not taken.
|
264 | WhitelistTimestamp(time(NULL) + validity_days * 24 * 3600) + "\n" + "N" + |
54 |
3/6✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 66 times.
✗ Branch 8 not taken.
|
198 | fqrn + "\n" + signature_manager->FingerprintCertificate(hash_algorithm) + |
55 |
1/2✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
|
66 | "\n"; |
56 |
1/2✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
|
66 | shash::Any hash(hash_algorithm); |
57 |
1/2✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
|
66 | shash::HashString(to_sign, &hash); |
58 |
1/2✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
|
66 | std::string hash_str = hash.ToString(); |
59 | |||
60 |
1/2✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
|
66 | std::string whitelist(to_sign); |
61 |
3/6✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 66 times.
✗ Branch 8 not taken.
|
66 | whitelist += "--\n" + hash_str + "\n"; |
62 | unsigned char *signature; | ||
63 | unsigned signature_size; | ||
64 |
1/2✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
|
66 | const bool retval = signature_manager->SignRsa( |
65 | 66 | reinterpret_cast<const unsigned char *>(hash_str.data()), | |
66 | 66 | hash_str.length(), &signature, &signature_size); | |
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
66 | assert(retval); |
68 |
2/4✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 66 times.
✗ Branch 6 not taken.
|
66 | whitelist += std::string(reinterpret_cast<char *>(signature), signature_size); |
69 | 66 | free(signature); | |
70 | |||
71 | 132 | return whitelist; | |
72 | 66 | } | |
73 | |||
74 | |||
75 | 22 | std::string Whitelist::ExportString() const { | |
76 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | if (plain_buf_ == NULL) |
77 | ✗ | return ""; | |
78 |
1/2✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
|
22 | return std::string(reinterpret_cast<char *>(plain_buf_), plain_size_); |
79 | } | ||
80 | |||
81 | |||
82 | ✗ | time_t Whitelist::expires() const { | |
83 | ✗ | assert(status_ == kStAvailable); | |
84 | ✗ | return expires_; | |
85 | } | ||
86 | |||
87 | |||
88 | ✗ | bool Whitelist::IsExpired() const { | |
89 | ✗ | assert(status_ == kStAvailable); | |
90 | ✗ | return time(NULL) > expires_; | |
91 | } | ||
92 | |||
93 | |||
94 | 980 | Failures Whitelist::VerifyLoadedCertificate() const { | |
95 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 980 times.
|
980 | assert(status_ == kStAvailable); |
96 | |||
97 |
1/2✓ Branch 1 taken 980 times.
✗ Branch 2 not taken.
|
980 | vector<string> blacklist = signature_manager_->GetBlacklist(); |
98 |
2/2✓ Branch 1 taken 147 times.
✓ Branch 2 taken 882 times.
|
1029 | for (unsigned i = 0; i < blacklist.size(); ++i) { |
99 | const shash::Any this_hash = | ||
100 |
1/2✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
|
147 | signature::SignatureManager::MkFromFingerprint(blacklist[i]); |
101 |
2/2✓ Branch 1 taken 49 times.
✓ Branch 2 taken 98 times.
|
147 | if (this_hash.IsNull()) |
102 | 49 | continue; | |
103 | |||
104 | 98 | const shash::Algorithms algorithm = this_hash.algorithm; | |
105 |
2/5✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
|
98 | if (this_hash == signature_manager_->HashCertificate(algorithm)) |
106 | 98 | return kFailBlacklisted; | |
107 | } | ||
108 | |||
109 |
1/2✓ Branch 1 taken 882 times.
✗ Branch 2 not taken.
|
882 | for (unsigned i = 0; i < fingerprints_.size(); ++i) { |
110 | 882 | const shash::Algorithms algorithm = fingerprints_[i].algorithm; | |
111 |
2/5✓ Branch 2 taken 882 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 882 times.
✗ Branch 6 not taken.
|
882 | if (signature_manager_->HashCertificate(algorithm) == fingerprints_[i]) { |
112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 882 times.
|
882 | if (verification_flags_ & kFlagVerifyCaChain) { |
113 | ✗ | const bool retval = signature_manager_->VerifyCaChain(); | |
114 | ✗ | if (!retval) | |
115 | ✗ | return kFailBadCaChain; | |
116 | } | ||
117 | 882 | return kFailOk; | |
118 | } | ||
119 | } | ||
120 | ✗ | return kFailNotListed; | |
121 | 980 | } | |
122 | |||
123 | |||
124 | /** | ||
125 | * Expects whitelist to be loaded into plain_buf_ / plain_size_ and already | ||
126 | * parsed so that verification_flags_ is set | ||
127 | */ | ||
128 | 1024 | Failures Whitelist::VerifyWhitelist() { | |
129 | bool retval_b; | ||
130 | whitelist::Failures retval_wl; | ||
131 | |||
132 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1024 times.
|
1024 | assert(verification_flags_ != 0); |
133 | |||
134 |
1/2✓ Branch 0 taken 1024 times.
✗ Branch 1 not taken.
|
1024 | if (verification_flags_ & kFlagVerifyRsa) { |
135 | 1024 | retval_b = signature_manager_->VerifyLetter(plain_buf_, plain_size_, true); | |
136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1024 times.
|
1024 | if (!retval_b) { |
137 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug, "failed to verify repository whitelist"); | |
138 | ✗ | return kFailBadSignature; | |
139 | } | ||
140 | } | ||
141 | |||
142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1024 times.
|
1024 | if (verification_flags_ & kFlagVerifyPkcs7) { |
143 | unsigned char *extracted_whitelist; | ||
144 | unsigned extracted_whitelist_size; | ||
145 | ✗ | vector<string> alt_uris; | |
146 | ✗ | retval_b = signature_manager_->VerifyPkcs7( | |
147 | ✗ | pkcs7_buf_, pkcs7_size_, &extracted_whitelist, | |
148 | &extracted_whitelist_size, &alt_uris); | ||
149 | ✗ | if (!retval_b) { | |
150 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug, | |
151 | "failed to verify repository whitelist (pkcs#7): %s", | ||
152 | ✗ | signature_manager_->GetCryptoError().c_str()); | |
153 | ✗ | return kFailBadPkcs7; | |
154 | } | ||
155 | |||
156 | // Check for subject alternative name matching the repository name | ||
157 | ✗ | bool found_uri = false; | |
158 | ✗ | for (unsigned i = 0; i < alt_uris.size(); ++i) { | |
159 | ✗ | LogCvmfs(kLogSignature, kLogDebug, "found pkcs#7 signer uri %s", | |
160 | ✗ | alt_uris[i].c_str()); | |
161 | ✗ | if (alt_uris[i] == "cvmfs:" + fqrn_) { | |
162 | ✗ | found_uri = true; | |
163 | ✗ | break; | |
164 | } | ||
165 | } | ||
166 | ✗ | if (!found_uri) { | |
167 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug, | |
168 | "failed to find whitelist signer with SAN/URI cvmfs:%s", | ||
169 | fqrn_.c_str()); | ||
170 | ✗ | free(extracted_whitelist); | |
171 | ✗ | return kFailBadSignaturePkcs7; | |
172 | } | ||
173 | |||
174 | // Check once again the extracted whitelist | ||
175 | ✗ | Reset(); | |
176 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug, "Extracted pkcs#7 whitelist:\n%s", | |
177 | ✗ | string(reinterpret_cast<char *>(extracted_whitelist), | |
178 | extracted_whitelist_size) | ||
179 | .c_str()); | ||
180 | ✗ | retval_wl = ParseWhitelist(extracted_whitelist, extracted_whitelist_size); | |
181 | ✗ | if (retval_wl != kFailOk) { | |
182 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug, | |
183 | "failed to verify repository certificate against pkcs#7 " | ||
184 | "whitelist"); | ||
185 | ✗ | return kFailMalformedPkcs7; | |
186 | } | ||
187 | } | ||
188 | |||
189 | 1024 | status_ = kStAvailable; | |
190 | 1024 | return kFailOk; | |
191 | } | ||
192 | |||
193 | |||
194 | 88 | Failures Whitelist::LoadMem(const std::string &whitelist) { | |
195 | Failures retval_wl; | ||
196 | |||
197 | 88 | Reset(); | |
198 | |||
199 | 88 | plain_size_ = whitelist.length(); | |
200 | 88 | plain_buf_ = reinterpret_cast<unsigned char *>(smalloc(plain_size_)); | |
201 | 88 | memcpy(plain_buf_, whitelist.data(), plain_size_); | |
202 | |||
203 | 88 | retval_wl = ParseWhitelist(plain_buf_, plain_size_); | |
204 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 44 times.
|
88 | if (retval_wl != kFailOk) |
205 | 44 | return retval_wl; | |
206 | // TODO(jblomer): PKCS7 verification unsupported when loading from memory | ||
207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (verification_flags_ & kFlagVerifyPkcs7) |
208 | ✗ | return kFailLoadPkcs7; | |
209 | |||
210 | 44 | return VerifyWhitelist(); | |
211 | } | ||
212 | |||
213 | |||
214 | 980 | Failures Whitelist::LoadUrl(const std::string &base_url) { | |
215 | 980 | const bool probe_hosts = base_url == ""; | |
216 | download::Failures retval_dl; | ||
217 | Failures retval_wl; | ||
218 | |||
219 | 980 | Reset(); | |
220 | |||
221 |
2/4✓ Branch 2 taken 980 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 980 times.
✗ Branch 6 not taken.
|
1960 | const string whitelist_url = base_url + string("/.cvmfswhitelist"); |
222 | 980 | cvmfs::MemSink whitelist_memsink; | |
223 | download::JobInfo download_whitelist(&whitelist_url, false, probe_hosts, NULL, | ||
224 |
1/2✓ Branch 1 taken 980 times.
✗ Branch 2 not taken.
|
980 | &whitelist_memsink); |
225 |
1/2✓ Branch 1 taken 980 times.
✗ Branch 2 not taken.
|
980 | retval_dl = download_manager_->Fetch(&download_whitelist); |
226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 980 times.
|
980 | if (retval_dl != download::kFailOk) |
227 | ✗ | return kFailLoad; | |
228 | 980 | plain_size_ = whitelist_memsink.pos(); | |
229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 980 times.
|
980 | if (plain_size_ == 0) |
230 | ✗ | return kFailEmpty; | |
231 | 980 | whitelist_memsink.Release(); | |
232 | 980 | plain_buf_ = whitelist_memsink.data(); | |
233 | |||
234 |
1/2✓ Branch 1 taken 980 times.
✗ Branch 2 not taken.
|
980 | retval_wl = ParseWhitelist(plain_buf_, plain_size_); |
235 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 980 times.
|
980 | if (retval_wl != kFailOk) |
236 | ✗ | return retval_wl; | |
237 | |||
238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 980 times.
|
980 | if (verification_flags_ & kFlagVerifyPkcs7) { |
239 | // Load the separate whitelist pkcs7 structure | ||
240 | const string whitelist_pkcs7_url = base_url | ||
241 | ✗ | + string("cvmfswhitelist.pkcs7"); | |
242 | ✗ | cvmfs::MemSink pkcs7_memsink; | |
243 | download::JobInfo download_whitelist_pkcs7( | ||
244 | ✗ | &whitelist_pkcs7_url, false, probe_hosts, NULL, &pkcs7_memsink); | |
245 | ✗ | retval_dl = download_manager_->Fetch(&download_whitelist_pkcs7); | |
246 | ✗ | if (retval_dl != download::kFailOk) | |
247 | ✗ | return kFailLoadPkcs7; | |
248 | ✗ | pkcs7_size_ = pkcs7_memsink.pos(); | |
249 | ✗ | if (pkcs7_size_ == 0) | |
250 | ✗ | return kFailEmptyPkcs7; | |
251 | ✗ | pkcs7_memsink.Release(); | |
252 | ✗ | pkcs7_buf_ = pkcs7_memsink.data(); | |
253 | } | ||
254 | |||
255 |
1/2✓ Branch 1 taken 980 times.
✗ Branch 2 not taken.
|
980 | return VerifyWhitelist(); |
256 | 980 | } | |
257 | |||
258 | |||
259 | /** | ||
260 | * Helps for the time being with whitelists valid until after Y2038 on 32 bit | ||
261 | * systems. | ||
262 | */ | ||
263 | 1156 | bool Whitelist::IsBefore(time_t now, const struct tm &t_whitelist) { | |
264 | struct tm t_local; | ||
265 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1156 times.
|
1156 | if (gmtime_r(&now, &t_local) == NULL) |
266 | ✗ | return false; | |
267 |
2/2✓ Branch 0 taken 637 times.
✓ Branch 1 taken 519 times.
|
1156 | if (t_local.tm_year < t_whitelist.tm_year) |
268 | 637 | return true; | |
269 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 497 times.
|
519 | if (t_local.tm_year > t_whitelist.tm_year) |
270 | 22 | return false; | |
271 |
2/2✓ Branch 0 taken 343 times.
✓ Branch 1 taken 154 times.
|
497 | if (t_local.tm_mon < t_whitelist.tm_mon) |
272 | 343 | return true; | |
273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
|
154 | if (t_local.tm_mon > t_whitelist.tm_mon) |
274 | ✗ | return false; | |
275 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 88 times.
|
154 | if (t_local.tm_mday < t_whitelist.tm_mday) |
276 | 66 | return true; | |
277 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 44 times.
|
88 | if (t_local.tm_mday > t_whitelist.tm_mday) |
278 | 44 | return false; | |
279 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | if (t_local.tm_hour < t_whitelist.tm_hour) |
280 | 44 | return true; | |
281 | ✗ | return false; | |
282 | } | ||
283 | |||
284 | |||
285 | 1200 | Failures Whitelist::ParseWhitelist(const unsigned char *whitelist, | |
286 | const unsigned whitelist_size) { | ||
287 | 1200 | const time_t local_timestamp = time(NULL); | |
288 | 1200 | string line; | |
289 | 1200 | unsigned payload_bytes = 0; | |
290 | 1200 | bool verify_pkcs7 = false; | |
291 | 1200 | bool verify_cachain = false; | |
292 | |||
293 | // Check timestamp (UTC), ignore issue date (legacy) | ||
294 |
1/2✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
|
1200 | line = GetLineMem(reinterpret_cast<const char *>(whitelist), whitelist_size); |
295 |
2/2✓ Branch 1 taken 22 times.
✓ Branch 2 taken 1178 times.
|
1200 | if (line.length() != 14) { |
296 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | LogCvmfs(kLogSignature, kLogDebug, "invalid timestamp format"); |
297 | 22 | return kFailMalformed; | |
298 | } | ||
299 | 1178 | payload_bytes += 15; | |
300 | |||
301 | // Expiry date | ||
302 | 1178 | line = GetLineMem(reinterpret_cast<const char *>(whitelist) + payload_bytes, | |
303 |
1/2✓ Branch 1 taken 1178 times.
✗ Branch 2 not taken.
|
1178 | whitelist_size - payload_bytes); |
304 |
2/2✓ Branch 1 taken 22 times.
✓ Branch 2 taken 1156 times.
|
1178 | if (line.length() != 15) { |
305 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | LogCvmfs(kLogSignature, kLogDebug, "invalid timestamp format"); |
306 | 22 | return kFailMalformed; | |
307 | } | ||
308 | struct tm tm_wl; | ||
309 | 1156 | memset(&tm_wl, 0, sizeof(struct tm)); | |
310 |
2/4✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1156 times.
✗ Branch 5 not taken.
|
1156 | tm_wl.tm_year = String2Int64(line.substr(1, 4)) - 1900; |
311 |
2/4✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1156 times.
✗ Branch 5 not taken.
|
1156 | tm_wl.tm_mon = String2Int64(line.substr(5, 2)) - 1; |
312 |
2/4✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1156 times.
✗ Branch 5 not taken.
|
1156 | tm_wl.tm_mday = String2Int64(line.substr(7, 2)); |
313 |
2/4✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1156 times.
✗ Branch 5 not taken.
|
1156 | tm_wl.tm_hour = String2Int64(line.substr(9, 2)); |
314 | 1156 | tm_wl.tm_min = tm_wl.tm_sec = 0; // exact on hours level | |
315 | 1156 | const time_t timestamp = timegm(&tm_wl); | |
316 |
1/2✓ Branch 2 taken 1156 times.
✗ Branch 3 not taken.
|
1156 | LogCvmfs(kLogSignature, kLogDebug, |
317 | "whitelist UTC expiry timestamp in localtime: %s", | ||
318 |
1/2✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
|
2312 | StringifyTime(timestamp, false).c_str()); |
319 |
1/2✓ Branch 2 taken 1156 times.
✗ Branch 3 not taken.
|
1156 | LogCvmfs(kLogSignature, kLogDebug, "local time: %s", |
320 |
1/2✓ Branch 1 taken 1156 times.
✗ Branch 2 not taken.
|
2312 | StringifyTime(local_timestamp, true).c_str()); |
321 | // Makeshift solution to deal with whitelists valid after Y2038 on 32bit | ||
322 | // machines. Still unclear how glibc is going to treat the problem. | ||
323 |
2/2✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1090 times.
|
1156 | if (!IsBefore(local_timestamp, tm_wl)) { |
324 |
1/2✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
|
66 | LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr, |
325 | "whitelist lifetime verification failed, expired"); | ||
326 | 66 | return kFailExpired; | |
327 | } | ||
328 | // if (timestamp < 0) { | ||
329 | // LogCvmfs(kLogSignature, kLogDebug, "invalid timestamp"); | ||
330 | // return kFailMalformed; | ||
331 | // } | ||
332 | // if (local_timestamp > timestamp) { | ||
333 | // LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr, | ||
334 | // "whitelist lifetime verification failed, expired"); | ||
335 | // return kFailExpired; | ||
336 | // } | ||
337 | 1090 | expires_ = timestamp; | |
338 | 1090 | payload_bytes += 16; | |
339 | |||
340 | // Check repository name | ||
341 | 1090 | line = GetLineMem(reinterpret_cast<const char *>(whitelist) + payload_bytes, | |
342 |
1/2✓ Branch 1 taken 1090 times.
✗ Branch 2 not taken.
|
1090 | whitelist_size - payload_bytes); |
343 |
7/14✓ Branch 1 taken 1090 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1090 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 44 times.
✓ Branch 8 taken 1046 times.
✓ Branch 9 taken 1090 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 44 times.
✓ Branch 13 taken 1046 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
1090 | if ((fqrn_ != "") && ("N" + fqrn_ != line)) { |
344 |
1/2✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
|
44 | LogCvmfs(kLogSignature, kLogDebug, |
345 | "repository name on the whitelist does not match " | ||
346 | "(found %s, expected %s)", | ||
347 | line.c_str(), fqrn_.c_str()); | ||
348 | 44 | return kFailNameMismatch; | |
349 | } | ||
350 | 1046 | payload_bytes += line.length() + 1; | |
351 | |||
352 | // Check for PKCS7 | ||
353 | 1046 | line = GetLineMem(reinterpret_cast<const char *>(whitelist) + payload_bytes, | |
354 |
1/2✓ Branch 1 taken 1046 times.
✗ Branch 2 not taken.
|
1046 | whitelist_size - payload_bytes); |
355 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1046 times.
|
1046 | if (line == "Vpkcs7") { |
356 | ✗ | LogCvmfs(kLogSignature, kLogDebug, "whitelist verification: pkcs#7"); | |
357 | ✗ | verify_pkcs7 = true; | |
358 | ✗ | payload_bytes += line.length() + 1; | |
359 | ✗ | line = GetLineMem(reinterpret_cast<const char *>(whitelist) + payload_bytes, | |
360 | ✗ | whitelist_size - payload_bytes); | |
361 | } | ||
362 | |||
363 | // Check for CA chain verification | ||
364 | 1046 | line = GetLineMem(reinterpret_cast<const char *>(whitelist) + payload_bytes, | |
365 |
1/2✓ Branch 1 taken 1046 times.
✗ Branch 2 not taken.
|
1046 | whitelist_size - payload_bytes); |
366 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1046 times.
|
1046 | if (line == "Wcachain") { |
367 | ✗ | LogCvmfs(kLogSignature, kLogDebug, | |
368 | "whitelist imposes ca chain verification of manifest signature"); | ||
369 | ✗ | verify_cachain = true; | |
370 | ✗ | payload_bytes += line.length() + 1; | |
371 | ✗ | line = GetLineMem(reinterpret_cast<const char *>(whitelist) + payload_bytes, | |
372 | ✗ | whitelist_size - payload_bytes); | |
373 | } | ||
374 | |||
375 | do { | ||
376 |
2/2✓ Branch 1 taken 1024 times.
✓ Branch 2 taken 1046 times.
|
2070 | if (line == "--") |
377 | 1024 | break; | |
378 | const shash::Any this_hash = | ||
379 |
1/2✓ Branch 1 taken 1046 times.
✗ Branch 2 not taken.
|
1046 | signature::SignatureManager::MkFromFingerprint(line); |
380 |
2/2✓ Branch 1 taken 1024 times.
✓ Branch 2 taken 22 times.
|
1046 | if (!this_hash.IsNull()) |
381 |
1/2✓ Branch 1 taken 1024 times.
✗ Branch 2 not taken.
|
1024 | fingerprints_.push_back(this_hash); |
382 | |||
383 | 1046 | payload_bytes += line.length() + 1; | |
384 | 1046 | line = GetLineMem(reinterpret_cast<const char *>(whitelist) + payload_bytes, | |
385 |
1/2✓ Branch 1 taken 1046 times.
✗ Branch 2 not taken.
|
1046 | whitelist_size - payload_bytes); |
386 |
2/2✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 22 times.
|
1046 | } while (payload_bytes < whitelist_size); |
387 | |||
388 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1046 times.
|
1046 | verification_flags_ = verify_pkcs7 ? kFlagVerifyPkcs7 : kFlagVerifyRsa; |
389 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1046 times.
|
1046 | if (verify_cachain) |
390 | ✗ | verification_flags_ |= kFlagVerifyCaChain; | |
391 | 1046 | return kFailOk; | |
392 | 1200 | } | |
393 | |||
394 | |||
395 | 3390 | void Whitelist::Reset() { | |
396 | 3390 | status_ = kStNone; | |
397 | 3390 | fingerprints_.clear(); | |
398 | 3390 | expires_ = 0; | |
399 | 3390 | verification_flags_ = 0; | |
400 |
2/2✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 2322 times.
|
3390 | if (plain_buf_) |
401 | 1068 | free(plain_buf_); | |
402 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3390 times.
|
3390 | if (pkcs7_buf_) |
403 | ✗ | free(pkcs7_buf_); | |
404 | 3390 | plain_buf_ = NULL; | |
405 | 3390 | pkcs7_buf_ = NULL; | |
406 | 3390 | plain_size_ = 0; | |
407 | 3390 | pkcs7_size_ = 0; | |
408 | 3390 | } | |
409 | |||
410 | |||
411 | 1150 | Whitelist::Whitelist(const string &fqrn, | |
412 | download::DownloadManager *download_manager, | ||
413 | 1150 | signature::SignatureManager *signature_manager) | |
414 | 1150 | : fqrn_(fqrn) | |
415 | 1150 | , download_manager_(download_manager) | |
416 | 1150 | , signature_manager_(signature_manager) | |
417 | 1150 | , plain_buf_(NULL) | |
418 | 1150 | , plain_size_(0) | |
419 | 1150 | , pkcs7_buf_(NULL) | |
420 | 1150 | , pkcs7_size_(0) { | |
421 | 1150 | Reset(); | |
422 | 1150 | } | |
423 | |||
424 | |||
425 | ✗ | Whitelist::Whitelist(const Whitelist &other) | |
426 | ✗ | : fqrn_(other.fqrn_) | |
427 | ✗ | , download_manager_(other.download_manager_) | |
428 | ✗ | , signature_manager_(other.signature_manager_) | |
429 | ✗ | , status_(other.status_) | |
430 | ✗ | , fingerprints_(other.fingerprints_) | |
431 | ✗ | , expires_(other.expires_) | |
432 | ✗ | , verification_flags_(other.verification_flags_) { | |
433 | ✗ | other.CopyBuffers(&plain_size_, &plain_buf_, &pkcs7_size_, &pkcs7_buf_); | |
434 | } | ||
435 | |||
436 | |||
437 | // Testing only | ||
438 | 22 | Whitelist::Whitelist() | |
439 | 22 | : download_manager_(NULL) | |
440 | 22 | , signature_manager_(NULL) | |
441 | 22 | , status_(kStNone) | |
442 | 22 | , expires_(0) | |
443 | 22 | , verification_flags_(0) | |
444 | 22 | , plain_buf_(NULL) | |
445 | 22 | , plain_size_(0) | |
446 | 22 | , pkcs7_buf_(NULL) | |
447 | 22 | , pkcs7_size_(0) { } | |
448 | |||
449 | ✗ | Whitelist &Whitelist::operator=(const Whitelist &other) { | |
450 | ✗ | if (&other == this) | |
451 | ✗ | return *this; | |
452 | |||
453 | ✗ | Reset(); | |
454 | ✗ | fqrn_ = other.fqrn_; | |
455 | ✗ | download_manager_ = other.download_manager_; | |
456 | ✗ | signature_manager_ = other.signature_manager_; | |
457 | ✗ | status_ = other.status_; | |
458 | ✗ | fingerprints_ = other.fingerprints_; | |
459 | ✗ | expires_ = other.expires_; | |
460 | ✗ | verification_flags_ = other.verification_flags_; | |
461 | ✗ | other.CopyBuffers(&plain_size_, &plain_buf_, &pkcs7_size_, &pkcs7_buf_); | |
462 | |||
463 | ✗ | return *this; | |
464 | } | ||
465 | |||
466 | |||
467 | 1172 | Whitelist::~Whitelist() { Reset(); } | |
468 | |||
469 | } // namespace whitelist | ||
470 |