puma 3.11.1 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +2092 -422
  3. data/LICENSE +23 -20
  4. data/README.md +301 -69
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +59 -21
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +69 -58
  9. data/docs/fork_worker.md +41 -0
  10. data/docs/java_options.md +54 -0
  11. data/docs/jungle/README.md +9 -0
  12. data/docs/jungle/rc.d/README.md +74 -0
  13. data/docs/jungle/rc.d/puma +61 -0
  14. data/docs/jungle/rc.d/puma.conf +10 -0
  15. data/docs/kubernetes.md +78 -0
  16. data/docs/nginx.md +2 -2
  17. data/docs/plugins.md +26 -12
  18. data/docs/rails_dev_mode.md +28 -0
  19. data/docs/restart.md +48 -22
  20. data/docs/signals.md +13 -11
  21. data/docs/stats.md +147 -0
  22. data/docs/systemd.md +108 -117
  23. data/docs/testing_benchmarks_local_files.md +150 -0
  24. data/docs/testing_test_rackup_ci_files.md +36 -0
  25. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  26. data/ext/puma_http11/ext_help.h +1 -1
  27. data/ext/puma_http11/extconf.rb +68 -3
  28. data/ext/puma_http11/http11_parser.c +106 -118
  29. data/ext/puma_http11/http11_parser.h +2 -2
  30. data/ext/puma_http11/http11_parser.java.rl +22 -38
  31. data/ext/puma_http11/http11_parser.rl +6 -4
  32. data/ext/puma_http11/http11_parser_common.rl +6 -6
  33. data/ext/puma_http11/mini_ssl.c +474 -94
  34. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  35. data/ext/puma_http11/org/jruby/puma/Http11.java +136 -121
  36. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +84 -99
  37. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +251 -88
  38. data/ext/puma_http11/puma_http11.c +53 -58
  39. data/lib/puma/app/status.rb +71 -49
  40. data/lib/puma/binder.rb +257 -151
  41. data/lib/puma/cli.rb +61 -38
  42. data/lib/puma/client.rb +464 -224
  43. data/lib/puma/cluster/worker.rb +183 -0
  44. data/lib/puma/cluster/worker_handle.rb +96 -0
  45. data/lib/puma/cluster.rb +343 -239
  46. data/lib/puma/commonlogger.rb +23 -14
  47. data/lib/puma/configuration.rb +144 -96
  48. data/lib/puma/const.rb +194 -115
  49. data/lib/puma/control_cli.rb +135 -81
  50. data/lib/puma/detect.rb +34 -2
  51. data/lib/puma/dsl.rb +1092 -153
  52. data/lib/puma/error_logger.rb +113 -0
  53. data/lib/puma/events.rb +17 -111
  54. data/lib/puma/io_buffer.rb +44 -5
  55. data/lib/puma/jruby_restart.rb +2 -73
  56. data/lib/puma/json_serialization.rb +96 -0
  57. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  58. data/lib/puma/launcher.rb +205 -138
  59. data/lib/puma/log_writer.rb +147 -0
  60. data/lib/puma/minissl/context_builder.rb +96 -0
  61. data/lib/puma/minissl.rb +279 -70
  62. data/lib/puma/null_io.rb +61 -2
  63. data/lib/puma/plugin/systemd.rb +90 -0
  64. data/lib/puma/plugin/tmp_restart.rb +3 -1
  65. data/lib/puma/plugin.rb +9 -13
  66. data/lib/puma/rack/builder.rb +10 -11
  67. data/lib/puma/rack/urlmap.rb +3 -1
  68. data/lib/puma/rack_default.rb +21 -4
  69. data/lib/puma/reactor.rb +97 -185
  70. data/lib/puma/request.rb +688 -0
  71. data/lib/puma/runner.rb +114 -69
  72. data/lib/puma/sd_notify.rb +146 -0
  73. data/lib/puma/server.rb +409 -704
  74. data/lib/puma/single.rb +29 -72
  75. data/lib/puma/state_file.rb +48 -9
  76. data/lib/puma/thread_pool.rb +234 -93
  77. data/lib/puma/util.rb +23 -10
  78. data/lib/puma.rb +68 -5
  79. data/lib/rack/handler/puma.rb +119 -86
  80. data/tools/Dockerfile +16 -0
  81. data/tools/trickletest.rb +0 -1
  82. metadata +55 -33
  83. data/ext/puma_http11/io_buffer.c +0 -155
  84. data/lib/puma/accept_nonblock.rb +0 -23
  85. data/lib/puma/compat.rb +0 -14
  86. data/lib/puma/convenient.rb +0 -23
  87. data/lib/puma/daemon_ext.rb +0 -31
  88. data/lib/puma/delegation.rb +0 -11
  89. data/lib/puma/java_io_buffer.rb +0 -45
  90. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  91. data/lib/puma/tcp_logger.rb +0 -39
  92. data/tools/jungle/README.md +0 -13
  93. data/tools/jungle/init.d/README.md +0 -59
  94. data/tools/jungle/init.d/puma +0 -421
  95. data/tools/jungle/init.d/run-puma +0 -18
  96. data/tools/jungle/upstart/README.md +0 -61
  97. data/tools/jungle/upstart/puma-manager.conf +0 -31
  98. data/tools/jungle/upstart/puma.conf +0 -69
