ITS#5660 SHA2 password hashes

This commit is contained in:
Howard Chu 2009-01-26 04:08:34 +00:00
parent 4fe69b3fc5
commit ba0863d500
5 changed files with 1551 additions and 0 deletions

View File

@ -0,0 +1,15 @@
# $OpenLDAP$
OPENLDAP := ../../../..
#CCFLAGS = -Wall -g -DSLAPD_SHA2_DEBUG
CCFLAGS = -Wall -g
slapd-sha2.so: slapd-sha2.o sha2.o
$(CC) -I$(OPENLDAP)/include -shared -Wall -g $^ -o $@
%.o: %.c
$(CC) -I$(OPENLDAP)/include $(CCFLAGS) -c $<
clean:
@rm -f slapd-sha2.so *.o

View File

@ -0,0 +1,131 @@
SHA-512 OpenLDAP support
------------------------
Based on SHA2 implementation by Aaron D. Gifford (http://www.aarongifford.com/), also used in OpenBSD.
Adapted for OpenLDAP use by Jeff Turner <jeff@atlassian.com>
Distributed under open source BSD license - see code for details.
slapd-sha2.c provides support for 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) Obtain the OpenLDAP source, eg. 'apt-get source slapd'. Really we
only want the headers, but there doesn't seem to be a Debian package
with them.
2) Customize the OPENLDAP variable in Makefile to point to the OpenLDAP
source root.
For initial testing you might also want to edit CCFLAGS to define
SLAPD_SHA2_DEBUG, which enables logging to stderr (don't leave this on
in production, as it prints passwords in cleartext).
3) Run 'make' to produce slapd-sha2.so
4) 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.
The {SHA512} scheme should now be recognised.
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
ldapmodify, and then test binding as that user:
$ ldapmodify -D "cn=admin,dc=example,dc=com" -x -W
Enter LDAP Password:
dn: uid=jturner,ou=People,dc=example,dc=com
changetype: modify
replace: userPassword
userPassword: {SHA512}vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cmW192CF5bDufKRpayrW/isg==
modifying entry "uid=jturner,ou=People,dc=example,dc=com"
$ ldapsearch -b "dc=example,dc=com" -D "uid=jturner,ou=People,dc=example,dc=com" -x -w secret
Debugging
---------
To see what's going on, recompile with SLAPD_SHA2_DEBUG (use the
commented-out CCFLAGS 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 256
@(#) $OpenLDAP$
buildd@palmer:/build/buildd/openldap2.3-2.4.9/debian/build/servers/slapd
/etc/ldap/slapd.conf: line 123: rootdn is always granted unlimited privileges.
/etc/ldap/slapd.conf: line 140: rootdn is always granted unlimited privileges.
slapd starting
...
Validating password
Password to validate: secret
Hashes to: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=
Stored password scheme: {SHA256}
Stored password value: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=
-> Passwords 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)
Origin
------
Based on code maintained at:
http://confluence.atlassian.com/display/JIRAEXT/OpenLDAP+support+for+SHA-2+(SHA-256%2C+SHA-384%2C+SHA-512)+and+atlassian-sha1+passwords

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,198 @@
/* $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__
#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 ******************************/
#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__ */

View File

