GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/signature.cc Lines: 212 391 54.2 %
Date: 2019-02-03 02:48:13 Branches: 96 221 43.4 %

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 verifiying
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
#include "cvmfs_config.h"
15
#include "signature.h"
16
17
#include <openssl/evp.h>
18
#include <openssl/pkcs7.h>
19
#include <openssl/x509v3.h>
20
21
#include <cassert>
22
#include <cctype>
23
#include <cstdio>
24
#include <cstdlib>
25
#include <cstring>
26
#include <string>
27
#include <vector>
28
29
#include "compression.h"
30
#include "duplex_ssl.h"
31
#include "hash.h"
32
#include "logging.h"
33
#include "platform.h"
34
#include "smalloc.h"
35
#include "util/string.h"
36
#include "util_concurrency.h"
37
38
using namespace std;  // NOLINT
39
40
namespace signature {
41
42
const char *kDefaultPublicKey = "/etc/cvmfs/keys/cern.ch.pub";
43
44
45
static int CallbackCertVerify(int ok, X509_STORE_CTX *ctx) {
46
  LogCvmfs(kLogCvmfs, kLogDebug, "certificate chain verification: %d", ok);
47
  if (ok) return ok;
48
49
  int error = X509_STORE_CTX_get_error(ctx);
50
  X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
51
  string subject = "subject n/a";
52
  if (current_cert) {
53
    char *buffer = NULL;
54
    buffer = X509_NAME_oneline(X509_get_subject_name(current_cert), NULL, 0);
55
    if (buffer) {
56
      subject = string(buffer);
57
      free(buffer);
58
    }
59
  }
60
  LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogErr,
61
           "certificate verification error: %s, error %s (%d)",
62
           subject.c_str(), X509_verify_cert_error_string(error), error);
63
  return ok;
64
}
65
66
67
151
SignatureManager::SignatureManager() {
68
151
  private_key_ = NULL;
69
151
  certificate_ = NULL;
70
151
  x509_store_ = NULL;
71
151
  x509_lookup_ = NULL;
72
151
  int retval = pthread_mutex_init(&lock_blacklist_, NULL);
73
151
  assert(retval == 0);
74
}
75
76
77
141
void SignatureManager::InitX509Store() {
78
141
  if (x509_store_) X509_STORE_free(x509_store_);
79
141
  x509_lookup_ = NULL;
80
141
  x509_store_ = X509_STORE_new();
81
141
  assert(x509_store_ != NULL);
82
83
  unsigned long verify_flags =  // NOLINT(runtime/int)
84
    X509_V_FLAG_CRL_CHECK |
85
141
    X509_V_FLAG_CRL_CHECK_ALL;
86
#ifdef OPENSSL_API_INTERFACE_V09
87
  X509_STORE_set_flags(x509_store_, verify_flags);
88
#else
89
  int retval;
90
141
  X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new();
91
141
  assert(param != NULL);
92
141
  retval = X509_VERIFY_PARAM_set_flags(param, verify_flags);
93
141
  assert(retval == 1);
94
141
  retval = X509_STORE_set1_param(x509_store_, param);
95
141
  assert(retval == 1);
96
141
  X509_VERIFY_PARAM_free(param);
97
#endif
98
99
141
  x509_lookup_ = X509_STORE_add_lookup(x509_store_, X509_LOOKUP_hash_dir());
100
141
  assert(x509_lookup_ != NULL);
101
102
141
  X509_STORE_set_verify_cb_func(x509_store_, CallbackCertVerify);
103
141
}
104
105
106
141
void SignatureManager::Init() {
107
141
  OpenSSL_add_all_algorithms();
108
141
  InitX509Store();
109
141
}
110
111
112
141
void SignatureManager::Fini() {
113
141
  if (certificate_) X509_free(certificate_);
114
141
  certificate_ = NULL;
115
141
  if (private_key_) EVP_PKEY_free(private_key_);
116
141
  private_key_ = NULL;
117
141
  if (!public_keys_.empty()) {
118
152
    for (unsigned i = 0; i < public_keys_.size(); ++i)
119
76
      RSA_free(public_keys_[i]);
120
76
    public_keys_.clear();
121
  }
122
  // Lookup is freed automatically
123
141
  if (x509_store_) X509_STORE_free(x509_store_);
124
125
141
  EVP_cleanup();
126
127
141
  private_key_ = NULL;
128
141
  certificate_ = NULL;
129
141
  x509_store_ = NULL;
130
141
  x509_lookup_ = NULL;
131
141
}
132
133
134
/**
135
 * OpenSSL error strings.
136
 */
