raioquic 0.1.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 (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