-
Notifications
You must be signed in to change notification settings - Fork 108
/
Copy pathdtls.h
288 lines (273 loc) · 8.23 KB
/
dtls.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#ifndef DTLS_H
#define DTLS_H
#include <map>
#include <string>
#include "ip.h"
#include "tools_global.h"
#if defined(HAVE_OPENSSL101) and defined(HAVE_LIBGNUTLS)
#include <openssl/ssl.h>
#else
#ifndef SSL3_MASTER_SECRET_SIZE
#define SSL3_MASTER_SECRET_SIZE 48
#endif
#endif
using namespace std;
#define DTLS_RANDOM_SIZE 32
#define DTLS_CONTENT_TYPE_HANDSHAKE 22
#define DTLS_HANDSHAKE_TYPE_CLIENT_HELLO 1
#define DTLS_HANDSHAKE_TYPE_SERVER_HELLO 2
class cDtlsLink {
public:
struct sDtlsLinkId {
vmIPport server;
vmIPport client;
sDtlsLinkId(cDtlsLink *link)
: server(link->server.ip, link->server.port),
client(link->client.ip, link->client.port) {
}
sDtlsLinkId(vmIP server_ip, vmPort server_port,
vmIP client_ip, vmPort client_port)
: server(server_ip, server_port),
client(client_ip, client_port) {
}
inline bool operator == (const sDtlsLinkId& other) const {
return(this->server == other.server &&
this->client == other.client);
}
inline bool operator < (const sDtlsLinkId& other) const {
return(this->server < other.server ||
(this->server == other.server && this->client < other.client));
}
};
struct sDtlsServerId {
vmIPport server;
sDtlsServerId(cDtlsLink *link)
: server(link->server.ip, link->server.port) {
}
sDtlsServerId(vmIP server_ip, vmPort server_port)
: server(server_ip, server_port) {
}
inline bool operator == (const sDtlsServerId& other) const {
return(this->server == other.server);
}
inline bool operator < (const sDtlsServerId& other) const {
return(this->server < other.server);
}
};
struct sDtlsClientId {
vmIPport client;
sDtlsClientId(cDtlsLink *link)
: client(link->client.ip, link->client.port) {
}
sDtlsClientId(vmIP client_ip, vmPort client_port)
: client(client_ip, client_port) {
}
inline bool operator == (const sDtlsClientId& other) const {
return(this->client == other.client);
}
inline bool operator < (const sDtlsClientId& other) const {
return(this->client < other.client);
}
};
struct sSrtpKeys {
string server_key;
string client_key;
vmIPport server;
vmIPport client;
string cipher;
inline bool operator == (const sSrtpKeys& other) const {
return(this->server_key == other.server_key &&
this->client_key == other.client_key &&
this->server == other.server &&
this->client == other.client &&
this->cipher == other.cipher);
}
};
struct sHeader {
u_int8_t content_type;
u_int16_t version;
u_int16_t epoch;
u_int16_t sequence_number_filler;
u_int32_t sequence_number;
u_int16_t length;
unsigned length_() {
return(ntohs(length));
}
} __attribute__((packed));
struct sHeaderHandshake {
u_int8_t handshake_type;
u_int8_t length_upper;
u_int16_t length;
u_int16_t message_sequence;
u_int8_t fragment_offset_upper;
u_int16_t fragment_offset;
u_int8_t fragment_length_upper;
u_int16_t fragment_length;
unsigned length_() {
return(ntohs(length) + (length_upper << 16));
}
unsigned fragment_offset_() {
return(ntohs(fragment_offset) + (fragment_offset_upper << 16));
}
unsigned fragment_length_() {
return(ntohs(fragment_length) + (fragment_length_upper << 16));
}
unsigned content_length() {
return(fragment_length_() ? fragment_length_() : length_());
}
} __attribute__((packed));
struct sHeaderHandshakeHello : public sHeaderHandshake {
u_int16_t version;
u_char random[DTLS_RANDOM_SIZE];
} __attribute__((packed));
struct sHeaderHandshakeDefragmenter {
u_int8_t handshake_type;
unsigned length;
map<unsigned, SimpleBuffer> fragments;
bool empty() {
return(fragments.size() == 0);
}
void clear() {
fragments.clear();
}
bool isComplete() {
unsigned offset = 0;
for(map<unsigned, SimpleBuffer>::iterator iter = fragments.begin(); iter != fragments.end(); iter++) {
if(offset != ((sHeaderHandshake*)iter->second.data())->fragment_offset_()) {
return(false);
}
offset += ((sHeaderHandshake*)iter->second.data())->fragment_length_();
}
return(offset == length);
}
u_char *complete() {
u_char *hs = new u_char[sizeof(sHeaderHandshake) + length];
unsigned offset = 0;
for(map<unsigned, SimpleBuffer>::iterator iter = fragments.begin(); iter != fragments.end(); iter++) {
if(!offset) {
memcpy(hs, iter->second.data(),
sizeof(sHeaderHandshake) + ((sHeaderHandshake*)iter->second.data())->fragment_length_());
offset += sizeof(sHeaderHandshake);
} else {
memcpy(hs + offset, iter->second.data() + sizeof(sHeaderHandshake),
((sHeaderHandshake*)iter->second.data())->fragment_length_());
}
offset += ((sHeaderHandshake*)iter->second.data())->fragment_length_();
}
return(hs);
}
};
enum eCipherType {
_ct_na = 0,
_ct_SRTP_AES128_CM_HMAC_SHA1_80 = 0x0001,
_ct_SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002,
_ct_SRTP_NULL_HMAC_SHA1_80 = 0x0005,
_ct_SRTP_NULL_HMAC_SHA1_32 = 0x0006,
_ct_SRTP_AEAD_AES_128_GCM = 0x0007,
_ct_SRTP_AEAD_AES_256_GCM = 0x0008
};
struct sHandshakeData {
sHandshakeData() {
client_random_set = false;
server_random_set = false;
}
void init() {
client_random_set = false;
server_random_set = false;
cipher_types.clear();
}
bool isComplete() {
return(client_random_set && server_random_set &&
cipher_types.size() > 0);
}
u_char client_random[DTLS_RANDOM_SIZE];
bool client_random_set;
u_char server_random[DTLS_RANDOM_SIZE];
bool server_random_set;
list<eCipherType> cipher_types;
};
public:
cDtlsLink(vmIP server_ip, vmPort server_port,
vmIP client_ip, vmPort client_port);
~cDtlsLink();
void processHandshake(sHeaderHandshake *handshake, u_int64_t time_us);
bool findSrtpKeys(list<sSrtpKeys*> *keys, class Call *call,
bool enable_handshake_safe, bool use_handshake_safe);
private:
void init();
void setClientRandom(u_char *client_random);
void setServerRandom(u_char *server_random);
bool findMasterSecret();
bool cipherTypeIsOK(unsigned ct) {
return(ct == _ct_SRTP_AES128_CM_HMAC_SHA1_80 ||
ct == _ct_SRTP_AES128_CM_HMAC_SHA1_32 ||
ct == _ct_SRTP_NULL_HMAC_SHA1_80 ||
ct == _ct_SRTP_NULL_HMAC_SHA1_32 ||
ct == _ct_SRTP_AEAD_AES_128_GCM ||
ct == _ct_SRTP_AEAD_AES_256_GCM);
}
bool cipherIsSupported(unsigned ct) {
return(ct == _ct_SRTP_AES128_CM_HMAC_SHA1_80 ||
ct == _ct_SRTP_AES128_CM_HMAC_SHA1_32);
}
string cipherName(unsigned ct) {
return(ct == _ct_SRTP_AES128_CM_HMAC_SHA1_80 ? "AES_CM_128_HMAC_SHA1_80" :
ct == _ct_SRTP_AES128_CM_HMAC_SHA1_32 ? "AES_CM_128_HMAC_SHA1_32" :
cipherTypeIsOK(ct) ? "unsupported" :"unknown");
}
unsigned cipherSrtpKeyLen(unsigned ct) {
return(ct == _ct_SRTP_AES128_CM_HMAC_SHA1_80 ? 16 :
ct == _ct_SRTP_AES128_CM_HMAC_SHA1_32 ? 16 :
0);
}
unsigned cipherSrtpSaltLen(unsigned /*ct*/) {
return(14);
}
private:
vmIPport server;
vmIPport client;
sHandshakeData handshake_data;
u_char master_secret[SSL3_MASTER_SECRET_SIZE];
u_int16_t master_secret_length;
u_int16_t keys_block_attempts;
u_int16_t max_keys_block_attempts;
sHeaderHandshakeDefragmenter defragmenter;
u_int64_t last_time_us;
friend class cDtls;
};
class cDtls {
public:
cDtls();
~cDtls();
void setNeedLock(bool need_lock);
bool processHandshake(vmIP src_ip, vmPort src_port,
vmIP dst_ip, vmPort dst_port,
u_char *data, unsigned data_len,
u_int64_t time_us);
bool findSrtpKeys(vmIP src_ip, vmPort src_port,
vmIP dst_ip, vmPort dst_port,
list<cDtlsLink::sSrtpKeys*> *keys,
int8_t *direction, int8_t *node,
class Call *call,
bool enable_handshake_safe, bool use_handshake_safe);
bool getHandshakeData(vmIP server_ip, vmPort server_port,
vmIP client_ip, vmPort client_port,
cDtlsLink::sHandshakeData *handshake_data);
void cleanup();
private:
void lock();
void unlock();
private:
list<cDtlsLink*> links;
map<cDtlsLink::sDtlsLinkId, cDtlsLink*> links_by_link_id;
map<cDtlsLink::sDtlsServerId, cDtlsLink*> links_by_server_id;
map<cDtlsLink::sDtlsClientId, cDtlsLink*> links_by_client_id;
int debug_flags[2];
bool need_lock;
volatile int _sync;
u_int32_t last_cleanup_at_s;
u_int32_t cleanup_interval_s;
u_int32_t link_expiration_s;
friend class RTP;
};
#endif //DTLS_H