137
string SignatureManager::GetCryptoError() {
138
  char buf[121];
139
  string err;
140
  while (ERR_peek_error() != 0) {
141
    ERR_error_string(ERR_get_error(), buf);
142
    err += string(buf);
143
  }
144
  return err;
145
}
146
147
148
/**
149
 * @param[in] file_pem File name of the PEM key file
150
 * @param[in] password Password for the private key.
151
 *     Password is not saved internally, but the private key is.
152
 * \return True on success, false otherwise
153
 */
154
60
bool SignatureManager::LoadPrivateKeyPath(const string &file_pem,
155
                                          const string &password)
156
{
157
  bool result;
158
60
  FILE *fp = NULL;
159
60
  char *tmp = strdupa(password.c_str());
160
161
60
  if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
162
    return false;
163
60
  result = (private_key_ = PEM_read_PrivateKey(fp, NULL, NULL, tmp)) != NULL;
164
60
  fclose(fp);
165
60
  return result;
166
}
167
168
169
/**
170
 * Clears the memory storing the private key.
171
 */
172
void SignatureManager::UnloadPrivateKey() {
173
  if (private_key_) EVP_PKEY_free(private_key_);
174
  private_key_ = NULL;
175
}
176
177
178
/**
179
 * Loads a certificate.  This certificate is used for the following
180
 * signature verifications
181
 *
182
 * \return True on success, false otherwise
183
 */
184
60
bool SignatureManager::LoadCertificatePath(const string &file_pem) {
185
60
  if (certificate_) {
186
    X509_free(certificate_);
187
    certificate_ = NULL;
188
  }
189
190
  bool result;
191
60
  char *nopwd = strdupa("");
192
  FILE *fp;
193
194
60
  if ((fp = fopen(file_pem.c_str(), "r")) == NULL)
195
    return false;
196
60
  result = (certificate_ = PEM_read_X509_AUX(fp, NULL, NULL, nopwd)) != NULL;
197
198

60
  if (!result && certificate_) {
199
    X509_free(certificate_);
200
    certificate_ = NULL;
201
  }
202
203
60
  fclose(fp);
204
60
  return result;
205
}
206
207
208
/**
209
 * See the function that loads the certificate from file.
210
 */
211
32
bool SignatureManager::LoadCertificateMem(const unsigned char *buffer,
212
                                          const unsigned buffer_size)
213
{
214
32
  if (certificate_) {
215
4
    X509_free(certificate_);
216
4
    certificate_ = NULL;
217
  }
218
219
  bool result;
220
32
  char *nopwd = strdupa("");
221
222
32
  BIO *mem = BIO_new(BIO_s_mem());
223
32
  if (!mem) return false;
224
32
  if (BIO_write(mem, buffer, buffer_size) <= 0) {
225
    BIO_free(mem);
226
    return false;
227
  }
228
  result = (certificate_ = PEM_read_bio_X509_AUX(mem, NULL, NULL, nopwd))
229
32
           != NULL;
230
32
  BIO_free(mem);
231
232

32
  if (!result && certificate_) {
233
    X509_free(certificate_);
234
    certificate_ = NULL;
235
  }
236
237
32
  return result;
238
}
239
240
241
/**
242
 * Loads a list of public RSA keys separated by ":".
243
 */
244
81
bool SignatureManager::LoadPublicRsaKeys(const string &path_list) {
245
81
  if (!public_keys_.empty()) {
246
    for (unsigned i = 0; i < public_keys_.size(); ++i)
247
      RSA_free(public_keys_[i]);
248
    public_keys_.clear();
249
  }
250
251
81
  if (path_list == "")
252
3
    return true;
253
78
  const vector<string> pem_files = SplitString(path_list, ':');
254
255
78
  char *nopwd = strdupa("");
256
  FILE *fp;
257
258
154
  for (unsigned i = 0; i < pem_files.size(); ++i) {
259
78
    const char* pubkey_file = pem_files[i].c_str();
260
261
    // open public key file
262
78
    fp = fopen(pubkey_file, "r");
263
78
    if (fp == NULL) {
264
      LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr, "failed to open "
265
                                                         "public key '%s'",
266
2
               pubkey_file);
267
2
      return false;
268
    }
269
270
    // load the public key from the file (and close it)
271
76
    EVP_PKEY *this_key = PEM_read_PUBKEY(fp, NULL, NULL, nopwd);
272
76
    fclose(fp);
273
76
    if (this_key == NULL) {
274
      LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr, "failed to load "
275
                                                         "public key '%s'",
276
               pubkey_file);
277
      return false;
278
    }
