Merge pull request #275 from the-nic/feat/4895-argon2

feat(core): Support ARGON2I/ARGON2ID password hashes
This commit is contained in:
Extra Fu 2020-07-03 14:44:20 -04:00 committed by GitHub
commit 2f75c389f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 241 additions and 32 deletions

View file

@ -229,10 +229,16 @@ Some of the softwares on which SOGo depends are available from the repository
"Extra Packages for Enterprise Linux" (EPEL). To add EPEL to your packages "Extra Packages for Enterprise Linux" (EPEL). To add EPEL to your packages
sources, install the following package: sources, install the following package:
On RHEL/CentOS 7,
---- ----
rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
---- ----
For RHEL/CentOS 8
----
yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
---
SOGo relies on the GNUstep packages provided by Inverse and must not use the SOGo relies on the GNUstep packages provided by Inverse and must not use the
packages from EPEL. Adjust the repository definition to exclude those packages: packages from EPEL. Adjust the repository definition to exclude those packages:
@ -1666,6 +1672,8 @@ passwords. Possible values are: `none`, `plain`, `crypt`, `md5`,
`md5-crypt`, `smd5`, `cram-md5`, `ldap-md5`, and `sha`, `sha256`, `md5-crypt`, `smd5`, `cram-md5`, `ldap-md5`, and `sha`, `sha256`,
`sha256-crypt`, `sha512`, `sha512-crypt`, its ssha (e.g. `ssha` or `sha256-crypt`, `sha512`, `sha512-crypt`, its ssha (e.g. `ssha` or
`ssha256`) variants, `blf-crypt`, `PBKDF2`, and `sym-aes-128-cbc`. `ssha256`) variants, `blf-crypt`, `PBKDF2`, and `sym-aes-128-cbc`.
The `argon2i` and `argon2id` password hashing algorithms are supported
if SOGo is compiled with `libsodium`.
Passwords can have the scheme prepended in the form Passwords can have the scheme prepended in the form
`{scheme}encryptedPass`. `{scheme}encryptedPass`.

View file

@ -47,6 +47,11 @@ ifeq ($(HAS_LIBRARY_oath), yes)
SOGo_LIBRARIES_DEPEND_UPON += $(MFA_LIBS) SOGo_LIBRARIES_DEPEND_UPON += $(MFA_LIBS)
endif endif
ifeq ($(HAS_LIBRARY_sodium), yes)
ADDITIONAL_CPPFLAGS += -DHAVE_SODIUM=1 `pkg-config --cflags libsodium`
SOGo_LIBRARIES_DEPEND_UPON += -lsodium
endif
ifeq ($(findstring openbsd, $(GNUSTEP_HOST_OS)), openbsd) ifeq ($(findstring openbsd, $(GNUSTEP_HOST_OS)), openbsd)
SOGo_LIBRARIES_DEPEND_UPON += -lcrypto SOGo_LIBRARIES_DEPEND_UPON += -lcrypto
else else

View file

@ -58,6 +58,10 @@
- (NSData *) asCryptUsingSalt: (NSData *) theSalt; - (NSData *) asCryptUsingSalt: (NSData *) theSalt;
- (NSData *) asMD5CryptUsingSalt: (NSData *) theSalt; - (NSData *) asMD5CryptUsingSalt: (NSData *) theSalt;
- (NSData *) asBlowfishCryptUsingSalt: (NSData *) theSalt; - (NSData *) asBlowfishCryptUsingSalt: (NSData *) theSalt;
#ifdef HAVE_SODIUM
- (NSData *) asArgon2iUsingSalt: (NSData *) theSalt;
- (NSData *) asArgon2idUsingSalt: (NSData *) theSalt;
#endif /* HAVE_SODIUM */
- (NSData *) extractSalt: (NSString *) theScheme; - (NSData *) extractSalt: (NSString *) theScheme;

View file

