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
60 static unsigned long iterations = SLAPD_ARGON2_ITERATIONS;
61 static unsigned long memory = SLAPD_ARGON2_MEMORY;
62 static unsigned long parallelism = SLAPD_ARGON2_PARALLELISM;
63
64 const struct berval slapd_argon2_scheme = BER_BVC("{ARGON2}");
65
66 static int
slapd_argon2_hash(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)67 slapd_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
155 static int
slapd_argon2_verify(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)156 slapd_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
init_module(int argc,char * argv[])182 int 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