279
280
    // read the RSA key from the loaded public key
281
76
    RSA *key = EVP_PKEY_get1_RSA(this_key);
282
76
    EVP_PKEY_free(this_key);
283
76
    if (key == NULL) {
284
      LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr, "failed to read "
285
                                                         "public key '%s'",
286
               pubkey_file);
287
      return false;
288
    }
289
290
    // store the loaded public key
291
76
    public_keys_.push_back(key);
292
  }
293
294
76
  return true;
295
}
296
297
298
std::string SignatureManager::GenerateKeyText(RSA *pubkey) {
299
  if (!pubkey) {return "";}
300
301
  BIO *bp = BIO_new(BIO_s_mem());
302
  if (bp == NULL) {
303
    LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr, "Failed to allocate"
304
             " memory for pubkey");
305
    return "";
306
  }
307
  if (!PEM_write_bio_RSA_PUBKEY(bp, pubkey)) {
308
    LogCvmfs(kLogSignature, kLogDebug | kLogSyslogErr, "Failed to write"
309
             " pubkey to memory");
310
    return "";
311
  }
312
  char *bio_pubkey_text;
313
  long bytes = BIO_get_mem_data(bp, &bio_pubkey_text);  // NOLINT
314
  std::string bio_pubkey_str(bio_pubkey_text, bytes);
315
  BIO_free(bp);
316
317
  return bio_pubkey_str;
318
}
319
320
321
std::string SignatureManager::GetActivePubkeys() {
322
  std::string pubkeys;
323
  for (std::vector<RSA *>::const_iterator it = public_keys_.begin();
324
       it != public_keys_.end();
325
       it++) {
326
    pubkeys += GenerateKeyText(*it);
327
  }
328
  // NOTE: we do not add the pubkey of the certificate here, as it is
329
  // not used for the whitelist verification.
330
  return pubkeys;
331
}
332
333
/**
334
 * Loads a list of blacklisted certificates (fingerprints) from a file.
335
 */
336
9
bool SignatureManager::LoadBlacklist(
337
  const std::string &path_blacklist,
338
  bool append)
339
{
340
9
  MutexLockGuard lock_guard(&lock_blacklist_);
341
  LogCvmfs(kLogSignature, kLogDebug, "reading from blacklist %s",
342
9
           path_blacklist.c_str());
343
9
  if (!append)
344
9
    blacklist_.clear();
345
346
  char *buffer;
347
  unsigned buffer_size;
348
9
  if (!CopyPath2Mem(path_blacklist,
349
                    reinterpret_cast<unsigned char **>(&buffer), &buffer_size))
350
  {
351
    return false;
352
  }
353
354
9
  unsigned num_bytes = 0;
355
18
  while (num_bytes < buffer_size) {
356
    const string line = GetLineMem(buffer + num_bytes,
357
9
                                   buffer_size - num_bytes);
358
9
    blacklist_.push_back(line);
359
9
    num_bytes += line.length() + 1;
360
  }
361
9
  free(buffer);
362
363
9
  return true;
364
}
365
366
367
72
vector<string> SignatureManager::GetBlacklist() {
368
72
  MutexLockGuard lock_guard(&lock_blacklist_);
369
72
  return blacklist_;
370
}
371
372
373
/**
374
 * Loads CA certificates CRLs from a ":" separated list of paths.
375
 * The information is used for proper X509 verification.
376
 * The format of the certificates and CRLs has to be OpenSSL hashed certs.
377
 * The path can be something like /etc/grid-security/certificates.
378
 * If path_list is empty, the default path is taken.
379
 */
