quic 0.0.3 → 0.0.5
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.
- checksums.yaml +4 -4
- data/.clang-format +1 -0
- data/.git-blame-ignore-revs +2 -0
- data/CHANGELOG.md +15 -0
- data/README.md +76 -2
- data/examples/demo_certificates.rb +67 -0
- data/examples/echo_endpoint_demo.rb +170 -0
- data/examples/echo_server_demo.rb +2 -58
- data/ext/quic/connection_client.c +77 -59
- data/ext/quic/connection_common.c +423 -377
- data/ext/quic/connection_common.h +20 -11
- data/ext/quic/connection_server.c +67 -48
- data/ext/quic/endpoint.c +206 -200
- data/ext/quic/endpoint.h +8 -5
- data/ext/quic/ext_api.c +41 -47
- data/ext/quic/include/quic/ext.h +26 -19
- data/ext/quic/quic.c +75 -67
- data/ext/quic/quic.h +4 -2
- data/ext/quic/stream.c +80 -80
- data/ext/quic/stream.h +11 -5
- data/ext/quic/tls_context.c +79 -70
- data/ext/quic/tls_context.h +2 -1
- data/lib/quic/version.rb +1 -1
- data/sig/quic.rbs +8 -4
- metadata +5 -1
|
@@ -10,14 +10,13 @@
|
|
|
10
10
|
share across verifications; creation runs under the GVL. Never freed. */
|
|
11
11
|
static X509_STORE *quic_default_store;
|
|
12
12
|
|
|
13
|
-
static X509_STORE *
|
|
14
|
-
quic_get_default_store(void)
|
|
15
|
-
{
|
|
13
|
+
static X509_STORE *quic_get_default_store(void) {
|
|
16
14
|
if (quic_default_store == NULL) {
|
|
17
15
|
X509_STORE *store = X509_STORE_new();
|
|
18
16
|
if (store == NULL || X509_STORE_set_default_paths(store) != 1) {
|
|
19
17
|
X509_STORE_free(store);
|
|
20
|
-
rb_raise(rb_eRuntimeError,
|
|
18
|
+
rb_raise(rb_eRuntimeError,
|
|
19
|
+
"failed to load the default certificate store");
|
|
21
20
|
}
|
|
22
21
|
quic_default_store = store;
|
|
23
22
|
}
|
|
@@ -31,8 +30,7 @@ quic_get_default_store(void)
|
|
|
31
30
|
static int
|
|
32
31
|
quic_override_verify_cb(ptls_openssl_override_verify_certificate_t *self,
|
|
33
32
|
ptls_t *tls, int ret, int ossl_ret, X509 *cert,
|
|
34
|
-
STACK_OF(X509) *chain)
|
|
35
|
-
{
|
|
33
|
+
STACK_OF(X509) * chain) {
|
|
36
34
|
(void)self;
|
|
37
35
|
(void)cert;
|
|
38
36
|
(void)chain;
|
|
@@ -46,35 +44,40 @@ quic_override_verify_cb(ptls_openssl_override_verify_certificate_t *self,
|
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
static ptls_openssl_override_verify_certificate_t quic_override_verify = {
|
|
49
|
-
|
|
47
|
+
quic_override_verify_cb,
|
|
50
48
|
};
|
|
51
49
|
|
|
52
50
|
/* Install picotls's certificate verifier on c->tls_ctx according to the
|
|
53
51
|
verify_mode / ca_file / ca_path settings. Leaves verify_certificate NULL
|
|
54
52
|
for verify_mode :none, which skips verification altogether. */
|
|
55
|
-
static void
|
|
56
|
-
|
|
57
|
-
{
|
|
53
|
+
static void quic_client_setup_verify(quic_conn_t *c, VALUE settings_v,
|
|
54
|
+
VALUE server_name) {
|
|
58
55
|
VALUE mode = rb_funcall(settings_v, rb_intern("verify_mode"), 0);
|
|
59
56
|
/* ca_file and ca_path are not even type-checked under :none. */
|
|
60
|
-
if (mode == ID2SYM(rb_intern("none")))
|
|
57
|
+
if (mode == ID2SYM(rb_intern("none")))
|
|
58
|
+
return;
|
|
61
59
|
if (mode != ID2SYM(rb_intern("peer"))) {
|
|
62
|
-
rb_raise(rb_eArgError,
|
|
60
|
+
rb_raise(rb_eArgError,
|
|
61
|
+
"verify_mode must be :peer or :none (got %+" PRIsVALUE ")", mode);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
VALUE ca_file = quic_path_value(
|
|
66
|
-
|
|
64
|
+
VALUE ca_file = quic_path_value(
|
|
65
|
+
rb_funcall(settings_v, rb_intern("ca_file"), 0), "ca_file");
|
|
66
|
+
VALUE ca_path = quic_path_value(
|
|
67
|
+
rb_funcall(settings_v, rb_intern("ca_path"), 0), "ca_path");
|
|
67
68
|
|
|
68
69
|
/* An empty name makes OpenSSL clear its host list and skip the name check,
|
|
69
70
|
and both SNI and the check would silently stop at an embedded NUL. */
|
|
70
71
|
if (RSTRING_LEN(server_name) == 0 ||
|
|
71
|
-
memchr(RSTRING_PTR(server_name), '\0',
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
memchr(RSTRING_PTR(server_name), '\0',
|
|
73
|
+
(size_t)RSTRING_LEN(server_name)) != NULL) {
|
|
74
|
+
rb_raise(rb_eArgError, "server_name must be a non-empty string without NUL "
|
|
75
|
+
"bytes when verify_mode is :peer");
|
|
74
76
|
}
|
|
75
77
|
/* X509_LOOKUP_hash_dir does not check that the directory exists. */
|
|
76
|
-
if (!NIL_P(ca_path) &&
|
|
77
|
-
|
|
78
|
+
if (!NIL_P(ca_path) &&
|
|
79
|
+
!RTEST(rb_funcall(rb_cFile, rb_intern("directory?"), 1, ca_path))) {
|
|
80
|
+
rb_raise(rb_eArgError, "ca_path is not a directory: %" PRIsVALUE, ca_path);
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
X509_STORE *store;
|
|
@@ -85,17 +88,17 @@ quic_client_setup_verify(quic_conn_t *c, VALUE settings_v, VALUE server_name)
|
|
|
85
88
|
if (store == NULL) {
|
|
86
89
|
rb_raise(rb_eRuntimeError, "X509_STORE_new failed");
|
|
87
90
|
}
|
|
88
|
-
if (X509_STORE_load_locations(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
if (X509_STORE_load_locations(
|
|
92
|
+
store, NIL_P(ca_file) ? NULL : RSTRING_PTR(ca_file),
|
|
93
|
+
NIL_P(ca_path) ? NULL : RSTRING_PTR(ca_path)) != 1) {
|
|
91
94
|
X509_STORE_free(store);
|
|
92
95
|
/* libcrypto is shared with Ruby's openssl extension; do not leave our
|
|
93
96
|
failure on its error queue. */
|
|
94
97
|
ERR_clear_error();
|
|
95
98
|
if (NIL_P(ca_file)) {
|
|
96
|
-
rb_raise(rb_eArgError, "failed to load ca_path: %"PRIsVALUE, ca_path);
|
|
99
|
+
rb_raise(rb_eArgError, "failed to load ca_path: %" PRIsVALUE, ca_path);
|
|
97
100
|
}
|
|
98
|
-
rb_raise(rb_eArgError, "failed to load ca_file: %"PRIsVALUE, ca_file);
|
|
101
|
+
rb_raise(rb_eArgError, "failed to load ca_file: %" PRIsVALUE, ca_file);
|
|
99
102
|
}
|
|
100
103
|
} else {
|
|
101
104
|
store = quic_get_default_store();
|
|
@@ -103,7 +106,8 @@ quic_client_setup_verify(quic_conn_t *c, VALUE settings_v, VALUE server_name)
|
|
|
103
106
|
|
|
104
107
|
/* init takes its own reference on the store, so ours can go right away. */
|
|
105
108
|
int rv = ptls_openssl_init_verify_certificate(&c->verify_cert, store);
|
|
106
|
-
if (own_store)
|
|
109
|
+
if (own_store)
|
|
110
|
+
X509_STORE_free(store);
|
|
107
111
|
if (rv != 0) {
|
|
108
112
|
rb_raise(rb_eRuntimeError, "ptls_openssl_init_verify_certificate failed");
|
|
109
113
|
}
|
|
@@ -112,29 +116,31 @@ quic_client_setup_verify(quic_conn_t *c, VALUE settings_v, VALUE server_name)
|
|
|
112
116
|
c->tls_ctx.verify_certificate = &c->verify_cert.super;
|
|
113
117
|
}
|
|
114
118
|
|
|
115
|
-
static VALUE
|
|
116
|
-
quic_client_open(int argc, VALUE *argv, VALUE klass)
|
|
117
|
-
{
|
|
119
|
+
static VALUE quic_client_open(int argc, VALUE *argv, VALUE klass) {
|
|
118
120
|
VALUE opts = Qnil;
|
|
119
121
|
rb_scan_args(argc, argv, "0:", &opts);
|
|
120
122
|
if (NIL_P(opts)) {
|
|
121
|
-
rb_raise(rb_eArgError,
|
|
122
|
-
|
|
123
|
+
rb_raise(rb_eArgError, "missing keywords: local_sockaddr, remote_sockaddr, "
|
|
124
|
+
"server_name, transport_params, settings");
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
VALUE local_sockaddr
|
|
126
|
-
|
|
127
|
-
VALUE
|
|
128
|
-
|
|
129
|
-
VALUE
|
|
127
|
+
VALUE local_sockaddr =
|
|
128
|
+
rb_hash_aref(opts, ID2SYM(rb_intern("local_sockaddr")));
|
|
129
|
+
VALUE remote_sockaddr =
|
|
130
|
+
rb_hash_aref(opts, ID2SYM(rb_intern("remote_sockaddr")));
|
|
131
|
+
VALUE server_name = rb_hash_aref(opts, ID2SYM(rb_intern("server_name")));
|
|
132
|
+
VALUE transport_params =
|
|
133
|
+
rb_hash_aref(opts, ID2SYM(rb_intern("transport_params")));
|
|
134
|
+
VALUE settings_v = rb_hash_aref(opts, ID2SYM(rb_intern("settings")));
|
|
130
135
|
|
|
131
136
|
if (NIL_P(local_sockaddr) || NIL_P(remote_sockaddr) || NIL_P(server_name) ||
|
|
132
137
|
NIL_P(transport_params) || NIL_P(settings_v)) {
|
|
133
138
|
rb_raise(rb_eArgError,
|
|
134
|
-
"all keywords required: local_sockaddr, remote_sockaddr,
|
|
139
|
+
"all keywords required: local_sockaddr, remote_sockaddr, "
|
|
140
|
+
"server_name, transport_params, settings");
|
|
135
141
|
}
|
|
136
142
|
|
|
137
|
-
quic_require_sockaddr(local_sockaddr,
|
|
143
|
+
quic_require_sockaddr(local_sockaddr, "local_sockaddr");
|
|
138
144
|
quic_require_sockaddr(remote_sockaddr, "remote_sockaddr");
|
|
139
145
|
Check_Type(server_name, T_STRING);
|
|
140
146
|
|
|
@@ -153,17 +159,18 @@ quic_client_open(int argc, VALUE *argv, VALUE klass)
|
|
|
153
159
|
the ngtcp2-side initialization explicit and the TLS setup in one place. */
|
|
154
160
|
ngtcp2_crypto_picotls_ctx_init(&c->cptls);
|
|
155
161
|
c->tls_ctx = (ptls_context_t){
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
.random_bytes = ptls_openssl_random_bytes,
|
|
163
|
+
.get_time = &ptls_get_time,
|
|
164
|
+
.key_exchanges = quic_key_exchanges,
|
|
165
|
+
.cipher_suites = quic_cipher_suites,
|
|
166
|
+
/* No session resumption yet, so this has no effect today. Keep it so that
|
|
167
|
+
when resumption is added, PSK-only (non-forward-secret) resumption is
|
|
168
|
+
refused rather than silently accepted. */
|
|
169
|
+
.require_dhe_on_psk = 1,
|
|
164
170
|
};
|
|
165
171
|
if (ngtcp2_crypto_picotls_configure_client_context(&c->tls_ctx) != 0) {
|
|
166
|
-
rb_raise(rb_eRuntimeError,
|
|
172
|
+
rb_raise(rb_eRuntimeError,
|
|
173
|
+
"ngtcp2_crypto_picotls_configure_client_context failed");
|
|
167
174
|
}
|
|
168
175
|
|
|
169
176
|
/* ptls_client_new keeps a pointer to tls_ctx, so the verifier has to be in
|
|
@@ -189,21 +196,27 @@ quic_client_open(int argc, VALUE *argv, VALUE klass)
|
|
|
189
196
|
|
|
190
197
|
ngtcp2_settings settings;
|
|
191
198
|
quic_fill_settings(&settings, settings_v);
|
|
192
|
-
quic_conn_open_qlog(c, settings_v, &settings);
|
|
193
199
|
|
|
194
200
|
ngtcp2_transport_params params;
|
|
195
201
|
quic_fill_transport_params(¶ms, transport_params);
|
|
196
202
|
|
|
203
|
+
/* Opened once the caller's values have all been read, so that a bad one
|
|
204
|
+
leaves no file behind. Every raise below closes it first. */
|
|
205
|
+
quic_conn_open_qlog(c, settings_v, &settings);
|
|
206
|
+
|
|
197
207
|
ngtcp2_path path = {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
208
|
+
{(struct sockaddr *)RSTRING_PTR(local_sockaddr),
|
|
209
|
+
(ngtcp2_socklen)RSTRING_LEN(local_sockaddr)},
|
|
210
|
+
{(struct sockaddr *)RSTRING_PTR(remote_sockaddr),
|
|
211
|
+
(ngtcp2_socklen)RSTRING_LEN(remote_sockaddr)},
|
|
212
|
+
NULL,
|
|
201
213
|
};
|
|
202
214
|
|
|
203
215
|
int rv = ngtcp2_conn_client_new(&c->conn, &c->dcid, &c->scid, &path,
|
|
204
|
-
NGTCP2_PROTO_VER_V1, &callbacks,
|
|
205
|
-
&
|
|
216
|
+
NGTCP2_PROTO_VER_V1, &callbacks, &settings,
|
|
217
|
+
¶ms, NULL, c);
|
|
206
218
|
if (rv != 0) {
|
|
219
|
+
quic_conn_close_qlog(c);
|
|
207
220
|
quic_raise_ngtcp2_error(rv);
|
|
208
221
|
}
|
|
209
222
|
|
|
@@ -211,6 +224,7 @@ quic_client_open(int argc, VALUE *argv, VALUE klass)
|
|
|
211
224
|
transport parameters from the conn, so it needs the conn to exist. */
|
|
212
225
|
c->cptls.ptls = ptls_client_new(&c->tls_ctx);
|
|
213
226
|
if (c->cptls.ptls == NULL) {
|
|
227
|
+
quic_conn_close_qlog(c);
|
|
214
228
|
rb_raise(rb_eRuntimeError, "ptls_client_new failed");
|
|
215
229
|
}
|
|
216
230
|
/* Let ngtcp2's crypto callbacks (add_handshake_data,
|
|
@@ -222,13 +236,17 @@ quic_client_open(int argc, VALUE *argv, VALUE klass)
|
|
|
222
236
|
c->tls_exts[1].type = UINT16_MAX;
|
|
223
237
|
c->cptls.handshake_properties.additional_extensions = c->tls_exts;
|
|
224
238
|
if (ngtcp2_crypto_picotls_configure_client_session(&c->cptls, c->conn) != 0) {
|
|
225
|
-
|
|
239
|
+
quic_conn_close_qlog(c);
|
|
240
|
+
rb_raise(rb_eRuntimeError,
|
|
241
|
+
"ngtcp2_crypto_picotls_configure_client_session failed");
|
|
226
242
|
}
|
|
227
243
|
c->cptls.handshake_properties.client.negotiated_protocols.list = c->alpn;
|
|
228
|
-
c->cptls.handshake_properties.client.negotiated_protocols.count =
|
|
244
|
+
c->cptls.handshake_properties.client.negotiated_protocols.count =
|
|
245
|
+
c->alpn_count;
|
|
229
246
|
/* ptls_set_server_name copies the name. */
|
|
230
247
|
if (ptls_set_server_name(c->cptls.ptls, RSTRING_PTR(server_name),
|
|
231
248
|
(size_t)RSTRING_LEN(server_name)) != 0) {
|
|
249
|
+
quic_conn_close_qlog(c);
|
|
232
250
|
rb_raise(rb_eRuntimeError, "ptls_set_server_name failed");
|
|
233
251
|
}
|
|
234
252
|
|
|
@@ -246,11 +264,11 @@ quic_client_open(int argc, VALUE *argv, VALUE klass)
|
|
|
246
264
|
return self;
|
|
247
265
|
}
|
|
248
266
|
|
|
249
|
-
void
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
rb_cQUICConnectionClient = rb_define_class_under(rb_mQUICConnectionArg, "Client", rb_cObject);
|
|
267
|
+
void Init_quic_connection_client(VALUE rb_mQUICConnectionArg) {
|
|
268
|
+
rb_cQUICConnectionClient =
|
|
269
|
+
rb_define_class_under(rb_mQUICConnectionArg, "Client", rb_cObject);
|
|
253
270
|
rb_define_alloc_func(rb_cQUICConnectionClient, quic_conn_alloc);
|
|
254
|
-
rb_define_singleton_method(rb_cQUICConnectionClient, "_open",
|
|
271
|
+
rb_define_singleton_method(rb_cQUICConnectionClient, "_open",
|
|
272
|
+
quic_client_open, -1);
|
|
255
273
|
quic_conn_define_shared_methods(rb_cQUICConnectionClient);
|
|
256
274
|
}
|