Coverage Report

Created: 2026-08-28 09:48

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