raioquic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.containerignore +4 -0
  3. data/.rubocop.yml +93 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Containerfile +6 -0
  7. data/Gemfile +24 -0
  8. data/Gemfile.lock +113 -0
  9. data/LICENSE +28 -0
  10. data/README.md +48 -0
  11. data/Rakefile +16 -0
  12. data/Steepfile +8 -0
  13. data/example/curlcatcher.rb +18 -0
  14. data/example/interoperability/README.md +9 -0
  15. data/example/interoperability/aioquic/aioquic_client.py +47 -0
  16. data/example/interoperability/aioquic/aioquic_server.py +34 -0
  17. data/example/interoperability/key.pem +28 -0
  18. data/example/interoperability/localhost-unasuke-dev.crt +21 -0
  19. data/example/interoperability/quic-go/sample_server.go +61 -0
  20. data/example/interoperability/raioquic_client.rb +42 -0
  21. data/example/interoperability/raioquic_server.rb +43 -0
  22. data/example/parse_curl_example.rb +108 -0
  23. data/lib/raioquic/buffer.rb +202 -0
  24. data/lib/raioquic/core_ext.rb +54 -0
  25. data/lib/raioquic/crypto/README.md +5 -0
  26. data/lib/raioquic/crypto/aesgcm.rb +52 -0
  27. data/lib/raioquic/crypto/backend/aead.rb +52 -0
  28. data/lib/raioquic/crypto/backend.rb +12 -0
  29. data/lib/raioquic/crypto.rb +10 -0
  30. data/lib/raioquic/quic/configuration.rb +81 -0
  31. data/lib/raioquic/quic/connection.rb +2776 -0
  32. data/lib/raioquic/quic/crypto.rb +317 -0
  33. data/lib/raioquic/quic/event.rb +69 -0
  34. data/lib/raioquic/quic/logger.rb +272 -0
  35. data/lib/raioquic/quic/packet.rb +471 -0
  36. data/lib/raioquic/quic/packet_builder.rb +301 -0
  37. data/lib/raioquic/quic/rangeset.rb +113 -0
  38. data/lib/raioquic/quic/recovery.rb +528 -0
  39. data/lib/raioquic/quic/stream.rb +343 -0
  40. data/lib/raioquic/quic.rb +20 -0
  41. data/lib/raioquic/tls.rb +1659 -0
  42. data/lib/raioquic/version.rb +5 -0
  43. data/lib/raioquic.rb +12 -0
  44. data/misc/export_x25519.py +43 -0
  45. data/misc/gen_rfc8448_keypair.rb +90 -0
  46. data/raioquic.gemspec +37 -0
  47. data/sig/raioquic/buffer.rbs +37 -0
  48. data/sig/raioquic/core_ext.rbs +7 -0
  49. data/sig/raioquic/crypto/aesgcm.rbs +20 -0
  50. data/sig/raioquic/crypto/backend/aead.rbs +11 -0
  51. data/sig/raioquic/quic/configuration.rbs +34 -0
  52. data/sig/raioquic/quic/connection.rbs +277 -0
  53. data/sig/raioquic/quic/crypto.rbs +88 -0
  54. data/sig/raioquic/quic/event.rbs +51 -0
  55. data/sig/raioquic/quic/logger.rbs +57 -0
  56. data/sig/raioquic/quic/packet.rbs +157 -0
  57. data/sig/raioquic/quic/packet_builder.rbs +76 -0
  58. data/sig/raioquic/quic/rangeset.rbs +17 -0
  59. data/sig/raioquic/quic/recovery.rbs +142 -0
  60. data/sig/raioquic/quic/stream.rbs +87 -0
  61. data/sig/raioquic/tls.rbs +444 -0
  62. data/sig/raioquic.rbs +9 -0
  63. metadata +121 -0
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Raioquic
4
+ VERSION = "0.1.0"
5
+ end
data/lib/raioquic.rb ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "raioquic/version"
4
+ require_relative "raioquic/buffer"
5
+ require_relative "raioquic/quic"
6
+ require_relative "raioquic/crypto"
7
+
8
+ module Raioquic
9
+ class Error < StandardError; end
10
+ # Your code goes here...
11
+ class ValueError < Error; end
12
+ end
@@ -0,0 +1,43 @@
1
+ # Create X25519 kay pair as PEM format it illustrated in RFC 8448.
2
+
3
+ from cryptography.hazmat.primitives import serialization
4
+ from cryptography.hazmat.primitives.asymmetric import x25519
5
+ import binascii
6
+
7
+ client_priv_key = x25519.X25519PrivateKey.from_private_bytes(
8
+ binascii.unhexlify("49af42ba7f7994852d713ef2784bcbcaa7911de26adc5642cb634540e7ea5005")
9
+ )
10
+
11
+ print(client_priv_key.private_bytes(
12
+ encoding=serialization.Encoding.PEM,
13
+ format=serialization.PrivateFormat.PKCS8,
14
+ encryption_algorithm=serialization.NoEncryption()
15
+ ))
16
+
17
+ client_pub_key = x25519.X25519PublicKey.from_public_bytes(
18
+ binascii.unhexlify("99381de560e4bd43d23d8e435a7dbafeb3c06e51c13cae4d5413691e529aaf2c")
19
+ )
20
+
21
+ print(client_pub_key.public_bytes(
22
+ encoding=serialization.Encoding.PEM,
23
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
24
+ ))
25
+
26
+ server_priv_key = x25519.X25519PrivateKey.from_private_bytes(
27
+ binascii.unhexlify("b1580eeadf6dd589b8ef4f2d5652578cc810e9980191ec8d058308cea216a21e")
28
+ )
29
+
30
+ print(server_priv_key.private_bytes(
31
+ encoding=serialization.Encoding.PEM,
32
+ format=serialization.PrivateFormat.PKCS8,
33
+ encryption_algorithm=serialization.NoEncryption()
34
+ ))
35
+
36
+ server_pub_key = x25519.X25519PublicKey.from_public_bytes(
37
+ binascii.unhexlify("c9828876112095fe66762bdbf7c672e156d6cc253b833df1dd69b1b04e751f0f")
38
+ )
39
+
40
+ print(server_pub_key.public_bytes(
41
+ encoding=serialization.Encoding.PEM,
42
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
43
+ ))
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ # Generate key pair illustrated in RFC 8448.
6
+ # https://datatracker.ietf.org/doc/html/rfc8448
7
+ #
8
+ # In OpenSSL 3 environtment, openssl gem did not support OpenSSL::PKey::RSA#set_key, OpenSSL::PKey::RSA#set_factors,
9
+ # and OpenSSL::PKey::RSA#set_crt_params because PKey object made immutable from OpenSSL 3.
10
+ # Run this script in OpenSSL 1 env (like a container), get key pair with PEM format,
11
+ # then read in OpenSSL 3 env by OpenSSL::Pkey.read method and so on.
12
+
13
+ rfc8448_rsa_pkey_moduls = <<~MODULUS.split.map(&:hex).map(&:chr).join
14
+ b4 bb 49 8f 82 79 30 3d 98 08 36 39 9b 36 c6 98
15
+ 8c 0c 68 de 55 e1 bd b8 26 d3 90 1a 24 61 ea fd
16
+ 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c 1a f1
17
+ 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0
18
+ cc b0 52 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38
19
+ e2 2a 5f da 43 08 46 74 80 30 53 0e f0 46 1c 8c
20
+ a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 ef f0 ab
21
+ 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f
22
+ MODULUS
23
+
24
+ rfc8448_rsa_pkey_public_exponent = <<~EXPONENT.split.map(&:hex).map(&:chr).join
25
+ 01 00 01
26
+ EXPONENT
27
+
28
+ rfc8448_rsa_pkey_private_exponent = <<~EXPONENT.split.map(&:hex).map(&:chr).join
29
+ 04 de a7 05 d4 3a 6e a7 20 9d d8 07 21 11 a8 3c
30
+ 81 e3 22 a5 92 78 b3 34 80 64 1e af 7c 0a 69 85
31
+ b8 e3 1c 44 f6 de 62 e1 b4 c2 30 9f 61 26 e7 7b
32
+ 7c 41 e9 23 31 4b bf a3 88 13 05 dc 12 17 f1 6c
33
+ 81 9c e5 38 e9 22 f3 69 82 8d 0e 57 19 5d 8c 84
34
+ 88 46 02 07 b2 fa a7 26 bc f7 08 bb d7 db 7f 67
35
+ 9f 89 34 92 fc 2a 62 2e 08 97 0a ac 44 1c e4 e0
36
+ c3 08 8d f2 5a e6 79 23 3d f8 a3 bd a2 ff 99 41
37
+ EXPONENT
38
+
39
+ rfc8448_rsa_pkey_prime1 = <<~PRIME1.split.map(&:hex).map(&:chr).join
40
+ e4 35 fb 7c c8 37 37 75 6d ac ea 96 ab 7f 59 a2
41
+ cc 10 69 db 7d eb 19 0e 17 e3 3a 53 2b 27 3f 30
42
+ a3 27 aa 0a aa bc 58 cd 67 46 6a f9 84 5f ad c6
43
+ 75 fe 09 4a f9 2c 4b d1 f2 c1 bc 33 dd 2e 05 15
44
+ PRIME1
45
+
46
+ rfc8448_rsa_pkey_prime2 = <<~PRIME2.split.map(&:hex).map(&:chr).join
47
+ ca bd 3b c0 e0 43 86 64 c8 d4 cc 9f 99 97 7a 94
48
+ d9 bb fe ad 8e 43 87 0a ba e3 f7 eb 8b 4e 0e ee
49
+ 8a f1 d9 b4 71 9b a6 19 6c f2 cb ba ee eb f8 b3
50
+ 49 0a fe 9e 9f fa 74 a8 8a a5 1f c6 45 62 93 03
51
+ PRIME2
52
+
53
+ rfc8448_rsa_pkey_exponent1 = <<~EXPONENT1.split.map(&:hex).map(&:chr).join
54
+ 3f 57 34 5c 27 fe 1b 68 7e 6e 76 16 27 b7 8b 1b
55
+ 82 64 33 dd 76 0f a0 be a6 a6 ac f3 94 90 aa 1b
56
+ 47 cd a4 86 9d 68 f5 84 dd 5b 50 29 bd 32 09 3b
57
+ 82 58 66 1f e7 15 02 5e 5d 70 a4 5a 08 d3 d3 19
58
+ EXPONENT1
59
+
60
+ rfc8448_rsa_pkey_exponent2 = <<~EXPONENT2.split.map(&:hex).map(&:chr).join
61
+ 18 3d a0 13 63 bd 2f 28 85 ca cb dc 99 64 bf 47
62
+ 64 f1 51 76 36 f8 64 01 28 6f 71 89 3c 52 cc fe
63
+ 40 a6 c2 3d 0d 08 6b 47 c6 fb 10 d8 fd 10 41 e0
64
+ 4d ef 7e 9a 40 ce 95 7c 41 77 94 e1 04 12 d1 39
65
+ EXPONENT2
66
+
67
+ rfc8448_rsa_pkey_coefficient = <<~COEF.split.map(&:hex).map(&:chr).join
68
+ 83 9c a9 a0 85 e4 28 6b 2c 90 e4 66 99 7a 2c 68
69
+ 1f 21 33 9a a3 47 78 14 e4 de c1 18 33 05 0e d5
70
+ 0d d1 3c c0 38 04 8a 43 c5 9b 2a cc 41 68 89 c0
71
+ 37 66 5f e5 af a6 05 96 9f 8c 01 df a5 ca 96 9d
72
+ COEF
73
+
74
+ rsa_cert = OpenSSL::PKey::RSA.new
75
+ rsa_cert.set_key(
76
+ OpenSSL::BN.new(rfc8448_rsa_pkey_moduls, 2),
77
+ OpenSSL::BN.new(rfc8448_rsa_pkey_public_exponent, 2),
78
+ OpenSSL::BN.new(rfc8448_rsa_pkey_private_exponent, 2),
79
+ )
80
+ rsa_cert.set_factors(
81
+ OpenSSL::BN.new(rfc8448_rsa_pkey_prime1, 2),
82
+ OpenSSL::BN.new(rfc8448_rsa_pkey_prime2, 2),
83
+ )
84
+ rsa_cert.set_crt_params(
85
+ OpenSSL::BN.new(rfc8448_rsa_pkey_exponent1, 2),
86
+ OpenSSL::BN.new(rfc8448_rsa_pkey_exponent2, 2),
87
+ OpenSSL::BN.new(rfc8448_rsa_pkey_coefficient, 2),
88
+ )
89
+
90
+ File.write("rfc8448.pem", rsa_cert.to_pem)
data/raioquic.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/raioquic/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "raioquic"
7
+ spec.version = Raioquic::VERSION
8
+ spec.authors = ["Yusuke Nakamura"]
9
+ spec.email = ["yusuke1994525@gmail.com"]
10
+
11
+ spec.summary = "Write a short summary, because RubyGems requires one."
12
+ spec.description = "Write a longer description or delete this line."
13
+ spec.homepage = "https://example.com"
14
+ spec.required_ruby_version = ">= 3.0.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+ spec.metadata["changelog_uri"] = spec.homepage
19
+ spec.metadata["rubygems_mfa_required"] = "true"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ # Uncomment to register a new dependency of your gem
33
+ spec.add_dependency "tttls1.3"
34
+
35
+ # For more information and examples about making a new gem, check out our
36
+ # guide at: https://bundler.io/guides/creating_gem.html
37
+ end
@@ -0,0 +1,37 @@
1
+ module Raioquic
2
+ class Buffer
3
+ # extend Forwardable
4
+
5
+ UINT_VAR_MAX: ::Integer
6
+ UINT_VAR_MAX_SIZE: 8
7
+
8
+ class BufferReadError < StandardError
9
+ end
10
+ class BufferWriteError < StandardError
11
+ end
12
+
13
+ def self.encode_uint_var: (Integer) -> String
14
+ def self.size_uint_var: (Integer) -> (1 | 2 | 4 | 8)
15
+ def initialize: (?capacity: Integer?, ?data: String) -> void
16
+ def dealloc: () -> nil
17
+ def data: () -> String
18
+ def tell: () -> ::Integer # delegated method
19
+ def seek: (Integer) -> void
20
+ def capacity: -> ::Integer
21
+ def data_slice: (start: Integer, ends: Integer) -> untyped
22
+ def pull_bytes: (Integer) -> String
23
+ def pull_uint8: () -> Integer
24
+ def pull_uint16: () -> Integer
25
+ def pull_uint32: () -> Integer
26
+ def pull_uint64: () -> Integer
27
+ def pull_uint_var: () -> Integer
28
+ def push_bytes: (String) -> void
29
+ def push_uint8: (Integer) -> void
30
+ def push_uint16: (Integer) -> void
31
+ def push_uint32: (Integer) -> void
32
+ def push_uint64: (Integer) -> void
33
+ def push_uint_var: (Integer) -> void
34
+ def encode_uint_var: (Integer) -> nil
35
+ private def check_read_bounds: (Integer) -> void
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ class ::String
2
+ def bytes_to_int: () -> ::Integer
3
+ end
4
+
5
+ class ::Integer
6
+ def to_bytes: (::Integer) -> ::String
7
+ end
@@ -0,0 +1,20 @@
1
+ module Raioquic
2
+ module Crypto
3
+ class AESGCM
4
+ MAX_SIZE: Numeric
5
+
6
+ class OverflowError < StandardError
7
+ end
8
+
9
+ attr_reader key: ::String
10
+
11
+ def initialize: (String) -> void
12
+ def encrypt: (nonce: ::String, data: ::String, associated_data: ::String) -> ::String
13
+ | (nonce: ::String, data: ::String) -> ::String
14
+ def decrypt: (nonce: ::String, data: ::String, associated_data: ::String) -> ::String
15
+ | (nonce: ::String, data: ::String) -> ::String
16
+ def validate_length: (nonce: ::String, data: ::String) -> void
17
+ def check_nonce: (::String) -> void
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Raioquic
2
+ module Crypto
3
+ module Backend
4
+ class Aead
5
+ def self.aead_cipher_name: (::Raioquic::Crypto::AESGCM | untyped) -> String
6
+ def self.encrypt: (cipher: untyped, key: String, nonce: String, data: String, associated_data: Array[String?], tag_length: Integer) -> String
7
+ def self.decrypt: (cipher: untyped, key: String, nonce: String, data: String, associated_data: Array[String?], tag_length: Integer) -> String
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ module Raioquic
2
+ module Quic
3
+ module QuicConfiguration
4
+ attr_accessor alpn_protocols: ::Array[untyped]
5
+ attr_accessor connection_id_length: ::Integer
6
+ attr_accessor idle_timeout: ::Float
7
+ attr_accessor is_client: bool
8
+ attr_accessor max_data: ::Integer
9
+ attr_accessor max_stream_data: ::Integer
10
+ attr_accessor quic_logger: ::Raioquic::Quic::Logger::QuicLogger
11
+ attr_accessor secrets_log_file: untyped
12
+ attr_accessor server_name: ::String | nil
13
+ attr_accessor session_ticket: ::String | nil
14
+ attr_accessor cadata: ::String | nil
15
+ attr_accessor cafile: ::String | nil
16
+ attr_accessor capath: ::String | nil
17
+ attr_accessor certificate: untyped
18
+ attr_accessor certificate_chain: ::Array[untyped]
19
+ attr_accessor cipher_suites: ::Array[::Integer]
20
+ attr_accessor initial_rtt: ::Float
21
+ attr_accessor max_datagram_frame_size: ::Integer
22
+ attr_accessor private_key: untyped
23
+ attr_accessor quantam_readiness_test: bool
24
+ attr_accessor supported_versions: ::Array[::Integer]
25
+ attr_accessor verify_mode: ::Integer # OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER
26
+
27
+ def initialize: (untyped) -> void
28
+ def load_cert_chain: (::String certfile) -> void
29
+ | (::String certfile, ::String keyfile) -> void
30
+ | (::String certfile, ::String keyfile, ::String password) -> void
31
+ def load_verify_locations: (?cafile: ::String|nil, ?capath: ::String|nil, ?cadata: ::String|nil) -> void
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,277 @@
1
+ module Raioquic
2
+ module Quic
3
+ module Connection
4
+ CRYPTO_BUFFER_SIZE: ::Integer
5
+ EPOCH_SHORTCUTS: ::Hash[::String, ::Integer]
6
+ MAX_EARLY_DATA: ::Integer
7
+ SECRETS_LABELS: ::Array[::Array[::String | nil]]
8
+ STREAM_FLAGS: ::Integer
9
+ STREAM_COUNT_MAX: ::Integer
10
+ UDP_HEADER_SIZE: 8
11
+ ACK_FRAME_CAPACITY: ::Integer
12
+ APPLICATION_CLOSE_FRAME_CAPACITY: ::Integer
13
+ CONNECTION_LIMIT_FRAME_CAPACITY: ::Integer
14
+ HANDSHAKE_DONE_FRAME_CAPACITY: ::Integer
15
+ MAX_STREAM_DATA_FRAME_CAPACITY: ::Integer
16
+ NEW_CONNECTION_ID_FRAME_CAPACITY: ::Integer
17
+ PATH_CHALLENGE_FRAME_CAPACITY: ::Integer
18
+ PATH_RESPONSE_FRAME_CAPACITY: ::Integer
19
+ PING_FRAME_CAPACITY: ::Integer
20
+ RESET_STREAM_FRAME_CAPACITY: ::Integer
21
+ RETIRE_CONNECTION_ID_CAPACITY: ::Integer
22
+ STOP_SENDING_FRAME_CAPACITY: ::Integer
23
+ STREAMS_BLOCKED_CAPACITY: ::Integer
24
+ TRANSPORT_CLOSE_FLAME_CAPACITY: ::Integer
25
+
26
+ def self.epochs: (::String shortcut) -> ::Array[::Integer]
27
+ def self.dump_cid: (::String cid) -> ::String
28
+ def self.get_epoch: (::Integer packet_type) -> ::Integer
29
+ def self.get_transport_parameters_extension: (::Integer version) -> ::Integer
30
+ def self.stream_is_client_initialized: (::Integer stream_id) -> bool
31
+ def self.stream_is_unidirectional: (::Integer stream_id) -> bool
32
+
33
+ class Limit
34
+ @frame_type: ::Integer
35
+ @name: ::String
36
+ @sent: ::Integer
37
+ @used: ::Integer
38
+ @value: ::Integer
39
+
40
+ attr_reader frame_type: ::Integer
41
+
42
+ attr_accessor used: ::Integer
43
+ attr_accessor sent: ::Integer
44
+ attr_accessor value: ::Integer
45
+
46
+ def initialize: (frame_type: ::Integer, name: ::String, value: ::Integer) -> void
47
+ end
48
+
49
+ class QuicConnectionError < Error
50
+ @error_code: ::Integer
51
+ @frame_type: ::Integer
52
+ @reason_phrase: ::String
53
+ end
54
+
55
+ # TODO: QuicConnectionAdapter
56
+
57
+ class QuicConnectionId
58
+ attr_accessor cid: ::String
59
+ attr_accessor sequence_number: ::Integer
60
+ attr_accessor stateless_reset_token: ::String
61
+ attr_accessor was_sent: bool
62
+ end
63
+
64
+ class QuicConnectionState
65
+ FIRSTFLIGHT: 0
66
+ CONNECTED: 1
67
+ CLOSING: 2
68
+ DRAINING: 3
69
+ TERMINATED: 4
70
+ end
71
+
72
+ class QuicNetworkPath
73
+ attr_accessor addr: untyped
74
+ attr_accessor bytes_received: ::Integer
75
+ attr_accessor bytes_sent: ::Integer
76
+ attr_accessor is_validated: bool
77
+ attr_accessor local_challenge: ::String | nil
78
+ attr_accessor remote_challenge: ::String | nil
79
+
80
+ def can_send: (::Integer size) -> bool
81
+ end
82
+
83
+ class QuicReceiveContext
84
+ attr_accessor epoch: ::Integer
85
+ attr_accessor host_cid: ::String
86
+ attr_accessor network_path: QuicNetworkPath
87
+ attr_accessor quic_logger_frames: ::Array[untyped] | nil
88
+ attr_accessor time: ::Float
89
+ end
90
+
91
+ END_STATES: ::Array[::Integer]
92
+
93
+
94
+ class QuicConnection
95
+ attr_reader configuration: QuicConfiguration
96
+ attr_reader original_destination_connection_id: ::String
97
+ attr_reader loss: Quic::Recovery::QuicPacketRecovery
98
+ attr_reader tls: ::Raioquic::TLS::Context
99
+ attr_reader local_max_streams_bidi: Limit
100
+
101
+ attr_accessor ack_delay: ::Float
102
+ attr_accessor is_client: bool
103
+
104
+ @configuration: QuicConfiguration
105
+ @is_client: bool
106
+ @ack_delay: ::Float
107
+ @close_at: ::Float | nil
108
+ @close_event: untyped # TODO: events
109
+ @connect_called: bool
110
+ @cryptos: ::Hash[::Integer, ::Raioquic::Quic::Crypto::CryptoPair]
111
+ @crypto_buffers: ::Hash[::Integer, ::Raioquic::Buffer]
112
+ @crypto_retransmitted: bool
113
+ @crypto_streams: ::Hash[::Integer, ::Raioquic::Quic::Stream::QuicStream] # TODO: QuicStream
114
+ @events: untyped # TODO: deque?
115
+ @handshake_complete: bool
116
+ @handshake_confirmed: bool
117
+ @host_cids: ::Array[QuicConnectionId]
118
+ @host_cid: ::String
119
+ @host_cid_seq: ::Integer
120
+ @local_ack_delay_exponent: ::Integer
121
+ @local_active_connection_id_limit: ::Integer
122
+ @local_initial_source_connection_id: ::String
123
+ @local_max_data: Limit
124
+ @local_max_stream_data_bidi_local: ::Integer
125
+ @local_max_stream_data_bidi_remote: ::Integer
126
+ @local_max_stream_data_uni: ::Integer
127
+ @local_max_streams_bidi: Limit
128
+ @local_max_streams_uni: Limit
129
+ @loss_at: ::Float | nil
130
+ @network_paths: ::Array[QuicNetworkPath]
131
+ @pacing_at: ::Float | nil
132
+ @packet_number: ::Integer
133
+ @parameters_received: bool
134
+ @peer_cid: QuicConnectionId
135
+ @peer_cid_available: ::Array[QuicConnectionId]
136
+ @peer_cid_sequence_numbers: ::Array[::Integer] # TODO: set
137
+ @peer_token: ::String
138
+ @quic_logger: ::Raioquic::Quic::Logger::QuicLoggerTrace
139
+ @remote_ack_delay_exponent: ::Integer
140
+ @remote_active_connection_id_limit: ::Integer
141
+ @remote_initial_source_connection_id: ::String | nil
142
+ @remote_max_idle_timeout: ::Float
143
+ @remote_max_data: ::Integer
144
+ @remote_max_data_used: ::Integer
145
+ @remote_max_datagram_frame_size: ::Integer | nil
146
+ @remote_max_stream_data_bidi_local: ::Integer
147
+ @remote_max_stream_data_bidi_remote: ::Integer
148
+ @remote_max_stream_data_uni: ::Integer
149
+ @remote_max_streams_bidi: ::Integer
150
+ @remote_max_streams_uni: ::Integer
151
+ @retry_count: ::Integer
152
+ @retry_source_connection_id: ::String | nil
153
+ @spaces: ::Hash[::Integer, Quic::Recovery::QuicPacketSpace]
154
+ @spin_bit: bool
155
+ @spin_highest_pn: ::Integer
156
+ @state: ::Integer
157
+ @streams: ::Hash[::Integer, Quic::Stream::QuicStream] # TODO: QuicStream
158
+ @streams_blocked_bidi: ::Array[untyped] # TODO: QuicStream
159
+ @streams_blocked_uni: ::Array[untyped] # TODO: QuicStream
160
+ @streams_finished: ::Array[::Integer] # TODO: ::Set
161
+ @version: ::Integer | nil
162
+ @version_negotiation_count: ::Integer
163
+ @original_destination_connection_id: ::String
164
+ @logger: untyped
165
+ @loss: Quic::Recovery::QuicPacketRecovery
166
+ @close_pending: bool
167
+ @datagrams_pending: untyped # TODO: set
168
+ @handshake_done_pending: bool
169
+ @ping_pending: ::Array[::Integer]
170
+ @probe_pending: bool
171
+ @retire_connection_ids: ::Array[::Integer]
172
+ @streams_blocked_pending: bool
173
+ @session_ticket_fetcher: untyped
174
+ @session_ticket_handler: untyped
175
+ @frame_handlers: ::Hash[::Integer, [::Symbol, ::Array[::Integer]]]
176
+ @tls: ::Raioquic::TLS::Context
177
+
178
+ def intialize: (
179
+ configuration: QuicConfiguration,
180
+ ?original_destination_connection_id: ::String,
181
+ ?retry_source_connection_id: ::String,
182
+ ?session_ticket_fetcher: untyped,
183
+ ?session_ticket_handler: untyped,
184
+ ) -> void
185
+ def change_connection_id: () -> void
186
+ def close: (?error_code: ::Integer, ?frame_type: ::Integer|nil, ?reason_phrase: ::String) -> void
187
+ def connect: (addr: untyped, now: ::Float) -> void # TODO: type of addr
188
+ def datagrams_to_send: (now: ::Float) -> ::Array[[::String, untyped]] # TODO: NetworkAddress
189
+ def get_next_available_stream_id: (?is_unidirectional: bool) -> ::Integer
190
+ def get_timer: () -> (::Float | nil)
191
+ def handle_timer: (now: ::Float) -> void
192
+ def next_event: () -> (::Raioquic::Quic::Event::QuicEvent | nil)
193
+ def receive_datagram: (data: ::String, addr: untyped, now: ::Float) -> void # TODO: NetworkAddress
194
+ def request_key_update: () -> void
195
+ def reset_stream: (stream_id: ::Integer, error_code: ::Integer) -> void
196
+ def send_ping: (::Integer uid) -> void
197
+ def send_datagram_frame: (:String data) -> void
198
+ def send_stream_data: (stream_id: ::Integer, data: ::String, ?end_stream: bool) -> void
199
+ def stop_stream: (stream_id: ::Integer, error_code: ::Integer) -> void
200
+ private def alpn_handler: (::String alpn_protocol) -> void
201
+ private def assert_stream_can_receive: (frame_type: ::Integer, stream_id: ::Integer) -> void
202
+ private def assert_stream_can_send: (frame_type: ::Integer, stream_id: ::Integer) -> void
203
+ private def consume_peer_cid: () -> void
204
+ private def close_begin: (is_initiator: bool, now: ::Float) -> void
205
+ private def close_end: () -> void
206
+ private def _connect: (now: ::Float) -> void
207
+ private def discard_epoch: (::Integer epoch) -> void
208
+ private def find_network_path: (untyped addr) -> QuicNetworkPath # TODO: NetworkAddress
209
+ private def get_or_create_stream: (frame_type: ::Integer, stream_id: ::Integer) -> ::Raioquic::Quic::Stream::QuicStream
210
+ private def get_or_create_stream_for_send: (::Integer stream_id) -> ::Raioquic::Quic::Stream::QuicStream
211
+ private def handle_session_ticket: (::Raioquic::TLS::SessionTicket session_ticket) -> void
212
+ private def initialize_connection: (::String peer_cid) -> void
213
+ private def handle_ack_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
214
+ private def handle_connection_close_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
215
+ private def handle_crypto_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
216
+ private def handle_data_blocked_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
217
+ private def handle_datagram_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
218
+ private def handle_handshake_done_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
219
+ private def handle_max_data_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
220
+ private def handle_max_stream_data_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
221
+ private def handle_max_streams_bidi_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
222
+ private def handle_max_streams_uni_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
223
+ private def handle_new_connection_id_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
224
+ private def handle_new_token_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
225
+ private def handle_padding_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
226
+ private def handle_path_challenge_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
227
+ private def handle_path_response_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
228
+ private def handle_ping_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
229
+ private def handle_reset_stream_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
230
+ private def handle_retire_connection_id_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
231
+ private def handle_stop_sending_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
232
+ private def handle_stream_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
233
+ private def handle_stream_data_blocked_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
234
+ private def handle_streams_blocked_frame: (context: QuicReceiveContext, frame_type: ::Integer, buf: ::Raioquic::Buffer) -> void
235
+ private def log_key_retired: (key_type: ::String, trigger: ::String) -> void
236
+ private def log_key_updated: (key_type: ::String, trigger: ::String) -> void
237
+ private def on_ack_delivery: (delivery: ::Integer, space: ::Raioquic::Quic::Recovery::QuicPacketSpace, highest_acked: ::Integer) -> void
238
+ private def on_connection_limit_delivery: (delivery: ::Integer, limit: Limit) -> void
239
+ private def on_handshake_done_delivery: (delivery: ::Integer) -> void
240
+ private def on_max_stream_data_delivery: (delivery: ::Integer, stream: ::Raioquic::Quic::Stream::QuicStream) -> void
241
+ private def on_new_connection_id_delivery: (delivery: ::Integer, connection_id: QuicConnectionId) -> void
242
+ private def on_ping_delivery: (delivery: ::Integer, uids: ::Array[::Integer]) -> void
243
+ private def on_retire_connection_id_delivery: (delivery: ::Integer, sequence_number: ::Integer) -> void
244
+ private def payload_received: (context: QuicReceiveContext, plain: ::String) -> [bool, bool]
245
+ private def replenish_connection_ids: () -> void
246
+ private def retire_peer_cid: (QuicConnectionId connection_id) -> void
247
+ private def push_crypto_data: () -> void
248
+ private def send_probe: () -> void
249
+ private def parse_transport_parameters: (data: ::String, ?from_session_ticket: bool) -> void
250
+ private def serialize_transport_parameters: () -> ::String
251
+ private def set_state: (::Integer quic_connection_state) -> void
252
+ private def stream_can_receive: (::Integer stream_id) -> bool
253
+ private def stream_can_send: (::Integer stream_id) -> bool
254
+ private def unblock_streams: (bool is_unidirectional) -> void
255
+ private def update_traffic_key: (direction: ::Integer, epoch: ::Integer, cipher_suite: ::Integer, secret: ::String) -> void
256
+ private def write_application: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, network_path: QuicNetworkPath, now: ::Float) -> void
257
+ private def write_handshake: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, epoch: ::Integer, now: ::Float) -> void
258
+ private def write_ack_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, space: ::Raioquic::Quic::Recovery::QuicPacketSpace, now: ::Float) -> void
259
+ private def write_connection_close_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, epoch: ::Integer, error_code: ::Integer, ?frame_type: ::Integer, reason_phrase: ::String) -> void
260
+ private def write_connection_limits: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, space: ::Raioquic::Quic::Recovery::QuicPacketSpace) -> void
261
+ private def write_crypto_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, space: ::Raioquic::Quic::Recovery::QuicPacketSpace, stream: ::Raioquic::Quic::Stream::QuicStream) -> bool
262
+ private def write_datagram_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, data: ::String, frame_type: ::Integer) -> bool
263
+ private def write_handshake_done_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder) -> void
264
+ private def write_new_connection_id_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, connection_id: QuicConnectionId) -> void
265
+ private def write_path_challenge_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, challenge: ::String) -> void
266
+ private def write_path_response_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, challenge: ::String) -> void
267
+ private def write_ping_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, ?uids: ::Array[::Integer], ?comment: ::String) -> void
268
+ private def write_reset_stream_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, stream: ::Raioquic::Quic::Stream::QuicStream) -> void
269
+ private def write_retire_connection_id_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, sequence_number: ::Integer) -> void
270
+ private def write_stop_sending_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, stream: ::Raioquic::Quic::Stream::QuicStream) -> void
271
+ private def write_stream_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, space: ::Raioquic::Quic::Recovery::QuicPacketSpace, stream: ::Raioquic::Quic::Stream::QuicStream, max_offset: ::Integer) -> ::Integer
272
+ private def write_stream_limits: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, space: ::Raioquic::Quic::Recovery::QuicPacketSpace, stream: ::Raioquic::Quic::Stream::QuicStream) -> void
273
+ private def write_streams_blocked_frame: (builder: ::Raioquic::Quic::PacketBuilder::QuicPacketBuilder, frame_type: ::Integer, limit: ::Integer) -> void
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,88 @@
1
+ module Raioquic
2
+ module Quic
3
+ module Crypto
4
+ INITIAL_CIPHER_SUITE: untyped
5
+ AEAD_KEY_LENGTH_MAX: 32
6
+ AEAD_NONCE_LENGTH: 12
7
+ AEAD_TAG_LENGTH: 16
8
+ PACKET_LENGTH_MAX: 1500
9
+ PACKET_NUMBER_LENGTH_MAX: 4
10
+ SAMPLE_LENGTH: 16
11
+ INITIAL_SALT_VERSION_1: ::String
12
+
13
+
14
+ def self?.derive_key_iv_hp: (untyped, ::String) -> Array[::String]
15
+ def self?.xor_str: (::String, ::String) -> ::String
16
+
17
+ class CryptoError
18
+ end
19
+
20
+ class NoCallback
21
+ end
22
+
23
+ class CryptoContext
24
+ attr_reader aead: untyped
25
+ attr_reader key_phase: 0 | 1
26
+ attr_reader secret: nil | ::String
27
+ @aead: nil | AEAD
28
+ @cipher_suite: untyped # TODO: ?
29
+ @key_phase: 0 | 1
30
+ @secret: nil | ::String
31
+ @version: untyped # TODO: ::Raioquic::Quic::Packet::QuicProtocolVersion::VERSION_1
32
+ @setup_cb: NoCallback | untyped
33
+ @teardown_cb: NoCallback | untyped
34
+ @hp: HeaderProtection|nil
35
+
36
+ def initialize: (key_phase: 0|1, setup_cb: untyped, teardown_cb: untyped) -> void
37
+ | (setup_cb: untyped, teardown_cb: untyped) -> void
38
+ def decrypt_packet: (packet: ::String, encrypted_offset: ::Integer, expected_packet_number: ::Integer) -> [::String, ::String, ::Integer, bool]
39
+ def encrypt_packet: (plain_header: ::String, plain_payload: ::String, packet_number: ::Integer) -> ::String
40
+ def is_valid: () -> bool
41
+ def setup: (cipher_suite: untyped, secret: ::String, version: untyped) -> void
42
+ def teardown: () -> void
43
+ def apply_key_phase: (CryptoContext, ::String) -> void
44
+ def next_key_phase: () -> CryptoContext
45
+ end
46
+
47
+ class CryptoPair
48
+ attr_reader recv: CryptoContext
49
+ attr_reader send: CryptoContext
50
+
51
+ @aead_tag_size: ::Integer
52
+ @update_key_requested: bool
53
+
54
+ def initialize: (recv_setup_cb: NoCallback|untyped, recv_teardown_cb: NoCallback|untyped, send_setup_cb: NoCallback|untyped, send_teardown_cb: NoCallback|untyped) -> void
55
+ def decrypt_packet: (packet: ::String, encrypted_offset: ::Integer, expected_packet_number: ::Integer) -> [::String, ::String, ::Integer]
56
+ def encrypt_packet: (plain_header: ::String, plain_payload: ::Integer, packet_number: ::Integer) -> ::String
57
+ def setup_initial: (cid: ::String, is_client: bool, version: untyped) -> void
58
+ def teardown: () -> void
59
+ def key_phase: () -> ::Integer # TODO: 0 or 1
60
+ def update_key: () -> void
61
+ def _update_key: (::String) -> void
62
+ end
63
+
64
+ class AEAD
65
+ @cipher: OpenSSL::Cipher
66
+ @key: ::String
67
+ @iv: ::String
68
+ @cipher_name: ::String
69
+
70
+ def initialize: (cipher_name: ::String, key: ::String, iv: ::String) -> void
71
+ def decrypt: (data: ::String, associated_data: ::String, packet_number: ::Integer) -> ::String
72
+ def encrypt: (data: ::String, associated_data: ::String, packet_number: ::Integer) -> ::String
73
+ end
74
+
75
+ class HeaderProtection
76
+ @cipher: OpenSSL::Cipher
77
+ @key: ::String
78
+ @mask: ::String
79
+ @zero: ::String
80
+
81
+ def initialize: (cipher_name: ::String, key: ::String) -> void
82
+ def apply: (plain_header: ::String, protected_payload: ::String) -> ::String
83
+ def remove: (packet: ::String, encrypted_offset: ::Integer) -> [::String, ::Integer]
84
+ private def mask: (::String) -> ::String
85
+ end
86
+ end
87
+ end
88
+ end