@@ -2,12 +2,7 @@
2
2
 
3
3
  #include <ruby.h>
4
4
  #include <ruby/version.h>
5
-
6
- #if RUBY_API_VERSION_MAJOR == 1
7
- #include <rubyio.h>
8
- #else
9
5
  #include <ruby/io.h>
10
- #endif
11
6
 
12
7
  #ifdef HAVE_OPENSSL_BIO_H
13
8
 
@@ -33,7 +28,22 @@ typedef struct {
33
28
  int bytes;
34
29
  } ms_cert_buf;
35
30
 
36
- void engine_free(ms_conn* conn) {
31
+ VALUE eError;
32
+
33
+ NORETURN(void raise_file_error(const char* caller, const char *filename));
34
+
35
+ void raise_file_error(const char* caller, const char *filename) {
36
+ rb_raise(eError, "%s: error in file '%s': %s", caller, filename, ERR_error_string(ERR_get_error(), NULL));
37
+ }
38
+
39
+ NORETURN(void raise_param_error(const char* caller, const char *param));
40
+
41
+ void raise_param_error(const char* caller, const char *param) {
42
+ rb_raise(eError, "%s: error with parameter '%s': %s", caller, param, ERR_error_string(ERR_get_error(), NULL));
43
+ }
44
+
45
+ void engine_free(void *ptr) {
46
+ ms_conn *conn = ptr;
37
47
  ms_cert_buf* cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
38
48
  if(cert_buf) {
39
49
  OPENSSL_free(cert_buf->buf);
@@ -45,61 +55,72 @@ void engine_free(ms_conn* conn) {
45
55
  free(conn);
46
56
  }
47
57
 
48
- ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
49
- ms_conn* conn;
50
-
51
- *obj = Data_Make_Struct(klass, ms_conn, 0, engine_free, conn);
52
-
53
- conn->read = BIO_new(BIO_s_mem());
54
- BIO_set_nbio(conn->read, 1);
55
-
56
- conn->write = BIO_new(BIO_s_mem());
57
- BIO_set_nbio(conn->write, 1);
58
-
59
- conn->ssl = 0;
60
- conn->ctx = 0;
61
-
62
- return conn;
63
- }
58
+ const rb_data_type_t engine_data_type = {
59
+ "MiniSSL/ENGINE",
60
+ { 0, engine_free, 0 },
61
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
62
+ };
64
63
 
65
- DH *get_dh1024() {
66
- /* `openssl dhparam 1024 -C`
64
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
65
+ DH *get_dh2048(void) {
66
+ /* `openssl dhparam -C 2048`
67
67
  * -----BEGIN DH PARAMETERS-----
68
- * MIGHAoGBALPwcEv0OstmQCZdfHw0N5r+07lmXMxkpQacy1blwj0LUqC+Divp6pBk
69
- * usTJ9W2/dOYr1X7zi6yXNLp4oLzc/31PUL3D9q8CpGS7vPz5gijKSw9BwCTT5z9+
70
- * KF9v46qw8XqT5HHV87sWFlGQcVFq+pEkA2kPikkKZ/X/CCcpCAV7AgEC
68
+ * MIIBCAKCAQEAjmh1uQHdTfxOyxEbKAV30fUfzqMDF/ChPzjfyzl2jcrqQMhrk76o
69
+ * 2NPNXqxHwsddMZ1RzvU8/jl+uhRuPWjXCFZbhET4N1vrviZM3VJhV8PPHuiVOACO
70
+ * y32jFd+Szx4bo2cXSK83hJ6jRd+0asP1awWjz9/06dFkrILCXMIfQLo0D8rqmppn
71
+ * EfDDAwuudCpM9kcDmBRAm9JsKbQ6gzZWjkc5+QWSaQofojIHbjvj3xzguaCJn+oQ
72
+ * vHWM+hsAnaOgEwCyeZ3xqs+/5lwSbkE/tqJW98cEZGygBUVo9jxZRZx6KOfjpdrb
73
+ * yenO9LJr/qtyrZB31WJbqxI0m0AKTAO8UwIBAg==
71
74
  * -----END DH PARAMETERS-----
72
75
  */
73
- static unsigned char dh1024_p[] = {
74
- 0xB3,0xF0,0x70,0x4B,0xF4,0x3A,0xCB,0x66,0x40,0x26,0x5D,0x7C,
75
- 0x7C,0x34,0x37,0x9A,0xFE,0xD3,0xB9,0x66,0x5C,0xCC,0x64,0xA5,
76
- 0x06,0x9C,0xCB,0x56,0xE5,0xC2,0x3D,0x0B,0x52,0xA0,0xBE,0x0E,
77
- 0x2B,0xE9,0xEA,0x90,0x64,0xBA,0xC4,0xC9,0xF5,0x6D,0xBF,0x74,
78
- 0xE6,0x2B,0xD5,0x7E,0xF3,0x8B,0xAC,0x97,0x34,0xBA,0x78,0xA0,
79
- 0xBC,0xDC,0xFF,0x7D,0x4F,0x50,0xBD,0xC3,0xF6,0xAF,0x02,0xA4,
80
- 0x64,0xBB,0xBC,0xFC,0xF9,0x82,0x28,0xCA,0x4B,0x0F,0x41,0xC0,
81
- 0x24,0xD3,0xE7,0x3F,0x7E,0x28,0x5F,0x6F,0xE3,0xAA,0xB0,0xF1,
82
- 0x7A,0x93,0xE4,0x71,0xD5,0xF3,0xBB,0x16,0x16,0x51,0x90,0x71,
83
- 0x51,0x6A,0xFA,0x91,0x24,0x03,0x69,0x0F,0x8A,0x49,0x0A,0x67,
84
- 0xF5,0xFF,0x08,0x27,0x29,0x08,0x05,0x7B
76
+ static unsigned char dh2048_p[] = {
77
+ 0x8E, 0x68, 0x75, 0xB9, 0x01, 0xDD, 0x4D, 0xFC, 0x4E, 0xCB,
78
+ 0x11, 0x1B, 0x28, 0x05, 0x77, 0xD1, 0xF5, 0x1F, 0xCE, 0xA3,
79
+ 0x03, 0x17, 0xF0, 0xA1, 0x3F, 0x38, 0xDF, 0xCB, 0x39, 0x76,
80
+ 0x8D, 0xCA, 0xEA, 0x40, 0xC8, 0x6B, 0x93, 0xBE, 0xA8, 0xD8,
81
+ 0xD3, 0xCD, 0x5E, 0xAC, 0x47, 0xC2, 0xC7, 0x5D, 0x31, 0x9D,
82
+ 0x51, 0xCE, 0xF5, 0x3C, 0xFE, 0x39, 0x7E, 0xBA, 0x14, 0x6E,
83
+ 0x3D, 0x68, 0xD7, 0x08, 0x56, 0x5B, 0x84, 0x44, 0xF8, 0x37,
84
+ 0x5B, 0xEB, 0xBE, 0x26, 0x4C, 0xDD, 0x52, 0x61, 0x57, 0xC3,
85
+ 0xCF, 0x1E, 0xE8, 0x95, 0x38, 0x00, 0x8E, 0xCB, 0x7D, 0xA3,
86
+ 0x15, 0xDF, 0x92, 0xCF, 0x1E, 0x1B, 0xA3, 0x67, 0x17, 0x48,
87
+ 0xAF, 0x37, 0x84, 0x9E, 0xA3, 0x45, 0xDF, 0xB4, 0x6A, 0xC3,
88
+ 0xF5, 0x6B, 0x05, 0xA3, 0xCF, 0xDF, 0xF4, 0xE9, 0xD1, 0x64,
89
+ 0xAC, 0x82, 0xC2, 0x5C, 0xC2, 0x1F, 0x40, 0xBA, 0x34, 0x0F,
90
+ 0xCA, 0xEA, 0x9A, 0x9A, 0x67, 0x11, 0xF0, 0xC3, 0x03, 0x0B,
91
+ 0xAE, 0x74, 0x2A, 0x4C, 0xF6, 0x47, 0x03, 0x98, 0x14, 0x40,
92
+ 0x9B, 0xD2, 0x6C, 0x29, 0xB4, 0x3A, 0x83, 0x36, 0x56, 0x8E,
93
+ 0x47, 0x39, 0xF9, 0x05, 0x92, 0x69, 0x0A, 0x1F, 0xA2, 0x32,
94
+ 0x07, 0x6E, 0x3B, 0xE3, 0xDF, 0x1C, 0xE0, 0xB9, 0xA0, 0x89,
95
+ 0x9F, 0xEA, 0x10, 0xBC, 0x75, 0x8C, 0xFA, 0x1B, 0x00, 0x9D,
96
+ 0xA3, 0xA0, 0x13, 0x00, 0xB2, 0x79, 0x9D, 0xF1, 0xAA, 0xCF,
97
+ 0xBF, 0xE6, 0x5C, 0x12, 0x6E, 0x41, 0x3F, 0xB6, 0xA2, 0x56,
98
+ 0xF7, 0xC7, 0x04, 0x64, 0x6C, 0xA0, 0x05, 0x45, 0x68, 0xF6,
99
+ 0x3C, 0x59, 0x45, 0x9C, 0x7A, 0x28, 0xE7, 0xE3, 0xA5, 0xDA,
100
+ 0xDB, 0xC9, 0xE9, 0xCE, 0xF4, 0xB2, 0x6B, 0xFE, 0xAB, 0x72,
101
+ 0xAD, 0x90, 0x77, 0xD5, 0x62, 0x5B, 0xAB, 0x12, 0x34, 0x9B,
102
+ 0x40, 0x0A, 0x4C, 0x03, 0xBC, 0x53
85
103
  };
86
- static unsigned char dh1024_g[] = { 0x02 };
104
+ static unsigned char dh2048_g[] = { 0x02 };
87
105
 
88
106
  DH *dh;
107
+ #if !(OPENSSL_VERSION_NUMBER < 0x10100005L)
108
+ BIGNUM *p, *g;
109
+ #endif
110
+
89
111
  dh = DH_new();
90
112
 
91
- #if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
92
- dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
93
- dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
113
+ #if OPENSSL_VERSION_NUMBER < 0x10100005L
114
+ dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
115
+ dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
94
116
 
95
117
  if ((dh->p == NULL) || (dh->g == NULL)) {
96
118
  DH_free(dh);
97
119
  return NULL;
98
120
  }
99
121
  #else
100
- BIGNUM *p, *g;
101
- p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
102
- g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
122
+ p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
123
+ g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
103
124
 
104
125
  if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) {
105
126
  DH_free(dh);
@@ -111,6 +132,38 @@ DH *get_dh1024() {
111
132
 
112
133
  return dh;
113
134
  }
135
+ #endif
136
+
137
+ static void
138
+ sslctx_free(void *ptr) {
139
+ SSL_CTX *ctx = ptr;
140
+ SSL_CTX_free(ctx);
141
+ }
142
+
143
+ static const rb_data_type_t sslctx_type = {
144
+ "MiniSSL/SSLContext",
145
+ {
146
+ 0, sslctx_free,
147
+ },
148
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
149
+ };
150
+
151
+ ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
152
+ ms_conn* conn;
153
+
154
+ *obj = TypedData_Make_Struct(klass, ms_conn, &engine_data_type, conn);
155
+
156
+ conn->read = BIO_new(BIO_s_mem());
157
+ BIO_set_nbio(conn->read, 1);
158
+
159
+ conn->write = BIO_new(BIO_s_mem());
160
+ BIO_set_nbio(conn->write, 1);
161
+
162
+ conn->ssl = 0;
163
+ conn->ctx = 0;
164
+
165
+ return conn;
166
+ }
114
167
 
115
168
  static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
116
169
  X509* err_cert;
@@ -138,68 +191,328 @@ static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
138
191
  return preverify_ok;
139
192
  }
140
193
 
141
- VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
142
- VALUE obj;
194
+ static int password_callback(char *buf, int size, int rwflag, void *userdata) {
195
+ const char *password = (const char *) userdata;
196
+ size_t len = strlen(password);
197
+
198
+ if (len > (size_t) size) {
199
+ return 0;
200
+ }
201
+
202
+ memcpy(buf, password, len);
203
+ return (int) len;
204
+ }
205
+
206
+ static VALUE
207
+ sslctx_alloc(VALUE klass) {
208
+ SSL_CTX *ctx;
209
+ long mode = 0 |
210
+ SSL_MODE_ENABLE_PARTIAL_WRITE |
211
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
212
+ SSL_MODE_RELEASE_BUFFERS;
213
+
214
+ #ifdef HAVE_TLS_SERVER_METHOD
215
+ ctx = SSL_CTX_new(TLS_method());
216
+ // printf("\nctx using TLS_method security_level %d\n", SSL_CTX_get_security_level(ctx));
217
+ #else
218
+ ctx = SSL_CTX_new(SSLv23_method());
219
+ #endif
220
+ if (!ctx) {
221
+ rb_raise(eError, "SSL_CTX_new");
222
+ }
223
+ SSL_CTX_set_mode(ctx, mode);
224
+
225
+ return TypedData_Wrap_Struct(klass, &sslctx_type, ctx);
226
+ }
227
+
228
+ VALUE
229
+ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
143
230
  SSL_CTX* ctx;
144
- SSL* ssl;
231
+ int ssl_options;
232
+ VALUE key, cert, ca, verify_mode, ssl_cipher_filter, ssl_ciphersuites, no_tlsv1, no_tlsv1_1,
233
+ verification_flags, session_id_bytes, cert_pem, key_pem, key_password_command, key_password;
234
+ BIO *bio;
235
+ X509 *x509 = NULL;
236
+ EVP_PKEY *pkey;
237
+ pem_password_cb *password_cb = NULL;
238
+ const char *password = NULL;
239
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
240
+ int min;
241
+ #endif
242
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
243
+ DH *dh;
244
+ #endif
245
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
246
+ EC_KEY *ecdh;
247
+ #endif
248
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
249
+ VALUE reuse, reuse_cache_size, reuse_timeout;
250
+
251
+ reuse = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse"), 0);
252
+ reuse_cache_size = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_cache_size"), 0);
253
+ reuse_timeout = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_timeout"), 0);
254
+ #endif
255
+
256
+ key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
257
+
258
+ key_password_command = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password_command"), 0);
259
+
260
+ cert = rb_funcall(mini_ssl_ctx, rb_intern_const("cert"), 0);
261
+
262
+ ca = rb_funcall(mini_ssl_ctx, rb_intern_const("ca"), 0);
263
+
264
+ cert_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("cert_pem"), 0);
265
+
266
+ key_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("key_pem"), 0);
267
+
268
+ verify_mode = rb_funcall(mini_ssl_ctx, rb_intern_const("verify_mode"), 0);
269
+
270
+ ssl_cipher_filter = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_cipher_filter"), 0);
271
+
272
+ ssl_ciphersuites = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_ciphersuites"), 0);
273
+
274
+ no_tlsv1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1"), 0);
275
+
276
+ no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0);
277
+
278
+ TypedData_Get_Struct(self, SSL_CTX, &sslctx_type, ctx);
279
+
280
+ if (!NIL_P(cert)) {
281
+ StringValue(cert);
282
+
283
+ if (SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)) != 1) {
284
+ raise_file_error("SSL_CTX_use_certificate_chain_file", RSTRING_PTR(cert));
285
+ }
286
+ }
287
+
288
+ if (!NIL_P(key_password_command)) {
289
+ key_password = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password"), 0);
290
+
291
+ if (!NIL_P(key_password)) {
292
+ StringValue(key_password);
293
+ password_cb = password_callback;
294
+ password = RSTRING_PTR(key_password);
295
+ SSL_CTX_set_default_passwd_cb(ctx, password_cb);
296
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) password);
297
+ }
298
+ }
299
+
300
+ if (!NIL_P(key)) {
301
+ StringValue(key);
302
+
303
+ if (SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM) != 1) {
304
+ raise_file_error("SSL_CTX_use_PrivateKey_file", RSTRING_PTR(key));
305
+ }
306
+ }
307
+
308
+ if (!NIL_P(cert_pem)) {
309
+ X509 *ca = NULL;
310
+ unsigned long err;
311
+
312
+ bio = BIO_new(BIO_s_mem());
313
+ BIO_puts(bio, RSTRING_PTR(cert_pem));
314
+
315
+ /**
316
+ * Much of this pulled as a simplified version of the `use_certificate_chain_file` method
317
+ * from openssl's `ssl_rsa.c` file.
318
+ */
319
+
320
+ /* first read the cert as the first item in the pem file */
321
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
322
+ if (NULL == x509) {
323
+ BIO_free_all(bio);
324
+ raise_param_error("PEM_read_bio_X509", "cert_pem");
325
+ }
145
326
 
146
- ms_conn* conn = engine_alloc(self, &obj);
327
+ /* Add the cert to the context */
328
+ /* 1 is success - otherwise check the error codes */
329
+ if (1 != SSL_CTX_use_certificate(ctx, x509)) {
330
+ BIO_free_all(bio);
331
+ raise_param_error("SSL_CTX_use_certificate", "cert_pem");
332
+ }
147
333
 
148
- ID sym_key = rb_intern("key");
149
- VALUE key = rb_funcall(mini_ssl_ctx, sym_key, 0);
334
+ X509_free(x509); /* no longer need our reference */
150
335
 
151
- StringValue(key);
336
+ /* Now lets load up the rest of the certificate chain */
337
+ /* 1 is success 0 is error */
338
+ if (0 == SSL_CTX_clear_chain_certs(ctx)) {
339
+ BIO_free_all(bio);
340
+ raise_param_error("SSL_CTX_clear_chain_certs","cert_pem");
341
+ }
152
342
 
153
- ID sym_cert = rb_intern("cert");
154
- VALUE cert = rb_funcall(mini_ssl_ctx, sym_cert, 0);
343
+ while (1) {
344
+ ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
155
345
 
156
- StringValue(cert);
346
+ if (NULL == ca) {
347
+ break;
348
+ }
157
349
 
158
- ID sym_ca = rb_intern("ca");
159
- VALUE ca = rb_funcall(mini_ssl_ctx, sym_ca, 0);
350
+ if (0 == SSL_CTX_add0_chain_cert(ctx, ca)) {
351
+ BIO_free_all(bio);
352
+ raise_param_error("SSL_CTX_add0_chain_cert","cert_pem");
353
+ }
354
+ /* don't free ca - its now owned by the context */
355
+ }
160
356
 
161
- ID sym_verify_mode = rb_intern("verify_mode");
162
- VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
357
+ /* ca is NULL - so its either the end of the file or an error */
358
+ err = ERR_peek_last_error();
163
359
 
164
- ctx = SSL_CTX_new(SSLv23_server_method());
165
- conn->ctx = ctx;
360
+ /* If its the end of the file - then we are done, in any case free the bio */
361
+ BIO_free_all(bio);
166
362
 
167
- SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
168
- SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
363
+ if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
364
+ ERR_clear_error();
365
+ } else {
366
+ raise_param_error("PEM_read_bio_X509","cert_pem");
367
+ }
368
+ }
369
+
370
+ if (!NIL_P(key_pem)) {
371
+ bio = BIO_new(BIO_s_mem());
372
+ BIO_puts(bio, RSTRING_PTR(key_pem));
373
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, password_cb, (void *) password);
374
+
375
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
376
+ BIO_free(bio);
377
+ raise_file_error("SSL_CTX_use_PrivateKey", RSTRING_PTR(key_pem));
378
+ }
379
+ EVP_PKEY_free(pkey);
380
+ BIO_free(bio);
381
+ }
382
+
383
+ verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
384
+
385
+ if (!NIL_P(verification_flags)) {
386
+ X509_VERIFY_PARAM *param = SSL_CTX_get0_param(ctx);
387
+ X509_VERIFY_PARAM_set_flags(param, NUM2INT(verification_flags));
388
+ SSL_CTX_set1_param(ctx, param);
389
+ }
169
390
 
