|
Packit |
fcad23 |
/* Portions of this file are subject to the following copyright(s). See
|
|
Packit |
fcad23 |
* the Net-SNMP's COPYING file for more details and other copyrights
|
|
Packit |
fcad23 |
* that may apply:
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* See the following web pages for useful documentation on this transport:
|
|
Packit |
fcad23 |
* http://www.net-snmp.org/wiki/index.php/TUT:Using_TLS
|
|
Packit |
fcad23 |
* http://www.net-snmp.org/wiki/index.php/Using_DTLS
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
#include <net-snmp/net-snmp-config.h>
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#include <net-snmp/net-snmp-features.h>
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_feature_require(cert_util)
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#include <stdio.h>
|
|
Packit |
fcad23 |
#include <sys/types.h>
|
|
Packit |
fcad23 |
#include <ctype.h>
|
|
Packit |
fcad23 |
#include <errno.h>
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#if HAVE_STRING_H
|
|
Packit |
fcad23 |
#include <string.h>
|
|
Packit |
fcad23 |
#else
|
|
Packit |
fcad23 |
#include <strings.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_STDLIB_H
|
|
Packit |
fcad23 |
#include <stdlib.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_UNISTD_H
|
|
Packit |
fcad23 |
#include <unistd.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_SYS_SOCKET_H
|
|
Packit |
fcad23 |
#include <sys/socket.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_NETINET_IN_H
|
|
Packit |
fcad23 |
#include <netinet/in.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_ARPA_INET_H
|
|
Packit |
fcad23 |
#include <arpa/inet.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_NETDB_H
|
|
Packit |
fcad23 |
#include <netdb.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
#if HAVE_SYS_UIO_H
|
|
Packit |
fcad23 |
#include <sys/uio.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#if HAVE_ARPA_INET_H
|
|
Packit |
fcad23 |
#include <arpa/inet.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#if HAVE_DMALLOC_H
|
|
Packit |
fcad23 |
#include <dmalloc.h>
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#include <net-snmp/types.h>
|
|
Packit |
fcad23 |
#include <net-snmp/output_api.h>
|
|
Packit |
fcad23 |
#include <net-snmp/config_api.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/snmp_assert.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/snmpIPv4BaseDomain.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/snmpSocketBaseDomain.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/snmpTLSBaseDomain.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/snmpTLSTCPDomain.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/system.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/tools.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/cert_util.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/snmp_openssl.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/callback.h>
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#include "openssl/bio.h"
|
|
Packit |
fcad23 |
#include "openssl/ssl.h"
|
|
Packit |
fcad23 |
#include "openssl/err.h"
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#ifndef INADDR_NONE
|
|
Packit |
fcad23 |
#define INADDR_NONE -1
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#define WE_ARE_SERVER 0
|
|
Packit |
fcad23 |
#define WE_ARE_CLIENT 1
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
oid netsnmpTLSTCPDomain[] = { TRANSPORT_DOMAIN_TLS_TCP_IP };
|
|
Packit |
fcad23 |
size_t netsnmpTLSTCPDomain_len = OID_LENGTH(netsnmpTLSTCPDomain);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static netsnmp_tdomain tlstcpDomain;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* Return a string representing the address in data, or else the "far end"
|
|
Packit |
fcad23 |
* address if data is NULL.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static char *
|
|
Packit |
fcad23 |
netsnmp_tlstcp_fmtaddr(netsnmp_transport *t, const void *data, int len)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
if (t && !data) {
|
|
Packit |
fcad23 |
data = t->data;
|
|
Packit |
fcad23 |
len = t->data_length;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
switch (data ? len : 0) {
|
|
Packit |
fcad23 |
case sizeof(netsnmp_indexed_addr_pair):
|
|
Packit |
fcad23 |
return netsnmp_ipv4_fmtaddr("TLSTCP", t, data, len);
|
|
Packit |
fcad23 |
case sizeof(netsnmp_tmStateReference): {
|
|
Packit |
fcad23 |
const netsnmp_tmStateReference *r = data;
|
|
Packit |
fcad23 |
const netsnmp_indexed_addr_pair *p = &r->addresses;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
return netsnmp_ipv4_fmtaddr("TLSTCP", t, p, sizeof(*p));
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
case sizeof(_netsnmpTLSBaseData): {
|
|
Packit |
fcad23 |
const _netsnmpTLSBaseData *b = data;
|
|
Packit |
fcad23 |
char *buf;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (asprintf(&buf, "TLSTCP: %s", b->addr_string) < 0)
|
|
Packit |
fcad23 |
buf = NULL;
|
|
Packit |
fcad23 |
return buf;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
case 0:
|
|
Packit |
fcad23 |
return strdup("TLSTCP: unknown");
|
|
Packit |
fcad23 |
default: {
|
|
Packit |
fcad23 |
char *buf;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (asprintf(&buf, "TLSTCP: len %d", len) < 0)
|
|
Packit |
fcad23 |
buf = NULL;
|
|
Packit |
fcad23 |
return buf;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static void netsnmp_tlstcp_get_taddr(struct netsnmp_transport_s *t,
|
|
Packit |
fcad23 |
void **addr, size_t *addr_len)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
*addr_len = t->remote_length;
|
|
Packit |
fcad23 |
*addr = netsnmp_memdup(t->remote, *addr_len);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* You can write something into opaque that will subsequently get passed back
|
|
Packit |
fcad23 |
* to your send function if you like. For instance, you might want to
|
|
Packit |
fcad23 |
* remember where a PDU came from, so that you can send a reply there...
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static int
|
|
Packit |
fcad23 |
netsnmp_tlstcp_copy(const netsnmp_transport *oldt, netsnmp_transport *newt)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *oldtlsdata = (_netsnmpTLSBaseData *) oldt->data;
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *newtlsdata = (_netsnmpTLSBaseData *) newt->data;
|
|
Packit |
fcad23 |
oldtlsdata->accepted_bio = NULL;
|
|
Packit |
fcad23 |
oldtlsdata->ssl = NULL;
|
|
Packit |
fcad23 |
newtlsdata->ssl_context = NULL;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (oldtlsdata->addr_string)
|
|
Packit |
fcad23 |
newtlsdata->addr_string = strdup(oldtlsdata->addr_string);
|
|
Packit |
fcad23 |
if (oldtlsdata->securityName)
|
|
Packit |
fcad23 |
newtlsdata->securityName = strdup(oldtlsdata->securityName);
|
|
Packit |
fcad23 |
if (oldtlsdata->our_identity)
|
|
Packit |
fcad23 |
newtlsdata->our_identity = strdup(oldtlsdata->our_identity);
|
|
Packit |
fcad23 |
if (oldtlsdata->their_identity)
|
|
Packit |
fcad23 |
newtlsdata->their_identity = strdup(oldtlsdata->their_identity);
|
|
Packit |
fcad23 |
if (oldtlsdata->their_fingerprint)
|
|
Packit |
fcad23 |
newtlsdata->their_fingerprint = strdup(oldtlsdata->their_fingerprint);
|
|
Packit |
fcad23 |
if (oldtlsdata->their_hostname)
|
|
Packit |
fcad23 |
newtlsdata->their_hostname = strdup(oldtlsdata->their_hostname);
|
|
Packit |
fcad23 |
if (oldtlsdata->trust_cert)
|
|
Packit |
fcad23 |
newtlsdata->trust_cert = strdup(oldtlsdata->trust_cert);
|
|
Packit |
fcad23 |
if (oldtlsdata->addr)
|
|
Packit |
fcad23 |
newtlsdata->addr = netsnmp_memdup(oldtlsdata->addr,
|
|
Packit |
fcad23 |
sizeof(*oldtlsdata->addr));
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
return 0;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static int
|
|
Packit |
fcad23 |
netsnmp_tlstcp_recv(netsnmp_transport *t, void *buf, int size,
|
|
Packit |
fcad23 |
void **opaque, int *olength)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
int rc = -1;
|
|
Packit |
fcad23 |
netsnmp_tmStateReference *tmStateRef = NULL;
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *tlsdata;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (NULL == t || t->sock < 0 || NULL == t->data) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR,
|
|
Packit |
fcad23 |
"tlstcp received an invalid invocation with missing data\n");
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "recvfrom fd %d err %d (\"%s\")\n",
|
|
Packit |
fcad23 |
(t ? t->sock : -1), errno, strerror(errno)));
|
|
Packit |
fcad23 |
if (t)
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", " tdata = %p", t->data));
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "\n"));
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.1.2 step 1:
|
|
Packit |
fcad23 |
1) Determine the tlstmSessionID for the incoming message. The
|
|
Packit |
fcad23 |
tlstmSessionID MUST be a unique session identifier for this
|
|
Packit |
fcad23 |
(D)TLS connection. The contents and format of this identifier
|
|
Packit |
fcad23 |
are implementation-dependent as long as it is unique to the
|
|
Packit |
fcad23 |
session. A session identifier MUST NOT be reused until all
|
|
Packit |
fcad23 |
references to it are no longer in use. The tmSessionID is
|
|
Packit |
fcad23 |
equal to the tlstmSessionID discussed in Section 5.1.1.
|
|
Packit |
fcad23 |
tmSessionID refers to the session identifier when stored in the
|
|
Packit |
fcad23 |
tmStateReference and tlstmSessionID refers to the session
|
|
Packit |
fcad23 |
identifier when stored in the LCD. They MUST always be equal
|
|
Packit |
fcad23 |
when processing a given session's traffic.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* For this implementation we use the t->data memory pointer as
|
|
Packit |
fcad23 |
the sessionID. As it's a pointer to session specific data tied
|
|
Packit |
fcad23 |
with the transport object we know it'll never be realloated
|
|
Packit |
fcad23 |
(ie, duplicated) until release by this transport object and is
|
|
Packit |
fcad23 |
safe to use as a unique session identifier. */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlsdata = t->data;
|
|
Packit |
fcad23 |
if (NULL == tlsdata->ssl) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR,
|
|
Packit |
fcad23 |
"tlstcp received an invalid invocation without ssl data\n");
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.1.2 step 1, part2:
|
|
Packit |
fcad23 |
* This part (incrementing the counter) is done in the
|
|
Packit |
fcad23 |
netsnmp_tlstcp_accept function.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.1.2 step 2:
|
|
Packit |
fcad23 |
* Create a tmStateReference cache for the subsequent reference and
|
|
Packit |
fcad23 |
assign the following values within it:
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tmTransportDomain = snmpTLSTCPDomain or snmpDTLSUDPDomain as
|
|
Packit |
fcad23 |
appropriate.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tmTransportAddress = The address the message originated from.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tmSecurityLevel = The derived tmSecurityLevel for the session,
|
|
Packit |
fcad23 |
as discussed in Section 3.1.2 and Section 5.3.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tmSecurityName = The fderived tmSecurityName for the session as
|
|
Packit |
fcad23 |
discussed in Section 5.3. This value MUST
|
|
Packit |
fcad23 |
be constant during the lifetime of the
|
|
Packit |
fcad23 |
session.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tmSessionID = The tlstmSessionID described in step 1 above.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Implementation notes:
|
|
Packit |
fcad23 |
* - The tmTransportDomain is represented by the transport object
|
|
Packit |
fcad23 |
* - The tmpSessionID is represented by the tlsdata pointer (as
|
|
Packit |
fcad23 |
discussed above)
|
|
Packit |
fcad23 |
* - The following items are handled later in netsnmp_tlsbase_wrapup_recv:
|
|
Packit |
fcad23 |
- tmSecurityLevel
|
|
Packit |
fcad23 |
- tmSecurityName
|
|
Packit |
fcad23 |
- tmSessionID
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* create a tmStateRef cache for slow fill-in */
|
|
Packit |
fcad23 |
tmStateRef = SNMP_MALLOC_TYPEDEF(netsnmp_tmStateReference);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (tmStateRef == NULL) {
|
|
Packit |
fcad23 |
*opaque = NULL;
|
|
Packit |
fcad23 |
*olength = 0;
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Set the transportDomain */
|
|
Packit |
fcad23 |
memcpy(tmStateRef->transportDomain,
|
|
Packit |
fcad23 |
netsnmpTLSTCPDomain, sizeof(netsnmpTLSTCPDomain[0]) *
|
|
Packit |
fcad23 |
netsnmpTLSTCPDomain_len);
|
|
Packit |
fcad23 |
tmStateRef->transportDomainLen = netsnmpTLSTCPDomain_len;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Set the tmTransportAddress */
|
|
Packit |
fcad23 |
tmStateRef->have_addresses = 1;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.1.2 step 1:
|
|
Packit |
fcad23 |
* 3) The incomingMessage and incomingMessageLength are assigned values
|
|
Packit |
fcad23 |
from the (D)TLS processing.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Implementation notes:
|
|
Packit |
fcad23 |
- incomingMessage = buf pointer
|
|
Packit |
fcad23 |
- incomingMessageLength = rc
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* read the packet from openssl */
|
|
Packit |
fcad23 |
do {
|
|
Packit |
fcad23 |
rc = SSL_read(tlsdata->ssl, buf, size);
|
|
Packit |
fcad23 |
if (rc == 0) {
|
|
Packit |
fcad23 |
/* XXX closed connection */
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "remote side closed connection\n"));
|
|
Packit |
fcad23 |
/* XXX: openssl cleanup */
|
|
Packit |
fcad23 |
SNMP_FREE(tmStateRef);
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
if (rc == -1) {
|
|
Packit |
fcad23 |
int err = SSL_get_error(tlsdata->ssl, rc);
|
|
Packit |
fcad23 |
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
|
|
Packit |
fcad23 |
/* error detected */
|
|
Packit |
fcad23 |
_openssl_log_error(rc, tlsdata->ssl, "SSL_read");
|
|
Packit |
fcad23 |
SNMP_FREE(tmStateRef);
|
|
Packit |
fcad23 |
return rc;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
/* retry read for SSL_ERROR_WANT_READ || SSL_ERROR_WANT_WRITE */
|
|
Packit |
fcad23 |
} while (rc <= 0);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "received %d decoded bytes from tls\n", rc));
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* log the packet */
|
|
Packit |
fcad23 |
DEBUGIF("tlstcp") {
|
|
Packit |
fcad23 |
char *str = netsnmp_tlstcp_fmtaddr(t, NULL, 0);
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp",
|
|
Packit |
fcad23 |
"recvfrom fd %d got %d bytes (from %s)\n",
|
|
Packit |
fcad23 |
t->sock, rc, str));
|
|
Packit |
fcad23 |
free(str);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Other wrap-up things common to TLS and DTLS */
|
|
Packit |
fcad23 |
if (netsnmp_tlsbase_wrapup_recv(tmStateRef, tlsdata, opaque, olength) !=
|
|
Packit |
fcad23 |
SNMPERR_SUCCESS)
|
|
Packit |
fcad23 |
return SNMPERR_GENERR;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.1.2 step 1:
|
|
Packit |
fcad23 |
* 4) The TLS Transport Model passes the transportDomain,
|
|
Packit |
fcad23 |
transportAddress, incomingMessage, and incomingMessageLength to
|
|
Packit |
fcad23 |
the Dispatcher using the receiveMessage ASI:
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* In our implementation, this is done simply by returning */
|
|
Packit |
fcad23 |
return rc;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static int
|
|
Packit |
fcad23 |
netsnmp_tlstcp_send(netsnmp_transport *t, const void *buf, int size,
|
|
Packit |
fcad23 |
void **opaque, int *olength)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
int rc = -1;
|
|
Packit |
fcad23 |
const netsnmp_tmStateReference *tmStateRef = NULL;
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *tlsdata;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUGTRACETOK("tlstcp");
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 section 5.2:
|
|
Packit |
fcad23 |
1) If tmStateReference does not refer to a cache containing values
|
|
Packit |
fcad23 |
for tmTransportDomain, tmTransportAddress, tmSecurityName,
|
|
Packit |
fcad23 |
tmRequestedSecurityLevel, and tmSameSecurity, then increment the
|
|
Packit |
fcad23 |
snmpTlstmSessionInvalidCaches counter, discard the message, and
|
|
Packit |
fcad23 |
return the error indication in the statusInformation. Processing
|
|
Packit |
fcad23 |
of this message stops.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation Notes: the tmStateReference is stored in the opaque ptr */
|
|
Packit |
fcad23 |
if (opaque != NULL && *opaque != NULL &&
|
|
Packit |
fcad23 |
*olength == sizeof(netsnmp_tmStateReference)) {
|
|
Packit |
fcad23 |
tmStateRef = (const netsnmp_tmStateReference *) *opaque;
|
|
Packit |
fcad23 |
} else {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "TLSTCP was called with an invalid state; possibly the wrong security model is in use. It should be 'tsm'.\n");
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCACHES);
|
|
Packit |
fcad23 |
return SNMPERR_GENERR;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 section 5.2:
|
|
Packit |
fcad23 |
2) Extract the tmSessionID, tmTransportDomain, tmTransportAddress,
|
|
Packit |
fcad23 |
tmSecurityName, tmRequestedSecurityLevel, and tmSameSecurity
|
|
Packit |
fcad23 |
values from the tmStateReference. Note: The tmSessionID value
|
|
Packit |
fcad23 |
may be undefined if no session exists yet over which the message
|
|
Packit |
fcad23 |
can be sent.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation Notes:
|
|
Packit |
fcad23 |
- Our session will always exist by now as it's created when the
|
|
Packit |
fcad23 |
transport object is created. Auto-session creation is handled
|
|
Packit |
fcad23 |
higher in the stack.
|
|
Packit |
fcad23 |
- We don't "extract" per say since we just leave the data in
|
|
Packit |
fcad23 |
the structure.
|
|
Packit |
fcad23 |
- The sessionID is stored in the t->data memory pointer.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 section 5.2:
|
|
Packit |
fcad23 |
3) If tmSameSecurity is true and either tmSessionID is undefined or
|
|
Packit |
fcad23 |
refers to a session that is no longer open then increment the
|
|
Packit |
fcad23 |
snmpTlstmSessionNoSessions counter, discard the message and
|
|
Packit |
fcad23 |
return the error indication in the statusInformation. Processing
|
|
Packit |
fcad23 |
of this message stops.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation Notes:
|
|
Packit |
fcad23 |
- We would never get here if the sessionID was either undefined
|
|
Packit |
fcad23 |
or different. We tie packets directly to the transport
|
|
Packit |
fcad23 |
object and it could never be sent back over a different
|
|
Packit |
fcad23 |
transport, which is what the above text is trying to prevent.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 section 5.2:
|
|
Packit |
fcad23 |
4) If tmSameSecurity is false and tmSessionID refers to a session
|
|
Packit |
fcad23 |
that is no longer available then an implementation SHOULD open a
|
|
Packit |
fcad23 |
new session using the openSession() ASI (described in greater
|
|
Packit |
fcad23 |
detail in step 5b). Instead of opening a new session an
|
|
Packit |
fcad23 |
implementation MAY return a snmpTlstmSessionNoSessions error to
|
|
Packit |
fcad23 |
the calling module and stop processing of the message.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation Notes:
|
|
Packit |
fcad23 |
- We would never get here if the sessionID was either undefined
|
|
Packit |
fcad23 |
or different. We tie packets directly to the transport
|
|
Packit |
fcad23 |
object and it could never be sent back over a different
|
|
Packit |
fcad23 |
transport, which is what the above text is trying to prevent.
|
|
Packit |
fcad23 |
- Auto-connections are handled higher in the Net-SNMP library stack
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 section 5.2:
|
|
Packit |
fcad23 |
5) If tmSessionID is undefined, then use tmTransportDomain,
|
|
Packit |
fcad23 |
tmTransportAddress, tmSecurityName and tmRequestedSecurityLevel
|
|
Packit |
fcad23 |
to see if there is a corresponding entry in the LCD suitable to
|
|
Packit |
fcad23 |
send the message over.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
5a) If there is a corresponding LCD entry, then this session
|
|
Packit |
fcad23 |
will be used to send the message.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
5b) If there is not a corresponding LCD entry, then open a
|
|
Packit |
fcad23 |
session using the openSession() ASI (discussed further in
|
|
Packit |
fcad23 |
Section 5.3.1). Implementations MAY wish to offer message
|
|
Packit |
fcad23 |
buffering to prevent redundant openSession() calls for the
|
|
Packit |
fcad23 |
same cache entry. If an error is returned from
|
|
Packit |
fcad23 |
openSession(), then discard the message, discard the
|
|
Packit |
fcad23 |
tmStateReference, increment the snmpTlstmSessionOpenErrors,
|
|
Packit |
fcad23 |
return an error indication to the calling module and stop
|
|
Packit |
fcad23 |
processing of the message.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation Notes:
|
|
Packit |
fcad23 |
- We would never get here if the sessionID was either undefined
|
|
Packit |
fcad23 |
or different. We tie packets directly to the transport
|
|
Packit |
fcad23 |
object and it could never be sent back over a different
|
|
Packit |
fcad23 |
transport, which is what the above text is trying to prevent.
|
|
Packit |
fcad23 |
- Auto-connections are handled higher in the Net-SNMP library stack
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* our session pointer is functionally t->data */
|
|
Packit |
fcad23 |
if (NULL == t->data) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "netsnmp_tlstcp_send received no incoming data\n");
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlsdata = t->data;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (tlsdata->ssl == NULL) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp_send was called without a SSL connection.\n");
|
|
Packit |
fcad23 |
return SNMPERR_GENERR;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* If the first packet and we have no secname, then copy the
|
|
Packit |
fcad23 |
important securityName data into the longer-lived session
|
|
Packit |
fcad23 |
reference information. */
|
|
Packit |
fcad23 |
if ((tlsdata->flags & NETSNMP_TLSBASE_IS_CLIENT) &&
|
|
Packit |
fcad23 |
!tlsdata->securityName && tmStateRef && tmStateRef->securityNameLen > 0)
|
|
Packit |
fcad23 |
tlsdata->securityName = strdup(tmStateRef->securityName);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 section 5.2:
|
|
Packit |
fcad23 |
6) Using either the session indicated by the tmSessionID if there
|
|
Packit |
fcad23 |
was one or the session resulting from a previous step (4 or 5),
|
|
Packit |
fcad23 |
pass the outgoingMessage to (D)TLS for encapsulation and
|
|
Packit |
fcad23 |
transmission.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
rc = SSL_write(tlsdata->ssl, buf, size);
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "wrote %d bytes\n", size));
|
|
Packit |
fcad23 |
if (rc < 0) {
|
|
Packit |
fcad23 |
_openssl_log_error(rc, tlsdata->ssl, "SSL_write");
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
return rc;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static int
|
|
Packit |
fcad23 |
netsnmp_tlstcp_close(netsnmp_transport *t)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *tlsdata;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (NULL == t || NULL == t->data)
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.4. Closing a Session
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
1) Increment either the snmpTlstmSessionClientCloses or the
|
|
Packit |
fcad23 |
snmpTlstmSessionServerCloses counter as appropriate.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
if (t->flags & NETSNMP_TLSBASE_IS_CLIENT)
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONCLIENTCLOSES);
|
|
Packit |
fcad23 |
else
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONSERVERCLOSES);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.4. Closing a Session
|
|
Packit |
fcad23 |
2) Look up the session using the tmSessionID.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
tlsdata = (_netsnmpTLSBaseData *) t->data;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.4. Closing a Session
|
|
Packit |
fcad23 |
3) If there is no open session associated with the tmSessionID, then
|
|
Packit |
fcad23 |
closeSession processing is completed.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation notes: if we have a non-zero tlsdata then it's
|
|
Packit |
fcad23 |
always true */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
4) Have (D)TLS close the specified connection. This SHOULD include
|
|
Packit |
fcad23 |
sending a close_notify TLS Alert to inform the other side that
|
|
Packit |
fcad23 |
session cleanup may be performed.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "Shutting down SSL connection\n"));
|
|
Packit |
fcad23 |
if (tlsdata->ssl) {
|
|
Packit |
fcad23 |
SSL_shutdown(tlsdata->ssl);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_tlsbase_free_tlsdata(tlsdata);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
t->data = NULL;
|
|
Packit |
fcad23 |
return netsnmp_socketbase_close(t);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
static int
|
|
Packit |
fcad23 |
netsnmp_tlstcp_accept(netsnmp_transport *t)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
BIO *accepted_bio;
|
|
Packit |
fcad23 |
int rc;
|
|
Packit |
fcad23 |
SSL_CTX *ctx;
|
|
Packit |
fcad23 |
SSL *ssl;
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *tlsdata = NULL;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "netsnmp_tlstcp_accept called\n"));
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlsdata = (_netsnmpTLSBaseData *) t->data;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
rc = BIO_do_accept(tlsdata->accept_bio);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (rc <= 0) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "BIO_do_accept failed\n");
|
|
Packit |
fcad23 |
_openssl_log_error(rc, NULL, "BIO_do_accept");
|
|
Packit |
fcad23 |
/* XXX: need to close the listening connection here? */
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlsdata->accepted_bio = accepted_bio = BIO_pop(tlsdata->accept_bio);
|
|
Packit |
fcad23 |
if (!accepted_bio) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "Failed to pop an accepted bio off the bio stack\n");
|
|
Packit |
fcad23 |
/* XXX: need to close the listening connection here? */
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* create the OpenSSL TLS context */
|
|
Packit |
fcad23 |
ctx = tlsdata->ssl_context;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* create the server's main SSL bio */
|
|
Packit |
fcad23 |
ssl = tlsdata->ssl = SSL_new(ctx);
|
|
Packit |
fcad23 |
if (!tlsdata->ssl) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "TLSTCP: Failed to create a SSL BIO\n");
|
|
Packit |
fcad23 |
BIO_free(accepted_bio);
|
|
Packit |
fcad23 |
tlsdata->accepted_bio = NULL;
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
SSL_set_bio(ssl, accepted_bio, accepted_bio);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if ((rc = SSL_accept(ssl)) <= 0) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "TLSTCP: Failed SSL_accept\n");
|
|
Packit |
fcad23 |
_openssl_log_error(rc, ssl, "SSL_accept");
|
|
Packit |
fcad23 |
SSL_shutdown(tlsdata->ssl);
|
|
Packit |
fcad23 |
SSL_free(tlsdata->ssl);
|
|
Packit |
fcad23 |
tlsdata->accepted_bio = NULL; /* freed by SSL_free */
|
|
Packit |
fcad23 |
tlsdata->ssl = NULL;
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* currently netsnmp_tlsbase_wrapup_recv is where we check for
|
|
Packit |
fcad23 |
* algorithm compliance, but for tls we know the algorithms
|
|
Packit |
fcad23 |
* at this point, so we could bail earlier...
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
#if 0 /* moved checks to netsnmp_tlsbase_wrapup_recv */
|
|
Packit |
fcad23 |
netsnmp_openssl_null_checks(tlsdata->ssl, &no_auth, NULL);
|
|
Packit |
fcad23 |
if (no_auth != 0) { /* null/unknown authentication */
|
|
Packit |
fcad23 |
/* xxx-rks: snmp_increment_statistic(STAT_???); */
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp: connection with NULL authentication\n");
|
|
Packit |
fcad23 |
SSL_shutdown(tlsdata->ssl);
|
|
Packit |
fcad23 |
SSL_free(tlsdata->ssl);
|
|
Packit |
fcad23 |
tlsdata->accepted_bio = NULL; /* freed by SSL_free */
|
|
Packit |
fcad23 |
tlsdata->ssl = NULL;
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
#endif
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.2: Accepting a Session as a Server
|
|
Packit |
fcad23 |
A (D)TLS server should accept new session connections from any client
|
|
Packit |
fcad23 |
that it is able to verify the client's credentials for. This is done
|
|
Packit |
fcad23 |
by authenticating the client's presented certificate through a
|
|
Packit |
fcad23 |
certificate path validation process (e.g. [RFC5280]) or through
|
|
Packit |
fcad23 |
certificate fingerprint verification using fingerprints configured in
|
|
Packit |
fcad23 |
the snmpTlstmCertToTSNTable. Afterward the server will determine the
|
|
Packit |
fcad23 |
identity of the remote entity using the following procedures.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
The (D)TLS server identifies the authenticated identity from the
|
|
Packit |
fcad23 |
(D)TLS client's principal certificate using configuration information
|
|
Packit |
fcad23 |
from the snmpTlstmCertToTSNTable mapping table. The (D)TLS server
|
|
Packit |
fcad23 |
MUST request and expect a certificate from the client and MUST NOT
|
|
Packit |
fcad23 |
accept SNMP messages over the (D)TLS connection until the client has
|
|
Packit |
fcad23 |
sent a certificate and it has been authenticated. The resulting
|
|
Packit |
fcad23 |
derived tmSecurityName is recorded in the tmStateReference cache as
|
|
Packit |
fcad23 |
tmSecurityName. The details of the lookup process are fully
|
|
Packit |
fcad23 |
described in the DESCRIPTION clause of the snmpTlstmCertToTSNTable
|
|
Packit |
fcad23 |
MIB object. If any verification fails in any way (for example
|
|
Packit |
fcad23 |
because of failures in cryptographic verification or because of the
|
|
Packit |
fcad23 |
lack of an appropriate row in the snmpTlstmCertToTSNTable) then the
|
|
Packit |
fcad23 |
session establishment MUST fail, and the
|
|
Packit |
fcad23 |
snmpTlstmSessionInvalidClientCertificates object is incremented. If
|
|
Packit |
fcad23 |
the session can not be opened for any reason at all, including
|
|
Packit |
fcad23 |
cryptographic verification failures, then the
|
|
Packit |
fcad23 |
snmpTlstmSessionOpenErrors counter is incremented and processing
|
|
Packit |
fcad23 |
stops.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
Servers that wish to support multiple principals at a particular port
|
|
Packit |
fcad23 |
SHOULD make use of a (D)TLS extension that allows server-side
|
|
Packit |
fcad23 |
principal selection like the Server Name Indication extension defined
|
|
Packit |
fcad23 |
in Section 3.1 of [RFC4366]. Supporting this will allow, for
|
|
Packit |
fcad23 |
example, sending notifications to a specific principal at a given TCP
|
|
Packit |
fcad23 |
or UDP port.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation notes:
|
|
Packit |
fcad23 |
- we expect fingerprints to be stored in the transport config
|
|
Packit |
fcad23 |
- we do not currently support mulitple principals and only offer one
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
if ((rc = netsnmp_tlsbase_verify_client_cert(ssl, tlsdata))
|
|
Packit |
fcad23 |
!= SNMPERR_SUCCESS) {
|
|
Packit |
fcad23 |
/* XXX: free needed memory */
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "TLSTCP: Falied checking client certificate\n");
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCLIENTCERTIFICATES);
|
|
Packit |
fcad23 |
SSL_shutdown(tlsdata->ssl);
|
|
Packit |
fcad23 |
SSL_free(tlsdata->ssl);
|
|
Packit |
fcad23 |
tlsdata->accepted_bio = NULL; /* freed by SSL_free */
|
|
Packit |
fcad23 |
tlsdata->ssl = NULL;
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* XXX: check acceptance criteria here */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "accept succeeded on sock %d\n", t->sock));
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.1.2 step 1, part2::
|
|
Packit |
fcad23 |
* If this is the first message received through this session and
|
|
Packit |
fcad23 |
the session does not have an assigned tlstmSessionID yet then the
|
|
Packit |
fcad23 |
snmpTlstmSessionAccepts counter is incremented and a
|
|
Packit |
fcad23 |
tlstmSessionID for the session is created. This will only happen
|
|
Packit |
fcad23 |
on the server side of a connection because a client would have
|
|
Packit |
fcad23 |
already assigned a tlstmSessionID during the openSession()
|
|
Packit |
fcad23 |
invocation. Implementations may have performed the procedures
|
|
Packit |
fcad23 |
described in Section 5.3.2 prior to this point or they may
|
|
Packit |
fcad23 |
perform them now, but the procedures described in Section 5.3.2
|
|
Packit |
fcad23 |
MUST be performed before continuing beyond this point.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* We're taking option 2 and incrementing the session accepts here
|
|
Packit |
fcad23 |
rather than upon receiving the first packet */
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONACCEPTS);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* XXX: check that it returns something so we can free stuff? */
|
|
Packit |
fcad23 |
return BIO_get_fd(tlsdata->accepted_bio, NULL);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_transport *
|
|
Packit |
fcad23 |
netsnmp_tlstcp_open(netsnmp_transport *t)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *tlsdata;
|
|
Packit |
fcad23 |
BIO *bio;
|
|
Packit |
fcad23 |
SSL_CTX *ctx;
|
|
Packit |
fcad23 |
SSL *ssl;
|
|
Packit |
fcad23 |
int rc = 0;
|
|
Packit |
fcad23 |
_netsnmp_verify_info *verify_info;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_assert_or_return(t != NULL, NULL);
|
|
Packit |
fcad23 |
netsnmp_assert_or_return(t->data != NULL, NULL);
|
|
Packit |
fcad23 |
netsnmp_assert_or_return(sizeof(_netsnmpTLSBaseData) == t->data_length,
|
|
Packit |
fcad23 |
NULL);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlsdata = t->data;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (tlsdata->flags & NETSNMP_TLSBASE_IS_CLIENT) {
|
|
Packit |
fcad23 |
/* Is the client */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
* 1) The snmpTlstmSessionOpens counter is incremented.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENS);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
2) The client selects the appropriate certificate and cipher_suites
|
|
Packit |
fcad23 |
for the key agreement based on the tmSecurityName and the
|
|
Packit |
fcad23 |
tmRequestedSecurityLevel for the session. For sessions being
|
|
Packit |
fcad23 |
established as a result of a SNMP-TARGET-MIB based operation, the
|
|
Packit |
fcad23 |
certificate will potentially have been identified via the
|
|
Packit |
fcad23 |
snmpTlstmParamsTable mapping and the cipher_suites will have to
|
|
Packit |
fcad23 |
be taken from system-wide or implementation-specific
|
|
Packit |
fcad23 |
configuration. If no row in the snmpTlstmParamsTable exists then
|
|
Packit |
fcad23 |
implementations MAY choose to establish the connection using a
|
|
Packit |
fcad23 |
default client certificate available to the application.
|
|
Packit |
fcad23 |
Otherwise, the certificate and appropriate cipher_suites will
|
|
Packit |
fcad23 |
need to be passed to the openSession() ASI as supplemental
|
|
Packit |
fcad23 |
information or configured through an implementation-dependent
|
|
Packit |
fcad23 |
mechanism. It is also implementation-dependent and possibly
|
|
Packit |
fcad23 |
policy-dependent how tmRequestedSecurityLevel will be used to
|
|
Packit |
fcad23 |
influence the security capabilities provided by the (D)TLS
|
|
Packit |
fcad23 |
connection. However this is done, the security capabilities
|
|
Packit |
fcad23 |
provided by (D)TLS MUST be at least as high as the level of
|
|
Packit |
fcad23 |
security indicated by the tmRequestedSecurityLevel parameter.
|
|
Packit |
fcad23 |
The actual security level of the session is reported in the
|
|
Packit |
fcad23 |
tmStateReference cache as tmSecurityLevel. For (D)TLS to provide
|
|
Packit |
fcad23 |
strong authentication, each principal acting as a command
|
|
Packit |
fcad23 |
generator SHOULD have its own certificate.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
Implementation notes: we do most of this in the
|
|
Packit |
fcad23 |
sslctx_client_setup The transport should have been
|
|
Packit |
fcad23 |
f_config()ed with the proper fingerprints to use (which is
|
|
Packit |
fcad23 |
stored in tlsdata), or we'll use the default identity
|
|
Packit |
fcad23 |
fingerprint if that can be found.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* XXX: check securityLevel and ensure no NULL fingerprints are used */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* set up the needed SSL context */
|
|
Packit |
fcad23 |
tlsdata->ssl_context = ctx = sslctx_client_setup(TLS_method(), tlsdata);
|
|
Packit |
fcad23 |
if (!ctx) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "failed to create TLS context\n");
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
3) Using the destTransportDomain and destTransportAddress values,
|
|
Packit |
fcad23 |
the client will initiate the (D)TLS handshake protocol to
|
|
Packit |
fcad23 |
establish session keys for message integrity and encryption.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation note:
|
|
Packit |
fcad23 |
The transport domain and address are pre-processed by this point
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Create a BIO connection for it */
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "connecting to tlstcp %s\n",
|
|
Packit |
fcad23 |
tlsdata->addr_string));
|
|
Packit |
fcad23 |
t->remote = (void *) strdup(tlsdata->addr_string);
|
|
Packit |
fcad23 |
t->remote_length = strlen(tlsdata->addr_string) + 1;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
bio = BIO_new_connect(tlsdata->addr_string);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
3) continued:
|
|
Packit |
fcad23 |
If the attempt to establish a session is unsuccessful, then
|
|
Packit |
fcad23 |
snmpTlstmSessionOpenErrors is incremented, an error indication is
|
|
Packit |
fcad23 |
returned, and processing stops.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (NULL == bio) {
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp: failed to create bio\n");
|
|
Packit |
fcad23 |
_openssl_log_error(rc, NULL, "BIO creation");
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Tell the BIO to actually do the connection */
|
|
Packit |
fcad23 |
if ((rc = BIO_do_connect(bio)) <= 0) {
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp: failed to connect to %s\n",
|
|
Packit |
fcad23 |
tlsdata->addr_string);
|
|
Packit |
fcad23 |
_openssl_log_error(rc, NULL, "BIO_do_connect");
|
|
Packit |
fcad23 |
BIO_free(bio);
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Create the SSL layer on top of the socket bio */
|
|
Packit |
fcad23 |
ssl = tlsdata->ssl = SSL_new(ctx);
|
|
Packit |
fcad23 |
if (NULL == ssl) {
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp: failed to create a SSL connection\n");
|
|
Packit |
fcad23 |
BIO_free(bio);
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Bind the SSL layer to the BIO */
|
|
Packit |
fcad23 |
SSL_set_bio(ssl, bio, bio);
|
|
Packit |
fcad23 |
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
verify_info = SNMP_MALLOC_TYPEDEF(_netsnmp_verify_info);
|
|
Packit |
fcad23 |
if (NULL == verify_info) {
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp: failed to create a SSL connection\n");
|
|
Packit |
fcad23 |
SSL_shutdown(ssl);
|
|
Packit |
fcad23 |
BIO_free(bio);
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
SSL_set_ex_data(ssl, tls_get_verify_info_index(), verify_info);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Then have SSL do it's connection over the BIO */
|
|
Packit |
fcad23 |
if ((rc = SSL_connect(ssl)) <= 0) {
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp: failed to ssl_connect\n");
|
|
Packit |
fcad23 |
BIO_free(bio);
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
3) continued:
|
|
Packit |
fcad23 |
If the session failed to open because the presented
|
|
Packit |
fcad23 |
server certificate was unknown or invalid then the
|
|
Packit |
fcad23 |
snmpTlstmSessionUnknownServerCertificate or
|
|
Packit |
fcad23 |
snmpTlstmSessionInvalidServerCertificates MUST be
|
|
Packit |
fcad23 |
incremented and a snmpTlstmServerCertificateUnknown or
|
|
Packit |
fcad23 |
snmpTlstmServerInvalidCertificate notification SHOULD be
|
|
Packit |
fcad23 |
sent as appropriate. Reasons for server certificate
|
|
Packit |
fcad23 |
invalidation includes, but is not limited to,
|
|
Packit |
fcad23 |
cryptographic validation failures and an unexpected
|
|
Packit |
fcad23 |
presented certificate identity.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
4) The (D)TLS client MUST then verify that the (D)TLS server's
|
|
Packit |
fcad23 |
presented certificate is the expected certificate. The (D)TLS
|
|
Packit |
fcad23 |
client MUST NOT transmit SNMP messages until the server
|
|
Packit |
fcad23 |
certificate has been authenticated, the client certificate has
|
|
Packit |
fcad23 |
been transmitted and the TLS connection has been fully
|
|
Packit |
fcad23 |
established.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
If the connection is being established from configuration based
|
|
Packit |
fcad23 |
on SNMP-TARGET-MIB configuration, then the snmpTlstmAddrTable
|
|
Packit |
fcad23 |
DESCRIPTION clause describes how the verification is done (using
|
|
Packit |
fcad23 |
either a certificate fingerprint, or an identity authenticated
|
|
Packit |
fcad23 |
via certification path validation).
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
If the connection is being established for reasons other than
|
|
Packit |
fcad23 |
configuration found in the SNMP-TARGET-MIB then configuration and
|
|
Packit |
fcad23 |
procedures outside the scope of this document should be followed.
|
|
Packit |
fcad23 |
Configuration mechanisms SHOULD be similar in nature to those
|
|
Packit |
fcad23 |
defined in the snmpTlstmAddrTable to ensure consistency across
|
|
Packit |
fcad23 |
management configuration systems. For example, a command-line
|
|
Packit |
fcad23 |
tool for generating SNMP GETs might support specifying either the
|
|
Packit |
fcad23 |
server's certificate fingerprint or the expected host name as a
|
|
Packit |
fcad23 |
command line argument.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Implementation notes:
|
|
Packit |
fcad23 |
- All remote certificate fingerprints are expected to be
|
|
Packit |
fcad23 |
stored in the transport's config information. This is
|
|
Packit |
fcad23 |
true both for CLI clients and TARGET-MIB sessions.
|
|
Packit |
fcad23 |
- netsnmp_tlsbase_verify_server_cert implements these checks
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
if (netsnmp_tlsbase_verify_server_cert(ssl, tlsdata) != SNMPERR_SUCCESS) {
|
|
Packit |
fcad23 |
/* XXX: unknown vs invalid; two counters */
|
|
Packit |
fcad23 |
snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONUNKNOWNSERVERCERTIFICATE);
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "tlstcp: failed to verify ssl certificate\n");
|
|
Packit |
fcad23 |
SSL_shutdown(ssl);
|
|
Packit |
fcad23 |
BIO_free(bio);
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
5) (D)TLS provides assurance that the authenticated identity has
|
|
Packit |
fcad23 |
been signed by a trusted configured certification authority. If
|
|
Packit |
fcad23 |
verification of the server's certificate fails in any way (for
|
|
Packit |
fcad23 |
example because of failures in cryptographic verification or the
|
|
Packit |
fcad23 |
presented identity did not match the expected named entity) then
|
|
Packit |
fcad23 |
the session establishment MUST fail, the
|
|
Packit |
fcad23 |
snmpTlstmSessionInvalidServerCertificates object is incremented.
|
|
Packit |
fcad23 |
If the session can not be opened for any reason at all, including
|
|
Packit |
fcad23 |
cryptographic verification failures, then the
|
|
Packit |
fcad23 |
snmpTlstmSessionOpenErrors counter is incremented and processing
|
|
Packit |
fcad23 |
stops.
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* XXX: add snmpTlstmSessionInvalidServerCertificates on
|
|
Packit |
fcad23 |
crypto failure */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* RFC5953 Section 5.3.1: Establishing a Session as a Client
|
|
Packit |
fcad23 |
6) The TLSTM-specific session identifier (tlstmSessionID) is set in
|
|
Packit |
fcad23 |
the tmSessionID of the tmStateReference passed to the TLS
|
|
Packit |
fcad23 |
Transport Model to indicate that the session has been established
|
|
Packit |
fcad23 |
successfully and to point to a specific (D)TLS connection for
|
|
Packit |
fcad23 |
future use. The tlstmSessionID is also stored in the LCD for
|
|
Packit |
fcad23 |
later lookup during processing of incoming messages
|
|
Packit |
fcad23 |
(Section 5.1.2).
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
/* Implementation notes:
|
|
Packit |
fcad23 |
- the tlsdata pointer is used as our session identifier, as
|
|
Packit |
fcad23 |
noted in the netsnmp_tlstcp_recv() function comments.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
t->sock = BIO_get_fd(bio, NULL);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
} else {
|
|
Packit |
fcad23 |
#ifndef NETSNMP_NO_LISTEN_SUPPORT
|
|
Packit |
fcad23 |
/* Is the server */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* Create the socket bio */
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "listening on tlstcp port %s\n",
|
|
Packit |
fcad23 |
tlsdata->addr_string));
|
|
Packit |
fcad23 |
tlsdata->accept_bio = BIO_new_accept(tlsdata->addr_string);
|
|
Packit |
fcad23 |
t->local = (void *) strdup(tlsdata->addr_string);
|
|
Packit |
fcad23 |
t->local_length = strlen(tlsdata->addr_string)+1;
|
|
Packit |
fcad23 |
if (NULL == tlsdata->accept_bio) {
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "TLSTCP: Falied to create a accept BIO\n");
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* openssl requires an initial accept to bind() the socket */
|
|
Packit |
fcad23 |
if (BIO_do_accept(tlsdata->accept_bio) <= 0) {
|
|
Packit |
fcad23 |
_openssl_log_error(rc, tlsdata->ssl, "BIO_do__accept");
|
|
Packit |
fcad23 |
snmp_log(LOG_ERR, "TLSTCP: Falied to do first accept on the TLS accept BIO\n");
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* create the OpenSSL TLS context */
|
|
Packit |
fcad23 |
tlsdata->ssl_context = sslctx_server_setup(TLS_method());
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
t->sock = BIO_get_fd(tlsdata->accept_bio, NULL);
|
|
Packit |
fcad23 |
t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;
|
|
Packit |
fcad23 |
#else /* NETSNMP_NO_LISTEN_SUPPORT */
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
return t;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* Create a TLS-based transport for SNMP. Local is TRUE if addr is the local
|
|
Packit |
fcad23 |
* address to bind to (i.e. this is a server-type session); otherwise addr is
|
|
Packit |
fcad23 |
* the remote address to send things to.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_transport *
|
|
Packit |
fcad23 |
netsnmp_tlstcp_transport(const char *addr_string, int isserver)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
netsnmp_transport *t = NULL;
|
|
Packit |
fcad23 |
_netsnmpTLSBaseData *tlsdata;
|
|
Packit |
fcad23 |
char *cp;
|
|
Packit |
fcad23 |
char buf[SPRINT_MAX_LEN];
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#ifdef NETSNMP_NO_LISTEN_SUPPORT
|
|
Packit |
fcad23 |
if (isserver)
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* allocate our transport structure */
|
|
Packit |
fcad23 |
t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
|
|
Packit |
fcad23 |
if (NULL == t) {
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* allocate our TLS specific data */
|
|
Packit |
fcad23 |
if (NULL == (tlsdata = netsnmp_tlsbase_allocate_tlsdata(t, isserver)))
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (!isserver)
|
|
Packit |
fcad23 |
t->flags |= NETSNMP_TLSBASE_IS_CLIENT;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlsdata->addr_string = strdup(addr_string);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* see if we can extract the remote hostname */
|
|
Packit |
fcad23 |
if (!isserver && tlsdata && addr_string) {
|
|
Packit |
fcad23 |
/* search for a : */
|
|
Packit |
fcad23 |
if (NULL != (cp = strrchr(addr_string, ':'))) {
|
|
Packit |
fcad23 |
sprintf(buf, "%.*s",
|
|
Packit |
fcad23 |
(int) SNMP_MIN(cp - addr_string, sizeof(buf) - 1),
|
|
Packit |
fcad23 |
addr_string);
|
|
Packit |
fcad23 |
} else {
|
|
Packit |
fcad23 |
/* else the entire spec is a host name only */
|
|
Packit |
fcad23 |
strlcpy(buf, addr_string, sizeof(buf));
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
tlsdata->their_hostname = strdup(buf);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
t->data = tlsdata;
|
|
Packit |
fcad23 |
t->data_length = sizeof(_netsnmpTLSBaseData);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* Set Domain
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
t->domain = netsnmpTLSTCPDomain;
|
|
Packit |
fcad23 |
t->domain_length = netsnmpTLSTCPDomain_len;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* 16-bit length field, 8 byte TLS header, 20 byte IPv4 header
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
t->msgMaxSize = 0xffff - 8 - 20;
|
|
Packit |
fcad23 |
t->f_recv = netsnmp_tlstcp_recv;
|
|
Packit |
fcad23 |
t->f_send = netsnmp_tlstcp_send;
|
|
Packit |
fcad23 |
t->f_open = netsnmp_tlstcp_open;
|
|
Packit |
fcad23 |
t->f_close = netsnmp_tlstcp_close;
|
|
Packit |
fcad23 |
t->f_accept = netsnmp_tlstcp_accept;
|
|
Packit |
fcad23 |
t->f_copy = netsnmp_tlstcp_copy;
|
|
Packit |
fcad23 |
t->f_config = netsnmp_tlsbase_config;
|
|
Packit |
fcad23 |
t->f_setup_session = netsnmp_tlsbase_session_init;
|
|
Packit |
fcad23 |
t->f_fmtaddr = netsnmp_tlstcp_fmtaddr;
|
|
Packit |
fcad23 |
t->f_get_taddr = netsnmp_tlstcp_get_taddr;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
t->flags |= NETSNMP_TRANSPORT_FLAG_TUNNELED | NETSNMP_TRANSPORT_FLAG_STREAM;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
return t;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_transport *
|
|
Packit |
fcad23 |
netsnmp_tlstcp_create_tstring(const char *str, int local,
|
|
Packit |
fcad23 |
const char *default_target)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
char buf[SPRINT_MAX_LEN];
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
if (str == NULL || *str == '\0')
|
|
Packit |
fcad23 |
str = default_target + 1; /* drop the leading : */
|
|
Packit |
fcad23 |
else if (!strchr(str, ':')) {
|
|
Packit |
fcad23 |
/* it's either :port or :address. Try to guess which. */
|
|
Packit |
fcad23 |
const char *cp;
|
|
Packit |
fcad23 |
int isport = 1;
|
|
Packit |
fcad23 |
for(cp = str; *cp != '\0'; cp++) {
|
|
Packit |
fcad23 |
/* if ALL numbers, it must be just a port */
|
|
Packit |
fcad23 |
/* if it contains anything else, assume a host or ip address */
|
|
Packit |
fcad23 |
if (!isdigit(0xFF & *cp)) {
|
|
Packit |
fcad23 |
isport = 0;
|
|
Packit |
fcad23 |
break;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
if (isport) {
|
|
Packit |
fcad23 |
/* Just :NNN can be passed to openssl */
|
|
Packit |
fcad23 |
snprintf(buf, sizeof(buf)-1, "0.0.0.0:%s", str);
|
|
Packit |
fcad23 |
} else {
|
|
Packit |
fcad23 |
/* add the default port */
|
|
Packit |
fcad23 |
snprintf(buf, sizeof(buf)-1, "%s%s", str, default_target);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
str = buf;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
return netsnmp_tlstcp_transport(str, local);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_transport *
|
|
Packit |
fcad23 |
netsnmp_tlstcp_create_ostring(const void *o, size_t o_len, int local)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
char buf[SPRINT_MAX_LEN];
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* ensure buf is big enough */
|
|
Packit |
fcad23 |
if (o_len > SPRINT_MAX_LEN - 1)
|
|
Packit |
fcad23 |
return NULL;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
memcpy(buf, o, o_len);
|
|
Packit |
fcad23 |
buf[o_len] = '\0';
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
return netsnmp_tlstcp_transport(buf, local);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
void
|
|
Packit |
fcad23 |
netsnmp_tlstcp_ctor(void)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
DEBUGMSGTL(("tlstcp", "registering TLS constructor\n"));
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* config settings */
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlstcpDomain.name = netsnmpTLSTCPDomain;
|
|
Packit |
fcad23 |
tlstcpDomain.name_length = netsnmpTLSTCPDomain_len;
|
|
Packit |
fcad23 |
tlstcpDomain.prefix = (const char**)calloc(3, sizeof(char *));
|
|
Packit |
fcad23 |
tlstcpDomain.prefix[0] = "tlstcp";
|
|
Packit |
fcad23 |
tlstcpDomain.prefix[1] = "tls";
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
tlstcpDomain.f_create_from_tstring = NULL;
|
|
Packit |
fcad23 |
tlstcpDomain.f_create_from_tstring_new = netsnmp_tlstcp_create_tstring;
|
|
Packit |
fcad23 |
tlstcpDomain.f_create_from_ostring = netsnmp_tlstcp_create_ostring;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
netsnmp_tdomain_register(&tlstcpDomain);
|
|
Packit |
fcad23 |
}
|