gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

mechtools.c
Go to the documentation of this file.
1 /* mechtools.c --- Helper functions available for use by any mechanism.
2  * Copyright (C) 2010-2021 Simon Josefsson
3  *
4  * This file is part of GNU SASL Library.
5  *
6  * GNU SASL Library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GNU SASL Library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with GNU SASL Library; if not, write to the Free
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 /* Get specification. */
28 #include "mechtools.h"
29 
30 /* Get strcmp. */
31 #include <string.h>
32 
33 /* Get malloc, free. */
34 #include <stdlib.h>
35 
36 /* Get asprintf. */
37 #include <stdio.h>
38 
39 /* Get error codes. */
40 #include <gsasl.h>
41 
42 /* Gnulib gc.h */
43 #include <gc.h>
44 
45 /* Create in AUTHZID a newly allocated copy of STR where =2C is
46  replaced with , and =3D is replaced with =. Return GSASL_OK on
47  success, GSASL_MALLOC_ERROR on memory errors, GSASL_PARSE_ERRORS if
48  string contains any unencoded ',' or incorrectly encoded
49  sequence. */
50 static int
51 unescape_authzid (const char *str, size_t len, char **authzid)
52 {
53  char *p;
54 
55  if (memchr (str, ',', len) != NULL)
57 
58  p = *authzid = malloc (len + 1);
59  if (!p)
60  return GSASL_MALLOC_ERROR;
61 
62  while (len > 0 && *str)
63  {
64  if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
65  {
66  *p++ = ',';
67  str += 3;
68  len -= 3;
69  }
70  else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
71  {
72  *p++ = '=';
73  str += 3;
74  len -= 3;
75  }
76  else if (str[0] == '=')
77  {
78  free (*authzid);
79  *authzid = NULL;
81  }
82  else
83  {
84  *p++ = *str;
85  str++;
86  len--;
87  }
88  }
89  *p = '\0';
90 
91  return GSASL_OK;
92 }
93 
94 /* Parse the GS2 header containing flags and authorization identity.
95  Put authorization identity (or NULL) in AUTHZID and length of
96  header in HEADERLEN. Return GSASL_OK on success or an error
97  code.*/
98 int
99 _gsasl_parse_gs2_header (const char *data, size_t len,
100  char **authzid, size_t *headerlen)
101 {
102  char *authzid_endptr;
103 
104  if (len < 3)
106 
107  if (strncmp (data, "n,,", 3) == 0)
108  {
109  *headerlen = 3;
110  *authzid = NULL;
111  }
112  else if (strncmp (data, "n,a=", 4) == 0 &&
113  (authzid_endptr = memchr (data + 4, ',', len - 4)))
114  {
115  int res;
116 
117  if (authzid_endptr == NULL)
119 
120  res = unescape_authzid (data + 4, authzid_endptr - (data + 4), authzid);
121  if (res != GSASL_OK)
122  return res;
123 
124  *headerlen = authzid_endptr - data + 1;
125  }
126  else
128 
129  return GSASL_OK;
130 }
131 
132 /* Return newly allocated copy of STR with all occurrences of ','
133  replaced with =2C and '=' with '=3D', or return NULL on memory
134  allocation errors. */
135 static char *
136 escape_authzid (const char *str)
137 {
138  char *out = malloc (strlen (str) * 3 + 1);
139  char *p = out;
140 
141  if (!out)
142  return NULL;
143 
144  while (*str)
145  {
146  if (*str == ',')
147  {
148  memcpy (p, "=2C", 3);
149  p += 3;
150  }
151  else if (*str == '=')
152  {
153  memcpy (p, "=3D", 3);
154  p += 3;
155  }
156  else
157  {
158  *p = *str;
159  p++;
160  }
161  str++;
162  }
163  *p = '\0';
164 
165  return out;
166 }
167 
168 /* Generate a newly allocated GS2 header, escaping authzid
169  appropriately, and appending EXTRA. */
170 int
171 _gsasl_gs2_generate_header (bool nonstd, char cbflag,
172  const char *cbname, const char *authzid,
173  size_t extralen, const char *extra,
174  char **gs2h, size_t *gs2hlen)
175 {
176  int elen = extralen;
177  char *gs2cbflag;
178  int len;
179 
180  if (cbflag == 'p')
181  len = asprintf (&gs2cbflag, "p=%s", cbname);
182  else if (cbflag == 'n')
183  len = asprintf (&gs2cbflag, "n");
184  else if (cbflag == 'y')
185  len = asprintf (&gs2cbflag, "y");
186  else
187  /* internal caller error */
189 
190  if (len <= 0 || gs2cbflag == NULL)
191  return GSASL_MALLOC_ERROR;
192 
193  if (authzid)
194  {
195  char *escaped_authzid = escape_authzid (authzid);
196 
197  if (!escaped_authzid)
198  {
199  free (gs2cbflag);
200  return GSASL_MALLOC_ERROR;
201  }
202 
203  len = asprintf (gs2h, "%s%s,a=%s,%.*s", nonstd ? "F," : "",
204  gs2cbflag, escaped_authzid, elen, extra);
205 
206  free (escaped_authzid);
207  }
208  else
209  len = asprintf (gs2h, "%s%s,,%.*s", nonstd ? "F," : "", gs2cbflag,
210  elen, extra);
211 
212  free (gs2cbflag);
213 
214  if (len <= 0 || gs2h == NULL)
215  return GSASL_MALLOC_ERROR;
216 
217  *gs2hlen = len;
218 
219  return GSASL_OK;
220 }
221 
222 /* Hex encode binary octet array IN of INLEN length, putting the hex
223  encoded string in OUT which must have room for the data and
224  terminating zero, i.e., 2*INLEN+1. */
225 void
226 _gsasl_hex_encode (const char *in, size_t inlen, char *out)
227 {
228  size_t i;
229  const char *p = in;
230 
231  for (i = 0; i < 2 * inlen;)
232  {
233  unsigned char c = *p++;
234  out[i++] = "0123456789abcdef"[c >> 4];
235  out[i++] = "0123456789abcdef"[c & 0x0f];
236  }
237 
238  out[i] = '\0';
239 }
240 
241 static char
242 hexdigit_to_char (char hexdigit)
243 {
244  if (hexdigit >= '0' && hexdigit <= '9')
245  return hexdigit - '0';
246  if (hexdigit >= 'a' && hexdigit <= 'f')
247  return hexdigit - 'a' + 10;
248  return 0;
249 }
250 
251 static char
252 hex_to_char (char u, char l)
253 {
254  return (char) (((unsigned char) hexdigit_to_char (u)) * 16
255  + hexdigit_to_char (l));
256 }
257 
258 /* Hex decode string HEXSTR containing only hex "0-9A-F" characters
259  into binary buffer BIN which must have room for data, i.e., strlen
260  (hexstr)/2. */
261 void
262 _gsasl_hex_decode (const char *hexstr, char *bin)
263 {
264  while (*hexstr)
265  {
266  *bin = hex_to_char (hexstr[0], hexstr[1]);
267  hexstr += 2;
268  bin++;
269  }
270 }
271 
272 /* Return whether string contains hex "0-9a-f" symbols only. */
273 bool
274 _gsasl_hex_p (const char *hexstr)
275 {
276  static const char hexalpha[] = "0123456789abcdef";
277 
278  for (; *hexstr; hexstr++)
279  if (strchr (hexalpha, *hexstr) == NULL)
280  return false;
281 
282  return true;
283 }
284 
285 /*
286  * _gsasl_hash:
287  * @hash: a %Gsasl_hash hash algorithm identifier, e.g. #GSASL_HASH_SHA256.
288  * @in: input character array of data to hash.
289  * @inlen: length of input character array of data to hash.
290  * @outhash: buffer to hold hash of data.
291  *
292  * Compute hash of data using the @hash algorithm. The @outhash
293  * buffer must have room to hold the size of @hash's output; a safe
294  * value that have room for all possible outputs is
295  * %GSASL_HASH_MAX_SIZE.
296  *
297  * Return value: Returns %GSASL_OK iff successful.
298  *
299  * Since: 1.10
300  **/
301 int
302 _gsasl_hash (Gsasl_hash hash, const char *in, size_t inlen, char *outhash)
303 {
304  int rc;
305 
306  if (hash == GSASL_HASH_SHA1)
307  rc = gc_sha1 (in, inlen, outhash);
308  else if (hash == GSASL_HASH_SHA256)
309  rc = gc_sha256 (in, inlen, outhash);
310  else
312 
313  return rc;
314 }
315 
316 /*
317  * _gsasl_hmac:
318  * @hash: a %Gsasl_hash hash algorithm identifier, e.g. #GSASL_HASH_SHA256.
319  * @key: input character array with key to use.
320  * @keylen: length of input character array with key to use.
321  * @in: input character array of data to hash.
322  * @inlen: length of input character array of data to hash.
323  * @outhash: buffer to hold keyed hash of data.
324  *
325  * Compute keyed checksum of data using HMAC for the @hash algorithm.
326  * The @outhash buffer must have room to hold the size of @hash's
327  * output; a safe value that have room for all possible outputs is
328  * %GSASL_HASH_MAX_SIZE.
329  *
330  * Return value: Returns %GSASL_OK iff successful.
331  *
332  * Since: 1.10
333  **/
334 int
336  const char *key, size_t keylen,
337  const char *in, size_t inlen, char *outhash)
338 {
339  int rc;
340 
341  if (hash == GSASL_HASH_SHA1)
342  rc = gc_hmac_sha1 (key, keylen, in, inlen, outhash);
343  else if (hash == GSASL_HASH_SHA256)
344  rc = gc_hmac_sha256 (key, keylen, in, inlen, outhash);
345  else
347 
348  return rc;
349 }
350 
351 /*
352  * gsasl_pbkdf2:
353  * @hash: a %Gsasl_hash hash algorithm identifier.
354  * @password: input character array with password to use.
355  * @passwordlen: length of @password.
356  * @salt: input character array with salt, typically a short string.
357  * @saltlen: length of @salt.
358  * @c: iteration count, typically larger than 4096.
359  * @dk: output buffer, must be able to hold @dklen.
360  * @dklen: length of output buffer, or 0 to indicate @hash output size.
361  *
362  * Hash and salt password according to PBKDF2 algorithm with the @hash
363  * function used in HMAC. This function can be used to prepare SCRAM
364  * SaltedPassword values for the %GSASL_SCRAM_SALTED_PASSWORD
365  * property. Note that password should normally be prepared using
366  * gsasl_saslprep(GSASL_ALLOW_UNASSIGNED) before calling this
367  * function.
368  *
369  * Return value: Returns %GSASL_OK if successful, or error code.
370  *
371  * Since: 1.10
372  **/
373 int
375  const char *password, size_t passwordlen,
376  const char *salt, size_t saltlen,
377  unsigned int c, char *dk, size_t dklen)
378 {
379  int rc;
380  Gc_hash gch;
381 
382  switch (hash)
383  {
384  case GSASL_HASH_SHA1:
385  if (dklen == 0)
386  dklen = GSASL_HASH_SHA1_SIZE;
387  gch = GC_SHA1;
388  break;
389 
390  case GSASL_HASH_SHA256:
391  if (dklen == 0)
392  dklen = GSASL_HASH_SHA256_SIZE;
393  gch = GC_SHA256;
394  break;
395 
396  default:
397  return GSASL_CRYPTO_ERROR;
398  }
399 
400  rc = gc_pbkdf2_hmac (gch, password, passwordlen,
401  salt, saltlen, c, dk, dklen);
402  if (rc != GC_OK)
403  return GSASL_CRYPTO_ERROR;
404 
405  return GSASL_OK;
406 }
Gc_rc gc_hmac_sha1(const void *key, size_t keylen, const void *in, size_t inlen, char *resbuf)
Definition: gc-gnulib.c:1037
Gc_rc gc_sha1(const void *in, size_t inlen, void *resbuf)
Definition: gc-gnulib.c:991
Gc_rc gc_pbkdf2_hmac(Gc_hash hash, const char *P, size_t Plen, const char *S, size_t Slen, unsigned int c, char *DK, size_t dkLen)
Definition: gc-pbkdf2.c:102
Gc_hash
Definition: gc.h:41
@ GC_SHA256
Definition: gc.h:47
@ GC_SHA1
Definition: gc.h:44
Gc_rc gc_hmac_sha256(const void *key, size_t keylen, const void *in, size_t inlen, char *resbuf)
@ GC_OK
Definition: gc.h:27
Gc_rc gc_sha256(const void *in, size_t inlen, void *resbuf)
int asprintf(char **resultp, const char *format,...)
Definition: asprintf.c:30
void * memchr(void const *s, int c_in, size_t n)
Definition: memchr.c:59
#define NULL
Definition: stddef.in.h:72
Gsasl_hash
Definition: gsasl.h:471
@ GSASL_HASH_SHA1
Definition: gsasl.h:473
@ GSASL_HASH_SHA256
Definition: gsasl.h:474
@ GSASL_OK
Definition: gsasl.h:171
@ GSASL_MALLOC_ERROR
Definition: gsasl.h:175
@ GSASL_MECHANISM_PARSE_ERROR
Definition: gsasl.h:179
@ GSASL_CRYPTO_ERROR
Definition: gsasl.h:177
@ GSASL_HASH_SHA1_SIZE
Definition: gsasl.h:480
@ GSASL_HASH_SHA256_SIZE
Definition: gsasl.h:481
int rc
Definition: error.c:42
unsigned char c
int res
Definition: mbrtowc-impl.h:45
const char * p
Definition: mbrtowc-impl.h:42
void _gsasl_hex_decode(const char *hexstr, char *bin)
Definition: mechtools.c:262
int _gsasl_hmac(Gsasl_hash hash, const char *key, size_t keylen, const char *in, size_t inlen, char *outhash)
Definition: mechtools.c:335
int _gsasl_gs2_generate_header(signed char nonstd, char cbflag, const char *cbname, const char *authzid, size_t extralen, const char *extra, char **gs2h, size_t *gs2hlen)
Definition: mechtools.c:171
int _gsasl_parse_gs2_header(const char *data, size_t len, char **authzid, size_t *headerlen)
Definition: mechtools.c:99
signed char _gsasl_hex_p(const char *hexstr)
Definition: mechtools.c:274
static char * escape_authzid(const char *str)
Definition: mechtools.c:136
int _gsasl_pbkdf2(Gsasl_hash hash, const char *password, size_t passwordlen, const char *salt, size_t saltlen, unsigned int c, char *dk, size_t dklen)
Definition: mechtools.c:374
int _gsasl_hash(Gsasl_hash hash, const char *in, size_t inlen, char *outhash)
Definition: mechtools.c:302
static char hexdigit_to_char(char hexdigit)
Definition: mechtools.c:242
void _gsasl_hex_encode(const char *in, size_t inlen, char *out)
Definition: mechtools.c:226
static int unescape_authzid(const char *str, size_t len, char **authzid)
Definition: mechtools.c:51
static char hex_to_char(char u, char l)
Definition: mechtools.c:252