GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/letter.cc
Date: 2025-07-06 02:35:01
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