380
bool SignatureManager::LoadTrustedCaCrl(const string &path_list) {
381
  InitX509Store();
382
383
  /* TODO if (path_list == "") {
384
    return true;
385
  }*/
386
  const vector<string> paths = SplitString(path_list, ':');
387
  for (unsigned i = 0; i < paths.size(); ++i) {
388
    int retval = X509_LOOKUP_add_dir(x509_lookup_, paths[i].c_str(),
389
                                     X509_FILETYPE_PEM);
390
    if (!retval)
391
      return false;
392
  }
393
  return true;
394
}
395
396
397
/**
398
 * Returns cryptographic hash from DER encoded certificate, encoded the same way
399
 * OpenSSL does (01:AB:...).
400
 * Empty string on failure.
401
 */
402
52
shash::Any SignatureManager::HashCertificate(
403
  const shash::Algorithms hash_algorithm)
404
{
405
52
  shash::Any result;
406
52
  if (!certificate_)
407
    return result;
408
409
  int buffer_size;
410
52
  unsigned char *buffer = NULL;
411
412
52
  buffer_size = i2d_X509(certificate_, &buffer);
413
52
  if (buffer_size < 0)
414
    return result;
415
416
52
  result.algorithm = hash_algorithm;
417
52
  shash::HashMem(buffer, buffer_size, &result);
418
52
  free(buffer);
419
420
52
  return result;
421
}
422
423
424
/**
425
 * Returns cryptographic hash from DER encoded certificate, encoded the same way
426
 * OpenSSL does (01:AB:...).
427
 * Empty string on failure.
428
 */
429
20
string SignatureManager::FingerprintCertificate(
430
  const shash::Algorithms hash_algorithm)
431
{
432
20
  shash::Any hash = HashCertificate(hash_algorithm);
433
20
  if (hash.IsNull())
434
    return "";
435
436
20
  const string hash_str = hash.ToString();
437
20
  string result;
438
820
  for (unsigned i = 0; i < hash_str.length(); ++i) {
439
800
    if (i < 2*shash::kDigestSizes[hash_algorithm]) {
440

800
      if ((i > 0) && (i%2 == 0)) result += ":";
441
    }
442
800
    result += toupper(hash_str[i]);
443
  }
444
20
  return result;
445
}
446
447
448
/**
449
 * Parses a fingerprint from the whitelist
450
 */
451
42
shash::Any SignatureManager::MkFromFingerprint(const std::string &fingerprint) {
452
42
  string convert;
453
2323
  for (unsigned i = 0; i < fingerprint.length(); ++i) {
454


2284
    if ((fingerprint[i] == ' ') || (fingerprint[i] == '\t') ||
455
        (fingerprint[i] == '#'))
456
    {
457
3
      break;
458
    }
459
2281
    if (fingerprint[i] != ':')
460
1559
      convert.push_back(tolower(fingerprint[i]));
461
  }
462
463
42
  return shash::MkFromHexPtr(shash::HexPtr(convert));
464
}
465
466
467
/**
468
 * \return Some human-readable information about the loaded certificate.
469
 */
470
string SignatureManager::Whois() {
471
  if (!certificate_) return "No certificate loaded";
472
473
  string result;
474
  X509_NAME *subject = X509_get_subject_name(certificate_);
475
  X509_NAME *issuer = X509_get_issuer_name(certificate_);
476
  char *buffer = NULL;
477
  buffer = X509_NAME_oneline(subject, NULL, 0);
478
  if (buffer) {
479
    result = "Publisher: " + string(buffer);
480
    free(buffer);
481
  }
482
  buffer = X509_NAME_oneline(issuer, NULL, 0);
483
  if (buffer) {
484
    result += "\nCertificate issued by: " + string(buffer);
485
    free(buffer);
486
  }
487
  return result;
488
}
489
490
491
bool SignatureManager::WriteCertificateMem(unsigned char **buffer,
492
                                           unsigned *buffer_size)
493
{
494
  BIO *mem = BIO_new(BIO_s_mem());
495
  if (!mem) return false;
496
  if (!PEM_write_bio_X509(mem, certificate_)) {
497
    BIO_free(mem);
498
    return false;
499
  }
500
501
  void *bio_buffer;
502
  *buffer_size = BIO_get_mem_data(mem, &bio_buffer);
503
  *buffer = reinterpret_cast<unsigned char *>(smalloc(*buffer_size));
504
  memcpy(*buffer, bio_buffer, *buffer_size);
505
  BIO_free(mem);
506
  return true;
507
}
508
509
510
/**
511
 * Checks, whether the loaded certificate and the loaded private key match.
512
 *
513
 * \return True, if private key and certificate match, false otherwise.
514
 */
