kerberos: Fix numerous segfaults when using weak crypto

Weak crypto is provided by the openssl legacy provider which is
not load by default. Load the legacy providers as needed.

When the legacy provider is loaded into the default context the default
provider will no longer be automatically loaded. Without the default
provider the various kerberos applicaions and functions will abort().

This is the second attempt at this patch. Instead of linking
secure/lib/libcrypto at build time we now link it at runtime, avoiding
buildworld failures under Linux and MacOS. This is because
TARGET_ENDIANNESS is undefined at pre-build time.

PR:		272835
MFC after:	3 days
X-MFC:		only to stable/14
Tested by:	netchild
		Joerg Pulz <Joerg.Pulz@frm2.tum.de> (previous version)
This commit is contained in:
Cy Schubert 2023-12-06 07:30:05 -08:00
parent 7a4d1d1df0
commit 476d63e091
10 changed files with 109 additions and 2 deletions

View File

@ -169,6 +169,10 @@ kadm5_s_create_principal(void *server_handle,
ent.entry.keys.len = 0;
ent.entry.keys.val = NULL;
ret = fbsd_ossl_provider_load();
if (ret)
goto out;
ret = _kadm5_set_keys(context, &ent.entry, password);
if (ret)
goto out;

View File

@ -79,5 +79,6 @@
#include <der.h>
#include <parse_units.h>
#include "private.h"
#include "fbsd_ossl_provider.h"
#endif /* __KADM5_LOCL_H__ */

View File

@ -392,6 +392,10 @@ krb5_init_context(krb5_context *context)
}
HEIMDAL_MUTEX_init(p->mutex);
ret = fbsd_ossl_provider_load();
if(ret)
goto out;
p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
ret = krb5_get_default_config_files(&files);

View File

@ -2054,6 +2054,9 @@ krb5_crypto_init(krb5_context context,
*crypto = NULL;
return ret;
}
ret = fbsd_ossl_provider_load();
if (ret)
return ret;
(*crypto)->key.schedule = NULL;
(*crypto)->num_key_usage = 0;
(*crypto)->key_usage = NULL;

View File

@ -43,6 +43,8 @@ krb5_salttype_to_string (krb5_context context,
struct _krb5_encryption_type *e;
struct salt_type *st;
(void) fbsd_ossl_provider_load();
e = _krb5_find_enctype (etype);
if (e == NULL) {
krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
@ -75,6 +77,8 @@ krb5_string_to_salttype (krb5_context context,
struct _krb5_encryption_type *e;
struct salt_type *st;
(void) fbsd_ossl_provider_load();
e = _krb5_find_enctype (etype);
if (e == NULL) {
krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
@ -196,6 +200,7 @@ krb5_string_to_key_data_salt_opaque (krb5_context context,
enctype);
return KRB5_PROG_ETYPE_NOSUPP;
}
(void) fbsd_ossl_provider_load();
for(st = et->keytype->string_to_key; st && st->type; st++)
if(st->type == salt.salttype)
return (*st->string_to_key)(context, enctype, password,

View File

@ -13,6 +13,7 @@ HEIMDAL_ROKEN_1.0 {
ct_memcmp;
err;
errx;
fbsd_ossl_provider_load;
free_getarg_strings;
get_default_username;
get_window_size;

View File

@ -17,5 +17,9 @@
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/ecdh.h>
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
#include <openssl/provider.h>
#include "fbsd_ossl_provider.h"
#endif
#endif /* __crypto_headers_h__ */

View File

@ -0,0 +1,4 @@
#ifndef __fbsd_ossl_provider_h
#define __fbsd_ossl_provider_h
int fbsd_ossl_provider_load(void);
#endif

View File

@ -74,9 +74,13 @@ SRCS= base64.c \
vis.c \
warnerr.c \
write_pid.c \
xfree.c
xfree.c \
fbsd_ossl_provider_load.c
CFLAGS+=-I${KRB5DIR}/lib/roken -I.
CFLAGS+=-I${KRB5DIR}/lib/roken \
-I${SRCTOP}/kerberos5/include \
-I${KRB5DIR}/lib/krb5 \
-I${SRCTOP}/crypto/openssl/include -I.
CLEANFILES= roken.h

View File

@ -0,0 +1,77 @@
#include <dlfcn.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/provider.h>
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
static void fbsd_ossl_provider_unload(void);
static void print_dlerror(char *);
static OSSL_PROVIDER *legacy;
static OSSL_PROVIDER *deflt;
static int providers_loaded = 0;
static OSSL_PROVIDER * (*ossl_provider_load)(OSSL_LIB_CTX *, const char*) = NULL;
static int (*ossl_provider_unload)(OSSL_PROVIDER *) = NULL;
static void *crypto_lib_handle = NULL;
static void
fbsd_ossl_provider_unload(void)
{
if (ossl_provider_unload == NULL) {
if (!(ossl_provider_unload = (int (*)(OSSL_PROVIDER*)) dlsym(crypto_lib_handle, "OSSL_PROVIDER_unload"))) {
print_dlerror("Unable to link OSSL_PROVIDER_unload");
return;
}
}
if (providers_loaded == 1) {
(*ossl_provider_unload)(legacy);
(*ossl_provider_unload)(deflt);
providers_loaded = 0;
}
}
static void
print_dlerror(char *message)
{
char *errstr;
if ((errstr = dlerror()) != NULL)
fprintf(stderr, "%s: %s\n",
message, errstr);
}
#endif
int
fbsd_ossl_provider_load(void)
{
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
if (crypto_lib_handle == NULL) {
if (!(crypto_lib_handle = dlopen("/usr/lib/libcrypto.so",
RTLD_LAZY|RTLD_GLOBAL))) {
print_dlerror("Unable to load libcrypto.so");
return (EINVAL);
}
}
if (ossl_provider_load == NULL) {
if (!(ossl_provider_load = (OSSL_PROVIDER * (*)(OSSL_LIB_CTX*, const char *)) dlsym(crypto_lib_handle, "OSSL_PROVIDER_load"))) {
print_dlerror("Unable to link OSSL_PROVIDER_load");
return(ENOENT);
}
}
if (providers_loaded == 0) {
if ((legacy = (*ossl_provider_load)(NULL, "legacy")) == NULL)
return (EINVAL);
if ((deflt = (*ossl_provider_load)(NULL, "default")) == NULL) {
(*ossl_provider_unload)(legacy);
return (EINVAL);
}
if (atexit(fbsd_ossl_provider_unload)) {
fbsd_ossl_provider_unload();
return (errno);
}
providers_loaded = 1;
}
#endif
return (0);
}