GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/signature.cc
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 391 581 67.3%
Branches: 213 592 36.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * This is a wrapper around OpenSSL's libcrypto. It supports
5 * signing of data with an X.509 certificate and verifying
6 * a signature against a certificate. The certificates can act only as key
7 * store, in which case there is no verification against the CA chain.
8 *
9 * It also supports verification of plain RSA signatures (for the whitelist).
10 *
11 * We work exclusively with PEM formatted files (= Base64-encoded DER files).
12 */
13
14
15 #include "crypto/signature.h"
16
17 #include <openssl/bn.h>
18 #include <openssl/evp.h>
19 #include <openssl/pkcs7.h>
20 #include <openssl/x509v3.h>
21
22 #include <cassert>
23 #include <cctype>
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <string>
28 #include <vector>
29
30 #include "crypto/hash.h"
31 #include "crypto/openssl_version.h"
32 #include "util/concurrency.h"
33 #include "util/logging.h"
34 #include "util/platform.h"
35 #include "util/posix.h"
36 #include "util/prng.h"
37 #include "util/smalloc.h"
38 #include "util/string.h"
39
40 using namespace std; // NOLINT
41
42 namespace signature {
43
44 const char *kDefaultPublicKey = "/etc/cvmfs/keys/cern.ch/cern-it4.pub";
45
46
47 static int CallbackCertVerify(int ok, X509_STORE_CTX *ctx) {
48 LogCvmfs(kLogCvmfs, kLogDebug, "certificate chain verification: %d", ok);
49 if (ok)
50 return ok;
51
52 const int error = X509_STORE_CTX_get_error(ctx);
53 X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
54 string subject = "subject n/a";
55 if (current_cert) {
56 char *buffer = NULL;
57 buffer = X509_NAME_oneline(X509_get_subject_name(current_cert), NULL, 0);
58 if (buffer) {
59 subject = string(buffer);
60 free(buffer);
61 }
62 }
63 LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogErr,
64 "certificate verification error: %s, error %s (%d)", subject.c_str(),
65 X509_verify_cert_error_string(error), error);
66 return ok;
67 }
68
69
70 514 SignatureManager::SignatureManager() {
71 514 private_key_ = NULL;
72 514 private_master_key_ = NULL;
73 514 certificate_ = NULL;
74 514 x509_store_ = NULL;
75 514 x509_lookup_ = NULL;
76 514 const int retval = pthread_mutex_init(&lock_blacklist_, NULL);
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
514 assert(retval == 0);
78 514 }
79
80
81 494 void SignatureManager::InitX509Store() {
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 494 times.
494 if (x509_store_)
83 X509_STORE_free(x509_store_);
84 494 x509_lookup_ = NULL;
85 494 x509_store_ = X509_STORE_new();
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 494 times.
494 assert(x509_store_ != NULL);
87
88 494 const unsigned long verify_flags = // NOLINT(runtime/int)
89 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL;
90 #ifdef OPENSSL_API_INTERFACE_V09
91 X509_STORE_set_flags(x509_store_, verify_flags);
92 #else
93 int retval;
94 494 X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new();
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 494 times.
494 assert(param != NULL);
96 494 retval = X509_VERIFY_PARAM_set_flags(param, verify_flags);
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 494 times.
494 assert(retval == 1);
98 494 retval = X509_STORE_set1_param(x509_store_, param);
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 494 times.
494 assert(retval == 1);
100 494 X509_VERIFY_PARAM_free(param);
101 #endif
102
103 494 x509_lookup_ = X509_STORE_add_lookup(x509_store_, X509_LOOKUP_hash_dir());
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 494 times.
494 assert(x509_lookup_ != NULL);
105
106 494 X509_STORE_set_verify_cb_func(x509_store_, CallbackCertVerify);
107 494 }
108
109
110 494 void SignatureManager::Init() {
111 494 OpenSSL_add_all_algorithms();
112 494 InitX509Store();
113 494 }
114
115
116 494 void SignatureManager::Fini() {
117 494 UnloadCertificate();
118 494 UnloadPrivateKey();
119 494 UnloadPrivateMasterKey();
120 494 UnloadPublicRsaKeys();
121 // Lookup is freed automatically
122
1/2
✓ Branch 0 taken 494 times.
✗ Branch 1 not taken.
494 if (x509_store_)
123 494 X509_STORE_free(x509_store_);
124
125 494 EVP_cleanup();
126
127 494 private_key_ = NULL;
128 494 private_master_key_ = NULL;
129 494 certificate_ = NULL;
130 494 x509_store_ = NULL;
131 494 x509_lookup_ = NULL;
132 494 }
133
134
135 /**
136 * OpenSSL error strings.
137 */
138 string SignatureManager::GetCryptoError() {
139 char buf[121];
140 string err;
141 while (ERR_peek_error() != 0) {
142 ERR_error_string(ERR_get_error(), buf);
143 err += string(buf);
144 }
145 return err;
146 }
147
148
149 /**
150 * @param[in] file_pem File name of the PEM key file
151 * @param[in] password Password for the private key.
152 * Password is not saved internally, but the private key is.
153 * \return True on success, false otherwise
154 */
155 164 bool SignatureManager::LoadPrivateMasterKeyPath(const string &file_pem) {
156 164 UnloadPrivateMasterKey();
157 FILE *fp;
158
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 164 times.
164 if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
159 return false;
160 164 private_master_key_ = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
161 164 fclose(fp);
162 164 return (private_master_key_ != NULL);
163 }
164
165 4 bool SignatureManager::LoadPrivateMasterKeyMem(const string &key) {
166 4 UnloadPrivateMasterKey();
167 4 BIO *bp = BIO_new(BIO_s_mem());
168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assert(bp != NULL);
169
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (BIO_write(bp, key.data(), key.size()) <= 0) {
170 BIO_free(bp);
171 return false;
172 }
173 4 private_master_key_ = PEM_read_bio_RSAPrivateKey(bp, NULL, NULL, NULL);
174 4 BIO_free(bp);
175 4 return (private_master_key_ != NULL);
176 }
177
178
179 /**
180 * @param[in] file_pem File name of the PEM key file
181 * @param[in] password Password for the private key.
182 * Password is not saved internally, but the private key is.
183 * \return True on success, false otherwise
184 */
185 256 bool SignatureManager::LoadPrivateKeyPath(const string &file_pem,
186 const string &password) {
187 256 UnloadPrivateKey();
188 bool result;
189 256 FILE *fp = NULL;
190 256 char *tmp = strdupa(password.c_str());
191
192
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 256 times.
256 if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
193 return false;
194 256 result = (private_key_ = PEM_read_PrivateKey(fp, NULL, NULL, tmp)) != NULL;
195 256 fclose(fp);
196 256 return result;
197 }
198
199 4 bool SignatureManager::LoadPrivateKeyMem(const std::string &key) {
200 4 UnloadPrivateKey();
201 4 BIO *bp = BIO_new(BIO_s_mem());
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assert(bp != NULL);
203
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (BIO_write(bp, key.data(), key.size()) <= 0) {
204 BIO_free(bp);
205 return false;
206 }
207 4 private_key_ = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL);
208 4 BIO_free(bp);
209 4 return (private_key_ != NULL);
210 }
211
212
213 /**
214 * Clears the memory storing the private key.
215 */
216 768 void SignatureManager::UnloadPrivateKey() {
217
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 494 times.
768 if (private_key_)
218 274 EVP_PKEY_free(private_key_);
219 768 private_key_ = NULL;
220 768 }
221
222
223 508 void SignatureManager::UnloadCertificate() {
224
2/2
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 169 times.
508 if (certificate_)
225 339 X509_free(certificate_);
226 508 certificate_ = NULL;
227 508 }
228
229
230 /**
231 * Clears the memory storing the private RSA master key (whitelist signing).
232 */
233 676 void SignatureManager::UnloadPrivateMasterKey() {
234
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 494 times.
676 if (private_master_key_)
235 182 RSA_free(private_master_key_);
236 676 private_master_key_ = NULL;
237 676 }
238
239
240 /**
241 * Loads a certificate. This certificate is used for the following
242 * signature verifications
243 *
244 * \return True on success, false otherwise
245 */
246 252 bool SignatureManager::LoadCertificatePath(const string &file_pem) {
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (certificate_) {
248 X509_free(certificate_);
249 certificate_ = NULL;
250 }
251
252 bool result;
253 252 char *nopwd = strdupa("");
254 FILE *fp;
255
256
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 252 times.
252 if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
257 return false;
258 252 result = (certificate_ = PEM_read_X509_AUX(fp, NULL, NULL, nopwd)) != NULL;
259
260
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
252 if (!result && certificate_) {
261 X509_free(certificate_);
262 certificate_ = NULL;
263 }
264
265 252 fclose(fp);
266 252 return result;
267 }
268
269
270 /**
271 * See the function that loads the certificate from file.
272 */
273 107 bool SignatureManager::LoadCertificateMem(const unsigned char *buffer,
274 const unsigned buffer_size) {
275
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 73 times.
107 if (certificate_) {
276 34 X509_free(certificate_);
277 34 certificate_ = NULL;
278 }
279
280 bool result;
281 107 char *nopwd = strdupa("");
282
283 107 BIO *mem = BIO_new(BIO_s_mem());
284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107 times.
107 if (!mem)
285 return false;
286
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 107 times.
107 if (BIO_write(mem, buffer, buffer_size) <= 0) {
287 BIO_free(mem);
288 return false;
289 }
290 107 result = (certificate_ = PEM_read_bio_X509_AUX(mem, NULL, NULL, nopwd))
291 != NULL;
292 107 BIO_free(mem);
293
294
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
107 if (!result && certificate_) {
295 X509_free(certificate_);
296 certificate_ = NULL;
297 }
298
299 107 return result;
300 }
301
302
303 /**
304 * Loads a list of public RSA keys separated by ":".
305 */
306 228 bool SignatureManager::LoadPublicRsaKeys(const string &path_list) {
307
1/2
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
228 UnloadPublicRsaKeys();
308
309
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 214 times.
228 if (path_list == "")
310 14 return true;
311
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 const vector<string> pem_files = SplitString(path_list, ':');
312
313 214 char *nopwd = strdupa("");
314 FILE *fp;
315
316
2/2
✓ Branch 1 taken 214 times.
✓ Branch 2 taken 210 times.
424 for (unsigned i = 0; i < pem_files.size(); ++i) {
317 214 const char *pubkey_file = pem_files[i].c_str();
318
319 // open public key file
320
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 fp = fopen(pubkey_file, "r");
321
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 210 times.
214 if (fp == NULL) {
322
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr,
323 "failed to open "
324 "public key '%s'",
325 pubkey_file);
326 4 return false;
327 }
328
329 // load the public key from the file (and close it)
330
1/2
✓ Branch 1 taken 210 times.
✗ Branch 2 not taken.
210 EVP_PKEY *this_key = PEM_read_PUBKEY(fp, NULL, NULL, nopwd);
331
1/2
✓ Branch 1 taken 210 times.
✗ Branch 2 not taken.
210 fclose(fp);
332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (this_key == NULL) {
333 LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr,
334 "failed to load "
335 "public key '%s'",
336 pubkey_file);
337 return false;
338 }
339
340 // read the RSA key from the loaded public key
341
1/2
✓ Branch 1 taken 210 times.
✗ Branch 2 not taken.
210 RSA *key = EVP_PKEY_get1_RSA(this_key);
342
1/2
✓ Branch 1 taken 210 times.
✗ Branch 2 not taken.
210 EVP_PKEY_free(this_key);
343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (key == NULL) {
344 LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr,
345 "failed to read "
346 "public key '%s'",
347 pubkey_file);
348 return false;
349 }
350
351 // store the loaded public key
352
1/2
✓ Branch 1 taken 210 times.
✗ Branch 2 not taken.
210 public_keys_.push_back(key);
353 }
354
355 210 return true;
356 214 }
357
358
359 736 void SignatureManager::UnloadPublicRsaKeys() {
360
2/2
✓ Branch 1 taken 224 times.
✓ Branch 2 taken 736 times.
960 for (unsigned i = 0; i < public_keys_.size(); ++i)
361 224 RSA_free(public_keys_[i]);
362 736 public_keys_.clear();
363 736 }
364
365
366 4 std::string SignatureManager::GenerateKeyText(RSA *pubkey) const {
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pubkey) {
368 return "";
369 }
370
371
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 BIO *bp = BIO_new(BIO_s_mem());
372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (bp == NULL) {
373 LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr,
374 "Failed to allocate"
375 " memory for pubkey");
376 return "";
377 }
378
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (!PEM_write_bio_RSA_PUBKEY(bp, pubkey)) {
379 LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr,
380 "Failed to write"
381 " pubkey to memory");
382 return "";
383 }
384 char *bio_pubkey_text;
385
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 long bytes = BIO_get_mem_data(bp, &bio_pubkey_text); // NOLINT
386
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 std::string bio_pubkey_str(bio_pubkey_text, bytes);
387
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 BIO_free(bp);
388
389 4 return bio_pubkey_str;
390 4 }
391
392
393 4 std::string SignatureManager::GetActivePubkeys() const {
394 4 std::string pubkeys;
395 4 for (std::vector<RSA *>::const_iterator it = public_keys_.begin();
396
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
8 it != public_keys_.end();
397 4 it++) {
398
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 pubkeys += GenerateKeyText(*it);
399 }
400 // NOTE: we do not add the pubkey of the certificate here, as it is
401 // not used for the whitelist verification.
402 4 return pubkeys;
403 }
404
405 std::vector<std::string> SignatureManager::GetActivePubkeysAsVector() const {
406 std::vector<std::string> pubkeys;
407 for (std::vector<RSA *>::const_iterator it = public_keys_.begin();
408 it != public_keys_.end();
409 it++) {
410 pubkeys.push_back(GenerateKeyText(*it));
411 }
412 // NOTE: we do not add the pubkey of the certificate here, as it is
413 // not used for the whitelist verification.
414 return pubkeys;
415 }
416
417 8 std::string SignatureManager::GetCertificate() const {
418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!certificate_)
419 return "";
420
421
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 BIO *bp = BIO_new(BIO_s_mem());
422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bp != NULL);
423
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const bool rvb = PEM_write_bio_X509(bp, certificate_);
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(rvb);
425 char *bio_crt_text;
426
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 long bytes = BIO_get_mem_data(bp, &bio_crt_text); // NOLINT
427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bytes > 0);
428
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 std::string bio_crt_str(bio_crt_text, bytes);
429
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 BIO_free(bp);
430 8 return bio_crt_str;
431 8 }
432
433
434 8 std::string SignatureManager::GetPrivateKey() {
435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!private_key_)
436 return "";
437
438
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 BIO *bp = BIO_new(BIO_s_mem());
439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bp != NULL);
440 const bool rvb =
441
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 PEM_write_bio_PrivateKey(bp, private_key_, NULL, NULL, 0, 0, NULL);
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(rvb);
443 char *bio_privkey_text;
444
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 long bytes = BIO_get_mem_data(bp, &bio_privkey_text); // NOLINT
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bytes > 0);
446
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 std::string bio_privkey_str(bio_privkey_text, bytes);
447
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 BIO_free(bp);
448 8 return bio_privkey_str;
449 8 }
450
451
452 8 std::string SignatureManager::GetPrivateMasterKey() {
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!private_master_key_)
454 return "";
455
456
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 BIO *bp = BIO_new(BIO_s_mem());
457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bp != NULL);
458
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const bool rvb = PEM_write_bio_RSAPrivateKey(bp, private_master_key_, NULL,
459 8 NULL, 0, 0, NULL);
460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(rvb);
461 char *bio_master_privkey_text;
462
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 long bytes = BIO_get_mem_data(bp, &bio_master_privkey_text); // NOLINT
463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bytes > 0);
464
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 std::string bio_master_privkey_str(bio_master_privkey_text, bytes);
465
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 BIO_free(bp);
466 8 return bio_master_privkey_str;
467 8 }
468
469 28 RSA *SignatureManager::GenerateRsaKeyPair() {
470 28 RSA *rsa = NULL;
471 28 BIGNUM *bn = BN_new();
472 28 int retval = BN_set_word(bn, RSA_F4);
473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 assert(retval == 1);
474 #ifdef OPENSSL_API_INTERFACE_V09
475 rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL);
476 assert(rsa != NULL);
477 #else
478 28 rsa = RSA_new();
479 28 retval = RSA_generate_key_ex(rsa, 2048, bn, NULL);
480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 assert(retval == 1);
481 #endif
482 28 BN_free(bn);
483 28 return rsa;
484 }
485
486
487 /**
488 * Creates the RSA master key pair for whitelist signing
489 */
490 14 void SignatureManager::GenerateMasterKeyPair() {
491 14 UnloadPrivateMasterKey();
492 14 UnloadPublicRsaKeys();
493
494 14 RSA *rsa = GenerateRsaKeyPair();
495 14 private_master_key_ = RSAPrivateKey_dup(rsa);
496
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 public_keys_.push_back(RSAPublicKey_dup(rsa));
497 14 RSA_free(rsa);
498 14 }
499
500 /**
501 * Creates a new RSA key pair (private key) and a self-signed certificate
502 */
503 14 void SignatureManager::GenerateCertificate(const std::string &cn) {
504
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 UnloadPrivateKey();
505
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 UnloadCertificate();
506 int retval;
507
508
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 RSA *rsa = GenerateRsaKeyPair();
509
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 private_key_ = EVP_PKEY_new();
510
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 retval = EVP_PKEY_set1_RSA(private_key_, RSAPrivateKey_dup(rsa));
511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 assert(retval == 1);
512
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 EVP_PKEY *pkey = EVP_PKEY_new();
513
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 retval = EVP_PKEY_set1_RSA(pkey, rsa);
514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 assert(retval == 1);
515
516
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 certificate_ = X509_new();
517
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 X509_set_version(certificate_, 2L);
518
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 X509_set_pubkey(certificate_, pkey);
519
520 14 Prng prng;
521 14 prng.InitLocaltime();
522 14 unsigned long rnd_serial_no = prng.Next(uint64_t(1) + uint32_t(-1)); // NOLINT
523 14 rnd_serial_no = rnd_serial_no
524 14 | uint64_t(prng.Next(uint64_t(1) + uint32_t(-1))) << 32;
525
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 ASN1_INTEGER_set(X509_get_serialNumber(certificate_), rnd_serial_no);
526
527 // valid as of now
528
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 X509_gmtime_adj(
529
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 reinterpret_cast<ASN1_TIME *>(X509_get_notBefore(certificate_)), 0);
530 // valid for 1 year (validity range is unused)
531
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 X509_gmtime_adj(
532
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 reinterpret_cast<ASN1_TIME *>(X509_get_notAfter(certificate_)),
533 3600 * 24 * 365);
534
535
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 X509_NAME *name = X509_get_subject_name(certificate_);
536 #ifdef OPENSSL_API_INTERFACE_V09
537 X509_NAME_add_entry_by_txt(
538 name, "CN", MBSTRING_ASC,
539 const_cast<unsigned char *>(
540 reinterpret_cast<const unsigned char *>(cn.c_str())),
541 -1, -1, 0);
542 #else
543
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 X509_NAME_add_entry_by_txt(
544 name, "CN", MBSTRING_ASC,
545 14 reinterpret_cast<const unsigned char *>(cn.c_str()), -1, -1, 0);
546 #endif
547
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 retval = X509_set_issuer_name(certificate_, name);
548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 assert(retval == 1);
549
550 #ifdef OPENSSL_API_INTERFACE_V09
551 retval = X509_sign(certificate_, pkey, EVP_sha1());
552 #else
553
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 retval = X509_sign(certificate_, pkey, EVP_sha256());
554 #endif
555
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 EVP_PKEY_free(pkey);
556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 assert(retval > 0);
557 14 }
558
559 /**
560 * Loads a list of blacklisted certificates (fingerprints) from a file.
561 */
562 12 bool SignatureManager::LoadBlacklist(const std::string &path_blacklist,
563 bool append) {
564 12 const MutexLockGuard lock_guard(&lock_blacklist_);
565
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 LogCvmfs(kLogSignature, kLogDebug, "reading from blacklist %s",
566 path_blacklist.c_str());
567
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (!append)
568 12 blacklist_.clear();
569
570
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 const int fd = open(path_blacklist.c_str(), O_RDONLY);
571
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (fd < 0)
572 return false;
573 12 std::string blacklist_buffer;
574
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 const bool retval = SafeReadToString(fd, &blacklist_buffer);
575
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 close(fd);
576
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!retval)
577 return false;
578
579 12 unsigned num_bytes = 0;
580
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
24 while (num_bytes < blacklist_buffer.size()) {
581 24 const string line = GetLineMem(blacklist_buffer.data() + num_bytes,
582
1/2
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
12 blacklist_buffer.size() - num_bytes);
583
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 blacklist_.push_back(line);
584 12 num_bytes += line.length() + 1;
585 12 }
586
587 12 return true;
588 12 }
589
590
591 193 vector<string> SignatureManager::GetBlacklist() {
592 193 const MutexLockGuard lock_guard(&lock_blacklist_);
593
1/2
✓ Branch 1 taken 193 times.
✗ Branch 2 not taken.
386 return blacklist_;
594 193 }
595
596
597 /**
598 * Loads CA certificates CRLs from a ":" separated list of paths.
599 * The information is used for proper X509 verification.
600 * The format of the certificates and CRLs has to be OpenSSL hashed certs.
601 * The path can be something like /etc/grid-security/certificates.
602 * If path_list is empty, the default path is taken.
603 */
604 bool SignatureManager::LoadTrustedCaCrl(const string &path_list) {
605 InitX509Store();
606
607 /* TODO if (path_list == "") {
608 return true;
609 }*/
610 const vector<string> paths = SplitString(path_list, ':');
611 for (unsigned i = 0; i < paths.size(); ++i) {
612 const int retval =
613 X509_LOOKUP_add_dir(x509_lookup_, paths[i].c_str(), X509_FILETYPE_PEM);
614 if (!retval)
615 return false;
616 }
617 return true;
618 }
619
620
621 /**
622 * Returns cryptographic hash from DER encoded certificate, encoded the same way
623 * OpenSSL does (01:AB:...).
624 * Empty string on failure.
625 */
626 185 shash::Any SignatureManager::HashCertificate(
627 const shash::Algorithms hash_algorithm) {
628
1/2
✓ Branch 1 taken 185 times.
✗ Branch 2 not taken.
185 shash::Any result;
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 if (!certificate_)
630 return result;
631
632 int buffer_size;
633 185 unsigned char *buffer = NULL;
634
635
1/2
✓ Branch 1 taken 185 times.
✗ Branch 2 not taken.
185 buffer_size = i2d_X509(certificate_, &buffer);
636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 if (buffer_size < 0)
637 return result;
638
639 185 result.algorithm = hash_algorithm;
640
1/2
✓ Branch 1 taken 185 times.
✗ Branch 2 not taken.
185 shash::HashMem(buffer, buffer_size, &result);
641 185 free(buffer);
642
643 185 return result;
644 }
645
646
647 /**
648 * Returns cryptographic hash from DER encoded certificate, encoded the same way
649 * OpenSSL does (01:AB:...).
650 * Empty string on failure.
651 */
652 86 string SignatureManager::FingerprintCertificate(
653 const shash::Algorithms hash_algorithm) {
654
1/2
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
86 const shash::Any hash = HashCertificate(hash_algorithm);
655
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 86 times.
86 if (hash.IsNull())
656 return "";
657
658
1/2
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
86 const string hash_str = hash.ToString();
659 86 string result;
660
2/2
✓ Branch 1 taken 3494 times.
✓ Branch 2 taken 86 times.
3580 for (unsigned i = 0; i < hash_str.length(); ++i) {
661
2/2
✓ Branch 0 taken 3440 times.
✓ Branch 1 taken 54 times.
3494 if (i < 2 * shash::kDigestSizes[hash_algorithm]) {
662
4/4
✓ Branch 0 taken 3354 times.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 1634 times.
✓ Branch 3 taken 1720 times.
3440 if ((i > 0) && (i % 2 == 0))
663
1/2
✓ Branch 1 taken 1634 times.
✗ Branch 2 not taken.
1634 result += ":";
664 }
665
1/2
✓ Branch 2 taken 3494 times.
✗ Branch 3 not taken.
3494 result += toupper(hash_str[i]);
666 }
667 86 return result;
668 86 }
669
670
671 /**
672 * Parses a fingerprint from the whitelist
673 */
674 117 shash::Any SignatureManager::MkFromFingerprint(const std::string &fingerprint) {
675 117 string convert;
676
2/2
✓ Branch 1 taken 6641 times.
✓ Branch 2 taken 113 times.
6754 for (unsigned i = 0; i < fingerprint.length(); ++i) {
677
1/2
✓ Branch 2 taken 6637 times.
✗ Branch 3 not taken.
13278 if ((fingerprint[i] == ' ') || (fingerprint[i] == '\t')
678
5/6
✓ Branch 0 taken 6637 times.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6637 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 6637 times.
13278 || (fingerprint[i] == '#')) {
679 4 break;
680 }
681
2/2
✓ Branch 1 taken 4528 times.
✓ Branch 2 taken 2109 times.
6637 if (fingerprint[i] != ':')
682
1/2
✓ Branch 2 taken 4528 times.
✗ Branch 3 not taken.
4528 convert.push_back(tolower(fingerprint[i]));
683 }
684
685
1/2
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
234 return shash::MkFromHexPtr(shash::HexPtr(convert));
686 117 }
687
688
689 /**
690 * \return Some human-readable information about the loaded certificate.
691 */
692 string SignatureManager::Whois() {
693 if (!certificate_)
694 return "No certificate loaded";
695
696 string result;
697 X509_NAME *subject = X509_get_subject_name(certificate_);
698 X509_NAME *issuer = X509_get_issuer_name(certificate_);
699 char *buffer = NULL;
700 buffer = X509_NAME_oneline(subject, NULL, 0);
701 if (buffer) {
702 result = "Publisher: " + string(buffer);
703 free(buffer);
704 }
705 buffer = X509_NAME_oneline(issuer, NULL, 0);
706 if (buffer) {
707 result += "\nCertificate issued by: " + string(buffer);
708 free(buffer);
709 }
710 return result;
711 }
712
713
714 bool SignatureManager::WriteCertificateMem(unsigned char **buffer,
715 unsigned *buffer_size) {
716 BIO *mem = BIO_new(BIO_s_mem());
717 if (!mem)
718 return false;
719 if (!PEM_write_bio_X509(mem, certificate_)) {
720 BIO_free(mem);
721 return false;
722 }
723
724 void *bio_buffer;
725 *buffer_size = BIO_get_mem_data(mem, &bio_buffer);
726 *buffer = reinterpret_cast<unsigned char *>(smalloc(*buffer_size));
727 memcpy(*buffer, bio_buffer, *buffer_size);
728 BIO_free(mem);
729 return true;
730 }
731
732
733 /**
734 * Checks, whether the loaded certificate and the loaded private key match.
735 *
736 * \return True, if private key and certificate match, false otherwise.
737 */
738 108 bool SignatureManager::KeysMatch() {
739
2/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
108 if (!certificate_ || !private_key_)
740 return false;
741
742 108 bool result = false;
743 108 const unsigned char *sign_me = reinterpret_cast<const unsigned char *>(
744 "sign me");
745 108 unsigned char *signature = NULL;
746 unsigned signature_size;
747
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
108 if (Sign(sign_me, 7, &signature, &signature_size)
748
4/8
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 108 times.
✗ Branch 8 not taken.
108 && Verify(sign_me, 7, signature, signature_size)) {
749 108 result = true;
750 }
751
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if (signature)
752 108 free(signature);
753 108 return result;
754 }
755
756
757 /**
758 * Verifies the currently loaded certificate against the trusted CA chain.
759 */
760 bool SignatureManager::VerifyCaChain() {
761 if (!certificate_)
762 return false;
763
764 X509_STORE_CTX *csc = NULL;
765 csc = X509_STORE_CTX_new();
766 assert(csc);
767
768 X509_STORE_CTX_init(csc, x509_store_, certificate_, NULL);
769 const bool result = X509_verify_cert(csc) == 1;
770 X509_STORE_CTX_free(csc);
771
772 return result;
773 }
774
775
776 /**
777 * Signs a data block using the loaded private key.
778 *
779 * \return True on success, false otherwise
780 */
781 292 bool SignatureManager::Sign(const unsigned char *buffer,
782 const unsigned buffer_size,
783 unsigned char **signature,
784 unsigned *signature_size) {
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 if (!private_key_) {
786 *signature_size = 0;
787 *signature = NULL;
788 return false;
789 }
790
791 292 bool result = false;
792 #ifdef OPENSSL_API_INTERFACE_V11
793 292 EVP_MD_CTX *ctx_ptr = EVP_MD_CTX_new();
794 #else
795 EVP_MD_CTX ctx;
796 EVP_MD_CTX_init(&ctx);
797 EVP_MD_CTX *ctx_ptr = &ctx;
798 #endif
799
800 292 *signature = reinterpret_cast<unsigned char *>(
801 292 smalloc(EVP_PKEY_size(private_key_)));
802 292 if (EVP_SignInit(ctx_ptr, EVP_sha1())
803
1/2
✓ Branch 1 taken 292 times.
✗ Branch 2 not taken.
292 && EVP_SignUpdate(ctx_ptr, buffer, buffer_size)
804
3/6
✓ Branch 0 taken 292 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 292 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 292 times.
✗ Branch 6 not taken.
584 && EVP_SignFinal(ctx_ptr, *signature, signature_size, private_key_)) {
805 292 result = true;
806 }
807 #ifdef OPENSSL_API_INTERFACE_V11
808 292 EVP_MD_CTX_free(ctx_ptr);
809 #else
810 EVP_MD_CTX_cleanup(&ctx);
811 #endif
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 if (!result) {
813 free(*signature);
814 *signature_size = 0;
815 *signature = NULL;
816 }
817
818 292 return result;
819 }
820
821
822 /**
823 * Signs a data block using the loaded private master key.
824 *
825 * \return True on success, false otherwise
826 */
827 102 bool SignatureManager::SignRsa(const unsigned char *buffer,
828 const unsigned buffer_size,
829 unsigned char **signature,
830 unsigned *signature_size) {
831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (!private_master_key_) {
832 *signature_size = 0;
833 *signature = NULL;
834 return false;
835 }
836
837 102 unsigned char *to = (unsigned char *)smalloc(RSA_size(private_master_key_));
838 102 unsigned char *from = (unsigned char *)smalloc(buffer_size);
839 102 memcpy(from, buffer, buffer_size);
840
841 102 const int size = RSA_private_encrypt(buffer_size, from, to,
842 private_master_key_, RSA_PKCS1_PADDING);
843 102 free(from);
844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (size < 0) {
845 *signature_size = 0;
846 *signature = NULL;
847 return false;
848 }
849 102 *signature = to;
850 102 *signature_size = size;
851 102 return true;
852 }
853
854
855 /**
856 * Verifies a signature against loaded certificate.
857 *
858 * \return True if signature is valid, false on error or otherwise
859 */
860 219 bool SignatureManager::Verify(const unsigned char *buffer,
861 const unsigned buffer_size,
862 const unsigned char *signature,
863 const unsigned signature_size) {
864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (!certificate_)
865 return false;
866
867 219 bool result = false;
868 #ifdef OPENSSL_API_INTERFACE_V11
869 219 EVP_MD_CTX *ctx_ptr = EVP_MD_CTX_new();
870 #else
871 EVP_MD_CTX ctx;
872 EVP_MD_CTX_init(&ctx);
873 EVP_MD_CTX *ctx_ptr = &ctx;
874 #endif
875
876 219 EVP_PKEY *pubkey = X509_get_pubkey(certificate_);
877 219 if (EVP_VerifyInit(ctx_ptr, EVP_sha1())
878
3/6
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 219 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 219 times.
✗ Branch 6 not taken.
438 && EVP_VerifyUpdate(ctx_ptr, buffer, buffer_size) &&
879 #ifdef OPENSSL_API_INTERFACE_V09
880 EVP_VerifyFinal(ctx_ptr, const_cast<unsigned char *>(signature),
881 signature_size, pubkey)
882 #else
883
1/2
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
219 EVP_VerifyFinal(ctx_ptr, signature, signature_size, pubkey)
884 #endif
885 ) {
886 219 result = true;
887 }
888
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 if (pubkey != NULL)
889 219 EVP_PKEY_free(pubkey);
890 #ifdef OPENSSL_API_INTERFACE_V11
891 219 EVP_MD_CTX_free(ctx_ptr);
892 #else
893 EVP_MD_CTX_cleanup(&ctx);
894 #endif
895
896 219 return result;
897 }
898
899
900 /**
901 * Verifies a signature against all loaded public keys.
902 *
903 * \return True if signature is valid with any public key, false on error or
904 * otherwise
905 */
906 119 bool SignatureManager::VerifyRsa(const unsigned char *buffer,
907 const unsigned buffer_size,
908 const unsigned char *signature,
909 const unsigned signature_size) {
910
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
119 for (unsigned i = 0, s = public_keys_.size(); i < s; ++i) {
911
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 119 times.
119 if (buffer_size > (unsigned)RSA_size(public_keys_[i]))
912 continue;
913
914 119 unsigned char *to = (unsigned char *)smalloc(RSA_size(public_keys_[i]));
915 119 unsigned char *from = (unsigned char *)smalloc(signature_size);
916 119 memcpy(from, signature, signature_size);
917
918 119 const int size = RSA_public_decrypt(signature_size, from, to,
919 119 public_keys_[i], RSA_PKCS1_PADDING);
920 119 free(from);
921
2/4
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
119 if ((size >= 0) && (unsigned(size) == buffer_size)
922
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
119 && (memcmp(buffer, to, size) == 0)) {
923 119 free(to);
924 119 return true;
925 }
926
927 free(to);
928 }
929
930 LogCvmfs(kLogSignature, kLogDebug, "VerifyRsa, no public key fits");
931 return false;
932 }
933
934
935 /**
936 * Strips a signature from the letter (if exists)
937 */
938 202 void SignatureManager::CutLetter(const unsigned char *buffer,
939 const unsigned buffer_size,
940 const char separator,
941 unsigned *letter_length,
942 unsigned *pos_after_mark) {
943 202 unsigned pos = 0;
944 202 *letter_length = *pos_after_mark = 0;
945 do {
946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30874 times.
30874 if (pos == buffer_size) {
947 *pos_after_mark = pos; // Careful: pos_after_mark points out of buffer
948 *letter_length = pos;
949 break;
950 }
951
952
3/4
✓ Branch 0 taken 1459 times.
✓ Branch 1 taken 29415 times.
✓ Branch 2 taken 1459 times.
✗ Branch 3 not taken.
30874 if ((buffer[pos] == '\n') && (pos + 4 <= buffer_size)
953
3/4
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 1257 times.
✓ Branch 2 taken 202 times.
✗ Branch 3 not taken.
1459 && (buffer[pos + 1] == separator) && (buffer[pos + 2] == separator)
954
1/2
✓ Branch 0 taken 202 times.
✗ Branch 1 not taken.
202 && (buffer[pos + 3] == '\n')) {
955 202 *letter_length = pos + 1;
956 202 pos += 4;
957 202 break;
958 }
959 30672 pos++;
960 } while (true);
961 202 *pos_after_mark = pos;
962 202 }
963
964
965 /**
966 * Checks a document of the form
967 * <ASCII LINES>
968 * --
969 * <hash>
970 * <signature>
971 */
972 202 bool SignatureManager::VerifyLetter(const unsigned char *buffer,
973 const unsigned buffer_size,
974 const bool by_rsa) {
975 202 unsigned pos = 0;
976 202 unsigned letter_length = 0;
977
1/2
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
202 CutLetter(buffer, buffer_size, '-', &letter_length, &pos);
978
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 202 times.
202 if (pos >= buffer_size)
979 return false;
980
981
1/2
✓ Branch 2 taken 202 times.
✗ Branch 3 not taken.
202 string hash_str = "";
982 202 const unsigned hash_pos = pos;
983 do {
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8318 times.
8318 if (pos == buffer_size)
985 return false;
986
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 8116 times.
8318 if (buffer[pos] == '\n') {
987 202 pos++;
988 202 break;
989 }
990
1/2
✓ Branch 1 taken 8116 times.
✗ Branch 2 not taken.
8116 hash_str.push_back(buffer[pos++]);
991 } while (true);
992
1/2
✓ Branch 2 taken 202 times.
✗ Branch 3 not taken.
202 const shash::Any hash_printed = shash::MkFromHexPtr(shash::HexPtr(hash_str));
993
1/2
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
202 shash::Any hash_computed(hash_printed.algorithm);
994
1/2
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
202 shash::HashMem(buffer, letter_length, &hash_computed);
995
2/4
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 202 times.
202 if (hash_printed != hash_computed)
996 return false;
997
998
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 99 times.
202 if (by_rsa) {
999
1/2
✓ Branch 2 taken 103 times.
✗ Branch 3 not taken.
103 return VerifyRsa(&buffer[hash_pos], hash_str.length(), &buffer[pos],
1000 103 buffer_size - pos);
1001 } else {
1002
1/2
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
99 return Verify(&buffer[hash_pos], hash_str.length(), &buffer[pos],
1003 99 buffer_size - pos);
1004 }
1005 202 }
1006
1007
1008 /**
1009 * Verifies a PKCS#7 binary content + signature structure
1010 * using the loaded trusted CAs/CRLs
1011 */
1012 bool SignatureManager::VerifyPkcs7(const unsigned char *buffer,
1013 const unsigned buffer_size,
1014 unsigned char **content,
1015 unsigned *content_size,
1016 vector<string> *alt_uris) {
1017 *content = NULL;
1018 *content_size = 0;
1019
1020 BIO *bp_pkcs7 = BIO_new(BIO_s_mem());
1021 if (!bp_pkcs7)
1022 return false;
1023 if (BIO_write(bp_pkcs7, buffer, buffer_size) <= 0) {
1024 BIO_free(bp_pkcs7);
1025 return false;
1026 }
1027
1028 PKCS7 *pkcs7 = NULL;
1029 pkcs7 = PEM_read_bio_PKCS7(bp_pkcs7, NULL, NULL, NULL);
1030 BIO_free(bp_pkcs7);
1031 if (!pkcs7) {
1032 LogCvmfs(kLogSignature, kLogDebug, "invalid pkcs#7 signature");
1033 return false;
1034 }
1035
1036 BIO *bp_content = BIO_new(BIO_s_mem());
1037 if (!bp_content) {
1038 PKCS7_free(pkcs7);
1039 return false;
1040 }
1041
1042 const int flags = 0;
1043 STACK_OF(X509) *extra_signers = NULL;
1044 BIO *indata = NULL;
1045 const bool result = PKCS7_verify(pkcs7, extra_signers, x509_store_, indata,
1046 bp_content, flags);
1047 if (result != 1) {
1048 BIO_free(bp_content);
1049 PKCS7_free(pkcs7);
1050 return false;
1051 }
1052
1053 BUF_MEM *bufmem_content;
1054 BIO_get_mem_ptr(bp_content, &bufmem_content);
1055 // BIO_free() leaves BUF_MEM alone
1056 (void)BIO_set_close(bp_content, BIO_NOCLOSE);
1057 BIO_free(bp_content);
1058 *content = reinterpret_cast<unsigned char *>(bufmem_content->data);
1059 *content_size = bufmem_content->length;
1060 free(bufmem_content);
1061 if (*content == NULL) {
1062 PKCS7_free(pkcs7);
1063 LogCvmfs(kLogSignature, kLogDebug, "empty pkcs#7 structure");
1064 return false;
1065 }
1066
1067 // Extract signing certificates
1068 STACK_OF(X509) *signers = NULL;
1069 signers = PKCS7_get0_signers(pkcs7, NULL, 0);
1070 assert(signers);
1071
1072 // Extract alternative names
1073 for (int i = 0; i < sk_X509_num(signers); ++i) {
1074 X509 *this_signer = sk_X509_value(signers, i);
1075 GENERAL_NAMES *subject_alt_names = NULL;
1076 subject_alt_names = reinterpret_cast<GENERAL_NAMES *>(
1077 X509_get_ext_d2i(this_signer, NID_subject_alt_name, NULL, NULL));
1078 if (subject_alt_names != NULL) {
1079 for (int j = 0; j < sk_GENERAL_NAME_num(subject_alt_names); ++j) {
1080 GENERAL_NAME *this_name = sk_GENERAL_NAME_value(subject_alt_names, j);
1081 if (this_name->type != GEN_URI)
1082 continue;
1083
1084 const char *name_ptr = reinterpret_cast<const char *>(
1085 #ifdef OPENSSL_API_INTERFACE_V11
1086 ASN1_STRING_get0_data(this_name->d.uniformResourceIdentifier));
1087 #else
1088 ASN1_STRING_data(this_name->d.uniformResourceIdentifier));
1089 #endif
1090 const int name_len =
1091 ASN1_STRING_length(this_name->d.uniformResourceIdentifier);
1092 if (!name_ptr || (name_len <= 0))
1093 continue;
1094 alt_uris->push_back(string(name_ptr, name_len));
1095 }
1096 }
1097 }
1098 sk_X509_free(signers);
1099 PKCS7_free(pkcs7);
1100 return true;
1101 }
1102
1103 } // namespace signature
1104