515
20
bool SignatureManager::KeysMatch() {
516

20
  if (!certificate_ || !private_key_)
517
    return false;
518
519
20
  bool result = false;
520
  const unsigned char *sign_me = reinterpret_cast<const unsigned char *>
521
20
                                   ("sign me");
522
20
  unsigned char *signature = NULL;
523
  unsigned signature_size;
524

20
  if (Sign(sign_me, 7, &signature, &signature_size) &&
525
      Verify(sign_me, 7, signature, signature_size))
526
  {
527
20
    result = true;
528
  }
529
20
  if (signature) free(signature);
530
20
  return result;
531
}
532
533
534
/**
535
 * Verifies the currently loaded certificate against the trusted CA chain.
536
 */
537
bool SignatureManager::VerifyCaChain() {
538
  if (!certificate_)
539
    return false;
540
541
  X509_STORE_CTX *csc = NULL;
542
  csc = X509_STORE_CTX_new();
543
  assert(csc);
544
545
  X509_STORE_CTX_init(csc, x509_store_, certificate_, NULL);
546
  bool result = X509_verify_cert(csc) == 1;
547
  X509_STORE_CTX_free(csc);
548
549
  return result;
550
}
551
552
553
/**
554
 * Signs a data block using the loaded private key.
555
 *
556
 * \return True on sucess, false otherwise
557
 */
558
60
bool SignatureManager::Sign(const unsigned char *buffer,
559
                            const unsigned buffer_size,
560
                            unsigned char **signature,
561
                            unsigned *signature_size)
562
{
563
60
  if (!private_key_) {
564
    *signature_size = 0;
565
    *signature = NULL;
566
    return false;
567
  }
568
569
60
  bool result = false;
570
#ifdef OPENSSL_API_INTERFACE_V11
571
  EVP_MD_CTX *ctx_ptr = EVP_MD_CTX_new();
572
#else
573
  EVP_MD_CTX ctx;
574
60
  EVP_MD_CTX_init(&ctx);
575
60
  EVP_MD_CTX *ctx_ptr = &ctx;
576
#endif
577
578
  *signature = reinterpret_cast<unsigned char *>(
579
60
                 smalloc(EVP_PKEY_size(private_key_)));
580


60
  if (EVP_SignInit(ctx_ptr, EVP_sha1()) &&
581
      EVP_SignUpdate(ctx_ptr, buffer, buffer_size) &&
582
      EVP_SignFinal(ctx_ptr, *signature, signature_size, private_key_))
583
  {
584
60
    result = true;
585
  }
586
#ifdef OPENSSL_API_INTERFACE_V11
587
  EVP_MD_CTX_free(ctx_ptr);
588
#else
589
60
  EVP_MD_CTX_cleanup(&ctx);
590
#endif
591
60
  if (!result) {
592
    free(*signature);
593
    *signature_size = 0;
594
    *signature = NULL;
595
  }
596
597
60
  return result;
598
}
599
600
601
/**
602
 * Veryfies a signature against loaded certificate.
603
 *
604
 * \return True if signature is valid, false on error or otherwise
605
 */
606
52
bool SignatureManager::Verify(const unsigned char *buffer,
607
                              const unsigned buffer_size,
608
                              const unsigned char *signature,
609
                              const unsigned signature_size)
610
{
611
52
  if (!certificate_) return false;
612
613
52
  bool result = false;
614
#ifdef OPENSSL_API_INTERFACE_V11
615
  EVP_MD_CTX *ctx_ptr = EVP_MD_CTX_new();
616
#else
617
  EVP_MD_CTX ctx;
618
52
  EVP_MD_CTX_init(&ctx);
619
52
  EVP_MD_CTX *ctx_ptr = &ctx;
620
#endif
621
622
52
  EVP_PKEY *pubkey = X509_get_pubkey(certificate_);
623


52
  if (EVP_VerifyInit(ctx_ptr, EVP_sha1()) &&
624
      EVP_VerifyUpdate(ctx_ptr, buffer, buffer_size) &&
625
#ifdef OPENSSL_API_INTERFACE_V09
626
      EVP_VerifyFinal(ctx_ptr,
627
                      const_cast<unsigned char *>(signature), signature_size,
628
                      pubkey)
629
#else
630
      EVP_VerifyFinal(ctx_ptr, signature, signature_size, pubkey)
631
#endif
632
    )
633
  {
634
52
    result = true;
635
  }
636
52
  if (pubkey != NULL)
637
52
    EVP_PKEY_free(pubkey);
638
#ifdef OPENSSL_API_INTERFACE_V11
639
  EVP_MD_CTX_free(ctx_ptr);
640
#else
641
52
  EVP_MD_CTX_cleanup(&ctx);
642
#endif
643
644
52
  return result;
645
}
646
647
648
/**
649
 * Veryfies a signature against all loaded public keys.
650
 *
651
 * \return True if signature is valid with any public key, false on error or otherwise
652
 */