@ -49,6 +49,10 @@
#error this module requires either gnutls or openssl #error this module requires either gnutls or openssl
#endif #endif
#ifdef HAVE_SODIUM
#include <sodium.h>
#endif
#include "aes.h" #include "aes.h"
#include "crypt_blowfish.h" #include "crypt_blowfish.h"
#include "lmhash.h" #include "lmhash.h"
@ -267,6 +271,18 @@ static const char salt_chars[] =
{ {
return [self asPBKDF2SHA1UsingSalt: theSalt]; return [self asPBKDF2SHA1UsingSalt: theSalt];
} }
#ifdef HAVE_SODIUM
else if ([passwordScheme caseInsensitiveCompare: @"argon2i"] == NSOrderedSame)
{
return [self asArgon2iUsingSalt: theSalt];
}
# ifdef crypto_pwhash_ALG_ARGON2ID13
else if ([passwordScheme caseInsensitiveCompare: @"argon2id"] == NSOrderedSame)
{
return [self asArgon2idUsingSalt: theSalt];
}
# endif /* crypto_pwhash_ALG_ARGON2ID13 */
#endif /* HAVE_SODIUM */
else if ([[passwordScheme lowercaseString] hasPrefix: @"sym"]) else if ([[passwordScheme lowercaseString] hasPrefix: @"sym"])
{ {
// We first support one sym cipher, AES-128-CBC. If something else is provided // We first support one sym cipher, AES-128-CBC. If something else is provided
@ -309,7 +325,7 @@ static const char salt_chars[] =
* clear text password using the passed encryption scheme * clear text password using the passed encryption scheme
* *
* @param passwordScheme The password scheme to use for comparison * @param passwordScheme The password scheme to use for comparison
* @param thePassword * @param thePassword cleartext key
*/ */
- (BOOL) verifyUsingScheme: (NSString *) passwordScheme - (BOOL) verifyUsingScheme: (NSString *) passwordScheme
withPassword: (NSData *) thePassword withPassword: (NSData *) thePassword
@ -321,6 +337,30 @@ static const char salt_chars[] =
salt = [self extractSalt: passwordScheme]; salt = [self extractSalt: passwordScheme];
if (salt == nil) if (salt == nil)
return NO; return NO;
#ifdef HAVE_SODIUM
// use verification function provided by libsodium
if ([passwordScheme caseInsensitiveCompare: @"argon2i"] == NSOrderedSame
#ifdef crypto_pwhash_ALG_ARGON2ID13
|| [passwordScheme caseInsensitiveCompare: @"argon2id"] == NSOrderedSame
#endif /* crypto_pwhash_ALG_ARGON2ID13 */
)
{
NSString *cryptString;
int result;
if (sodium_init() < 0)
return NO;
// For the sodium comparison we need to pass a null-terminated string
// as the first parameter
cryptString = [[NSString alloc] initWithData: self encoding: NSUTF8StringEncoding];
const char* pass = [thePassword bytes];
result = crypto_pwhash_str_verify([cryptString UTF8String], pass, [thePassword length]);
[cryptString release];
return result == 0;
}
#endif /* HAVE_SODIUM */
// encrypt self with the salt an compare the results // encrypt self with the salt an compare the results
passwordCrypted = [thePassword asCryptedPassUsingScheme: passwordScheme passwordCrypted = [thePassword asCryptedPassUsingScheme: passwordScheme
withSalt: salt withSalt: salt
@ -916,6 +956,43 @@ static const char salt_chars[] =
return [result dataUsingEncoding:NSUTF8StringEncoding]; return [result dataUsingEncoding:NSUTF8StringEncoding];
} }
#ifdef HAVE_SODIUM
- (NSData *) asArgon2iUsingSalt: (NSData *) theSalt
{
char hashed_password[crypto_pwhash_argon2i_STRBYTES];
int rounds = crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE;
size_t memlimit = crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE;
if (sodium_init() < 0)
return nil;
const char* password = [self bytes];
if (crypto_pwhash_argon2i_str(hashed_password, password, [self length], rounds, memlimit) != 0)
return nil;
return [NSData dataWithBytes: hashed_password length: strlen(hashed_password)];
}
# ifdef crypto_pwhash_ALG_ARGON2ID13
- (NSData *) asArgon2idUsingSalt: (NSData *) theSalt;
{
char hashed_password[crypto_pwhash_argon2id_STRBYTES];
int rounds = crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE;
size_t memlimit = crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE;
if (sodium_init() < 0)
return nil;
const char* password = [self bytes];
if (crypto_pwhash_argon2id_str(hashed_password, password, [self length], rounds, memlimit) != 0)
return nil;
return [NSData dataWithBytes: hashed_password length: strlen(hashed_password)];
}
#endif /* crypto_pwhash_ALG_ARGON2ID13 */
#endif /* HAVE_SODIUM */
/** /**
* Get the salt from a password encrypted with a specied scheme * Get the salt from a password encrypted with a specied scheme
* *

View file

@ -46,10 +46,14 @@ ADDITIONAL_LIB_DIRS += \
-Wl,-rpath,../../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo -Wl,-rpath,../../SOPE/NGCards/obj -Wl,-rpath,../../SOPE/GDLContentStore/obj -Wl,-rpath,../../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo -Wl,-rpath,../../SOPE/NGCards/obj -Wl,-rpath,../../SOPE/GDLContentStore/obj
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed ADDITIONAL_LDFLAGS += -Wl,--no-as-needed
ifeq ($(HAS_LIBRARY_sodium), yes)
ADDITIONAL_CPPFLAGS += -DHAVE_SODIUM=1 `pkg-config --cflags libsodium`
endif
-include GNUmakefile.preamble -include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/test-tool.make include $(GNUSTEP_MAKEFILES)/test-tool.make
-include GNUmakefile.postamble -include GNUmakefile.postamble
check :: $(TEST_TOOL) check :: $(TEST_TOOL)
./obj/sogo-tests ./obj/sogo-tests

View file

@ -112,4 +112,33 @@
test([pbkdf2_key isEqualToCrypted:pkbf2_result withDefaultScheme: @"PBKDF2" keyPath: nil]); test([pbkdf2_key isEqualToCrypted:pkbf2_result withDefaultScheme: @"PBKDF2" keyPath: nil]);
} }
#ifdef HAVE_SODIUM
- (void) test_argon2
{
NSString *error;
// well-known comparison
NSString *cleartext = @"123456";
NSString *hash = @"{ARGON2I}$argon2i$v=19$m=32768,t=4,p=1$HWg68rEbwmY6yrdByJ7U1g$z1c06BysT+51u1RXGtYIknTpA9jAHUfw1dAqPgTiQJ8";
NSString *prefix;
NSString *crypted_hash;
error = [NSString stringWithFormat:
@"string '%@' wrong ARGON2ID: '%@'",
cleartext, hash];
testWithMessage([cleartext isEqualToCrypted:hash withDefaultScheme: @"CRYPT" keyPath: nil], error);
// generate a new argon2id key
prefix = @"$argon2id$";
crypted_hash = [cleartext asCryptedPassUsingScheme: @"ARGON2ID" keyPath: nil];
fprintf(stdout, "hash = %s\n", [crypted_hash UTF8String]);
error = [NSString stringWithFormat:
@"returned hash '%@' has incorrect ARGON2ID prefix: '%@'",
crypted_hash, prefix];
testWithMessage([crypted_hash hasPrefix: prefix], error);
test([cleartext isEqualToCrypted:crypted_hash withDefaultScheme: @"ARGON2ID" keyPath: nil]);
}
#endif /* HAVE_SODUM */
@end @end

17
configure vendored
View file

@ -26,6 +26,7 @@ ARG_WITH_DEBUG=1
ARG_WITH_STRIP=0 ARG_WITH_STRIP=0
ARG_ENABLE_SAML2=0 ARG_ENABLE_SAML2=0
ARG_ENABLE_MFA=0 ARG_ENABLE_MFA=0
ARG_ENABLE_SODIUM=1
ARG_WITH_LDAP_CONFIG=0 ARG_WITH_LDAP_CONFIG=0
GNUSTEP_INSTALLATION_DOMAIN="LOCAL" GNUSTEP_INSTALLATION_DOMAIN="LOCAL"
@ -78,7 +79,7 @@ Installation directories:
--with-ssl=SSL specify ssl library (none, ssl, gnutls, auto) [auto] --with-ssl=SSL specify ssl library (none, ssl, gnutls, auto) [auto]
--enable-saml2 enable support for SAML2 authentication (requires liblasso) --enable-saml2 enable support for SAML2 authentication (requires liblasso)
--enable-mfa enable multi-factor authentication (requires liboath) --enable-mfa enable multi-factor authentication (requires liboath)
--disable-sodium disable building with libsodium (will disable argon2 password schemes)
--enable-ldap-config enable LDAP based configuration of SOGo --enable-ldap-config enable LDAP based configuration of SOGo
_ACEOF _ACEOF
@ -113,6 +114,11 @@ printParas() {
else else
echo " mfa support: no"; echo " mfa support: no";
fi fi
if test $ARG_ENABLE_SODIUM = 1; then
echo " argon2 support: yes";
else
echo " argon2 support: no";
fi
if test $ARG_WITH_LDAP_CONFIG = 1; then if test $ARG_WITH_LDAP_CONFIG = 1; then
echo " ldap-based configuration: yes"; echo " ldap-based configuration: yes";
else else
@ -407,6 +413,9 @@ checkDependencies() {
cfgwrite "MFA_LIBS := -loath" cfgwrite "MFA_LIBS := -loath"
fi; fi;
fi fi
if test "x$ARG_ENABLE_SODIUM" = "x1"; then
checkLinking "sodium" required;
fi
if test "x$ARG_CFGSSL" = "xauto"; then if test "x$ARG_CFGSSL" = "xauto"; then
checkLinking "ssl" optional; checkLinking "ssl" optional;
if test $? != 0; then if test $? != 0; then
@ -501,6 +510,12 @@ processOption() {
"x--enable-mfa") "x--enable-mfa")
ARG_ENABLE_MFA=1 ARG_ENABLE_MFA=1
;; ;;
"x--enable-sodium")
ARG_ENABLE_SODIUM=1
;;
"x--disable-sodium")
ARG_ENABLE_SODIUM=0
;;
"x--enable-ldap-config") "x--enable-ldap-config")
ARG_WITH_LDAP_CONFIG=1 ARG_WITH_LDAP_CONFIG=1
;; ;;

