xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/pwmods/argon2.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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