653
32
bool SignatureManager::VerifyRsa(const unsigned char *buffer,
654
                                 const unsigned buffer_size,
655
                                 const unsigned char *signature,
656
                                 const unsigned signature_size)
657
{
658
32
  for (unsigned i = 0, s = public_keys_.size(); i < s; ++i) {
659
32
    if (buffer_size > (unsigned)RSA_size(public_keys_[i]))
660
      continue;
661
662
32
    unsigned char *to = (unsigned char *)smalloc(RSA_size(public_keys_[i]));
663
32
    unsigned char *from = (unsigned char *)smalloc(signature_size);
664
32
    memcpy(from, signature, signature_size);
665
666
    int size = RSA_public_decrypt(signature_size, from, to,
667
32
                                  public_keys_[i], RSA_PKCS1_PADDING);
668
32
    free(from);
669

32
    if ((size >= 0) && (unsigned(size) == buffer_size) &&
670
        (memcmp(buffer, to, size) == 0))
671
    {
672
32
      free(to);
673
32
      return true;
674
    }
675
676
    free(to);
677
  }
678
679
  LogCvmfs(kLogSignature, kLogDebug, "VerifyRsa, no public key fits");
680
  return false;
681
}
682
683
684
/**
685
 * Strips a signature from the letter (if exists)
686
 */
687
64
void SignatureManager::CutLetter(const unsigned char *buffer,
688
                                 const unsigned buffer_size,
689
                                 const char separator,
690
                                 unsigned *letter_length,
691
                                 unsigned *pos_after_mark)
692
{
693
64
  unsigned pos = 0;
694
64
  *letter_length = *pos_after_mark = 0;
695
9872
  do {
696
9936
    if (pos == buffer_size) {
697
      *pos_after_mark = pos;  // Careful: pos_after_mark points out of buffer
698
      *letter_length = pos;
699
      break;
700
    }
701
702


10537
    if ((buffer[pos] == '\n') && (pos+4 <= buffer_size) &&
703
537
        (buffer[pos+1] == separator) && (buffer[pos+2] == separator) &&
704
64
        (buffer[pos+3] == '\n'))
705
    {
706
64
      *letter_length = pos+1;
707
64
      pos += 4;
708
64
      break;
709
    }
710
9872
    pos++;
711
  } while (true);
712
64
  *pos_after_mark = pos;
713
64
}
714
715
716
/**
717
 * Checks a document of the form
718
 *  <ASCII LINES>
719
 *  --
720
 *  <hash>
721
 *  <signature>
722
 */
723
64
bool SignatureManager::VerifyLetter(const unsigned char *buffer,
724
                                    const unsigned buffer_size,
725
                                    const bool by_rsa)
726
{
727
64
  unsigned pos = 0;
728
64
  unsigned letter_length = 0;
729
64
  CutLetter(buffer, buffer_size, '-', &letter_length, &pos);
730
64
  if (pos >= buffer_size)
731
    return false;
732
733
64
  string hash_str = "";
734
64
  unsigned hash_pos = pos;
735
2560
  do {
736
2624
    if (pos == buffer_size)
737
      return false;
738
2624
    if (buffer[pos] == '\n') {
739
64
      pos++;
740
64
      break;
741
    }
742
2560
    hash_str.push_back(buffer[pos++]);
743
  } while (true);
744
64
  shash::Any hash_printed = shash::MkFromHexPtr(shash::HexPtr(hash_str));
745
64
  shash::Any hash_computed(hash_printed.algorithm);
746
64
  shash::HashMem(buffer, letter_length, &hash_computed);
747
64
  if (hash_printed != hash_computed)
748
    return false;
749
750
64
  if (by_rsa) {
751
    return VerifyRsa(&buffer[hash_pos], hash_str.length(),
752
32
                     &buffer[pos], buffer_size-pos);
753
  } else {
754
    return Verify(&buffer[hash_pos], hash_str.length(),
755
32
                  &buffer[pos], buffer_size-pos);
756
  }
757
}
758
759
760
/**
761
 * Verifies a PKCS#7 binary content + signature structure
762
 * using the loaded trusted CAs/CRLs
763
 */
