You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.4 KiB

  1. commit 6338b7d4a884639f98823e885325a50750f72e04
  2. Author: William Lallemand <wlallemand@haproxy.org>
  3. Date: Tue Dec 28 18:47:17 2021 +0100
  4. BUG/MEDIUM: ssl: initialize correctly ssl w/ default-server
  5. This bug was introduced by d817dc73 ("MEDIUM: ssl: Load client
  6. certificates in a ckch for backend servers") in which the creation of
  7. the SSL_CTX for a server was moved to the configuration parser when
  8. using a "crt" keyword instead of being done in ssl_sock_prepare_srv_ctx().
  9. The patch 0498fa40 ("BUG/MINOR: ssl: Default-server configuration ignored by
  10. server") made it worse by setting the same SSL_CTX for every servers
  11. using a default-server. Resulting in any SSL option on a server applied
  12. to every server in its backend.
  13. This patch fixes the issue by reintroducing a string which store the
  14. path of certificate inside the server structure, and loading the
  15. certificate in ssl_sock_prepare_srv_ctx() again.
  16. This is a quick fix to backport, a cleaner way can be achieve by always
  17. creating the SSL_CTX in ssl_sock_prepare_srv_ctx() and splitting
  18. properly the ssl_sock_load_srv_cert() function.
  19. This patch fixes issue #1488.
  20. Must be backported as far as 2.4.
  21. (cherry picked from commit 2c776f1c30c85be11c9ba8ca8d9a7d62690d1a32)
  22. Signed-off-by: Willy Tarreau <w@1wt.eu>
  23. (cherry picked from commit 2f3c354b6cdc21ee185e263b5c7422c86ae58c98)
  24. [wt: ssl_sock_load_srv_cert() doesn't take the create_if_none arg in 2.4,
  25. thus adjust context and make sure ssl_sock_prepare_srv_ctx() matches
  26. what srv_parse_crt() used to do]
  27. Signed-off-by: Willy Tarreau <w@1wt.eu>
  28. --- a/include/haproxy/server-t.h
  29. +++ b/include/haproxy/server-t.h
  30. @@ -364,6 +364,7 @@ struct server {
  31. char *verify_host; /* hostname of certificate must match this host */
  32. char *ca_file; /* CAfile to use on verify */
  33. char *crl_file; /* CRLfile to use on verify */
  34. + char *client_crt; /* client certificate to send */
  35. struct sample_expr *sni; /* sample expression for SNI */
  36. #ifdef OPENSSL_NPN_NEGOTIATED
  37. char *npn_str; /* NPN protocol string */
  38. --- a/reg-tests/ssl/ssl_default_server.vtc
  39. +++ b/reg-tests/ssl/ssl_default_server.vtc
  40. @@ -15,7 +15,7 @@ feature cmd "$HAPROXY_PROGRAM -cc 'versi
  41. feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
  42. feature ignore_unknown_macro
  43. -server s1 -repeat 7 {
  44. +server s1 -repeat 10 {
  45. rxreq
  46. txresp
  47. } -start
  48. @@ -56,7 +56,10 @@ haproxy h1 -conf {
  49. backend third_be
  50. default-server ssl crt client1.pem ca-file ca-auth.crt verify none
  51. - server s1 "${tmpdir}/ssl.sock" crt client2_expired.pem
  52. + server s1 "${tmpdir}/ssl.sock"
  53. + server s2 "${tmpdir}/ssl.sock" crt client2_expired.pem
  54. + server s3 "${tmpdir}/ssl.sock"
  55. + server s4 "${tmpdir}/ssl.sock"
  56. backend fourth_be
  57. default-server ssl crt client1.pem verify none
  58. @@ -106,9 +109,25 @@ client c1 -connect ${h1_clearlst_sock} {
  59. txreq
  60. rxresp
  61. expect resp.status == 200
  62. + expect resp.http.x-ssl == "Ok"
  63. +} -run
  64. +
  65. +client c1 -connect ${h1_clearlst_sock} {
  66. + txreq -url "/third"
  67. + txreq
  68. + rxresp
  69. + expect resp.status == 200
  70. expect resp.http.x-ssl == "Expired"
  71. } -run
  72. +client c1 -connect ${h1_clearlst_sock} -repeat 2 {
  73. + txreq -url "/third"
  74. + txreq
  75. + rxresp
  76. + expect resp.status == 200
  77. + expect resp.http.x-ssl == "Ok"
  78. +} -run
  79. +
  80. client c1 -connect ${h1_clearlst_sock} {
  81. txreq -url "/fourth"
  82. txreq
  83. --- a/src/cfgparse-ssl.c
  84. +++ b/src/cfgparse-ssl.c
  85. @@ -1450,25 +1450,17 @@ static int srv_parse_crl_file(char **arg
  86. /* parse the "crt" server keyword */
  87. static int srv_parse_crt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
  88. {
  89. - int retval = -1;
  90. - char *path = NULL;
  91. -
  92. if (!*args[*cur_arg + 1]) {
  93. memprintf(err, "'%s' : missing certificate file path", args[*cur_arg]);
  94. return ERR_ALERT | ERR_FATAL;
  95. }
  96. if ((*args[*cur_arg + 1] != '/') && global_ssl.crt_base)
  97. - memprintf(&path, "%s/%s", global_ssl.crt_base, args[*cur_arg + 1]);
  98. + memprintf(&newsrv->ssl_ctx.client_crt, "%s/%s", global_ssl.crt_base, args[*cur_arg + 1]);
  99. else
  100. - memprintf(&path, "%s", args[*cur_arg + 1]);
  101. -
  102. - if (path) {
  103. - retval = ssl_sock_load_srv_cert(path, newsrv, err);
  104. - free(path);
  105. - }
  106. + memprintf(&newsrv->ssl_ctx.client_crt, "%s", args[*cur_arg + 1]);
  107. - return retval;
  108. + return 0;
  109. }
  110. /* parse the "no-check-ssl" server keyword */
  111. --- a/src/server.c
  112. +++ b/src/server.c
  113. @@ -2063,6 +2063,8 @@ static void srv_conn_src_cpy(struct serv
  114. static void srv_ssl_settings_cpy(struct server *srv, struct server *src)
  115. {
  116. /* <src> is the current proxy's default server and SSL is enabled */
  117. + BUG_ON(src->ssl_ctx.ctx != NULL); /* the SSL_CTX must never be initialized in a default-server */
  118. +
  119. if (src == &srv->proxy->defsrv && src->use_ssl == 1)
  120. srv->flags |= SRV_F_DEFSRV_USE_SSL;
  121. @@ -2070,10 +2072,11 @@ static void srv_ssl_settings_cpy(struct
  122. srv->ssl_ctx.ca_file = strdup(src->ssl_ctx.ca_file);
  123. if (src->ssl_ctx.crl_file != NULL)
  124. srv->ssl_ctx.crl_file = strdup(src->ssl_ctx.crl_file);
  125. + if (src->ssl_ctx.client_crt != NULL)
  126. + srv->ssl_ctx.client_crt = strdup(src->ssl_ctx.client_crt);
  127. srv->ssl_ctx.verify = src->ssl_ctx.verify;
  128. - srv->ssl_ctx.ctx = src->ssl_ctx.ctx;
  129. if (src->ssl_ctx.verify_host != NULL)
  130. srv->ssl_ctx.verify_host = strdup(src->ssl_ctx.verify_host);
  131. --- a/src/ssl_sock.c
  132. +++ b/src/ssl_sock.c
  133. @@ -4669,7 +4669,7 @@ int ssl_sock_prepare_srv_ctx(struct serv
  134. {
  135. struct proxy *curproxy = srv->proxy;
  136. int cfgerr = 0;
  137. - SSL_CTX *ctx = srv->ssl_ctx.ctx;
  138. + SSL_CTX *ctx;
  139. /* Make sure openssl opens /dev/urandom before the chroot */
  140. if (!ssl_initialize_random()) {
  141. @@ -4693,6 +4693,26 @@ int ssl_sock_prepare_srv_ctx(struct serv
  142. if (srv->use_ssl == 1)
  143. srv->xprt = &ssl_sock;
  144. + if (srv->ssl_ctx.client_crt) {
  145. + char *err = NULL;
  146. + int err_code = 0;
  147. +
  148. + /* If there is a crt keyword there, the SSL_CTX will be created here. */
  149. + err_code = ssl_sock_load_srv_cert(srv->ssl_ctx.client_crt, srv, &err);
  150. + if (err_code != ERR_NONE) {
  151. + if ((err_code & ERR_WARN) && !(err_code & ERR_ALERT))
  152. + ha_warning("%s", err);
  153. + else
  154. + ha_alert("%s", err);
  155. +
  156. + if (err_code & (ERR_FATAL|ERR_ABORT))
  157. + cfgerr++;
  158. + }
  159. + ha_free(&err);
  160. + }
  161. +
  162. + ctx = srv->ssl_ctx.ctx;
  163. +
  164. /* The context will be uninitialized if there wasn't any "cert" option
  165. * in the server line. */
  166. if (!ctx) {