Noise-C
 All Data Structures Files Functions Variables Typedefs Macros Groups Pages
names.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2016 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "internal.h"
24 #include <string.h>
25 
48 /* List of all known algorithm names and the corresponding identifiers */
49 typedef struct
50 {
51  int id;
52  const char *name;
53  size_t name_len;
54 
55 } NoiseIdMapping;
56 static NoiseIdMapping const algorithm_names[] = {
57  /* Cipher algorithsm */
58  {NOISE_CIPHER_CHACHAPOLY, "ChaChaPoly", 10},
59  {NOISE_CIPHER_AESGCM, "AESGCM", 6},
60 
61  /* Hash algorithms */
62  {NOISE_HASH_BLAKE2s, "BLAKE2s", 7},
63  {NOISE_HASH_BLAKE2b, "BLAKE2b", 7},
64  {NOISE_HASH_SHA256, "SHA256", 6},
65  {NOISE_HASH_SHA512, "SHA512", 6},
66 
67  /* Diffie-Hellman algorithms */
68  {NOISE_DH_CURVE25519, "25519", 5},
69  {NOISE_DH_CURVE448, "448", 3},
70  {NOISE_DH_NEWHOPE, "NewHope", 7},
71 
72  /* Handshake patterns */
73  {NOISE_PATTERN_N, "N", 1},
74  {NOISE_PATTERN_X, "X", 1},
75  {NOISE_PATTERN_K, "K", 1},
76  {NOISE_PATTERN_NN, "NN", 2},
77  {NOISE_PATTERN_NK, "NK", 2},
78  {NOISE_PATTERN_NX, "NX", 2},
79  {NOISE_PATTERN_XN, "XN", 2},
80  {NOISE_PATTERN_XK, "XK", 2},
81  {NOISE_PATTERN_XX, "XX", 2},
82  {NOISE_PATTERN_KN, "KN", 2},
83  {NOISE_PATTERN_KK, "KK", 2},
84  {NOISE_PATTERN_KX, "KX", 2},
85  {NOISE_PATTERN_IN, "IN", 2},
86  {NOISE_PATTERN_IK, "IK", 2},
87  {NOISE_PATTERN_IX, "IX", 2},
88  {NOISE_PATTERN_XX_FALLBACK, "XXfallback", 10},
89  {NOISE_PATTERN_X_NOIDH, "Xnoidh", 6},
90  {NOISE_PATTERN_NX_NOIDH, "NXnoidh", 7},
91  {NOISE_PATTERN_XX_NOIDH, "XXnoidh", 7},
92  {NOISE_PATTERN_KX_NOIDH, "KXnoidh", 7},
93  {NOISE_PATTERN_IK_NOIDH, "IKnoidh", 7},
94  {NOISE_PATTERN_IX_NOIDH, "IXnoidh", 7},
95  {NOISE_PATTERN_NN_HFS, "NNhfs", 5},
96  {NOISE_PATTERN_NK_HFS, "NKhfs", 5},
97  {NOISE_PATTERN_NX_HFS, "NXhfs", 5},
98  {NOISE_PATTERN_XN_HFS, "XNhfs", 5},
99  {NOISE_PATTERN_XK_HFS, "XKhfs", 5},
100  {NOISE_PATTERN_XX_HFS, "XXhfs", 5},
101  {NOISE_PATTERN_KN_HFS, "KNhfs", 5},
102  {NOISE_PATTERN_KK_HFS, "KKhfs", 5},
103  {NOISE_PATTERN_KX_HFS, "KXhfs", 5},
104  {NOISE_PATTERN_IN_HFS, "INhfs", 5},
105  {NOISE_PATTERN_IK_HFS, "IKhfs", 5},
106  {NOISE_PATTERN_IX_HFS, "IXhfs", 5},
107  {NOISE_PATTERN_XX_FALLBACK_HFS, "XXfallback+hfs", 14},
108  {NOISE_PATTERN_NX_NOIDH_HFS,"NXnoidh+hfs", 11},
109  {NOISE_PATTERN_XX_NOIDH_HFS,"XXnoidh+hfs", 11},
110  {NOISE_PATTERN_KX_NOIDH_HFS,"KXnoidh+hfs", 11},
111  {NOISE_PATTERN_IK_NOIDH_HFS,"IKnoidh+hfs", 11},
112  {NOISE_PATTERN_IX_NOIDH_HFS,"IXnoidh+hfs", 11},
113 
114  /* Protocol name prefixes */
115  {NOISE_PREFIX_STANDARD, "Noise", 5},
116  {NOISE_PREFIX_PSK, "NoisePSK", 8},
117 
118  /* Signature algorithms */
119  {NOISE_SIGN_ED25519, "Ed25519", 7},
120 
121  /* Terminator for the list */
122  {0, 0, 0}
123 };
124 
146 int noise_name_to_id(int category, const char *name, size_t name_len)
147 {
148  const NoiseIdMapping *mapping = algorithm_names;
149  int mask = category ? NOISE_ID(0xFF, 0) : 0;
150  if (!name)
151  return 0;
152  while (mapping->name_len) {
153  if ((mapping->id & mask) == category) {
154  if (mapping->name_len == name_len &&
155  !memcmp(mapping->name, name, name_len)) {
156  return mapping->id;
157  }
158  }
159  ++mapping;
160  }
161  return 0;
162 }
163 
182 const char *noise_id_to_name(int category, int id)
183 {
184  const NoiseIdMapping *mapping = algorithm_names;
185  int mask = category ? NOISE_ID(0xFF, 0) : 0;
186  if (id <= 0)
187  return 0;
188  while (mapping->name_len) {
189  if ((mapping->id & mask) == category) {
190  if (mapping->id == id)
191  return mapping->name;
192  }
193  ++mapping;
194  }
195  return 0;
196 }
197 
214 static int noise_protocol_parse_field
215  (int category, const char *name, size_t len, size_t *posn,
216  int is_last, int *ok)
217 {
218  size_t start, field_len;
219  int id;
220 
221  /* If the parse already failed, then nothing further to do */
222  if (!(*ok))
223  return 0;
224 
225  /* Find the start and end of the current field */
226  start = *posn;
227  while (*posn < len && name[*posn] != '_')
228  ++(*posn);
229  field_len = *posn - start;
230 
231  /* If this is the last field, we should be at the end
232  of the string. Otherwise there should be a '_' here */
233  if (is_last) {
234  if (*posn < len) {
235  *ok = 0;
236  return 0;
237  }
238  } else {
239  if (*posn >= len) {
240  *ok = 0;
241  return 0;
242  }
243  ++(*posn); /* Skip the '_' */
244  }
245 
246  /* Look up the name in the current category */
247  id = noise_name_to_id(category, name + start, field_len);
248  if (!id)
249  *ok = 0;
250  return id;
251 }
252 
270 static int noise_protocol_parse_dual_field
271  (int category, const char *name, size_t len,
272  size_t *posn, int *second_id, int *ok)
273 {
274  size_t start, field_len;
275  int first_id;
276 
277  /* Clear the second identifier before we start in case we don't find one */
278  *second_id = 0;
279 
280  /* If the parse already failed, then nothing further to do */
281  if (!(*ok))
282  return 0;
283 
284  /* Find the start and end of the current field */
285  start = *posn;
286  while (*posn < len && name[*posn] != '_' && name[*posn] != '+')
287  ++(*posn);
288  if (*posn >= len) {
289  /* Should be terminated with either '_' or '+' */
290  *ok = 0;
291  return 0;
292  }
293  field_len = *posn - start;
294 
295  /* Look up the first name in the current category */
296  first_id = noise_name_to_id(category, name + start, field_len);
297  if (!first_id) {
298  *ok = 0;
299  return 0;
300  }
301 
302  /* If the next character is '_', then we are finished */
303  if (name[*posn] == '_') {
304  ++(*posn);
305  return first_id;
306  }
307 
308  /* Parse the rest of the field until the next '_' as the second id */
309  ++(*posn);
310  *second_id = noise_protocol_parse_field(category, name, len, posn, 0, ok);
311  if (*second_id)
312  return first_id;
313  else
314  return 0;
315 }
316 
332  (NoiseProtocolId *id, const char *name, size_t name_len)
333 {
334  size_t posn;
335  int ok;
336 
337  /* Bail out if the parameters are incorrect */
338  if (!id || !name)
340 
341  /* Parse underscore-separated fields from the name */
342  posn = 0;
343  ok = 1;
344  memset(id, 0, sizeof(NoiseProtocolId));
345  id->prefix_id = noise_protocol_parse_field
346  (NOISE_PREFIX_CATEGORY, name, name_len, &posn, 0, &ok);
347  id->pattern_id = noise_protocol_parse_field
348  (NOISE_PATTERN_CATEGORY, name, name_len, &posn, 0, &ok);
349  id->dh_id = noise_protocol_parse_dual_field
350  (NOISE_DH_CATEGORY, name, name_len, &posn, &(id->hybrid_id), &ok);
351  id->cipher_id = noise_protocol_parse_field
352  (NOISE_CIPHER_CATEGORY, name, name_len, &posn, 0, &ok);
353  id->hash_id = noise_protocol_parse_field
354  (NOISE_HASH_CATEGORY, name, name_len, &posn, 1, &ok);
355 
356  /* If there was a parse error, then clear everything */
357  if (!ok) {
358  memset(id, 0, sizeof(NoiseProtocolId));
360  }
361 
362  /* The name has been parsed */
363  return NOISE_ERROR_NONE;
364 }
365 
379 static void noise_protocol_format_field
380  (int category, int id, char *name, size_t len, size_t *posn,
381  int is_last, int *err)
382 {
383  const char *alg_name;
384  size_t alg_len;
385 
386  /* If the formatting already failed, then bail out now */
387  if (*err != NOISE_ERROR_NONE)
388  return;
389 
390  /* Look up the name for the algorithm identifier */
391  alg_name = noise_id_to_name(category, id);
392  if (!alg_name) {
393  *err = NOISE_ERROR_UNKNOWN_ID;
394  return;
395  }
396  alg_len = strlen(alg_name);
397 
398  /* Will the name fit into the buffer, followed by either '_' or '\0'? */
399  if (alg_len >= (len - *posn)) {
401  return;
402  }
403  memcpy(name + *posn, alg_name, alg_len);
404  *posn += alg_len;
405 
406  /* Add either a separator or a terminator */
407  if (!is_last)
408  name[(*posn)++] = '_';
409  else
410  name[*posn] = '\0';
411 }
412 
437  (char *name, size_t name_len, const NoiseProtocolId *id)
438 {
439  size_t posn;
440  int err;
441 
442  /* Bail out if the parameters are incorrect */
443  if (!id) {
444  if (name && name_len)
445  *name = '\0'; /* Just to be safe */
447  }
448  if (!name)
450  if (!name_len)
452 
453  /* Format the fields into the return buffer */
454  posn = 0;
455  err = NOISE_ERROR_NONE;
456  noise_protocol_format_field
457  (NOISE_PREFIX_CATEGORY, id->prefix_id, name, name_len, &posn, 0, &err);
458  noise_protocol_format_field
459  (NOISE_PATTERN_CATEGORY, id->pattern_id, name, name_len, &posn, 0, &err);
460  if (!id->hybrid_id) {
461  noise_protocol_format_field
462  (NOISE_DH_CATEGORY, id->dh_id, name, name_len, &posn, 0, &err);
463  } else {
464  /* Format the DH names as "dh_id+hybrid_id"; e.g. "25519+NewHope" */
465  noise_protocol_format_field
466  (NOISE_DH_CATEGORY, id->dh_id, name, name_len, &posn, 1, &err);
467  if (err == NOISE_ERROR_NONE) {
468  if ((posn + 1) < name_len)
469  name[posn++] = '+';
470  else
472  }
473  noise_protocol_format_field
474  (NOISE_DH_CATEGORY, id->hybrid_id, name, name_len, &posn, 0, &err);
475  }
476  noise_protocol_format_field
477  (NOISE_CIPHER_CATEGORY, id->cipher_id, name, name_len, &posn, 0, &err);
478  noise_protocol_format_field
479  (NOISE_HASH_CATEGORY, id->hash_id, name, name_len, &posn, 1, &err);
480 
481  /* The reserved identifiers must be zero. We don't know how to
482  format reserved identifiers other than zero */
483  for (posn = 0; posn < (sizeof(id->reserved) / sizeof(id->reserved[0])) &&
484  err == NOISE_ERROR_NONE; ++posn) {
485  if (id->reserved[posn] != 0)
487  }
488 
489  /* If an error occurred, then clear the buffer just to be safe */
490  if (err != NOISE_ERROR_NONE)
491  *name = '\0';
492 
493  /* Done */
494  return err;
495 }
496 
#define NOISE_PATTERN_XX
Handshake pattern identifier for "XX".
Noise protocol name broken out into separate identifier fields.
Definition: names.h:33
#define NOISE_PATTERN_NX_NOIDH_HFS
Definition: constants.h:93
#define NOISE_PATTERN_NX_HFS
Definition: constants.h:82
int cipher_id
Definition: names.h:38
#define NOISE_ERROR_UNKNOWN_ID
Algorithm identifier is unknown.
#define NOISE_PATTERN_KX
Handshake pattern identifier for "KX".
#define NOISE_PREFIX_CATEGORY
Category for protocol prefixes.
#define NOISE_PATTERN_KX_NOIDH
Handshake pattern identifier for "KXnoidh".
#define NOISE_PATTERN_KX_HFS
Definition: constants.h:88
#define NOISE_ERROR_INVALID_PARAM
Invalid parameter to function; e.g. a NULL value.
#define NOISE_PATTERN_IK_HFS
Definition: constants.h:90
#define NOISE_PATTERN_IK
Handshake pattern identifier for "IK".
#define NOISE_ERROR_NONE
Success, no error.
#define NOISE_SIGN_ED25519
Signature algorithm identifier for "Ed25519".
#define NOISE_CIPHER_AESGCM
Cipher identifier for "AESGCM".
int reserved[4]
Definition: names.h:41
int noise_protocol_name_to_id(NoiseProtocolId *id, const char *name, size_t name_len)
Parses a protocol name into a set of identifiers for the algorithms that are indicated by the name...
Definition: names.c:332
#define NOISE_PATTERN_IX
Handshake pattern identifier for "IX".
#define NOISE_PATTERN_NN_HFS
Definition: constants.h:80
#define NOISE_PATTERN_XN
Handshake pattern identifier for "XN".
#define NOISE_HASH_BLAKE2b
Hash identifier for "BLAKE2b".
#define NOISE_HASH_CATEGORY
Category for hash algorithms.
#define NOISE_PATTERN_KK_HFS
Definition: constants.h:87
#define NOISE_PATTERN_XK
Handshake pattern identifier for "XK".
#define NOISE_PATTERN_NK
Handshake pattern identifier for "NK".
#define NOISE_PATTERN_XN_HFS
Definition: constants.h:83
#define NOISE_DH_CATEGORY
Category for Diffie-Hellman algorithms.
#define NOISE_PATTERN_XK_HFS
Definition: constants.h:84
#define NOISE_DH_CURVE448
Diffie-Hellman identifier for "448".
#define NOISE_PATTERN_KK
Handshake pattern identifier for "KK".
#define NOISE_PATTERN_NK_HFS
Definition: constants.h:81
#define NOISE_ERROR_UNKNOWN_NAME
Algorithm name is unknown.
int hash_id
Definition: names.h:39
#define NOISE_CIPHER_CHACHAPOLY
Cipher identifier for "ChaChaPoly".
#define NOISE_PATTERN_NX_NOIDH
Handshake pattern identifier for "NXnoidh".
#define NOISE_ERROR_INVALID_LENGTH
Invalid length specified for a key, packet, etc.
#define NOISE_DH_NEWHOPE
Diffie-Hellman identifier for "NewHope" (post-quantum, ephemeral key exchanges only).
#define NOISE_HASH_SHA256
Hash identifier for "SHA256".
#define NOISE_PATTERN_K
Handshake pattern identifier for "K".
#define NOISE_PATTERN_IX_NOIDH_HFS
Definition: constants.h:97
int noise_name_to_id(int category, const char *name, size_t name_len)
Maps an algorithm name to the corresponding identifier.
Definition: names.c:146
#define NOISE_CIPHER_CATEGORY
Category for cipher algorithms.
#define NOISE_PATTERN_CATEGORY
Category for handshake patterns.
#define NOISE_PATTERN_IN
Handshake pattern identifier for "IN".
Internal definitions for the library.
#define NOISE_DH_CURVE25519
Diffie-Hellman identifier for "25519".
#define NOISE_PATTERN_IN_HFS
Definition: constants.h:89
#define NOISE_PATTERN_IK_NOIDH
Handshake pattern identifier for "IKnoidh".
#define NOISE_PATTERN_NX
Handshake pattern identifier for "NX".
#define NOISE_PATTERN_KN_HFS
Definition: constants.h:86
#define NOISE_PATTERN_XX_HFS
Definition: constants.h:85
#define NOISE_PREFIX_STANDARD
Protocol prefix identifier for "Noise".
const char * noise_id_to_name(int category, int id)
Maps an algorithm identifier to the corresponding name.
Definition: names.c:182
#define NOISE_PATTERN_NN
Handshake pattern identifier for "NN".
#define NOISE_PATTERN_IX_HFS
Definition: constants.h:91
#define NOISE_ID(ch, num)
Builds an algorithm identifier for the library.
#define NOISE_PATTERN_XX_FALLBACK
Handshake pattern identifier for "XXfallback".
#define NOISE_PATTERN_XX_NOIDH
Handshake pattern identifier for "XXnoidh".
#define NOISE_PATTERN_N
Handshake pattern identifier for "N".
int prefix_id
Definition: names.h:35
#define NOISE_PATTERN_KN
Handshake pattern identifier for "KN".
#define NOISE_HASH_BLAKE2s
Hash identifier for "BLAKE2s".
#define NOISE_PATTERN_X_NOIDH
Handshake pattern identifier for "Xnoidh".
#define NOISE_HASH_SHA512
Hash identifier for "SHA512".
#define NOISE_PATTERN_IK_NOIDH_HFS
Definition: constants.h:96
#define NOISE_PREFIX_PSK
Protocol prefix identifier for "NoisePSK".
#define NOISE_PATTERN_XX_FALLBACK_HFS
Definition: constants.h:92
#define NOISE_PATTERN_KX_NOIDH_HFS
Definition: constants.h:95
int noise_protocol_id_to_name(char *name, size_t name_len, const NoiseProtocolId *id)
Formats a protocol name from a set of identifiers for the algorithms that make up the name...
Definition: names.c:437
#define NOISE_PATTERN_XX_NOIDH_HFS
Definition: constants.h:94
int hybrid_id
Definition: names.h:40
#define NOISE_PATTERN_IX_NOIDH
Handshake pattern identifier for "IXnoidh".
#define NOISE_PATTERN_X
Handshake pattern identifier for "X".
int pattern_id
Definition: names.h:36