GCC Code Coverage Report


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