1 /* Portions of this file are subject to the following copyright(s). See
2 * the Net-SNMP's COPYING file for more details and other copyrights
3 * that may apply:
4 */
5 /*
6 * Portions of this file are copyrighted by:
7 * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
8 * Use is subject to license terms specified in the COPYING file
9 * distributed with the Net-SNMP package.
10 */
11 /*
12 * See the following web pages for useful documentation on this transport:
13 * http://www.net-snmp.org/wiki/index.php/TUT:Using_TLS
14 * http://www.net-snmp.org/wiki/index.php/Using_DTLS
15 */
16
17 #include <net-snmp/net-snmp-config.h>
18
19 #ifdef HAVE_LIBSSL_DTLS
20
21 #include <net-snmp/net-snmp-features.h>
22
23 netsnmp_feature_require(cert_util);
24 netsnmp_feature_require(sockaddr_size);
25
26 #include <net-snmp/library/snmpIPBaseDomain.h>
27 #include <net-snmp/library/snmpDTLSUDPDomain.h>
28 #include <net-snmp/library/snmpUDPIPv6Domain.h>
29 #include <net-snmp/library/snmp_assert.h>
30
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <ctype.h>
34 #include <errno.h>
35
36 #if HAVE_STRING_H
37 #include <string.h>
38 #else
39 #include <strings.h>
40 #endif
41 #if HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
44 #if HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #if HAVE_SYS_SOCKET_H
48 #include <sys/socket.h>
49 #endif
50 #if HAVE_NETINET_IN_H
51 #include <netinet/in.h>
52 #endif
53 #if HAVE_ARPA_INET_H
54 #include <arpa/inet.h>
55 #endif
56 #if HAVE_NETDB_H
57 #include <netdb.h>
58 #endif
59 #if HAVE_SYS_UIO_H
60 #include <sys/uio.h>
61 #endif
62
63 #include "../memcheck.h"
64
65 #include <net-snmp/types.h>
66 #include <net-snmp/output_api.h>
67 #include <net-snmp/config_api.h>
68
69 #include <net-snmp/library/snmp_transport.h>
70 #include <net-snmp/library/system.h>
71 #include <net-snmp/library/tools.h>
72 #include <net-snmp/library/callback.h>
73
74 #include "openssl/bio.h"
75 #include "openssl/ssl.h"
76 #include "openssl/err.h"
77 #include "openssl/rand.h"
78
79 #include <net-snmp/library/snmpSocketBaseDomain.h>
80 #include <net-snmp/library/snmpTLSBaseDomain.h>
81 #include <net-snmp/library/snmpUDPDomain.h>
82 #include <net-snmp/library/cert_util.h>
83 #include <net-snmp/library/snmp_openssl.h>
84
85 #ifndef INADDR_NONE
86 #define INADDR_NONE -1
87 #endif
88
89 #define WE_ARE_SERVER 0
90 #define WE_ARE_CLIENT 1
91
92 oid netsnmpDTLSUDPDomain[] = { TRANSPORT_DOMAIN_DTLS_UDP_IP };
93 size_t netsnmpDTLSUDPDomain_len = OID_LENGTH(netsnmpDTLSUDPDomain);
94
95 static netsnmp_tdomain dtlsudpDomain;
96 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
97 static int openssl_addr_index6 = 0;
98 #endif
99
100 /* this stores openssl credentials for each connection since openssl
101 can't do it for us at the moment; hopefully future versions will
102 change */
103 typedef struct bio_cache_s {
104 BIO *read_bio; /* OpenSSL will read its incoming SSL packets from here */
105 BIO *write_bio; /* OpenSSL will write its outgoing SSL packets to here */
106 netsnmp_sockaddr_storage sas;
107 u_int flags;
108 struct bio_cache_s *next;
109 int msgnum;
110 char *write_cache;
111 size_t write_cache_len;
112 _netsnmpTLSBaseData *tlsdata;
113 } bio_cache;
114
115 /** bio_cache flags */
116 #define NETSNMP_BIO_HAVE_COOKIE 0x0001 /* verified cookie */
117 #define NETSNMP_BIO_CONNECTED 0x0002 /* received decoded data */
118 #define NETSNMP_BIO_DISCONNECTED 0x0004 /* peer shutdown */
119
120 static bio_cache *biocache = NULL;
121
122 static int openssl_addr_index = 0;
123
124 static int netsnmp_dtls_verify_cookie(SSL *ssl,
125 SECOND_APPVERIFY_COOKIE_CB_ARG_QUALIFIER
126 unsigned char *cookie,
127 unsigned int cookie_len);
128 static int netsnmp_dtls_gen_cookie(SSL *ssl, unsigned char *cookie,
129 unsigned int *cookie_len);
130
131 /* this stores remote connections in a list to search through */
132 /* XXX: optimize for searching */
133 /* XXX: handle state issues for new connections to reduce DOS issues */
134 /* (TLS should do this, but openssl can't do more than one ctx per sock */
135 /* XXX: put a timer on the cache for expirary purposes */
find_bio_cache(const netsnmp_sockaddr_storage * from_addr)136 static bio_cache *find_bio_cache(const netsnmp_sockaddr_storage *from_addr)
137 {
138 bio_cache *cachep = NULL;
139
140 for (cachep = biocache; cachep; cachep = cachep->next) {
141
142 if (cachep->sas.sa.sa_family != from_addr->sa.sa_family)
143 continue;
144
145 if ((from_addr->sa.sa_family == AF_INET) &&
146 ((cachep->sas.sin.sin_addr.s_addr !=
147 from_addr->sin.sin_addr.s_addr) ||
148 (cachep->sas.sin.sin_port != from_addr->sin.sin_port)))
149 continue;
150 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
151 else if ((from_addr->sa.sa_family == AF_INET6) &&
152 ((cachep->sas.sin6.sin6_port != from_addr->sin6.sin6_port) ||
153 (cachep->sas.sin6.sin6_scope_id !=
154 from_addr->sin6.sin6_scope_id) ||
155 (memcmp(cachep->sas.sin6.sin6_addr.s6_addr,
156 from_addr->sin6.sin6_addr.s6_addr,
157 sizeof(from_addr->sin6.sin6_addr.s6_addr)) != 0)))
158 continue;
159 #endif
160 /* found an existing connection */
161 break;
162 }
163 return cachep;
164 }
165
166 /* removes a single cache entry and returns SUCCESS on finding and
167 removing it. */
remove_bio_cache(bio_cache * thiscache)168 static int remove_bio_cache(bio_cache *thiscache)
169 {
170 bio_cache *cachep = NULL, *prevcache = NULL;
171
172 cachep = biocache;
173 while (cachep) {
174 if (cachep == thiscache) {
175
176 /* remove it from the list */
177 if (NULL == prevcache) {
178 /* at the first cache in the list */
179 biocache = thiscache->next;
180 } else {
181 prevcache->next = thiscache->next;
182 }
183
184 return SNMPERR_SUCCESS;
185 }
186 prevcache = cachep;
187 cachep = cachep->next;
188 }
189 return SNMPERR_GENERR;
190 }
191
192 /* frees the contents of a bio_cache */
free_bio_cache(bio_cache * cachep)193 static void free_bio_cache(bio_cache *cachep)
194 {
195 /* These are freed by the SSL_free() call */
196 /*
197 BIO_free(cachep->read_bio);
198 BIO_free(cachep->write_bio);
199 */
200 DEBUGMSGTL(("9:dtlsudp:bio_cache", "releasing %p\n", cachep));
201 SNMP_FREE(cachep->write_cache);
202 netsnmp_tlsbase_free_tlsdata(cachep->tlsdata);
203 }
204
remove_and_free_bio_cache(bio_cache * cachep)205 static void remove_and_free_bio_cache(bio_cache *cachep)
206 {
207 /** no debug, remove_bio_cache does it */
208 remove_bio_cache(cachep);
209 free_bio_cache(cachep);
210 }
211
212
213 /* XXX: lots of malloc/state cleanup needed */
214 #define DIEHERE(msg) do { snmp_log(LOG_ERR, "%s\n", msg); return NULL; } while(0)
215
216 static bio_cache *
start_new_cached_connection(netsnmp_transport * t,const netsnmp_sockaddr_storage * remote_addr,int we_are_client)217 start_new_cached_connection(netsnmp_transport *t,
218 const netsnmp_sockaddr_storage *remote_addr,
219 int we_are_client)
220 {
221 bio_cache *cachep = NULL;
222 _netsnmpTLSBaseData *tlsdata;
223
224 DEBUGTRACETOK("9:dtlsudp");
225
226 /* RFC5953: section 5.3.1, step 1:
227 1) The snmpTlstmSessionOpens counter is incremented.
228 */
229 if (we_are_client)
230 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENS);
231
232 if (!t->sock)
233 DIEHERE("no socket passed in to start_new_cached_connection\n");
234 if (!remote_addr)
235 DIEHERE("no remote_addr passed in to start_new_cached_connection\n");
236
237 cachep = SNMP_MALLOC_TYPEDEF(bio_cache);
238 if (!cachep)
239 return NULL;
240
241 /* allocate our TLS specific data */
242 if (NULL == (tlsdata = netsnmp_tlsbase_allocate_tlsdata(t, !we_are_client))) {
243 SNMP_FREE(cachep);
244 return NULL;
245 }
246 cachep->tlsdata = tlsdata;
247
248 /* RFC5953: section 5.3.1, step 1:
249 2) The client selects the appropriate certificate and cipher_suites
250 for the key agreement based on the tmSecurityName and the
251 tmRequestedSecurityLevel for the session. For sessions being
252 established as a result of a SNMP-TARGET-MIB based operation, the
253 certificate will potentially have been identified via the
254 snmpTlstmParamsTable mapping and the cipher_suites will have to
255 be taken from system-wide or implementation-specific
256 configuration. If no row in the snmpTlstmParamsTable exists then
257 implementations MAY choose to establish the connection using a
258 default client certificate available to the application.
259 Otherwise, the certificate and appropriate cipher_suites will
260 need to be passed to the openSession() ASI as supplemental
261 information or configured through an implementation-dependent
262 mechanism. It is also implementation-dependent and possibly
263 policy-dependent how tmRequestedSecurityLevel will be used to
264 influence the security capabilities provided by the (D)TLS
265 connection. However this is done, the security capabilities
266 provided by (D)TLS MUST be at least as high as the level of
267 security indicated by the tmRequestedSecurityLevel parameter.
268 The actual security level of the session is reported in the
269 tmStateReference cache as tmSecurityLevel. For (D)TLS to provide
270 strong authentication, each principal acting as a command
271 generator SHOULD have its own certificate.
272 */
273 /* Implementation notes:
274 + This Information is passed in via the transport and default
275 paremeters
276 */
277 /* see if we have base configuration to copy in to this new one */
278 if (NULL != t->data && t->data_length == sizeof(_netsnmpTLSBaseData)) {
279 _netsnmpTLSBaseData *parentdata = t->data;
280 if (parentdata->our_identity)
281 tlsdata->our_identity = strdup(parentdata->our_identity);
282 if (parentdata->their_identity)
283 tlsdata->their_identity = strdup(parentdata->their_identity);
284 if (parentdata->their_fingerprint)
285 tlsdata->their_fingerprint = strdup(parentdata->their_fingerprint);
286 if (parentdata->trust_cert)
287 tlsdata->trust_cert = strdup(parentdata->trust_cert);
288 if (parentdata->their_hostname)
289 tlsdata->their_hostname = strdup(parentdata->their_hostname);
290 }
291
292 DEBUGMSGTL(("dtlsudp", "starting a new connection\n"));
293 cachep->next = biocache;
294 biocache = cachep;
295
296 if (remote_addr->sa.sa_family == AF_INET)
297 memcpy(&cachep->sas.sin, &remote_addr->sin, sizeof(remote_addr->sin));
298 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
299 else if (remote_addr->sa.sa_family == AF_INET6)
300 memcpy(&cachep->sas.sin6, &remote_addr->sin6, sizeof(remote_addr->sin6));
301 #endif
302 else
303 DIEHERE("unknown address family");
304
305 /* create caching memory bios for OpenSSL to read and write to */
306
307 cachep->read_bio = BIO_new(BIO_s_mem()); /* openssl reads from */
308 if (!cachep->read_bio)
309 DIEHERE("failed to create the openssl read_bio");
310
311 cachep->write_bio = BIO_new(BIO_s_mem()); /* openssl writes to */
312 if (!cachep->write_bio) {
313 BIO_free(cachep->read_bio);
314 cachep->read_bio = NULL;
315 DIEHERE("failed to create the openssl write_bio");
316 }
317
318 BIO_set_mem_eof_return(cachep->read_bio, -1);
319 BIO_set_mem_eof_return(cachep->write_bio, -1);
320
321 if (we_are_client) {
322 /* we're the client */
323 DEBUGMSGTL(("dtlsudp",
324 "starting a new connection as a client to sock: %d\n",
325 t->sock));
326 tlsdata->ssl = SSL_new(sslctx_client_setup(DTLS_method(), tlsdata));
327
328 /* XXX: session setting 735 */
329 } else {
330 /* we're the server */
331 SSL_CTX *ctx = sslctx_server_setup(DTLS_method());
332 if (!ctx) {
333 BIO_free(cachep->read_bio);
334 BIO_free(cachep->write_bio);
335 cachep->read_bio = NULL;
336 cachep->write_bio = NULL;
337 DIEHERE("failed to create the SSL Context");
338 }
339
340 /* turn on cookie exchange */
341 /* Set DTLS cookie generation and verification callbacks */
342 SSL_CTX_set_cookie_generate_cb(ctx, netsnmp_dtls_gen_cookie);
343 SSL_CTX_set_cookie_verify_cb(ctx, netsnmp_dtls_verify_cookie);
344
345 tlsdata->ssl = SSL_new(ctx);
346 }
347
348 if (!tlsdata->ssl) {
349 BIO_free(cachep->read_bio);
350 BIO_free(cachep->write_bio);
351 cachep->read_bio = NULL;
352 cachep->write_bio = NULL;
353 DIEHERE("failed to create the SSL session structure");
354 }
355
356 SSL_set_mode(tlsdata->ssl, SSL_MODE_AUTO_RETRY);
357
358 /* set the bios that openssl should read from and write to */
359 /* (and we'll do the opposite) */
360 SSL_set_bio(tlsdata->ssl, cachep->read_bio, cachep->write_bio);
361
362 /* RFC5953: section 5.3.1, step 1:
363 3) Using the destTransportDomain and destTransportAddress values,
364 the client will initiate the (D)TLS handshake protocol to
365 establish session keys for message integrity and encryption.
366
367 If the attempt to establish a session is unsuccessful, then
368 snmpTlstmSessionOpenErrors is incremented, an error indication is
369 returned, and processing stops. If the session failed to open
370 because the presented server certificate was unknown or invalid
371 then the snmpTlstmSessionUnknownServerCertificate or
372 snmpTlstmSessionInvalidServerCertificates MUST be incremented and
373 a snmpTlstmServerCertificateUnknown or
374 snmpTlstmServerInvalidCertificate notification SHOULD be sent as
375 appropriate. Reasons for server certificate invalidation
376 includes, but is not limited to, cryptographic validation
377 failures and an unexpected presented certificate identity.
378 */
379 /* Implementation notes:
380 + Because we're working asynchronously the real "end" point of
381 opening a connection doesn't occur here as certificate
382 verification and other things needs to happen first in the
383 verify callback, etc. See the netsnmp_dtlsudp_recv()
384 function for the final processing.
385 */
386 /* set the SSL notion of we_are_client/server */
387 if (we_are_client)
388 SSL_set_connect_state(tlsdata->ssl);
389 else {
390 /* XXX: we need to only create cache entries when cookies succeed */
391
392 SSL_set_options(tlsdata->ssl, SSL_OP_COOKIE_EXCHANGE);
393
394 SSL_set_ex_data(tlsdata->ssl, openssl_addr_index, cachep);
395
396 SSL_set_accept_state(tlsdata->ssl);
397 }
398
399 /* RFC5953: section 5.3.1, step 1:
400 6) The TLSTM-specific session identifier (tlstmSessionID) is set in
401 the tmSessionID of the tmStateReference passed to the TLS
402 Transport Model to indicate that the session has been established
403 successfully and to point to a specific (D)TLS connection for
404 future use. The tlstmSessionID is also stored in the LCD for
405 later lookup during processing of incoming messages
406 (Section 5.1.2).
407 */
408 /* Implementation notes:
409 + our sessionID is stored as the transport's data pointer member
410 */
411 DEBUGMSGT(("9:dtlsudp:bio_cache:created", "%p\n", cachep));
412
413 return cachep;
414 }
415
416 static bio_cache *
find_or_create_bio_cache(netsnmp_transport * t,const netsnmp_sockaddr_storage * from_addr,int we_are_client)417 find_or_create_bio_cache(netsnmp_transport *t,
418 const netsnmp_sockaddr_storage *from_addr,
419 int we_are_client)
420 {
421 bio_cache *cachep = find_bio_cache(from_addr);
422
423 if (NULL == cachep) {
424 /* none found; need to start a new context */
425 cachep = start_new_cached_connection(t, from_addr, we_are_client);
426 if (NULL == cachep) {
427 snmp_log(LOG_ERR, "failed to open a new dtls connection\n");
428 }
429 } else {
430 DEBUGMSGT(("9:dtlsudp:bio_cache:found", "%p\n", cachep));
431 }
432 return cachep;
433 }
434
435 static const netsnmp_indexed_addr_pair *
_extract_addr_pair(netsnmp_transport * t,const void * opaque,int olen)436 _extract_addr_pair(netsnmp_transport *t, const void *opaque, int olen)
437 {
438 if (opaque) {
439 switch (olen) {
440 case sizeof(netsnmp_tmStateReference): {
441 const netsnmp_tmStateReference *tmStateRef = opaque;
442
443 if (tmStateRef->have_addresses)
444 return &tmStateRef->addresses;
445 break;
446 }
447 default:
448 netsnmp_assert(0);
449 }
450 }
451 if (t && t->data) {
452 switch (t->data_length) {
453 case sizeof(netsnmp_indexed_addr_pair):
454 return t->data;
455 case sizeof(_netsnmpTLSBaseData): {
456 _netsnmpTLSBaseData *tlsdata = t->data;
457
458 return tlsdata->addr;
459 }
460 default:
461 netsnmp_assert(0);
462 }
463 }
464
465 return NULL;
466 }
467
468 static const struct sockaddr *
_find_remote_sockaddr(netsnmp_transport * t,const void * opaque,int olen,int * socklen)469 _find_remote_sockaddr(netsnmp_transport *t, const void *opaque, int olen,
470 int *socklen)
471 {
472 const netsnmp_indexed_addr_pair *addr_pair;
473 const struct sockaddr *sa = NULL;
474
475 addr_pair = _extract_addr_pair(t, opaque, olen);
476 if (NULL == addr_pair)
477 return NULL;
478
479 sa = &addr_pair->remote_addr.sa;
480 *socklen = netsnmp_sockaddr_size(sa);
481 return sa;
482 }
483
484
485 /*
486 * Reads data from our internal openssl outgoing BIO and sends any
487 * queued packets out the UDP port
488 */
489 static int
_netsnmp_send_queued_dtls_pkts(netsnmp_transport * t,bio_cache * cachep)490 _netsnmp_send_queued_dtls_pkts(netsnmp_transport *t, bio_cache *cachep)
491 {
492 int outsize, rc2;
493 void *outbuf;
494
495 DEBUGTRACETOK("9:dtlsudp");
496
497 /* for memory bios, we now read from openssl's write
498 buffer (ie, the packet to go out) and send it out
499 the udp port manually */
500
501 outsize = BIO_ctrl_pending(cachep->write_bio);
502 outbuf = malloc(outsize);
503 if (outsize > 0 && outbuf) {
504 int socksize;
505 void *sa;
506
507 DEBUGMSGTL(("dtlsudp", "have %d bytes to send\n", outsize));
508
509 outsize = BIO_read(cachep->write_bio, outbuf, outsize);
510 MAKE_MEM_DEFINED(outbuf, outsize);
511 sa = NETSNMP_REMOVE_CONST(struct sockaddr *,
512 _find_remote_sockaddr(t, NULL, 0, &socksize));
513 if (NULL == sa)
514 sa = &cachep->sas.sa;
515 socksize = netsnmp_sockaddr_size(sa);
516 rc2 = t->base_transport->f_send(t, outbuf, outsize, &sa, &socksize);
517 if (rc2 == -1) {
518 snmp_log(LOG_ERR, "failed to send a DTLS specific packet\n");
519 }
520 } else if (outsize == 0) {
521 DEBUGMSGTL(("9:dtlsudp", "have 0 bytes to send\n"));
522 } else {
523 DEBUGMSGTL(("9:dtlsudp", "buffer allocation failed\n"));
524 }
525
526 free(outbuf);
527
528 return outsize;
529 }
530
531 /*
532 * If we have any outgoing SNMP data queued that OpenSSL/DTLS couldn't send
533 * (likely due to DTLS control packets needing to go out first)
534 * then this function attempts to send them.
535 */
536 /* returns SNMPERR_SUCCESS if we succeeded in getting the data out */
537 /* returns SNMPERR_GENERR if we still need more time */
538 static int
_netsnmp_bio_try_and_write_buffered(netsnmp_transport * t,bio_cache * cachep)539 _netsnmp_bio_try_and_write_buffered(netsnmp_transport *t, bio_cache *cachep)
540 {
541 int rc;
542 _netsnmpTLSBaseData *tlsdata;
543
544 DEBUGTRACETOK("9:dtlsudp");
545
546 tlsdata = cachep->tlsdata;
547
548 /* make sure we have something to write */
549 if (!cachep->write_cache || cachep->write_cache_len == 0)
550 return SNMPERR_SUCCESS;
551
552 DEBUGMSGTL(("dtlsudp", "Trying to write %" NETSNMP_PRIz "d of buffered data\n",
553 cachep->write_cache_len));
554
555 /* try and write out the cached data */
556 rc = SSL_write(tlsdata->ssl, cachep->write_cache, cachep->write_cache_len);
557
558 while (rc == -1) {
559 int errnum = SSL_get_error(tlsdata->ssl, rc);
560 int bytesout;
561
562 /* don't treat want_read/write errors as real errors */
563 if (errnum != SSL_ERROR_WANT_READ &&
564 errnum != SSL_ERROR_WANT_WRITE) {
565 DEBUGMSGTL(("dtlsudp", "ssl_write error (of buffered data)\n"));
566 _openssl_log_error(rc, tlsdata->ssl, "SSL_write");
567 return SNMPERR_GENERR;
568 }
569
570 /* check to see if we have outgoing DTLS packets to send */
571 /* (SSL_write could have created DTLS control packets) */
572 bytesout = _netsnmp_send_queued_dtls_pkts(t, cachep);
573
574 /* If want_read/write but failed to actually send anything
575 then we need to wait for the other side, so quit */
576 if (bytesout <= 0) {
577 /* sending failed; must wait longer */
578 return SNMPERR_GENERR;
579 }
580
581 /* retry writing */
582 DEBUGMSGTL(("9:dtlsudp", "recalling ssl_write\n"));
583 rc = SSL_write(tlsdata->ssl, cachep->write_cache,
584 cachep->write_cache_len);
585 }
586
587 if (rc > 0)
588 cachep->msgnum++;
589
590 if (_netsnmp_send_queued_dtls_pkts(t, cachep) > 0) {
591 SNMP_FREE(cachep->write_cache);
592 cachep->write_cache_len = 0;
593 DEBUGMSGTL(("dtlsudp", " Write was successful\n"));
594 return SNMPERR_SUCCESS;
595 }
596 DEBUGMSGTL(("dtlsudp", " failed to send over UDP socket\n"));
597 return SNMPERR_GENERR;
598 }
599
600 static int
_netsnmp_add_buffered_data(bio_cache * cachep,const char * buf,size_t size)601 _netsnmp_add_buffered_data(bio_cache *cachep, const char *buf, size_t size)
602 {
603 if (cachep->write_cache && cachep->write_cache_len > 0) {
604 size_t newsize = cachep->write_cache_len + size;
605
606 char *newbuf = realloc(cachep->write_cache, newsize);
607 if (NULL == newbuf) {
608 /* ack! malloc failure */
609 /* XXX: free and close */
610 return SNMPERR_GENERR;
611 }
612 cachep->write_cache = newbuf;
613
614 /* write the new packet to the end */
615 memcpy(cachep->write_cache + cachep->write_cache_len,
616 buf, size);
617 cachep->write_cache_len = newsize;
618 } else {
619 cachep->write_cache = netsnmp_memdup(buf, size);
620 if (!cachep->write_cache) {
621 /* ack! malloc failure */
622 /* XXX: free and close */
623 return SNMPERR_GENERR;
624 }
625 cachep->write_cache_len = size;
626 }
627 return SNMPERR_SUCCESS;
628 }
629
630 static int
netsnmp_dtlsudp_recv(netsnmp_transport * t,void * buf,int size,void ** opaque,int * olength)631 netsnmp_dtlsudp_recv(netsnmp_transport *t, void *buf, int size,
632 void **opaque, int *olength)
633 {
634 int rc = -1;
635 netsnmp_indexed_addr_pair *addr_pair = NULL;
636 netsnmp_tmStateReference *tmStateRef = NULL;
637 _netsnmpTLSBaseData *tlsdata;
638 bio_cache *cachep;
639
640 DEBUGTRACETOK("9:dtlsudp");
641
642 if (NULL == t || t->sock == 0)
643 return -1;
644
645 /* create a tmStateRef cache for slow fill-in */
646 tmStateRef = SNMP_MALLOC_TYPEDEF(netsnmp_tmStateReference);
647
648 if (tmStateRef == NULL) {
649 *opaque = NULL;
650 *olength = 0;
651 return -1;
652 }
653
654 /* Set the transportDomain */
655 memcpy(tmStateRef->transportDomain,
656 netsnmpDTLSUDPDomain, sizeof(netsnmpDTLSUDPDomain[0]) *
657 netsnmpDTLSUDPDomain_len);
658 tmStateRef->transportDomainLen = netsnmpDTLSUDPDomain_len;
659
660 addr_pair = &tmStateRef->addresses;
661 tmStateRef->have_addresses = 1;
662
663 while (rc < 0) {
664 void *opaque = NULL;
665 int olen;
666 rc = t->base_transport->f_recv(t, buf, size, &opaque, &olen);
667 if (rc > 0) {
668 if (olen > sizeof(*addr_pair))
669 snmp_log(LOG_ERR, "%s: from address length %d > %d\n",
670 __func__, olen, (int)sizeof(*addr_pair));
671 memcpy(addr_pair, opaque, SNMP_MIN(sizeof(*addr_pair), olen));
672 }
673 SNMP_FREE(opaque);
674 if (rc < 0 && errno != EINTR) {
675 break;
676 }
677 }
678
679 DEBUGMSGTL(("dtlsudp", "received %d raw bytes on way to dtls\n", rc));
680 if (rc < 0) {
681 DEBUGMSGTL(("dtlsudp", "recvfrom fd %d err %d (\"%s\")\n",
682 t->sock, errno, strerror(errno)));
683 SNMP_FREE(tmStateRef);
684 return -1;
685 }
686
687 /* now that we have the from address filled in, we can look up
688 the openssl context and have openssl read and process
689 appropriately */
690
691 /* RFC5953: section 5.1, step 1:
692 1) Determine the tlstmSessionID for the incoming message. The
693 tlstmSessionID MUST be a unique session identifier for this
694 (D)TLS connection. The contents and format of this identifier
695 are implementation-dependent as long as it is unique to the
696 session. A session identifier MUST NOT be reused until all
697 references to it are no longer in use. The tmSessionID is equal
698 to the tlstmSessionID discussed in Section 5.1.1. tmSessionID
699 refers to the session identifier when stored in the
700 tmStateReference and tlstmSessionID refers to the session
701 identifier when stored in the LCD. They MUST always be equal
702 when processing a given session's traffic.
703
704 If this is the first message received through this session and
705 the session does not have an assigned tlstmSessionID yet then the
706 snmpTlstmSessionAccepts counter is incremented and a
707 tlstmSessionID for the session is created. This will only happen
708 on the server side of a connection because a client would have
709 already assigned a tlstmSessionID during the openSession()
710 invocation. Implementations may have performed the procedures
711 described in Section 5.3.2 prior to this point or they may
712 perform them now, but the procedures described in Section 5.3.2
713 MUST be performed before continuing beyond this point.
714 */
715
716 /* RFC5953: section 5.1, step 2:
717 2) Create a tmStateReference cache for the subsequent reference and
718 assign the following values within it:
719
720 tmTransportDomain = snmpTLSTCPDomain or snmpDTLSUDPDomain as
721 appropriate.
722
723 tmTransportAddress = The address the message originated from.
724
725 tmSecurityLevel = The derived tmSecurityLevel for the session,
726 as discussed in Section 3.1.2 and Section 5.3.
727
728 tmSecurityName = The derived tmSecurityName for the session as
729 discussed in Section 5.3. This value MUST be constant during
730 the lifetime of the session.
731
732 tmSessionID = The tlstmSessionID described in step 1 above.
733 */
734
735 /* if we don't have a cachep for this connection then
736 we're receiving something new and are the server
737 side */
738 cachep =
739 find_or_create_bio_cache(t, &addr_pair->remote_addr, WE_ARE_SERVER);
740 if (NULL == cachep) {
741 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONACCEPTS);
742 SNMP_FREE(tmStateRef);
743 return -1;
744 }
745 tlsdata = cachep->tlsdata;
746 if (NULL == tlsdata->ssl) {
747 /*
748 * this happens when the server starts but doesn't have an
749 * identity and a client connects...
750 */
751 snmp_log(LOG_ERR,
752 "DTLSUDP: missing tlsdata!\n");
753 /*snmp_increment_statistic( XXX-rks ??? );*/
754 SNMP_FREE(tmStateRef);
755 return -1;
756 }
757
758 /* Implementation notes:
759 - we use the t->data memory pointer as the session ID
760 - the transport domain is already the correct type if we got here
761 - if we don't have a session yet (eg, no tmSessionID from the
762 specs) then we create one automatically here.
763 */
764
765 /* write the received buffer to the memory-based input bio */
766 BIO_write(cachep->read_bio, buf, rc);
767
768 /* RFC5953: section 5.1, step 3:
769 3) The incomingMessage and incomingMessageLength are assigned values
770 from the (D)TLS processing.
771 */
772 /* Implementation notes:
773 + rc = incomingMessageLength
774 + buf = IncomingMessage
775 */
776
777 /* XXX: in Wes' other example we do a SSL_pending() call
778 too to ensure we're ready to read... it's possible
779 that buffered stuff in openssl won't be caught by the
780 net-snmp select loop because it's already been pulled
781 out; need to deal with this) */
782 rc = SSL_read(tlsdata->ssl, buf, size);
783 MAKE_MEM_DEFINED(&rc, sizeof(rc));
784 if (rc > 0)
785 MAKE_MEM_DEFINED(buf, rc);
786
787 /*
788 * moved netsnmp_openssl_null_checks to netsnmp_tlsbase_wrapup_recv.
789 * currently netsnmp_tlsbase_wrapup_recv is where we check for
790 * algorithm compliance, but we (sometimes) know the algorithms
791 * at this point, so we could bail earlier (here)...
792 */
793
794 while (rc == -1) {
795 int errnum = SSL_get_error(tlsdata->ssl, rc);
796 int bytesout;
797
798 /* don't treat want_read/write errors as real errors */
799 if (errnum != SSL_ERROR_WANT_READ &&
800 errnum != SSL_ERROR_WANT_WRITE) {
801 _openssl_log_error(rc, tlsdata->ssl, "SSL_read");
802 break;
803 }
804
805 /* check to see if we have outgoing DTLS packets to send */
806 /* (SSL_read could have created DTLS control packets) */
807 bytesout = _netsnmp_send_queued_dtls_pkts(t, cachep);
808
809 /* If want_read/write but failed to actually send
810 anything then we need to wait for the other side,
811 so quit */
812 if (bytesout <= 0)
813 break;
814
815 /* retry reading */
816 DEBUGMSGTL(("9:dtlsudp", "recalling ssl_read\n"));
817 rc = SSL_read(tlsdata->ssl, buf, size);
818 MAKE_MEM_DEFINED(&rc, sizeof(rc));
819 if (rc > 0)
820 MAKE_MEM_DEFINED(buf, rc);
821 }
822
823 if (rc == -1) {
824 SNMP_FREE(tmStateRef);
825
826 DEBUGMSGTL(("9:dtlsudp", "no decoded data from dtls\n"));
827
828 if (SSL_get_error(tlsdata->ssl, rc) == SSL_ERROR_WANT_READ) {
829 DEBUGMSGTL(("9:dtlsudp", "ssl error want read\n"));
830
831 /* see if we have buffered write date to send out first */
832 if (cachep->write_cache) {
833 _netsnmp_bio_try_and_write_buffered(t, cachep);
834 /* XXX: check error or not here? */
835 /* (what would we do differently?) */
836 }
837
838 rc = -1; /* XXX: it's ok, but what's the right return? */
839 }
840 else
841 _openssl_log_error(rc, tlsdata->ssl, "SSL_read");
842
843 #if 0 /* to dump cache if we don't have a cookie, this is where to do it */
844 if (!(cachep->flags & NETSNMP_BIO_HAVE_COOKIE))
845 remove_and_free_bio_cache(cachep);
846 #endif
847 return rc;
848 }
849
850 DEBUGMSGTL(("dtlsudp", "received %d decoded bytes from dtls\n", rc));
851
852 if ((0 == rc) && (SSL_get_shutdown(tlsdata->ssl) & SSL_RECEIVED_SHUTDOWN)) {
853 DEBUGMSGTL(("dtlsudp", "peer disconnected\n"));
854 cachep->flags |= NETSNMP_BIO_DISCONNECTED;
855 remove_and_free_bio_cache(cachep);
856 SNMP_FREE(tmStateRef);
857 return rc;
858 }
859 cachep->flags |= NETSNMP_BIO_CONNECTED;
860
861 /* Until we've locally assured ourselves that all is well in
862 certificate-verification-land we need to be prepared to stop
863 here and ensure all our required checks have been done. */
864 if (0 == (tlsdata->flags & NETSNMP_TLSBASE_CERT_FP_VERIFIED)) {
865 int verifyresult;
866
867 if (tlsdata->flags & NETSNMP_TLSBASE_IS_CLIENT) {
868
869 /* verify that the server's certificate is the correct one */
870
871 /* RFC5953: section 5.3.1, step 1:
872 3) Using the destTransportDomain and
873 destTransportAddress values, the client will
874 initiate the (D)TLS handshake protocol to establish
875 session keys for message integrity and encryption.
876
877 If the attempt to establish a session is
878 unsuccessful, then snmpTlstmSessionOpenErrors is
879 incremented, an error indication is returned, and
880 processing stops. If the session failed to open
881 because the presented server certificate was
882 unknown or invalid then the
883 snmpTlstmSessionUnknownServerCertificate or
884 snmpTlstmSessionInvalidServerCertificates MUST be
885 incremented and a snmpTlstmServerCertificateUnknown
886 or snmpTlstmServerInvalidCertificate notification
887 SHOULD be sent as appropriate. Reasons for server
888 certificate invalidation includes, but is not
889 limited to, cryptographic validation failures and
890 an unexpected presented certificate identity.
891 */
892 /* RFC5953: section 5.3.1, step 1:
893 4) The (D)TLS client MUST then verify that the (D)TLS
894 server's presented certificate is the expected
895 certificate. The (D)TLS client MUST NOT transmit
896 SNMP messages until the server certificate has been
897 authenticated, the client certificate has been
898 transmitted and the TLS connection has been fully
899 established.
900
901 If the connection is being established from
902 configuration based on SNMP-TARGET-MIB
903 configuration, then the snmpTlstmAddrTable
904 DESCRIPTION clause describes how the verification
905 is done (using either a certificate fingerprint, or
906 an identity authenticated via certification path
907 validation).
908
909 If the connection is being established for reasons
910 other than configuration found in the
911 SNMP-TARGET-MIB then configuration and procedures
912 outside the scope of this document should be
913 followed. Configuration mechanisms SHOULD be
914 similar in nature to those defined in the
915 snmpTlstmAddrTable to ensure consistency across
916 management configuration systems. For example, a
917 command-line tool for generating SNMP GETs might
918 support specifying either the server's certificate
919 fingerprint or the expected host name as a command
920 line argument.
921 */
922 /* RFC5953: section 5.3.1, step 1:
923 5) (D)TLS provides assurance that the authenticated
924 identity has been signed by a trusted configured
925 certification authority. If verification of the
926 server's certificate fails in any way (for example
927 because of failures in cryptographic verification
928 or the presented identity did not match the
929 expected named entity) then the session
930 establishment MUST fail, the
931 snmpTlstmSessionInvalidServerCertificates object is
932 incremented. If the session can not be opened for
933 any reason at all, including cryptographic
934 verification failures and snmpTlstmCertToTSNTable
935 lookup failures, then the
936 snmpTlstmSessionOpenErrors counter is incremented
937 and processing stops.
938 */
939
940 /* Implementation notes:
941 + in the following function the server's certificate and
942 presented commonname or subjectAltName is checked
943 according to the rules in the snmpTlstmAddrTable.
944 */
945 if ((verifyresult = netsnmp_tlsbase_verify_server_cert(tlsdata->ssl, tlsdata))
946 != SNMPERR_SUCCESS) {
947 if (verifyresult == SNMPERR_TLS_NO_CERTIFICATE) {
948 /* assume we simply haven't received it yet and there
949 is more data to wait-for or send */
950 /* XXX: probably need to check for whether we should
951 send stuff from our end to continue the transaction
952 */
953 SNMP_FREE(tmStateRef);
954 return -1;
955 } else {
956 /* XXX: free needed memory */
957 snmp_log(LOG_ERR,
958 "DTLSUDP: failed to verify ssl certificate (of the server)\n");
959 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONUNKNOWNSERVERCERTIFICATE);
960 /* Step 5 says these are always incremented */
961 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDSERVERCERTIFICATES);
962 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
963 SNMP_FREE(tmStateRef);
964 return -1;
965 }
966 }
967 tlsdata->flags |= NETSNMP_TLSBASE_CERT_FP_VERIFIED;
968 DEBUGMSGTL(("dtlsudp", "Verified the server's certificate\n"));
969 } else {
970 #ifndef NETSNMP_NO_LISTEN_SUPPORT
971 /* verify that the client's certificate is the correct one */
972
973 if ((verifyresult = netsnmp_tlsbase_verify_client_cert(tlsdata->ssl, tlsdata))
974 != SNMPERR_SUCCESS) {
975 if (verifyresult == SNMPERR_TLS_NO_CERTIFICATE) {
976 /* assume we simply haven't received it yet and there
977 is more data to wait-for or send */
978 /* XXX: probably need to check for whether we should
979 send stuff from our end to continue the transaction
980 */
981 SNMP_FREE(tmStateRef);
982 return -1;
983 } else {
984 /* XXX: free needed memory */
985 snmp_log(LOG_ERR,
986 "DTLSUDP: failed to verify ssl certificate (of the client)\n");
987 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCLIENTCERTIFICATES);
988 SNMP_FREE(tmStateRef);
989 return -1;
990 }
991 }
992 tlsdata->flags |= NETSNMP_TLSBASE_CERT_FP_VERIFIED;
993 DEBUGMSGTL(("dtlsudp", "Verified the client's certificate\n"));
994 #else /* NETSNMP_NO_LISTEN_SUPPORT */
995 return NULL;
996 #endif /* NETSNMP_NO_LISTEN_SUPPORT */
997 }
998 }
999
1000 if (rc > 0)
1001 cachep->msgnum++;
1002
1003 if (BIO_ctrl_pending(cachep->write_bio) > 0) {
1004 _netsnmp_send_queued_dtls_pkts(t, cachep);
1005 }
1006
1007 DEBUGIF ("9:dtlsudp") {
1008 char *str =
1009 t->base_transport->f_fmtaddr(t, addr_pair,
1010 sizeof(netsnmp_indexed_addr_pair));
1011 DEBUGMSGTL(("9:dtlsudp",
1012 "recvfrom fd %d got %d bytes (from %s)\n",
1013 t->sock, rc, str));
1014 free(str);
1015 }
1016
1017 /* see if we have buffered write date to send out first */
1018 if (cachep->write_cache) {
1019 if (SNMPERR_GENERR ==
1020 _netsnmp_bio_try_and_write_buffered(t, cachep)) {
1021 /* we still have data that can't get out in the buffer */
1022 /* XXX: nothing to do here? */
1023 }
1024 }
1025
1026 if (netsnmp_tlsbase_wrapup_recv(tmStateRef, tlsdata, opaque, olength) !=
1027 SNMPERR_SUCCESS)
1028 return SNMPERR_GENERR;
1029
1030 /* RFC5953: section 5.1, step 4:
1031 4) The TLS Transport Model passes the transportDomain,
1032 transportAddress, incomingMessage, and incomingMessageLength to
1033 the Dispatcher using the receiveMessage ASI:
1034
1035 statusInformation =
1036 receiveMessage(
1037 IN transportDomain -- snmpTLSTCPDomain or snmpDTLSUDPDomain,
1038 IN transportAddress -- address for the received message
1039 IN incomingMessage -- the whole SNMP message from (D)TLS
1040 IN incomingMessageLength -- the length of the SNMP message
1041 IN tmStateReference -- transport info
1042 )
1043 */
1044 /* Implementation notes: those parameters are all passed outward
1045 using the functions arguments and the return code below (the length) */
1046
1047 return rc;
1048 }
1049
1050
1051
1052 static int
netsnmp_dtlsudp_send(netsnmp_transport * t,const void * buf,int size,void ** opaque,int * olength)1053 netsnmp_dtlsudp_send(netsnmp_transport *t, const void *buf, int size,
1054 void **opaque, int *olength)
1055 {
1056 int rc = -1;
1057 const netsnmp_indexed_addr_pair *addr_pair = NULL;
1058 bio_cache *cachep = NULL;
1059 const netsnmp_tmStateReference *tmStateRef = NULL;
1060 void *outbuf;
1061 _netsnmpTLSBaseData *tlsdata = NULL;
1062 int socksize;
1063 void *sa;
1064
1065 DEBUGTRACETOK("9:dtlsudp");
1066 DEBUGMSGTL(("dtlsudp", "sending %d bytes\n", size));
1067
1068 if (NULL == t || t->sock <= 0) {
1069 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCACHES);
1070 snmp_log(LOG_ERR, "invalid netsnmp_dtlsudp_send usage\n");
1071 return -1;
1072 }
1073
1074 /* determine remote addresses */
1075 addr_pair = _extract_addr_pair(t, opaque ? *opaque : NULL,
1076 olength ? *olength : 0);
1077 if (NULL == addr_pair) {
1078 /* RFC5953: section 5.2, step 1:
1079 1) If tmStateReference does not refer to a cache containing values
1080 for tmTransportDomain, tmTransportAddress, tmSecurityName,
1081 tmRequestedSecurityLevel, and tmSameSecurity, then increment the
1082 snmpTlstmSessionInvalidCaches counter, discard the message, and
1083 return the error indication in the statusInformation. Processing
1084 of this message stops.
1085 */
1086 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCACHES);
1087 snmp_log(LOG_ERR, "dtlsudp_send: can't get address to send to\n");
1088 return -1;
1089 }
1090
1091 /* RFC5953: section 5.2, step 2:
1092 2) Extract the tmSessionID, tmTransportDomain, tmTransportAddress,
1093 tmSecurityName, tmRequestedSecurityLevel, and tmSameSecurity
1094 values from the tmStateReference. Note: The tmSessionID value
1095 may be undefined if no session exists yet over which the message
1096 can be sent.
1097 */
1098 /* Implementation notes:
1099 - we use the t->data memory pointer as the session ID
1100 - the transport domain is already the correct type if we got here
1101 - if we don't have a session yet (eg, no tmSessionID from the
1102 specs) then we create one automatically here.
1103 */
1104 if (opaque != NULL && *opaque != NULL &&
1105 olength != NULL && *olength == sizeof(netsnmp_tmStateReference))
1106 tmStateRef = *opaque;
1107
1108
1109 /* RFC5953: section 5.2, step 3:
1110 3) If tmSameSecurity is true and either tmSessionID is undefined or
1111 refers to a session that is no longer open then increment the
1112 snmpTlstmSessionNoSessions counter, discard the message and
1113 return the error indication in the statusInformation. Processing
1114 of this message stops.
1115 */
1116 /* RFC5953: section 5.2, step 4:
1117 4) If tmSameSecurity is false and tmSessionID refers to a session
1118 that is no longer available then an implementation SHOULD open a
1119 new session using the openSession() ASI (described in greater
1120 detail in step 5b). Instead of opening a new session an
1121 implementation MAY return a snmpTlstmSessionNoSessions error to
1122 the calling module and stop processing of the message.
1123 */
1124 /* Implementation Notes:
1125 - We would never get here if the sessionID was different. We
1126 tie packets directly to the transport object and it could
1127 never be sent back over a different transport, which is what
1128 the above text is trying to prevent.
1129 - Auto-connections are handled higher in the Net-SNMP library stack
1130 */
1131
1132 /* RFC5953: section 5.2, step 5:
1133 5) If tmSessionID is undefined, then use tmTransportDomain,
1134 tmTransportAddress, tmSecurityName and tmRequestedSecurityLevel
1135 to see if there is a corresponding entry in the LCD suitable to
1136 send the message over.
1137
1138 5a) If there is a corresponding LCD entry, then this session
1139 will be used to send the message.
1140
1141 5b) If there is no corresponding LCD entry, then open a session
1142 using the openSession() ASI (discussed further in
1143 Section 5.3.1). Implementations MAY wish to offer message
1144 buffering to prevent redundant openSession() calls for the
1145 same cache entry. If an error is returned from
1146 openSession(), then discard the message, discard the
1147 tmStateReference, increment the snmpTlstmSessionOpenErrors,
1148 return an error indication to the calling module and stop
1149 processing of the message.
1150 */
1151
1152 /* we're always a client if we're sending to something unknown yet */
1153 if (NULL ==
1154 (cachep = find_or_create_bio_cache(t, &addr_pair->remote_addr,
1155 WE_ARE_CLIENT))) {
1156 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
1157 return -1;
1158 }
1159
1160 tlsdata = cachep->tlsdata;
1161 if (NULL == tlsdata || NULL == tlsdata->ssl) {
1162 /** xxx mem leak? free created bio cache? */
1163 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONNOSESSIONS);
1164 snmp_log(LOG_ERR, "bad tls data or ssl ptr in netsnmp_dtlsudp_send\n");
1165 return -1;
1166 }
1167
1168 if (!tlsdata->securityName && tmStateRef &&
1169 tmStateRef->securityNameLen > 0) {
1170 tlsdata->securityName = strdup(tmStateRef->securityName);
1171 }
1172
1173 /* see if we have previous outgoing data to send */
1174 if (cachep->write_cache) {
1175 if (SNMPERR_GENERR == _netsnmp_bio_try_and_write_buffered(t, cachep)) {
1176 /* we still have data that can't get out in the buffer */
1177
1178 DEBUGIF ("9:dtlsudp") {
1179 char *str = t->base_transport->f_fmtaddr(t, addr_pair,
1180 sizeof(netsnmp_indexed_addr_pair));
1181 DEBUGMSGTL(("9:dtlsudp", "cached %d bytes for %s on fd %d\n",
1182 size, str, t->sock));
1183 free(str);
1184 }
1185
1186 /* add the new data to the end of the existing cache */
1187 if (_netsnmp_add_buffered_data(cachep, buf, size) !=
1188 SNMPERR_SUCCESS) {
1189 /* XXX: free and close */
1190 }
1191 return -1;
1192 }
1193 }
1194
1195 DEBUGIF ("9:dtlsudp") {
1196 char *str = t->base_transport->f_fmtaddr(t, addr_pair,
1197 sizeof(netsnmp_indexed_addr_pair));
1198 DEBUGMSGTL(("9:dtlsudp", "send %d bytes from %p to %s on fd %d\n",
1199 size, buf, str, t->sock));
1200 free(str);
1201 }
1202
1203 /* RFC5953: section 5.2, step 6:
1204 6) Using either the session indicated by the tmSessionID if there
1205 was one or the session resulting from a previous step (4 or 5),
1206 pass the outgoingMessage to (D)TLS for encapsulation and
1207 transmission.
1208 */
1209 rc = SSL_write(tlsdata->ssl, buf, size);
1210
1211 while (rc == -1) {
1212 int bytesout;
1213 int errnum = SSL_get_error(tlsdata->ssl, rc);
1214
1215 /* don't treat want_read/write errors as real errors */
1216 if (errnum != SSL_ERROR_WANT_READ &&
1217 errnum != SSL_ERROR_WANT_WRITE) {
1218 DEBUGMSGTL(("dtlsudp", "ssl_write error\n"));
1219 _openssl_log_error(rc, tlsdata->ssl, "SSL_write");
1220 break;
1221 }
1222
1223 /* check to see if we have outgoing DTLS packets to send */
1224 /* (SSL_read could have created DTLS control packets) */
1225 bytesout = _netsnmp_send_queued_dtls_pkts(t, cachep);
1226
1227 /* If want_read/write but failed to actually send
1228 anything then we need to wait for the other side,
1229 so quit */
1230 if (bytesout <= 0) {
1231 /* We need more data written to or read from the socket
1232 but we're failing to do so and need to wait till the
1233 socket is ready again; unfortunately this means we need
1234 to buffer the SNMP data temporarily in the mean time */
1235
1236 DEBUGMSGTL(("9:dtlsudp", "cached %d bytes for fd %d\n", size,
1237 t->sock));
1238
1239 /* remember the packet */
1240 if (_netsnmp_add_buffered_data(cachep, buf, size) !=
1241 SNMPERR_SUCCESS) {
1242
1243 /* XXX: free and close */
1244 return -1;
1245 }
1246
1247 /* exit out of the loop until we get called again from
1248 socket data */
1249 break;
1250 }
1251 DEBUGMSGTL(("9:dtlsudp", "recalling ssl_write\n"));
1252 rc = SSL_write(tlsdata->ssl, buf, size);
1253 }
1254
1255 if (rc > 0)
1256 cachep->msgnum++;
1257
1258 /* for memory bios, we now read from openssl's write buffer (ie,
1259 the packet to go out) and send it out the udp port manually */
1260 rc = BIO_ctrl_pending(cachep->write_bio);
1261 if (rc <= 0) {
1262 /* in theory an ok thing */
1263 return 0;
1264 }
1265 outbuf = malloc(rc);
1266 if (!outbuf)
1267 return -1;
1268 rc = BIO_read(cachep->write_bio, outbuf, rc);
1269 MAKE_MEM_DEFINED(outbuf, rc);
1270 socksize = netsnmp_sockaddr_size(&cachep->sas.sa);
1271 sa = &cachep->sas.sa;
1272 rc = t->base_transport->f_send(t, outbuf, rc, &sa, &socksize);
1273 free(outbuf);
1274
1275 return rc;
1276 }
1277
1278
1279
1280 static int
netsnmp_dtlsudp_close(netsnmp_transport * t)1281 netsnmp_dtlsudp_close(netsnmp_transport *t)
1282 {
1283 /* XXX: issue a proper dtls closure notification(s) */
1284
1285 bio_cache *cachep = NULL;
1286 _netsnmpTLSBaseData *tlsbase = NULL;
1287
1288 DEBUGTRACETOK("9:dtlsudp");
1289
1290 DEBUGMSGTL(("dtlsudp:close", "closing dtlsudp transport %p\n", t));
1291
1292 /* RFC5953: section 5.4, step 1:
1293 1) Increment either the snmpTlstmSessionClientCloses or the
1294 snmpTlstmSessionServerCloses counter as appropriate.
1295 */
1296 snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONCLIENTCLOSES);
1297
1298 /* RFC5953: section 5.4, step 2:
1299 2) Look up the session using the tmSessionID.
1300 */
1301 /* Implementation notes:
1302 + Our session id is stored as the t->data pointer
1303 */
1304 if (NULL != t->data && t->data_length == sizeof(_netsnmpTLSBaseData)) {
1305 tlsbase = t->data;
1306
1307 if (tlsbase->addr)
1308 cachep = find_bio_cache(&tlsbase->addr->remote_addr);
1309 }
1310
1311 /* RFC5953: section 5.4, step 3:
1312 3) If there is no open session associated with the tmSessionID, then
1313 closeSession processing is completed.
1314 */
1315 if (NULL == cachep)
1316 return netsnmp_socketbase_close(t);
1317
1318 /* if we have any remaining packets to send, try to send them */
1319 if (cachep->write_cache_len > 0) {
1320 int i = 0;
1321 char buf[8192];
1322 int rc;
1323 void *opaque = NULL;
1324 int opaque_len = 0;
1325 fd_set readfs;
1326 NETSNMP_SELECT_TIMEVAL tv;
1327
1328 DEBUGMSGTL(("dtlsudp:close",
1329 "%" NETSNMP_PRIz "d bytes remain in write_cache\n",
1330 cachep->write_cache_len));
1331
1332 /*
1333 * if negotiations have completed and we've received data, try and
1334 * send any queued packets.
1335 */
1336 if (1) {
1337 /* make configurable:
1338 - do this at all?
1339 - retries
1340 - timeout
1341 */
1342 for (i = 0; i < 6 && cachep->write_cache_len != 0; ++i) {
1343
1344 /* first see if we can send out what we have */
1345 _netsnmp_bio_try_and_write_buffered(t, cachep);
1346 if (cachep->write_cache_len == 0)
1347 break;
1348
1349 /* if we've failed that, we probably need to wait for packets */
1350 FD_ZERO(&readfs);
1351 FD_SET(t->sock, &readfs);
1352 tv.tv_sec = 0;
1353 tv.tv_usec = 50000;
1354 rc = select(t->sock+1, &readfs, NULL, NULL, &tv);
1355 if (rc > 0) {
1356 /* junk recv for catching negotiations still in play */
1357 opaque_len = 0;
1358 rc = netsnmp_dtlsudp_recv(t, buf, sizeof(buf),
1359 &opaque, &opaque_len);
1360 DEBUGMSGTL(("dtlsudp:close",
1361 "netsnmp_dtlsudp_recv() returned %d\n", rc));
1362 SNMP_FREE(opaque);
1363 }
1364 } /* for loop */
1365 }
1366
1367 /** dump anything that wasn't sent */
1368 if (cachep->write_cache_len > 0) {
1369 DEBUGMSGTL(("dtlsudp:close",
1370 "dumping %" NETSNMP_PRIz "d bytes from write_cache\n",
1371 cachep->write_cache_len));
1372 SNMP_FREE(cachep->write_cache);
1373 cachep->write_cache_len = 0;
1374 }
1375 }
1376
1377 /* RFC5953: section 5.4, step 4:
1378 4) Have (D)TLS close the specified connection. This MUST include
1379 sending a close_notify TLS Alert to inform the other side that
1380 session cleanup may be performed.
1381 */
1382 if (NULL != cachep->tlsdata && NULL != cachep->tlsdata->ssl) {
1383
1384 DEBUGMSGTL(("dtlsudp:close", "closing SSL socket\n"));
1385 SSL_shutdown(cachep->tlsdata->ssl);
1386
1387 /* send the close_notify we maybe generated in step 4 */
1388 if (BIO_ctrl_pending(cachep->write_bio) > 0)
1389 _netsnmp_send_queued_dtls_pkts(t, cachep);
1390 }
1391
1392 remove_and_free_bio_cache(cachep);
1393
1394 return netsnmp_socketbase_close(t);
1395 }
1396
1397 static char *
netsnmp_dtlsudp_fmtaddr(netsnmp_transport * t,const void * data,int len,const char * pfx,char * (* fmt_base_addr)(const char * pfx,netsnmp_transport * t,const void * data,int len))1398 netsnmp_dtlsudp_fmtaddr(netsnmp_transport *t, const void *data, int len,
1399 const char *pfx,
1400 char *(*fmt_base_addr)(const char *pfx,
1401 netsnmp_transport *t,
1402 const void *data, int len))
1403 {
1404 if (!data) {
1405 data = t->data;
1406 len = t->data_length;
1407 }
1408
1409 switch (data ? len : 0) {
1410 case sizeof(netsnmp_indexed_addr_pair):
1411 return netsnmp_ipv4_fmtaddr(pfx, t, data, len);
1412 case sizeof(netsnmp_tmStateReference): {
1413 const netsnmp_tmStateReference *r = data;
1414 const netsnmp_indexed_addr_pair *p = &r->addresses;
1415 netsnmp_transport *bt = t->base_transport;
1416
1417 if (r->have_addresses) {
1418 return fmt_base_addr("DTLSUDP", t, p, sizeof(*p));
1419 } else if (bt && t->data_length == sizeof(_netsnmpTLSBaseData)) {
1420 _netsnmpTLSBaseData *tlsdata = t->data;
1421 netsnmp_indexed_addr_pair *tls_addr = tlsdata->addr;
1422
1423 return bt->f_fmtaddr(bt, tls_addr, sizeof(*tls_addr));
1424 } else if (bt) {
1425 return bt->f_fmtaddr(bt, t->data, t->data_length);
1426 } else {
1427 return strdup("DTLSUDP: unknown");
1428 }
1429 }
1430 case sizeof(_netsnmpTLSBaseData): {
1431 const _netsnmpTLSBaseData *b = data;
1432 char *buf;
1433
1434 if (asprintf(&buf, "DTLSUDP: %s", b->addr_string) < 0)
1435 buf = NULL;
1436 return buf;
1437 }
1438 case 0:
1439 return strdup("DTLSUDP: unknown");
1440 default: {
1441 char *buf;
1442
1443 if (asprintf(&buf, "DTLSUDP: len %d", len) < 0)
1444 buf = NULL;
1445 return buf;
1446 }
1447 }
1448 }
1449
1450 static char *
netsnmp_dtlsudp4_fmtaddr(netsnmp_transport * t,const void * data,int len)1451 netsnmp_dtlsudp4_fmtaddr(netsnmp_transport *t, const void *data, int len)
1452 {
1453 return netsnmp_dtlsudp_fmtaddr(t, data, len, "DTLSUDP",
1454 netsnmp_ipv4_fmtaddr);
1455 }
1456
1457 /*
1458 * Open a DTLS-based transport for SNMP. Local is TRUE if addr is the local
1459 * address to bind to (i.e. this is a server-type session); otherwise addr is
1460 * the remote address to send things to.
1461 */
1462
1463 static netsnmp_transport *
_transport_common(netsnmp_transport * t,int local)1464 _transport_common(netsnmp_transport *t, int local)
1465 {
1466 char *tmp = NULL;
1467 int tmp_len;
1468
1469 DEBUGTRACETOK("9:dtlsudp");
1470
1471 if (NULL == t)
1472 return NULL;
1473
1474 /** save base transport for clients; need in send/recv functions later */
1475 if (t->data) { /* don't copy data */
1476 tmp = t->data;
1477 tmp_len = t->data_length;
1478 t->data = NULL;
1479 }
1480 t->base_transport = netsnmp_transport_copy(t);
1481
1482 if (tmp) {
1483 t->data = tmp;
1484 t->data_length = tmp_len;
1485 }
1486 if (NULL != t->data &&
1487 t->data_length == sizeof(netsnmp_indexed_addr_pair)) {
1488 _netsnmpTLSBaseData *tlsdata =
1489 netsnmp_tlsbase_allocate_tlsdata(t, local);
1490 tlsdata->addr = t->data;
1491 t->data = tlsdata;
1492 t->data_length = sizeof(_netsnmpTLSBaseData);
1493 }
1494
1495 /*
1496 * Set Domain
1497 */
1498 t->domain = netsnmpDTLSUDPDomain;
1499 t->domain_length = netsnmpDTLSUDPDomain_len;
1500
1501 t->f_recv = netsnmp_dtlsudp_recv;
1502 t->f_send = netsnmp_dtlsudp_send;
1503 t->f_close = netsnmp_dtlsudp_close;
1504 t->f_config = netsnmp_tlsbase_config;
1505 t->f_setup_session = netsnmp_tlsbase_session_init;
1506 t->f_accept = NULL;
1507 t->f_fmtaddr = netsnmp_dtlsudp4_fmtaddr;
1508 t->f_get_taddr = netsnmp_ipv4_get_taddr;
1509
1510 t->flags = NETSNMP_TRANSPORT_FLAG_TUNNELED;
1511
1512 return t;
1513 }
1514
1515 netsnmp_transport *
netsnmp_dtlsudp_transport(const struct netsnmp_ep * ep,int local)1516 netsnmp_dtlsudp_transport(const struct netsnmp_ep *ep, int local)
1517 {
1518 const struct sockaddr_in *addr = &ep->a.sin;
1519 netsnmp_transport *t, *t2;
1520
1521 DEBUGTRACETOK("dtlsudp");
1522
1523 t = netsnmp_udp_transport(ep, local);
1524 if (NULL == t)
1525 return NULL;
1526
1527 t2 = _transport_common(t, local);
1528 if (!t2) {
1529 netsnmp_transport_free(t);
1530 return NULL;
1531 }
1532
1533 if (!local) {
1534 /* dtls needs to bind the socket for SSL_write to work */
1535 if (connect(t->sock, (const struct sockaddr *)addr, sizeof(*addr)) < 0)
1536 snmp_log(LOG_ERR, "dtls: failed to connect\n");
1537 }
1538
1539 return t2;
1540 }
1541
1542
1543 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1544
1545 static char *
netsnmp_dtlsudp6_fmtaddr(netsnmp_transport * t,const void * data,int len)1546 netsnmp_dtlsudp6_fmtaddr(netsnmp_transport *t, const void *data, int len)
1547 {
1548 return netsnmp_dtlsudp_fmtaddr(t, data, len, "DTLSUDP6",
1549 netsnmp_ipv6_fmtaddr);
1550 }
1551
1552 /*
1553 * Open a DTLS-based transport for SNMP. Local is TRUE if addr is the local
1554 * address to bind to (i.e. this is a server-type session); otherwise addr is
1555 * the remote address to send things to.
1556 */
1557
1558 netsnmp_transport *
netsnmp_dtlsudp6_transport(const struct netsnmp_ep * ep,int local)1559 netsnmp_dtlsudp6_transport(const struct netsnmp_ep *ep, int local)
1560 {
1561 const struct sockaddr_in6 *addr = &ep->a.sin6;
1562 netsnmp_transport *t, *t2;
1563
1564 DEBUGTRACETOK("dtlsudp");
1565
1566 t = netsnmp_udp6_transport(ep, local);
1567 if (NULL == t)
1568 return NULL;
1569
1570 t2 = _transport_common(t, local);
1571 if (!t2) {
1572 netsnmp_transport_free(t);
1573 return NULL;
1574 }
1575
1576 if (!local) {
1577 /* dtls needs to bind the socket for SSL_write to work */
1578 if (connect(t->sock, (const struct sockaddr *)addr, sizeof(*addr)) < 0)
1579 snmp_log(LOG_ERR, "dtls: failed to connect\n");
1580 }
1581
1582 /* XXX: Potentially set sock opts here (SO_SNDBUF/SO_RCV_BUF) */
1583 /* XXX: and buf size */
1584
1585 t2->f_fmtaddr = netsnmp_dtlsudp6_fmtaddr;
1586 t2->f_get_taddr = netsnmp_ipv6_get_taddr;
1587
1588 return t2;
1589 }
1590 #endif
1591
1592
1593 netsnmp_transport *
netsnmp_dtlsudp_create_tstring(const char * str,int isserver,const char * default_target)1594 netsnmp_dtlsudp_create_tstring(const char *str, int isserver,
1595 const char *default_target)
1596 {
1597 struct netsnmp_ep ep;
1598 netsnmp_transport *t;
1599 _netsnmpTLSBaseData *tlsdata;
1600 char buf[SPRINT_MAX_LEN], *cp;
1601
1602 if (netsnmp_sockaddr_in3(&ep, str, default_target))
1603 t = netsnmp_dtlsudp_transport(&ep, isserver);
1604 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1605 else if (netsnmp_sockaddr_in6_3(&ep, str, default_target))
1606 t = netsnmp_dtlsudp6_transport(&ep, isserver);
1607 #endif
1608 else
1609 return NULL;
1610
1611
1612 /* see if we can extract the remote hostname */
1613 if (!isserver && t && t->data && str) {
1614 tlsdata = t->data;
1615 /* search for a : */
1616 if (NULL != (cp = strrchr(str, ':'))) {
1617 sprintf(buf, "%.*s", (int) SNMP_MIN(cp - str, sizeof(buf) - 1),
1618 str);
1619 } else {
1620 /* else the entire spec is a host name only */
1621 strlcpy(buf, str, sizeof(buf));
1622 }
1623 tlsdata->their_hostname = strdup(buf);
1624 }
1625 return t;
1626 }
1627
1628
1629 netsnmp_transport *
netsnmp_dtlsudp_create_ostring(const void * o,size_t o_len,int local)1630 netsnmp_dtlsudp_create_ostring(const void *o, size_t o_len, int local)
1631 {
1632 struct netsnmp_ep ep;
1633
1634 memset(&ep, 0, sizeof(ep));
1635 if (netsnmp_ipv4_ostring_to_sockaddr(&ep.a.sin, o, o_len))
1636 return netsnmp_dtlsudp_transport(&ep, local);
1637 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1638 else if (netsnmp_ipv6_ostring_to_sockaddr(&ep.a.sin6, o, o_len))
1639 return netsnmp_dtlsudp6_transport(&ep, local);
1640 #endif
1641 else
1642 return NULL;
1643 }
1644
1645 void
netsnmp_dtlsudp_ctor(void)1646 netsnmp_dtlsudp_ctor(void)
1647 {
1648 static const char indexname[] = "_netsnmp_addr_info";
1649 static const char *prefixes[] = { "dtlsudp", "dtls"
1650 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1651 , "dtlsudp6", "dtls6"
1652 #endif
1653 };
1654 int i, num_prefixes = sizeof(prefixes) / sizeof(char *);
1655 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1656 static const char indexname6[] = "_netsnmp_addr_info6";
1657 #endif
1658
1659 DEBUGMSGTL(("dtlsudp", "registering DTLS constructor\n"));
1660
1661 /* config settings */
1662
1663 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1664 if (!openssl_addr_index6)
1665 openssl_addr_index6 =
1666 SSL_get_ex_new_index(0, NETSNMP_REMOVE_CONST(void *, indexname6),
1667 NULL, NULL, NULL);
1668 #endif
1669
1670 dtlsudpDomain.name = netsnmpDTLSUDPDomain;
1671 dtlsudpDomain.name_length = netsnmpDTLSUDPDomain_len;
1672 dtlsudpDomain.prefix = calloc(num_prefixes + 1, sizeof(char *));
1673 for (i = 0; i < num_prefixes; ++ i)
1674 dtlsudpDomain.prefix[i] = prefixes[i];
1675
1676 dtlsudpDomain.f_create_from_tstring_new = netsnmp_dtlsudp_create_tstring;
1677 dtlsudpDomain.f_create_from_ostring = netsnmp_dtlsudp_create_ostring;
1678
1679 if (!openssl_addr_index)
1680 openssl_addr_index =
1681 SSL_get_ex_new_index(0, NETSNMP_REMOVE_CONST(void *, indexname),
1682 NULL, NULL, NULL);
1683
1684 netsnmp_tdomain_register(&dtlsudpDomain);
1685 }
1686
1687 /*
1688 * Much of the code below was taken from the OpenSSL example code
1689 * and is subject to the OpenSSL copyright.
1690 */
1691 #define NETSNMP_COOKIE_SECRET_LENGTH 16
1692 int cookie_initialized=0;
1693 unsigned char cookie_secret[NETSNMP_COOKIE_SECRET_LENGTH];
1694
netsnmp_dtls_gen_cookie(SSL * ssl,unsigned char * cookie,unsigned int * cookie_len)1695 int netsnmp_dtls_gen_cookie(SSL *ssl, unsigned char *cookie,
1696 unsigned int *cookie_len)
1697 {
1698 unsigned char *buffer, result[EVP_MAX_MD_SIZE];
1699 unsigned int length, resultlength;
1700 bio_cache *cachep = NULL;
1701 const netsnmp_sockaddr_storage *peer;
1702
1703 /* Initialize a random secret */
1704 if (!cookie_initialized) {
1705 if (!RAND_bytes(cookie_secret, NETSNMP_COOKIE_SECRET_LENGTH)) {
1706 snmp_log(LOG_ERR, "dtls: error setting random cookie secret\n");
1707 return 0;
1708 }
1709 MAKE_MEM_DEFINED(cookie_secret, NETSNMP_COOKIE_SECRET_LENGTH);
1710 cookie_initialized = 1;
1711 }
1712
1713 DEBUGMSGT(("dtlsudp:cookie", "generating cookie...\n"));
1714
1715 /* Read peer information */
1716 cachep = SSL_get_ex_data(ssl, openssl_addr_index);
1717 if (!cachep) {
1718 snmp_log(LOG_ERR, "dtls: failed to get the peer address\n");
1719 return 0;
1720 }
1721 peer = &cachep->sas;
1722
1723 /* Create buffer with peer's address and port */
1724 length = 0;
1725 switch (peer->sa.sa_family) {
1726 case AF_INET:
1727 length += sizeof(struct in_addr);
1728 length += sizeof(peer->sin.sin_port);
1729 break;
1730 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1731 case AF_INET6:
1732 length += sizeof(struct in6_addr);
1733 length += sizeof(peer->sin6.sin6_port);
1734 break;
1735 #endif
1736 default:
1737 snmp_log(LOG_ERR, "dtls generating cookie: unknown family: %d\n",
1738 peer->sa.sa_family);
1739 return 0;
1740 }
1741 buffer = malloc(length);
1742 if (buffer == NULL) {
1743 snmp_log(LOG_ERR,"dtls: out of memory\n");
1744 return 0;
1745 }
1746
1747 switch (peer->sa.sa_family) {
1748 case AF_INET:
1749 memcpy(buffer,
1750 &peer->sin.sin_port,
1751 sizeof(peer->sin.sin_port));
1752 memcpy(buffer + sizeof(peer->sin.sin_port),
1753 &peer->sin.sin_addr,
1754 sizeof(struct in_addr));
1755 break;
1756 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1757 case AF_INET6:
1758 memcpy(buffer,
1759 &peer->sin6.sin6_port,
1760 sizeof(peer->sin6.sin6_port));
1761 memcpy(buffer + sizeof(peer->sin6.sin6_port),
1762 &peer->sin6.sin6_addr,
1763 sizeof(struct in6_addr));
1764 break;
1765 #endif
1766 default:
1767 snmp_log(LOG_ERR, "dtls: unknown address family generating a cookie\n");
1768 free(buffer);
1769 return 0;
1770 }
1771
1772 /* Calculate HMAC of buffer using the secret */
1773 HMAC(EVP_sha1(), cookie_secret, NETSNMP_COOKIE_SECRET_LENGTH,
1774 buffer, length, result, &resultlength);
1775 free(buffer);
1776
1777 memcpy(cookie, result, resultlength);
1778 *cookie_len = resultlength;
1779
1780 DEBUGMSGT(("9:dtlsudp:cookie", "generated %d byte cookie\n", *cookie_len));
1781
1782 return 1;
1783 }
1784
netsnmp_dtls_verify_cookie(SSL * ssl,SECOND_APPVERIFY_COOKIE_CB_ARG_QUALIFIER unsigned char * cookie,unsigned int cookie_len)1785 int netsnmp_dtls_verify_cookie(SSL *ssl,
1786 SECOND_APPVERIFY_COOKIE_CB_ARG_QUALIFIER
1787 unsigned char *cookie,
1788 unsigned int cookie_len)
1789 {
1790 unsigned char *buffer, result[EVP_MAX_MD_SIZE];
1791 unsigned int length, resultlength, rc;
1792 bio_cache *cachep = NULL;
1793 const netsnmp_sockaddr_storage *peer;
1794
1795 /* If secret isn't initialized yet, the cookie can't be valid */
1796 if (!cookie_initialized)
1797 return 0;
1798
1799 DEBUGMSGT(("9:dtlsudp:cookie", "verifying %d byte cookie\n", cookie_len));
1800
1801 cachep = SSL_get_ex_data(ssl, openssl_addr_index);
1802 if (!cachep) {
1803 snmp_log(LOG_ERR, "dtls: failed to get the peer address\n");
1804 return 0;
1805 }
1806 peer = &cachep->sas;
1807
1808 /* Create buffer with peer's address and port */
1809 length = 0;
1810 switch (peer->sa.sa_family) {
1811 case AF_INET:
1812 length += sizeof(struct in_addr);
1813 length += sizeof(peer->sin.sin_port);
1814 break;
1815 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1816 case AF_INET6:
1817 length += sizeof(struct in6_addr);
1818 length += sizeof(peer->sin6.sin6_port);
1819 break;
1820 #endif
1821 default:
1822 snmp_log(LOG_ERR,
1823 "dtls: unknown address family %d generating a cookie\n",
1824 peer->sa.sa_family);
1825 return 0;
1826 }
1827 buffer = malloc(length);
1828 if (buffer == NULL) {
1829 snmp_log(LOG_ERR, "dtls: unknown address family generating a cookie\n");
1830 return 0;
1831 }
1832
1833 switch (peer->sa.sa_family) {
1834 case AF_INET:
1835 memcpy(buffer,
1836 &peer->sin.sin_port,
1837 sizeof(peer->sin.sin_port));
1838 memcpy(buffer + sizeof(peer->sin.sin_port),
1839 &peer->sin.sin_addr,
1840 sizeof(struct in_addr));
1841 break;
1842 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
1843 case AF_INET6:
1844 memcpy(buffer,
1845 &peer->sin6.sin6_port,
1846 sizeof(peer->sin6.sin6_port));
1847 memcpy(buffer + sizeof(peer->sin6.sin6_port),
1848 &peer->sin6.sin6_addr,
1849 sizeof(struct in6_addr));
1850 break;
1851 #endif
1852 default:
1853 snmp_log(LOG_ERR,
1854 "dtls: unknown address family %d generating a cookie\n",
1855 peer->sa.sa_family);
1856 free(buffer);
1857 return 0;
1858 }
1859
1860 /* Calculate HMAC of buffer using the secret */
1861 HMAC(EVP_sha1(), cookie_secret, NETSNMP_COOKIE_SECRET_LENGTH,
1862 buffer, length, result, &resultlength);
1863 free(buffer);
1864
1865 if (cookie_len != resultlength || memcmp(result, cookie, resultlength) != 0)
1866 rc = 0;
1867 else {
1868 rc = 1;
1869 cachep->flags |= NETSNMP_BIO_HAVE_COOKIE;
1870 }
1871
1872 DEBUGMSGT(("dtlsudp:cookie", "verify cookie: %d\n", rc));
1873
1874 return rc;
1875 }
1876
1877 #endif /* HAVE_LIBSSL_DTLS */
1878