mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-09 02:52:04 +08:00
ITS#7742 New: PBKDF2 module
Signed-off-by: HAMANO Tsukasa <hamano@osstech.co.jp>
This commit is contained in:
parent
ce84b177b6
commit
0fbabb115b
48
contrib/slapd-modules/passwd/pbkdf2/Makefile
Normal file
48
contrib/slapd-modules/passwd/pbkdf2/Makefile
Normal file
@ -0,0 +1,48 @@
|
||||
# $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
|
||||
prefix=`grep -e "^prefix =" $(LDAP_BUILD)/Makefile | cut -d= -f2`
|
||||
|
||||
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
|
87
contrib/slapd-modules/passwd/pbkdf2/README
Normal file
87
contrib/slapd-modules/passwd/pbkdf2/README
Normal file
@ -0,0 +1,87 @@
|
||||
PBKDF2 for OpenLDAP
|
||||
=======================
|
||||
|
||||
pw-pbkdf2.c provides support for PBKDF2 key derivation functions in
|
||||
OpenLDAP.
|
||||
|
||||
# Requirements
|
||||
|
||||
* OpenSSL 1.0.0 or later
|
||||
|
||||
# Installations
|
||||
|
||||
$ cd <OPENLDAP_BUILD_DIR>/contrib/slapd-modules/passwd/
|
||||
$ git clone https://github.com/hamano/openldap-pbkdf2.git
|
||||
$ cd openldap-pbkdf2/
|
||||
$ make
|
||||
# make install
|
||||
|
||||
# Configuration
|
||||
|
||||
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}
|
||||
|
||||
# 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-2013 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>
|
295
contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c
Normal file
295
contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c
Normal file
@ -0,0 +1,295 @@
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2009-2013 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 <openssl/evp.h>
|
||||
|
||||
#define PBKDF2_SALT_SIZE 16
|
||||
#define PBKDF2_DK_SIZE 20
|
||||
#define PBKDF2_ITERATION 60000
|
||||
|
||||
const struct berval pbkdf2scheme = BER_BVC("{PBKDF2}");
|
||||
|
||||
/*
|
||||
* 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;
|
||||
while(*p++){
|
||||
if(*p == '+'){
|
||||
*p = '.';
|
||||
}
|
||||
if(*p == '='){
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
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;
|
||||
char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
|
||||
char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_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->bv_len = asprintf(&msg->bv_val, "%s%d$%s$%s",
|
||||
sc->bv_val, iteration,
|
||||
salt_b64, dk_b64);
|
||||
if(msg->bv_len < 0){
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
#ifdef SLAPD_PBKDF2_DEBUG
|
||||
printf(" Output:\t%s\n", msg->bv_val);
|
||||
#endif
|
||||
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_DK_SIZE];
|
||||
struct berval dk;
|
||||
int iteration = PBKDF2_ITERATION;
|
||||
|
||||
dk.bv_val = (char *)dk_value;
|
||||
dk.bv_len = PBKDF2_DK_SIZE;
|
||||
salt.bv_val = (char *)salt_value;
|
||||
salt.bv_len = sizeof(salt_value);
|
||||
|
||||
if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
if(!PKCS5_PBKDF2_HMAC_SHA1(passwd->bv_val, passwd->bv_len,
|
||||
(unsigned char *)salt.bv_val, salt.bv_len,
|
||||
iteration, PBKDF2_DK_SIZE, dk_value)){
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
#ifdef SLAPD_PBKDF2_DEBUG
|
||||
printf("DEBUG pbkdf2_encrypt()\n");
|
||||
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<PBKDF2_DK_SIZE; i++){
|
||||
printf("%02x", dk_value[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
return pbkdf2_format(scheme, iteration, &salt, &dk, msg);
|
||||
}
|
||||
|
||||
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_DK_SIZE + 1 in lutil_b64_pton. */
|
||||
unsigned char dk_value[PBKDF2_DK_SIZE + 1];
|
||||
char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_DK_SIZE) + 1];
|
||||
unsigned char input_dk_value[PBKDF2_DK_SIZE];
|
||||
|
||||
#ifdef SLAPD_PBKDF2_DEBUG
|
||||
printf("DEBUG pbkdf2_check()\n");
|
||||
printf(" Stored Value:\t%s\n", passwd->bv_val);
|
||||
printf(" Input Cred:\t%s\n", cred->bv_val);
|
||||
#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_DK_SIZE + 1 in lutil_b64_pton. */
|
||||
rc = lutil_b64_pton(dk_b64, dk_value, PBKDF2_DK_SIZE + 1);
|
||||
if(rc < 0){
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
/* consistency check */
|
||||
if(rc != PBKDF2_DK_SIZE){
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
if(!PKCS5_PBKDF2_HMAC_SHA1(cred->bv_val, cred->bv_len,
|
||||
salt_value, PBKDF2_SALT_SIZE,
|
||||
iteration, PBKDF2_DK_SIZE, input_dk_value)){
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
|
||||
rc = memcmp(dk_value, input_dk_value, PBKDF2_DK_SIZE);
|
||||
#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<PBKDF2_DK_SIZE; i++){
|
||||
printf("%02x", dk_value[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf(" Input DK:\t");
|
||||
for(i=0; i<PBKDF2_DK_SIZE; 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 *)&pbkdf2scheme,
|
||||
pbkdf2_check, pbkdf2_encrypt);
|
||||
if(!rc) return rc;
|
||||
|
||||
/* TODO: add {PBKDF2-SHA256} and {PBKDF2-SHA512} schemes. */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* indent-tabs-mode: t
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
Loading…
Reference in New Issue
Block a user