GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/letter.cc
Date: 2026-10-04 02:40:33
Exec Total Coverage
Lines: 0 71 0.0%
Branches: 0 30 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5
6 #include "letter.h"
7
8 #include <inttypes.h>
9
10 #include <cassert>
11 #include <map>
12
13 #include "crypto/signature.h"
14 #include "util/string.h"
15
16 using namespace std; // NOLINT
17
18 namespace letter {
19
20 ✗ Letter::Letter(const string &fqrn,
21 const string &text,
22 ✗ signature::SignatureManager *signature_manager)
23 ✗ : fqrn_(fqrn), text_(text), signature_manager_(signature_manager) { }
24
25
26 ✗ string Letter::Sign(const shash::Algorithms hash_algorithm) {
27 ✗ unsigned char *cert_buf = NULL;
28 unsigned cert_buf_size;
29 ✗ bool retval = signature_manager_->WriteCertificateMem(&cert_buf,
30 &cert_buf_size);
31 ✗ assert(retval);
32 const string cert_base64 = Base64(
33 ✗ string(reinterpret_cast<char *>(cert_buf), cert_buf_size));
34 ✗ free(cert_buf);
35
36 ✗ string output = text_;
37 ✗ output += string("\n##\n") + "V1" + "\n" + "N" + fqrn_ + "\n" + "T"
38 ✗ + StringifyInt(time(NULL)) + "\n" + "X" + cert_base64 + "\n";
39 ✗ shash::Any output_hash(hash_algorithm);
40 ✗ shash::HashMem(reinterpret_cast<const unsigned char *>(output.data()),
41 ✗ output.length(), &output_hash);
42 ✗ output += "--\n" + output_hash.ToString() + "\n";
43
44 unsigned char *sig;
45 unsigned sig_size;
46 ✗ retval = signature_manager_->Sign(
47 ✗ reinterpret_cast<const unsigned char *>(output_hash.ToString().data()),
48 output_hash.GetHexSize(), &sig, &sig_size);
49 ✗ assert(retval);
50 ✗ output.append(reinterpret_cast<char *>(sig), sig_size);
51 ✗ free(sig);
52
53 ✗ return Base64(output);
54 }
55
56
57 ✗ Failures Letter::Verify(uint64_t max_age, string *msg, string *cert) {
58 ✗ msg->clear();
59 ✗ cert->clear();
60 bool retval;
61
62 ✗ string dec;
63 ✗ retval = Debase64(text_, &dec);
64
65 ✗ if (!retval)
66 ✗ return kFailBadBase64;
67
68 // Cut envelope and signature
69 ✗ unsigned env_pos = 0;
70 ✗ unsigned sig_pos = 0;
71 ✗ unsigned msg_len = 0;
72 ✗ unsigned env_len = 0;
73 const unsigned char *data_ptr = reinterpret_cast<const unsigned char *>(
74 ✗ dec.data());
75 ✗ signature::SignatureManager::CutLetter(data_ptr, dec.length(), '#', &msg_len,
76 &env_pos);
77 ✗ if (env_pos >= dec.length())
78 ✗ return kFailMalformed;
79 // Sign adds a newline
80 ✗ if (msg_len == 0)
81 ✗ return kFailMalformed;
82 ✗ *msg = dec.substr(0, msg_len - 1);
83 ✗ signature::SignatureManager::CutLetter(
84 ✗ data_ptr + env_pos, dec.length() - env_pos, '-', &env_len, &sig_pos);
85 ✗ if (sig_pos >= dec.length())
86 ✗ return kFailMalformed;
87
88 ✗ map<char, string> env;
89 ✗ ParseKeyvalMem(data_ptr + env_pos, env_len, &env);
90 ✗ map<char, string>::const_iterator iter;
91 ✗ if ((iter = env.find('T')) == env.end())
92 ✗ return kFailMalformed;
93 ✗ const uint64_t timestamp = String2Uint64(iter->second);
94 ✗ if (max_age > 0) {
95 ✗ if (timestamp + max_age < static_cast<uint64_t>(time(NULL)))
96 ✗ return kFailExpired;
97 }
98 ✗ if ((iter = env.find('N')) == env.end())
99 ✗ return kFailMalformed;
100 ✗ if (iter->second != fqrn_)
101 ✗ return kFailNameMismatch;
102 ✗ if ((iter = env.find('X')) == env.end())
103 ✗ return kFailMalformed;
104 ✗ const string cert_b64 = iter->second;
105 ✗ retval = Debase64(cert_b64, cert);
106 ✗ if (!retval)
107 ✗ return kFailMalformed;
108 ✗ retval = signature_manager_->LoadCertificateMem(
109 ✗ reinterpret_cast<const unsigned char *>(cert->data()), cert->length());
110 ✗ if (!retval)
111 ✗ return kFailBadCertificate;
112
113 ✗ retval = signature_manager_->VerifyLetter(data_ptr, dec.length(), false);
114 ✗ if (!retval)
115 ✗ return kFailBadSignature;
116
117 ✗ return kFailOk;
118 }
119
120 } // namespace letter
121