Esempio n. 1
0
int netsnmp_tlsbase_wrapup_recv (netsnmp_tmStateReference * tmStateRef,
                                 _netsnmpTLSBaseData * tlsdata, void **opaque, int *olength)
{
    int no_auth, no_priv;

    if (NULL == tlsdata)
        return SNMPERR_GENERR;

    /* RFC5953 Section 5.1.2 step 2: tmSecurityLevel */
    /*
     * Don't accept null authentication. Null encryption ok.
     *
     * XXX: this should actually check for a configured list of encryption
     *      algorithms to map to NOPRIV, but for the moment we'll
     *      accept any encryption alogrithms that openssl is using.
     */
    netsnmp_openssl_null_checks (tlsdata->ssl, &no_auth, &no_priv);
    if (no_auth == 1)
    {                            /* null/unknown authentication */
        /* xxx-rks: snmp_increment_statistic(STAT_???); */
        snmp_log (LOG_ERR, "tls connection with NULL authentication\n");
        SNMP_FREE (tmStateRef);
        return SNMPERR_GENERR;
    }
    else if (no_priv == 1)        /* null/unknown encryption */
        tmStateRef->transportSecurityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
    else
        tmStateRef->transportSecurityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
    DEBUGMSGTL (("tls:secLevel", "SecLevel %d\n", tmStateRef->transportSecurityLevel));

    /* use x509 cert to do lookup to secname if DNE in cachep yet */

    /* RFC5953: section 5.3.2, paragraph 2:
       The (D)TLS server identifies the authenticated identity from the
       (D)TLS client's principal certificate using configuration information
       from the snmpTlstmCertToTSNTable mapping table.  The (D)TLS server
       MUST request and expect a certificate from the client and MUST NOT
       accept SNMP messages over the (D)TLS connection until the client has
       sent a certificate and it has been authenticated.  The resulting
       derived tmSecurityName is recorded in the tmStateReference cache as
       tmSecurityName.  The details of the lookup process are fully
       described in the DESCRIPTION clause of the snmpTlstmCertToTSNTable
       MIB object.  If any verification fails in any way (for example
       because of failures in cryptographic verification or because of the
       lack of an appropriate row in the snmpTlstmCertToTSNTable) then the
       session establishment MUST fail, and the
       snmpTlstmSessionInvalidClientCertificates object is incremented.  If
       the session can not be opened for any reason at all, including
       cryptographic verification failures, then the
       snmpTlstmSessionOpenErrors counter is incremented and processing
       stops.
     */

    if (!tlsdata->securityName)
    {
        netsnmp_tlsbase_extract_security_name (tlsdata->ssl, tlsdata);
        if (NULL != tlsdata->securityName)
        {
            DEBUGMSGTL (("tls", "set SecName to: %s\n", tlsdata->securityName));
        }
        else
        {
            snmp_increment_statistic (STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCLIENTCERTIFICATES);
            snmp_increment_statistic (STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS);
            SNMP_FREE (tmStateRef);
            return SNMPERR_GENERR;
        }
    }

    /* RFC5953 Section 5.1.2 step 2: tmSecurityName */
    /* XXX: detect and throw out overflow secname sizes rather
       than truncating. */
    strlcpy (tmStateRef->securityName, tlsdata->securityName, sizeof (tmStateRef->securityName));
    tmStateRef->securityNameLen = strlen (tmStateRef->securityName);

    /* RFC5953 Section 5.1.2 step 2: tmSessionID */
    /* use our TLSData pointer as the session ID */
    memcpy (tmStateRef->sessionID, &tlsdata, sizeof (netsnmp_tmStateReference *));

    /* save the tmStateRef in our special pointer */
    *opaque = tmStateRef;
    *olength = sizeof (netsnmp_tmStateReference);

    return SNMPERR_SUCCESS;
}
Esempio n. 2
0
static int
netsnmp_tlstcp_accept(netsnmp_transport *t)
{
    BIO            *accepted_bio;
    int             rc;
    SSL_CTX *ctx;
    SSL     *ssl;
    _netsnmpTLSBaseData *tlsdata = NULL;

    DEBUGMSGTL(("tlstcp", "netsnmp_tlstcp_accept called\n"));

    tlsdata = (_netsnmpTLSBaseData *) t->data;

    rc = BIO_do_accept(tlsdata->accept_bio);

    if (rc <= 0) {
        snmp_log(LOG_ERR, "BIO_do_accept failed\n");
        _openssl_log_error(rc, NULL, "BIO_do_accept");
        /* XXX: need to close the listening connection here? */
        return -1;
    }

    tlsdata->accepted_bio = accepted_bio = BIO_pop(tlsdata->accept_bio);
    if (!accepted_bio) {
        snmp_log(LOG_ERR, "Failed to pop an accepted bio off the bio staack\n");
        /* XXX: need to close the listening connection here? */
        return -1;
    }

    /* create the OpenSSL TLS context */
    ctx = tlsdata->ssl_context;

    /* create the server's main SSL bio */
    ssl = tlsdata->ssl = SSL_new(ctx);
    if (!tlsdata->ssl) {
        snmp_log(LOG_ERR, "TLSTCP: Failed to create a SSL BIO\n");
        BIO_free(accepted_bio);
        tlsdata->accepted_bio = NULL;
        return -1;
    }

    SSL_set_bio(ssl, accepted_bio, accepted_bio);

    if ((rc = SSL_accept(ssl)) <= 0) {
        snmp_log(LOG_ERR, "TLSTCP: Failed SSL_accept\n");
        _openssl_log_error(rc, ssl, "SSL_accept");
        SSL_shutdown(tlsdata->ssl);
        SSL_free(tlsdata->ssl);
        tlsdata->accepted_bio = NULL; /* freed by SSL_free */
        tlsdata->ssl = NULL;
        return -1;
    }

    /*
     * currently netsnmp_tlsbase_wrapup_recv is where we check for
     * algorithm compliance, but for tls we know the algorithms
     * at this point, so we could bail earlier...
     */
#if 0 /* moved checks to netsnmp_tlsbase_wrapup_recv */
    netsnmp_openssl_null_checks(tlsdata->ssl, &no_auth, NULL);
    if (no_auth != 0) { /* null/unknown authentication */
        /* xxx-rks: snmp_increment_statistic(STAT_???); */
        snmp_log(LOG_ERR, "tlstcp: connection with NULL authentication\n");
        SSL_shutdown(tlsdata->ssl);
        SSL_free(tlsdata->ssl);
        tlsdata->accepted_bio = NULL; /* freed by SSL_free */
        tlsdata->ssl = NULL;
        return -1;
    }
#endif

    /* RFC5953 Section 5.3.2: Accepting a Session as a Server
       A (D)TLS server should accept new session connections from any client
       that it is able to verify the client's credentials for.  This is done
       by authenticating the client's presented certificate through a
       certificate path validation process (e.g.  [RFC5280]) or through
       certificate fingerprint verification using fingerprints configured in
       the snmpTlstmCertToTSNTable.  Afterward the server will determine the
       identity of the remote entity using the following procedures.

       The (D)TLS server identifies the authenticated identity from the
       (D)TLS client's principal certificate using configuration information
       from the snmpTlstmCertToTSNTable mapping table.  The (D)TLS server
       MUST request and expect a certificate from the client and MUST NOT
       accept SNMP messages over the (D)TLS connection until the client has
       sent a certificate and it has been authenticated.  The resulting
       derived tmSecurityName is recorded in the tmStateReference cache as
       tmSecurityName.  The details of the lookup process are fully
       described in the DESCRIPTION clause of the snmpTlstmCertToTSNTable
       MIB object.  If any verification fails in any way (for example
       because of failures in cryptographic verification or because of the
       lack of an appropriate row in the snmpTlstmCertToTSNTable) then the
       session establishment MUST fail, and the
       snmpTlstmSessionInvalidClientCertificates object is incremented.  If
       the session can not be opened for any reason at all, including
       cryptographic verification failures, then the
       snmpTlstmSessionOpenErrors counter is incremented and processing
       stops.

       Servers that wish to support multiple principals at a particular port
       SHOULD make use of a (D)TLS extension that allows server-side
       principal selection like the Server Name Indication extension defined
       in Section 3.1 of [RFC4366].  Supporting this will allow, for
       example, sending notifications to a specific principal at a given TCP
       or UDP port.
    */
    /* Implementation notes:
       - we expect fingerprints to be stored in the transport config
       - we do not currently support mulitple principals and only offer one
    */
    if ((rc = netsnmp_tlsbase_verify_client_cert(ssl, tlsdata))
            != SNMPERR_SUCCESS) {
        /* XXX: free needed memory */
        snmp_log(LOG_ERR, "TLSTCP: Falied checking client certificate\n");
        snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCLIENTCERTIFICATES);
        SSL_shutdown(tlsdata->ssl);
        SSL_free(tlsdata->ssl);
        tlsdata->accepted_bio = NULL; /* freed by SSL_free */
        tlsdata->ssl = NULL;
        return -1;
    }


    /* XXX: check acceptance criteria here */

    DEBUGMSGTL(("tlstcp", "accept succeeded on sock %d\n", t->sock));

    /* RFC5953 Section 5.1.2 step 1, part2::
     * If this is the first message received through this session and
     the session does not have an assigned tlstmSessionID yet then the
     snmpTlstmSessionAccepts counter is incremented and a
     tlstmSessionID for the session is created.  This will only happen
     on the server side of a connection because a client would have
     already assigned a tlstmSessionID during the openSession()
     invocation.  Implementations may have performed the procedures
     described in Section 5.3.2 prior to this point or they may
     perform them now, but the procedures described in Section 5.3.2
     MUST be performed before continuing beyond this point.
    */
    /* We're taking option 2 and incrementing the session accepts here
       rather than upon receiving the first packet */
    snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONACCEPTS);

    /* XXX: check that it returns something so we can free stuff? */
    return BIO_get_fd(tlsdata->accepted_bio, NULL);
}