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; }
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); }