diff options
Diffstat (limited to 'contrib/slapd-modules/passwd')
20 files changed, 3981 insertions, 0 deletions
diff --git a/contrib/slapd-modules/passwd/Makefile b/contrib/slapd-modules/passwd/Makefile new file mode 100644 index 0000000..b4f2b93 --- /dev/null +++ b/contrib/slapd-modules/passwd/Makefile @@ -0,0 +1,58 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = pw-kerberos.la pw-netscape.la pw-radius.la pw-apr1.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-kerberos.la: kerberos.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? -lkrb5 + +pw-netscape.la: netscape.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? + +pw-radius.la: radius.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? -lradius + +pw-apr1.la: apr1.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/passwd/README b/contrib/slapd-modules/passwd/README new file mode 100644 index 0000000..aff7c85 --- /dev/null +++ b/contrib/slapd-modules/passwd/README @@ -0,0 +1,69 @@ +This directory contains native slapd plugins for password mechanisms that +are not actively supported by the project. Currently this includes the +Kerberos, Netscape MTA-MD5 and RADIUS password mechanisms. The Apache +APR1 MD5 and BSD/Paul Henning Kamp MD5 mechanisms are also included. + +To use the Kerberos plugin, add: + +moduleload pw-kerberos.so + +to your slapd configuration file. + +To use the Netscape plugin, add: + +moduleload pw-netscape.so + +to your slapd configuration file. + +To use the APR1/BSD/MD5 plugin, add: + +moduleload pw-apr1.so + +to your slapd configuration file. + +To use the RADIUS plugin, add: + +moduleload pw-radius.so + +to your slapd configuration file; optionally, the path to a configuration +file can be appended in the form + +moduleload pw-radius.so config="/etc/radius.conf" + +Use Makefile to compile this plugin or use a command line similar to: + +gcc -shared -I../../../include -Wall -g -DHAVE_KRB5 -o pw-kerberos.so kerberos.c + +Replace HAVE_KRB5 with HAVE_KRB4 if you want to use Kerberos IV. +If your Kerberos header files are not in the C compiler's +default path, you will need to add a "-I" directive for that as well. + +The corresponding command for the Netscape plugin would be: + +gcc -shared -I../../../include -Wall -g -o pw-netscape.so netscape.c + +The corresponding command for the RADIUS plugin would be: + +gcc -shared -I../../../include -Wall -g -o pw-radius.so radius.c -lradius + +(Actually, you might want to statically link the RADIUS client library +libradius.a into the module). + +The corresponding command for the APR1 plugin would be: + +gcc -shared -I../../../include -Wall -g -o pw-apr1.so apr1.c + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2004-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + diff --git a/contrib/slapd-modules/passwd/apr1-atol.pl b/contrib/slapd-modules/passwd/apr1-atol.pl new file mode 100644 index 0000000..d6eaee7 --- /dev/null +++ b/contrib/slapd-modules/passwd/apr1-atol.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w
+
+# Apache $apr1$ to OpenLDAP {APR1} hash converter
+# (C) 2011 Devin J. Pohly
+# You may use this code freely. It would be nice to be credited.
+
+use MIME::Base64;
+
+while (<>) {
+ ($user, $hash) = split(/:/, $_);
+ unless ($hash =~ /^\$apr1\$/) {
+ print STDERR "Not an Apache MD5 hash\n";
+ exit 1;
+ }
+
+ chomp $hash;
+ ($_,$_,$salt,$hash) = split(/\$/, $hash);
+
+ $hash =~ tr|./0-9A-Za-z|A-Za-z0-9+/|;
+ $hash .= "AA";
+ $hash =~ s/(.)(.)(.)(.)/$4$3$2$1/gs;
+ $hash = decode_base64($hash);
+ $hash =~ s/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)..(.)/$1$4$7$10$13$15$2$5$8$11$14$16$3$6$9$12/s;
+ $hash .= $salt;
+ $hash = encode_base64($hash);
+ chop $hash;
+
+ print "$user:{APR1}$hash\n";
+}
\ No newline at end of file diff --git a/contrib/slapd-modules/passwd/apr1-ltoa.pl b/contrib/slapd-modules/passwd/apr1-ltoa.pl new file mode 100644 index 0000000..ee628ec --- /dev/null +++ b/contrib/slapd-modules/passwd/apr1-ltoa.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl -w
+
+# OpenLDAP {APR1} to Apache $apr1$ hash converter
+# (C) 2011 Devin J. Pohly
+# You may use this code freely. It would be nice to be credited.
+
+use MIME::Base64;
+
+while (<>) {
+ ($user, $hash) = split(/:/, $_);
+ unless ($hash =~ /^{APR1}/) {
+ print STDERR "Not an Apache MD5 hash\n";
+ next;
+ }
+
+ chomp $hash;
+ $hash = decode_base64(substr($hash, 6));
+ ($hash, $salt) = (substr($hash, 0, 16), substr($hash, 16));
+ $hash = $hash;
+ $hash =~ s/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)/$1$7$13$2$8$14$3$9$15$4$10$16$5$11$6\0\0$12/s;
+ $hash = encode_base64($hash);
+ chomp $hash;
+ $hash =~ s/(.)(.)(.)(.)/$4$3$2$1/gs;
+ unless ($hash =~ /AA$/) {
+ #print "Problem with hash\n";
+ next;
+ }
+ $hash =~ s/AA$//;
+ $hash =~ tr|A-Za-z0-9+/|./0-9A-Za-z|;
+ print "$user:\$apr1\$$salt\$$hash\n"
+}
\ No newline at end of file diff --git a/contrib/slapd-modules/passwd/apr1.c b/contrib/slapd-modules/passwd/apr1.c new file mode 100644 index 0000000..0ddb01b --- /dev/null +++ b/contrib/slapd-modules/passwd/apr1.c @@ -0,0 +1,233 @@ +/* $OpenLDAP$ */ +/* + * This file is derived from OpenLDAP Software. All of the modifications to + * OpenLDAP Software represented in the following file were developed by + * Devin J. Pohly <djpohly@gmail.com>. I have not assigned rights and/or + * interest in this work to any party. + * + * The extensions to OpenLDAP Software herein are subject to the following + * notice: + * + * Copyright 2011 Devin J. Pohly + * Portions Copyright 2011 Howard Chu + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP Public + * License. + * + * A portion of this code is used in accordance with the Beer-ware License, + * revision 42, as noted. + * + */ +#include <lber.h> +#include <lber_pvt.h> +#include "lutil.h" +#include "lutil_md5.h" +#include <ac/string.h> + +#include <assert.h> + +/* the only difference between this and straight PHK is the magic */ +static LUTIL_PASSWD_CHK_FUNC chk_apr1; +static LUTIL_PASSWD_HASH_FUNC hash_apr1; +static const struct berval scheme_apr1 = BER_BVC("{APR1}"); +static const struct berval magic_apr1 = BER_BVC("$apr1$"); + +static LUTIL_PASSWD_CHK_FUNC chk_bsdmd5; +static LUTIL_PASSWD_HASH_FUNC hash_bsdmd5; +static const struct berval scheme_bsdmd5 = BER_BVC("{BSDMD5}"); +static const struct berval magic_bsdmd5 = BER_BVC("$1$"); + +static const unsigned char apr64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +#define APR_SALT_SIZE 8 + +/* The algorithm implemented in this function was created by Poul-Henning + * Kamp and released under the following license: + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ +static void do_phk_hash( + const struct berval *passwd, + const struct berval *salt, + const struct berval *magic, + unsigned char *digest) +{ + lutil_MD5_CTX ctx, ctx1; + int n; + + /* Start hashing */ + lutil_MD5Init(&ctx); + lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Update(&ctx, (const unsigned char *) magic->bv_val, magic->bv_len); + lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len); + /* Inner hash */ + lutil_MD5Init(&ctx1); + lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len); + lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Final(digest, &ctx1); + /* Nom start mixing things up */ + for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES) + lutil_MD5Update(&ctx, digest, + (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n)); + memset(digest, 0, LUTIL_MD5_BYTES); + /* Curiouser and curiouser... */ + for (n = passwd->bv_len; n; n >>= 1) + if (n & 1) + lutil_MD5Update(&ctx, digest, 1); + else + lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1); + lutil_MD5Final(digest, &ctx); + /* + * Repeatedly hash things into the final value. This was originally + * intended to slow the algorithm down. + */ + for (n = 0; n < 1000; n++) { + lutil_MD5Init(&ctx1); + if (n & 1) + lutil_MD5Update(&ctx1, + (const unsigned char *) passwd->bv_val, passwd->bv_len); + else + lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); + + if (n % 3) + lutil_MD5Update(&ctx1, + (const unsigned char *) salt->bv_val, salt->bv_len); + if (n % 7) + lutil_MD5Update(&ctx1, + (const unsigned char *) passwd->bv_val, passwd->bv_len); + + if (n & 1) + lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); + else + lutil_MD5Update(&ctx1, + (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Final(digest, &ctx1); + } +} + +static int chk_phk( + const struct berval *magic, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + unsigned char digest[LUTIL_MD5_BYTES]; + unsigned char *orig_pass; + int rc; + struct berval salt; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(digest)) + return LUTIL_PASSWD_ERR; + + /* base64 un-encode password hash */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if (orig_pass == NULL) + return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if (rc <= (int) sizeof(digest)) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + salt.bv_val = (char *) &orig_pass[sizeof(digest)]; + salt.bv_len = rc - sizeof(digest); + + do_phk_hash(cred, &salt, magic, digest); + + if (text) + *text = NULL; + + /* compare */ + rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_apr1( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + return chk_phk(&magic_apr1, passwd, cred, text); +} + +static int chk_bsdmd5( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + return chk_phk(&magic_bsdmd5, passwd, cred, text); +} + +static int hash_phk( + const struct berval *scheme, + const struct berval *magic, + const struct berval *passwd, + struct berval *hash, + const char **text) +{ + unsigned char digest_buf[LUTIL_MD5_BYTES]; + char salt_buf[APR_SALT_SIZE]; + struct berval digest; + struct berval salt; + int n; + + digest.bv_val = (char *) digest_buf; + digest.bv_len = sizeof(digest_buf); + salt.bv_val = salt_buf; + salt.bv_len = APR_SALT_SIZE; + + /* generate random salt */ + if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0) + return LUTIL_PASSWD_ERR; + /* limit it to characters in the 64-char set */ + for (n = 0; n < salt.bv_len; n++) + salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)]; + + do_phk_hash(passwd, &salt, magic, digest_buf); + + if (text) + *text = NULL; + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_apr1( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text) +{ + return hash_phk(scheme, &magic_apr1, passwd, hash, text); +} + +static int hash_bsdmd5( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text) +{ + return hash_phk(scheme, &magic_bsdmd5, passwd, hash, text); +} + +int init_module(int argc, char *argv[]) { + int rc; + rc = lutil_passwd_add((struct berval *) &scheme_apr1, chk_apr1, hash_apr1); + if ( !rc ) + rc = lutil_passwd_add((struct berval *) &scheme_bsdmd5, + chk_bsdmd5, hash_bsdmd5); + return rc; +} diff --git a/contrib/slapd-modules/passwd/argon2/Makefile b/contrib/slapd-modules/passwd/argon2/Makefile new file mode 100644 index 0000000..0294ba0 --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/Makefile @@ -0,0 +1,70 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../../.. +LDAP_BUILD = ../../../.. +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +INSTALL = /usr/bin/install +CC = gcc +OPT = -g -O2 -Wall +#DEFS = -DSLAPD_ARGON2_DEBUG + +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +implementation = sodium + +ifeq ($(implementation),argon2) +LIBS += -largon2 +DEFS += -DSLAPD_ARGON2_USE_ARGON2 +else ifeq ($(implementation),sodium) +LIBS += -lsodium +DEFS += -DSLAPD_ARGON2_USE_SODIUM +else +$(error Unsupported implementation $(implementation)) +endif + +PROGRAMS = pw-argon2.la +MANPAGES = slapd-pw-argon2.5 +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) +mandir = $(exec_prefix)/share/man +man5dir = $(mandir)/man5 + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-argon2.la: pw-argon2.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: install-lib install-man FORCE + +install-lib: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + +install-man: $(MANPAGES) + mkdir -p $(DESTDIR)$(man5dir) + $(INSTALL) -m 644 $(MANPAGES) $(DESTDIR)$(man5dir) + +FORCE: diff --git a/contrib/slapd-modules/passwd/argon2/README b/contrib/slapd-modules/passwd/argon2/README new file mode 100644 index 0000000..13ba69f --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/README @@ -0,0 +1,109 @@ +Argon2 OpenLDAP support +---------------------- + +pw-argon2.c provides support for ARGON2 hashed passwords in OpenLDAP. For +instance, one could have the LDAP attribute: + +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$DKlexoEJUoZTmkAAC3SaMWk30El9/RvVhlqGo6afIng + +or: + +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$qOCkx9nMeFlaGOO4DUmPDgrlUbgMMuO9T1+vQCFuyzw + +Both hash the password "secret", the first using the salt "saltsalt", the second using the salt "saltsaltsalt" + +Building +-------- + +1) Customize the OPENLDAP variable in Makefile to point to the OpenLDAP +source root. + +For initial testing you might also want to edit DEFS to define +SLAPD_ARGON2_DEBUG, which enables logging to stderr (don't leave this on +in production, as it prints passwords in cleartext). + +2) Run 'make' to produce pw-argon2.so + +3) Copy pw-argon2.so somewhere permanent. + +4) Edit your slapd.conf (eg. /etc/ldap/slapd.conf), and add: + +moduleload ...path/to/pw-argon2.so + +5) Restart slapd. + + +Configuring +----------- + +The {ARGON2} password scheme should now be recognised. + +You can also tell OpenLDAP to use one of this scheme when processing LDAP +Password Modify Extended Operations, thanks to the password-hash option in +slapd.conf: + +password-hash {ARGON2} + + +Testing +------- + +A quick way to test whether it's working is to customize the rootdn and +rootpw in slapd.conf, eg: + +rootdn "cn=admin,dc=example,dc=com" + +# This hashes the string 'secret', with a random salt +rootpw {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$uJyf0UfB25SQTfX7oCyK2w$U45DJqEFwD0yFaLvTVyACHLvGMwzNGf19dvzPR8XvGc + + +Then to test, run something like: + +ldapsearch -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -x -w secret + + +-- Test hashes: + +Test hashes can be generated with argon2: +$ echo -n "secret" | argon2 "saltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$DKlexoEJUoZTmkAAC3SaMWk30El9/RvVhlqGo6afIng + +$ echo -n "secret" | argon2 "saltsaltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$qOCkx9nMeFlaGOO4DUmPDgrlUbgMMuO9T1+vQCFuyzw + +$ echo -n "secretsecret" | argon2 "saltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$U0Pd/wEsssZ9bHezDA8oxHnWe01xftykEy+7ehM2vic + +$ echo -n "secretsecret" | argon2 "saltsaltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$fkvoOwKgVtlX9ZDqcHFyyArBvqnAM0Igca8SScB4Jsc + + + +Alternatively we could modify an existing user's password with +ldappasswd, and then test binding as that user: + +$ ldappasswd -D "cn=admin,dc=example,dc=com" -x -W -S uid=jturner,ou=People,dc=example,dc=com +New password: secret +Re-enter new password: secret +Enter LDAP Password: <cn=admin's password> + +$ ldapsearch -b "dc=example,dc=com" -D "uid=jturner,ou=People,dc=example,dc=com" -x -w secret + + + +--- + +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2017-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + +--- diff --git a/contrib/slapd-modules/passwd/argon2/pw-argon2.c b/contrib/slapd-modules/passwd/argon2/pw-argon2.c new file mode 100644 index 0000000..94c9e46 --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/pw-argon2.c @@ -0,0 +1,220 @@ +/* pw-argon2.c - Password module for argon2 */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2017-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include "portable.h" +#include "ac/string.h" +#include "lber_pvt.h" +#include "lutil.h" + +#include <stdint.h> +#include <stdlib.h> + +#ifdef SLAPD_ARGON2_USE_ARGON2 +#include <argon2.h> + +/* + * For now, we hardcode the default values from the argon2 command line tool + * (as of argon2 release 20161029) + */ +#define SLAPD_ARGON2_ITERATIONS 3 +#define SLAPD_ARGON2_MEMORY (1 << 12) +#define SLAPD_ARGON2_PARALLELISM 1 +#define SLAPD_ARGON2_SALT_LENGTH 16 +#define SLAPD_ARGON2_HASH_LENGTH 32 + +#else /* !SLAPD_ARGON2_USE_ARGON2 */ +#include <sodium.h> + +/* + * Or libsodium interactive settings + */ +#define SLAPD_ARGON2_ITERATIONS crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE +#define SLAPD_ARGON2_MEMORY (crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE / 1024) +#define SLAPD_ARGON2_PARALLELISM 1 +#define SLAPD_ARGON2_SALT_LENGTH crypto_pwhash_argon2id_SALTBYTES +#define SLAPD_ARGON2_HASH_LENGTH 32 + +#endif + +static unsigned long iterations = SLAPD_ARGON2_ITERATIONS; +static unsigned long memory = SLAPD_ARGON2_MEMORY; +static unsigned long parallelism = SLAPD_ARGON2_PARALLELISM; + +const struct berval slapd_argon2_scheme = BER_BVC("{ARGON2}"); + +static int +slapd_argon2_hash( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + + /* + * Duplicate these values here so future code which allows + * configuration has an easier time. + */ + uint32_t salt_length, hash_length; + char *p; + int rc = LUTIL_PASSWD_ERR; + +#ifdef SLAPD_ARGON2_USE_ARGON2 + struct berval salt; + size_t encoded_length; + + salt_length = SLAPD_ARGON2_SALT_LENGTH; + hash_length = SLAPD_ARGON2_HASH_LENGTH; + + encoded_length = argon2_encodedlen( iterations, memory, parallelism, + salt_length, hash_length, Argon2_id ); + + salt.bv_len = salt_length; + salt.bv_val = ber_memalloc( salt.bv_len ); + + if ( salt.bv_val == NULL ) { + return LUTIL_PASSWD_ERR; + } + + if ( lutil_entropy( (unsigned char*)salt.bv_val, salt.bv_len ) ) { + ber_memfree( salt.bv_val ); + return LUTIL_PASSWD_ERR; + } + + p = hash->bv_val = ber_memalloc( scheme->bv_len + encoded_length ); + if ( p == NULL ) { + ber_memfree( salt.bv_val ); + return LUTIL_PASSWD_ERR; + } + + AC_MEMCPY( p, scheme->bv_val, scheme->bv_len ); + p += scheme->bv_len; + + /* + * Do the actual heavy lifting + */ + if ( argon2i_hash_encoded( iterations, memory, parallelism, + passwd->bv_val, passwd->bv_len, + salt.bv_val, salt_length, hash_length, + p, encoded_length ) == 0 ) { + rc = LUTIL_PASSWD_OK; + } + hash->bv_len = scheme->bv_len + encoded_length; + ber_memfree( salt.bv_val ); + +#else /* !SLAPD_ARGON2_USE_ARGON2 */ + /* Not exposed by libsodium + salt_length = SLAPD_ARGON2_SALT_LENGTH; + hash_length = SLAPD_ARGON2_HASH_LENGTH; + */ + + p = hash->bv_val = ber_memalloc( scheme->bv_len + crypto_pwhash_STRBYTES ); + if ( p == NULL ) { + return LUTIL_PASSWD_ERR; + } + + AC_MEMCPY( hash->bv_val, scheme->bv_val, scheme->bv_len ); + p += scheme->bv_len; + + if ( crypto_pwhash_str_alg( p, passwd->bv_val, passwd->bv_len, + iterations, memory * 1024, + crypto_pwhash_ALG_ARGON2ID13 ) == 0 ) { + hash->bv_len = strlen( hash->bv_val ); + rc = LUTIL_PASSWD_OK; + } +#endif + + if ( rc ) { + ber_memfree( hash->bv_val ); + return LUTIL_PASSWD_ERR; + } + + return LUTIL_PASSWD_OK; +} + +static int +slapd_argon2_verify( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text ) +{ + int rc = LUTIL_PASSWD_ERR; + +#ifdef SLAPD_ARGON2_USE_ARGON2 + if ( strncmp( passwd->bv_val, "$argon2i$", STRLENOF("$argon2i$") ) == 0 ) { + rc = argon2i_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); + } else if ( strncmp( passwd->bv_val, "$argon2d$", STRLENOF("$argon2d$") ) == 0 ) { + rc = argon2d_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); + } else if ( strncmp( passwd->bv_val, "$argon2id$", STRLENOF("$argon2id$") ) == 0 ) { + rc = argon2id_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); + } +#else /* !SLAPD_ARGON2_USE_ARGON2 */ + rc = crypto_pwhash_str_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); +#endif + + if ( rc ) { + return LUTIL_PASSWD_ERR; + } + return LUTIL_PASSWD_OK; +} + +int init_module( int argc, char *argv[] ) +{ + int i; + +#ifndef SLAPD_ARGON2_USE_ARGON2 + if ( sodium_init() == -1 ) { + return -1; + } +#endif + + for ( i=0; i < argc; i++ ) { + char *p; + unsigned long value; + + switch ( *argv[i] ) { + case 'm': + p = strchr( argv[i], '=' ); + if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { + return -1; + } + memory = value; + break; + + case 't': + p = strchr( argv[i], '=' ); + if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { + return -1; + } + iterations = value; + break; + + case 'p': + p = strchr( argv[i], '=' ); + if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { + return -1; + } + parallelism = value; + break; + + default: + return -1; + } + } + + return lutil_passwd_add( (struct berval *)&slapd_argon2_scheme, + slapd_argon2_verify, slapd_argon2_hash ); +} diff --git a/contrib/slapd-modules/passwd/argon2/slapd-pw-argon2.5 b/contrib/slapd-modules/passwd/argon2/slapd-pw-argon2.5 new file mode 100644 index 0000000..23cc87a --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/slapd-pw-argon2.5 @@ -0,0 +1,122 @@ +.TH SLAPD-PW-ARGON2 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2020-2021 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ +.SH NAME +slapd-pw-argon2 \- Argon2 password module to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.RS +.LP +.B moduleload pw-argon2 +.RI [ <parameters> ] +.RE +.SH DESCRIPTION +.LP +The +.B pw-argon2 +module to +.BR slapd (8) +provides support for the use of the key derivation function Argon2, +that was selected as the winner of the Password Hashing Competition in July 2015, +in hashed passwords in OpenLDAP. +.LP +It does so by providing the additional password scheme +.B {ARGON2} +for use in slapd. + +.SH CONFIGURATION +The +.B pw-argon2 +module does not need any configuration, +but it can be configured by giving the following parameters: +.TP +.BI m= <memory> +Set memory usage to +.I <memory> +kiB. +.TP +.BI p= <parallelism> +Set parallelism to +.I <parallelism> +threads. +.TP +.BI t= <iterations> +Set the number of iterations to +.IR <iterations> . +.LP +These replace defaults when preparing hashes for new passwords where possible. +.LP +After loading the module, the password scheme +.B {ARGON2} +will be recognised in values of the +.I userPassword +attribute. +.LP +You can then instruct OpenLDAP to use this scheme when processing +the LDAPv3 Password Modify (RFC 3062) extended operations by using the +.BR password-hash +option in +.BR slapd.conf (5): +.RS +.LP +.B password\-hash {ARGON2} +.RE +.LP + +.SS NOTES +If you want to use the scheme described here with +.BR slappasswd (8), +remember to load the module using its command line options. +The relevant option/value is: +.RS +.LP +.B \-o +.BR module\-load = pw-argon2 +.LP +.RE +Depending on +.BR pw-argon2 's +location, you may also need: +.RS +.LP +.B \-o +.BR module\-path = \fIpathspec\fP +.RE + +.SH EXAMPLES +Both userPassword LDAP attributes below encode the password +.RI ' secret ' +using different salts: +.EX +.LP +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$DKlexoEJUoZTmkAAC3SaMWk30El9/RvVhlqGo6afIng +.LP +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$qOCkx9nMeFlaGOO4DUmPDgrlUbgMMuO9T1+vQCFuyzw +.EE + +.SH SEE ALSO +.BR slapd.conf (5), +.BR ldappasswd (1), +.BR slappasswd (8), +.BR ldap (3), +.LP +.UR http://www.OpenLDAP.org/doc/ +"OpenLDAP Administrator's Guide" +.UE +.LP + +.SH ACKNOWLEDGEMENTS +This manual page has been written by Peter Marschall based on the +module's README file written by +.MT simon@levermann.de +Simon Levermann +.ME . +.LP +.B OpenLDAP +is developed and maintained by +.UR http://www.openldap.org/ +The OpenLDAP Project +.UE . +.B OpenLDAP +is derived from University of Michigan LDAP 3.3 Release. diff --git a/contrib/slapd-modules/passwd/kerberos.c b/contrib/slapd-modules/passwd/kerberos.c new file mode 100644 index 0000000..eecf00a --- /dev/null +++ b/contrib/slapd-modules/passwd/kerberos.c @@ -0,0 +1,209 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <unistd.h> + +#include <lber.h> +#include <lber_pvt.h> /* BER_BVC definition */ +#include "lutil.h" +#include <ac/string.h> + +#ifdef HAVE_KRB5 +#include <krb5.h> +#elif defined(HAVE_KRB4) +#include <krb.h> +#endif + +/* From <ldap_pvt.h> */ +LDAP_F( char *) ldap_pvt_get_fqdn LDAP_P(( char * )); + +static LUTIL_PASSWD_CHK_FUNC chk_kerberos; +static const struct berval scheme = BER_BVC("{KERBEROS}"); + +static int chk_kerberos( + const struct berval *sc, + const struct berval * passwd, + const struct berval * cred, + const char **text ) +{ + unsigned int i; + int rtn; + + for( i=0; i<cred->bv_len; i++) { + if(cred->bv_val[i] == '\0') { + return LUTIL_PASSWD_ERR; /* NUL character in password */ + } + } + + if( cred->bv_val[i] != '\0' ) { + return LUTIL_PASSWD_ERR; /* cred must behave like a string */ + } + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return LUTIL_PASSWD_ERR; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ + } + + rtn = LUTIL_PASSWD_ERR; + +#ifdef HAVE_KRB5 /* HAVE_HEIMDAL_KRB5 */ + { +/* Portions: + * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H\xf6gskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + krb5_context context; + krb5_error_code ret; + krb5_creds creds; + krb5_get_init_creds_opt get_options; + krb5_verify_init_creds_opt verify_options; + krb5_principal client, server; +#ifdef notdef + krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; +#endif + + ret = krb5_init_context( &context ); + if (ret) { + return LUTIL_PASSWD_ERR; + } + +#ifdef notdef + krb5_get_init_creds_opt_set_preauth_list(&get_options, + pre_auth_types, 1); +#endif + + krb5_get_init_creds_opt_init( &get_options ); + + krb5_verify_init_creds_opt_init( &verify_options ); + + ret = krb5_parse_name( context, passwd->bv_val, &client ); + + if (ret) { + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + ret = krb5_get_init_creds_password( context, + &creds, client, cred->bv_val, NULL, + NULL, 0, NULL, &get_options ); + + if (ret) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + { + char *host = ldap_pvt_get_fqdn( NULL ); + + if( host == NULL ) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + ret = krb5_sname_to_principal( context, + host, "ldap", KRB5_NT_SRV_HST, &server ); + + ber_memfree( host ); + } + + if (ret) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + ret = krb5_verify_init_creds( context, + &creds, server, NULL, NULL, &verify_options ); + + krb5_free_principal( context, client ); + krb5_free_principal( context, server ); + krb5_free_cred_contents( context, &creds ); + krb5_free_context( context ); + + rtn = ret ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; + } +#elif defined(HAVE_KRB4) + { + /* Borrowed from Heimdal kpopper */ +/* Portions: + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + + int status; + char lrealm[REALM_SZ]; + char tkt[MAXHOSTNAMELEN]; + + status = krb_get_lrealm(lrealm,1); + if (status == KFAILURE) { + return LUTIL_PASSWD_ERR; + } + + snprintf(tkt, sizeof(tkt), "%s_slapd.%u", + TKT_ROOT, (unsigned)getpid()); + krb_set_tkt_string (tkt); + + status = krb_verify_user( passwd->bv_val, "", lrealm, + cred->bv_val, 1, "ldap"); + + dest_tkt(); /* no point in keeping the tickets */ + + return status == KFAILURE ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; + } +#endif + + return rtn; +} + +int init_module(int argc, char *argv[]) { + return lutil_passwd_add( (struct berval *)&scheme, chk_kerberos, NULL ); +} diff --git a/contrib/slapd-modules/passwd/netscape.c b/contrib/slapd-modules/passwd/netscape.c new file mode 100644 index 0000000..0551fe6 --- /dev/null +++ b/contrib/slapd-modules/passwd/netscape.c @@ -0,0 +1,81 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <unistd.h> + +#include <lber.h> +#include <lber_pvt.h> +#include "lutil.h" +#include "lutil_md5.h" +#include <ac/string.h> + +static LUTIL_PASSWD_CHK_FUNC chk_ns_mta_md5; +static const struct berval scheme = BER_BVC("{NS-MTA-MD5}"); + +#define NS_MTA_MD5_PASSLEN 64 +static int chk_ns_mta_md5( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[LUTIL_MD5_BYTES], c; + char buffer[LUTIL_MD5_BYTES*2]; + int i; + + if( passwd->bv_len != NS_MTA_MD5_PASSLEN ) { + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + lutil_MD5Init(&MD5context); + lutil_MD5Update(&MD5context, + (const unsigned char *) &passwd->bv_val[32], + 32 ); + + c = 0x59; + lutil_MD5Update(&MD5context, + (const unsigned char *) &c, + 1 ); + + lutil_MD5Update(&MD5context, + (const unsigned char *) cred->bv_val, + cred->bv_len ); + + c = 0xF7; + lutil_MD5Update(&MD5context, + (const unsigned char *) &c, + 1 ); + + lutil_MD5Update(&MD5context, + (const unsigned char *) &passwd->bv_val[32], + 32 ); + + lutil_MD5Final(MD5digest, &MD5context); + + for( i=0; i < sizeof( MD5digest ); i++ ) { + buffer[i+i] = "0123456789abcdef"[(MD5digest[i]>>4) & 0x0F]; + buffer[i+i+1] = "0123456789abcdef"[ MD5digest[i] & 0x0F]; + } + + /* compare */ + return memcmp((char *)passwd->bv_val, + (char *)buffer, sizeof(buffer)) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +int init_module(int argc, char *argv[]) { + return lutil_passwd_add( (struct berval *)&scheme, chk_ns_mta_md5, NULL ); +} diff --git a/contrib/slapd-modules/passwd/pbkdf2/Makefile b/contrib/slapd-modules/passwd/pbkdf2/Makefile new file mode 100644 index 0000000..5234629 --- /dev/null +++ b/contrib/slapd-modules/passwd/pbkdf2/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../../.. +LDAP_BUILD = ../../../.. +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +#DEFS = -DSLAPD_PBKDF2_DEBUG + +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) -lcrypto + +PROGRAMS = pw-pbkdf2.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-pbkdf2.la: pw-pbkdf2.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done diff --git a/contrib/slapd-modules/passwd/pbkdf2/README b/contrib/slapd-modules/passwd/pbkdf2/README new file mode 100644 index 0000000..2f9a635 --- /dev/null +++ b/contrib/slapd-modules/passwd/pbkdf2/README @@ -0,0 +1,99 @@ +PBKDF2 for OpenLDAP +======================= + +pw-pbkdf2.c provides PBKDF2 key derivation functions in OpenLDAP. + +Schemes: + + * {PBKDF2} - alias to {PBKDF2-SHA1} + * {PBKDF2-SHA1} + * {PBKDF2-SHA256} + * {PBKDF2-SHA512} + +# Requirements + + * OpenSSL 1.0.0 or later + +# Installations + +First, You need to configure and build OpenLDAP. + + $ cd <OPENLDAP_BUILD_DIR>/contrib/slapd-modules/passwd/ + $ git clone https://github.com/hamano/openldap-pbkdf2.git + $ cd openldap-pbkdf2/ + $ make + # make install + +# Configration + +In slapd.conf: + + moduleload pw-pbkdf2.so + +You can also tell OpenLDAP to use the schemes when processing LDAP +Password Modify Extended Operations, thanks to the password-hash +option in slapd.conf. For example: + + password-hash {PBKDF2} +or + password-hash {PBKDF2-SHA256} +or + password-hash {PBKDF2-SHA512} + +# Testing + +You can get hash to use slappasswd. + + $ slappasswd -o module-load=pw-pbkdf2.la -h {PBKDF2} -s secret + {PBKDF2}60000$Y6ZHtTTbeUgpIbIW0QDmDA$j/aU7jFKUSbH4UobNQDm9OEIwuw + +A quick way to test whether it's working is to customize the rootdn and +rootpw in slapd.conf, eg: + + rootdn "cn=Manager,dc=example,dc=com" + rootpw {PBKDF2}60000$Y6ZHtTTbeUgpIbIW0QDmDA$j/aU7jFKUSbH4UobNQDm9OEIwuw + +Then to test, run something like: + + $ ldapsearch -x -b "dc=example,dc=com" -D "cn=Manager,dc=example,dc=com" -w secret + +# Debugging +You can specify -DSLAPD_PBKDF2_DEBUG flag for debugging. + +# Message Format + + {PBKDF2}<Iteration>$<Adapted Base64 Salt>$<Adapted Base64 DK> + +# References + +* [RFC 2898 Password-Based Cryptography][^1] +[^1]: http://tools.ietf.org/html/rfc2898 + +* [PKCS #5 PBKDF2 Test Vectors][^2] +[^2]: http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06 + +* [RFC 2307 Using LDAP as a Network Information Service][^3] +[^3]: http://tools.ietf.org/html/rfc2307 + +* [Python Passlib][^4] +[^4]: http://pythonhosted.org/passlib/ + +* [Adapted Base64 Encoding][^5] +[^5]: http://pythonhosted.org/passlib/lib/passlib.utils.html#passlib.utils.ab64_encode + +# License +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2009-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + +# ACKNOWLEDGEMENT +This work was initially developed by HAMANO Tsukasa <hamano@osstech.co.jp> diff --git a/contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c b/contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c new file mode 100644 index 0000000..a931179 --- /dev/null +++ b/contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c @@ -0,0 +1,451 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2009-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENT: + * This work was initially developed by HAMANO Tsukasa <hamano@osstech.co.jp> + */ + +#define _GNU_SOURCE + +#include "portable.h" +#include <ac/string.h> +#include "lber_pvt.h" +#include "lutil.h" +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_OPENSSL +#include <openssl/evp.h> +#elif HAVE_GNUTLS +#include <nettle/pbkdf2.h> +#include <nettle/hmac.h> +typedef void (*pbkdf2_hmac_update)(void *, unsigned, const uint8_t *); +typedef void (*pbkdf2_hmac_digest)(void *, unsigned, uint8_t *); +#else +#error Unsupported crypto backend. +#endif + +#define PBKDF2_ITERATION 10000 +#define PBKDF2_SALT_SIZE 16 +#define PBKDF2_SHA1_DK_SIZE 20 +#define PBKDF2_SHA256_DK_SIZE 32 +#define PBKDF2_SHA512_DK_SIZE 64 +#define PBKDF2_MAX_DK_SIZE 64 + +const struct berval pbkdf2_scheme = BER_BVC("{PBKDF2}"); +const struct berval pbkdf2_sha1_scheme = BER_BVC("{PBKDF2-SHA1}"); +const struct berval pbkdf2_sha256_scheme = BER_BVC("{PBKDF2-SHA256}"); +const struct berval pbkdf2_sha512_scheme = BER_BVC("{PBKDF2-SHA512}"); + +/* + * Converting base64 string to adapted base64 string. + * Adapted base64 encode is identical to general base64 encode except + * that it uses '.' instead of '+', and omits trailing padding '=' and + * whitepsace. + * see http://pythonhosted.org/passlib/lib/passlib.utils.html + * This is destructive function. + */ +static int b64_to_ab64(char *str) +{ + char *p = str; + do { + if(*p == '+'){ + *p = '.'; + } + if(*p == '='){ + *p = '\0'; + } + } while(*p++); + return 0; +} + +/* + * Converting adapted base64 string to base64 string. + * dstsize will require src length + 2, due to output string have + * potential to append "=" or "==". + * return -1 if few output buffer. + */ +static int ab64_to_b64(char *src, char *dst, size_t dstsize){ + int i; + char *p = src; + for(i=0; p[i] && p[i] != '$'; i++){ + if(i >= dstsize){ + dst[0] = '\0'; + return -1; + } + if(p[i] == '.'){ + dst[i] = '+'; + }else{ + dst[i] = p[i]; + } + } + for(;i%4;i++){ + if(i >= dstsize){ + dst[0] = '\0'; + return -1; + } + dst[i] = '='; + } + dst[i] = '\0'; + return 0; +} + +static int pbkdf2_format( + const struct berval *sc, + int iteration, + const struct berval *salt, + const struct berval *dk, + struct berval *msg) +{ + + int rc, msg_len; + char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1]; + char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1]; + + rc = lutil_b64_ntop((unsigned char *)salt->bv_val, salt->bv_len, + salt_b64, sizeof(salt_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + b64_to_ab64(salt_b64); + rc = lutil_b64_ntop((unsigned char *)dk->bv_val, dk->bv_len, + dk_b64, sizeof(dk_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + b64_to_ab64(dk_b64); + msg_len = asprintf(&msg->bv_val, "%s%d$%s$%s", + sc->bv_val, iteration, + salt_b64, dk_b64); + if(msg_len < 0){ + msg->bv_len = 0; + return LUTIL_PASSWD_ERR; + } + + msg->bv_len = msg_len; + return LUTIL_PASSWD_OK; +} + +static int pbkdf2_encrypt( + const struct berval *scheme, + const struct berval *passwd, + struct berval *msg, + const char **text) +{ + unsigned char salt_value[PBKDF2_SALT_SIZE]; + struct berval salt; + unsigned char dk_value[PBKDF2_MAX_DK_SIZE]; + struct berval dk; + int iteration = PBKDF2_ITERATION; + int rc; +#ifdef HAVE_OPENSSL + const EVP_MD *md; +#elif HAVE_GNUTLS + struct hmac_sha1_ctx sha1_ctx; + struct hmac_sha256_ctx sha256_ctx; + struct hmac_sha512_ctx sha512_ctx; + void * current_ctx = NULL; + pbkdf2_hmac_update current_hmac_update = NULL; + pbkdf2_hmac_digest current_hmac_digest = NULL; +#endif + + salt.bv_val = (char *)salt_value; + salt.bv_len = sizeof(salt_value); + dk.bv_val = (char *)dk_value; + +#ifdef HAVE_OPENSSL + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk.bv_len = PBKDF2_SHA256_DK_SIZE; + md = EVP_sha256(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk.bv_len = PBKDF2_SHA512_DK_SIZE; + md = EVP_sha512(); + }else{ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk.bv_len = PBKDF2_SHA256_DK_SIZE; + current_ctx = &sha256_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest; + hmac_sha256_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk.bv_len = PBKDF2_SHA512_DK_SIZE; + current_ctx = &sha512_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest; + hmac_sha512_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else{ + return LUTIL_PASSWD_ERR; + } +#endif + + if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){ + return LUTIL_PASSWD_ERR; + } + +#ifdef HAVE_OPENSSL + if(!PKCS5_PBKDF2_HMAC(passwd->bv_val, passwd->bv_len, + (unsigned char *)salt.bv_val, salt.bv_len, + iteration, md, dk.bv_len, dk_value)){ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + PBKDF2(current_ctx, current_hmac_update, current_hmac_digest, + dk.bv_len, iteration, + salt.bv_len, (const uint8_t *) salt.bv_val, + dk.bv_len, dk_value); +#endif + +#ifdef SLAPD_PBKDF2_DEBUG + printf("Encrypt for %s\n", scheme->bv_val); + printf(" Password:\t%s\n", passwd->bv_val); + + printf(" Salt:\t\t"); + int i; + for(i=0; i<salt.bv_len; i++){ + printf("%02x", salt_value[i]); + } + printf("\n"); + printf(" Iteration:\t%d\n", iteration); + + printf(" DK:\t\t"); + for(i=0; i<dk.bv_len; i++){ + printf("%02x", dk_value[i]); + } + printf("\n"); +#endif + + rc = pbkdf2_format(scheme, iteration, &salt, &dk, msg); + +#ifdef SLAPD_PBKDF2_DEBUG + printf(" Output:\t%s\n", msg->bv_val); +#endif + + return rc; +} + +static int pbkdf2_check( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + int rc; + int iteration; + + /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */ + unsigned char salt_value[PBKDF2_SALT_SIZE + 1]; + char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1]; + /* dk_value require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */ + unsigned char dk_value[PBKDF2_MAX_DK_SIZE + 1]; + char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1]; + unsigned char input_dk_value[PBKDF2_MAX_DK_SIZE]; + size_t dk_len; +#ifdef HAVE_OPENSSL + const EVP_MD *md; +#elif HAVE_GNUTLS + struct hmac_sha1_ctx sha1_ctx; + struct hmac_sha256_ctx sha256_ctx; + struct hmac_sha512_ctx sha512_ctx; + void * current_ctx = NULL; + pbkdf2_hmac_update current_hmac_update = NULL; + pbkdf2_hmac_digest current_hmac_digest = NULL; +#endif + +#ifdef SLAPD_PBKDF2_DEBUG + printf("Checking for %s\n", scheme->bv_val); + printf(" Stored Value:\t%s\n", passwd->bv_val); + printf(" Input Cred:\t%s\n", cred->bv_val); +#endif + +#ifdef HAVE_OPENSSL + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk_len = PBKDF2_SHA256_DK_SIZE; + md = EVP_sha256(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk_len = PBKDF2_SHA512_DK_SIZE; + md = EVP_sha512(); + }else{ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk_len = PBKDF2_SHA256_DK_SIZE; + current_ctx = &sha256_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest; + hmac_sha256_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk_len = PBKDF2_SHA512_DK_SIZE; + current_ctx = &sha512_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest; + hmac_sha512_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else{ + return LUTIL_PASSWD_ERR; + } +#endif + + iteration = atoi(passwd->bv_val); + if(iteration < 1){ + return LUTIL_PASSWD_ERR; + } + + char *ptr; + ptr = strchr(passwd->bv_val, '$'); + if(!ptr){ + return LUTIL_PASSWD_ERR; + } + ptr++; /* skip '$' */ + rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + ptr = strchr(ptr, '$'); + if(!ptr){ + return LUTIL_PASSWD_ERR; + } + ptr++; /* skip '$' */ + rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */ + rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + /* consistency check */ + if(rc != PBKDF2_SALT_SIZE){ + return LUTIL_PASSWD_ERR; + } + + /* The targetsize require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */ + rc = lutil_b64_pton(dk_b64, dk_value, sizeof(dk_value)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + /* consistency check */ + if(rc != dk_len){ + return LUTIL_PASSWD_ERR; + } + +#ifdef HAVE_OPENSSL + if(!PKCS5_PBKDF2_HMAC(cred->bv_val, cred->bv_len, + salt_value, PBKDF2_SALT_SIZE, + iteration, md, dk_len, input_dk_value)){ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + PBKDF2(current_ctx, current_hmac_update, current_hmac_digest, + dk_len, iteration, + PBKDF2_SALT_SIZE, salt_value, + dk_len, input_dk_value); +#endif + + rc = memcmp(dk_value, input_dk_value, dk_len); +#ifdef SLAPD_PBKDF2_DEBUG + printf(" Iteration:\t%d\n", iteration); + printf(" Base64 Salt:\t%s\n", salt_b64); + printf(" Base64 DK:\t%s\n", dk_b64); + int i; + printf(" Stored Salt:\t"); + for(i=0; i<PBKDF2_SALT_SIZE; i++){ + printf("%02x", salt_value[i]); + } + printf("\n"); + + printf(" Stored DK:\t"); + for(i=0; i<dk_len; i++){ + printf("%02x", dk_value[i]); + } + printf("\n"); + + printf(" Input DK:\t"); + for(i=0; i<dk_len; i++){ + printf("%02x", input_dk_value[i]); + } + printf("\n"); + printf(" Result:\t%d\n", rc); +#endif + return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK; +} + +int init_module(int argc, char *argv[]) { + int rc; + rc = lutil_passwd_add((struct berval *)&pbkdf2_scheme, + pbkdf2_check, pbkdf2_encrypt); + if(rc) return rc; + rc = lutil_passwd_add((struct berval *)&pbkdf2_sha1_scheme, + pbkdf2_check, pbkdf2_encrypt); + if(rc) return rc; + + rc = lutil_passwd_add((struct berval *)&pbkdf2_sha256_scheme, + pbkdf2_check, pbkdf2_encrypt); + if(rc) return rc; + + rc = lutil_passwd_add((struct berval *)&pbkdf2_sha512_scheme, + pbkdf2_check, pbkdf2_encrypt); + return rc; +} + +/* + * Local variables: + * indent-tabs-mode: t + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/contrib/slapd-modules/passwd/radius.c b/contrib/slapd-modules/passwd/radius.c new file mode 100644 index 0000000..af8a8ef --- /dev/null +++ b/contrib/slapd-modules/passwd/radius.c @@ -0,0 +1,149 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include "portable.h" + +#include <stdio.h> + +#include <lber.h> +#include <lber_pvt.h> /* BER_BVC definition */ +#include "lutil.h" +#include <ldap_pvt_thread.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#include <radlib.h> + +extern char *global_host; /* from slapd */ +static LUTIL_PASSWD_CHK_FUNC chk_radius; +static const struct berval scheme = BER_BVC("{RADIUS}"); +static char *config_filename; +static ldap_pvt_thread_mutex_t libradius_mutex; + +static int +chk_radius( + const struct berval *sc, + const struct berval *passwd, + const struct berval *cred, + const char **text ) +{ + unsigned int i; + int rc = LUTIL_PASSWD_ERR; + + struct rad_handle *h = NULL; + + for ( i = 0; i < cred->bv_len; i++ ) { + if ( cred->bv_val[ i ] == '\0' ) { + return LUTIL_PASSWD_ERR; /* NUL character in cred */ + } + } + + if ( cred->bv_val[ i ] != '\0' ) { + return LUTIL_PASSWD_ERR; /* cred must behave like a string */ + } + + for ( i = 0; i < passwd->bv_len; i++ ) { + if ( passwd->bv_val[ i ] == '\0' ) { + return LUTIL_PASSWD_ERR; /* NUL character in password */ + } + } + + if ( passwd->bv_val[ i ] != '\0' ) { + return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ + } + + ldap_pvt_thread_mutex_lock( &libradius_mutex ); + + h = rad_auth_open(); + if ( h == NULL ) { + ldap_pvt_thread_mutex_unlock( &libradius_mutex ); + return LUTIL_PASSWD_ERR; + } + + if ( rad_config( h, config_filename ) != 0 ) { + goto done; + } + + if ( rad_create_request( h, RAD_ACCESS_REQUEST ) ) { + goto done; + } + + if ( rad_put_string( h, RAD_USER_NAME, passwd->bv_val ) != 0 ) { + goto done; + } + + if ( rad_put_string( h, RAD_USER_PASSWORD, cred->bv_val ) != 0 ) { + goto done; + } + + if ( rad_put_string( h, RAD_NAS_IDENTIFIER, global_host ) != 0 ) { + goto done; + } + + switch ( rad_send_request( h ) ) { + case RAD_ACCESS_ACCEPT: + rc = LUTIL_PASSWD_OK; + break; + + case RAD_ACCESS_REJECT: + rc = LUTIL_PASSWD_ERR; + break; + + case RAD_ACCESS_CHALLENGE: + rc = LUTIL_PASSWD_ERR; + break; + + case -1: + /* no valid response is received */ + break; + } + +done:; + rad_close( h ); + + ldap_pvt_thread_mutex_unlock( &libradius_mutex ); + return rc; +} + +int +term_module() +{ + return ldap_pvt_thread_mutex_destroy( &libradius_mutex ); +} + +int +init_module( int argc, char *argv[] ) +{ + int i; + + for ( i = 0; i < argc; i++ ) { + if ( strncasecmp( argv[ i ], "config=", STRLENOF( "config=" ) ) == 0 ) { + /* FIXME: what if multiple loads of same module? + * does it make sense (e.g. override an existing one)? */ + if ( config_filename == NULL ) { + config_filename = ber_strdup( &argv[ i ][ STRLENOF( "config=" ) ] ); + } + + } else { + fprintf( stderr, "init_module(radius): unknown arg#%d=\"%s\".\n", + i, argv[ i ] ); + return 1; + } + } + + ldap_pvt_thread_mutex_init( &libradius_mutex ); + + return lutil_passwd_add( (struct berval *)&scheme, chk_radius, NULL ); +} diff --git a/contrib/slapd-modules/passwd/sha2/Makefile b/contrib/slapd-modules/passwd/sha2/Makefile new file mode 100644 index 0000000..0abab68 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/Makefile @@ -0,0 +1,47 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +#DEFS = -DSLAPD_SHA2_DEBUG +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = pw-sha2.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-sha2.la: slapd-sha2.lo sha2.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/passwd/sha2/README b/contrib/slapd-modules/passwd/sha2/README new file mode 100644 index 0000000..10a2537 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/README @@ -0,0 +1,144 @@ +SHA-2 OpenLDAP support +---------------------- + +slapd-sha2.c provides support for SSHA-512, SSHA-384, SSHA-256, +SHA-512, SHA-384 and SHA-256 hashed passwords in OpenLDAP. For +instance, one could have the LDAP attribute: + +userPassword: {SHA512}vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cmW192CF5bDufKRpayrW/isg== + +or: + +userPassword: {SHA384}WKd1ukESvjAFrkQHznV9iP2nHUBJe7gCbsrFTU4//HIyzo3jq1rLMK45dg/ufFPt + +or: + +userPassword: {SHA256}K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + +all of which encode the password 'secret'. + + +Building +-------- + +1) Customize the OPENLDAP variable in Makefile to point to the OpenLDAP +source root. + +For initial testing you might also want to edit DEFS to define +SLAPD_SHA2_DEBUG, which enables logging to stderr (don't leave this on +in production, as it prints passwords in cleartext). + +2) Run 'make' to produce slapd-sha2.so + +3) Copy slapd-sha2.so somewhere permanent. + +4) Edit your slapd.conf (eg. /etc/ldap/slapd.conf), and add: + +moduleload ...path/to/slapd-sha2.so + +5) Restart slapd. + + +Configuring +----------- + +The {SSHA256}, {SSHA384}, {SSHA512}, {SSHA256}, {SHA384} and {SHA512} +password schemes should now be recognised. + +You can also tell OpenLDAP to use one of these new schemes when processing LDAP +Password Modify Extended Operations, thanks to the password-hash option in +slapd.conf. For example: + +password-hash {SSHA512} + + +Testing +------- + +A quick way to test whether it's working is to customize the rootdn and +rootpw in slapd.conf, eg: + +rootdn "cn=admin,dc=example,dc=com" +# This encrypts the string 'secret' + +rootpw {SHA256}K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + +Then to test, run something like: + +ldapsearch -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -x -w secret + + +-- Test hashes: + +Test hashes can be generated with openssl: + +$ echo -n "secret" | openssl dgst -sha256 -binary | openssl enc -base64 +K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= +$ echo -n "secret" | openssl dgst -sha384 -binary | openssl enc -base64 +WKd1ukESvjAFrkQHznV9iP2nHUBJe7gCbsrFTU4//HIyzo3jq1rLMK45dg/ufFPt +$ echo -n "secret" | openssl dgst -sha512 -binary | openssl enc -base64 +vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cm +W192CF5bDufKRpayrW/isg== + +(join those lines up to form the full hash) + + + +Alternatively we could modify an existing user's password with +ldappasswd, and then test binding as that user: + +$ ldappasswd -D "cn=admin,dc=example,dc=com" -x -W -S uid=jturner,ou=People,dc=example,dc=com +New password: secret +Re-enter new password: secret +Enter LDAP Password: <cn=admin's password> + +$ ldapsearch -b "dc=example,dc=com" -D "uid=jturner,ou=People,dc=example,dc=com" -x -w secret + + +Debugging (SHA-512, SHA-384 and SHA-256 only) +--------------------------------------------- + +To see what's going on, recompile with SLAPD_SHA2_DEBUG (use the +commented-out DEFS in Makefile), and then run slapd from the console +to see stderr: + +$ sudo /etc/init.d/slapd stop +Stopping OpenLDAP: slapd. +$ sudo /usr/sbin/slapd -f /etc/ldap/slapd.conf -h ldap://localhost:389 -d stats +@(#) $OpenLDAP$ + buildd@palmer:/build/buildd/openldap2.3-2.4.9/debian/build/servers/slapd +slapd starting +... +Validating password + Hash scheme: {SHA256} + Password to validate: secret + Password hash: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + Stored password hash: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + Result: match +conn=0 op=0 BIND dn="cn=admin,dc=example,dc=com" mech=SIMPLE ssf=0 +conn=0 op=0 RESULT tag=97 err=0 text= +conn=0 op=1 SRCH base="dc=example,dc=com" scope=2 deref=0 filter="(objectClass=*)" +conn=0 fd=12 closed (connection lost) + +--- + +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2009-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + +--- + +ACKNOWLEDGEMENT: +This work was initially developed by Jeff Turner for inclusion in +OpenLDAP Software, based upon the SHA-2 implementation independently +developed by Aaron Gifford. + diff --git a/contrib/slapd-modules/passwd/sha2/sha2.c b/contrib/slapd-modules/passwd/sha2/sha2.c new file mode 100644 index 0000000..808da10 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/sha2.c @@ -0,0 +1,1070 @@ +/* $OpenLDAP$ */ +/* + * FILE: sha2.c + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ + */ + +#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */ +#include <assert.h> /* assert() */ +#include "sha2.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including <sys/types.h> (which in turn includes + * <machine/endian.h> where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/* + * Define the followingsha2_* types to types of the correct length on + * the native archtecture. Most BSD systems and Linux define u_intXX_t + * types. Machines with very recent ANSI C headers, can use the + * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H + * during compile or in the sha.h header file. + * + * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t + * will need to define these three typedefs below (and the appropriate + * ones in sha.h too) by hand according to their system architecture. + * + * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t + * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. + */ +#ifdef SHA2_USE_INTTYPES_H + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +#else /* SHA2_USE_INTTYPES_H */ + +typedef u_int8_t sha2_byte; /* Exactly 1 byte */ +typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ +typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/* + * Macros for copying blocks of memory and for zeroing out ranges + * of memory. Using these macros makes it easy to switch from + * using memset()/memcpy() and using bzero()/bcopy(). + * + * Please define either SHA2_USE_MEMSET_MEMCPY or define + * SHA2_USE_BZERO_BCOPY depending on which function set you + * choose to use: + */ +#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) +/* Default to memset()/memcpy() if no option is specified */ +#define SHA2_USE_MEMSET_MEMCPY 1 +#endif +#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) +/* Abort with an error if BOTH options are defined */ +#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! +#endif + +#ifdef SHA2_USE_MEMSET_MEMCPY +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) +#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) +#endif +#ifdef SHA2_USE_BZERO_BCOPY +#define MEMSET_BZERO(p,l) bzero((p), (l)) +#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) +#endif + + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +static void SHA512_Last(SHA512_CTX*); +static void SHA256_Transform(SHA256_CTX*, const sha2_word32*); +static void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + sha2_word64 *p; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + p = (sha2_word64 *)&context->buffer[SHA256_SHORT_BLOCK_LENGTH]; + *p = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + MEMSET_BZERO(context, sizeof(*context)); + usedspace = 0; +} + +char *SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + sha2_word64 *p; + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + p = (sha2_word64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH]; + p[0] = context->bitcount[1]; + p[1] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(*context)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} + + +/*** SHA-384: *********************************************************/ +void SHA384_Init(SHA384_CTX* context) { + if (context == (SHA384_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { + SHA512_Update((SHA512_CTX*)context, data, len); +} + +void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(*context)); +} + +char *SHA384_End(SHA384_CTX* context, char buffer[]) { + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); + return buffer; +} + +char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { + SHA384_CTX context; + + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); +} + diff --git a/contrib/slapd-modules/passwd/sha2/sha2.h b/contrib/slapd-modules/passwd/sha2/sha2.h new file mode 100644 index 0000000..7fff142 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/sha2.h @@ -0,0 +1,236 @@ +/* $OpenLDAP$ */ +/* + * FILE: sha2.h + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#include "portable.h" + +#ifdef HAVE_INTTYPES_H +# define SHA2_USE_INTTYPES_H 1 +#endif + +#ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN 1234 +#endif +#ifndef BIG_ENDIAN +# define BIG_ENDIAN 4321 +#endif +#ifndef BYTE_ORDER +# ifdef WORDS_BIGENDIAN +# define BYTE_ORDER BIG_ENDIAN +# else +# define BYTE_ORDER LITTLE_ENDIAN +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Import u_intXX_t size_t type definitions from system headers. You + * may need to change this, or define these things yourself in this + * file. + */ +#include <sys/types.h> + +#ifdef SHA2_USE_INTTYPES_H + +#include <inttypes.h> + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +/* NOTE: If your architecture does not define either u_intXX_t types or + * uintXX_t (from inttypes.h), you may need to define things by hand + * for your system: + */ +#if 0 +typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ +typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ +typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ +#endif +/* + * Most BSD systems already define u_intXX_t types, as does Linux. + * Some systems, however, like Compaq's Tru64 Unix instead can use + * uintXX_t types defined by very recent ANSI C standards and included + * in the file: + * + * #include <inttypes.h> + * + * If you choose to use <inttypes.h> then please define: + * + * #define SHA2_USE_INTTYPES_H + * + * Or on the command line during compile: + * + * cc -DSHA2_USE_INTTYPES_H ... + */ +#ifdef SHA2_USE_INTTYPES_H + +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#else /* SHA2_USE_INTTYPES_H */ + +typedef struct _SHA256_CTX { + u_int32_t state[8]; + u_int64_t bitcount; + u_int8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + u_int64_t state[8]; + u_int64_t bitcount[2]; + u_int8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#endif /* SHA2_USE_INTTYPES_H */ + +typedef SHA512_CTX SHA384_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ +/* avoid symbol clash with other crypto libs */ +#define SHA256_Init pw_SHA256_Init +#define SHA256_Update pw_SHA256_Update +#define SHA256_Final pw_SHA256_Final +#define SHA256_End pw_SHA256_End +#define SHA256_Data pw_SHA256_Data + +#define SHA384_Init pw_SHA384_Init +#define SHA384_Update pw_SHA384_Update +#define SHA384_Final pw_SHA384_Final +#define SHA384_End pw_SHA384_End +#define SHA384_Data pw_SHA384_Data + +#define SHA512_Init pw_SHA512_Init +#define SHA512_Update pw_SHA512_Update +#define SHA512_Final pw_SHA512_Final +#define SHA512_End pw_SHA512_End +#define SHA512_Data pw_SHA512_Data + +#ifndef NOPROTO +#ifdef SHA2_USE_INTTYPES_H + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); +void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void SHA384_Init(SHA384_CTX*); +void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t); +void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); +char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); +char* SHA384_Data(const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); + +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); +void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#else /* SHA2_USE_INTTYPES_H */ + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t); +void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void SHA384_Init(SHA384_CTX*); +void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t); +void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); +char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); +char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); + +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t); +void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#endif /* SHA2_USE_INTTYPES_H */ + +#else /* NOPROTO */ + +void SHA256_Init(); +void SHA256_Update(); +void SHA256_Final(); +char* SHA256_End(); +char* SHA256_Data(); + +void SHA384_Init(); +void SHA384_Update(); +void SHA384_Final(); +char* SHA384_End(); +char* SHA384_Data(); + +void SHA512_Init(); +void SHA512_Update(); +void SHA512_Final(); +char* SHA512_End(); +char* SHA512_Data(); + +#endif /* NOPROTO */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/contrib/slapd-modules/passwd/sha2/slapd-sha2.c b/contrib/slapd-modules/passwd/sha2/slapd-sha2.c new file mode 100644 index 0000000..c35d9d9 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/slapd-sha2.c @@ -0,0 +1,508 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2009-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENT: + * This work was initially developed by Jeff Turner for inclusion + * in OpenLDAP Software. + * + * Hash methods for passwords generation added by Cédric Delfosse. + * + * SSHA256 / SSHA384 / SSHA512 support added, and chk_sha*() replaced + * with libraries/liblutil/passwd.c:chk_sha1() implementation to + * fix a race by SATOH Fumiyasu @ OSS Technology, Inc. + */ + +#include "portable.h" + +#include <ac/string.h> + +#include "lber_pvt.h" +#include "lutil.h" +#include "sha2.h" + +#ifdef SLAPD_SHA2_DEBUG +#include <stdio.h> +#endif + +#define SHA2_SALT_SIZE 8 + +static int hash_ssha256( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA256_CTX ct; + unsigned char hash256[SHA256_DIGEST_LENGTH]; + char saltdata[SHA2_SALT_SIZE]; + struct berval digest; + struct berval salt; + + digest.bv_val = (char *) hash256; + digest.bv_len = sizeof(hash256); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if (lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0) { + return LUTIL_PASSWD_ERR; + } + + SHA256_Init(&ct); + SHA256_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA256_Update(&ct, (const uint8_t*)salt.bv_val, salt.bv_len); + SHA256_Final(hash256, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_sha256( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA256_CTX ct; + unsigned char hash256[SHA256_DIGEST_LENGTH]; + struct berval digest; + digest.bv_val = (char *) hash256; + digest.bv_len = sizeof(hash256); + + SHA256_Init(&ct); + SHA256_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA256_Final(hash256, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, NULL); +} + +static int hash_ssha384( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA384_CTX ct; + unsigned char hash384[SHA384_DIGEST_LENGTH]; + char saltdata[SHA2_SALT_SIZE]; + struct berval digest; + struct berval salt; + + digest.bv_val = (char *) hash384; + digest.bv_len = sizeof(hash384); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if (lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0) { + return LUTIL_PASSWD_ERR; + } + + SHA384_Init(&ct); + SHA384_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA384_Update(&ct, (const uint8_t*)salt.bv_val, salt.bv_len); + SHA384_Final(hash384, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_sha384( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA384_CTX ct; + unsigned char hash384[SHA384_DIGEST_LENGTH]; + struct berval digest; + digest.bv_val = (char *) hash384; + digest.bv_len = sizeof(hash384); + + SHA384_Init(&ct); + SHA384_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA384_Final(hash384, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, NULL); +} + +static int hash_ssha512( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA512_CTX ct; + unsigned char hash512[SHA512_DIGEST_LENGTH]; + char saltdata[SHA2_SALT_SIZE]; + struct berval digest; + struct berval salt; + + digest.bv_val = (char *) hash512; + digest.bv_len = sizeof(hash512); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if (lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0) { + return LUTIL_PASSWD_ERR; + } + + SHA512_Init(&ct); + SHA512_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA512_Update(&ct, (const uint8_t*)salt.bv_val, salt.bv_len); + SHA512_Final(hash512, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_sha512( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA512_CTX ct; + unsigned char hash512[SHA512_DIGEST_LENGTH]; + struct berval digest; + digest.bv_val = (char *) hash512; + digest.bv_len = sizeof(hash512); + + SHA512_Init(&ct); + SHA512_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA512_Final(hash512, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, NULL); +} + +#ifdef SLAPD_SHA2_DEBUG +static void chk_sha_debug( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char *cred_hash, + size_t cred_len, + int cmp_rc) +{ + int rc; + struct berval cred_b64; + + cred_b64.bv_len = LUTIL_BASE64_ENCODE_LEN(cred_len) + 1; + cred_b64.bv_val = ber_memalloc(cred_b64.bv_len + 1); + + if( cred_b64.bv_val == NULL ) { + return; + } + + rc = lutil_b64_ntop( + (unsigned char *) cred_hash, cred_len, + cred_b64.bv_val, cred_b64.bv_len ); + + if( rc < 0 ) { + ber_memfree(cred_b64.bv_val); + return; + } + + fprintf(stderr, "Validating password\n"); + fprintf(stderr, " Hash scheme:\t\t%s\n", scheme->bv_val); + fprintf(stderr, " Password to validate: %s\n", cred->bv_val); + fprintf(stderr, " Password hash:\t%s\n", cred_b64.bv_val); + fprintf(stderr, " Stored password hash:\t%s\n", passwd->bv_val); + fprintf(stderr, " Result:\t\t%s\n", cmp_rc ? "do not match" : "match"); + + ber_memfree(cred_b64.bv_val); +} +#endif + +static int chk_ssha256( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA256_CTX SHAcontext; + unsigned char SHAdigest[SHA256_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc <= (int)(sizeof(SHAdigest)) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA256_Init(&SHAcontext); + SHA256_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA256_Update(&SHAcontext, + (const unsigned char *) &orig_pass[sizeof(SHAdigest)], + rc - sizeof(SHAdigest)); + SHA256_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_sha256( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA256_CTX SHAcontext; + unsigned char SHAdigest[SHA256_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len < sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc != sizeof(SHAdigest) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA256_Init(&SHAcontext); + SHA256_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA256_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); +#ifdef SLAPD_SHA2_DEBUG + chk_sha_debug(scheme, passwd, cred, (char *)SHAdigest, sizeof(SHAdigest), rc); +#endif + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_ssha384( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA384_CTX SHAcontext; + unsigned char SHAdigest[SHA384_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc <= (int)(sizeof(SHAdigest)) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA384_Init(&SHAcontext); + SHA384_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA384_Update(&SHAcontext, + (const unsigned char *) &orig_pass[sizeof(SHAdigest)], + rc - sizeof(SHAdigest)); + SHA384_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_sha384( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA384_CTX SHAcontext; + unsigned char SHAdigest[SHA384_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len < sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc != sizeof(SHAdigest) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA384_Init(&SHAcontext); + SHA384_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA384_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); +#ifdef SLAPD_SHA2_DEBUG + chk_sha_debug(scheme, passwd, cred, (char *)SHAdigest, sizeof(SHAdigest), rc); +#endif + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_ssha512( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA512_CTX SHAcontext; + unsigned char SHAdigest[SHA512_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc <= (int)(sizeof(SHAdigest)) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA512_Init(&SHAcontext); + SHA512_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA512_Update(&SHAcontext, + (const unsigned char *) &orig_pass[sizeof(SHAdigest)], + rc - sizeof(SHAdigest)); + SHA512_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_sha512( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA512_CTX SHAcontext; + unsigned char SHAdigest[SHA512_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len < sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc != sizeof(SHAdigest) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA512_Init(&SHAcontext); + SHA512_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA512_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); +#ifdef SLAPD_SHA2_DEBUG + chk_sha_debug(scheme, passwd, cred, (char *)SHAdigest, sizeof(SHAdigest), rc); +#endif + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +const struct berval ssha256scheme = BER_BVC("{SSHA256}"); +const struct berval sha256scheme = BER_BVC("{SHA256}"); +const struct berval ssha384scheme = BER_BVC("{SSHA384}"); +const struct berval sha384scheme = BER_BVC("{SHA384}"); +const struct berval ssha512scheme = BER_BVC("{SSHA512}"); +const struct berval sha512scheme = BER_BVC("{SHA512}"); + +int init_module(int argc, char *argv[]) { + int result = 0; + result = lutil_passwd_add( (struct berval *)&ssha256scheme, chk_ssha256, hash_ssha256 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&sha256scheme, chk_sha256, hash_sha256 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&ssha384scheme, chk_ssha384, hash_ssha384 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&sha384scheme, chk_sha384, hash_sha384 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&ssha512scheme, chk_ssha512, hash_ssha512 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&sha512scheme, chk_sha512, hash_sha512 ); + return result; +} |