200-x509-excessive-resource-use-verifying-policy-constra.patch 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. From 959c59c7a0164117e7f8366466a32bb1f8d77ff1 Mon Sep 17 00:00:00 2001
  2. From: Pauli <[email protected]>
  3. Date: Wed, 8 Mar 2023 15:28:20 +1100
  4. Subject: [PATCH] x509: excessive resource use verifying policy constraints
  5. A security vulnerability has been identified in all supported versions
  6. of OpenSSL related to the verification of X.509 certificate chains
  7. that include policy constraints. Attackers may be able to exploit this
  8. vulnerability by creating a malicious certificate chain that triggers
  9. exponential use of computational resources, leading to a denial-of-service
  10. (DoS) attack on affected systems.
  11. Fixes CVE-2023-0464
  12. Reviewed-by: Tomas Mraz <[email protected]>
  13. Reviewed-by: Shane Lontis <[email protected]>
  14. (Merged from https://github.com/openssl/openssl/pull/20568)
  15. --- a/crypto/x509/pcy_local.h
  16. +++ b/crypto/x509/pcy_local.h
  17. @@ -111,6 +111,11 @@ struct X509_POLICY_LEVEL_st {
  18. };
  19. struct X509_POLICY_TREE_st {
  20. + /* The number of nodes in the tree */
  21. + size_t node_count;
  22. + /* The maximum number of nodes in the tree */
  23. + size_t node_maximum;
  24. +
  25. /* This is the tree 'level' data */
  26. X509_POLICY_LEVEL *levels;
  27. int nlevel;
  28. @@ -157,7 +162,8 @@ X509_POLICY_NODE *ossl_policy_tree_find_
  29. X509_POLICY_NODE *ossl_policy_level_add_node(X509_POLICY_LEVEL *level,
  30. X509_POLICY_DATA *data,
  31. X509_POLICY_NODE *parent,
  32. - X509_POLICY_TREE *tree);
  33. + X509_POLICY_TREE *tree,
  34. + int extra_data);
  35. void ossl_policy_node_free(X509_POLICY_NODE *node);
  36. int ossl_policy_node_match(const X509_POLICY_LEVEL *lvl,
  37. const X509_POLICY_NODE *node, const ASN1_OBJECT *oid);
  38. --- a/crypto/x509/pcy_node.c
  39. +++ b/crypto/x509/pcy_node.c
  40. @@ -59,10 +59,15 @@ X509_POLICY_NODE *ossl_policy_level_find
  41. X509_POLICY_NODE *ossl_policy_level_add_node(X509_POLICY_LEVEL *level,
  42. X509_POLICY_DATA *data,
  43. X509_POLICY_NODE *parent,
  44. - X509_POLICY_TREE *tree)
  45. + X509_POLICY_TREE *tree,
  46. + int extra_data)
  47. {
  48. X509_POLICY_NODE *node;
  49. + /* Verify that the tree isn't too large. This mitigates CVE-2023-0464 */
  50. + if (tree->node_maximum > 0 && tree->node_count >= tree->node_maximum)
  51. + return NULL;
  52. +
  53. node = OPENSSL_zalloc(sizeof(*node));
  54. if (node == NULL) {
  55. ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
  56. @@ -70,7 +75,7 @@ X509_POLICY_NODE *ossl_policy_level_add_
  57. }
  58. node->data = data;
  59. node->parent = parent;
  60. - if (level) {
  61. + if (level != NULL) {
  62. if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
  63. if (level->anyPolicy)
  64. goto node_error;
  65. @@ -90,7 +95,7 @@ X509_POLICY_NODE *ossl_policy_level_add_
  66. }
  67. }
  68. - if (tree) {
  69. + if (extra_data) {
  70. if (tree->extra_data == NULL)
  71. tree->extra_data = sk_X509_POLICY_DATA_new_null();
  72. if (tree->extra_data == NULL){
  73. @@ -103,6 +108,7 @@ X509_POLICY_NODE *ossl_policy_level_add_
  74. }
  75. }
  76. + tree->node_count++;
  77. if (parent)
  78. parent->nchild++;
  79. --- a/crypto/x509/pcy_tree.c
  80. +++ b/crypto/x509/pcy_tree.c
  81. @@ -14,6 +14,17 @@
  82. #include "pcy_local.h"
  83. +/*
  84. + * If the maximum number of nodes in the policy tree isn't defined, set it to
  85. + * a generous default of 1000 nodes.
  86. + *
  87. + * Defining this to be zero means unlimited policy tree growth which opens the
  88. + * door on CVE-2023-0464.
  89. + */
  90. +#ifndef OPENSSL_POLICY_TREE_NODES_MAX
  91. +# define OPENSSL_POLICY_TREE_NODES_MAX 1000
  92. +#endif
  93. +
  94. static void expected_print(BIO *channel,
  95. X509_POLICY_LEVEL *lev, X509_POLICY_NODE *node,
  96. int indent)
  97. @@ -163,6 +174,9 @@ static int tree_init(X509_POLICY_TREE **
  98. return X509_PCY_TREE_INTERNAL;
  99. }
  100. + /* Limit the growth of the tree to mitigate CVE-2023-0464 */
  101. + tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX;
  102. +
  103. /*
  104. * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3.
  105. *
  106. @@ -180,7 +194,7 @@ static int tree_init(X509_POLICY_TREE **
  107. if ((data = ossl_policy_data_new(NULL,
  108. OBJ_nid2obj(NID_any_policy), 0)) == NULL)
  109. goto bad_tree;
  110. - if (ossl_policy_level_add_node(level, data, NULL, tree) == NULL) {
  111. + if (ossl_policy_level_add_node(level, data, NULL, tree, 1) == NULL) {
  112. ossl_policy_data_free(data);
  113. goto bad_tree;
  114. }
  115. @@ -239,7 +253,8 @@ static int tree_init(X509_POLICY_TREE **
  116. * Return value: 1 on success, 0 otherwise
  117. */
  118. static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
  119. - X509_POLICY_DATA *data)
  120. + X509_POLICY_DATA *data,
  121. + X509_POLICY_TREE *tree)
  122. {
  123. X509_POLICY_LEVEL *last = curr - 1;
  124. int i, matched = 0;
  125. @@ -249,13 +264,13 @@ static int tree_link_matching_nodes(X509
  126. X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i);
  127. if (ossl_policy_node_match(last, node, data->valid_policy)) {
  128. - if (ossl_policy_level_add_node(curr, data, node, NULL) == NULL)
  129. + if (ossl_policy_level_add_node(curr, data, node, tree, 0) == NULL)
  130. return 0;
  131. matched = 1;
  132. }
  133. }
  134. if (!matched && last->anyPolicy) {
  135. - if (ossl_policy_level_add_node(curr, data, last->anyPolicy, NULL) == NULL)
  136. + if (ossl_policy_level_add_node(curr, data, last->anyPolicy, tree, 0) == NULL)
  137. return 0;
  138. }
  139. return 1;
  140. @@ -268,7 +283,8 @@ static int tree_link_matching_nodes(X509
  141. * Return value: 1 on success, 0 otherwise.
  142. */
  143. static int tree_link_nodes(X509_POLICY_LEVEL *curr,
  144. - const X509_POLICY_CACHE *cache)
  145. + const X509_POLICY_CACHE *cache,
  146. + X509_POLICY_TREE *tree)
  147. {
  148. int i;
  149. @@ -276,7 +292,7 @@ static int tree_link_nodes(X509_POLICY_L
  150. X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i);
  151. /* Look for matching nodes in previous level */
  152. - if (!tree_link_matching_nodes(curr, data))
  153. + if (!tree_link_matching_nodes(curr, data, tree))
  154. return 0;
  155. }
  156. return 1;
  157. @@ -307,7 +323,7 @@ static int tree_add_unmatched(X509_POLIC
  158. /* Curr may not have anyPolicy */
  159. data->qualifier_set = cache->anyPolicy->qualifier_set;
  160. data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
  161. - if (ossl_policy_level_add_node(curr, data, node, tree) == NULL) {
  162. + if (ossl_policy_level_add_node(curr, data, node, tree, 1) == NULL) {
  163. ossl_policy_data_free(data);
  164. return 0;
  165. }
  166. @@ -370,7 +386,7 @@ static int tree_link_any(X509_POLICY_LEV
  167. /* Finally add link to anyPolicy */
  168. if (last->anyPolicy &&
  169. ossl_policy_level_add_node(curr, cache->anyPolicy,
  170. - last->anyPolicy, NULL) == NULL)
  171. + last->anyPolicy, tree, 0) == NULL)
  172. return 0;
  173. return 1;
  174. }
  175. @@ -553,7 +569,7 @@ static int tree_calculate_user_set(X509_
  176. extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
  177. | POLICY_DATA_FLAG_EXTRA_NODE;
  178. node = ossl_policy_level_add_node(NULL, extra, anyPolicy->parent,
  179. - tree);
  180. + tree, 1);
  181. }
  182. if (!tree->user_policies) {
  183. tree->user_policies = sk_X509_POLICY_NODE_new_null();
  184. @@ -580,7 +596,7 @@ static int tree_evaluate(X509_POLICY_TRE
  185. for (i = 1; i < tree->nlevel; i++, curr++) {
  186. cache = ossl_policy_cache_set(curr->cert);
  187. - if (!tree_link_nodes(curr, cache))
  188. + if (!tree_link_nodes(curr, cache, tree))
  189. return X509_PCY_TREE_INTERNAL;
  190. if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)