blob: d0adb63820fcf37ca9c2517cb1ada789b8bb1834 [file] [log] [blame]
Adrien Béraud612b55b2023-05-29 10:42:04 -04001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
Adrien Béraudcb753622023-07-17 22:32:49 -04004 * This program is free software: you can redistribute it and/or modify
Adrien Béraud612b55b2023-05-29 10:42:04 -04005 * it under the terms of the GNU General Public License as published by
Adrien Béraudcb753622023-07-17 22:32:49 -04006 * the Free Software Foundation, either version 3 of the License, or
Adrien Béraud612b55b2023-05-29 10:42:04 -04007 * (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
Adrien Béraudcb753622023-07-17 22:32:49 -040011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Adrien Béraud612b55b2023-05-29 10:42:04 -040012 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
Adrien Béraudcb753622023-07-17 22:32:49 -040015 * along with this program. If not, see <https://www.gnu.org/licenses/>.
Adrien Béraud612b55b2023-05-29 10:42:04 -040016 */
Adrien Béraud612b55b2023-05-29 10:42:04 -040017#pragma once
18
19//#include "noncopyable.h"
20#include "generic_io.h"
21#include "certstore.h"
22#include "diffie-hellman.h"
23
24#include <gnutls/gnutls.h>
25#include <asio/io_context.hpp>
26
27#include <string>
28#include <functional>
29#include <memory>
30#include <future>
31#include <chrono>
32#include <vector>
33#include <array>
34
35namespace dht {
36namespace crypto {
37struct Certificate;
38struct PrivateKey;
39} // namespace crypto
40} // namespace dht
41
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040042namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040043namespace tls {
44
45enum class TlsSessionState {
46 NONE,
47 SETUP,
48 COOKIE, // only used with non-initiator and non-reliable transport
49 HANDSHAKE,
50 MTU_DISCOVERY, // only used with non-reliable transport
51 ESTABLISHED,
52 SHUTDOWN
53};
54
55using clock = std::chrono::steady_clock;
56using duration = clock::duration;
57
58struct TlsParams
59{
60 // User CA list for session credentials
61 std::string ca_list;
62
63 std::shared_ptr<dht::crypto::Certificate> peer_ca;
64
65 // User identity for credential
66 std::shared_ptr<dht::crypto::Certificate> cert;
67 std::shared_ptr<dht::crypto::PrivateKey> cert_key;
68
69 // Diffie-Hellman computed by gnutls_dh_params_init/gnutls_dh_params_generateX
70 std::shared_future<DhParams> dh_params;
71
72 tls::CertificateStore& certStore;
73
74 // handshake timeout
75 duration timeout;
76
77 // Callback for certificate checkings
78 std::function<int(unsigned status, const gnutls_datum_t* cert_list, unsigned cert_list_size)>
79 cert_check;
80
81 std::shared_ptr<asio::io_context> io_context;
82
83 std::shared_ptr<Logger> logger;
84};
85
86/// TlsSession
87///
88/// Manages a TLS/DTLS data transport overlayed on a given generic socket.
89///
90/// \note API is not thread-safe.
91///
92class TlsSession : public GenericSocket<uint8_t>
93{
94public:
95 using SocketType = GenericSocket<uint8_t>;
96 using OnStateChangeFunc = std::function<void(TlsSessionState)>;
97 using OnRxDataFunc = std::function<void(std::vector<uint8_t>&&)>;
98 using OnCertificatesUpdate
99 = std::function<void(const gnutls_datum_t*, const gnutls_datum_t*, unsigned int)>;
100 using VerifyCertificate = std::function<int(gnutls_session_t)>;
101
102 // ===> WARNINGS <===
103 // Following callbacks are called into the FSM thread context
104 // Do not call blocking routines inside them.
105 using TlsSessionCallbacks = struct
106 {
107 OnStateChangeFunc onStateChange;
108 OnRxDataFunc onRxData;
109 OnCertificatesUpdate onCertificatesUpdate;
110 VerifyCertificate verifyCertificate;
111 };
112
113 TlsSession(std::unique_ptr<SocketType>&& transport,
114 const TlsParams& params,
115 const TlsSessionCallbacks& cbs,
116 bool anonymous = true);
117 ~TlsSession();
118
119 /// Request TLS thread to stop and quit.
120 /// \note IO operations return error after this call.
121 void shutdown() override;
122
123 void setOnRecv(RecvCb&& cb) override
124 {
125 (void) cb;
126 throw std::logic_error("TlsSession::setOnRecv not implemented");
127 }
128
129 /// Return true if the TLS session type is a server.
130 bool isInitiator() const override;
131
132 bool isReliable() const override;
133
134 int maxPayload() const override;
135
136 void waitForReady(const duration& timeout = {});
137
138 /// Synchronous writing.
139 /// Return a positive number for number of bytes write, or 0 and \a ec set in case of error.
140 std::size_t write(const ValueType* data, std::size_t size, std::error_code& ec) override;
141
142 /// Synchronous reading.
143 /// Return a positive number for number of bytes read, or 0 and \a ec set in case of error.
144 std::size_t read(ValueType* data, std::size_t size, std::error_code& ec) override;
145
146 int waitForData(std::chrono::milliseconds, std::error_code&) const override;
147
148 std::shared_ptr<dht::crypto::Certificate> peerCertificate() const;
149
150 const std::shared_ptr<dht::log::Logger>& logger() const;
151
152private:
153 class TlsSessionImpl;
154 std::unique_ptr<TlsSessionImpl> pimpl_;
155};
156
157} // namespace tls
Sébastien Blin464bdff2023-07-19 08:02:53 -0400158} // namespace dhtnet