View file

@ -1,7 +1,7 @@
Source: sogo Source: sogo
Priority: optional Priority: optional
Maintainer: Inverse Support <support@inverse.ca> Maintainer: Inverse Support <support@inverse.ca>
Build-Depends: debhelper (>= 8.0.0), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5), libzip-dev Build-Depends: debhelper (>= 8.0.0), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5), libzip-dev, libsodium-dev (>= 1.0.9) | base-files (<< 9.4ubuntu4~)
Section: web Section: web
Standards-Version: 3.9.2 Standards-Version: 3.9.2

View file

@ -7,22 +7,53 @@ DESTDIR=$(CURDIR)/debian/tmp
DIST_CODENAME=$(shell lsb_release -cs) DIST_CODENAME=$(shell lsb_release -cs)
SAML2_CONFIG=--enable-saml2 SAML2_CONFIG=--enable-saml2
# Debian 6
ifeq ($(DIST_CODENAME), squeeze)
SODIUM_CONFIG=--disable-sodium
endif
# Debian 7
ifeq ($(DIST_CODENAME), wheezy)
SODIUM_CONFIG=--disable-sodium
endif
# Debian 8
ifeq ($(DIST_CODENAME), jessie)
SODIUM_CONFIG=--disable-sodium
endif
# Debian 9
ifeq ($(DIST_CODENAME), stretch) ifeq ($(DIST_CODENAME), stretch)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
# Debian 10
ifeq ($(DIST_CODENAME), buster) ifeq ($(DIST_CODENAME), buster)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
ifeq ($(DIST_CODENAME), xenial) # Ubuntu 12.04
MFA_CONFIG=--enable-mfa ifeq ($(DIST_CODENAME), precise)
SODIUM_CONFIG=--disable-sodium
endif endif
# Ubuntu 14.04
ifeq ($(DIST_CODENAME), trusty)
SODIUM_CONFIG=--disable-sodium
endif
# Ubuntu 16.04
ifeq ($(DIST_CODENAME), xenial)
MFA_CONFIG=--enable-mfa
SODIUM_CONFIG=--disable-sodium
endif
# Ubuntu 18.04
ifeq ($(DIST_CODENAME), bionic) ifeq ($(DIST_CODENAME), bionic)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
# Ubuntu 20.04
ifeq ($(DIST_CODENAME), focal) ifeq ($(DIST_CODENAME), focal)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
@ -32,7 +63,7 @@ include /usr/share/GNUstep/Makefiles/common.make
config.make: configure config.make: configure
dh_testdir dh_testdir
./configure $(SAML2_CONFIG) $(MFA_CONFIG) ./configure $(SAML2_CONFIG) $(MFA_CONFIG) $(SODIUM_CONFIG)
#Architecture #Architecture
build: build-arch build: build-arch