170
391
  if (!NIL_P(ca)) {
171
392
  StringValue(ca);
172
- SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
393
+ if (SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL) != 1) {
394
+ raise_file_error("SSL_CTX_load_verify_locations", RSTRING_PTR(ca));
395
+ }
173
396
  }
174
397
 
175
- SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION);
176
- SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
398
+ ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
399
+
400
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
401
+ if (RTEST(no_tlsv1_1)) {
402
+ min = TLS1_2_VERSION;
403
+ }
404
+ else if (RTEST(no_tlsv1)) {
405
+ min = TLS1_1_VERSION;
406
+ }
407
+ else {
408
+ min = TLS1_VERSION;
409
+ }
177
410
 
178
- SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
411
+ SSL_CTX_set_min_proto_version(ctx, min);
179
412
 
180
- DH *dh = get_dh1024();
181
- SSL_CTX_set_tmp_dh(ctx, dh);
413
+ #else
414
+ /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
415
+ ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
182
416
 
183
- #ifndef OPENSSL_NO_ECDH
184
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
417
+ if (RTEST(no_tlsv1)) {
418
+ ssl_options |= SSL_OP_NO_TLSv1;
419
+ }
420
+ if(RTEST(no_tlsv1_1)) {
421
+ ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
422
+ }
423
+ #endif
424
+
425
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
426
+ if (!NIL_P(reuse)) {
427
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
428
+ if (!NIL_P(reuse_cache_size)) {
429
+ SSL_CTX_sess_set_cache_size(ctx, NUM2INT(reuse_cache_size));
430
+ }
431
+ if (!NIL_P(reuse_timeout)) {
432
+ SSL_CTX_set_timeout(ctx, NUM2INT(reuse_timeout));
433
+ }
434
+ } else {
435
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
436
+ }
437
+ #endif
438
+
439
+ SSL_CTX_set_options(ctx, ssl_options);
440
+
441
+ if (!NIL_P(ssl_cipher_filter)) {
442
+ StringValue(ssl_cipher_filter);
443
+ SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
444
+ }
445
+ else {
446
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
447
+ }
448
+
449
+ #if HAVE_SSL_CTX_SET_CIPHERSUITES
450
+ // Only override OpenSSL default ciphersuites if config option is supplied.
451
+ if (!NIL_P(ssl_ciphersuites)) {
452
+ StringValue(ssl_ciphersuites);
453
+ SSL_CTX_set_ciphersuites(ctx, RSTRING_PTR(ssl_ciphersuites));
454
+ }
455
+ #endif
456
+
457
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
458
+ // Remove this case if OpenSSL 1.0.1 (now EOL) support is no longer needed.
459
+ ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
185
460
  if (ecdh) {
186
461
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
187
462
  EC_KEY_free(ecdh);
188
463
  }
