reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
DtlsSocket.hxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#ifdef USE_SSL
6
7#ifndef DtlsSocket_hxx
8#define DtlsSocket_hxx
9
10#include <chrono>
11#include <functional>
12#include <memory>
13#include <mutex>
14#include <string>
15#include <vector>
16extern "C"
17{
18#include "../Srtp2Helper.hxx"
19}
20
21#include <openssl/e_os2.h>
22#include <openssl/rand.h>
23#include <openssl/err.h>
24#include <openssl/crypto.h>
25#include <openssl/ssl.h>
26
27namespace dtls
28{
29class DtlsFactory;
30class DtlsSocket;
31class DtlsTimer;
32
34{
35 public:
36 //memory is only valid for duration of callback; must be copied if queueing
37 //is required
38 virtual ~DtlsSocketContext(){}
39 virtual void write(const unsigned char* data, unsigned int len)=0;
40 virtual void handshakeCompleted()=0;
41 virtual void handshakeFailed(const char *err)=0;
42
43 // The lock the application holds while it uses the socket, if its timers fire on another
44 // thread: the socket's retransmission timer takes it too before it runs (see DtlsTimer::setLock)
45 virtual std::shared_ptr<std::mutex> timerLock() { return nullptr; }
46
47 protected:
49
50 private:
51 friend class DtlsSocket;
52
53 void setDtlsSocket(DtlsSocket *sock) {mSocket=sock;}
54};
55
57{
58 public:
59 std::vector<unsigned char> clientMasterKey;
60 std::vector<unsigned char> serverMasterKey;
61 std::vector<unsigned char> clientMasterSalt;
62 std::vector<unsigned char> serverMasterSalt;
63};
64
65class DtlsSocketTimer;
66
68{
69 public:
71 ~DtlsSocket();
72
73 // Inspects packet to see if it's a DTLS packet, if so continue processing
74 bool handlePacketMaybe(const unsigned char* bytes, size_t len);
75
76 // Called by DtlsSocketTimer when the retransmission timer expires: retransmits the last
77 // flight if OpenSSL's timer has expired (see handleTimeout)
79
80 // Size of the buffer getMyCertFingerprint and computeFingerprint write to: a SHA-256
81 // fingerprint, as uppercase hex pairs separated by colons
82 static const size_t FingerprintSize = 32 * 3;
83
84 // Retrieves the finger print of the certificate presented by the remote party, computed with
85 // the hash function an SDP fingerprint names (see checkFingerprint) - returns false if there is
86 // no certificate, the hash function isn't supported, or the fingerprint doesn't fit in
87 // fingerprintSize (EVP_MAX_MD_SIZE * 3 is always enough)
88 bool getRemoteFingerprint(const char* hashFunction, char *fingerprint, size_t fingerprintSize);
89
90 // Checks the certificate presented by the remote party against an SDP fingerprint
91 // (RFC 8122): hashFunction is its hash function textual name (eg. "sha-256"), and
92 // fingerprint its uppercase or lowercase hex pairs separated by colons
93 bool checkFingerprint(const char* hashFunction, const char* fingerprint);
94
95 // Returns true if checkFingerprint supports this hash function textual name
96 static bool isFingerprintHashFunctionSupported(const char* hashFunction);
97
98 // Retrieves the finger print of our local certificate, same as getMyCertFingerprint from DtlsFactory
99 void getMyCertFingerprint(char *fingerprint);
100
101 // For client sockets only - causes a client handshake to start (doHandshakeIteration)
102 void startClient();
103
104 // Returns the socket type: Client or Server
105 SocketType getSocketType() {return mSocketType;}
106
107 // Retreives the SRTP session keys from the Dtls session, sized for the negotiated SRTP
108 // profile - empty if no profile was negotiated or libsrtp doesn't support it
110
111 // Utility fn to compute a certificate's SHA-256 fingerprint into a buffer of FingerprintSize
112 static void computeFingerprint(X509 *cert, char *fingerprint);
113
114 // Utility fn to compute a certificate's fingerprint with the given digest - returns false
115 // if it doesn't fit in fingerprintSize (EVP_MAX_MD_SIZE * 3 is always enough)
116 static bool computeFingerprint(X509 *cert, const EVP_MD* digest, char *fingerprint, size_t fingerprintSize);
117
118 // Retrieves the DTLS negotiated SRTP profile - may return 0 if profile selection failed
120
121 // Creates SRTP session policies appropriately based on socket type (client vs server), the
122 // negotiated SRTP profile and keys extracted from the DTLS handshake process. Returns false
123 // if no SRTP profile was negotiated or libsrtp doesn't support it. On success the policies'
124 // key members point to memory allocated with new[]: the caller must delete[] them once
125 // it has created its SRTP sessions (srtp_create copies them).
127
128 // returns true if the DTLS handshake has completed
129 bool handshakeCompleted() { return mHandshakeCompleted; }
130
131 // returns true if the DTLS handshake has failed
132 bool handshakeFailed() const { return mHandshakeFailed; }
133
134 // How long since the socket was created - for a server socket, since the peer's ClientHello
135 std::chrono::steady_clock::duration getAge() const { return std::chrono::steady_clock::now() - mCreated; }
136
137 DtlsSocketContext* getSocketContext() { return mSocketContext.get(); }
138
139 private:
140 friend class DtlsFactory;
141 friend class DtlsListener;
142
143 // The retransmission timer has fired: retransmits the last flight (DTLSv1_handle_timeout),
144 // or reports the handshake as failed once OpenSSL gives up
145 void handleTimeout();
146
147 // Handles a packet after the handshake: eg. the peer's last flight again, if our final one
148 // was lost, which OpenSSL answers by retransmitting ours
149 void handlePacketAfterHandshake();
150
151 // Sends what OpenSSL wrote to mOutBio
152 void writeOutput();
153
154 // Sets mReadTimer to fire when OpenSSL's retransmission timer expires (DTLSv1_get_timeout),
155 // or clears it if no timer is running
156 void scheduleTimer();
157
158 // Creates an SSL socket, and if client sets state to connect_state and if server sets state to accept_state. Sets SSL BIO's.
159 DtlsSocket(std::unique_ptr<DtlsSocketContext> socketContext, DtlsFactory* factory, enum SocketType);
160
161 // A server socket continuing the handshake DtlsListener started on acceptedSsl, with peer
162 DtlsSocket(std::unique_ptr<DtlsSocketContext> socketContext, DtlsFactory* factory, SSL* acceptedSsl, const std::string& peer);
163
164 // Creates the SSL object for a socket of the given type, with its BIOs
165 static SSL* newSsl(DtlsFactory* factory, SocketType type);
166
167 // Give CPU cyces to the handshake process - checks current state and acts appropraitely
168 void doHandshakeIteration();
169
170 // Internals
171 std::unique_ptr<DtlsSocketContext> mSocketContext;
172 DtlsFactory* mFactory;
173 std::shared_ptr<DtlsTimer> mReadTimer; // Retransmission timer, during the handshake
174
175 // OpenSSL context data
176 SSL *mSsl;
177 BIO *mInBio;
178 BIO *mOutBio;
179
180 SocketType mSocketType;
181 bool mHandshakeCompleted;
182 bool mHandshakeFailed;
183 std::chrono::steady_clock::time_point mCreated;
184
185 // How long a server socket's handshake has left before it fails (DtlsFactory::
186 // setServerHandshakeTimeout), or duration::max() if there's no limit
187 std::chrono::steady_clock::duration serverHandshakeTimeLeft() const;
188 std::string mCookiePeer; // the peer of a socket created by DtlsListener, for the cookie callbacks
189};
190
191// Stands in front of the server DtlsSockets for one local address, doing the cookie exchange of
192// RFC 6347 section 4.2.1: a ClientHello from a new peer is answered with a HelloVerifyRequest and
193// nothing is kept for the peer; only a ClientHello that returns a valid cookie - which proves the
194// peer receives at its address - gets a server DtlsSocket. So packets from spoofed addresses
195// can't make us keep state, or answer them with a full handshake flight (amplification).
197{
198 public:
200
201 // Handles a DTLS packet from peer (anything that identifies its address and port, eg.
202 // "192.0.2.1:5004"), which has no DtlsSocket yet. Returns a new server DtlsSocket, with the
203 // context makeContext() returns, once peer's ClientHello carries a valid cookie - the socket
204 // has already handled that ClientHello. Otherwise returns null, with response holding what
205 // to send back to peer (a HelloVerifyRequest), if anything.
206 DtlsSocket* handlePacket(const unsigned char* bytes, size_t len, const std::string& peer,
207 std::vector<unsigned char>& response,
208 const std::function<std::unique_ptr<DtlsSocketContext>()>& makeContext);
209
210 private:
211 friend class DtlsFactory;
213
214 DtlsFactory* mFactory;
215 SSL* mSsl; // the SSL DTLSv1_listen runs on, handed to the socket it creates
216 std::string mPeer; // the peer of the packet being handled, for the cookie callbacks
217};
218
219}
220#endif
221
222#endif
223/* ====================================================================
224
225 Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com
226 Copyright (c) 2007-2008, Eric Rescorla and Derek MacDonald
227 All rights reserved.
228
229 Redistribution and use in source and binary forms, with or without
230 modification, are permitted provided that the following conditions are
231 met:
232
233 1. Redistributions of source code must retain the above copyright
234 notice, this list of conditions and the following disclaimer.
235
236 2. Redistributions in binary form must reproduce the above copyright
237 notice, this list of conditions and the following disclaimer in the
238 documentation and/or other materials provided with the distribution.
239
240 3. None of the contributors names may be used to endorse or promote
241 products derived from this software without specific prior written
242 permission.
243
244 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
246 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
247 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
248 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
249 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
250 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
251 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
254 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
255
256 ==================================================================== */
struct x509_st X509
struct ssl_st SSL
static Data digest("digest")
DtlsSocket * handlePacket(const unsigned char *bytes, size_t len, const std::string &peer, std::vector< unsigned char > &response, const std::function< std::unique_ptr< DtlsSocketContext >()> &makeContext)
virtual void handshakeFailed(const char *err)=0
virtual void handshakeCompleted()=0
virtual void write(const unsigned char *data, unsigned int len)=0
virtual std::shared_ptr< std::mutex > timerLock()
bool handshakeFailed() const
std::chrono::steady_clock::duration getAge() const
static const size_t FingerprintSize
bool createSrtpSessionPolicies(srtp_policy_t &outboundPolicy, srtp_policy_t &inboundPolicy)
static void computeFingerprint(X509 *cert, char *fingerprint)
SocketType getSocketType()
static bool isFingerprintHashFunctionSupported(const char *hashFunction)
bool checkFingerprint(const char *hashFunction, const char *fingerprint)
SRTP_PROTECTION_PROFILE * getSrtpProfile()
bool getRemoteFingerprint(const char *hashFunction, char *fingerprint, size_t fingerprintSize)
void expired(DtlsSocketTimer *)
DtlsSocketContext * getSocketContext()
void getMyCertFingerprint(char *fingerprint)
bool handlePacketMaybe(const unsigned char *bytes, size_t len)
SrtpSessionKeys getSrtpSessionKeys()
bool handshakeCompleted()
std::vector< unsigned char > serverMasterSalt
std::vector< unsigned char > clientMasterKey
std::vector< unsigned char > clientMasterSalt
std::vector< unsigned char > serverMasterKey
void list()
Definition userAdmin.cxx:66