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