From be47ec9799ef7708f181d1b20fc238f23539a9b0 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 8 Jun 2020 15:59:24 +0200 Subject: [PATCH] libotp: Replace NSS with OpenSSL HMAC Use OpenSSL's HMAC API instead of NSS. Fixes: Fixes: https://pagure.io/freeipa/issue/6857 Signed-off-by: Christian Heimes Reviewed-By: Alexander Bokovoy --- configure.ac | 4 +- daemons/ipa-kdb/Makefile.am | 3 - daemons/ipa-otpd/Makefile.am | 2 +- .../ipa-pwd-extop/Makefile.am | 3 - .../ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h | 1 - daemons/ipa-slapi-plugins/libotp/Makefile.am | 6 +- daemons/ipa-slapi-plugins/libotp/hotp.c | 155 ++++-------------- daemons/ipa-slapi-plugins/libotp/t_hotp.c | 4 - freeipa.spec.in | 2 - server.m4 | 3 + 10 files changed, 41 insertions(+), 142 deletions(-) diff --git a/configure.ac b/configure.ac index ab6a2ef0e..36f9a1ebf 100644 --- a/configure.ac +++ b/configure.ac @@ -54,10 +54,8 @@ AM_CONDITIONAL([WITH_IPATESTS], [test x"$with_ipatests" = xyes]) AM_CONDITIONAL([HAVE_GCC], [test "$ac_cv_prog_gcc" = yes]) dnl --------------------------------------------------------------------------- -dnl - Check for NSPR/NSS +dnl - Check for POPT dnl --------------------------------------------------------------------------- -PKG_CHECK_MODULES([NSPR], [nspr]) -PKG_CHECK_MODULES([NSS], [nss]) PKG_CHECK_MODULES([POPT], [popt]) diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am index 0a8c65994..11aeec5f0 100644 --- a/daemons/ipa-kdb/Makefile.am +++ b/daemons/ipa-kdb/Makefile.am @@ -17,7 +17,6 @@ AM_CPPFLAGS = \ $(KRB5_CFLAGS) \ $(WARN_CFLAGS) \ $(NDRPAC_CFLAGS) \ - $(NSS_CFLAGS) \ $(SSSCERTMAP_CFLAGS) \ $(NULL) @@ -60,7 +59,6 @@ ipadb_la_LIBADD = \ $(LDAP_LIBS) \ $(NDRPAC_LIBS) \ $(UNISTRING_LIBS) \ - $(NSS_LIBS) \ $(SSSCERTMAP_LIBS) \ $(top_builddir)/util/libutil.la \ $(NULL) @@ -100,7 +98,6 @@ ipa_kdb_tests_LDADD = \ $(LDAP_LIBS) \ $(NDRPAC_LIBS) \ $(UNISTRING_LIBS) \ - $(NSS_LIBS) \ $(SSSCERTMAP_LIBS) \ $(top_builddir)/util/libutil.la \ -lkdb5 \ diff --git a/daemons/ipa-otpd/Makefile.am b/daemons/ipa-otpd/Makefile.am index c1d6c2053..867269300 100644 --- a/daemons/ipa-otpd/Makefile.am +++ b/daemons/ipa-otpd/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS := @LDAP_CFLAGS@ @LIBVERTO_CFLAGS@ @KRB5_CFLAGS@ +AM_CFLAGS := @LDAP_CFLAGS@ @LIBVERTO_CFLAGS@ @KRB5_CFLAGS@ @NSPR_CFLAGS@ AM_LDFLAGS := @LDAP_LIBS@ @LIBVERTO_LIBS@ @KRAD_LIBS@ @KRB5_LIBS@ noinst_HEADERS = internal.h diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am index f2639ba7f..969fe7cd8 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am @@ -17,7 +17,6 @@ AM_CPPFLAGS = \ $(LDAP_CFLAGS) \ $(KRB5_CFLAGS) \ $(NSPR_CFLAGS) \ - $(NSS_CFLAGS) \ $(WARN_CFLAGS) \ $(NULL) @@ -25,8 +24,6 @@ AM_LDFLAGS = \ $(CRYPTO_LIBS) \ $(KRB5_LIBS) \ $(LDAP_LIBS) \ - $(NSPR_LIBS) \ - $(NSS_LIBS) \ -avoid-version \ -export-symbols-regex ^ipapwd_init$ diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h index 5a49fa7e6..79606a8c7 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h @@ -51,7 +51,6 @@ #include #include -#include #include #include #include diff --git a/daemons/ipa-slapi-plugins/libotp/Makefile.am b/daemons/ipa-slapi-plugins/libotp/Makefile.am index eb4494d7a..3e9088b58 100644 --- a/daemons/ipa-slapi-plugins/libotp/Makefile.am +++ b/daemons/ipa-slapi-plugins/libotp/Makefile.am @@ -4,15 +4,15 @@ PLUGIN_COMMON_DIR = $(srcdir)/../common AM_CPPFLAGS = \ -I$(PLUGIN_COMMON_DIR) \ $(DIRSRV_CFLAGS) \ + $(CRYPTO_CFLAGS) \ $(NSPR_CFLAGS) \ - $(NSS_CFLAGS) \ $(NULL) noinst_LTLIBRARIES = libhotp.la libotp.la libhotp_la_SOURCES = hotp.c hotp.h libotp_la_SOURCES = otp_config.c otp_config.h otp_token.c otp_token.h -libotp_la_LIBADD = libhotp.la +libotp_la_LIBADD = libhotp.la $(CRYPTO_LIBS) check_PROGRAMS = t_hotp TESTS = $(check_PROGRAMS) -t_hotp_LDADD = libhotp.la $(NSPR_LIBS) $(NSS_LIBS) +t_hotp_LDADD = libhotp.la $(CRYPTO_LIBS) diff --git a/daemons/ipa-slapi-plugins/libotp/hotp.c b/daemons/ipa-slapi-plugins/libotp/hotp.c index 1b9110ebf..109ee6760 100644 --- a/daemons/ipa-slapi-plugins/libotp/hotp.c +++ b/daemons/ipa-slapi-plugins/libotp/hotp.c @@ -43,139 +43,48 @@ */ #include "hotp.h" -#include - -#include -#include -#include -#include -#include -#include +#include +#include #include +#include +#include struct digest_buffer { - uint8_t buf[SHA512_LENGTH]; + unsigned char buf[EVP_MAX_MD_SIZE]; unsigned int len; }; static const struct { const char *algo; - CK_MECHANISM_TYPE mech; + const char *sn_mech; } algo2mech[] = { - { "sha1", CKM_SHA_1_HMAC }, - { "sha256", CKM_SHA256_HMAC }, - { "sha384", CKM_SHA384_HMAC }, - { "sha512", CKM_SHA512_HMAC }, + { "sha1", SN_sha1 }, + { "sha256", SN_sha256 }, + { "sha384", SN_sha384 }, + { "sha512", SN_sha512 }, { } }; -static PK11SymKey * -import_key(PK11SlotInfo *slot, CK_MECHANISM_TYPE mech, SECItem *key) +static bool hmac(const struct hotp_token_key *key, const char *sn_mech, + uint64_t counter, struct digest_buffer *out) { - uint8_t ct[(key->len / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE]; - uint8_t iv[AES_BLOCK_SIZE] = {}; - SECItem ivitem = { .data = iv, .len = sizeof(iv), .type = siBuffer }; - SECItem ctitem = { .data = ct, .len = sizeof(ct), .type = siBuffer }; - PK11SymKey *ekey = NULL; - PK11SymKey *skey = NULL; + unsigned char in[sizeof(uint64_t)]; + const EVP_MD *evp; + unsigned char *result; - /* Try to import the key directly. */ - skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, - CKA_SIGN, key, NULL); - if (skey) - return skey; + memcpy(in, &counter, sizeof(uint64_t)); - /* If we get here, we are probably in FIPS mode. Let's encrypt the key so - * that we can unseal it instead of loading it directly. */ - - /* Generate an ephemeral key. */ - ekey = PK11_TokenKeyGenWithFlags(slot, CKM_AES_CBC_PAD, NULL, - AES_128_KEY_LENGTH, NULL, - CKF_ENCRYPT | CKF_UNWRAP, - PK11_ATTR_SESSION | - PK11_ATTR_PRIVATE | - PK11_ATTR_SENSITIVE, NULL); - if (!ekey) { - syslog(LOG_ERR, "libotp: in FIPS, PK11_TokenKeyGenWithFlags failed: %d", - PR_GetError()); - goto egress; + evp = EVP_get_digestbyname(sn_mech); + if (evp == NULL) { + return false; } - /* Encrypt the input key. */ - if (PK11_Encrypt(ekey, CKM_AES_CBC_PAD, &ivitem, ctitem.data, &ctitem.len, - ctitem.len, key->data, key->len) != SECSuccess) { - syslog(LOG_ERR, "libotp: in FIPS, PK11_Encrypt failed: %d", - PR_GetError()); - goto egress; + if (!HMAC(evp, (void *)key->bytes, key->len, in, sizeof(in), + out->buf, &out->len)) { + return false; } - /* Unwrap the input key. */ - skey = PK11_UnwrapSymKey(ekey, CKM_AES_CBC_PAD, &ivitem, - &ctitem, mech, CKA_SIGN, key->len); - if (!skey) { - syslog(LOG_ERR, "libotp: in FIPS, PK11_UnwrapSymKey failed: %d", - PR_GetError()); - } - -egress: - PK11_FreeSymKey(ekey); - return skey; -} - -/* - * This code is mostly cargo-cult taken from here: - * http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn5.html - * - * It should implement HMAC with the given mechanism (SHA: 1, 256, 384, 512). - */ -static bool hmac(SECItem *key, CK_MECHANISM_TYPE mech, const SECItem *in, - struct digest_buffer *out) -{ - SECItem param = { siBuffer, NULL, 0 }; - PK11SlotInfo *slot = NULL; - PK11SymKey *symkey = NULL; - PK11Context *ctx = NULL; - bool ret = false; - SECStatus s; - - slot = PK11_GetBestSlot(mech, NULL); - if (slot == NULL) { - slot = PK11_GetInternalKeySlot(); - if (slot == NULL) { - goto done; - } - } - - symkey = import_key(slot, mech, key); - if (symkey == NULL) - goto done; - - ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, symkey, ¶m); - if (ctx == NULL) - goto done; - - s = PK11_DigestBegin(ctx); - if (s != SECSuccess) - goto done; - - s = PK11_DigestOp(ctx, in->data, in->len); - if (s != SECSuccess) - goto done; - - s = PK11_DigestFinal(ctx, out->buf, &out->len, sizeof(out->buf)); - if (s != SECSuccess) - goto done; - - ret = true; - -done: - if (ctx != NULL) - PK11_DestroyContext(ctx, PR_TRUE); - if (symkey != NULL) - PK11_FreeSymKey(symkey); - if (slot != NULL) - PK11_FreeSlot(slot); - return ret; + return true; } /* @@ -183,32 +92,34 @@ done: */ bool hotp(const struct hotp_token *token, uint64_t counter, uint32_t *out) { - const SECItem cntr = { siBuffer, (uint8_t *) &counter, sizeof(counter) }; - SECItem keyitm = { siBuffer, token->key.bytes, token->key.len }; - CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC; - PRUint64 offset, binary, div; + const char *mech = SN_sha1; struct digest_buffer digest; + unsigned char counter_buf[sizeof(uint64_t)]; + const EVP_MD *evp; int digits = token->digits; int i; + uint64_t div, offset, binary; /* Convert counter to network byte order. */ - counter = PR_htonll(counter); + counter = htobe64(counter); + + /* Copy counter to buffer */ + memcpy(counter_buf, &counter, sizeof(uint64_t)); /* Find the mech. */ for (i = 0; algo2mech[i].algo; i++) { if (strcasecmp(algo2mech[i].algo, token->algo) == 0) { - mech = algo2mech[i].mech; + mech = algo2mech[i].sn_mech; break; } } - /* Create the digits divisor. */ for (div = 1; digits > 0; digits--) { div *= 10; } /* Do the digest. */ - if (!hmac(&keyitm, mech, &cntr, &digest)) { + if (!hmac(&(token->key), mech, counter, &digest)) { return false; } diff --git a/daemons/ipa-slapi-plugins/libotp/t_hotp.c b/daemons/ipa-slapi-plugins/libotp/t_hotp.c index 2e995fdaa..0a0dbff55 100644 --- a/daemons/ipa-slapi-plugins/libotp/t_hotp.c +++ b/daemons/ipa-slapi-plugins/libotp/t_hotp.c @@ -43,7 +43,6 @@ #include #include #include -#include #define KEY(s) { (uint8_t *) s, sizeof(s) - 1 } @@ -104,8 +103,6 @@ main(int argc, const char *argv[]) uint32_t otp; int i; - NSS_NoDB_Init("."); - for (i = 0; i < sizeof(hotp_answers) / sizeof(*hotp_answers); i++) { assert(hotp(&hotp_token, i, &otp)); assert(otp == hotp_answers[i]); @@ -116,6 +113,5 @@ main(int argc, const char *argv[]) assert(otp == totp_tests[i].answer); } - NSS_Shutdown(); return 0; } diff --git a/freeipa.spec.in b/freeipa.spec.in index 38237d0ec..56de28207 100755 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -178,7 +178,6 @@ BuildRequires: systemd # systemd-tmpfiles which is executed from make install requires apache user BuildRequires: httpd BuildRequires: nspr-devel -BuildRequires: nss-devel >= %{nss_version} BuildRequires: openssl-devel BuildRequires: libini_config-devel BuildRequires: cyrus-sasl-devel @@ -323,7 +322,6 @@ Requires: python3-ipaserver = %{version}-%{release} Requires: python3-ldap >= %{python_ldap_version} Requires: 389-ds-base >= %{ds_version} Requires: openldap-clients > 2.4.35-4 -Requires: nss >= %{nss_version} Requires: nss-tools >= %{nss_version} Requires(post): krb5-server >= %{krb5_version} Requires(post): krb5-server >= %{krb5_base_version}, krb5-server < %{krb5_base_version}.100 diff --git a/server.m4 b/server.m4 index 79c2fd270..d35823e80 100644 --- a/server.m4 +++ b/server.m4 @@ -4,6 +4,9 @@ dnl --------------------------------------------------------------------------- dnl - Check for DS slapi plugin dnl --------------------------------------------------------------------------- +# 389-ds headers depend on NSPR +PKG_CHECK_MODULES([NSPR], [nspr]) + # Need to hack CPPFLAGS to be able to correctly detect slapi-plugin.h SAVE_CPPFLAGS=$CPPFLAGS CPPFLAGS=$NSPR_CFLAGS