Greenbone Vulnerability Management Libraries 22.30.0
passwordbasedauthentication.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
7// internal usage to have access to gvm_auth initialized to verify if
8// initialization is needed
9#include "authutils.c"
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14// UFC_crypt defines crypt_r when only when __USE_GNU is set
15// this shouldn't affect other implementations
16#define __USE_GNU
17#include <crypt.h>
18// INVALID_HASH is used on verify when the given hash is a NULL pointer.
19// This is done to not directly jump to exit with a INVALID_HASH result
20// but rather keep calculating to make it a little bit harder to guess
21// if a user exists or not based on timing.
22#define INVALID_HASH "1234567890$"
23#ifndef CRYPT_GENSALT_OUTPUT_SIZE
24#define CRYPT_GENSALT_OUTPUT_SIZE 192
25#endif
26
27#ifndef CRYPT_OUTPUT_SIZE
28#define CRYPT_OUTPUT_SIZE 384
29#endif
30
38static int
39is_prefix_supported (const char *id)
40{
41 return strcmp (PREFIX_DEFAULT, id) == 0;
42}
43
44// we assume something else than libxcrypt > 3.1; like UFC-crypt
45// libxcrypt sets a macro of crypt_gensalt_r to crypt_gensalt_rn
46// therefore we could use that mechanism to figure out if we are on
47// debian buster or newer.
48#ifndef EXTERNAL_CRYPT_GENSALT_R
49
50// used printables within salt
51const char ascii64[] =
52 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
53
62static int
63get_random (char *buf, size_t buflen)
64{
65 FILE *fp = fopen ("/dev/urandom", "r");
66 int result = 0;
67 if (fp == NULL)
68 {
69 result = -1;
70 goto exit;
71 }
72 size_t nread = fread (buf, 1, buflen, fp);
73 fclose (fp);
74 if (nread < buflen)
75 {
76 result = -2;
77 }
78
79exit:
80 return result;
81}
82
100char *
101crypt_gensalt_r (const char *prefix, unsigned long count, const char *rbytes,
102 int nrbytes, char *output, int output_size);
103char *
104crypt_gensalt_r (const char *prefix, unsigned long count, const char *rbytes,
105 int nrbytes, char *output, int output_size)
106{
107 char *internal_rbytes = NULL;
108 unsigned int written = 0, used = 0;
109 unsigned long value = 0;
110 if ((rbytes != NULL && nrbytes < 3) || output_size < 16
111 || !is_prefix_supported (prefix))
112 {
113 output[0] = '*';
114 goto exit;
115 }
116 if (rbytes == NULL)
117 {
118 internal_rbytes = malloc (16);
119 if (get_random (internal_rbytes, 16) != 0)
120 {
121 output[0] = '*';
122 goto exit;
123 }
124 nrbytes = 16;
125 rbytes = internal_rbytes;
126 }
127 written = snprintf (output, output_size, "%srounds=%lu$",
128 prefix == NULL ? PREFIX_DEFAULT : prefix, count);
129 while (written + 5 < (unsigned int) output_size
130 && used + 3 < (unsigned int) nrbytes && (used * 4 / 3) < 16)
131 {
132 value = ((unsigned long) rbytes[used + 0] << 0)
133 | ((unsigned long) rbytes[used + 1] << 8)
134 | ((unsigned long) rbytes[used + 2] << 16);
135 output[written] = ascii64[value & 0x3f];
136 output[written + 1] = ascii64[(value >> 6) & 0x3f];
137 output[written + 2] = ascii64[(value >> 12) & 0x3f];
138 output[written + 3] = ascii64[(value >> 18) & 0x3f];
139 written += 4;
140 used += 3;
141 }
142 output[written] = '\0';
143exit:
144 if (internal_rbytes != NULL)
145 free (internal_rbytes);
146 return output[0] == '*' ? 0 : output;
147}
148
149#endif
150
164struct PBASettings *
165pba_init (const char *pepper, unsigned int pepper_size, unsigned int count,
166 char *prefix)
167{
168 unsigned int i = 0;
169 struct PBASettings *result = NULL;
170 if (pepper_size > MAX_PEPPER_SIZE)
171 goto exit;
172 if (prefix != NULL && !is_prefix_supported (prefix))
173 goto exit;
174 result = malloc (sizeof (struct PBASettings));
175 for (i = 0; i < MAX_PEPPER_SIZE; i++)
176 result->pepper[i] = pepper != NULL && i < pepper_size ? pepper[i] : 0;
177 result->count = count == 0 ? COUNT_DEFAULT : count;
178 result->prefix = prefix == NULL ? PREFIX_DEFAULT : prefix;
179exit:
180 return result;
181}
182
188void
189pba_finalize (struct PBASettings *settings)
190{
191 free (settings);
192}
193
201static int
202pba_is_phc_compliant (const char *setting)
203{
204 if (setting == NULL)
205 {
206 return 1;
207 }
208 return strlen (setting) > 1 && setting[0] == '$';
209}
210
219char *
220pba_hash (struct PBASettings *setting, const char *password)
221{
222 char *result = NULL, *settings = NULL, *tmp, *rslt;
223 int i;
224 struct crypt_data *data = NULL;
225
226 if (!setting || !password)
227 goto exit;
228 if (!is_prefix_supported (setting->prefix))
229 goto exit;
230 settings = malloc (CRYPT_GENSALT_OUTPUT_SIZE);
231 if (crypt_gensalt_r (setting->prefix, setting->count, NULL, 0, settings,
233 == NULL)
234 goto exit;
235 tmp = settings + strlen (settings) - 1;
236 for (i = MAX_PEPPER_SIZE - 1; i > -1; i--)
237 {
238 if (setting->pepper[i] != 0)
239 tmp[0] = setting->pepper[i];
240 tmp--;
241 }
242
243 data = calloc (1, sizeof (struct crypt_data));
244 rslt = crypt_r (password, settings, data);
245 if (rslt == NULL)
246 goto exit;
247 result = calloc (1, CRYPT_OUTPUT_SIZE);
248 memcpy (result, rslt, CRYPT_OUTPUT_SIZE);
249 // remove pepper, by jumping to begin of applied pepper within result
250 // and overriding it.
251 tmp = result + (tmp - settings);
252 for (i = 0; i < MAX_PEPPER_SIZE; i++)
253 {
254 tmp++;
255 if (setting->pepper[i] != 0)
256 tmp[0] = '0';
257 }
258exit:
259 if (data != NULL)
260 free (data);
261 if (settings != NULL)
262 free (settings);
263 return result;
264}
265
275enum pba_rc
276pba_verify_hash (const struct PBASettings *setting, const char *hash,
277 const char *password)
278{
279 char *cmp, *tmp = NULL;
280 struct crypt_data *data = NULL;
281 int i = 0;
282 enum pba_rc result = ERR;
283
284 char *invalid_hash = calloc (1, CRYPT_OUTPUT_SIZE);
285 memset (invalid_hash, 0, CRYPT_OUTPUT_SIZE);
286 memcpy (invalid_hash, INVALID_HASH, strlen (INVALID_HASH));
287
288 if (!setting)
289 goto exit;
290 if (!is_prefix_supported (setting->prefix))
291 goto exit;
292 if (pba_is_phc_compliant (hash) != 0)
293 {
294 int hash_size;
295 hash_size = hash ? strlen (hash) : strlen (invalid_hash);
296
297 data = calloc (1, sizeof (struct crypt_data));
298 // manipulate hash to reapply pepper
299 tmp = calloc (1, CRYPT_OUTPUT_SIZE);
300
301 memset (tmp, 0, CRYPT_OUTPUT_SIZE);
302 memcpy (tmp, hash ? hash : invalid_hash,
303 (hash_size < CRYPT_OUTPUT_SIZE) ? hash_size
304 : CRYPT_OUTPUT_SIZE - 1);
305 cmp = strrchr (tmp, '$');
306 for (i = MAX_PEPPER_SIZE - 1; i > -1; i--)
307 {
308 cmp--;
309 if (setting->pepper[i] != 0)
310 cmp[0] = setting->pepper[i];
311 }
312 // some crypt_r implementations cannot handle if password is a
313 // NULL pointer and run into SEGMENTATION faults.
314 // Therefore we set it to ""
315 cmp = crypt_r (password ? password : "", tmp, data);
316 if (strcmp (tmp, cmp) == 0)
317 result = VALID;
318 else
319 result = INVALID;
320 }
321 else
322 {
323 // assume authutils hash handling
324 // initialize gvm_auth utils if not already initialized
325 if (initialized == FALSE && gvm_auth_init () != 0)
326 {
327 goto exit;
328 }
329 // verify result of gvm_authenticate_classic
330 i = gvm_authenticate_classic (NULL, password, hash);
331 if (i == 0)
332 result = UPDATE_RECOMMENDED;
333 else if (i == 1)
334 result = INVALID;
335 }
336exit:
337 free (invalid_hash);
338 if (data != NULL)
339 free (data);
340 if (tmp != NULL)
341 free (tmp);
342 return result;
343}
Authentication mechanism(s).
int gvm_authenticate_classic(const gchar *username, const gchar *password, const gchar *hash_arg)
Authenticate a credential pair against user file contents.
Definition authutils.c:274
int gvm_auth_init(void)
Initializes Gcrypt.
Definition authutils.c:109
static gboolean initialized
Flag whether the config file was read.
Definition authutils.c:33
static int pba_is_phc_compliant(const char *setting)
Check if a PBA settings is PHC compliant.
Definition passwordbasedauthentication.c:202
static int get_random(char *buf, size_t buflen)
Try to get random bytes.
Definition passwordbasedauthentication.c:63
#define INVALID_HASH
Definition passwordbasedauthentication.c:22
const char ascii64[]
Definition passwordbasedauthentication.c:51
char * crypt_gensalt_r(const char *prefix, unsigned long count, const char *rbytes, int nrbytes, char *output, int output_size)
Generate string suitable for use as setting when hashing a passphrase.
Definition passwordbasedauthentication.c:104
void pba_finalize(struct PBASettings *settings)
Cleanup PBA settings.
Definition passwordbasedauthentication.c:189
#define CRYPT_OUTPUT_SIZE
Definition passwordbasedauthentication.c:28
char * pba_hash(struct PBASettings *setting, const char *password)
Create a password hash.
Definition passwordbasedauthentication.c:220
struct PBASettings * pba_init(const char *pepper, unsigned int pepper_size, unsigned int count, char *prefix)
Init PBA.
Definition passwordbasedauthentication.c:165
enum pba_rc pba_verify_hash(const struct PBASettings *setting, const char *hash, const char *password)
Verify a password hash.
Definition passwordbasedauthentication.c:276
#define CRYPT_GENSALT_OUTPUT_SIZE
Definition passwordbasedauthentication.c:24
static int is_prefix_supported(const char *id)
Check if a prefix is supported.
Definition passwordbasedauthentication.c:39
#define COUNT_DEFAULT
Definition passwordbasedauthentication.h:12
pba_rc
Definition passwordbasedauthentication.h:46
@ ERR
Definition passwordbasedauthentication.h:50
@ VALID
Definition passwordbasedauthentication.h:47
@ UPDATE_RECOMMENDED
Definition passwordbasedauthentication.h:48
@ INVALID
Definition passwordbasedauthentication.h:49
#define MAX_PEPPER_SIZE
Definition passwordbasedauthentication.h:10
#define PREFIX_DEFAULT
Definition passwordbasedauthentication.h:14
Definition passwordbasedauthentication.h:23
char pepper[MAX_PEPPER_SIZE]
Definition passwordbasedauthentication.h:24
char * prefix
Definition passwordbasedauthentication.h:26
unsigned int count
Definition passwordbasedauthentication.h:25