Blame snmplib/transports/snmpTLSBaseDomain.c

Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#include <net-snmp/net-snmp-features.h>
Packit fcad23
#include <net-snmp/types.h>
Packit fcad23
Packit fcad23
netsnmp_feature_require(cert_util)
Packit fcad23
Packit fcad23
#if HAVE_DMALLOC_H
Packit fcad23
#include <dmalloc.h>
Packit fcad23
#endif
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_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
#include <errno.h>
Packit fcad23
#include <ctype.h>
Packit fcad23
Packit fcad23
/* OpenSSL Includes */
Packit fcad23
#include <openssl/bio.h>
Packit fcad23
#include <openssl/ssl.h>
Packit fcad23
#include <openssl/err.h>
Packit fcad23
#include <openssl/x509.h>
Packit fcad23
#include <openssl/x509_vfy.h>
Packit fcad23
#include <openssl/x509v3.h>
Packit fcad23
Packit fcad23
#include <net-snmp/config_api.h>
Packit fcad23
#include <net-snmp/library/container.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/default_store.h>
Packit fcad23
#include <net-snmp/library/callback.h>
Packit fcad23
#include <net-snmp/library/snmp_logging.h>
Packit fcad23
#include <net-snmp/library/snmp_api.h>
Packit fcad23
#include <net-snmp/library/tools.h>
Packit fcad23
#include <net-snmp/library/snmp_debug.h>
Packit fcad23
#include <net-snmp/library/snmp_assert.h>
Packit fcad23
#include <net-snmp/library/snmp_transport.h>
Packit fcad23
#include <net-snmp/library/snmp_secmod.h>
Packit fcad23
#include <net-snmp/library/read_config.h>
Packit fcad23
#include <net-snmp/library/system.h>
Packit fcad23
#include <net-snmp/library/snmpTLSBaseDomain.h>
Packit fcad23
Packit fcad23
#define LOGANDDIE(msg) do { snmp_log(LOG_ERR, "%s\n", msg); return 0; } while(0)
Packit fcad23
Packit fcad23
int openssl_local_index;
Packit fcad23
Packit fcad23
/* this is called during negotiation */
Packit fcad23
int verify_callback(int ok, X509_STORE_CTX *ctx) {
Packit fcad23
    int err, depth;
Packit fcad23
    char buf[1024], *fingerprint;
Packit fcad23
    X509 *thecert;
Packit fcad23
    netsnmp_cert *cert;
Packit fcad23
    _netsnmp_verify_info *verify_info;
Packit fcad23
    SSL *ssl;
Packit fcad23
Packit fcad23
    thecert = X509_STORE_CTX_get_current_cert(ctx);
Packit fcad23
    err = X509_STORE_CTX_get_error(ctx);
Packit fcad23
    depth = X509_STORE_CTX_get_error_depth(ctx);
Packit fcad23
    
Packit fcad23
    /* things to do: */
Packit fcad23
Packit fcad23
    X509_NAME_oneline(X509_get_subject_name(thecert), buf, sizeof(buf));
Packit fcad23
    fingerprint = netsnmp_openssl_cert_get_fingerprint(thecert, -1);
Packit fcad23
    DEBUGMSGTL(("tls_x509:verify", "Cert: %s\n", buf));
Packit fcad23
    DEBUGMSGTL(("tls_x509:verify", "  fp: %s\n", fingerprint ?
Packit fcad23
                fingerprint : "unknown"));
Packit fcad23
Packit fcad23
    ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
Packit fcad23
    verify_info = SSL_get_ex_data(ssl, openssl_local_index);
Packit fcad23
Packit fcad23
    if (verify_info && ok && depth > 0) {
Packit fcad23
        /* remember that a parent certificate has been marked as trusted */
Packit fcad23
        verify_info->flags |= VRFY_PARENT_WAS_OK;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* this ensures for self-signed certificates we have a valid
Packit fcad23
       locally known fingerprint and then accept it */
Packit fcad23
    if (!ok &&
Packit fcad23
        (X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT == err ||
Packit fcad23
         X509_V_ERR_CERT_UNTRUSTED == err ||
Packit fcad23
         X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE == err ||
Packit fcad23
         X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN == err)) {
Packit fcad23
Packit fcad23
        cert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_FINGERPRINT,
Packit fcad23
                                 (void*)fingerprint);
Packit fcad23
        if (cert)
Packit fcad23
            DEBUGMSGTL(("tls_x509:verify", " Found locally: %s/%s\n",
Packit fcad23
                        cert->info.dir, cert->info.filename));
Packit fcad23
Packit fcad23
Packit fcad23
        if (cert) {
Packit fcad23
            DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err)));
Packit fcad23
            DEBUGMSGTL(("tls_x509:verify", "  accepting matching fp of self-signed certificate found in: %s\n",
Packit fcad23
                        cert->info.filename));
Packit fcad23
            SNMP_FREE(fingerprint);
Packit fcad23
            return 1;
Packit fcad23
        } else {
Packit fcad23
            DEBUGMSGTL(("tls_x509:verify", "  no matching fp found\n"));
Packit fcad23
            /* log where we are and why called */
Packit fcad23
            snmp_log(LOG_ERR, "tls verification failure: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err));
Packit fcad23
            SNMP_FREE(fingerprint);
Packit fcad23
            return 0;
Packit fcad23
        }
Packit fcad23
Packit fcad23
#if 0
Packit fcad23
        /*
Packit fcad23
         * This code is unreachable because of the return statements above.
Packit fcad23
         * Comment it out to avoid that Coverity complains about this code.
Packit fcad23
         */
Packit fcad23
        if (0 == depth && verify_info &&
Packit fcad23
            (verify_info->flags & VRFY_PARENT_WAS_OK)) {
Packit fcad23
            DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err)));
Packit fcad23
            DEBUGMSGTL(("tls_x509:verify", "  a parent was ok, so returning ok for this child certificate\n"));
Packit fcad23
            SNMP_FREE(fingerprint);
Packit fcad23
            return 1; /* we'll check the hostname later at this level */
Packit fcad23
        }
Packit fcad23
#endif
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (0 == ok)
Packit fcad23
        snmp_log(LOG_ERR, "tls verification failure: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err));
Packit fcad23
    else
Packit fcad23
        DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err)));
Packit fcad23
    DEBUGMSGTL(("tls_x509:verify", "  returning the passed in value of %d\n",
Packit fcad23
                ok));
Packit fcad23
    SNMP_FREE(fingerprint);
Packit fcad23
    return(ok);