764
bool SignatureManager::VerifyPkcs7(const unsigned char *buffer,
765
                                   const unsigned buffer_size,
766
                                   unsigned char **content,
767
                                   unsigned *content_size,
768
                                   vector<string> *alt_uris)
769
{
770
  *content = NULL;
771
  *content_size = 0;
772
773
  BIO *bp_pkcs7 = BIO_new(BIO_s_mem());
774
  if (!bp_pkcs7) return false;
775
  if (BIO_write(bp_pkcs7, buffer, buffer_size) <= 0) {
776
    BIO_free(bp_pkcs7);
777
    return false;
778
  }
779
780
  PKCS7 *pkcs7 = NULL;
781
  pkcs7 = PEM_read_bio_PKCS7(bp_pkcs7, NULL, NULL, NULL);
782
  BIO_free(bp_pkcs7);
783
  if (!pkcs7) {
784
    LogCvmfs(kLogSignature, kLogDebug, "invalid pkcs#7 signature");
785
    return false;
786
  }
787
788
  BIO *bp_content = BIO_new(BIO_s_mem());
789
  if (!bp_content) {
790
    PKCS7_free(pkcs7);
791
    return false;
792
  }
793
794
  int flags = 0;
795
  STACK_OF(X509) *extra_signers = NULL;
796
  BIO *indata = NULL;
797
  bool result = PKCS7_verify(pkcs7, extra_signers, x509_store_, indata,
798
                             bp_content, flags);
799
  if (result != 1) {
800
    BIO_free(bp_content);
801
    PKCS7_free(pkcs7);
802
    return false;
803
  }
804
805
  BUF_MEM *bufmem_content;
806
  BIO_get_mem_ptr(bp_content, &bufmem_content);
807
  // BIO_free() leaves BUF_MEM alone
808
  (void) BIO_set_close(bp_content, BIO_NOCLOSE);
809
  BIO_free(bp_content);
810
  *content = reinterpret_cast<unsigned char *>(bufmem_content->data);
811
  *content_size = bufmem_content->length;
812
  free(bufmem_content);
813
  if (*content == NULL) {
814
    PKCS7_free(pkcs7);
815
    LogCvmfs(kLogSignature, kLogDebug, "empty pkcs#7 structure");
816
    return false;
817
  }
818
819
  // Extract signing certificates
820
  STACK_OF(X509) *signers = NULL;
821
  signers = PKCS7_get0_signers(pkcs7, NULL, 0);
822
  assert(signers);
823
824
  // Extract alternative names
825
  for (int i = 0; i < sk_X509_num(signers); ++i) {
826
    X509* this_signer = sk_X509_value(signers, i);
827
    GENERAL_NAMES *subject_alt_names = NULL;
828
    subject_alt_names = reinterpret_cast<GENERAL_NAMES *>(
829
      X509_get_ext_d2i(this_signer, NID_subject_alt_name, NULL, NULL));
830
    if (subject_alt_names != NULL) {
831
      for (int j = 0; j < sk_GENERAL_NAME_num(subject_alt_names); ++j) {
832
        GENERAL_NAME *this_name = sk_GENERAL_NAME_value(subject_alt_names, j);
833
        if (this_name->type != GEN_URI)
834
          continue;
835
836
        const char *name_ptr = reinterpret_cast<const char *>(
837
#ifdef OPENSSL_API_INTERFACE_V11
838
          ASN1_STRING_get0_data(this_name->d.uniformResourceIdentifier));
839
#else
840
          ASN1_STRING_data(this_name->d.uniformResourceIdentifier));
841
#endif
842
        int name_len =
843
          ASN1_STRING_length(this_name->d.uniformResourceIdentifier);
844
        if (!name_ptr || (name_len <= 0))
845
          continue;
846
        alt_uris->push_back(string(name_ptr, name_len));
847
      }
848
    }
849
  }
850
  sk_X509_free(signers);
851
  PKCS7_free(pkcs7);
852
  return true;
853
}
854
855
}  // namespace signature