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