GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/signature.cc
Date: 2025-07-06 02:35:01
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 522 SignatureManager::SignatureManager() {
72 522 private_key_ = NULL;
73 522 private_master_key_ = NULL;
74 522 certificate_ = NULL;
75 522 x509_store_ = NULL;
76 522 x509_lookup_ = NULL;
77 522 const int retval = pthread_mutex_init(&lock_blacklist_, NULL);
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 522 times.
522 assert(retval == 0);
79 522 }
80
81
82 482 void SignatureManager::InitX509Store() {
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 482 times.
482 if (x509_store_)
84 X509_STORE_free(x509_store_);
85 482 x509_lookup_ = NULL;
86 482 x509_store_ = X509_STORE_new();
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 482 times.
482 assert(x509_store_ != NULL);
88
89 482 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 482 X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new();
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 482 times.
482 assert(param != NULL);
97 482 retval = X509_VERIFY_PARAM_set_flags(param, verify_flags);
98
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 482 times.
482 assert(retval == 1);
99 482 retval = X509_STORE_set1_param(x509_store_, param);
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 482 times.
482 assert(retval == 1);
101 482 X509_VERIFY_PARAM_free(param);
102 #endif
103
104 482 x509_lookup_ = X509_STORE_add_lookup(x509_store_, X509_LOOKUP_hash_dir());
105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 482 times.
482 assert(x509_lookup_ != NULL);
106
107 482 X509_STORE_set_verify_cb_func(x509_store_, CallbackCertVerify);
108 482 }
109
110
111 482 void SignatureManager::Init() {
112 482 OpenSSL_add_all_algorithms();
113 482 InitX509Store();
114 482 }
115
116
117 482 void SignatureManager::Fini() {
118 482 UnloadCertificate();
119 482 UnloadPrivateKey();
120 482 UnloadPrivateMasterKey();
121 482 UnloadPublicRsaKeys();
122 // Lookup is freed automatically
123
1/2
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
482 if (x509_store_)
124 482 X509_STORE_free(x509_store_);
125
126 482 EVP_cleanup();
127
128 482 private_key_ = NULL;
129 482 private_master_key_ = NULL;
130 482 certificate_ = NULL;
131 482 x509_store_ = NULL;
132 482 x509_lookup_ = NULL;
133 482 }
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 164 bool SignatureManager::LoadPrivateMasterKeyPath(const string &file_pem) {
157 164 UnloadPrivateMasterKey();
158 FILE *fp;
159
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 164 times.
164 if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
160 return false;
161 164 private_master_key_ = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
162 164 fclose(fp);
163 164 return (private_master_key_ != NULL);
164 }
165
166 4 bool SignatureManager::LoadPrivateMasterKeyMem(const string &key) {
167 4 UnloadPrivateMasterKey();
168 4 BIO *bp = BIO_new(BIO_s_mem());
169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assert(bp != NULL);
170
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (BIO_write(bp, key.data(), key.size()) <= 0) {
171 BIO_free(bp);
172 return false;
173 }
174 4 private_master_key_ = PEM_read_bio_RSAPrivateKey(bp, NULL, NULL, NULL);
175 4 BIO_free(bp);
176 4 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 251 bool SignatureManager::LoadPrivateKeyPath(const string &file_pem,
187 const string &password) {
188 251 UnloadPrivateKey();
189 bool result;
190 251 FILE *fp = NULL;
191 251 char *tmp = strdupa(password.c_str());
192
193
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 251 times.
251 if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
194 return false;
195 251 result = (private_key_ = PEM_read_PrivateKey(fp, NULL, NULL, tmp)) != NULL;
196 251 fclose(fp);
197 251 return result;
198 }
199
200 4 bool SignatureManager::LoadPrivateKeyMem(const std::string &key) {
201 4 UnloadPrivateKey();
202 4 BIO *bp = BIO_new(BIO_s_mem());
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assert(bp != NULL);
204
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (BIO_write(bp, key.data(), key.size()) <= 0) {
205 BIO_free(bp);
206 return false;
207 }
208 4 private_key_ = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL);
209 4 BIO_free(bp);
210 4 return (private_key_ != NULL);
211 }
212
213
214 /**
215 * Clears the memory storing the private key.
216 */
217 753 void SignatureManager::UnloadPrivateKey() {
218
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 482 times.
753 if (private_key_)
219 271 EVP_PKEY_free(private_key_);
220 753 private_key_ = NULL;
221 753 }
222
223
224 498 void SignatureManager::UnloadCertificate() {
225
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 190 times.
498 if (certificate_)
226 308 X509_free(certificate_);
227 498 certificate_ = NULL;
228 498 }
229
230
231 /**
232 * Clears the memory storing the private RSA master key (whitelist signing).
233 */
234 666 void SignatureManager::UnloadPrivateMasterKey() {
235
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 482 times.
666 if (private_master_key_)
236 184 RSA_free(private_master_key_);
237 666 private_master_key_ = NULL;
238 666 }
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 247 bool SignatureManager::LoadCertificatePath(const string &file_pem) {
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (certificate_) {
249 X509_free(certificate_);
250 certificate_ = NULL;
251 }
252
253 bool result;
254 247 char *nopwd = strdupa("");
255 FILE *fp;
256
257
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 247 times.
247 if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
258 return false;
259 247 result = (certificate_ = PEM_read_X509_AUX(fp, NULL, NULL, nopwd)) != NULL;
260
261
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
247 if (!result && certificate_) {
262 X509_free(certificate_);
263 certificate_ = NULL;
264 }
265
266 247 fclose(fp);
267 247 return result;
268 }
269
270
271 /**
272 * See the function that loads the certificate from file.
273 */
274 63 bool SignatureManager::LoadCertificateMem(const unsigned char *buffer,
275 const unsigned buffer_size) {
276
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 45 times.
63 if (certificate_) {
277 18 X509_free(certificate_);
278 18 certificate_ = NULL;
279 }
280
281 bool result;
282 63 char *nopwd = strdupa("");
283
284 63 BIO *mem = BIO_new(BIO_s_mem());
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 if (!mem)
286 return false;
287
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
63 if (BIO_write(mem, buffer, buffer_size) <= 0) {
288 BIO_free(mem);
289 return false;
290 }
291 63 result = (certificate_ = PEM_read_bio_X509_AUX(mem, NULL, NULL, nopwd))
292 != NULL;
293 63 BIO_free(mem);
294
295
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
63 if (!result && certificate_) {
296 X509_free(certificate_);
297 certificate_ = NULL;
298 }
299
300 63 return result;
301 }
302
303
304 /**
305 * Loads a list of public RSA keys separated by ":".
306 */
307 219 bool SignatureManager::LoadPublicRsaKeys(const string &path_list) {
308
1/2
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
219 UnloadPublicRsaKeys();
309
310
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 199 times.
219 if (path_list == "")
311 20 return true;
312
1/2
✓ Branch 1 taken 199 times.
✗ Branch 2 not taken.
199 const vector<string> pem_files = SplitString(path_list, ':');
313
314 199 char *nopwd = strdupa("");
315 FILE *fp;
316
317
2/2
✓ Branch 1 taken 199 times.
✓ Branch 2 taken 195 times.
394 for (unsigned i = 0; i < pem_files.size(); ++i) {
318 199 const char *pubkey_file = pem_files[i].c_str();
319
320 // open public key file
321
1/2
✓ Branch 1 taken 199 times.
✗ Branch 2 not taken.
199 fp = fopen(pubkey_file, "r");
322
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 195 times.
199 if (fp == NULL) {
323
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr,
324 "failed to open "
325 "public key '%s'",
326 pubkey_file);
327 4 return false;
328 }
329
330 // load the public key from the file (and close it)
331
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 EVP_PKEY *this_key = PEM_read_PUBKEY(fp, NULL, NULL, nopwd);
332
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 fclose(fp);
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 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 195 times.
✗ Branch 2 not taken.
195 RSA *key = EVP_PKEY_get1_RSA(this_key);
343
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 EVP_PKEY_free(this_key);
344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 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 195 times.
✗ Branch 2 not taken.
195 public_keys_.push_back(key);
354 }
355
356 195 return true;
357 199 }
358
359
360 717 void SignatureManager::UnloadPublicRsaKeys() {
361
2/2
✓ Branch 1 taken 211 times.
✓ Branch 2 taken 717 times.
928 for (unsigned i = 0; i < public_keys_.size(); ++i)
362 211 RSA_free(public_keys_[i]);
363 717 public_keys_.clear();
364 717 }
365
366
367 4 std::string SignatureManager::GenerateKeyText(RSA *pubkey) const {
368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pubkey) {
369 return "";
370 }
371
372
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());
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 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 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 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 4 times.
✗ Branch 2 not taken.
4 long bytes = BIO_get_mem_data(bp, &bio_pubkey_text); // NOLINT
387
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 std::string bio_pubkey_str(bio_pubkey_text, bytes);
388
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 BIO_free(bp);
389
390 4 return bio_pubkey_str;
391 4 }
392
393
394 4 std::string SignatureManager::GetActivePubkeys() const {
395 4 std::string pubkeys;
396 4 for (std::vector<RSA *>::const_iterator it = public_keys_.begin();
397
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
8 it != public_keys_.end();
398 4 it++) {
399
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 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 4 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 8 std::string SignatureManager::GetCertificate() const {
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!certificate_)
420 return "";
421
422
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());
423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bp != NULL);
424
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const bool rvb = PEM_write_bio_X509(bp, certificate_);
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(rvb);
426 char *bio_crt_text;
427
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 long bytes = BIO_get_mem_data(bp, &bio_crt_text); // NOLINT
428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bytes > 0);
429
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 std::string bio_crt_str(bio_crt_text, bytes);
430
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 BIO_free(bp);
431 8 return bio_crt_str;
432 8 }
433
434
435 8 std::string SignatureManager::GetPrivateKey() {
436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!private_key_)
437 return "";
438
439
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());
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bp != NULL);
441
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const bool rvb = PEM_write_bio_PrivateKey(bp, private_key_, NULL, NULL, 0, 0,
442 8 NULL);
443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(rvb);
444 char *bio_privkey_text;
445
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 long bytes = BIO_get_mem_data(bp, &bio_privkey_text); // NOLINT
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bytes > 0);
447
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 std::string bio_privkey_str(bio_privkey_text, bytes);
448
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 BIO_free(bp);
449 8 return bio_privkey_str;
450 8 }
451
452
453 8 std::string SignatureManager::GetPrivateMasterKey() {
454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!private_master_key_)
455 return "";
456
457
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());
458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bp != NULL);
459
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const bool rvb = PEM_write_bio_RSAPrivateKey(bp, private_master_key_, NULL,
460 8 NULL, 0, 0, NULL);
461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(rvb);
462 char *bio_master_privkey_text;
463
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 long bytes = BIO_get_mem_data(bp, &bio_master_privkey_text); // NOLINT
464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(bytes > 0);
465
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 std::string bio_master_privkey_str(bio_master_privkey_text, bytes);
466
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 BIO_free(bp);
467 8 return bio_master_privkey_str;
468 8 }
469
470 32 RSA *SignatureManager::GenerateRsaKeyPair() {
471 32 RSA *rsa = NULL;
472 32 BIGNUM *bn = BN_new();
473 32 int retval = BN_set_word(bn, RSA_F4);
474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 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 32 rsa = RSA_new();
480 32 retval = RSA_generate_key_ex(rsa, 2048, bn, NULL);
481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 assert(retval == 1);
482 #endif
483 32 BN_free(bn);
484 32 return rsa;
485 }
486
487
488 /**
489 * Creates the RSA master key pair for whitelist signing
490 */
491 16 void SignatureManager::GenerateMasterKeyPair() {
492 16 UnloadPrivateMasterKey();
493 16 UnloadPublicRsaKeys();
494
495 16 RSA *rsa = GenerateRsaKeyPair();
496 16 private_master_key_ = RSAPrivateKey_dup(rsa);
497
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 public_keys_.push_back(RSAPublicKey_dup(rsa));
498 16 RSA_free(rsa);
499 16 }
500
501 /**
502 * Creates a new RSA key pair (private key) and a self-signed certificate
503 */
504 16 void SignatureManager::GenerateCertificate(const std::string &cn) {
505
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 UnloadPrivateKey();
506
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 UnloadCertificate();
507 int retval;
508
509
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 RSA *rsa = GenerateRsaKeyPair();
510
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 private_key_ = EVP_PKEY_new();
511
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
16 retval = EVP_PKEY_set1_RSA(private_key_, RSAPrivateKey_dup(rsa));
512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 assert(retval == 1);
513
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 EVP_PKEY *pkey = EVP_PKEY_new();
514
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 retval = EVP_PKEY_set1_RSA(pkey, rsa);
515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 assert(retval == 1);
516
517
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 certificate_ = X509_new();
518
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 X509_set_version(certificate_, 2L);
519
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 X509_set_pubkey(certificate_, pkey);
520
521 16 Prng prng;
522 16 prng.InitLocaltime();
523 16 unsigned long rnd_serial_no = prng.Next(uint64_t(1)
524 16 + uint32_t(-1)); // NOLINT
525 16 rnd_serial_no = rnd_serial_no
526 16 | uint64_t(prng.Next(uint64_t(1) + uint32_t(-1))) << 32;
527
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
16 ASN1_INTEGER_set(X509_get_serialNumber(certificate_), rnd_serial_no);
528
529 // valid as of now
530
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 X509_gmtime_adj(
531
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 reinterpret_cast<ASN1_TIME *>(X509_get_notBefore(certificate_)), 0);
532 // valid for 1 year (validity range is unused)
533
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 X509_gmtime_adj(
534
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 reinterpret_cast<ASN1_TIME *>(X509_get_notAfter(certificate_)),
535 3600 * 24 * 365);
536
537
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 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 16 times.
✗ Branch 2 not taken.
16 X509_NAME_add_entry_by_txt(
546 name, "CN", MBSTRING_ASC,
547 16 reinterpret_cast<const unsigned char *>(cn.c_str()), -1, -1, 0);
548 #endif
549
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 retval = X509_set_issuer_name(certificate_, name);
550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 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 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
16 retval = X509_sign(certificate_, pkey, EVP_sha256());
556 #endif
557
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 EVP_PKEY_free(pkey);
558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 assert(retval > 0);
559 16 }
560
561 /**
562 * Loads a list of blacklisted certificates (fingerprints) from a file.
563 */
564 12 bool SignatureManager::LoadBlacklist(const std::string &path_blacklist,
565 bool append) {
566 12 const MutexLockGuard lock_guard(&lock_blacklist_);
567
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 LogCvmfs(kLogSignature, kLogDebug, "reading from blacklist %s",
568 path_blacklist.c_str());
569
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (!append)
570 12 blacklist_.clear();
571
572
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 const int fd = open(path_blacklist.c_str(), O_RDONLY);
573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (fd < 0)
574 return false;
575 12 std::string blacklist_buffer;
576
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 const bool retval = SafeReadToString(fd, &blacklist_buffer);
577
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 close(fd);
578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!retval)
579 return false;
580
581 12 unsigned num_bytes = 0;
582
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
24 while (num_bytes < blacklist_buffer.size()) {
583 24 const string line = GetLineMem(blacklist_buffer.data() + num_bytes,
584
1/2
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
12 blacklist_buffer.size() - num_bytes);
585
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 blacklist_.push_back(line);
586 12 num_bytes += line.length() + 1;
587 12 }
588
589 12 return true;
590 12 }
591
592
593 142 vector<string> SignatureManager::GetBlacklist() {
594 142 const MutexLockGuard lock_guard(&lock_blacklist_);
595
1/2
✓ Branch 1 taken 142 times.
✗ Branch 2 not taken.
284 return blacklist_;
596 142 }
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 147 shash::Any SignatureManager::HashCertificate(
629 const shash::Algorithms hash_algorithm) {
630
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 shash::Any result;
631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 if (!certificate_)
632 return result;
633
634 int buffer_size;
635 147 unsigned char *buffer = NULL;
636
637
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 buffer_size = i2d_X509(certificate_, &buffer);
638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 if (buffer_size < 0)
639 return result;
640
641 147 result.algorithm = hash_algorithm;
642
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 shash::HashMem(buffer, buffer_size, &result);
643 147 free(buffer);
644
645 147 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 92 string SignatureManager::FingerprintCertificate(
655 const shash::Algorithms hash_algorithm) {
656
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
92 const shash::Any hash = HashCertificate(hash_algorithm);
657
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 92 times.
92 if (hash.IsNull())
658 return "";
659
660
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
92 const string hash_str = hash.ToString();
661 92 string result;
662
2/2
✓ Branch 1 taken 3788 times.
✓ Branch 2 taken 92 times.
3880 for (unsigned i = 0; i < hash_str.length(); ++i) {
663
2/2
✓ Branch 0 taken 3680 times.
✓ Branch 1 taken 108 times.
3788 if (i < 2 * shash::kDigestSizes[hash_algorithm]) {
664
4/4
✓ Branch 0 taken 3588 times.
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 1748 times.
✓ Branch 3 taken 1840 times.
3680 if ((i > 0) && (i % 2 == 0))
665
1/2
✓ Branch 1 taken 1748 times.
✗ Branch 2 not taken.
1748 result += ":";
666 }
667
1/2
✓ Branch 2 taken 3788 times.
✗ Branch 3 not taken.
3788 result += toupper(hash_str[i]);
668 }
669 92 return result;
670 92 }
671
672
673 /**
674 * Parses a fingerprint from the whitelist
675 */
676 79 shash::Any SignatureManager::MkFromFingerprint(const std::string &fingerprint) {
677 79 string convert;
678
2/2
✓ Branch 1 taken 4317 times.
✓ Branch 2 taken 75 times.
4392 for (unsigned i = 0; i < fingerprint.length(); ++i) {
679
1/2
✓ Branch 2 taken 4313 times.
✗ Branch 3 not taken.
8630 if ((fingerprint[i] == ' ') || (fingerprint[i] == '\t')
680
5/6
✓ Branch 0 taken 4313 times.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4313 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4313 times.
8630 || (fingerprint[i] == '#')) {
681 4 break;
682 }
683
2/2
✓ Branch 1 taken 2964 times.
✓ Branch 2 taken 1349 times.
4313 if (fingerprint[i] != ':')
684
1/2
✓ Branch 2 taken 2964 times.
✗ Branch 3 not taken.
2964 convert.push_back(tolower(fingerprint[i]));
685 }
686
687
1/2
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
158 return shash::MkFromHexPtr(shash::HexPtr(convert));
688 79 }
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 103 bool SignatureManager::KeysMatch() {
741
2/4
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103 times.
103 if (!certificate_ || !private_key_)
742 return false;
743
744 103 bool result = false;
745 103 const unsigned char *sign_me = reinterpret_cast<const unsigned char *>(
746 "sign me");
747 103 unsigned char *signature = NULL;
748 unsigned signature_size;
749
1/2
✓ Branch 1 taken 103 times.
✗ Branch 2 not taken.
103 if (Sign(sign_me, 7, &signature, &signature_size)
750
4/8
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 103 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 103 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 103 times.
✗ Branch 8 not taken.
103 && Verify(sign_me, 7, signature, signature_size)) {
751 103 result = true;
752 }
753
1/2
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
103 if (signature)
754 103 free(signature);
755 103 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 282 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 282 times.
282 if (!private_key_) {
788 *signature_size = 0;
789 *signature = NULL;
790 return false;
791 }
792
793 282 bool result = false;
794 #ifdef OPENSSL_API_INTERFACE_V11
795 282 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 282 *signature = reinterpret_cast<unsigned char *>(
803 282 smalloc(EVP_PKEY_size(private_key_)));
804 282 if (EVP_SignInit(ctx_ptr, EVP_sha1())
805
1/2
✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
282 && EVP_SignUpdate(ctx_ptr, buffer, buffer_size)
806
3/6
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 282 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 282 times.
✗ Branch 6 not taken.
564 && EVP_SignFinal(ctx_ptr, *signature, signature_size, private_key_)) {
807 282 result = true;
808 }
809 #ifdef OPENSSL_API_INTERFACE_V11
810 282 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 282 times.
282 if (!result) {
815 free(*signature);
816 *signature_size = 0;
817 *signature = NULL;
818 }
819
820 282 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 108 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 108 times.
108 if (!private_master_key_) {
834 *signature_size = 0;
835 *signature = NULL;
836 return false;
837 }
838
839 108 unsigned char *to = (unsigned char *)smalloc(RSA_size(private_master_key_));
840 108 unsigned char *from = (unsigned char *)smalloc(buffer_size);
841 108 memcpy(from, buffer, buffer_size);
842
843 108 const int size = RSA_private_encrypt(buffer_size, from, to,
844 private_master_key_, RSA_PKCS1_PADDING);
845 108 free(from);
846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (size < 0) {
847 *signature_size = 0;
848 *signature = NULL;
849 return false;
850 }
851 108 *signature = to;
852 108 *signature_size = size;
853 108 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 170 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 170 times.
170 if (!certificate_)
867 return false;
868
869 170 bool result = false;
870 #ifdef OPENSSL_API_INTERFACE_V11
871 170 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 170 EVP_PKEY *pubkey = X509_get_pubkey(certificate_);
879 170 if (EVP_VerifyInit(ctx_ptr, EVP_sha1())
880
3/6
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 170 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 170 times.
✗ Branch 6 not taken.
340 && 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 170 times.
✗ Branch 2 not taken.
170 EVP_VerifyFinal(ctx_ptr, signature, signature_size, pubkey)
886 #endif
887 ) {
888 170 result = true;
889 }
890
1/2
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
170 if (pubkey != NULL)
891 170 EVP_PKEY_free(pubkey);
892 #ifdef OPENSSL_API_INTERFACE_V11
893 170 EVP_MD_CTX_free(ctx_ptr);
894 #else
895 EVP_MD_CTX_cleanup(&ctx);
896 #endif
897
898 170 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 79 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 79 times.
✗ Branch 2 not taken.
79 for (unsigned i = 0, s = public_keys_.size(); i < s; ++i) {
913
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 79 times.
79 if (buffer_size > (unsigned)RSA_size(public_keys_[i]))
914 continue;
915
916 79 unsigned char *to = (unsigned char *)smalloc(RSA_size(public_keys_[i]));
917 79 unsigned char *from = (unsigned char *)smalloc(signature_size);
918 79 memcpy(from, signature, signature_size);
919
920 79 const int size = RSA_public_decrypt(signature_size, from, to,
921 79 public_keys_[i], RSA_PKCS1_PADDING);
922 79 free(from);
923
2/4
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
79 if ((size >= 0) && (unsigned(size) == buffer_size)
924
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 && (memcmp(buffer, to, size) == 0)) {
925 79 free(to);
926 79 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 118 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 118 unsigned pos = 0;
946 118 *letter_length = *pos_after_mark = 0;
947 do {
948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17966 times.
17966 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 843 times.
✓ Branch 1 taken 17123 times.
✓ Branch 2 taken 843 times.
✗ Branch 3 not taken.
17966 if ((buffer[pos] == '\n') && (pos + 4 <= buffer_size)
955
3/4
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 725 times.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
843 && (buffer[pos + 1] == separator) && (buffer[pos + 2] == separator)
956
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 && (buffer[pos + 3] == '\n')) {
957 118 *letter_length = pos + 1;
958 118 pos += 4;
959 118 break;
960 }
961 17848 pos++;
962 } while (true);
963 118 *pos_after_mark = pos;
964 118 }
965
966
967 /**
968 * Checks a document of the form
969 * <ASCII LINES>
970 * --
971 * <hash>
972 * <signature>
973 */
974 118 bool SignatureManager::VerifyLetter(const unsigned char *buffer,
975 const unsigned buffer_size,
976 const bool by_rsa) {
977 118 unsigned pos = 0;
978 118 unsigned letter_length = 0;
979
1/2
✓ Branch 1 taken 118 times.
✗ Branch 2 not taken.
118 CutLetter(buffer, buffer_size, '-', &letter_length, &pos);
980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (pos >= buffer_size)
981 return false;
982
983
1/2
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
118 string hash_str = "";
984 118 const unsigned hash_pos = pos;
985 do {
986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4910 times.
4910 if (pos == buffer_size)
987 return false;
988
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 4792 times.
4910 if (buffer[pos] == '\n') {
989 118 pos++;
990 118 break;
991 }
992
1/2
✓ Branch 1 taken 4792 times.
✗ Branch 2 not taken.
4792 hash_str.push_back(buffer[pos++]);
993 } while (true);
994
1/2
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
118 const shash::Any hash_printed = shash::MkFromHexPtr(shash::HexPtr(hash_str));
995
1/2
✓ Branch 1 taken 118 times.
✗ Branch 2 not taken.
118 shash::Any hash_computed(hash_printed.algorithm);
996
1/2
✓ Branch 1 taken 118 times.
✗ Branch 2 not taken.
118 shash::HashMem(buffer, letter_length, &hash_computed);
997
2/4
✓ Branch 1 taken 118 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 118 times.
118 if (hash_printed != hash_computed)
998 return false;
999
1000
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 55 times.
118 if (by_rsa) {
1001
1/2
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
63 return VerifyRsa(&buffer[hash_pos], hash_str.length(), &buffer[pos],
1002 63 buffer_size - pos);
1003 } else {
1004
1/2
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
55 return Verify(&buffer[hash_pos], hash_str.length(), &buffer[pos],
1005 55 buffer_size - pos);
1006 }
1007 118 }
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