View file

@ -1,7 +1,7 @@
Source: sogo Source: sogo
Priority: optional Priority: optional
Maintainer: Inverse Support <support@inverse.ca> Maintainer: Inverse Support <support@inverse.ca>
Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5), libzip-dev Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5), libzip-dev, libsodium-dev (>= 1.0.9) | base-files (<< 9.4ubuntu4~)
Section: web Section: web
Standards-Version: 3.9.1 Standards-Version: 3.9.1

View file

@ -6,26 +6,54 @@ export DH_VERBOSE=1
DESTDIR=$(CURDIR)/debian/tmp DESTDIR=$(CURDIR)/debian/tmp
DIST_CODENAME=$(shell lsb_release -cs) DIST_CODENAME=$(shell lsb_release -cs)
# Debian 6
ifeq ($(DIST_CODENAME), squeeze) ifeq ($(DIST_CODENAME), squeeze)
SAML2_CONFIG=--enable-saml2 SAML2_CONFIG=--enable-saml2
SODIUM_CONFIG=--disable-sodium
endif endif
# Debian 7
ifeq ($(DIST_CODENAME), wheezy)
SODIUM_CONFIG=--disable-sodium
endif
# Debian 8
ifeq ($(DIST_CODENAME), jessie)
SODIUM_CONFIG=--disable-sodium
endif
# Debian 9
ifeq ($(DIST_CODENAME), stretch) ifeq ($(DIST_CODENAME), stretch)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
# Debian 10
ifeq ($(DIST_CODENAME), buster) ifeq ($(DIST_CODENAME), buster)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
ifeq ($(DIST_CODENAME), xenial) # Ubuntu 12.04
MFA_CONFIG=--enable-mfa ifeq ($(DIST_CODENAME), precise)
SODIUM_CONFIG=--disable-sodium
endif endif
# Ubuntu 14.04
ifeq ($(DIST_CODENAME), trusty)
SODIUM_CONFIG=--disable-sodium
endif
# Ubuntu 16.04
ifeq ($(DIST_CODENAME), xenial)
MFA_CONFIG=--enable-mfa
SODIUM_CONFIG=--disable-sodium
endif
# Ubuntu 18.04
ifeq ($(DIST_CODENAME), bionic) ifeq ($(DIST_CODENAME), bionic)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
# Ubuntu 20.04
ifeq ($(DIST_CODENAME), focal) ifeq ($(DIST_CODENAME), focal)
MFA_CONFIG=--enable-mfa MFA_CONFIG=--enable-mfa
endif endif
@ -35,7 +63,7 @@ include /usr/share/GNUstep/Makefiles/common.make
config.make: configure config.make: configure
dh_testdir dh_testdir
./configure $(SAML2_CONFIG) $(MFA_CONFIG) ./configure $(SAML2_CONFIG) $(MFA_CONFIG) $(SODIUM_CONFIG)
#Architecture #Architecture
build: build-arch build: build-arch

View file

@ -49,6 +49,14 @@ BuildRequires: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{so
%{?el8:Requires: liboath} %{?el8:Requires: liboath}
%{?el8:BuildRequires: liboath-devel} %{?el8:BuildRequires: liboath-devel}
%if 0%{?rhel} >= 7
Requires: libsodium
BuildRequires: libsodium-devel
%define sodium_cfg_opts "--enable-sodium"
%else
%define sodium_cfg_opts "--disable-sodium"
%endif
%description %description
SOGo is a groupware server built around OpenGroupware.org (OGo) and SOGo is a groupware server built around OpenGroupware.org (OGo) and
the SOPE application server. It focuses on scalability. the SOPE application server. It focuses on scalability.
@ -164,7 +172,7 @@ rm -fr ${RPM_BUILD_ROOT}
%else %else
. /usr/share/GNUstep/Makefiles/GNUstep.sh . /usr/share/GNUstep/Makefiles/GNUstep.sh
%endif %endif
./configure %saml2_cfg_opts %mfa_cfg_opts ./configure %saml2_cfg_opts %mfa_cfg_opts %sodium_cfg_opts
case %{_target_platform} in case %{_target_platform} in
ppc64-*) ppc64-*)