Packit fcad23
}
Packit fcad23
Packit fcad23
#define VERIFIED_FINGERPRINT      0
Packit fcad23
#define NO_FINGERPRINT_AVAILABLE  1
Packit fcad23
#define FAILED_FINGERPRINT_VERIFY 2
Packit fcad23
Packit fcad23
static int
Packit fcad23
_netsnmp_tlsbase_verify_remote_fingerprint(X509 *remote_cert,
Packit fcad23
                                           _netsnmpTLSBaseData *tlsdata,
Packit fcad23
                                           int try_default) {
Packit fcad23
Packit fcad23
    char            *fingerprint;
Packit fcad23
Packit fcad23
    fingerprint =
Packit fcad23
        netsnmp_openssl_cert_get_fingerprint(remote_cert, -1);
Packit fcad23
Packit fcad23
    if (!fingerprint) {
Packit fcad23
        /* no peer cert */
Packit fcad23
        snmp_log(LOG_ERR, "failed to get fingerprint of remote certificate\n");
Packit fcad23
        return FAILED_FINGERPRINT_VERIFY;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!tlsdata->their_fingerprint && tlsdata->their_identity) {
Packit fcad23
        /* we have an identity; try and find it's fingerprint */
Packit fcad23
        netsnmp_cert *peer_cert;
Packit fcad23
        peer_cert =
Packit fcad23
            netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_MULTIPLE,
Packit fcad23
                              tlsdata->their_identity);
Packit fcad23
Packit fcad23
        if (peer_cert)
Packit fcad23
            tlsdata->their_fingerprint =
Packit fcad23
                netsnmp_openssl_cert_get_fingerprint(peer_cert->ocert, -1);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!tlsdata->their_fingerprint && try_default) {
Packit fcad23
        /* try for the default instead */
Packit fcad23
        netsnmp_cert *peer_cert;
Packit fcad23
        peer_cert =
Packit fcad23
            netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_DEFAULT,
Packit fcad23
                              NULL);
Packit fcad23
Packit fcad23
        if (peer_cert)
Packit fcad23
            tlsdata->their_fingerprint =
Packit fcad23
                netsnmp_openssl_cert_get_fingerprint(peer_cert->ocert, -1);
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if (tlsdata->their_fingerprint) {
Packit fcad23
        netsnmp_fp_lowercase_and_strip_colon(tlsdata->their_fingerprint);
Packit fcad23
        if (0 != strcmp(tlsdata->their_fingerprint, fingerprint)) {
Packit fcad23
            snmp_log(LOG_ERR, "The fingerprint from the remote side's certificate didn't match the expected\n");
Packit fcad23
            snmp_log(LOG_ERR, "  got %s, expected %s\n",
Packit fcad23
                     fingerprint, tlsdata->their_fingerprint);
Packit fcad23
            free(fingerprint);
Packit fcad23
            return FAILED_FINGERPRINT_VERIFY;
Packit fcad23
        }
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSGTL(("tls_x509:verify", "No fingerprint for the remote entity available to verify\n"));
Packit fcad23
        free(fingerprint);
Packit fcad23
        return NO_FINGERPRINT_AVAILABLE;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    free(fingerprint);
Packit fcad23
    return VERIFIED_FINGERPRINT;
Packit fcad23
}
Packit fcad23
Packit fcad23
/* this is called after the connection on the client side by us to check
Packit fcad23
   other aspects about the connection */