@ -0,0 +1,141 @@
/* $OpenLDAP$ */
#include <lber.h>
#include <lber_pvt.h> // Required for BER_BVC
#include <ac/string.h> // Required for BER_BVC dep
#include "lutil.h"
#include <stdint.h>
#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
#include <assert.h> /* assert() */
#include "sha2.h"
#ifdef SLAPD_SHA2_DEBUG
#include <stdio.h>
#endif
char * sha256_hex_hash(const char * passwd) {
SHA256_CTX ct;
unsigned char hash[SHA256_DIGEST_LENGTH];
static char real_hash[LUTIL_BASE64_ENCODE_LEN(SHA256_DIGEST_LENGTH)+1]; // extra char for \0
SHA256_Init(&ct);
SHA256_Update(&ct, (const uint8_t*)passwd, strlen(passwd));
SHA256_Final(hash, &ct);
/* base64 encode it */
lutil_b64_ntop(
hash,
SHA256_DIGEST_LENGTH,
real_hash,
LUTIL_BASE64_ENCODE_LEN(SHA256_DIGEST_LENGTH)+1
);
return real_hash;
}
char * sha384_hex_hash(const char * passwd) {
SHA384_CTX ct;
unsigned char hash[SHA384_DIGEST_LENGTH];
static char real_hash[LUTIL_BASE64_ENCODE_LEN(SHA384_DIGEST_LENGTH)+1]; // extra char for \0
SHA384_Init(&ct);
SHA384_Update(&ct, (const uint8_t*)passwd, strlen(passwd));
SHA384_Final(hash, &ct);
/* base64 encode it */
lutil_b64_ntop(
hash,
SHA384_DIGEST_LENGTH,
real_hash,
LUTIL_BASE64_ENCODE_LEN(SHA384_DIGEST_LENGTH)+1
);
return real_hash;
}
char * sha512_hex_hash(const char * passwd) {
SHA512_CTX ct;
unsigned char hash[SHA512_DIGEST_LENGTH];
static char real_hash[LUTIL_BASE64_ENCODE_LEN(SHA512_DIGEST_LENGTH)+1]; // extra char for \0
SHA512_Init(&ct);
SHA512_Update(&ct, (const uint8_t*)passwd, strlen(passwd));
SHA512_Final(hash, &ct);
/* base64 encode it */
lutil_b64_ntop(
hash,
SHA512_DIGEST_LENGTH,
real_hash,
LUTIL_BASE64_ENCODE_LEN(SHA512_DIGEST_LENGTH)+1
);
return real_hash;
}
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 )
{
#ifdef SLAPD_SHA2_DEBUG
fprintf(stderr, "Validating password\n");
fprintf(stderr, " Password to validate: %s\n", cred->bv_val);
fprintf(stderr, " Hashes to: %s\n", sha256_hex_hash(cred->bv_val));
fprintf(stderr, " Stored password scheme: %s\n", scheme->bv_val);
fprintf(stderr, " Stored password value: %s\n", passwd->bv_val);
fprintf(stderr, " -> Passwords %s\n", strcmp(sha256_hex_hash(cred->bv_val), passwd->bv_val) == 0 ? "match" : "do not match");
#endif
return (strcmp(sha256_hex_hash(cred->bv_val), passwd->bv_val));
}
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 )
{
#ifdef SLAPD_SHA2_DEBUG
fprintf(stderr, "Validating password\n");
fprintf(stderr, " Password to validate: %s\n", cred->bv_val);
fprintf(stderr, " Hashes to: %s\n", sha384_hex_hash(cred->bv_val));
fprintf(stderr, " Stored password scheme: %s\n", scheme->bv_val);
fprintf(stderr, " Stored password value: %s\n", passwd->bv_val);
fprintf(stderr, " -> Passwords %s\n", strcmp(sha384_hex_hash(cred->bv_val), passwd->bv_val) == 0 ? "match" : "do not match");
#endif
return (strcmp(sha384_hex_hash(cred->bv_val), passwd->bv_val));
}
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 )
{
#ifdef SLAPD_SHA2_DEBUG
fprintf(stderr, " Password to validate: %s\n", cred->bv_val);
fprintf(stderr, " Hashes to: %s\n", sha512_hex_hash(cred->bv_val));
fprintf(stderr, " Stored password scheme: %s\n", scheme->bv_val);
fprintf(stderr, " Stored password value: %s\n", passwd->bv_val);
fprintf(stderr, " -> Passwords %s\n", strcmp(sha512_hex_hash(cred->bv_val), passwd->bv_val) == 0 ? "match" : "do not match");
#endif
return (strcmp(sha512_hex_hash(cred->bv_val), passwd->bv_val));
}
const struct berval sha256scheme = BER_BVC("{SHA256}");
const struct berval sha384scheme = BER_BVC("{SHA384}");
const struct berval sha512scheme = BER_BVC("{SHA512}");
int init_module(int argc, char *argv[]) {
int result = 0;
result = lutil_passwd_add( (struct berval *)&sha256scheme, chk_sha256, NULL );
if (result != 0) return result;
result = lutil_passwd_add( (struct berval *)&sha384scheme, chk_sha384, NULL );
if (result != 0) return result;
result = lutil_passwd_add( (struct berval *)&sha512scheme, chk_sha512, NULL );
return result;
}