diff options
Diffstat (limited to 'snmplib/snmp_openssl.c')
-rw-r--r-- | snmplib/snmp_openssl.c | 879 |
1 files changed, 879 insertions, 0 deletions
diff --git a/snmplib/snmp_openssl.c b/snmplib/snmp_openssl.c new file mode 100644 index 0000000..3b0eaa8 --- /dev/null +++ b/snmplib/snmp_openssl.c @@ -0,0 +1,879 @@ +/* + * snmp_openssl.c + */ + +#include <net-snmp/net-snmp-config.h> + +#include <net-snmp/net-snmp-includes.h> + +#include <net-snmp/net-snmp-features.h> + +#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && !defined(NETSNMP_FEATURE_REMOVE_CERT_UTIL) + +netsnmp_feature_require(container_free_all) + +netsnmp_feature_child_of(openssl_cert_get_subjectAltNames, netsnmp_unused) +netsnmp_feature_child_of(openssl_ht2nid, netsnmp_unused) +netsnmp_feature_child_of(openssl_err_log, netsnmp_unused) +netsnmp_feature_child_of(cert_dump_names, netsnmp_unused) + +#include <ctype.h> + +#include <openssl/evp.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/err.h> +#include <openssl/objects.h> + +#include <net-snmp/library/snmp_debug.h> +#include <net-snmp/library/cert_util.h> +#include <net-snmp/library/snmp_openssl.h> + +static u_char have_started_already = 0; + +/* + * This code merely does openssl initialization so that multilpe + * modules are safe to call netsnmp_init_openssl() for bootstrapping + * without worrying about other callers that may have already done so. + */ +void netsnmp_init_openssl(void) { + + /* avoid duplicate calls */ + if (have_started_already) + return; + have_started_already = 1; + + DEBUGMSGTL(("snmp_openssl", "initializing\n")); + + /* Initializing OpenSSL */ + SSL_library_init(); + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); +} + +/** netsnmp_openssl_cert_get_name: get subject name field from cert + * @internal + */ +/** instead of exposing this function, make helper functions for each + * field, like netsnmp_openssl_cert_get_commonName, below */ +static char * +_cert_get_name(X509 *ocert, int which, char **buf, int *len, int flags) +{ + X509_NAME *osubj_name; + int space; + char *buf_ptr; + + if ((NULL == ocert) || ((buf && !len) || (len && !buf))) + return NULL; + + osubj_name = X509_get_subject_name(ocert); + if (NULL == osubj_name) { + DEBUGMSGT(("openssl:cert:name", "no subject name!\n")); + return NULL; + } + + /** see if buf is big enough, or allocate buf if none specified */ + space = X509_NAME_get_text_by_NID(osubj_name, which, NULL, 0); + if (-1 == space) + return NULL; + ++space; /* for NUL */ + if (buf && *buf) { + if (*len < space) + return NULL; + buf_ptr = *buf; + } + else { + buf_ptr = calloc(1,space); + if (!buf_ptr) + return NULL; + } + space = X509_NAME_get_text_by_NID(osubj_name, which, buf_ptr, space); + if (len) + *len = space; + + return buf_ptr; +} + +/** netsnmp_openssl_cert_get_subjectName: get subject name field from cert + */ +char * +netsnmp_openssl_cert_get_subjectName(X509 *ocert, char **buf, int *len) +{ + X509_NAME *osubj_name; + int space; + char *buf_ptr; + + if ((NULL == ocert) || ((buf && !len) || (len && !buf))) + return NULL; + + osubj_name = X509_get_subject_name(ocert); + if (NULL == osubj_name) { + DEBUGMSGT(("openssl:cert:name", "no subject name!\n")); + return NULL; + } + + if (buf) { + buf_ptr = *buf; + space = *len; + } + else { + buf_ptr = NULL; + space = 0; + } + buf_ptr = X509_NAME_oneline(osubj_name, buf_ptr, space); + if (len) + *len = strlen(buf_ptr); + + return buf_ptr; +} + +/** netsnmp_openssl_cert_get_commonName: get commonName for cert. + * if a pointer to a buffer and its length are specified, they will be + * used. otherwise, a new buffer will be allocated, which the caller will + * be responsbile for releasing. + */ +char * +netsnmp_openssl_cert_get_commonName(X509 *ocert, char **buf, int *len) +{ + return _cert_get_name(ocert, NID_commonName, buf, len, 0); +} + +#ifndef NETSNMP_FEATURE_REMOVE_CERT_DUMP_NAMES +/** netsnmp_openssl_cert_dump_name: dump subject names in cert + */ +void +netsnmp_openssl_cert_dump_names(X509 *ocert) +{ + int i, onid; + X509_NAME_ENTRY *oname_entry; + X509_NAME *osubj_name; + const char *prefix_short, *prefix_long; + + if (NULL == ocert) + return; + + osubj_name = X509_get_subject_name(ocert); + if (NULL == osubj_name) { + DEBUGMSGT(("9:cert:dump:names", "no subject name!\n")); + return; + } + + for (i = 0; i < X509_NAME_entry_count(osubj_name); i++) { + oname_entry = X509_NAME_get_entry(osubj_name, i); + netsnmp_assert(NULL != oname_entry); + + if (oname_entry->value->type != V_ASN1_PRINTABLESTRING) + continue; + + /** get NID */ + onid = OBJ_obj2nid(oname_entry->object); + if (onid == NID_undef) { + prefix_long = prefix_short = "UNKNOWN"; + } + else { + prefix_long = OBJ_nid2ln(onid); + prefix_short = OBJ_nid2sn(onid); + } + + DEBUGMSGT(("9:cert:dump:names", + "[%02d] NID type %d, ASN type %d\n", i, onid, + oname_entry->value->type)); + DEBUGMSGT(("9:cert:dump:names", "%s/%s: '%s'\n", prefix_long, + prefix_short, ASN1_STRING_data(oname_entry->value))); + } +} +#endif /* NETSNMP_FEATURE_REMOVE_CERT_DUMP_NAMES */ + +static char * +_cert_get_extension(X509_EXTENSION *oext, char **buf, int *len, int flags) +{ + int space; + char *buf_ptr = NULL; + u_char *data; + BIO *bio; + + if ((NULL == oext) || ((buf && !len) || (len && !buf))) + return NULL; + + bio = BIO_new(BIO_s_mem()); + if (NULL == bio) { + snmp_log(LOG_ERR, "could not get bio for extension\n"); + return NULL; + } + if (X509V3_EXT_print(bio, oext, 0, 0) != 1) { + snmp_log(LOG_ERR, "could not print extension!\n"); + BIO_vfree(bio); + return NULL; + } + + space = BIO_get_mem_data(bio, &data); + if (buf && *buf) { + if (*len < space) + buf_ptr = NULL; + else + buf_ptr = *buf; + } + else + buf_ptr = calloc(1,space + 1); + + if (!buf_ptr) { + snmp_log(LOG_ERR, + "not enough space or error in allocation for extenstion\n"); + BIO_vfree(bio); + return NULL; + } + memcpy(buf_ptr, data, space); + buf_ptr[space] = 0; + if (len) + *len = space; + + BIO_vfree(bio); + + return buf_ptr; +} + +/** netsnmp_openssl_cert_get_extension: get extension field from cert + * @internal + */ +/** instead of exposing this function, make helper functions for each + * field, like netsnmp_openssl_cert_get_subjectAltName, below */ +X509_EXTENSION * +_cert_get_extension_at(X509 *ocert, int pos, char **buf, int *len, int flags) +{ + X509_EXTENSION *oext; + + if ((NULL == ocert) || ((buf && !len) || (len && !buf))) + return NULL; + + oext = X509_get_ext(ocert,pos); + if (NULL == oext) { + snmp_log(LOG_ERR, "extension number %d not found!\n", pos); + netsnmp_openssl_cert_dump_extensions(ocert); + return NULL; + } + + return oext; +} + +/** netsnmp_openssl_cert_get_extension: get extension field from cert + * @internal + */ +/** instead of exposing this function, make helper functions for each + * field, like netsnmp_openssl_cert_get_subjectAltName, below */ +static char * +_cert_get_extension_str_at(X509 *ocert, int pos, char **buf, int *len, + int flags) +{ + X509_EXTENSION *oext; + + if ((NULL == ocert) || ((buf && !len) || (len && !buf))) + return NULL; + + oext = X509_get_ext(ocert,pos); + if (NULL == oext) { + snmp_log(LOG_ERR, "extension number %d not found!\n", pos); + netsnmp_openssl_cert_dump_extensions(ocert); + return NULL; + } + + return _cert_get_extension(oext, buf, len, flags); +} + +/** _cert_get_extension_id: get extension field from cert + * @internal + */ +/** instead of exposing this function, make helper functions for each + * field, like netsnmp_openssl_cert_get_subjectAltName, below */ +X509_EXTENSION * +_cert_get_extension_id(X509 *ocert, int which, char **buf, int *len, int flags) +{ + int pos; + + if ((NULL == ocert) || ((buf && !len) || (len && !buf))) + return NULL; + + pos = X509_get_ext_by_NID(ocert,which,-1); + if (pos < 0) { + DEBUGMSGT(("openssl:cert:name", "no extension %d\n", which)); + return NULL; + } + + return _cert_get_extension_at(ocert, pos, buf, len, flags); +} + +/** _cert_get_extension_id_str: get extension field from cert + * @internal + */ +/** instead of exposing this function, make helper functions for each + * field, like netsnmp_openssl_cert_get_subjectAltName, below */ +static char * +_cert_get_extension_id_str(X509 *ocert, int which, char **buf, int *len, + int flags) +{ + int pos; + + if ((NULL == ocert) || ((buf && !len) || (len && !buf))) + return NULL; + + pos = X509_get_ext_by_NID(ocert,which,-1); + if (pos < 0) { + DEBUGMSGT(("openssl:cert:name", "no extension %d\n", which)); + return NULL; + } + + return _cert_get_extension_str_at(ocert, pos, buf, len, flags); +} + +static char * +_extract_oname(const GENERAL_NAME *oname) +{ + char ipbuf[60], *buf = NULL, *rtn = NULL; + + if (NULL == oname) + return NULL; + + switch ( oname->type ) { + case GEN_EMAIL: + case GEN_DNS: + /*case GEN_URI:*/ + ASN1_STRING_to_UTF8((unsigned char**)&buf, oname->d.ia5); + if (buf) + rtn = strdup(buf); + break; + + case GEN_IPADD: + if (oname->d.iPAddress->length == 4) { + sprintf(ipbuf, "%d.%d.%d.%d", oname->d.iPAddress->data[0], + oname->d.iPAddress->data[1], + oname->d.iPAddress->data[2], + oname->d.iPAddress->data[3]); + rtn = strdup(ipbuf); + } + else if ((oname->d.iPAddress->length == 16) || + (oname->d.iPAddress->length == 20)) { + char *pos = ipbuf; + int j; + for(j = 0; j < oname->d.iPAddress->length; ++j) { + *pos++ = VAL2HEX(oname->d.iPAddress->data[j]); + *pos++ = ':'; + } + *pos = '\0'; + rtn = strdup(ipbuf); + } + else + NETSNMP_LOGONCE((LOG_WARNING, "unexpected ip addr length %d\n", + oname->d.iPAddress->length)); + + break; + default: + DEBUGMSGT(("openssl:cert:san", "unknown/unsupported type %d\n", + oname->type)); + break; + } + DEBUGMSGT(("9:openssl:cert:san", "san=%s\n", buf)); + if (buf) + OPENSSL_free(buf); + + return rtn; +} + +#ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES +/** netsnmp_openssl_cert_get_subjectAltName: get subjectAltName for cert. + * if a pointer to a buffer and its length are specified, they will be + * used. otherwise, a new buffer will be allocated, which the caller will + * be responsbile for releasing. + */ +char * +netsnmp_openssl_cert_get_subjectAltNames(X509 *ocert, char **buf, int *len) +{ + return _cert_get_extension_id_str(ocert, NID_subject_alt_name, buf, len, 0); +} +#endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES */ + +void +netsnmp_openssl_cert_dump_extensions(X509 *ocert) +{ + X509_EXTENSION *extension; + const char *extension_name; + char buf[SNMP_MAXBUF_SMALL], *buf_ptr = buf, *str, *lf; + int i, num_extensions, buf_len, nid; + + if (NULL == ocert) + return; + + DEBUGIF("9:cert:dump") + ; + else + return; /* bail if debug not enabled */ + + num_extensions = X509_get_ext_count(ocert); + if (0 == num_extensions) + DEBUGMSGT(("9:cert:dump", " 0 extensions\n")); + for(i = 0; i < num_extensions; i++) { + extension = X509_get_ext(ocert, i); + nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension)); + extension_name = OBJ_nid2sn(nid); + buf_len = sizeof(buf); + str = _cert_get_extension_str_at(ocert, i, &buf_ptr, &buf_len, 0); + lf = strchr(str, '\n'); /* look for multiline strings */ + if (NULL != lf) + *lf = '\0'; /* only log first line of multiline here */ + DEBUGMSGT(("9:cert:dump", " %2d: %s = %s\n", i, + extension_name, str)); + while(lf) { /* log remaining parts of multiline string */ + str = ++lf; + if (*str == '\0') + break; + lf = strchr(str, '\n'); + if (NULL == lf) + break; + *lf = '\0'; + DEBUGMSGT(("9:cert:dump", " %s\n", str)); + } + } +} + +static int _htmap[NS_HASH_MAX + 1] = { + 0, NID_md5WithRSAEncryption, NID_sha1WithRSAEncryption, + NID_sha224WithRSAEncryption, NID_sha256WithRSAEncryption, + NID_sha384WithRSAEncryption, NID_sha512WithRSAEncryption }; + +int +_nid2ht(int nid) +{ + int i; + for (i=1; i<= NS_HASH_MAX; ++i) { + if (nid == _htmap[i]) + return i; + } + return 0; +} + +#ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_HT2NID +int +_ht2nid(int ht) +{ + if ((ht < 0) || (ht > NS_HASH_MAX)) + return 0; + return _htmap[ht]; +} +#endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_HT2NID */ + +/** + * returns allocated pointer caller must free. + */ +int +netsnmp_openssl_cert_get_hash_type(X509 *ocert) +{ + if (NULL == ocert) + return 0; + + return _nid2ht(OBJ_obj2nid(ocert->sig_alg->algorithm)); +} + +/** + * returns allocated pointer caller must free. + */ +char * +netsnmp_openssl_cert_get_fingerprint(X509 *ocert, int alg) +{ + u_char fingerprint[EVP_MAX_MD_SIZE]; + u_int fingerprint_len, nid; + const EVP_MD *digest; + char *result = NULL; + + if (NULL == ocert) + return NULL; + + nid = OBJ_obj2nid(ocert->sig_alg->algorithm); + DEBUGMSGT(("9:openssl:fingerprint", "alg %d, cert nid %d (%d)\n", alg, nid, + _nid2ht(nid))); + + if ((-1 == alg) && nid) + alg = _nid2ht(nid); + + switch (alg) { + case NS_HASH_MD5: + snmp_log(LOG_ERR, "hash type md5 not yet supported\n"); + return NULL; + break; + + case NS_HASH_NONE: + snmp_log(LOG_ERR, "hash type none not supported. using SHA1\n"); + /** fall through */ + + case NS_HASH_SHA1: + digest = EVP_sha1(); + break; + +#ifdef HAVE_EVP_SHA224 + case NS_HASH_SHA224: + digest = EVP_sha224(); + break; + + case NS_HASH_SHA256: + digest = EVP_sha256(); + break; + +#endif +#ifdef HAVE_EVP_SHA384 + case NS_HASH_SHA384: + digest = EVP_sha384(); + break; + + case NS_HASH_SHA512: + digest = EVP_sha512(); + break; +#endif + + default: + snmp_log(LOG_ERR, "unknown hash algorithm %d\n", alg); + return NULL; + } + + if (_nid2ht(nid) != alg) { + DEBUGMSGT(("openssl:fingerprint", + "WARNING: alg %d does not match cert alg %d\n", + alg, _nid2ht(nid))); + } + if (X509_digest(ocert,digest,fingerprint,&fingerprint_len)) { + binary_to_hex(fingerprint, fingerprint_len, &result); + if (NULL == result) + snmp_log(LOG_ERR, "failed to hexify fingerprint\n"); + else + DEBUGMSGT(("9:openssl:fingerprint", "fingerprint %s\n", result)); + } + else + snmp_log(LOG_ERR,"failed to compute fingerprint\n"); + + return result; +} + +/** + * get container of netsnmp_cert_map structures from an ssl connection + * certificate chain. + */ +netsnmp_container * +netsnmp_openssl_get_cert_chain(SSL *ssl) +{ + X509 *ocert, *ocert_tmp; + STACK_OF(X509) *ochain; + char *fingerprint; + netsnmp_container *chain_map; + netsnmp_cert_map *cert_map; + int i; + + netsnmp_assert_or_return(ssl != NULL, NULL); + + if (NULL == (ocert = SSL_get_peer_certificate(ssl))) { + /** no peer cert */ + snmp_log(LOG_ERR, "SSL peer has no certificate\n"); + return NULL; + } + DEBUGIF("9:cert:dump") { + netsnmp_openssl_cert_dump_extensions(ocert); + } + + /* + * get fingerprint and save it + */ + fingerprint = netsnmp_openssl_cert_get_fingerprint(ocert, -1); + if (NULL == fingerprint) + return NULL; + + /* + * allocate cert map. Don't pass in fingerprint, since it would strdup + * it and we've already got a copy. + */ + cert_map = netsnmp_cert_map_alloc(NULL, ocert); + if (NULL == cert_map) { + free(fingerprint); + return NULL; + } + cert_map->fingerprint = fingerprint; + cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert); + + chain_map = netsnmp_cert_map_container_create(0); /* no fp subcontainer */ + if (NULL == chain_map) { + netsnmp_cert_map_free(cert_map); + return NULL; + } + + CONTAINER_INSERT(chain_map, cert_map); + + /** check for a chain to a CA */ + ochain = SSL_get_peer_cert_chain(ssl); + if ((NULL == ochain) || (0 == sk_num((const void *)ochain))) { + DEBUGMSGT(("ssl:cert:chain", "peer has no cert chain\n")); + } + else { + /* + * loop over chain, adding fingerprint / cert for each + */ + DEBUGMSGT(("ssl:cert:chain", "examining cert chain\n")); + for(i = 0; i < sk_num((const void *)ochain); ++i) { + ocert_tmp = (X509*)sk_value((const void *)ochain,i); + fingerprint = netsnmp_openssl_cert_get_fingerprint(ocert_tmp, + NS_HASH_SHA1); + if (NULL == fingerprint) + break; + cert_map = netsnmp_cert_map_alloc(NULL, ocert); + if (NULL == cert_map) { + free(fingerprint); + break; + } + cert_map->fingerprint = fingerprint; + cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert_tmp); + + CONTAINER_INSERT(chain_map, cert_map); + } /* chain loop */ + /* + * if we broke out of loop before finishing, clean up + */ + if (i < sk_num((const void *)ochain)) + CONTAINER_FREE_ALL(chain_map, NULL); + } /* got peer chain */ + + DEBUGMSGT(("ssl:cert:chain", "found %" NETSNMP_PRIz "u certs in chain\n", + CONTAINER_SIZE(chain_map))); + if (CONTAINER_SIZE(chain_map) == 0) { + CONTAINER_FREE(chain_map); + chain_map = NULL; + } + + return chain_map; +} + +/* +tlstmCertSANRFC822Name "Maps a subjectAltName's rfc822Name to a + tmSecurityName. The local part of the rfc822Name is + passed unaltered but the host-part of the name must + be passed in lower case. + Example rfc822Name Field: FooBar@Example.COM + is mapped to tmSecurityName: FooBar@example.com" + +tlstmCertSANDNSName "Maps a subjectAltName's dNSName to a + tmSecurityName after first converting it to all + lower case." + +tlstmCertSANIpAddress "Maps a subjectAltName's iPAddress to a + tmSecurityName by transforming the binary encoded + address as follows: + 1) for IPv4 the value is converted into a decimal + dotted quad address (e.g. '192.0.2.1') + 2) for IPv6 addresses the value is converted into a + 32-character all lowercase hexadecimal string + without any colon separators. + + Note that the resulting length is the maximum + length supported by the View-Based Access Control + Model (VACM). Note that using both the Transport + Security Model's support for transport prefixes + (see the SNMP-TSM-MIB's + snmpTsmConfigurationUsePrefix object for details) + will result in securityName lengths that exceed + what VACM can handle." + +tlstmCertSANAny "Maps any of the following fields using the + corresponding mapping algorithms: + | rfc822Name | tlstmCertSANRFC822Name | + | dNSName | tlstmCertSANDNSName | + | iPAddress | tlstmCertSANIpAddress | + The first matching subjectAltName value found in the + certificate of the above types MUST be used when + deriving the tmSecurityName." +*/ +char * +_cert_get_san_type(X509 *ocert, int mapType) +{ + GENERAL_NAMES *onames; + const GENERAL_NAME *oname = NULL; + char *buf = NULL, *lower = NULL; + int count, i; + + onames = (GENERAL_NAMES *)X509_get_ext_d2i(ocert, NID_subject_alt_name, + NULL, NULL ); + if (NULL == onames) + return NULL; + + count = sk_GENERAL_NAME_num(onames); + + for (i=0 ; i <count; ++i) { + oname = sk_GENERAL_NAME_value(onames, i); + + if (GEN_DNS == oname->type) { + if ((TSNM_tlstmCertSANDNSName == mapType) || + (TSNM_tlstmCertSANAny == mapType)) { + lower = buf = _extract_oname( oname );; + break; + } + } + else if (GEN_IPADD == oname->type) { + if ((TSNM_tlstmCertSANIpAddress == mapType) || + (TSNM_tlstmCertSANAny == mapType)) + buf = _extract_oname(oname); + break; + } + else if (GEN_EMAIL == oname->type) { + if ((TSNM_tlstmCertSANRFC822Name == mapType) || + (TSNM_tlstmCertSANAny == mapType)) { + buf = _extract_oname(oname); + lower = strchr(buf, '@'); + if (NULL == lower) { + DEBUGMSGT(("openssl:secname:extract", + "email %s has no '@'!\n", buf)); + } + else { + ++lower; + break; + } + } + + } + } /* for loop */ + + if (lower) + for ( ; *lower; ++lower ) + if (isascii(*lower)) + *lower = tolower(0xFF & *lower); + DEBUGMSGT(("openssl:cert:extension:san", "#%d type %d: %s\n", i, + oname ? oname->type : -1, buf ? buf : "NULL")); + + return buf; +} + +char * +netsnmp_openssl_extract_secname(netsnmp_cert_map *cert_map, + netsnmp_cert_map *peer_cert) +{ + char *rtn = NULL; + + if (NULL == cert_map) + return NULL; + + DEBUGMSGT(("openssl:secname:extract", + "checking priority %d, san of type %d for %s\n", + cert_map->priority, cert_map->mapType, peer_cert->fingerprint)); + + switch(cert_map->mapType) { + case TSNM_tlstmCertSpecified: + rtn = strdup(cert_map->data); + break; + + case TSNM_tlstmCertSANRFC822Name: + case TSNM_tlstmCertSANDNSName: + case TSNM_tlstmCertSANIpAddress: + case TSNM_tlstmCertSANAny: + if (NULL == peer_cert) { + DEBUGMSGT(("openssl:secname:extract", "no peer cert for %s\n", + cert_map->fingerprint)); + break; + } + rtn = _cert_get_san_type(peer_cert->ocert, cert_map->mapType); + if (NULL == rtn) { + DEBUGMSGT(("openssl:secname:extract", "no san for %s\n", + peer_cert->fingerprint)); + } + break; + + case TSNM_tlstmCertCommonName: + rtn = netsnmp_openssl_cert_get_commonName(cert_map->ocert, NULL, + NULL); + break; + default: + snmp_log(LOG_ERR, "cant extract secname for unknown map type %d\n", + cert_map->mapType); + break; + } /* switch mapType */ + + if (rtn) { + DEBUGMSGT(("openssl:secname:extract", + "found map %d, type %d for %s: %s\n", cert_map->priority, + cert_map->mapType, peer_cert->fingerprint, rtn)); + if (strlen(rtn) >32) { + DEBUGMSGT(("openssl:secname:extract", + "secName longer than 32 chars! dropping...\n")); + SNMP_FREE(rtn); + } + } + else + DEBUGMSGT(("openssl:secname:extract", + "no map of type %d for %s\n", + cert_map->mapType, peer_cert->fingerprint)); + return rtn; +} + +int +netsnmp_openssl_cert_issued_by(X509 *issuer, X509 *cert) +{ + return (X509_check_issued(issuer, cert) == X509_V_OK); +} + + +#ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_ERR_LOG +void +netsnmp_openssl_err_log(const char *prefix) +{ + unsigned long err; + for (err = ERR_get_error(); err; err = ERR_get_error()) { + snmp_log(LOG_ERR,"%s: %ld\n", prefix ? prefix: "openssl error", err); + snmp_log(LOG_ERR, "library=%d, function=%d, reason=%d\n", + ERR_GET_LIB(err), ERR_GET_FUNC(err), ERR_GET_REASON(err)); + } +} +#endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_ERR_LOG */ + +void +netsnmp_openssl_null_checks(SSL *ssl, int *null_auth, int *null_cipher) +{ + const SSL_CIPHER *cipher; + char tmp_buf[128], *cipher_alg, *auth_alg; + + if (null_auth) + *null_auth = -1; /* unknown */ + if (null_cipher) + *null_cipher = -1; /* unknown */ + if (NULL == ssl) + return; + + cipher = SSL_get_current_cipher(ssl); + if (NULL == cipher) { + DEBUGMSGTL(("ssl:cipher", "no cipher yet\n")); + return; + } + SSL_CIPHER_description(NETSNMP_REMOVE_CONST(SSL_CIPHER *, cipher), tmp_buf, sizeof(tmp_buf)); + /** no \n since tmp_buf already has one */ + DEBUGMSGTL(("ssl:cipher", "current cipher: %s", tmp_buf)); + + /* + * run "openssl ciphers -v eNULL" and "openssl ciphers -v aNULL" + * to see NULL encryption/authentication algorithms. e.g. + * + * EXP-ADH-RC4-MD5 SSLv3 Kx=DH(512) Au=None Enc=RC4(40) Mac=MD5 export + * NULL-SHA SSLv3 Kx=RSA Au=RSA Enc=None Mac=SHA1 + */ + if (null_cipher) { + cipher_alg = strstr(tmp_buf, "Enc="); + if (cipher_alg) { + cipher_alg += 4; + if (strncmp(cipher_alg,"None", 4) == 0) + *null_cipher = 1; + else + *null_cipher = 0; + } + } + if (null_auth) { + auth_alg = strstr(tmp_buf, "Au="); + if (auth_alg) { + auth_alg += 3; + if (strncmp(auth_alg,"None", 4) == 0) + *null_auth = 1; + else + *null_auth = 0; + } + } +} + +#endif /* NETSNMP_USE_OPENSSL && HAVE_LIBSSL && !defined(NETSNMP_FEATURE_REMOVE_CERT_UTIL) */ |