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