Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 : #pragma once
18 :
19 : #include "enumclass_utils.h"
20 : #include <dhtnet/certstore.h>
21 :
22 : #include <string>
23 : #include <vector>
24 : #include <memory>
25 :
26 : // OpenDHT
27 : namespace dht {
28 : namespace crypto {
29 : struct Certificate;
30 : }
31 : } // namespace dht
32 :
33 : namespace jami {
34 : namespace tls {
35 :
36 : #if !defined(S_IRWXG)
37 : #define S_IRWXG 00070
38 : #endif /* S_IRWXG */
39 : #if !defined(S_IRGRP)
40 : #define S_IRGRP 00040
41 : #endif /* S_IRGRP */
42 : #if !defined(S_IWGRP)
43 : #define S_IWGRP 00020
44 : #endif /* S_IWGRP */
45 : #if !defined(S_IXGRP)
46 : #define S_IXGRP 00010
47 : #endif /* S_IXGRP */
48 : #if !defined(S_IRWXO)
49 : #define S_IRWXO 00007
50 : #endif /* S_IRWXO */
51 : #if !defined(S_IROTH)
52 : #define S_IROTH 00004
53 : #endif /* S_IROTH */
54 : #if !defined(S_IWOTH)
55 : #define S_IWOTH 00002
56 : #endif /* S_IWOTH */
57 : #if !defined(S_IXOTH)
58 : #define S_IXOTH 00001
59 : #endif /* S_IXOTH */
60 :
61 : class TlsValidatorException : public std::runtime_error
62 : {
63 : public:
64 0 : TlsValidatorException(const std::string& str)
65 0 : : std::runtime_error(str) {};
66 : };
67 :
68 : class TlsValidator
69 : {
70 : public:
71 : /**
72 : * @enum CertificateCheck All validation fields
73 : *
74 : */
75 : enum class CertificateCheck {
76 : HAS_PRIVATE_KEY, /** This certificate has a build in private key */
77 : EXPIRED, /** This certificate is past its expiration date */
78 : STRONG_SIGNING, /** This certificate has been signed with a brute-force-able method */
79 : NOT_SELF_SIGNED, /** This certificate has been self signed */
80 : KEY_MATCH, /** The public and private keys provided don't match */
81 : PRIVATE_KEY_STORAGE_PERMISSION, /** The file hosting the private key isn't correctly secured */
82 : PUBLIC_KEY_STORAGE_PERMISSION, /** The file hosting the public key isn't correctly secured */
83 : PRIVATE_KEY_DIRECTORY_PERMISSIONS, /** The folder storing the private key isn't correctly
84 : secured */
85 : PUBLIC_KEY_DIRECTORY_PERMISSIONS, /** The folder storing the public key isn't correctly
86 : secured */
87 : PRIVATE_KEY_STORAGE_LOCATION, /** Some operating systems have extra policies for certificate
88 : storage */
89 : PUBLIC_KEY_STORAGE_LOCATION, /** Some operating systems have extra policies for certificate
90 : storage */
91 : PRIVATE_KEY_SELINUX_ATTRIBUTES, /** Some operating systems require keys to have extra
92 : attributes */
93 : PUBLIC_KEY_SELINUX_ATTRIBUTES, /** Some operating systems require keys to have extra
94 : attributes */
95 : EXIST, /** The certificate file doesn't exist or is not accessible */
96 : VALID, /** The file is not a certificate */
97 : VALID_AUTHORITY, /** The claimed authority did not sign the certificate */
98 : KNOWN_AUTHORITY, /** Some operating systems provide a list of trusted authorities, use it */
99 : NOT_REVOKED, /** The certificate has been revoked by the authority */
100 : AUTHORITY_MISMATCH, /** The certificate and authority mismatch */
101 : UNEXPECTED_OWNER, /** The certificate has an expected owner */
102 : NOT_ACTIVATED, /** The certificate has not been activated yet */
103 : COUNT__,
104 : };
105 :
106 : /**
107 : * @enum CertificateDetails Informative fields about a certificate
108 : */
109 : enum class CertificateDetails {
110 : EXPIRATION_DATE, /** The certificate expiration date */
111 : ACTIVATION_DATE, /** The certificate activation date */
112 : REQUIRE_PRIVATE_KEY_PASSWORD, /** Does the private key require a password */
113 : PUBLIC_SIGNATURE,
114 : VERSION_NUMBER,
115 : SERIAL_NUMBER,
116 : ISSUER,
117 : SUBJECT_KEY_ALGORITHM,
118 : SUBJECT_KEY,
119 : CN,
120 : UID,
121 : N,
122 : O,
123 : SIGNATURE_ALGORITHM,
124 : MD5_FINGERPRINT,
125 : SHA1_FINGERPRINT,
126 : PUBLIC_KEY_ID,
127 : ISSUER_DN,
128 : ISSUER_CN,
129 : ISSUER_UID,
130 : ISSUER_N,
131 : ISSUER_O,
132 : NEXT_EXPECTED_UPDATE_DATE,
133 : OUTGOING_SERVER, /** The hostname/outgoing server used for this certificate */
134 : IS_CA,
135 : COUNT__
136 : };
137 :
138 : /**
139 : * @enum CheckValuesType Categories of possible values for each CertificateCheck
140 : */
141 : enum class CheckValuesType {
142 : BOOLEAN,
143 : ISO_DATE,
144 : CUSTOM,
145 : NUMBER,
146 : COUNT__,
147 : };
148 :
149 : /**
150 : * @enum CheckValue possible values for check
151 : *
152 : * All boolean check use PASSED when the test result is positive and
153 : * FAILED when it is negative. All new check need to keep this convention
154 : * or ::isValid() result will become unrepresentative of the real state.
155 : *
156 : * CUSTOM should be avoided when possible. This enum can be extended when
157 : * new validated types are required.
158 : */
159 : enum class CheckValues {
160 : PASSED, /** Equivalent of a boolean "true" */
161 : FAILED, /** Equivalent of a boolean "false" */
162 : UNSUPPORTED, /** The operating system doesn't support or require the check */
163 : ISO_DATE, /** The check value is an ISO 8601 date YYYY-MM-DD[TH24:MM:SS+00:00] */
164 : CUSTOM, /** The check value cannot be represented with a finite set of values */
165 : NUMBER,
166 : COUNT__,
167 : };
168 :
169 : /**
170 : * @typedef CheckResult A validated and unvalidated result pair
171 : *
172 : * The CheckValue is the most important value of the pair. The string
173 : * can either be the value of a CheckValues::CUSTOM result or an
174 : * error code (where applicable).
175 : */
176 : using CheckResult = std::pair<CheckValues, std::string>;
177 :
178 : /**
179 : * Create a TlsValidator for a given certificate
180 : * @param certificate The certificate path
181 : * @param privatekey An optional private key file path
182 : * @param privatekeyPasswd An optional private key password
183 : * @param caList An optional CA list to use for certificate validation
184 : */
185 : TlsValidator(const dhtnet::tls::CertificateStore& certStore,
186 : const std::string& certificate,
187 : const std::string& privatekey = "",
188 : const std::string& privatekeyPasswd = "",
189 : const std::string& caList = "");
190 :
191 : TlsValidator(const dhtnet::tls::CertificateStore& certStore, const std::vector<std::vector<uint8_t>>& certificate_chain_raw);
192 :
193 : TlsValidator(const dhtnet::tls::CertificateStore& certStore, const std::vector<uint8_t>& certificate_raw);
194 :
195 : TlsValidator(const dhtnet::tls::CertificateStore& certStore, const std::shared_ptr<dht::crypto::Certificate>&);
196 :
197 : ~TlsValidator();
198 :
199 : bool hasCa() const;
200 :
201 : bool isValid(bool verbose = false);
202 :
203 : // Security checks
204 : CheckResult hasPrivateKey();
205 : CheckResult notExpired();
206 : CheckResult strongSigning();
207 : CheckResult notSelfSigned();
208 : CheckResult keyMatch();
209 : CheckResult privateKeyStoragePermissions();
210 : CheckResult publicKeyStoragePermissions();
211 : CheckResult privateKeyDirectoryPermissions();
212 : CheckResult publicKeyDirectoryPermissions();
213 : CheckResult privateKeyStorageLocation();
214 : CheckResult publicKeyStorageLocation();
215 : CheckResult privateKeySelinuxAttributes();
216 : CheckResult publicKeySelinuxAttributes();
217 : CheckResult exist();
218 : CheckResult valid();
219 : CheckResult validAuthority();
220 : CheckResult knownAuthority();
221 : CheckResult notRevoked();
222 : CheckResult authorityMatch();
223 : CheckResult expectedOwner();
224 : CheckResult activated();
225 :
226 : // Certificate details
227 : CheckResult getExpirationDate();
228 : CheckResult getActivationDate();
229 : CheckResult requirePrivateKeyPassword();
230 : CheckResult getPublicSignature();
231 : CheckResult getVersionNumber();
232 : CheckResult getSerialNumber();
233 : CheckResult getIssuer();
234 : CheckResult getSubjectKeyAlgorithm();
235 : CheckResult getSubjectKey();
236 : CheckResult getCN();
237 : CheckResult getUID();
238 : CheckResult getN();
239 : CheckResult getO();
240 : CheckResult getSignatureAlgorithm();
241 : CheckResult getMd5Fingerprint();
242 : CheckResult getSha1Fingerprint();
243 : CheckResult getPublicKeyId();
244 : CheckResult getIssuerDN();
245 : CheckResult getIssuerCN();
246 : CheckResult getIssuerUID();
247 : CheckResult getIssuerN();
248 : CheckResult getIssuerO();
249 : CheckResult outgoingServer();
250 : CheckResult isCA();
251 :
252 : void setCaTlsValidator(const TlsValidator& validator);
253 :
254 : std::map<std::string, std::string> getSerializedChecks();
255 :
256 : std::map<std::string, std::string> getSerializedDetails();
257 :
258 0 : std::shared_ptr<dht::crypto::Certificate> getCertificate() const { return x509crt_; }
259 :
260 : private:
261 : // Enum class names
262 : static const EnumClassNames<CertificateCheck> CertificateCheckNames;
263 :
264 : static const EnumClassNames<CertificateDetails> CertificateDetailsNames;
265 :
266 : static const EnumClassNames<const CheckValuesType> CheckValuesTypeNames;
267 :
268 : static const EnumClassNames<CheckValues> CheckValuesNames;
269 :
270 : /**
271 : * Map check to their check method
272 : */
273 : static const CallbackMatrix1D<CertificateCheck, TlsValidator, CheckResult> checkCallback;
274 :
275 : /**
276 : * Map check to their getter method
277 : */
278 : static const CallbackMatrix1D<CertificateDetails, TlsValidator, CheckResult> getterCallback;
279 :
280 : /**
281 : * Valid values for each categories
282 : */
283 : static const Matrix2D<CheckValuesType, CheckValues, bool> acceptedCheckValuesResult;
284 :
285 : static const Matrix1D<CertificateCheck, CheckValuesType> enforcedCheckType;
286 :
287 : const dhtnet::tls::CertificateStore& certStore_;
288 : std::string certificatePath_;
289 : std::string privateKeyPath_;
290 : std::string caListPath_ {};
291 :
292 : std::vector<uint8_t> certificateContent_;
293 :
294 : std::shared_ptr<dht::crypto::Certificate> x509crt_;
295 :
296 : bool certificateFileFound_ {false};
297 : bool certificateFound_ {false};
298 : bool privateKeyFound_ {false};
299 : bool privateKeyPassword_ {false};
300 : bool privateKeyMatch_ {false};
301 :
302 : bool caChecked_ {false};
303 : unsigned int caValidationOutput_ {
304 : 0}; // 0 means "no flags set", where flags are ones from gnutls_certificate_status_t
305 :
306 : mutable char copy_buffer[4096];
307 :
308 : /**
309 : * Helper method to convert a CheckResult into a std::string
310 : */
311 : std::string getStringValue(const CertificateCheck check, const CheckResult result);
312 :
313 : // Helper
314 : unsigned int compareToCa();
315 :
316 : public:
317 : #if 0 // TODO reimplement this method. do not use it as it
318 : /**
319 : * Verify that the local hostname points to a valid SSL server by
320 : * establishing a connection to it and by validating its certificate.
321 : *
322 : * @param host the DNS domain address that the certificate should feature
323 : * @return 0 if success, -1 otherwise
324 : */
325 : static int verifyHostnameCertificate(const std::string& host,
326 : const uint16_t port);
327 : #endif
328 :
329 : }; // TlsValidator
330 :
331 : } // namespace tls
332 : } // namespace jami
|