Coverage Report

Created: 2023-06-07 06:43

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