Packit fcad23
int
Packit fcad23
netsnmp_tlsbase_verify_server_cert(SSL *ssl, _netsnmpTLSBaseData *tlsdata) {
Packit fcad23
    /* XXX */
Packit fcad23
    X509            *remote_cert;
Packit fcad23
    char            *check_name;
Packit fcad23
    int              ret;
Packit fcad23
    
Packit fcad23
    netsnmp_assert_or_return(ssl != NULL, SNMPERR_GENERR);
Packit fcad23
    netsnmp_assert_or_return(tlsdata != NULL, SNMPERR_GENERR);
Packit fcad23
    
Packit fcad23
    if (NULL == (remote_cert = SSL_get_peer_certificate(ssl))) {
Packit fcad23
        /* no peer cert */
Packit fcad23
        DEBUGMSGTL(("tls_x509:verify",
Packit fcad23
                    "remote connection provided no certificate (yet)\n"));
Packit fcad23
        return SNMPERR_TLS_NO_CERTIFICATE;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* make sure that the fingerprint matches */
Packit fcad23
    ret = _netsnmp_tlsbase_verify_remote_fingerprint(remote_cert, tlsdata, 1);
Packit fcad23
    switch(ret) {
Packit fcad23
    case VERIFIED_FINGERPRINT:
Packit fcad23
        return SNMPERR_SUCCESS;
Packit fcad23
Packit fcad23
    case FAILED_FINGERPRINT_VERIFY:
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
Packit fcad23
    case NO_FINGERPRINT_AVAILABLE:
Packit fcad23
        if (tlsdata->their_hostname && tlsdata->their_hostname[0] != '\0') {
Packit fcad23
            GENERAL_NAMES      *onames;
Packit fcad23
            const GENERAL_NAME *oname = NULL;
Packit fcad23
            int                 i, j;
Packit fcad23
            int                 count;
Packit fcad23
            char                buf[SPRINT_MAX_LEN];
Packit fcad23
            int                 is_wildcarded = 0;
Packit fcad23
            char               *compare_to;
Packit fcad23
Packit fcad23
            /* see if the requested hostname has a wildcard prefix */
Packit fcad23
            if (strncmp(tlsdata->their_hostname, "*.", 2) == 0) {
Packit fcad23
                is_wildcarded = 1;
Packit fcad23
                compare_to = tlsdata->their_hostname + 2;
Packit fcad23
            } else {
Packit fcad23
                compare_to = tlsdata->their_hostname;
Packit fcad23
            }
Packit fcad23
Packit fcad23
            /* if the hostname we were expecting to talk to matches
Packit fcad23
               the cert, then we can accept this connection. */
Packit fcad23
Packit fcad23
            /* check against the DNS subjectAltName */
Packit fcad23
            onames = (GENERAL_NAMES *)X509_get_ext_d2i(remote_cert,
Packit fcad23
                                                       NID_subject_alt_name,
Packit fcad23
                                                       NULL, NULL );
Packit fcad23
            if (NULL != onames) {
Packit fcad23
                count = sk_GENERAL_NAME_num(onames);
Packit fcad23
Packit fcad23
                for (i=0 ; i 
Packit fcad23
                    oname = sk_GENERAL_NAME_value(onames, i);
Packit fcad23
                    if (GEN_DNS == oname->type) {
Packit fcad23
Packit fcad23
                        /* get the value */
Packit fcad23
                        ASN1_STRING_to_UTF8((unsigned char**)&check_name,
Packit fcad23
                                            oname->d.ia5);
Packit fcad23
Packit fcad23
                        /* convert to lowercase for comparisons */
Packit fcad23
                        for (j = 0 ;
Packit fcad23
                             *check_name && j < sizeof(buf)-1;
Packit fcad23
                             ++check_name, ++j ) {
Packit fcad23
                            if (isascii(*check_name))
Packit fcad23
                                buf[j] = tolower(0xFF & *check_name);
Packit fcad23
                        }
Packit fcad23
                        if (j < sizeof(buf))
Packit fcad23
                            buf[j] = '\0';
Packit fcad23
                        check_name = buf;
Packit fcad23
                        
Packit fcad23
                        if (is_wildcarded) {
Packit fcad23
                            /* we *only* allow passing till the first '.' */
Packit fcad23
                            /* ie *.example.com can't match a.b.example.com */
Packit fcad23
                            check_name = strchr(check_name, '.') + 1;
Packit fcad23
                        }
Packit fcad23
Packit fcad23
                        DEBUGMSGTL(("tls_x509:verify", "checking subjectAltname of dns:%s\n", check_name));
Packit fcad23
                        if (strcmp(compare_to, check_name) == 0) {
Packit fcad23
Packit fcad23
                            DEBUGMSGTL(("tls_x509:verify", "Successful match on a subjectAltname of dns:%s\n", check_name));
Packit fcad23
                            return SNMPERR_SUCCESS;
Packit fcad23
                        }
Packit fcad23
                    }
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
Packit fcad23
            /* check the common name for a match */
Packit fcad23
            check_name =
Packit fcad23
                netsnmp_openssl_cert_get_commonName(remote_cert, NULL, NULL);
Packit fcad23
Packit fcad23
            if (is_wildcarded) {
Packit fcad23
                /* we *only* allow passing till the first '.' */
Packit fcad23
                /* ie *.example.com can't match a.b.example.com */
Packit fcad23
                if (check_name)
Packit fcad23
                    check_name = strchr(check_name, '.');
Packit fcad23
                if (check_name)
Packit fcad23
                    check_name++;
Packit fcad23
            }
Packit fcad23
Packit fcad23
            if (check_name && strcmp(compare_to, check_name) == 0) {
Packit fcad23
                DEBUGMSGTL(("tls_x509:verify", "Successful match on a common name of %s\n", check_name));
Packit fcad23
                return SNMPERR_SUCCESS;
Packit fcad23
            }
Packit fcad23
Packit fcad23
            snmp_log(LOG_ERR, "No matching names in the certificate to match the expected %s\n", tlsdata->their_hostname);
Packit fcad23
            return SNMPERR_GENERR;
Packit fcad23
Packit fcad23
        }
Packit fcad23
        /* XXX: check for hostname match instead */
Packit fcad23
        snmp_log(LOG_ERR, "Can not verify a remote server identity without configuration\n");
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
    DEBUGMSGTL(("tls_x509:verify", "shouldn't get here\n"));
Packit fcad23
    return SNMPERR_GENERR;
Packit fcad23
}
Packit fcad23
Packit fcad23
/* this is called after the connection on the server side by us to check
Packit fcad23
   the validity of the client's certificate */
Packit fcad23
int
Packit fcad23
netsnmp_tlsbase_verify_client_cert(SSL *ssl, _netsnmpTLSBaseData *tlsdata) {
Packit fcad23
    /* XXX */
Packit fcad23
    X509            *remote_cert;
Packit fcad23
    int ret;
Packit fcad23
Packit fcad23
    /* RFC5953: section 5.3.2, paragraph 1:
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
    /* Implementation notes:
Packit fcad23
       + path validation is taken care of during the openssl verify
Packit fcad23
         routines, our part of which is hanlded in verify_callback
Packit fcad23
         above.
Packit fcad23
       + fingerprint verification happens below.
Packit fcad23
    */
Packit fcad23
    if (NULL == (remote_cert = SSL_get_peer_certificate(ssl))) {
Packit fcad23
        /* no peer cert */
Packit fcad23
        DEBUGMSGTL(("tls_x509:verify",
Packit fcad23
                    "remote connection provided no certificate (yet)\n"));
Packit fcad23
        return SNMPERR_TLS_NO_CERTIFICATE;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* we don't force a known remote fingerprint for a client since we
Packit fcad23
       will accept any certificate we know about (and later derive the
Packit fcad23
       securityName from it and apply access control) */
Packit fcad23
    ret = _netsnmp_tlsbase_verify_remote_fingerprint(remote_cert, tlsdata, 0);
Packit fcad23
    switch(ret) {
Packit fcad23
    case FAILED_FINGERPRINT_VERIFY:
Packit fcad23
        DEBUGMSGTL(("tls_x509:verify", "failed to verify a client fingerprint\n"));
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
Packit fcad23
    case NO_FINGERPRINT_AVAILABLE:
Packit fcad23
        DEBUGMSGTL(("tls_x509:verify", "no known fingerprint available (not a failure case)\n"));
Packit fcad23
        return SNMPERR_SUCCESS;
Packit fcad23
Packit fcad23
    case VERIFIED_FINGERPRINT:
Packit fcad23
        DEBUGMSGTL(("tls_x509:verify", "Verified client fingerprint\n"));
Packit fcad23
        tlsdata->flags |= NETSNMP_TLSBASE_CERT_FP_VERIFIED;
Packit fcad23
        return SNMPERR_SUCCESS;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("tls_x509:verify", "shouldn't get here\n"));
Packit fcad23
    return SNMPERR_GENERR;
Packit fcad23
}
Packit fcad23
Packit fcad23
/* this is called after the connection on the server side by us to
Packit fcad23
   check other aspects about the connection and obtain the
Packit fcad23
   securityName from the remote certificate. */
Packit fcad23
int
Packit fcad23
netsnmp_tlsbase_extract_security_name(SSL *ssl, _netsnmpTLSBaseData *tlsdata) {
Packit fcad23
    netsnmp_container  *chain_maps;
Packit fcad23
    netsnmp_cert_map   *cert_map, *peer_cert;
Packit fcad23
    netsnmp_iterator  *itr;
Packit fcad23
    int                 rc;
Packit fcad23
Packit fcad23
    netsnmp_assert_or_return(ssl != NULL, SNMPERR_GENERR);
Packit fcad23
    netsnmp_assert_or_return(tlsdata != NULL, SNMPERR_GENERR);
Packit fcad23
Packit fcad23
    if (NULL == (chain_maps = netsnmp_openssl_get_cert_chain(ssl)))
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    /*
Packit fcad23
     * map fingerprints to mapping entries
Packit fcad23
     */
Packit fcad23
    rc = netsnmp_cert_get_secname_maps(chain_maps);
Packit fcad23
    if ((-1 == rc) || (CONTAINER_SIZE(chain_maps) == 0)) {
Packit fcad23
        netsnmp_cert_map_container_free(chain_maps);
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * change container to sorted (by clearing unsorted option), then
Packit fcad23
     * iterate over it until we find a map that returns a secname.
Packit fcad23
     */
Packit fcad23
    CONTAINER_SET_OPTIONS(chain_maps, 0, rc);
Packit fcad23
    itr = CONTAINER_ITERATOR(chain_maps);
Packit fcad23
    if (NULL == itr) {
Packit fcad23
        snmp_log(LOG_ERR, "could not get iterator for secname fingerprints\n");
Packit fcad23
        netsnmp_cert_map_container_free(chain_maps);
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
    peer_cert = cert_map = ITERATOR_FIRST(itr);
Packit fcad23
    for( ; !tlsdata->securityName && cert_map; cert_map = ITERATOR_NEXT(itr))
Packit fcad23
        tlsdata->securityName =
Packit fcad23
            netsnmp_openssl_extract_secname(cert_map, peer_cert);
Packit fcad23
    ITERATOR_RELEASE(itr);
Packit fcad23
Packit fcad23
    netsnmp_cert_map_container_free(chain_maps);
Packit fcad23
       
Packit fcad23
    return (tlsdata->securityName ? SNMPERR_SUCCESS : SNMPERR_GENERR);
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
_trust_this_cert(SSL_CTX *the_ctx, char *certspec) {
Packit fcad23
    netsnmp_cert *trustcert;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("sslctx_client", "Trying to load a trusted certificate: %s\n",
Packit fcad23
                certspec));
Packit fcad23
Packit fcad23
    /* load this identifier into the trust chain */
Packit fcad23
    trustcert = netsnmp_cert_find(NS_CERT_CA,
Packit fcad23
                                  NS_CERTKEY_MULTIPLE,
Packit fcad23
                                  certspec);
Packit fcad23
    if (!trustcert)
Packit fcad23
        trustcert = netsnmp_cert_find(NS_CERT_REMOTE_PEER,
Packit fcad23
                                      NS_CERTKEY_MULTIPLE,
Packit fcad23
                                      certspec);
Packit fcad23
    if (!trustcert)
Packit fcad23
        LOGANDDIE("failed to find requested certificate to trust");
Packit fcad23
        
Packit fcad23
    /* Add the certificate to the context */
Packit fcad23
    if (netsnmp_cert_trust_ca(the_ctx, trustcert) != SNMPERR_SUCCESS)
Packit fcad23
        LOGANDDIE("failed to load trust certificate");
Packit fcad23
Packit fcad23
    return 1;
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
_load_trusted_certs(SSL_CTX *the_ctx) {
Packit fcad23
    netsnmp_container *trusted_certs = NULL;
Packit fcad23
    netsnmp_iterator  *trusted_cert_iterator = NULL;
Packit fcad23
    char *fingerprint;
Packit fcad23
Packit fcad23
    trusted_certs = netsnmp_cert_get_trustlist();
Packit fcad23
    trusted_cert_iterator = CONTAINER_ITERATOR(trusted_certs);
Packit fcad23
    if (trusted_cert_iterator) {
Packit fcad23
        for (fingerprint = (char *) ITERATOR_FIRST(trusted_cert_iterator);
Packit fcad23
             fingerprint; fingerprint = ITERATOR_NEXT(trusted_cert_iterator)) {
Packit fcad23
            if (!_trust_this_cert(the_ctx, fingerprint))
Packit fcad23
                snmp_log(LOG_ERR, "failed to load trust cert: %s\n",
Packit fcad23
                         fingerprint);
Packit fcad23
        }
Packit fcad23
        ITERATOR_RELEASE(trusted_cert_iterator);
Packit fcad23
    }
Packit fcad23
}    
Packit fcad23
Packit fcad23
SSL_CTX *
Packit fcad23
_sslctx_common_setup(SSL_CTX *the_ctx, _netsnmpTLSBaseData *tlsbase) {
Packit fcad23
    char         *crlFile;
Packit fcad23
    char         *cipherList;
Packit fcad23
    X509_LOOKUP  *lookup;
Packit fcad23
    X509_STORE   *cert_store = NULL;
Packit fcad23
Packit fcad23
    _load_trusted_certs(the_ctx);
Packit fcad23
Packit fcad23
    /* add in the CRLs if available */
Packit fcad23
Packit fcad23
    crlFile = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                                    NETSNMP_DS_LIB_X509_CRL_FILE);
Packit fcad23
    if (NULL != crlFile) {
Packit fcad23
        cert_store = SSL_CTX_get_cert_store(the_ctx);
Packit fcad23
        DEBUGMSGTL(("sslctx_client", "loading CRL: %s\n", crlFile));
Packit fcad23
        if (!cert_store)
Packit fcad23
            LOGANDDIE("failed to find certificate store");
Packit fcad23
        if (!(lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file())))
Packit fcad23
            LOGANDDIE("failed to create a lookup function for the CRL file");
Packit fcad23
        if (X509_load_crl_file(lookup, crlFile, X509_FILETYPE_PEM) != 1)
Packit fcad23
            LOGANDDIE("failed to load the CRL file");
Packit fcad23
        /* tell openssl to check CRLs */
Packit fcad23
        X509_STORE_set_flags(cert_store,
Packit fcad23
                             X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    cipherList = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                                       NETSNMP_DS_LIB_TLS_ALGORITMS);
Packit fcad23
    if (NULL != cipherList) {
Packit fcad23
        if (SSL_CTX_set_cipher_list(the_ctx, cipherList) != 1)
Packit fcad23
            LOGANDDIE("failed to set the cipher list to the requested value");
Packit fcad23
        else
Packit fcad23
            snmp_log(LOG_INFO,"set SSL cipher list to '%s'\n", cipherList);
Packit fcad23
    }
Packit fcad23
    return the_ctx;
Packit fcad23
}
Packit fcad23
Packit fcad23
SSL_CTX *
Packit fcad23
sslctx_client_setup(const SSL_METHOD *method, _netsnmpTLSBaseData *tlsbase) {
Packit fcad23
    netsnmp_cert *id_cert, *peer_cert;
Packit fcad23
    SSL_CTX      *the_ctx;
Packit fcad23
Packit fcad23
    /***********************************************************************
Packit fcad23
     * Set up the client context
Packit fcad23
     */
Packit fcad23
    the_ctx = SSL_CTX_new(NETSNMP_REMOVE_CONST(SSL_METHOD *, method));
Packit fcad23
    if (!the_ctx) {
Packit fcad23
        snmp_log(LOG_ERR, "ack: %p\n", the_ctx);
Packit fcad23
        LOGANDDIE("can't create a new context");
Packit fcad23
    }
Packit fcad23
    SSL_CTX_set_read_ahead (the_ctx, 1); /* Required for DTLS */
Packit fcad23
        
Packit fcad23
    SSL_CTX_set_verify(the_ctx,
Packit fcad23
                       SSL_VERIFY_PEER|
Packit fcad23
                       SSL_VERIFY_FAIL_IF_NO_PEER_CERT|
Packit fcad23
                       SSL_VERIFY_CLIENT_ONCE,
Packit fcad23
                       &verify_callback);
Packit fcad23
Packit fcad23
    if (tlsbase->our_identity) {
Packit fcad23
        DEBUGMSGTL(("sslctx_client", "looking for local id: %s\n", tlsbase->our_identity));
Packit fcad23
        id_cert = netsnmp_cert_find(NS_CERT_IDENTITY, NS_CERTKEY_MULTIPLE,
Packit fcad23
                                    tlsbase->our_identity);
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSGTL(("sslctx_client", "looking for default local id: %s\n", tlsbase->our_identity));
Packit fcad23
        id_cert = netsnmp_cert_find(NS_CERT_IDENTITY, NS_CERTKEY_DEFAULT, NULL);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!id_cert)
Packit fcad23
        LOGANDDIE ("error finding client identity keys");
Packit fcad23
Packit fcad23
    if (!id_cert->key || !id_cert->key->okey)
Packit fcad23
        LOGANDDIE("failed to load private key");
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("sslctx_client", "using public key: %s\n",
Packit fcad23
                id_cert->info.filename));
Packit fcad23
    DEBUGMSGTL(("sslctx_client", "using private key: %s\n",
Packit fcad23
                id_cert->key->info.filename));
Packit fcad23
Packit fcad23
    if (SSL_CTX_use_certificate(the_ctx, id_cert->ocert) <= 0)
Packit fcad23
        LOGANDDIE("failed to set the certificate to use");
Packit fcad23
Packit fcad23
    if (SSL_CTX_use_PrivateKey(the_ctx, id_cert->key->okey) <= 0)
Packit fcad23
        LOGANDDIE("failed to set the private key to use");
Packit fcad23
Packit fcad23
    if (!SSL_CTX_check_private_key(the_ctx))
Packit fcad23
        LOGANDDIE("public and private keys incompatible");
Packit fcad23
Packit fcad23
    if (tlsbase->their_identity)
Packit fcad23
        peer_cert = netsnmp_cert_find(NS_CERT_REMOTE_PEER,
Packit fcad23
                                      NS_CERTKEY_MULTIPLE,
Packit fcad23
                                      tlsbase->their_identity);
Packit fcad23
    else
Packit fcad23
        peer_cert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_DEFAULT,
Packit fcad23
                                      NULL);
Packit fcad23
    if (peer_cert) {
Packit fcad23
        DEBUGMSGTL(("sslctx_client", "server's expected public key: %s\n",
Packit fcad23
                    peer_cert ? peer_cert->info.filename : "none"));
Packit fcad23
Packit fcad23
        /* Trust the expected certificate */
Packit fcad23
        if (netsnmp_cert_trust_ca(the_ctx, peer_cert) != SNMPERR_SUCCESS)
Packit fcad23
            LOGANDDIE ("failed to set verify paths");
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* trust a certificate (possibly a CA) aspecifically passed in */
Packit fcad23
    if (tlsbase->trust_cert) {
Packit fcad23
        if (!_trust_this_cert(the_ctx, tlsbase->trust_cert))
Packit fcad23
            return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return _sslctx_common_setup(the_ctx, tlsbase);
Packit fcad23
}
Packit fcad23
Packit fcad23
SSL_CTX *
Packit fcad23
sslctx_server_setup(const SSL_METHOD *method) {
Packit fcad23
    netsnmp_cert *id_cert;
Packit fcad23
Packit fcad23
    /***********************************************************************
Packit fcad23
     * Set up the server context
Packit fcad23
     */
Packit fcad23
    /* setting up for ssl */
Packit fcad23
    SSL_CTX *the_ctx = SSL_CTX_new(NETSNMP_REMOVE_CONST(SSL_METHOD *, method));
Packit fcad23
    if (!the_ctx) {
Packit fcad23
        LOGANDDIE("can't create a new context");
Packit fcad23
    }
Packit fcad23
Packit fcad23
    id_cert = netsnmp_cert_find(NS_CERT_IDENTITY, NS_CERTKEY_DEFAULT, NULL);
Packit fcad23
    if (!id_cert)
Packit fcad23
        LOGANDDIE ("error finding server identity keys");
Packit fcad23
Packit fcad23
    if (!id_cert->key || !id_cert->key->okey)
Packit fcad23
        LOGANDDIE("failed to load private key");
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("sslctx_server", "using public key: %s\n",
Packit fcad23
                id_cert->info.filename));
Packit fcad23
    DEBUGMSGTL(("sslctx_server", "using private key: %s\n",
Packit fcad23
                id_cert->key->info.filename));
Packit fcad23
Packit fcad23
    if (SSL_CTX_use_certificate(the_ctx, id_cert->ocert) <= 0)
Packit fcad23
        LOGANDDIE("failed to set the certificate to use");
Packit fcad23
Packit fcad23
    if (SSL_CTX_use_PrivateKey(the_ctx, id_cert->key->okey) <= 0)
Packit fcad23
        LOGANDDIE("failed to set the private key to use");
Packit fcad23
Packit fcad23
    if (!SSL_CTX_check_private_key(the_ctx))
Packit fcad23
        LOGANDDIE("public and private keys incompatible");
Packit fcad23
Packit fcad23
    SSL_CTX_set_read_ahead(the_ctx, 1); /* XXX: DTLS only? */
Packit fcad23
Packit fcad23
    SSL_CTX_set_verify(the_ctx,
Packit fcad23
                       SSL_VERIFY_PEER|
Packit fcad23
                       SSL_VERIFY_FAIL_IF_NO_PEER_CERT|
Packit fcad23
                       SSL_VERIFY_CLIENT_ONCE,
Packit fcad23
                       &verify_callback);
Packit fcad23
Packit fcad23
    return _sslctx_common_setup(the_ctx, NULL);
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
netsnmp_tlsbase_config(struct netsnmp_transport_s *t, const char *token, const char *value) {
Packit fcad23
    _netsnmpTLSBaseData *tlsdata;
Packit fcad23
Packit fcad23
    netsnmp_assert_or_return(t != NULL, -1);
Packit fcad23
    netsnmp_assert_or_return(t->data != NULL, -1);
Packit fcad23
Packit fcad23
    tlsdata = t->data;
Packit fcad23
Packit fcad23
    if ((strcmp(token, "localCert") == 0) ||
Packit fcad23
        (strcmp(token, "our_identity") == 0)) {
Packit fcad23
        SNMP_FREE(tlsdata->our_identity);
Packit fcad23
        tlsdata->our_identity = strdup(value);
Packit fcad23
        DEBUGMSGT(("tls:config","our identity %s\n", value));
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ((strcmp(token, "peerCert") == 0) ||
Packit fcad23
        (strcmp(token, "their_identity") == 0)) {
Packit fcad23
        SNMP_FREE(tlsdata->their_identity);
Packit fcad23
        tlsdata->their_identity = strdup(value);
Packit fcad23
        DEBUGMSGT(("tls:config","their identity %s\n", value));
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ((strcmp(token, "peerHostname") == 0) ||
Packit fcad23
        (strcmp(token, "their_hostname") == 0)) {
Packit fcad23
        SNMP_FREE(tlsdata->their_hostname);
Packit fcad23
        tlsdata->their_hostname = strdup(value);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ((strcmp(token, "trust_cert") == 0) ||
Packit fcad23
        (strcmp(token, "trustCert") == 0)) {
Packit fcad23
        SNMP_FREE(tlsdata->trust_cert);
Packit fcad23
        tlsdata->trust_cert = strdup(value);
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    return SNMPERR_SUCCESS;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
netsnmp_tlsbase_session_init(struct netsnmp_transport_s *transport,
Packit fcad23
                             struct snmp_session *sess) {
Packit fcad23
    /* the default security model here should be TSM; most other
Packit fcad23
       things won't work with TLS because we'll throw out the packet
Packit fcad23
       if it doesn't have a proper tmStateRef (and onyl TSM generates
Packit fcad23
       this at the moment */
Packit fcad23
    if (!(transport->flags & NETSNMP_TRANSPORT_FLAG_LISTEN)) {
Packit fcad23
        if (sess->securityModel == SNMP_DEFAULT_SECMODEL) {
Packit fcad23
            sess->securityModel = SNMP_SEC_MODEL_TSM;
Packit fcad23
        } else if (sess->securityModel != SNMP_SEC_MODEL_TSM) {
Packit fcad23
            sess->securityModel = SNMP_SEC_MODEL_TSM;
Packit fcad23
            snmp_log(LOG_ERR, "A security model other than TSM is being used with (D)TLS; using TSM anyways\n");
Packit fcad23
        }
Packit fcad23
Packit fcad23
        if (NULL == sess->securityName) {
Packit fcad23
            /* client side doesn't need a real securityName */
Packit fcad23
            /* XXX: call-home issues require them to set one for VACM; but
Packit fcad23
               we don't do callhome yet */
Packit fcad23
            sess->securityName = strdup("__BOGUS__");
Packit fcad23
            sess->securityNameLen = strlen(sess->securityName);
Packit fcad23
        }
Packit fcad23
Packit fcad23
        if (sess->version != SNMP_VERSION_3) {
Packit fcad23
            sess->version = SNMP_VERSION_3;
Packit fcad23
            snmp_log(LOG_ERR, "A SNMP version other than 3 was requested with (D)TLS; using 3 anyways\n");
Packit fcad23
        }
Packit fcad23
Packit fcad23
        if (sess->securityLevel <= 0) {
Packit fcad23
            sess->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    return SNMPERR_SUCCESS;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int have_done_bootstrap = 0;
Packit fcad23
Packit fcad23
static int
Packit fcad23
tls_bootstrap(int majorid, int minorid, void *serverarg, void *clientarg) {
Packit fcad23
    char indexname[] = "_netsnmp_verify_info";
Packit fcad23
Packit fcad23
    /* don't do this more than once */
Packit fcad23
    if (have_done_bootstrap)
Packit fcad23
        return 0;
Packit fcad23
    have_done_bootstrap = 1;
Packit fcad23
Packit fcad23
    netsnmp_certs_load();
Packit fcad23
Packit fcad23
    openssl_local_index =
Packit fcad23
        SSL_get_ex_new_index(0, indexname, NULL, NULL, NULL);
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
tls_get_verify_info_index() {
Packit fcad23
    return openssl_local_index;
Packit fcad23
}
Packit fcad23
Packit fcad23
static void _parse_client_cert(const char *tok, char *line)
Packit fcad23
{
Packit fcad23
    config_pwarn("clientCert is deprecated. Clients should use localCert, servers should use peerCert");
Packit fcad23
    if (*line == '"') {
Packit fcad23
        char buf[SNMP_MAXBUF];
Packit fcad23
        copy_nword(line, buf, sizeof(buf));
Packit fcad23
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                              NETSNMP_DS_LIB_X509_CLIENT_PUB, buf);
Packit fcad23
    } else
Packit fcad23
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                              NETSNMP_DS_LIB_X509_CLIENT_PUB, line);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void _parse_server_cert(const char *tok, char *line)
Packit fcad23
{
Packit fcad23
    config_pwarn("serverCert is deprecated. Clients should use peerCert, servers should use localCert.");
Packit fcad23
    if (*line == '"') {
Packit fcad23
        char buf[SNMP_MAXBUF];
Packit fcad23
        copy_nword(line, buf, sizeof(buf));
Packit fcad23
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                              NETSNMP_DS_LIB_X509_CLIENT_PUB, buf);
Packit fcad23
    } else
Packit fcad23
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                              NETSNMP_DS_LIB_X509_SERVER_PUB, line);
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
netsnmp_tlsbase_ctor(void) {
Packit fcad23
Packit fcad23
    /* bootstrap ssl since we'll need it */
Packit fcad23
    netsnmp_init_openssl();
Packit fcad23
Packit fcad23
    /* the private client cert to authenticate with */
Packit fcad23
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "extraX509SubDir",
Packit fcad23
                               NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                               NETSNMP_DS_LIB_CERT_EXTRA_SUBDIR);
Packit fcad23
Packit fcad23
    /* Do we have a CRL list? */
Packit fcad23
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "x509CRLFile",
Packit fcad23
                               NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                               NETSNMP_DS_LIB_X509_CRL_FILE);
Packit fcad23
Packit fcad23
    /* What TLS algorithms should be use */
Packit fcad23
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tlsAlgorithms",
Packit fcad23
                               NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                               NETSNMP_DS_LIB_TLS_ALGORITMS);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * for the client
Packit fcad23
     */
Packit fcad23
Packit fcad23
    /* the public client cert to authenticate with */
Packit fcad23
    register_config_handler("snmp", "clientCert", _parse_client_cert, NULL,
Packit fcad23
                            NULL);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * for the server
Packit fcad23
     */
Packit fcad23
Packit fcad23
    /* The X509 server key to use */
Packit fcad23
    register_config_handler("snmp", "serverCert", _parse_server_cert, NULL,
Packit fcad23
                            NULL);
Packit fcad23
    /*
Packit fcad23
     * remove cert config ambiguity: localCert, peerCert
Packit fcad23
     */
Packit fcad23
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "localCert",
Packit fcad23
                               NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                               NETSNMP_DS_LIB_TLS_LOCAL_CERT);
Packit fcad23
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "peerCert",
Packit fcad23
                               NETSNMP_DS_LIBRARY_ID,
Packit fcad23
                               NETSNMP_DS_LIB_TLS_PEER_CERT);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * register our boot-strapping needs
Packit fcad23
     */
Packit fcad23
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
Packit fcad23
			   SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
Packit fcad23
			   tls_bootstrap, NULL);
Packit fcad23
Packit fcad23
}
Packit fcad23
Packit fcad23
_netsnmpTLSBaseData *
Packit fcad23
netsnmp_tlsbase_allocate_tlsdata(netsnmp_transport *t, int isserver) {
Packit fcad23
Packit fcad23
    _netsnmpTLSBaseData *tlsdata;
Packit fcad23
Packit fcad23
    if (NULL == t)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    /* allocate our TLS specific data */
Packit fcad23
    tlsdata = SNMP_MALLOC_TYPEDEF(_netsnmpTLSBaseData);
Packit fcad23
    if (NULL == tlsdata) {
Packit fcad23
        SNMP_FREE(t);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!isserver)
Packit fcad23
        tlsdata->flags |= NETSNMP_TLSBASE_IS_CLIENT;
Packit fcad23
Packit fcad23
    return tlsdata;
Packit fcad23
}
Packit fcad23
Packit fcad23
void netsnmp_tlsbase_free_tlsdata(_netsnmpTLSBaseData *tlsbase) {
Packit fcad23
    if (!tlsbase)
Packit fcad23
        return;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("tlsbase","Freeing TLS Base data for a session\n"));
Packit fcad23
Packit fcad23
    if (tlsbase->ssl)
Packit fcad23
        SSL_free(tlsbase->ssl);
Packit fcad23
Packit fcad23
    if (tlsbase->ssl_context)
Packit fcad23
        SSL_CTX_free(tlsbase->ssl_context);
Packit fcad23
   /* don't free the accept_bio since it's the parent bio */
Packit fcad23
    /*
Packit fcad23
    if (tlsbase->accept_bio)
Packit fcad23
        BIO_free(tlsbase->accept_bio);
Packit fcad23
    */
Packit fcad23
    /* and this is freed by the SSL shutdown */
Packit fcad23
    /* 
Packit fcad23
    if (tlsbase->accepted_bio)
Packit fcad23
      BIO_free(tlsbase->accept_bio);
Packit fcad23
    */
Packit fcad23
Packit fcad23
    /* free the config data */
Packit fcad23
    SNMP_FREE(tlsbase->securityName);
Packit fcad23
    SNMP_FREE(tlsbase->addr_string);
Packit fcad23
    SNMP_FREE(tlsbase->our_identity);
Packit fcad23
    SNMP_FREE(tlsbase->their_identity);
Packit fcad23
    SNMP_FREE(tlsbase->their_fingerprint);
Packit fcad23
    SNMP_FREE(tlsbase->their_hostname);
Packit fcad23
    SNMP_FREE(tlsbase->trust_cert);
Packit fcad23
Packit fcad23
    /* free the base itself */
Packit fcad23
    SNMP_FREE(tlsbase);
Packit fcad23
}
Packit fcad23
Packit fcad23
int netsnmp_tlsbase_wrapup_recv(netsnmp_tmStateReference *tmStateRef,
Packit fcad23
                                _netsnmpTLSBaseData *tlsdata,
Packit fcad23
                                void **opaque, int *olength) {
Packit fcad23
    int no_auth, no_priv;
Packit fcad23
Packit fcad23
    if (NULL == tlsdata)
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
Packit fcad23
    /* RFC5953 Section 5.1.2 step 2: tmSecurityLevel */
Packit fcad23
    /*
Packit fcad23
     * Don't accept null authentication. Null encryption ok.
Packit fcad23
     *
Packit fcad23
     * XXX: this should actually check for a configured list of encryption
Packit fcad23
     *      algorithms to map to NOPRIV, but for the moment we'll
Packit fcad23
     *      accept any encryption alogrithms that openssl is using.
Packit fcad23
     */
Packit fcad23
    netsnmp_openssl_null_checks(tlsdata->ssl, &no_auth, &no_priv);
Packit fcad23
    if (no_auth == 1) { /* null/unknown authentication */
Packit fcad23
        /* xxx-rks: snmp_increment_statistic(STAT_???); */
Packit fcad23
        snmp_log(LOG_ERR, "tls connection with NULL authentication\n");
Packit fcad23
        SNMP_FREE(tmStateRef);
Packit fcad23
        return SNMPERR_GENERR;
Packit fcad23
    }
Packit fcad23
    else if (no_priv == 1) /* null/unknown encryption */
Packit fcad23
        tmStateRef->transportSecurityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
Packit fcad23
    else
Packit fcad23
        tmStateRef->transportSecurityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
Packit fcad23
    DEBUGMSGTL(("tls:secLevel", "SecLevel %d\n",
Packit fcad23
                tmStateRef->transportSecurityLevel));
Packit fcad23
Packit fcad23
    /* use x509 cert to do lookup to secname if DNE in cachep yet */
Packit fcad23
Packit fcad23
    /* RFC5953: section 5.3.2, paragraph 2:
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
Packit fcad23
    if (!tlsdata->securityName) {
Packit fcad23
        netsnmp_tlsbase_extract_security_name(tlsdata->ssl, tlsdata);
Packit fcad23
        if (NULL != tlsdata->securityName) {
Packit fcad23
            DEBUGMSGTL(("tls", "set SecName to: %s\n", tlsdata->securityName));
Packit fcad23
        } else {
Packit fcad23
	    snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCLIENTCERTIFICATES);
Packit fcad23
	    snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
Packit fcad23
            SNMP_FREE(tmStateRef);
Packit fcad23
            return SNMPERR_GENERR;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* RFC5953 Section 5.1.2 step 2: tmSecurityName */
Packit fcad23
    /* XXX: detect and throw out overflow secname sizes rather
Packit fcad23
       than truncating. */
Packit fcad23
    strlcpy(tmStateRef->securityName, tlsdata->securityName,
Packit fcad23
            sizeof(tmStateRef->securityName));
Packit fcad23
    tmStateRef->securityNameLen = strlen(tmStateRef->securityName);
Packit fcad23
Packit fcad23
    /* RFC5953 Section 5.1.2 step 2: tmSessionID */
Packit fcad23
    /* use our TLSData pointer as the session ID */
Packit fcad23
    memcpy(tmStateRef->sessionID, &tlsdata, sizeof(netsnmp_tmStateReference *));
Packit fcad23
Packit fcad23
    /* save the tmStateRef in our special pointer */
Packit fcad23
    *opaque = tmStateRef;
Packit fcad23
    *olength = sizeof(netsnmp_tmStateReference);
Packit fcad23
Packit fcad23
    return SNMPERR_SUCCESS;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(_x509_get_error, netsnmp_unused)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE__X509_GET_ERROR
Packit fcad23
const char * _x509_get_error(int x509failvalue, const char *location) {
Packit fcad23
    static const char *reason = NULL;
Packit fcad23
    
Packit fcad23
    /* XXX: use this instead: X509_verify_cert_error_string(err) */
Packit fcad23
Packit fcad23
    switch (x509failvalue) {
Packit fcad23
    case X509_V_OK:
Packit fcad23
        reason = "X509_V_OK";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_GET_CRL:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_GET_CRL";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CERT_SIGNATURE_FAILURE:
Packit fcad23
        reason = "X509_V_ERR_CERT_SIGNATURE_FAILURE";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CRL_SIGNATURE_FAILURE:
Packit fcad23
        reason = "X509_V_ERR_CRL_SIGNATURE_FAILURE";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CERT_NOT_YET_VALID:
Packit fcad23
        reason = "X509_V_ERR_CERT_NOT_YET_VALID";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CERT_HAS_EXPIRED:
Packit fcad23
        reason = "X509_V_ERR_CERT_HAS_EXPIRED";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CRL_NOT_YET_VALID:
Packit fcad23
        reason = "X509_V_ERR_CRL_NOT_YET_VALID";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CRL_HAS_EXPIRED:
Packit fcad23
        reason = "X509_V_ERR_CRL_HAS_EXPIRED";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
Packit fcad23
        reason = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
Packit fcad23
        reason = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
Packit fcad23
        reason = "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
Packit fcad23
        reason = "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_OUT_OF_MEM:
Packit fcad23
        reason = "X509_V_ERR_OUT_OF_MEM";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
Packit fcad23
        reason = "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
Packit fcad23
        reason = "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CERT_CHAIN_TOO_LONG:
Packit fcad23
        reason = "X509_V_ERR_CERT_CHAIN_TOO_LONG";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CERT_REVOKED:
Packit fcad23
        reason = "X509_V_ERR_CERT_REVOKED";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_INVALID_CA:
Packit fcad23
        reason = "X509_V_ERR_INVALID_CA";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_PATH_LENGTH_EXCEEDED:
Packit fcad23
        reason = "X509_V_ERR_PATH_LENGTH_EXCEEDED";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_INVALID_PURPOSE:
Packit fcad23
        reason = "X509_V_ERR_INVALID_PURPOSE";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CERT_UNTRUSTED:
Packit fcad23
        reason = "X509_V_ERR_CERT_UNTRUSTED";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_CERT_REJECTED:
Packit fcad23
        reason = "X509_V_ERR_CERT_REJECTED";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
Packit fcad23
        reason = "X509_V_ERR_SUBJECT_ISSUER_MISMATCH";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_AKID_SKID_MISMATCH:
Packit fcad23
        reason = "X509_V_ERR_AKID_SKID_MISMATCH";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
Packit fcad23
        reason = "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
Packit fcad23
        reason = "X509_V_ERR_KEYUSAGE_NO_CERTSIGN";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
Packit fcad23
        reason = "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
Packit fcad23
        reason = "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
Packit fcad23
        reason = "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
Packit fcad23
        reason = "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_INVALID_NON_CA:
Packit fcad23
        reason = "X509_V_ERR_INVALID_NON_CA";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
Packit fcad23
        reason = "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
Packit fcad23
        reason = "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE";
Packit fcad23
        break;
Packit fcad23
    case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
Packit fcad23
        reason = "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED";
Packit fcad23
        break;
Packit fcad23
#ifdef X509_V_ERR_INVALID_EXTENSION /* not avail on darwin */
Packit fcad23
    case X509_V_ERR_INVALID_EXTENSION:
Packit fcad23
        reason = "X509_V_ERR_INVALID_EXTENSION";
Packit fcad23
        break;
Packit fcad23
#endif
Packit fcad23
#ifdef X509_V_ERR_INVALID_POLICY_EXTENSION /* not avail on darwin */
Packit fcad23
    case X509_V_ERR_INVALID_POLICY_EXTENSION:
Packit fcad23
        reason = "X509_V_ERR_INVALID_POLICY_EXTENSION";
Packit fcad23
        break;
Packit fcad23
#endif
Packit fcad23
#ifdef X509_V_ERR_NO_EXPLICIT_POLICY /* not avail on darwin */
Packit fcad23
    case X509_V_ERR_NO_EXPLICIT_POLICY:
Packit fcad23
        reason = "X509_V_ERR_NO_EXPLICIT_POLICY";
Packit fcad23
        break;
Packit fcad23
#endif
Packit fcad23
#ifdef X509_V_ERR_UNNESTED_RESOURCE /* not avail on darwin */
Packit fcad23
    case X509_V_ERR_UNNESTED_RESOURCE:
Packit fcad23
        reason = "X509_V_ERR_UNNESTED_RESOURCE";
Packit fcad23
        break;
Packit fcad23
#endif
Packit fcad23
    case X509_V_ERR_APPLICATION_VERIFICATION:
Packit fcad23
        reason = "X509_V_ERR_APPLICATION_VERIFICATION";
Packit fcad23
        break;
Packit fcad23
    default:
Packit fcad23
        reason = "unknown failure code";
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return reason;
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE__X509_GET_ERROR */
Packit fcad23
Packit fcad23
void _openssl_log_error(int rc, SSL *con, const char *location) {
Packit fcad23
    const char     *reason, *file, *data;
Packit fcad23
    unsigned long   numerical_reason;
Packit fcad23
    int             flags, line;
Packit fcad23
Packit fcad23
    snmp_log(LOG_ERR, "---- OpenSSL Related Errors: ----\n");
Packit fcad23
Packit fcad23
    /* SSL specific errors */
Packit fcad23
    if (con) {
Packit fcad23
Packit fcad23
        int sslnum = SSL_get_error(con, rc);
Packit fcad23
Packit fcad23
        switch(sslnum) {
Packit fcad23
        case SSL_ERROR_NONE:
Packit fcad23
            reason = "SSL_ERROR_NONE";
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case SSL_ERROR_SSL:
Packit fcad23
            reason = "SSL_ERROR_SSL";
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case SSL_ERROR_WANT_READ:
Packit fcad23
            reason = "SSL_ERROR_WANT_READ";
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case SSL_ERROR_WANT_WRITE:
Packit fcad23
            reason = "SSL_ERROR_WANT_WRITE";
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case SSL_ERROR_WANT_X509_LOOKUP:
Packit fcad23
            reason = "SSL_ERROR_WANT_X509_LOOKUP";
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case SSL_ERROR_SYSCALL:
Packit fcad23
            reason = "SSL_ERROR_SYSCALL";
Packit fcad23
            snmp_log(LOG_ERR, "TLS error: %s: rc=%d, sslerror = %d (%s): system_error=%d (%s)\n",
Packit fcad23
                     location, rc, sslnum, reason, errno, strerror(errno));
Packit fcad23
            snmp_log(LOG_ERR, "TLS Error: %s\n",
Packit fcad23
                     ERR_reason_error_string(ERR_get_error()));
Packit fcad23
            return;
Packit fcad23
Packit fcad23
        case SSL_ERROR_ZERO_RETURN:
Packit fcad23
            reason = "SSL_ERROR_ZERO_RETURN";
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case SSL_ERROR_WANT_CONNECT:
Packit fcad23
            reason = "SSL_ERROR_WANT_CONNECT";
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case SSL_ERROR_WANT_ACCEPT:
Packit fcad23
            reason = "SSL_ERROR_WANT_ACCEPT";
Packit fcad23
            break;
Packit fcad23
            
Packit fcad23
        default:
Packit fcad23
            reason = "unknown";
Packit fcad23
        }
Packit fcad23
Packit fcad23
        snmp_log(LOG_ERR, " TLS error: %s: rc=%d, sslerror = %d (%s)\n",
Packit fcad23
                 location, rc, sslnum, reason);
Packit fcad23
Packit fcad23
        snmp_log(LOG_ERR, " TLS Error: %s\n",
Packit fcad23
                 ERR_reason_error_string(ERR_get_error()));
Packit fcad23
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /* other errors */
Packit fcad23
    while ((numerical_reason =
Packit fcad23
            ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
Packit fcad23
        snmp_log(LOG_ERR, " error: #%lu (file %s, line %d)\n",
Packit fcad23
                 numerical_reason, file, line);
Packit fcad23
Packit fcad23
        /* if we have a text translation: */
Packit fcad23
        if (data && (flags & ERR_TXT_STRING)) {
Packit fcad23
            snmp_log(LOG_ERR, "  Textual Error: %s\n", data);
Packit fcad23
            /*
Packit fcad23
             * per openssl man page: If it has been allocated by
Packit fcad23
             * OPENSSL_malloc(), *flags&ERR_TXT_MALLOCED is true.
Packit fcad23
             *
Packit fcad23
             * arggh... stupid openssl prototype for ERR_get_error_line_data
Packit fcad23
             * wants a const char **, but returns something that we might
Packit fcad23
             * need to free??
Packit fcad23
             */
Packit fcad23
            if (flags & ERR_TXT_MALLOCED)
Packit fcad23
                OPENSSL_free(NETSNMP_REMOVE_CONST(void *, data));        }
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    snmp_log(LOG_ERR, "---- End of OpenSSL Errors ----\n");
Packit fcad23
}