core_namemap.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include "internal/namemap.h"
  10. #include <openssl/lhash.h>
  11. #include <openssl/safestack.h>
  12. /* The namemap entry */
  13. typedef struct {
  14. int number;
  15. const char *name;
  16. char body[1]; /* Sized appropriately to contain the name */
  17. } NAMEMAP_ENTRY;
  18. DEFINE_LHASH_OF(NAMEMAP_ENTRY);
  19. DEFINE_STACK_OF(NAMEMAP_ENTRY)
  20. /* The namemap, which provides for bidirectional indexing */
  21. struct ossl_namemap_st {
  22. /* Flags */
  23. unsigned int stored:1; /* If 1, it's stored in a library context */
  24. CRYPTO_RWLOCK *lock;
  25. LHASH_OF(NAMEMAP_ENTRY) *namenum; /* Name->number mapping */
  26. STACK_OF(NAMEMAP_ENTRY) *numname; /* Number->name mapping */
  27. };
  28. /* LHASH callbacks */
  29. static unsigned long namemap_hash(const NAMEMAP_ENTRY *n)
  30. {
  31. return OPENSSL_LH_strhash(n->name);
  32. }
  33. static int namemap_cmp(const NAMEMAP_ENTRY *a, const NAMEMAP_ENTRY *b)
  34. {
  35. return strcmp(a->name, b->name);
  36. }
  37. static void namemap_free(NAMEMAP_ENTRY *n)
  38. {
  39. OPENSSL_free(n);
  40. }
  41. /* OPENSSL_CTX_METHOD functions for a namemap stored in a library context */
  42. static void *stored_namemap_new(OPENSSL_CTX *libctx)
  43. {
  44. OSSL_NAMEMAP *namemap = ossl_namemap_new();
  45. if (namemap != NULL)
  46. namemap->stored = 1;
  47. return namemap;
  48. }
  49. static void stored_namemap_free(void *vnamemap)
  50. {
  51. OSSL_NAMEMAP *namemap = vnamemap;
  52. /* Pretend it isn't stored, or ossl_namemap_free() will do nothing */
  53. namemap->stored = 0;
  54. ossl_namemap_free(namemap);
  55. }
  56. static const OPENSSL_CTX_METHOD stored_namemap_method = {
  57. stored_namemap_new,
  58. stored_namemap_free,
  59. };
  60. /* API functions */
  61. OSSL_NAMEMAP *ossl_namemap_stored(OPENSSL_CTX *libctx)
  62. {
  63. return openssl_ctx_get_data(libctx, OPENSSL_CTX_NAMEMAP_INDEX,
  64. &stored_namemap_method);
  65. }
  66. OSSL_NAMEMAP *ossl_namemap_new(void)
  67. {
  68. OSSL_NAMEMAP *namemap;
  69. if ((namemap = OPENSSL_zalloc(sizeof(*namemap))) != NULL
  70. && (namemap->lock = CRYPTO_THREAD_lock_new()) != NULL
  71. && (namemap->numname = sk_NAMEMAP_ENTRY_new_null()) != NULL
  72. && (namemap->namenum =
  73. lh_NAMEMAP_ENTRY_new(namemap_hash, namemap_cmp)) != NULL) {
  74. return namemap;
  75. }
  76. ossl_namemap_free(namemap);
  77. return NULL;
  78. }
  79. void ossl_namemap_free(OSSL_NAMEMAP *namemap)
  80. {
  81. if (namemap == NULL || namemap->stored)
  82. return;
  83. /* The elements will be freed by sk_NAMEMAP_ENTRY_pop_free() */
  84. lh_NAMEMAP_ENTRY_free(namemap->namenum);
  85. sk_NAMEMAP_ENTRY_pop_free(namemap->numname, namemap_free);
  86. CRYPTO_THREAD_lock_free(namemap->lock);
  87. OPENSSL_free(namemap);
  88. }
  89. /*
  90. * TODO(3.0) It isn't currently possible to have a default namemap in the
  91. * FIPS module because if init and cleanup constraints, so we currently
  92. * disable the code that would allow it when FIPS_MODE is defined.
  93. */
  94. const char *ossl_namemap_name(const OSSL_NAMEMAP *namemap, int number)
  95. {
  96. NAMEMAP_ENTRY *entry;
  97. #ifndef FIPS_MODE
  98. if (namemap == NULL)
  99. namemap = ossl_namemap_stored(NULL);
  100. #endif
  101. if (namemap == NULL || number == 0)
  102. return NULL;
  103. CRYPTO_THREAD_read_lock(namemap->lock);
  104. entry = sk_NAMEMAP_ENTRY_value(namemap->numname, number);
  105. CRYPTO_THREAD_unlock(namemap->lock);
  106. if (entry != NULL)
  107. return entry->name;
  108. return NULL;
  109. }
  110. int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name)
  111. {
  112. NAMEMAP_ENTRY *entry, template;
  113. #ifndef FIPS_MODE
  114. if (namemap == NULL)
  115. namemap = ossl_namemap_stored(NULL);
  116. #endif
  117. if (namemap == NULL)
  118. return 0;
  119. template.name = name;
  120. CRYPTO_THREAD_read_lock(namemap->lock);
  121. entry = lh_NAMEMAP_ENTRY_retrieve(namemap->namenum, &template);
  122. CRYPTO_THREAD_unlock(namemap->lock);
  123. if (entry == NULL)
  124. return 0;
  125. return entry->number;
  126. }
  127. int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name)
  128. {
  129. NAMEMAP_ENTRY *entry;
  130. int number;
  131. #ifndef FIPS_MODE
  132. if (namemap == NULL)
  133. namemap = ossl_namemap_stored(NULL);
  134. #endif
  135. if (name == NULL || namemap == NULL)
  136. return 0;
  137. if ((number = ossl_namemap_number(namemap, name)) != 0)
  138. return number; /* Pretend success */
  139. if ((entry = OPENSSL_zalloc(sizeof(*entry) + strlen(name))) == NULL)
  140. goto err;
  141. strcpy(entry->body, name);
  142. entry->name = entry->body;
  143. CRYPTO_THREAD_write_lock(namemap->lock);
  144. entry->number = sk_NAMEMAP_ENTRY_push(namemap->numname, entry);
  145. if (entry->number == 0)
  146. goto err;
  147. (void)lh_NAMEMAP_ENTRY_insert(namemap->namenum, entry);
  148. if (lh_NAMEMAP_ENTRY_error(namemap->namenum))
  149. goto err;
  150. CRYPTO_THREAD_unlock(namemap->lock);
  151. return entry->number;
  152. err:
  153. if (entry != NULL) {
  154. if (entry->number != 0)
  155. (void)sk_NAMEMAP_ENTRY_pop(namemap->numname);
  156. lh_NAMEMAP_ENTRY_delete(namemap->namenum, entry);
  157. CRYPTO_THREAD_unlock(namemap->lock);
  158. }
  159. return 0;
  160. }