464
+ #elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
465
+ SSL_CTX_set_ecdh_auto(ctx, 1);
189
466
  #endif
190
467
 
191
- ssl = SSL_new(ctx);
192
- conn->ssl = ssl;
193
- SSL_set_app_data(ssl, NULL);
194
-
195
468
  if (NIL_P(verify_mode)) {
196
- /* SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); */
469
+ /* SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); */
197
470
  } else {
198
- SSL_set_verify(ssl, NUM2INT(verify_mode), engine_verify_callback);
471
+ SSL_CTX_set_verify(ctx, NUM2INT(verify_mode), engine_verify_callback);
199
472
  }
200
473
 
201
- SSL_set_bio(ssl, conn->read, conn->write);
474
+ // Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
475
+ session_id_bytes = rb_funcall(
476
+ #ifdef HAVE_RANDOM_BYTES
477
+ rb_cRandom,
478
+ #else
479
+ rb_const_get(rb_cRandom, rb_intern_const("DEFAULT")),
480
+ #endif
481
+ rb_intern_const("bytes"),
482
+ 1, ULL2NUM(SSL_MAX_SSL_SESSION_ID_LENGTH));
483
+
484
+ SSL_CTX_set_session_id_context(ctx,
485
+ (unsigned char *) RSTRING_PTR(session_id_bytes),
486
+ SSL_MAX_SSL_SESSION_ID_LENGTH);
487
+
488
+ // printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
202
489
 
