s2n_map.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. #include "utils/s2n_map.h"
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include "api/s2n.h"
  19. #include "crypto/s2n_hash.h"
  20. #include "error/s2n_errno.h"
  21. #include "utils/s2n_blob.h"
  22. #include "utils/s2n_map_internal.h"
  23. #include "utils/s2n_mem.h"
  24. #include "utils/s2n_result.h"
  25. #include "utils/s2n_safety.h"
  26. #define S2N_INITIAL_TABLE_SIZE 1024
  27. static S2N_RESULT s2n_map_slot(const struct s2n_map *map, struct s2n_blob *key, uint32_t *slot)
  28. {
  29. RESULT_ENSURE_REF(map);
  30. union {
  31. uint8_t u8[32];
  32. uint32_t u32[8];
  33. } digest;
  34. DEFER_CLEANUP(struct s2n_hash_state sha256 = { 0 }, s2n_hash_free);
  35. RESULT_GUARD_POSIX(s2n_hash_new(&sha256));
  36. RESULT_GUARD_POSIX(s2n_hash_init(&sha256, S2N_HASH_SHA256));
  37. RESULT_GUARD_POSIX(s2n_hash_update(&sha256, key->data, key->size));
  38. RESULT_GUARD_POSIX(s2n_hash_digest(&sha256, digest.u8, sizeof(digest)));
  39. *slot = digest.u32[0] % map->capacity;
  40. return S2N_RESULT_OK;
  41. }
  42. static S2N_RESULT s2n_map_embiggen(struct s2n_map *map, uint32_t capacity)
  43. {
  44. RESULT_ENSURE_REF(map);
  45. struct s2n_blob mem = { 0 };
  46. struct s2n_map tmp = { 0 };
  47. RESULT_ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE);
  48. RESULT_GUARD_POSIX(s2n_alloc(&mem, (capacity * sizeof(struct s2n_map_entry))));
  49. RESULT_GUARD_POSIX(s2n_blob_zero(&mem));
  50. tmp.capacity = capacity;
  51. tmp.size = 0;
  52. tmp.table = (void *) mem.data;
  53. tmp.immutable = 0;
  54. for (size_t i = 0; i < map->capacity; i++) {
  55. if (map->table[i].key.size) {
  56. RESULT_GUARD(s2n_map_add(&tmp, &map->table[i].key, &map->table[i].value));
  57. RESULT_GUARD_POSIX(s2n_free(&map->table[i].key));
  58. RESULT_GUARD_POSIX(s2n_free(&map->table[i].value));
  59. }
  60. }
  61. RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) &map->table, map->capacity * sizeof(struct s2n_map_entry)));
  62. /* Clone the temporary map */
  63. map->capacity = tmp.capacity;
  64. map->size = tmp.size;
  65. map->table = tmp.table;
  66. map->immutable = 0;
  67. return S2N_RESULT_OK;
  68. }
  69. struct s2n_map *s2n_map_new()
  70. {
  71. return s2n_map_new_with_initial_capacity(S2N_INITIAL_TABLE_SIZE);
  72. }
  73. struct s2n_map *s2n_map_new_with_initial_capacity(uint32_t capacity)
  74. {
  75. PTR_ENSURE(capacity != 0, S2N_ERR_MAP_INVALID_MAP_SIZE);
  76. struct s2n_blob mem = { 0 };
  77. struct s2n_map *map;
  78. PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_map)));
  79. map = (void *) mem.data;
  80. map->capacity = 0;
  81. map->size = 0;
  82. map->immutable = 0;
  83. map->table = NULL;
  84. PTR_GUARD_RESULT(s2n_map_embiggen(map, capacity));
  85. return map;
  86. }
  87. S2N_RESULT s2n_map_add(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value)
  88. {
  89. RESULT_ENSURE_REF(map);
  90. RESULT_ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE);
  91. if (map->capacity < (map->size * 2)) {
  92. /* Embiggen the map */
  93. RESULT_GUARD(s2n_map_embiggen(map, map->capacity * 2));
  94. }
  95. uint32_t slot = 0;
  96. RESULT_GUARD(s2n_map_slot(map, key, &slot));
  97. /* Linear probing until we find an empty slot */
  98. while (map->table[slot].key.size) {
  99. if (key->size != map->table[slot].key.size || memcmp(key->data, map->table[slot].key.data, key->size)) {
  100. slot++;
  101. slot %= map->capacity;
  102. continue;
  103. }
  104. /* We found a duplicate key */
  105. RESULT_BAIL(S2N_ERR_MAP_DUPLICATE);
  106. }
  107. RESULT_GUARD_POSIX(s2n_dup(key, &map->table[slot].key));
  108. RESULT_GUARD_POSIX(s2n_dup(value, &map->table[slot].value));
  109. map->size++;
  110. return S2N_RESULT_OK;
  111. }
  112. S2N_RESULT s2n_map_put(struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value)
  113. {
  114. RESULT_ENSURE_REF(map);
  115. RESULT_ENSURE(!map->immutable, S2N_ERR_MAP_IMMUTABLE);
  116. if (map->capacity < (map->size * 2)) {
  117. /* Embiggen the map */
  118. RESULT_GUARD(s2n_map_embiggen(map, map->capacity * 2));
  119. }
  120. uint32_t slot = 0;
  121. RESULT_GUARD(s2n_map_slot(map, key, &slot));
  122. /* Linear probing until we find an empty slot */
  123. while (map->table[slot].key.size) {
  124. if (key->size != map->table[slot].key.size || memcmp(key->data, map->table[slot].key.data, key->size)) {
  125. slot++;
  126. slot %= map->capacity;
  127. continue;
  128. }
  129. /* We found a duplicate key that will be overwritten */
  130. RESULT_GUARD_POSIX(s2n_free(&map->table[slot].key));
  131. RESULT_GUARD_POSIX(s2n_free(&map->table[slot].value));
  132. map->size--;
  133. break;
  134. }
  135. RESULT_GUARD_POSIX(s2n_dup(key, &map->table[slot].key));
  136. RESULT_GUARD_POSIX(s2n_dup(value, &map->table[slot].value));
  137. map->size++;
  138. return S2N_RESULT_OK;
  139. }
  140. S2N_RESULT s2n_map_complete(struct s2n_map *map)
  141. {
  142. RESULT_ENSURE_REF(map);
  143. map->immutable = 1;
  144. return S2N_RESULT_OK;
  145. }
  146. S2N_RESULT s2n_map_unlock(struct s2n_map *map)
  147. {
  148. RESULT_ENSURE_REF(map);
  149. map->immutable = 0;
  150. return S2N_RESULT_OK;
  151. }
  152. S2N_RESULT s2n_map_lookup(const struct s2n_map *map, struct s2n_blob *key, struct s2n_blob *value, bool *key_found)
  153. {
  154. RESULT_ENSURE_REF(map);
  155. RESULT_ENSURE(map->immutable, S2N_ERR_MAP_MUTABLE);
  156. uint32_t slot = 0;
  157. RESULT_GUARD(s2n_map_slot(map, key, &slot));
  158. const uint32_t initial_slot = slot;
  159. while (map->table[slot].key.size) {
  160. if (key->size != map->table[slot].key.size || memcmp(key->data, map->table[slot].key.data, key->size)) {
  161. slot++;
  162. slot %= map->capacity;
  163. /* We went over all the slots but found no match */
  164. if (slot == initial_slot) {
  165. break;
  166. }
  167. continue;
  168. }
  169. /* We found a match */
  170. value->data = map->table[slot].value.data;
  171. value->size = map->table[slot].value.size;
  172. *key_found = true;
  173. return S2N_RESULT_OK;
  174. }
  175. *key_found = false;
  176. return S2N_RESULT_OK;
  177. }
  178. S2N_RESULT s2n_map_free(struct s2n_map *map)
  179. {
  180. if (map == NULL) {
  181. return S2N_RESULT_OK;
  182. }
  183. /* Free the keys and values */
  184. /* cppcheck has a false positive warning for checking the pointer here */
  185. /* cppcheck-suppress nullPointerRedundantCheck */
  186. for (size_t i = 0; i < map->capacity; i++) {
  187. if (map->table[i].key.size) {
  188. RESULT_GUARD_POSIX(s2n_free(&map->table[i].key));
  189. RESULT_GUARD_POSIX(s2n_free(&map->table[i].value));
  190. }
  191. }
  192. /* Free the table */
  193. RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) &map->table, map->capacity * sizeof(struct s2n_map_entry)));
  194. /* And finally the map */
  195. RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) &map, sizeof(struct s2n_map)));
  196. return S2N_RESULT_OK;
  197. }