OpenSSL 4.0 compatibility. Fixes #3375

This commit is contained in:
dmiller 2026-06-16 13:58:41 +00:00
parent a5ee61bea2
commit 538764bb6a
5 changed files with 83 additions and 27 deletions

View file

@ -237,7 +237,7 @@ static void connect_report(nsock_iod nsi)
#ifdef HAVE_OPENSSL
if (nsock_iod_check_ssl(nsi)) {
X509 *cert;
X509_NAME *subject;
const X509_NAME *subject;
char digest_buf[SHA1_STRING_LENGTH + 1];
char *fp;
@ -249,11 +249,34 @@ static void connect_report(nsock_iod nsi)
subject = X509_get_subject_name(cert);
if (subject != NULL) {
char buf[256];
int n;
int lastpos = -1;
n = X509_NAME_get_text_by_NID(subject, NID_organizationName, buf, sizeof(buf));
if (n >= 0 && n <= sizeof(buf) - 1)
loguser_noprefix(" %s", buf);
lastpos = X509_NAME_get_index_by_NID(subject, NID_organizationName, lastpos);
if (lastpos >= 0) {
const X509_NAME_ENTRY *entry = X509_NAME_get_entry(subject, lastpos);
if (entry != NULL) {
const ASN1_STRING *asn1_str = X509_NAME_ENTRY_get_data(entry);
if (asn1_str != NULL) {
// ASN1_STRING_to_UTF8 handles converting BMPString, UniversalString,
// or UTF8String into a standard, readable UTF-8 format.
unsigned char *utf8_buf = NULL;
int len = ASN1_STRING_to_UTF8(&utf8_buf, asn1_str);
if (len >= 0) {
// Ensure we don't overflow our local buffer and null-terminate safely
int copy_len = (len < (int)sizeof(buf) - 1) ? len : (int)sizeof(buf) - 1;
memcpy(buf, utf8_buf, copy_len);
buf[copy_len] = '\0';
loguser_noprefix(" %s", buf);
// OpenSSL allocates memory for utf8_buf, so we must free it
OPENSSL_free(utf8_buf);
}
}
}
}
}
loguser_noprefix("\n");

View file

@ -72,11 +72,13 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined LIBRESSL_VERSION_NUMBER
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined LIBRESSL_VERSION_NUMBER || \
(defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER >= 0x3050000fL)
#define HAVE_OPAQUE_STRUCTS 1
#define FUNC_ASN1_STRING_data ASN1_STRING_get0_data
#else
#define FUNC_ASN1_STRING_data ASN1_STRING_data
#define FUNC_ASN1_STRING_length(_s) ((_s)->length)
#endif
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
@ -265,10 +267,10 @@ static int wildcard_match(const char *pattern, const char *hostname, int len)
static int cert_match_dnsname(X509 *cert, const char *hostname,
unsigned int *num_checked)
{
X509_EXTENSION *ext;
const X509_EXTENSION *ext;
STACK_OF(GENERAL_NAME) *gen_names;
const X509V3_EXT_METHOD *method;
unsigned char *data;
const unsigned char *data;
int i;
int ret = 0;
@ -291,8 +293,8 @@ static int cert_match_dnsname(X509 *cert, const char *hostname,
/* We must copy this address into a temporary variable because ASN1_item_d2i
increments it. We don't want it to corrupt ext->value->data. */
ASN1_OCTET_STRING* asn1_str = X509_EXTENSION_get_data(ext);
data = asn1_str->data;
const ASN1_OCTET_STRING* asn1_str = X509_EXTENSION_get_data(ext);
data = FUNC_ASN1_STRING_data(asn1_str);
/* Here we rely on the fact that the internal representation (the "i" in
"i2d") for NID_subject_alt_name is STACK_OF(GENERAL_NAME). Converting it
to a stack of CONF_VALUE with a i2v method is not satisfactory, because a
@ -300,15 +302,15 @@ static int cert_match_dnsname(X509 *cert, const char *hostname,
presence of null bytes. */
#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
if (method->it != NULL) {
ASN1_OCTET_STRING* asn1_str_a = X509_EXTENSION_get_data(ext);
const ASN1_OCTET_STRING* asn1_str_a = X509_EXTENSION_get_data(ext);
gen_names = (STACK_OF(GENERAL_NAME) *) ASN1_item_d2i(NULL,
(const unsigned char **) &data,
asn1_str_a->length, ASN1_ITEM_ptr(method->it));
ASN1_STRING_length(asn1_str_a), ASN1_ITEM_ptr(method->it));
} else {
ASN1_OCTET_STRING* asn1_str_b = X509_EXTENSION_get_data(ext);
const ASN1_OCTET_STRING* asn1_str_b = X509_EXTENSION_get_data(ext);
gen_names = (STACK_OF(GENERAL_NAME) *) method->d2i(NULL,
(const unsigned char **) &data,
asn1_str_b->length);
ASN1_STRING_length(asn1_str_b));
}
#else
gen_names = (STACK_OF(GENERAL_NAME) *) method->d2i(NULL,
@ -378,9 +380,9 @@ static int less_specific(const unsigned char *a, size_t a_len,
return num_components(a, a_len) < num_components(b, b_len);
}
static int most_specific_commonname(X509_NAME *subject, const char **result)
static int most_specific_commonname(const X509_NAME *subject, const char **result)
{
ASN1_STRING *best, *cur;
const ASN1_STRING *best, *cur;
int i;
i = -1;
@ -414,7 +416,7 @@ static int most_specific_commonname(X509_NAME *subject, const char **result)
components, the one that comes later in the certificate is more specific. */
static int cert_match_commonname(X509 *cert, const char *hostname)
{
X509_NAME *subject;
const X509_NAME *subject;
const char *commonname;
int n;
@ -477,7 +479,7 @@ int ssl_post_connect_check(SSL *ssl, const char *hostname)
"Making Certificates"; and apps/req.c in the OpenSSL source. */
static int ssl_gen_cert(X509 **cert, EVP_PKEY **key)
{
X509_NAME *subj;
X509_NAME *subj = NULL;
X509_EXTENSION *ext;
X509V3_CTX ctx;
const char *commonName = "localhost";
@ -531,13 +533,20 @@ static int ssl_gen_cert(X509 **cert, EVP_PKEY **key)
ASN1_INTEGER_set(X509_get_serialNumber(*cert), get_random_u32() & 0x7FFFFFFF);
/* Set the commonName. */
subj = X509_get_subject_name(*cert);
subj = X509_NAME_new();
if (subj == NULL)
goto err;
if (o.target != NULL)
commonName = o.target;
if (X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
(unsigned char *) commonName, -1, -1, 0) == 0) {
goto err;
}
if (X509_set_subject_name(*cert, subj) == 0) {
goto err;
}
X509_NAME_free(subj);
subj = NULL;
/* Set the dNSName. */
rc = Snprintf(dNSName, sizeof(dNSName), "DNS:%s", commonName);
@ -594,6 +603,8 @@ static int ssl_gen_cert(X509 **cert, EVP_PKEY **key)
return 1;
err:
if (subj != NULL)
X509_NAME_free(subj);
if (*cert != NULL)
X509_free(*cert);
if (*key != NULL)

View file

@ -17,6 +17,7 @@ are rejected. The SSL transactions happen over OpenSSL BIO pairs.
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/safestack.h>
#include "ncat_core.h"
#include "ncat_ssl.h"
@ -351,16 +352,24 @@ static int gen_cert(X509 **cert, EVP_PKEY **key,
/* Set the commonNames. */
if (commonNames != NULL) {
X509_NAME *subj;
const struct lstr *name;
X509_NAME *subj = X509_NAME_new();
if (subj == NULL)
goto err;
subj = X509_get_subject_name(*cert);
for (name = commonNames; !is_sentinel(name); name++) {
if (X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
(unsigned char *) name->s, name->len, -1, 0) == 0) {
X509_NAME_free(subj);
goto err;
}
}
if (X509_set_subject_name(*cert, subj) == 0) {
X509_NAME_free(subj);
goto err;
}
X509_NAME_free(subj);
subj = NULL;
}
/* Set the dNSNames. */

View file

@ -84,9 +84,13 @@
/* Technically some of these things were added in 0x10100006
* but that was pre-release. */
#define HAVE_OPAQUE_STRUCTS 1
#define FUNC_ASN1_STRING_get0_data ASN1_STRING_get0_data
#define FUNC_ASN1_STRING_length ASN1_STRING_length
#else
#define X509_get0_notBefore X509_get_notBefore
#define X509_get0_notAfter X509_get_notAfter
#define FUNC_ASN1_STRING_get0_data(_s) ((_s)->data)
#define FUNC_ASN1_STRING_length(_s) ((_s)->length)
#endif
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
@ -194,14 +198,14 @@ static void obj_to_key(lua_State *L, const ASN1_OBJECT *obj)
/* This is a helper function for l_get_ssl_certificate. It builds a table from
the given X509_NAME, using keys returned from obj_to_key as keys. The result
is pushed on the stack. */
static void x509_name_to_table(lua_State *L, X509_NAME *name)
static void x509_name_to_table(lua_State *L, const X509_NAME *name)
{
int i;
lua_createtable(L, 0, X509_NAME_entry_count(name));
for (i = 0; i < X509_NAME_entry_count(name); i++) {
X509_NAME_ENTRY *entry;
const X509_NAME_ENTRY *entry;
const ASN1_OBJECT *obj;
const ASN1_STRING *value;
@ -210,7 +214,7 @@ static void x509_name_to_table(lua_State *L, X509_NAME *name)
value = X509_NAME_ENTRY_get_data(entry);
obj_to_key(L, obj);
lua_pushlstring(L, (const char *) value->data, value->length);
lua_pushlstring(L, (const char *) FUNC_ASN1_STRING_get0_data(value), FUNC_ASN1_STRING_length(value));
lua_settable(L, -3);
}
@ -224,7 +228,7 @@ static bool x509_extensions_to_table(lua_State *L, const STACK_OF(X509_EXTENSION
lua_createtable(L, sk_X509_EXTENSION_num(exts), 0);
for (int i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
const ASN1_OBJECT *obj;
X509_EXTENSION *ext;
char *value = NULL;
BIO *out;
@ -265,6 +269,7 @@ static bool x509_extensions_to_table(lua_State *L, const STACK_OF(X509_EXTENSION
}
#ifndef HAVE_OPAQUE_STRUCTS
/* Parse as a decimal integer the len characters starting at s. This function
can only process positive numbers; if the return value is negative then a
parsing error occurred. */
@ -292,12 +297,17 @@ static int parse_int(const unsigned char *s, size_t len)
return (int) v;
}
#endif
/* This is a helper function for asn1_time_to_obj. It parses a textual ASN1_TIME
value and stores the time in the given struct tm. It returns 0 on success and
-1 on a parse error. */
static int time_to_tm(const ASN1_TIME *t, struct tm *result)
{
#ifdef HAVE_OPAQUE_STRUCTS
/* Returns 1 on success, 0 on error */
return ASN1_TIME_to_tm(t, result) - 1;
#else
const unsigned char *p;
p = t->data;
@ -345,6 +355,7 @@ static int time_to_tm(const ASN1_TIME *t, struct tm *result)
}
return 0;
#endif
}
/* This is a helper function for asn1_time_to_obj. It converts a struct tm into
@ -385,7 +396,7 @@ static void asn1_time_to_obj(lua_State *L, const ASN1_TIME *s)
} else if (time_to_tm(s, &tm) == 0) {
tm_to_table(L, &tm);
} else {
lua_pushlstring(L, (const char *) s->data, s->length);
lua_pushlstring(L, (const char *) FUNC_ASN1_STRING_get0_data(s), FUNC_ASN1_STRING_length(s));
}
}
@ -549,7 +560,7 @@ int l_get_ssl_certificate(lua_State *L)
static int parse_ssl_cert(lua_State *L, X509 *cert)
{
struct cert_userdata *udata;
X509_NAME *subject, *issuer;
const X509_NAME *subject, *issuer;
EVP_PKEY *pubkey;
int pkey_type;

View file

@ -133,6 +133,8 @@ static SSL_CTX *ssl_init_helper(const SSL_METHOD *method) {
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER
SSL_load_error_strings();
SSL_library_init();
#elif OPENSSL_VERSION_NUMBER >= 0x40000000L
atexit(nsock_ssl_atexit);
#else
OPENSSL_atexit(nsock_ssl_atexit);
#endif