1/* $NetBSD: argon2.c,v 1.2 2021/08/14 16:15:02 christos Exp $ */ 2 3/* argon2.c - Password module for argon2 */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2017-2021 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19#include <sys/cdefs.h> 20__RCSID("$NetBSD: argon2.c,v 1.2 2021/08/14 16:15:02 christos Exp $"); 21 22#include "portable.h" 23#ifdef SLAPD_PWMOD_PW_ARGON2 24#include "ac/string.h" 25#include "lber_pvt.h" 26#include "lutil.h" 27 28#include "slap.h" 29 30#include <stdint.h> 31#include <stdlib.h> 32 33#ifdef HAVE_LIBARGON2 34#include <argon2.h> 35 36/* 37 * For now, we hardcode the default values from the argon2 command line tool 38 * (as of argon2 release 20161029) 39 */ 40#define SLAPD_ARGON2_ITERATIONS 3 41#define SLAPD_ARGON2_MEMORY (1 << 12) 42#define SLAPD_ARGON2_PARALLELISM 1 43#define SLAPD_ARGON2_SALT_LENGTH 16 44#define SLAPD_ARGON2_HASH_LENGTH 32 45 46#else /* !HAVE_LIBARGON2 */ 47#include <sodium.h> 48 49/* 50 * Or libsodium interactive settings 51 */ 52#define SLAPD_ARGON2_ITERATIONS crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE 53#define SLAPD_ARGON2_MEMORY (crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE / 1024) 54#define SLAPD_ARGON2_PARALLELISM 1 55#define SLAPD_ARGON2_SALT_LENGTH crypto_pwhash_argon2id_SALTBYTES 56#define SLAPD_ARGON2_HASH_LENGTH 32 57 58#endif 59 60static unsigned long iterations = SLAPD_ARGON2_ITERATIONS; 61static unsigned long memory = SLAPD_ARGON2_MEMORY; 62static unsigned long parallelism = SLAPD_ARGON2_PARALLELISM; 63 64const struct berval slapd_argon2_scheme = BER_BVC("{ARGON2}"); 65 66static int 67slapd_argon2_hash( 68 const struct berval *scheme, 69 const struct berval *passwd, 70 struct berval *hash, 71 const char **text ) 72{ 73 74 /* 75 * Duplicate these values here so future code which allows 76 * configuration has an easier time. 77 */ 78 uint32_t salt_length, hash_length; 79 char *p; 80 int rc = LUTIL_PASSWD_ERR; 81 82#ifdef HAVE_LIBARGON2 83 struct berval salt; 84 size_t encoded_length; 85 86 salt_length = SLAPD_ARGON2_SALT_LENGTH; 87 hash_length = SLAPD_ARGON2_HASH_LENGTH; 88 89 encoded_length = argon2_encodedlen( iterations, memory, parallelism, 90 salt_length, hash_length, Argon2_id ); 91 92 salt.bv_len = salt_length; 93 salt.bv_val = ber_memalloc( salt.bv_len ); 94 95 if ( salt.bv_val == NULL ) { 96 return LUTIL_PASSWD_ERR; 97 } 98 99 if ( lutil_entropy( (unsigned char*)salt.bv_val, salt.bv_len ) ) { 100 ber_memfree( salt.bv_val ); 101 return LUTIL_PASSWD_ERR; 102 } 103 104 p = hash->bv_val = ber_memalloc( scheme->bv_len + encoded_length ); 105 if ( p == NULL ) { 106 ber_memfree( salt.bv_val ); 107 return LUTIL_PASSWD_ERR; 108 } 109 110 AC_MEMCPY( p, scheme->bv_val, scheme->bv_len ); 111 p += scheme->bv_len; 112 113 /* 114 * Do the actual heavy lifting 115 */ 116 if ( argon2i_hash_encoded( iterations, memory, parallelism, 117 passwd->bv_val, passwd->bv_len, 118 salt.bv_val, salt_length, hash_length, 119 p, encoded_length ) == 0 ) { 120 rc = LUTIL_PASSWD_OK; 121 } 122 hash->bv_len = scheme->bv_len + encoded_length; 123 ber_memfree( salt.bv_val ); 124 125#else /* !HAVE_LIBARGON2 */ 126 /* Not exposed by libsodium 127 salt_length = SLAPD_ARGON2_SALT_LENGTH; 128 hash_length = SLAPD_ARGON2_HASH_LENGTH; 129 */ 130 131 p = hash->bv_val = ber_memalloc( scheme->bv_len + crypto_pwhash_STRBYTES ); 132 if ( p == NULL ) { 133 return LUTIL_PASSWD_ERR; 134 } 135 136 AC_MEMCPY( hash->bv_val, scheme->bv_val, scheme->bv_len ); 137 p += scheme->bv_len; 138 139 if ( crypto_pwhash_str_alg( p, passwd->bv_val, passwd->bv_len, 140 iterations, memory * 1024, 141 crypto_pwhash_ALG_ARGON2ID13 ) == 0 ) { 142 hash->bv_len = strlen( hash->bv_val ); 143 rc = LUTIL_PASSWD_OK; 144 } 145#endif 146 147 if ( rc ) { 148 ber_memfree( hash->bv_val ); 149 return LUTIL_PASSWD_ERR; 150 } 151 152 return LUTIL_PASSWD_OK; 153} 154 155static int 156slapd_argon2_verify( 157 const struct berval *scheme, 158 const struct berval *passwd, 159 const struct berval *cred, 160 const char **text ) 161{ 162 int rc = LUTIL_PASSWD_ERR; 163 164#ifdef HAVE_LIBARGON2 165 if ( strncmp( passwd->bv_val, "$argon2i$", STRLENOF("$argon2i$") ) == 0 ) { 166 rc = argon2i_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); 167 } else if ( strncmp( passwd->bv_val, "$argon2d$", STRLENOF("$argon2d$") ) == 0 ) { 168 rc = argon2d_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); 169 } else if ( strncmp( passwd->bv_val, "$argon2id$", STRLENOF("$argon2id$") ) == 0 ) { 170 rc = argon2id_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); 171 } 172#else /* !HAVE_LIBARGON2 */ 173 rc = crypto_pwhash_str_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); 174#endif 175 176 if ( rc ) { 177 return LUTIL_PASSWD_ERR; 178 } 179 return LUTIL_PASSWD_OK; 180} 181 182int init_module( int argc, char *argv[] ) 183{ 184 int i; 185 186#ifdef HAVE_LIBSODIUM 187 if ( sodium_init() == -1 ) { 188 return -1; 189 } 190#endif 191 192 for ( i=0; i < argc; i++ ) { 193 char *p; 194 unsigned long value; 195 196 switch ( *argv[i] ) { 197 case 'm': 198 p = strchr( argv[i], '=' ); 199 if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { 200 return -1; 201 } 202 memory = value; 203 break; 204 205 case 't': 206 p = strchr( argv[i], '=' ); 207 if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { 208 return -1; 209 } 210 iterations = value; 211 break; 212 213 case 'p': 214 p = strchr( argv[i], '=' ); 215 if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { 216 return -1; 217 } 218 parallelism = value; 219 break; 220 221 default: 222 return -1; 223 } 224 } 225 226#ifndef HAVE_LIBARGON2 227 /* At the moment, we can only use libargon2 to set parallelism for new 228 * hashes */ 229 if ( parallelism != SLAPD_ARGON2_PARALLELISM ) { 230 Debug( LDAP_DEBUG_ANY, "pw-argon2: " 231 "non-default parallelism only supported when linked with " 232 "libargon2, got p=%lu\n", 233 parallelism ); 234 235 if ( (slapMode & SLAP_MODE) != SLAP_TOOL_MODE || 236 slapTool == SLAPPASSWD || slapTool == SLAPTEST ) { 237 return 1; 238 } 239 } 240#endif 241 242 return lutil_passwd_add( (struct berval *)&slapd_argon2_scheme, 243 slapd_argon2_verify, slapd_argon2_hash ); 244} 245#endif /* SLAPD_OVER_PW_ARGON2 */ 246