Greenbone Vulnerability Management Libraries 22.12.2
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
31static int
32is_prefix_supported (const char *id)
33{
34 return strcmp (PREFIX_DEFAULT, id) == 0;
35}
36
37// we assume something else than libxcrypt > 3.1; like UFC-crypt
38// libxcrypt sets a macro of crypt_gensalt_r to crypt_gensalt_rn
39// therefore we could use that mechanism to figure out if we are on
40// debian buster or newer.
41#ifndef EXTERNAL_CRYPT_GENSALT_R
42
43// used printables within salt
44const char ascii64[64] =
45 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
46
47/* Tries to get BUFLEN random bytes into BUF; returns 0 on success. */
48static int
49get_random (char *buf, size_t buflen)
50{
51 FILE *fp = fopen ("/dev/urandom", "r");
52 int result = 0;
53 if (fp == NULL)
54 {
55 result = -1;
56 goto exit;
57 }
58 size_t nread = fread (buf, 1, buflen, fp);
59 fclose (fp);
60 if (nread < buflen)
61 {
62 result = -2;
63 }
64
65exit:
66 return result;
67}
68/* Generate a string suitable for use as the setting when hashing a passphrase.
69 * PREFIX controls which hash function will be used,
70 * COUNT controls the computional cost of the hash,
71 * RBYTES should point to NRBYTES bytes of random data.
72 *
73 * If PREFIX is a NULL pointer, the current best default is used; if RBYTES
74 * is a NULL pointer, random data will be retrieved from the operating system
75 * if possible.
76 *
77 * The generated setting string is written to OUTPUT, which is OUTPUT_SIZE long.
78 * OUTPUT_SIZE must be at least CRYPT_GENSALT_OUTPUT_SIZE.
79 *
80 * */
81char *
82crypt_gensalt_r (const char *prefix, unsigned long count, const char *rbytes,
83 int nrbytes, char *output, int output_size);
84char *
85crypt_gensalt_r (const char *prefix, unsigned long count, const char *rbytes,
86 int nrbytes, char *output, int output_size)
87{
88 char *internal_rbytes = NULL;
89 unsigned int written = 0, used = 0;
90 unsigned long value = 0;
91 if ((rbytes != NULL && nrbytes < 3) || output_size < 16
92 || !is_prefix_supported (prefix))
93 {
94 output[0] = '*';
95 goto exit;
96 }
97 if (rbytes == NULL)
98 {
99 internal_rbytes = malloc (16);
100 if (get_random (internal_rbytes, 16) != 0)
101 {
102 output[0] = '*';
103 goto exit;
104 }
105 nrbytes = 16;
106 rbytes = internal_rbytes;
107 }
108 written = snprintf (output, output_size, "%srounds=%lu$",
109 prefix == NULL ? PREFIX_DEFAULT : prefix, count);
110 while (written + 5 < (unsigned int) output_size
111 && used + 3 < (unsigned int) nrbytes && (used * 4 / 3) < 16)
112 {
113 value = ((unsigned long) rbytes[used + 0] << 0)
114 | ((unsigned long) rbytes[used + 1] << 8)
115 | ((unsigned long) rbytes[used + 2] << 16);
116 output[written] = ascii64[value & 0x3f];
117 output[written + 1] = ascii64[(value >> 6) & 0x3f];
118 output[written + 2] = ascii64[(value >> 12) & 0x3f];
119 output[written + 3] = ascii64[(value >> 18) & 0x3f];
120 written += 4;
121 used += 3;
122 }
123 output[written] = '\0';
124exit:
125 if (internal_rbytes != NULL)
126 free (internal_rbytes);
127 return output[0] == '*' ? 0 : output;
128}
129
130#endif
131
132struct PBASettings *
133pba_init (const char *pepper, unsigned int pepper_size, unsigned int count,
134 char *prefix)
135{
136 unsigned int i = 0;
137 struct PBASettings *result = NULL;
138 if (pepper_size > MAX_PEPPER_SIZE)
139 goto exit;
140 if (prefix != NULL && !is_prefix_supported (prefix))
141 goto exit;
142 result = malloc (sizeof (struct PBASettings));
143 for (i = 0; i < MAX_PEPPER_SIZE; i++)
144 result->pepper[i] = pepper != NULL && i < pepper_size ? pepper[i] : 0;
145 result->count = count == 0 ? COUNT_DEFAULT : count;
146 result->prefix = prefix == NULL ? PREFIX_DEFAULT : prefix;
147exit:
148 return result;
149}
150
151void
152pba_finalize (struct PBASettings *settings)
153{
154 free (settings);
155}
156
157static int
158pba_is_phc_compliant (const char *setting)
159{
160 if (setting == NULL)
161 {
162 return 1;
163 }
164 return strlen (setting) > 1 && setting[0] == '$';
165}
166
167char *
168pba_hash (struct PBASettings *setting, const char *password)
169{
170 char *result = NULL, *settings = NULL, *tmp, *rslt;
171 int i;
172 struct crypt_data *data = NULL;
173
174 if (!setting || !password)
175 goto exit;
176 if (!is_prefix_supported (setting->prefix))
177 goto exit;
178 settings = malloc (CRYPT_GENSALT_OUTPUT_SIZE);
179 if (crypt_gensalt_r (setting->prefix, setting->count, NULL, 0, settings,
181 == NULL)
182 goto exit;
183 tmp = settings + strlen (settings) - 1;
184 for (i = MAX_PEPPER_SIZE - 1; i > -1; i--)
185 {
186 if (setting->pepper[i] != 0)
187 tmp[0] = setting->pepper[i];
188 tmp--;
189 }
190
191 data = calloc (1, sizeof (struct crypt_data));
192 rslt = crypt_r (password, settings, data);
193 if (rslt == NULL)
194 goto exit;
195 result = calloc (1, CRYPT_OUTPUT_SIZE);
196 memcpy (result, rslt, CRYPT_OUTPUT_SIZE);
197 // remove pepper, by jumping to begin of applied pepper within result
198 // and overriding it.
199 tmp = result + (tmp - settings);
200 for (i = 0; i < MAX_PEPPER_SIZE; i++)
201 {
202 tmp++;
203 if (setting->pepper[i] != 0)
204 tmp[0] = '0';
205 }
206exit:
207 if (data != NULL)
208 free (data);
209 if (settings != NULL)
210 free (settings);
211 return result;
212}
213
214enum pba_rc
215pba_verify_hash (const struct PBASettings *setting, const char *hash,
216 const char *password)
217{
218 char *cmp, *tmp = NULL;
219 struct crypt_data *data = NULL;
220 int i = 0;
221 enum pba_rc result = ERR;
222
223 char *invalid_hash = calloc (1, CRYPT_OUTPUT_SIZE);
224 memset (invalid_hash, 0, CRYPT_OUTPUT_SIZE);
225 memcpy (invalid_hash, INVALID_HASH, strlen (INVALID_HASH));
226
227 if (!setting)
228 goto exit;
229 if (!is_prefix_supported (setting->prefix))
230 goto exit;
231 if (pba_is_phc_compliant (hash) != 0)
232 {
233 int hash_size;
234 hash_size = hash ? strlen (hash) : strlen (invalid_hash);
235
236 data = calloc (1, sizeof (struct crypt_data));
237 // manipulate hash to reapply pepper
238 tmp = calloc (1, CRYPT_OUTPUT_SIZE);
239
240 memset (tmp, 0, CRYPT_OUTPUT_SIZE);
241 memcpy (tmp, hash ? hash : invalid_hash,
242 (hash_size < CRYPT_OUTPUT_SIZE) ? hash_size
243 : CRYPT_OUTPUT_SIZE - 1);
244 cmp = strrchr (tmp, '$');
245 for (i = MAX_PEPPER_SIZE - 1; i > -1; i--)
246 {
247 cmp--;
248 if (setting->pepper[i] != 0)
249 cmp[0] = setting->pepper[i];
250 }
251 // some crypt_r implementations cannot handle if password is a
252 // NULL pointer and run into SEGMENTATION faults.
253 // Therefore we set it to ""
254 cmp = crypt_r (password ? password : "", tmp, data);
255 if (strcmp (tmp, cmp) == 0)
256 result = VALID;
257 else
258 result = INVALID;
259 }
260 else
261 {
262 // assume authutils hash handling
263 // initialize gvm_auth utils if not already initialized
264 if (initialized == FALSE && gvm_auth_init () != 0)
265 {
266 goto exit;
267 }
268 // verify result of gvm_authenticate_classic
269 i = gvm_authenticate_classic (NULL, password, hash);
270 if (i == 0)
271 result = UPDATE_RECOMMENDED;
272 else if (i == 1)
273 result = INVALID;
274 }
275exit:
276 free (invalid_hash);
277 if (data != NULL)
278 free (data);
279 if (tmp != NULL)
280 free (tmp);
281 return result;
282}
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:272
int gvm_auth_init(void)
Initializes Gcrypt.
Definition authutils.c:108
static gboolean initialized
Flag whether the config file was read.
Definition authutils.c:33
static int pba_is_phc_compliant(const char *setting)
Definition passwordbasedauthentication.c:158
static int get_random(char *buf, size_t buflen)
Definition passwordbasedauthentication.c:49
#define INVALID_HASH
Definition passwordbasedauthentication.c:22
char * crypt_gensalt_r(const char *prefix, unsigned long count, const char *rbytes, int nrbytes, char *output, int output_size)
Definition passwordbasedauthentication.c:85
void pba_finalize(struct PBASettings *settings)
Definition passwordbasedauthentication.c:152
#define CRYPT_OUTPUT_SIZE
Definition passwordbasedauthentication.c:28
char * pba_hash(struct PBASettings *setting, const char *password)
Definition passwordbasedauthentication.c:168
struct PBASettings * pba_init(const char *pepper, unsigned int pepper_size, unsigned int count, char *prefix)
Definition passwordbasedauthentication.c:133
enum pba_rc pba_verify_hash(const struct PBASettings *setting, const char *hash, const char *password)
Definition passwordbasedauthentication.c:215
const char ascii64[64]
Definition passwordbasedauthentication.c:44
#define CRYPT_GENSALT_OUTPUT_SIZE
Definition passwordbasedauthentication.c:24
static int is_prefix_supported(const char *id)
Definition passwordbasedauthentication.c:32
#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