490
+ #ifdef HAVE_SSL_CTX_SET_DH_AUTO
491
+ // https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_dh_auto.html
492
+ SSL_CTX_set_dh_auto(ctx, 1);
493
+ #else
494
+ dh = get_dh2048();
495
+ SSL_CTX_set_tmp_dh(ctx, dh);
496
+ #endif
497
+
498
+ rb_obj_freeze(self);
499
+ return self;
500
+ }
501
+
502
+ VALUE engine_init_server(VALUE self, VALUE sslctx) {
503
+ ms_conn* conn;
504
+ VALUE obj;
505
+ SSL_CTX* ctx;
506
+ SSL* ssl;
507
+
508
+ conn = engine_alloc(self, &obj);
509
+
510
+ TypedData_Get_Struct(sslctx, SSL_CTX, &sslctx_type, ctx);
511
+
512
+ ssl = SSL_new(ctx);
513
+ conn->ssl = ssl;
514
+ SSL_set_app_data(ssl, NULL);
515
+ SSL_set_bio(ssl, conn->read, conn->write);
203
516
  SSL_set_accept_state(ssl);
204
517
  return obj;
205
518
  }
@@ -207,8 +520,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
207
520
  VALUE engine_init_client(VALUE klass) {
208
521
  VALUE obj;
209
522
  ms_conn* conn = engine_alloc(klass, &obj);
210
-
523
+ #ifdef HAVE_DTLS_METHOD
524
+ conn->ctx = SSL_CTX_new(DTLS_method());
525
+ #else
211
526
  conn->ctx = SSL_CTX_new(DTLSv1_method());
527
+ #endif
212
528
  conn->ssl = SSL_new(conn->ctx);
213
529
  SSL_set_app_data(conn->ssl, NULL);
214
530
  SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
@@ -223,7 +539,7 @@ VALUE engine_inject(VALUE self, VALUE str) {
223
539
  ms_conn* conn;
224
540
  long used;
225
541
 
226
- Data_Get_Struct(self, ms_conn, conn);
542
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
227
543
 
228
544
  StringValue(str);
229
545
 
@@ -236,13 +552,14 @@ VALUE engine_inject(VALUE self, VALUE str) {
236
552
  return INT2FIX(used);
237
553
  }
238
554
 
239
- static VALUE eError;
555
+ NORETURN(void raise_error(SSL* ssl, int result));
240
556
 
241
557
  void raise_error(SSL* ssl, int result) {
242
558
  char buf[512];
243
- char msg[512];
559
+ char msg[768];
244
560
  const char* err_str;
245
561
  int err = errno;
562
+ int mask = 4095;
246
563
  int ssl_err = SSL_get_error(ssl, result);
247
564
  int verify_err = (int) SSL_get_verify_result(ssl);
248
565
 
@@ -259,8 +576,7 @@ void raise_error(SSL* ssl, int result) {
259
576
  } else {
260
577
  err = (int) ERR_get_error();
261
578
  ERR_error_string_n(err, buf, sizeof(buf));
262
- snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
263
-
579
+ snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err & mask);
264
580
  }
265
581
  } else {
266
582
  snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
@@ -275,7 +591,7 @@ VALUE engine_read(VALUE self) {
275
591
  char buf[512];
276
592
  int bytes, error;
277
593
 
278
- Data_Get_Struct(self, ms_conn, conn);
594
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
279
595
 
280
596
  ERR_clear_error();
281
597
 
@@ -302,7 +618,7 @@ VALUE engine_write(VALUE self, VALUE str) {
302
618
  ms_conn* conn;
303
619
  int bytes;
304
620
 
305
- Data_Get_Struct(self, ms_conn, conn);
621
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
306
622
 
307
623
  StringValue(str);
308
624
 
@@ -324,9 +640,11 @@ VALUE engine_extract(VALUE self) {
324
640
  ms_conn* conn;
325
641
  int bytes;
326
642
  size_t pending;
327
- char buf[512];
643
+ // https://www.openssl.org/docs/manmaster/man3/BIO_f_buffer.html
644
+ // crypto/bio/bf_buff.c DEFAULT_BUFFER_SIZE
645
+ char buf[4096];
328
646
 
329
- Data_Get_Struct(self, ms_conn, conn);
647
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
330
648
 
331
649
  pending = BIO_pending(conn->write);
332
650
  if(pending > 0) {
@@ -345,7 +663,7 @@ VALUE engine_shutdown(VALUE self) {
345
663
  ms_conn* conn;
346
664
  int ok;
347
665
 
348
- Data_Get_Struct(self, ms_conn, conn);
666
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
349
667
 
350
668
  ERR_clear_error();
351
669
 
@@ -360,7 +678,7 @@ VALUE engine_shutdown(VALUE self) {
360
678
  VALUE engine_init(VALUE self) {
361
679
  ms_conn* conn;
362
680
 
363
- Data_Get_Struct(self, ms_conn, conn);
681
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
364
682
 
365
683
  return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
366
684
  }
@@ -373,9 +691,13 @@ VALUE engine_peercert(VALUE self) {
373
691
  ms_cert_buf* cert_buf = NULL;
374
692
  VALUE rb_cert_buf;
375
693
 
376
- Data_Get_Struct(self, ms_conn, conn);
694
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
377
695
 
696
+ #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
697
+ cert = SSL_get1_peer_certificate(conn->ssl);
698
+ #else
378
699
  cert = SSL_get_peer_certificate(conn->ssl);
700
+ #endif
379
701
  if(!cert) {
380
702
  /*
381
703
  * See if there was a failed certificate associated with this client.
@@ -404,12 +726,22 @@ VALUE engine_peercert(VALUE self) {
404
726
  return rb_cert_buf;
405
727
  }
406
728
 
729
+ /* @see Puma::MiniSSL::Socket#ssl_version_state
730
+ * @version 5.0.0
731
+ */
732
+ static VALUE
733
+ engine_ssl_vers_st(VALUE self) {
734
+ ms_conn* conn;
735
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
736
+ return rb_ary_new3(2, rb_str_new2(SSL_get_version(conn->ssl)), rb_str_new2(SSL_state_string(conn->ssl)));
737
+ }
738
+
407
739
  VALUE noop(VALUE self) {
408
740
  return Qnil;
409
741
  }
410
742
 
411
743
  void Init_mini_ssl(VALUE puma) {
412
- VALUE mod, eng;
744
+ VALUE mod, eng, sslctx;
413
745
 
414
746
  /* Fake operation for documentation (RDoc, YARD) */
415
747
  #if 0 == 1
@@ -422,7 +754,48 @@ void Init_mini_ssl(VALUE puma) {
422
754
  ERR_load_crypto_strings();
423
755
 
424
756
  mod = rb_define_module_under(puma, "MiniSSL");
757
+
425
758
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
759
+ rb_undef_alloc_func(eng);
760
+
761
+ sslctx = rb_define_class_under(mod, "SSLContext", rb_cObject);
762
+ rb_define_alloc_func(sslctx, sslctx_alloc);
763
+ rb_define_method(sslctx, "initialize", sslctx_initialize, 1);
764
+ rb_undef_method(sslctx, "initialize_copy");
765
+
766
+
767
+ // OpenSSL Build / Runtime/Load versions
768
+
769
+ /* Version of OpenSSL that Puma was compiled with */
770
+ rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
771
+
772
+ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
773
+ /* Version of OpenSSL that Puma loaded with */
774
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
775
+ #else
776
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
777
+ #endif
778
+
779
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
780
+ /* True if SSL3 is not available */
781
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
782
+ #else
783
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
784
+ #endif
785
+
786
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
787
+ /* True if TLS1 is not available */
788
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
789
+ #else
790
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
791
+ #endif
792
+
793
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
794
+ /* True if TLS1_1 is not available */
795
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
796
+ #else
797
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
798
+ #endif
426
799
 
427
800
  rb_define_singleton_method(mod, "check", noop, 0);
428
801
 
@@ -441,14 +814,21 @@ void Init_mini_ssl(VALUE puma) {
441
814
 
442
815
  rb_define_method(eng, "init?", engine_init, 0);
443
816
 
817
+ /* @!attribute [r] peercert
818
+ * Returns `nil` when `MiniSSL::Context#verify_mode` is set to `VERIFY_NONE`.
819
+ * @return [String, nil] DER encoded cert
820
+ */
444
821
  rb_define_method(eng, "peercert", engine_peercert, 0);
822
+
823
+ rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
445
824
  }
446
825
 
447
826
  #else
448
827
 
828
+ NORETURN(VALUE raise_error(VALUE self));
829
+
449
830
  VALUE raise_error(VALUE self) {
450
831
  rb_raise(rb_eStandardError, "SSL not available in this build");
451
- return Qnil;
452
832
  }
453
833
 
454
834
  void Init_mini_ssl(VALUE puma) {