From 84f8bca01c720ea82597828446cd2a95c9088566 Mon Sep 17 00:00:00 2001 From: Darien Raymond Date: Tue, 20 Nov 2018 23:51:25 +0100 Subject: [PATCH] vendor quic 44 --- vendor/lucas-clemente/quic-go/Changelog.md | 44 + vendor/lucas-clemente/quic-go/LICENSE | 21 + vendor/lucas-clemente/quic-go/README.md | 73 + vendor/lucas-clemente/quic-go/appveyor.yml | 35 + .../quic-go/benchmark/benchmark_suite_test.go | 26 + .../quic-go/benchmark/benchmark_test.go | 87 + vendor/lucas-clemente/quic-go/buffer_pool.go | 27 + .../quic-go/buffer_pool_test.go | 21 + vendor/lucas-clemente/quic-go/client.go | 595 ++ vendor/lucas-clemente/quic-go/client_test.go | 1030 +++ vendor/lucas-clemente/quic-go/codecov.yml | 18 + vendor/lucas-clemente/quic-go/conn.go | 54 + vendor/lucas-clemente/quic-go/conn_test.go | 119 + .../lucas-clemente/quic-go/crypto_stream.go | 41 + .../quic-go/crypto_stream_test.go | 26 + vendor/lucas-clemente/quic-go/docs/quic.png | Bin 0 -> 17299 bytes .../lucas-clemente/quic-go/docs/quic.sketch | Bin 0 -> 90112 bytes vendor/lucas-clemente/quic-go/docs/quic.svg | 65 + .../lucas-clemente/quic-go/example/Dockerfile | 9 + .../lucas-clemente/quic-go/example/Readme.md | 7 + .../quic-go/example/client/main.go | 66 + .../quic-go/example/echo/echo.go | 105 + .../quic-go/example/fullchain.pem | 62 + vendor/lucas-clemente/quic-go/example/main.go | 174 + .../quic-go/example/privkey.pem | 28 + vendor/lucas-clemente/quic-go/frame_sorter.go | 158 + .../quic-go/frame_sorter_test.go | 435 ++ .../lucas-clemente/quic-go/h2quic/client.go | 314 + .../quic-go/h2quic/client_test.go | 639 ++ .../quic-go/h2quic/gzipreader.go | 35 + .../quic-go/h2quic/h2quic_suite_test.go | 13 + .../lucas-clemente/quic-go/h2quic/request.go | 77 + .../quic-go/h2quic/request_body.go | 29 + .../quic-go/h2quic/request_body_test.go | 39 + .../quic-go/h2quic/request_test.go | 121 + .../quic-go/h2quic/request_writer.go | 203 + .../quic-go/h2quic/request_writer_test.go | 118 + .../lucas-clemente/quic-go/h2quic/response.go | 95 + .../quic-go/h2quic/response_writer.go | 114 + .../h2quic/response_writer_closenotifier.go | 9 + .../quic-go/h2quic/response_writer_test.go | 163 + .../quic-go/h2quic/roundtrip.go | 179 + .../quic-go/h2quic/roundtrip_test.go | 218 + .../lucas-clemente/quic-go/h2quic/server.go | 402 ++ .../quic-go/h2quic/server_test.go | 536 ++ .../chrome/chrome_suite_test.go | 210 + .../integrationtests/chrome/chrome_test.go | 76 + .../integrationtests/gquic/drop_test.go | 137 + .../gquic/gquic_suite_test.go | 45 + .../gquic/integration_test.go | 98 + .../integrationtests/gquic/random_rtt_test.go | 95 + .../integrationtests/gquic/rtt_test.go | 66 + .../integrationtests/gquic/server_test.go | 218 + .../integrationtests/self/client_test.go | 97 + .../integrationtests/self/conn_id_test.go | 101 + .../self/handshake_drop_test.go | 189 + .../self/handshake_rtt_test.go | 213 + .../integrationtests/self/handshake_test.go | 128 + .../integrationtests/self/multiplex_test.go | 232 + .../quic-go/integrationtests/self/rtt_test.go | 83 + .../integrationtests/self/self_suite_test.go | 20 + .../integrationtests/self/stream_test.go | 152 + .../integrationtests/self/uni_stream_test.go | 132 + .../integrationtests/tools/proxy/proxy.go | 270 + .../tools/proxy/proxy_suite_test.go | 13 + .../tools/proxy/proxy_test.go | 394 ++ .../integrationtests/tools/testlog/testlog.go | 46 + .../tools/testserver/server.go | 119 + vendor/lucas-clemente/quic-go/interface.go | 223 + .../ackhandler/ackhandler_suite_test.go | 24 + .../quic-go/internal/ackhandler/gen.go | 3 + .../quic-go/internal/ackhandler/interfaces.go | 47 + .../quic-go/internal/ackhandler/packet.go | 29 + .../internal/ackhandler/packet_linkedlist.go | 217 + .../ackhandler/received_packet_handler.go | 215 + .../received_packet_handler_test.go | 382 ++ .../ackhandler/received_packet_history.go | 121 + .../received_packet_history_test.go | 248 + .../internal/ackhandler/retransmittable.go | 36 + .../ackhandler/retransmittable_test.go | 45 + .../quic-go/internal/ackhandler/send_mode.go | 40 + .../internal/ackhandler/send_mode_test.go | 18 + .../ackhandler/sent_packet_handler.go | 658 ++ .../ackhandler/sent_packet_handler_test.go | 1080 +++ .../ackhandler/sent_packet_history.go | 168 + .../ackhandler/sent_packet_history_test.go | 297 + .../ackhandler/stop_waiting_manager.go | 43 + .../ackhandler/stop_waiting_manager_test.go | 55 + .../quic-go/internal/congestion/bandwidth.go | 22 + .../internal/congestion/bandwidth_test.go | 14 + .../quic-go/internal/congestion/clock.go | 18 + .../congestion/congestion_suite_test.go | 13 + .../quic-go/internal/congestion/cubic.go | 210 + .../internal/congestion/cubic_sender.go | 318 + .../internal/congestion/cubic_sender_test.go | 640 ++ .../quic-go/internal/congestion/cubic_test.go | 236 + .../internal/congestion/hybrid_slow_start.go | 111 + .../congestion/hybrid_slow_start_test.go | 75 + .../quic-go/internal/congestion/interface.go | 36 + .../quic-go/internal/congestion/prr_sender.go | 54 + .../internal/congestion/prr_sender_test.go | 107 + .../quic-go/internal/congestion/rtt_stats.go | 101 + .../internal/congestion/rtt_stats_test.go | 131 + .../quic-go/internal/congestion/stats.go | 8 + .../quic-go/internal/crypto/AEAD.go | 10 + .../quic-go/internal/crypto/aesgcm12_aead.go | 72 + .../internal/crypto/aesgcm12_aead_test.go | 69 + .../quic-go/internal/crypto/aesgcm_aead.go | 74 + .../internal/crypto/aesgcm_aead_test.go | 84 + .../quic-go/internal/crypto/cert_cache.go | 48 + .../internal/crypto/cert_cache_test.go | 51 + .../quic-go/internal/crypto/cert_chain.go | 113 + .../internal/crypto/cert_chain_test.go | 148 + .../internal/crypto/cert_compression.go | 272 + .../internal/crypto/cert_compression_test.go | 294 + .../quic-go/internal/crypto/cert_dict.go | 128 + .../quic-go/internal/crypto/cert_manager.go | 135 + .../internal/crypto/cert_manager_test.go | 348 + .../quic-go/internal/crypto/cert_sets.go | 24 + .../internal/crypto/chacha20poly1305_aead.go | 61 + .../crypto/chacha20poly1305_aead_test.go | 71 + .../internal/crypto/crypto_suite_test.go | 13 + .../quic-go/internal/crypto/curve_25519.go | 41 + .../internal/crypto/curve_25519_test.go | 27 + .../quic-go/internal/crypto/key_derivation.go | 60 + .../crypto/key_derivation_quic_crypto.go | 100 + .../crypto/key_derivation_quic_crypto_test.go | 197 + .../internal/crypto/key_derivation_test.go | 56 + .../quic-go/internal/crypto/key_exchange.go | 7 + .../quic-go/internal/crypto/null_aead.go | 11 + .../internal/crypto/null_aead_aesgcm.go | 41 + .../internal/crypto/null_aead_aesgcm_test.go | 86 + .../internal/crypto/null_aead_fnv128a.go | 79 + .../internal/crypto/null_aead_fnv128a_test.go | 55 + .../quic-go/internal/crypto/null_aead_test.go | 17 + .../quic-go/internal/crypto/server_proof.go | 66 + .../internal/crypto/server_proof_test.go | 127 + .../flowcontrol/base_flow_controller.go | 122 + .../flowcontrol/base_flow_controller_test.go | 235 + .../flowcontrol/connection_flow_controller.go | 87 + .../connection_flow_controller_test.go | 133 + .../flowcontrol/flowcontrol_suite_test.go | 24 + .../quic-go/internal/flowcontrol/interface.go | 38 + .../flowcontrol/stream_flow_controller.go | 149 + .../stream_flow_controller_test.go | 290 + .../internal/handshake/cookie_generator.go | 99 + .../handshake/cookie_generator_test.go | 111 + .../internal/handshake/cookie_protector.go | 86 + .../handshake/cookie_protector_test.go | 39 + .../internal/handshake/crypto_setup_client.go | 543 ++ .../handshake/crypto_setup_client_test.go | 1011 +++ .../internal/handshake/crypto_setup_server.go | 467 ++ .../handshake/crypto_setup_server_test.go | 731 +++ .../internal/handshake/crypto_setup_tls.go | 163 + .../handshake/crypto_setup_tls_test.go | 192 + .../internal/handshake/crypto_stream_conn.go | 69 + .../handshake/crypto_stream_conn_test.go | 41 + .../quic-go/internal/handshake/data_test.go | 24 + .../internal/handshake/ephermal_cache.go | 48 + .../internal/handshake/ephermal_cache_test.go | 35 + .../internal/handshake/handshake_message.go | 137 + .../handshake/handshake_message_test.go | 71 + .../handshake/handshake_suite_test.go | 24 + .../quic-go/internal/handshake/interface.go | 61 + .../internal/handshake/mock_mint_tls_test.go | 72 + .../quic-go/internal/handshake/mockgen.go | 3 + .../internal/handshake/server_config.go | 73 + .../handshake/server_config_client.go | 184 + .../handshake/server_config_client_test.go | 266 + .../internal/handshake/server_config_test.go | 45 + .../quic-go/internal/handshake/tags.go | 93 + .../internal/handshake/tls_extension.go | 123 + .../handshake/tls_extension_handler_client.go | 112 + .../tls_extension_handler_client_test.go | 233 + .../handshake/tls_extension_handler_server.go | 100 + .../tls_extension_handler_server_test.go | 155 + .../internal/handshake/tls_extension_test.go | 95 + .../handshake/transport_parameter_test.go | 265 + .../handshake/transport_parameters.go | 209 + .../quic-go/internal/mockgen_internal.sh | 36 + .../ackhandler/received_packet_handler.go | 83 + .../mocks/ackhandler/sent_packet_handler.go | 201 + .../quic-go/internal/mocks/congestion.go | 140 + .../mocks/connection_flow_controller.go | 112 + .../quic-go/internal/mocks/crypto/aead.go | 72 + .../quic-go/internal/mocks/mockgen.go | 9 + .../internal/mocks/stream_flow_controller.go | 124 + .../internal/mocks/tls_extension_handler.go | 72 + .../internal/protocol/connection_id.go | 69 + .../internal/protocol/connection_id_test.go | 108 + .../internal/protocol/encryption_level.go | 28 + .../protocol/encryption_level_test.go | 15 + .../internal/protocol/packet_number.go | 70 + .../internal/protocol/packet_number_test.go | 244 + .../quic-go/internal/protocol/perspective.go | 26 + .../internal/protocol/perspective_test.go | 19 + .../quic-go/internal/protocol/protocol.go | 90 + .../internal/protocol/protocol_suite_test.go | 13 + .../internal/protocol/protocol_test.go | 18 + .../internal/protocol/server_parameters.go | 154 + .../quic-go/internal/protocol/stream_id.go | 36 + .../internal/protocol/stream_id_test.go | 42 + .../quic-go/internal/protocol/version.go | 185 + .../quic-go/internal/protocol/version_test.go | 241 + .../quic-go/internal/testdata/cert.go | 44 + .../quic-go/internal/utils/atomic_bool.go | 22 + .../internal/utils/atomic_bool_test.go | 29 + .../internal/utils/byteinterval_linkedlist.go | 217 + .../utils/byteoder_big_endian_test.go | 220 + .../quic-go/internal/utils/byteorder.go | 25 + .../internal/utils/byteorder_big_endian.go | 157 + .../internal/utils/byteorder_little_endian.go | 157 + .../utils/byteorder_little_endian_test.go | 212 + .../quic-go/internal/utils/float16.go | 86 + .../quic-go/internal/utils/float16_test.go | 161 + .../quic-go/internal/utils/gen.go | 4 + .../quic-go/internal/utils/host.go | 27 + .../quic-go/internal/utils/host_test.go | 49 + .../internal/utils/linkedlist/README.md | 11 + .../internal/utils/linkedlist/linkedlist.go | 218 + .../quic-go/internal/utils/log.go | 131 + .../quic-go/internal/utils/log_test.go | 144 + .../quic-go/internal/utils/minmax.go | 147 + .../quic-go/internal/utils/minmax_test.go | 104 + .../quic-go/internal/utils/packet_interval.go | 9 + .../utils/packetinterval_linkedlist.go | 217 + .../internal/utils/streamframe_interval.go | 9 + .../quic-go/internal/utils/timer.go | 43 + .../quic-go/internal/utils/timer_test.go | 69 + .../internal/utils/utils_suite_test.go | 13 + .../quic-go/internal/utils/varint.go | 101 + .../internal/utils/varint_packetnumber.go | 50 + .../utils/varint_packetnumber_test.go | 157 + .../quic-go/internal/utils/varint_test.go | 157 + .../quic-go/internal/wire/ack_frame.go | 243 + .../quic-go/internal/wire/ack_frame_legacy.go | 364 ++ .../internal/wire/ack_frame_legacy_test.go | 1045 +++ .../quic-go/internal/wire/ack_frame_test.go | 410 ++ .../quic-go/internal/wire/ack_range.go | 14 + .../quic-go/internal/wire/ack_range_test.go | 13 + .../quic-go/internal/wire/blocked_frame.go | 45 + .../internal/wire/blocked_frame_legacy.go | 37 + .../wire/blocked_frame_legacy_test.go | 65 + .../internal/wire/blocked_frame_test.go | 54 + .../internal/wire/connection_close_frame.go | 96 + .../wire/connection_close_frame_test.go | 196 + .../quic-go/internal/wire/frame.go | 13 + .../quic-go/internal/wire/frame_parser.go | 172 + .../internal/wire/frame_parser_test.go | 359 + .../quic-go/internal/wire/goaway_frame.go | 68 + .../internal/wire/goaway_frame_test.go | 87 + .../quic-go/internal/wire/header.go | 333 + .../quic-go/internal/wire/header_parser.go | 273 + .../internal/wire/header_parser_test.go | 716 ++ .../quic-go/internal/wire/header_test.go | 902 +++ .../quic-go/internal/wire/log.go | 41 + .../quic-go/internal/wire/log_test.go | 96 + .../quic-go/internal/wire/max_data_frame.go | 51 + .../internal/wire/max_data_frame_test.go | 56 + .../internal/wire/max_stream_data_frame.go | 60 + .../wire/max_stream_data_frame_test.go | 62 + .../internal/wire/max_stream_id_frame.go | 37 + .../internal/wire/max_stream_id_frame_test.go | 51 + .../internal/wire/path_challenge_frame.go | 39 + .../wire/path_challenge_frame_test.go | 47 + .../internal/wire/path_response_frame.go | 39 + .../internal/wire/path_response_frame_test.go | 47 + .../quic-go/internal/wire/ping_frame.go | 33 + .../quic-go/internal/wire/ping_frame_test.go | 39 + .../quic-go/internal/wire/public_reset.go | 65 + .../internal/wire/public_reset_test.go | 96 + .../quic-go/internal/wire/rst_stream_frame.go | 89 + .../internal/wire/rst_stream_frame_test.go | 128 + .../internal/wire/stop_sending_frame.go | 47 + .../internal/wire/stop_sending_frame_test.go | 63 + .../internal/wire/stop_waiting_frame.go | 77 + .../internal/wire/stop_waiting_frame_test.go | 208 + .../internal/wire/stream_blocked_frame.go | 52 + .../wire/stream_blocked_frame_test.go | 63 + .../quic-go/internal/wire/stream_frame.go | 179 + .../internal/wire/stream_frame_legacy.go | 209 + .../internal/wire/stream_frame_legacy_test.go | 515 ++ .../internal/wire/stream_frame_test.go | 396 ++ .../internal/wire/stream_id_blocked_frame.go | 37 + .../wire/stream_id_blocked_frame_test.go | 53 + .../internal/wire/version_negotiation.go | 42 + .../internal/wire/version_negotiation_test.go | 49 + .../internal/wire/window_update_frame.go | 45 + .../internal/wire/window_update_frame_test.go | 98 + .../quic-go/internal/wire/wire_suite_test.go | 39 + vendor/lucas-clemente/quic-go/mint_utils.go | 52 + .../lucas-clemente/quic-go/mint_utils_test.go | 65 + .../quic-go/mock_crypto_stream_test.go | 141 + .../quic-go/mock_gquic_aead_test.go | 49 + .../quic-go/mock_multiplexer_test.go | 48 + .../mock_packet_handler_manager_test.go | 75 + .../quic-go/mock_packet_handler_test.go | 91 + .../quic-go/mock_quic_aead_test.go | 61 + .../quic-go/mock_quic_session_test.go | 242 + .../mock_receive_stream_internal_test.go | 132 + .../quic-go/mock_send_stream_internal_test.go | 154 + .../quic-go/mock_session_runner_test.go | 55 + .../quic-go/mock_stream_frame_source_test.go | 72 + .../quic-go/mock_stream_getter_test.go | 61 + .../quic-go/mock_stream_internal_test.go | 239 + .../quic-go/mock_stream_manager_test.go | 185 + .../quic-go/mock_stream_sender_test.go | 66 + .../mock_unknown_packet_handler_test.go | 56 + .../quic-go/mock_unpacker_test.go | 48 + vendor/lucas-clemente/quic-go/mockgen.go | 19 + .../lucas-clemente/quic-go/mockgen_private.sh | 28 + vendor/lucas-clemente/quic-go/multiplexer.go | 63 + .../quic-go/multiplexer_test.go | 23 + .../quic-go/packet_handler_map.go | 198 + .../quic-go/packet_handler_map_test.go | 206 + .../quic-go/packet_number_generator.go | 69 + .../quic-go/packet_number_generator_test.go | 87 + .../lucas-clemente/quic-go/packet_packer.go | 576 ++ .../quic-go/packet_packer_test.go | 1079 +++ .../lucas-clemente/quic-go/packet_unpacker.go | 127 + .../quic-go/packet_unpacker_test.go | 98 + .../quic-go/qerr/error_codes.go | 193 + .../quic-go/qerr/errorcode_string.go | 46 + .../quic-go/qerr/errorcodes_test.go | 38 + .../quic-go/qerr/errors_suite_test.go | 13 + .../lucas-clemente/quic-go/qerr/quic_error.go | 53 + .../quic-go/qerr/quic_error_test.go | 47 + .../lucas-clemente/quic-go/quic_suite_test.go | 37 + .../lucas-clemente/quic-go/receive_stream.go | 304 + .../quic-go/receive_stream_test.go | 630 ++ vendor/lucas-clemente/quic-go/send_stream.go | 325 + .../quic-go/send_stream_test.go | 599 ++ vendor/lucas-clemente/quic-go/server.go | 420 ++ .../lucas-clemente/quic-go/server_session.go | 63 + .../quic-go/server_session_test.go | 101 + vendor/lucas-clemente/quic-go/server_test.go | 519 ++ vendor/lucas-clemente/quic-go/server_tls.go | 178 + .../lucas-clemente/quic-go/server_tls_test.go | 125 + vendor/lucas-clemente/quic-go/session.go | 1283 ++++ vendor/lucas-clemente/quic-go/session_test.go | 1844 ++++++ vendor/lucas-clemente/quic-go/stream.go | 176 + .../lucas-clemente/quic-go/stream_framer.go | 98 + .../quic-go/stream_framer_test.go | 207 + vendor/lucas-clemente/quic-go/stream_test.go | 208 + vendor/lucas-clemente/quic-go/streams_map.go | 224 + .../quic-go/streams_map_generic_helper.go | 11 + .../quic-go/streams_map_incoming_bidi.go | 131 + .../quic-go/streams_map_incoming_generic.go | 129 + .../streams_map_incoming_generic_test.go | 165 + .../quic-go/streams_map_incoming_uni.go | 131 + .../quic-go/streams_map_legacy.go | 277 + .../quic-go/streams_map_legacy_test.go | 564 ++ .../quic-go/streams_map_outgoing_bidi.go | 126 + .../quic-go/streams_map_outgoing_generic.go | 124 + .../streams_map_outgoing_generic_test.go | 170 + .../quic-go/streams_map_outgoing_uni.go | 126 + .../quic-go/streams_map_test.go | 365 ++ .../github.com/bifurcation/mint/LICENSE.md | 21 + .../github.com/bifurcation/mint/README.md | 94 + .../github.com/bifurcation/mint/alert.go | 101 + .../bifurcation/mint/client-state-machine.go | 1083 +++ .../github.com/bifurcation/mint/common.go | 266 + .../github.com/bifurcation/mint/conn.go | 921 +++ .../bifurcation/mint/cookie-protector.go | 86 + .../github.com/bifurcation/mint/crypto.go | 667 ++ .../github.com/bifurcation/mint/dtls.go | 222 + .../github.com/bifurcation/mint/extensions.go | 626 ++ .../github.com/bifurcation/mint/ffdhe.go | 147 + .../bifurcation/mint/frame-reader.go | 98 + .../bifurcation/mint/handshake-layer.go | 551 ++ .../bifurcation/mint/handshake-messages.go | 481 ++ .../vendor/github.com/bifurcation/mint/log.go | 55 + .../github.com/bifurcation/mint/mint.svg | 101 + .../bifurcation/mint/negotiation.go | 218 + .../bifurcation/mint/record-layer.go | 458 ++ .../bifurcation/mint/server-state-machine.go | 1177 ++++ .../bifurcation/mint/state-machine.go | 247 + .../bifurcation/mint/syntax/README.md | 74 + .../bifurcation/mint/syntax/decode.go | 310 + .../bifurcation/mint/syntax/encode.go | 266 + .../bifurcation/mint/syntax/tags.go | 40 + .../github.com/bifurcation/mint/timer.go | 122 + .../vendor/github.com/bifurcation/mint/tls.go | 179 + .../github.com/cheekybits/genny/LICENSE | 22 + .../cheekybits/genny/generic/doc.go | 2 + .../cheekybits/genny/generic/generic.go | 13 + .../github.com/hashicorp/golang-lru/2q.go | 223 + .../github.com/hashicorp/golang-lru/LICENSE | 362 + .../github.com/hashicorp/golang-lru/README.md | 25 + .../github.com/hashicorp/golang-lru/arc.go | 257 + .../github.com/hashicorp/golang-lru/doc.go | 21 + .../github.com/hashicorp/golang-lru/lru.go | 110 + .../hashicorp/golang-lru/simplelru/lru.go | 161 + .../golang-lru/simplelru/lru_interface.go | 36 + .../github.com/lucas-clemente/aes12/LICENSE | 21 + .../github.com/lucas-clemente/aes12/Readme.md | 28 + .../lucas-clemente/aes12/aes_gcm.go | 148 + .../lucas-clemente/aes12/asm_amd64.s | 285 + .../github.com/lucas-clemente/aes12/block.go | 176 + .../github.com/lucas-clemente/aes12/cipher.go | 68 + .../lucas-clemente/aes12/cipher_2.go | 56 + .../lucas-clemente/aes12/cipher_amd64.go | 79 + .../lucas-clemente/aes12/cipher_generic.go | 22 + .../github.com/lucas-clemente/aes12/const.go | 358 + .../github.com/lucas-clemente/aes12/gcm.go | 401 ++ .../lucas-clemente/aes12/gcm_amd64.s | 1277 ++++ .../github.com/lucas-clemente/aes12/xor.go | 84 + .../quic-go-certificates/LICENSE | 21 + .../quic-go-certificates/README.md | 3 + .../quic-go-certificates/cert_set_2.go | 5824 +++++++++++++++++ .../quic-go-certificates/cert_set_3.go | 5456 +++++++++++++++ .../quic-go-certificates/createCertSets.rb | 34 + .../quic-go/window_update_queue.go | 79 + .../quic-go/window_update_queue_test.go | 102 + 414 files changed, 78680 insertions(+) create mode 100644 vendor/lucas-clemente/quic-go/Changelog.md create mode 100644 vendor/lucas-clemente/quic-go/LICENSE create mode 100644 vendor/lucas-clemente/quic-go/README.md create mode 100644 vendor/lucas-clemente/quic-go/appveyor.yml create mode 100644 vendor/lucas-clemente/quic-go/benchmark/benchmark_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/benchmark/benchmark_test.go create mode 100644 vendor/lucas-clemente/quic-go/buffer_pool.go create mode 100644 vendor/lucas-clemente/quic-go/buffer_pool_test.go create mode 100644 vendor/lucas-clemente/quic-go/client.go create mode 100644 vendor/lucas-clemente/quic-go/client_test.go create mode 100644 vendor/lucas-clemente/quic-go/codecov.yml create mode 100644 vendor/lucas-clemente/quic-go/conn.go create mode 100644 vendor/lucas-clemente/quic-go/conn_test.go create mode 100644 vendor/lucas-clemente/quic-go/crypto_stream.go create mode 100644 vendor/lucas-clemente/quic-go/crypto_stream_test.go create mode 100644 vendor/lucas-clemente/quic-go/docs/quic.png create mode 100644 vendor/lucas-clemente/quic-go/docs/quic.sketch create mode 100644 vendor/lucas-clemente/quic-go/docs/quic.svg create mode 100644 vendor/lucas-clemente/quic-go/example/Dockerfile create mode 100644 vendor/lucas-clemente/quic-go/example/Readme.md create mode 100644 vendor/lucas-clemente/quic-go/example/client/main.go create mode 100644 vendor/lucas-clemente/quic-go/example/echo/echo.go create mode 100644 vendor/lucas-clemente/quic-go/example/fullchain.pem create mode 100644 vendor/lucas-clemente/quic-go/example/main.go create mode 100644 vendor/lucas-clemente/quic-go/example/privkey.pem create mode 100644 vendor/lucas-clemente/quic-go/frame_sorter.go create mode 100644 vendor/lucas-clemente/quic-go/frame_sorter_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/client.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/client_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/gzipreader.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/h2quic_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/request.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/request_body.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/request_body_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/request_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/request_writer.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/request_writer_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/response.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/response_writer.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/response_writer_closenotifier.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/response_writer_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/roundtrip.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/roundtrip_test.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/server.go create mode 100644 vendor/lucas-clemente/quic-go/h2quic/server_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/gquic/drop_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/gquic/gquic_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/gquic/integration_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/gquic/random_rtt_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/gquic/rtt_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/gquic/server_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/client_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/conn_id_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/handshake_drop_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/handshake_rtt_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/handshake_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/multiplex_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/rtt_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/self_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/stream_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/self/uni_stream_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_test.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/tools/testlog/testlog.go create mode 100644 vendor/lucas-clemente/quic-go/integrationtests/tools/testserver/server.go create mode 100644 vendor/lucas-clemente/quic-go/interface.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/ackhandler_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/gen.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/interfaces.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/packet.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/packet_linkedlist.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager.go create mode 100644 vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/bandwidth.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/bandwidth_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/clock.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/congestion_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/cubic.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/cubic_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/interface.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/prr_sender.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/prr_sender_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/congestion/stats.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/AEAD.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_cache.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_cache_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_chain.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_chain_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_compression.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_compression_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_dict.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_manager.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_manager_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/cert_sets.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/crypto_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/curve_25519.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/curve_25519_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/key_derivation.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/key_exchange.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/null_aead.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/null_aead_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/server_proof.go create mode 100644 vendor/lucas-clemente/quic-go/internal/crypto/server_proof_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/flowcontrol_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/interface.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller.go create mode 100644 vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/data_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/handshake_message.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/handshake_message_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/handshake_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/interface.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/mock_mint_tls_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/mockgen.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/server_config.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/server_config_client.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/server_config_client_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/server_config_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/tags.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/tls_extension.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/transport_parameter_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/handshake/transport_parameters.go create mode 100755 vendor/lucas-clemente/quic-go/internal/mockgen_internal.sh create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/received_packet_handler.go create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/sent_packet_handler.go create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/congestion.go create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/connection_flow_controller.go create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/crypto/aead.go create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/mockgen.go create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/stream_flow_controller.go create mode 100644 vendor/lucas-clemente/quic-go/internal/mocks/tls_extension_handler.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/connection_id.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/connection_id_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/encryption_level.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/encryption_level_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/packet_number.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/packet_number_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/perspective.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/perspective_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/protocol.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/protocol_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/protocol_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/server_parameters.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/stream_id.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/stream_id_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/version.go create mode 100644 vendor/lucas-clemente/quic-go/internal/protocol/version_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/testdata/cert.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/atomic_bool.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/atomic_bool_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/byteinterval_linkedlist.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/byteoder_big_endian_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/byteorder.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/float16.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/float16_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/gen.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/host.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/host_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/linkedlist/README.md create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/linkedlist/linkedlist.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/log.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/log_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/minmax.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/minmax_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/packet_interval.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/packetinterval_linkedlist.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/streamframe_interval.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/timer.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/timer_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/utils_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/varint.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/utils/varint_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ack_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ack_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ack_range.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ack_range_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/blocked_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/frame_parser.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/frame_parser_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/goaway_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/goaway_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/header.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/header_parser.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/header_parser_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/header_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/log.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/log_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/max_data_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/max_data_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/path_response_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/path_response_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ping_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/ping_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/public_reset.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/public_reset_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/version_negotiation.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/version_negotiation_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/window_update_frame.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/window_update_frame_test.go create mode 100644 vendor/lucas-clemente/quic-go/internal/wire/wire_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/mint_utils.go create mode 100644 vendor/lucas-clemente/quic-go/mint_utils_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_crypto_stream_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_gquic_aead_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_multiplexer_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_packet_handler_manager_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_packet_handler_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_quic_aead_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_quic_session_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_receive_stream_internal_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_send_stream_internal_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_session_runner_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_stream_frame_source_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_stream_getter_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_stream_internal_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_stream_manager_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_stream_sender_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_unknown_packet_handler_test.go create mode 100644 vendor/lucas-clemente/quic-go/mock_unpacker_test.go create mode 100644 vendor/lucas-clemente/quic-go/mockgen.go create mode 100755 vendor/lucas-clemente/quic-go/mockgen_private.sh create mode 100644 vendor/lucas-clemente/quic-go/multiplexer.go create mode 100644 vendor/lucas-clemente/quic-go/multiplexer_test.go create mode 100644 vendor/lucas-clemente/quic-go/packet_handler_map.go create mode 100644 vendor/lucas-clemente/quic-go/packet_handler_map_test.go create mode 100644 vendor/lucas-clemente/quic-go/packet_number_generator.go create mode 100644 vendor/lucas-clemente/quic-go/packet_number_generator_test.go create mode 100644 vendor/lucas-clemente/quic-go/packet_packer.go create mode 100644 vendor/lucas-clemente/quic-go/packet_packer_test.go create mode 100644 vendor/lucas-clemente/quic-go/packet_unpacker.go create mode 100644 vendor/lucas-clemente/quic-go/packet_unpacker_test.go create mode 100644 vendor/lucas-clemente/quic-go/qerr/error_codes.go create mode 100644 vendor/lucas-clemente/quic-go/qerr/errorcode_string.go create mode 100644 vendor/lucas-clemente/quic-go/qerr/errorcodes_test.go create mode 100644 vendor/lucas-clemente/quic-go/qerr/errors_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/qerr/quic_error.go create mode 100644 vendor/lucas-clemente/quic-go/qerr/quic_error_test.go create mode 100644 vendor/lucas-clemente/quic-go/quic_suite_test.go create mode 100644 vendor/lucas-clemente/quic-go/receive_stream.go create mode 100644 vendor/lucas-clemente/quic-go/receive_stream_test.go create mode 100644 vendor/lucas-clemente/quic-go/send_stream.go create mode 100644 vendor/lucas-clemente/quic-go/send_stream_test.go create mode 100644 vendor/lucas-clemente/quic-go/server.go create mode 100644 vendor/lucas-clemente/quic-go/server_session.go create mode 100644 vendor/lucas-clemente/quic-go/server_session_test.go create mode 100644 vendor/lucas-clemente/quic-go/server_test.go create mode 100644 vendor/lucas-clemente/quic-go/server_tls.go create mode 100644 vendor/lucas-clemente/quic-go/server_tls_test.go create mode 100644 vendor/lucas-clemente/quic-go/session.go create mode 100644 vendor/lucas-clemente/quic-go/session_test.go create mode 100644 vendor/lucas-clemente/quic-go/stream.go create mode 100644 vendor/lucas-clemente/quic-go/stream_framer.go create mode 100644 vendor/lucas-clemente/quic-go/stream_framer_test.go create mode 100644 vendor/lucas-clemente/quic-go/stream_test.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_generic_helper.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_incoming_bidi.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_incoming_generic.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_incoming_generic_test.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_incoming_uni.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_legacy.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_legacy_test.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_outgoing_bidi.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_outgoing_generic.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_outgoing_generic_test.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_outgoing_uni.go create mode 100644 vendor/lucas-clemente/quic-go/streams_map_test.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/LICENSE.md create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/README.md create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/alert.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/client-state-machine.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/common.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/conn.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/cookie-protector.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/crypto.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/dtls.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/extensions.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/ffdhe.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/frame-reader.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-layer.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-messages.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/log.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/mint.svg create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/negotiation.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/record-layer.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/server-state-machine.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/state-machine.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/README.md create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/decode.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/encode.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/tags.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/timer.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/tls.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/LICENSE create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/doc.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/generic.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/2q.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/LICENSE create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/README.md create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/arc.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/doc.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/lru.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/LICENSE create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/Readme.md create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/aes_gcm.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/asm_amd64.s create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/block.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_2.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_amd64.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_generic.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/const.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm_amd64.s create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/xor.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/LICENSE create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/README.md create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_2.go create mode 100644 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_3.go create mode 100755 vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/createCertSets.rb create mode 100644 vendor/lucas-clemente/quic-go/window_update_queue.go create mode 100644 vendor/lucas-clemente/quic-go/window_update_queue_test.go diff --git a/vendor/lucas-clemente/quic-go/Changelog.md b/vendor/lucas-clemente/quic-go/Changelog.md new file mode 100644 index 00000000..cbc88e73 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/Changelog.md @@ -0,0 +1,44 @@ +# Changelog + +## v0.10.0 (2018-08-28) + +- Add support for QUIC 44, drop support for QUIC 42. + +## v0.9.0 (2018-08-15) + +- Add a `quic.Config` option for the length of the connection ID (for IETF QUIC). +- Split Session.Close into one method for regular closing and one for closing with an error. + +## v0.8.0 (2018-06-26) + +- Add support for unidirectional streams (for IETF QUIC). +- Add a `quic.Config` option for the maximum number of incoming streams. +- Add support for QUIC 42 and 43. +- Add dial functions that use a context. +- Multiplex clients on a net.PacketConn, when using Dial(conn). + +## v0.7.0 (2018-02-03) + +- The lower boundary for packets included in ACKs is now derived, and the value sent in STOP_WAITING frames is ignored. +- Remove `DialNonFWSecure` and `DialAddrNonFWSecure`. +- Expose the `ConnectionState` in the `Session` (experimental API). +- Implement packet pacing. + +## v0.6.0 (2017-12-12) + +- Add support for QUIC 39, drop support for QUIC 35 - 37 +- Added `quic.Config` options for maximal flow control windows +- Add a `quic.Config` option for QUIC versions +- Add a `quic.Config` option to request omission of the connection ID from a server +- Add a `quic.Config` option to configure the source address validation +- Add a `quic.Config` option to configure the handshake timeout +- Add a `quic.Config` option to configure the idle timeout +- Add a `quic.Config` option to configure keep-alive +- Rename the STK to Cookie +- Implement `net.Conn`-style deadlines for streams +- Remove the `tls.Config` from the `quic.Config`. The `tls.Config` must now be passed to the `Dial` and `Listen` functions as a separate parameter. See the [Godoc](https://godoc.org/github.com/lucas-clemente/quic-go) for details. +- Changed the log level environment variable to only accept strings ("DEBUG", "INFO", "ERROR"), see [the wiki](https://github.com/lucas-clemente/quic-go/wiki/Logging) for more details. +- Rename the `h2quic.QuicRoundTripper` to `h2quic.RoundTripper` +- Changed `h2quic.Server.Serve()` to accept a `net.PacketConn` +- Drop support for Go 1.7 and 1.8. +- Various bugfixes diff --git a/vendor/lucas-clemente/quic-go/LICENSE b/vendor/lucas-clemente/quic-go/LICENSE new file mode 100644 index 00000000..51378bef --- /dev/null +++ b/vendor/lucas-clemente/quic-go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 the quic-go authors & Google, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/lucas-clemente/quic-go/README.md b/vendor/lucas-clemente/quic-go/README.md new file mode 100644 index 00000000..58d65bd3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/README.md @@ -0,0 +1,73 @@ +# A QUIC implementation in pure Go + + + +[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/lucas-clemente/quic-go) +[![Travis Build Status](https://img.shields.io/travis/lucas-clemente/quic-go/master.svg?style=flat-square&label=Travis+build)](https://travis-ci.org/lucas-clemente/quic-go) +[![CircleCI Build Status](https://img.shields.io/circleci/project/github/lucas-clemente/quic-go.svg?style=flat-square&label=CircleCI+build)](https://circleci.com/gh/lucas-clemente/quic-go) +[![Windows Build Status](https://img.shields.io/appveyor/ci/lucas-clemente/quic-go/master.svg?style=flat-square&label=windows+build)](https://ci.appveyor.com/project/lucas-clemente/quic-go/branch/master) +[![Code Coverage](https://img.shields.io/codecov/c/github/lucas-clemente/quic-go/master.svg?style=flat-square)](https://codecov.io/gh/lucas-clemente/quic-go/) + +quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol in Go. + +## Roadmap + +quic-go is compatible with the current version(s) of Google Chrome and QUIC as deployed on Google's servers. We're actively tracking the development of the Chrome code to ensure compatibility as the protocol evolves. In that process, we're dropping support for old QUIC versions. +As Google's QUIC versions are expected to converge towards the [IETF QUIC draft](https://github.com/quicwg/base-drafts), quic-go will eventually implement that draft. + +## Guides + +We currently support Go 1.9+. + +Installing and updating dependencies: + + go get -t -u ./... + +Running tests: + + go test ./... + +### Running the example server + + go run example/main.go -www /var/www/ + +Using the `quic_client` from chromium: + + quic_client --host=127.0.0.1 --port=6121 --v=1 https://quic.clemente.io + +Using Chrome: + + /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir=/tmp/chrome --no-proxy-server --enable-quic --origin-to-force-quic-on=quic.clemente.io:443 --host-resolver-rules='MAP quic.clemente.io:443 127.0.0.1:6121' https://quic.clemente.io + +### QUIC without HTTP/2 + +Take a look at [this echo example](example/echo/echo.go). + +### Using the example client + + go run example/client/main.go https://clemente.io + +## Usage + +### As a server + +See the [example server](example/main.go) or try out [Caddy](https://github.com/mholt/caddy) (from version 0.9, [instructions here](https://github.com/mholt/caddy/wiki/QUIC)). Starting a QUIC server is very similar to the standard lib http in go: + +```go +http.Handle("/", http.FileServer(http.Dir(wwwDir))) +h2quic.ListenAndServeQUIC("localhost:4242", "/path/to/cert/chain.pem", "/path/to/privkey.pem", nil) +``` + +### As a client + +See the [example client](example/client/main.go). Use a `h2quic.RoundTripper` as a `Transport` in a `http.Client`. + +```go +http.Client{ + Transport: &h2quic.RoundTripper{}, +} +``` + +## Contributing + +We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [help wanted](https://github.com/lucas-clemente/quic-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). If you have any questions, please feel free to reach out by opening an issue or leaving a comment. diff --git a/vendor/lucas-clemente/quic-go/appveyor.yml b/vendor/lucas-clemente/quic-go/appveyor.yml new file mode 100644 index 00000000..d217edd1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/appveyor.yml @@ -0,0 +1,35 @@ +version: "{build}" + +os: Windows Server 2012 R2 + +environment: + GOPATH: c:\gopath + CGO_ENABLED: 0 + TIMESCALE_FACTOR: 20 + matrix: + - GOARCH: 386 + - GOARCH: amd64 + +clone_folder: c:\gopath\src\github.com\lucas-clemente\quic-go + +install: + - rmdir c:\go /s /q + - appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.windows-amd64.zip + - 7z x go1.11.windows-amd64.zip -y -oC:\ > NUL + - set PATH=%PATH%;%GOPATH%\bin\windows_%GOARCH%;%GOPATH%\bin + - echo %PATH% + - echo %GOPATH% + - git submodule update --init --recursive + - go get github.com/onsi/ginkgo/ginkgo + - go get github.com/onsi/gomega + - go version + - go env + - go get -v -t ./... + +build_script: + - ginkgo -r -v -randomizeAllSpecs -randomizeSuites -trace -skipPackage benchmark,integrationtests + - ginkgo -randomizeAllSpecs -randomizeSuites -trace benchmark -- -samples=1 + +test: off + +deploy: off diff --git a/vendor/lucas-clemente/quic-go/benchmark/benchmark_suite_test.go b/vendor/lucas-clemente/quic-go/benchmark/benchmark_suite_test.go new file mode 100644 index 00000000..d24ef6be --- /dev/null +++ b/vendor/lucas-clemente/quic-go/benchmark/benchmark_suite_test.go @@ -0,0 +1,26 @@ +package benchmark + +import ( + "flag" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestBenchmark(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Benchmark Suite") +} + +var ( + size int // file size in MB, will be read from flags + samples int // number of samples for Measure, will be read from flags +) + +func init() { + flag.IntVar(&size, "size", 50, "data length (in MB)") + flag.IntVar(&samples, "samples", 6, "number of samples") + flag.Parse() +} diff --git a/vendor/lucas-clemente/quic-go/benchmark/benchmark_test.go b/vendor/lucas-clemente/quic-go/benchmark/benchmark_test.go new file mode 100644 index 00000000..70b0264c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/benchmark/benchmark_test.go @@ -0,0 +1,87 @@ +package benchmark + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "math/rand" + "net" + + quic "github.com/lucas-clemente/quic-go" + _ "github.com/lucas-clemente/quic-go/integrationtests/tools/testlog" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func init() { + var _ = Describe("Benchmarks", func() { + dataLen := size * /* MB */ 1e6 + data := make([]byte, dataLen) + rand.Seed(GinkgoRandomSeed()) + rand.Read(data) // no need to check for an error. math.Rand.Read never errors + + for i := range protocol.SupportedVersions { + version := protocol.SupportedVersions[i] + + Context(fmt.Sprintf("with version %s", version), func() { + Measure(fmt.Sprintf("transferring a %d MB file", size), func(b Benchmarker) { + var ln quic.Listener + serverAddr := make(chan net.Addr) + handshakeChan := make(chan struct{}) + // start the server + go func() { + defer GinkgoRecover() + var err error + ln, err = quic.ListenAddr( + "localhost:0", + testdata.GetTLSConfig(), + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + serverAddr <- ln.Addr() + sess, err := ln.Accept() + Expect(err).ToNot(HaveOccurred()) + // wait for the client to complete the handshake before sending the data + // this should not be necessary, but due to timing issues on the CIs, this is necessary to avoid sending too many undecryptable packets + <-handshakeChan + str, err := sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + _, err = str.Write(data) + Expect(err).ToNot(HaveOccurred()) + err = str.Close() + Expect(err).ToNot(HaveOccurred()) + }() + + // start the client + addr := <-serverAddr + sess, err := quic.DialAddr( + addr.String(), + &tls.Config{InsecureSkipVerify: true}, + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + close(handshakeChan) + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + + buf := &bytes.Buffer{} + // measure the time it takes to download the dataLen bytes + // note we're measuring the time for the transfer, i.e. excluding the handshake + runtime := b.Time("transfer time", func() { + _, err := io.Copy(buf, str) + Expect(err).NotTo(HaveOccurred()) + }) + Expect(buf.Bytes()).To(Equal(data)) + + b.RecordValue("transfer rate [MB/s]", float64(dataLen)/1e6/runtime.Seconds()) + + ln.Close() + sess.Close() + }, samples) + }) + } + }) +} diff --git a/vendor/lucas-clemente/quic-go/buffer_pool.go b/vendor/lucas-clemente/quic-go/buffer_pool.go new file mode 100644 index 00000000..6b233696 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/buffer_pool.go @@ -0,0 +1,27 @@ +package quic + +import ( + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +var bufferPool sync.Pool + +func getPacketBuffer() *[]byte { + return bufferPool.Get().(*[]byte) +} + +func putPacketBuffer(buf *[]byte) { + if cap(*buf) != int(protocol.MaxReceivePacketSize) { + panic("putPacketBuffer called with packet of wrong size!") + } + bufferPool.Put(buf) +} + +func init() { + bufferPool.New = func() interface{} { + b := make([]byte, 0, protocol.MaxReceivePacketSize) + return &b + } +} diff --git a/vendor/lucas-clemente/quic-go/buffer_pool_test.go b/vendor/lucas-clemente/quic-go/buffer_pool_test.go new file mode 100644 index 00000000..7413ceaf --- /dev/null +++ b/vendor/lucas-clemente/quic-go/buffer_pool_test.go @@ -0,0 +1,21 @@ +package quic + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Buffer Pool", func() { + It("returns buffers of cap", func() { + buf := *getPacketBuffer() + Expect(buf).To(HaveCap(int(protocol.MaxReceivePacketSize))) + }) + + It("panics if wrong-sized buffers are passed", func() { + Expect(func() { + putPacketBuffer(&[]byte{0}) + }).To(Panic()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/client.go b/vendor/lucas-clemente/quic-go/client.go new file mode 100644 index 00000000..71e72dce --- /dev/null +++ b/vendor/lucas-clemente/quic-go/client.go @@ -0,0 +1,595 @@ +package quic + +import ( + "bytes" + "context" + "crypto/tls" + "errors" + "fmt" + "net" + "sync" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +type client struct { + mutex sync.Mutex + + conn connection + // If the client is created with DialAddr, we create a packet conn. + // If it is started with Dial, we take a packet conn as a parameter. + createdPacketConn bool + + hostname string + + packetHandlers packetHandlerManager + + token []byte + numRetries int + + versionNegotiated bool // has the server accepted our version + receivedVersionNegotiationPacket bool + negotiatedVersions []protocol.VersionNumber // the list of versions from the version negotiation packet + + tlsConf *tls.Config + mintConf *mint.Config + config *Config + + srcConnID protocol.ConnectionID + destConnID protocol.ConnectionID + + initialVersion protocol.VersionNumber + version protocol.VersionNumber + + handshakeChan chan struct{} + closeCallback func(protocol.ConnectionID) + + session quicSession + + logger utils.Logger +} + +var _ packetHandler = &client{} + +var ( + // make it possible to mock connection ID generation in the tests + generateConnectionID = protocol.GenerateConnectionID + generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial + errCloseSessionForNewVersion = errors.New("closing session in order to recreate it with a new version") + errCloseSessionForRetry = errors.New("closing session in response to a stateless retry") +) + +// DialAddr establishes a new QUIC connection to a server. +// The hostname for SNI is taken from the given address. +func DialAddr( + addr string, + tlsConf *tls.Config, + config *Config, +) (Session, error) { + return DialAddrContext(context.Background(), addr, tlsConf, config) +} + +// DialAddrContext establishes a new QUIC connection to a server using the provided context. +// The hostname for SNI is taken from the given address. +func DialAddrContext( + ctx context.Context, + addr string, + tlsConf *tls.Config, + config *Config, +) (Session, error) { + udpAddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + return nil, err + } + udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) + if err != nil { + return nil, err + } + return dialContext(ctx, udpConn, udpAddr, addr, tlsConf, config, true) +} + +// Dial establishes a new QUIC connection to a server using a net.PacketConn. +// The host parameter is used for SNI. +func Dial( + pconn net.PacketConn, + remoteAddr net.Addr, + host string, + tlsConf *tls.Config, + config *Config, +) (Session, error) { + return DialContext(context.Background(), pconn, remoteAddr, host, tlsConf, config) +} + +// DialContext establishes a new QUIC connection to a server using a net.PacketConn using the provided context. +// The host parameter is used for SNI. +func DialContext( + ctx context.Context, + pconn net.PacketConn, + remoteAddr net.Addr, + host string, + tlsConf *tls.Config, + config *Config, +) (Session, error) { + return dialContext(ctx, pconn, remoteAddr, host, tlsConf, config, false) +} + +func dialContext( + ctx context.Context, + pconn net.PacketConn, + remoteAddr net.Addr, + host string, + tlsConf *tls.Config, + config *Config, + createdPacketConn bool, +) (Session, error) { + config = populateClientConfig(config, createdPacketConn) + if !createdPacketConn { + for _, v := range config.Versions { + if v == protocol.Version44 { + return nil, errors.New("Cannot multiplex connections using gQUIC 44, see https://groups.google.com/a/chromium.org/forum/#!topic/proto-quic/pE9NlLLjizE. Please disable gQUIC 44 in the quic.Config, or use DialAddr") + } + } + } + packetHandlers, err := getMultiplexer().AddConn(pconn, config.ConnectionIDLength) + if err != nil { + return nil, err + } + c, err := newClient(pconn, remoteAddr, config, tlsConf, host, packetHandlers.Remove, createdPacketConn) + if err != nil { + return nil, err + } + c.packetHandlers = packetHandlers + if err := c.dial(ctx); err != nil { + return nil, err + } + return c.session, nil +} + +func newClient( + pconn net.PacketConn, + remoteAddr net.Addr, + config *Config, + tlsConf *tls.Config, + host string, + closeCallback func(protocol.ConnectionID), + createdPacketConn bool, +) (*client, error) { + var hostname string + if tlsConf != nil { + hostname = tlsConf.ServerName + } + if hostname == "" { + var err error + hostname, _, err = net.SplitHostPort(host) + if err != nil { + return nil, err + } + } + + // check that all versions are actually supported + if config != nil { + for _, v := range config.Versions { + if !protocol.IsValidVersion(v) { + return nil, fmt.Errorf("%s is not a valid QUIC version", v) + } + } + } + onClose := func(protocol.ConnectionID) {} + if closeCallback != nil { + onClose = closeCallback + } + c := &client{ + conn: &conn{pconn: pconn, currentAddr: remoteAddr}, + createdPacketConn: createdPacketConn, + hostname: hostname, + tlsConf: tlsConf, + config: config, + version: config.Versions[0], + handshakeChan: make(chan struct{}), + closeCallback: onClose, + logger: utils.DefaultLogger.WithPrefix("client"), + } + return c, c.generateConnectionIDs() +} + +// populateClientConfig populates fields in the quic.Config with their default values, if none are set +// it may be called with nil +func populateClientConfig(config *Config, createdPacketConn bool) *Config { + if config == nil { + config = &Config{} + } + versions := config.Versions + if len(versions) == 0 { + versions = protocol.SupportedVersions + } + + handshakeTimeout := protocol.DefaultHandshakeTimeout + if config.HandshakeTimeout != 0 { + handshakeTimeout = config.HandshakeTimeout + } + idleTimeout := protocol.DefaultIdleTimeout + if config.IdleTimeout != 0 { + idleTimeout = config.IdleTimeout + } + + maxReceiveStreamFlowControlWindow := config.MaxReceiveStreamFlowControlWindow + if maxReceiveStreamFlowControlWindow == 0 { + maxReceiveStreamFlowControlWindow = protocol.DefaultMaxReceiveStreamFlowControlWindowClient + } + maxReceiveConnectionFlowControlWindow := config.MaxReceiveConnectionFlowControlWindow + if maxReceiveConnectionFlowControlWindow == 0 { + maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindowClient + } + maxIncomingStreams := config.MaxIncomingStreams + if maxIncomingStreams == 0 { + maxIncomingStreams = protocol.DefaultMaxIncomingStreams + } else if maxIncomingStreams < 0 { + maxIncomingStreams = 0 + } + maxIncomingUniStreams := config.MaxIncomingUniStreams + if maxIncomingUniStreams == 0 { + maxIncomingUniStreams = protocol.DefaultMaxIncomingUniStreams + } else if maxIncomingUniStreams < 0 { + maxIncomingUniStreams = 0 + } + connIDLen := config.ConnectionIDLength + if connIDLen == 0 && !createdPacketConn { + connIDLen = protocol.DefaultConnectionIDLength + } + for _, v := range versions { + if v == protocol.Version44 { + connIDLen = 0 + } + } + + return &Config{ + Versions: versions, + HandshakeTimeout: handshakeTimeout, + IdleTimeout: idleTimeout, + RequestConnectionIDOmission: config.RequestConnectionIDOmission, + ConnectionIDLength: connIDLen, + MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, + MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, + MaxIncomingStreams: maxIncomingStreams, + MaxIncomingUniStreams: maxIncomingUniStreams, + KeepAlive: config.KeepAlive, + } +} + +func (c *client) generateConnectionIDs() error { + connIDLen := protocol.ConnectionIDLenGQUIC + if c.version.UsesTLS() { + connIDLen = c.config.ConnectionIDLength + } + srcConnID, err := generateConnectionID(connIDLen) + if err != nil { + return err + } + destConnID := srcConnID + if c.version.UsesTLS() { + destConnID, err = generateConnectionIDForInitial() + if err != nil { + return err + } + } + c.srcConnID = srcConnID + c.destConnID = destConnID + if c.version == protocol.Version44 { + c.srcConnID = nil + } + return nil +} + +func (c *client) dial(ctx context.Context) error { + c.logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", c.hostname, c.conn.LocalAddr(), c.conn.RemoteAddr(), c.srcConnID, c.destConnID, c.version) + + var err error + if c.version.UsesTLS() { + err = c.dialTLS(ctx) + } else { + err = c.dialGQUIC(ctx) + } + return err +} + +func (c *client) dialGQUIC(ctx context.Context) error { + if err := c.createNewGQUICSession(); err != nil { + return err + } + err := c.establishSecureConnection(ctx) + if err == errCloseSessionForNewVersion { + return c.dial(ctx) + } + return err +} + +func (c *client) dialTLS(ctx context.Context) error { + params := &handshake.TransportParameters{ + StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, + ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, + IdleTimeout: c.config.IdleTimeout, + OmitConnectionID: c.config.RequestConnectionIDOmission, + MaxBidiStreams: uint16(c.config.MaxIncomingStreams), + MaxUniStreams: uint16(c.config.MaxIncomingUniStreams), + DisableMigration: true, + } + extHandler := handshake.NewExtensionHandlerClient(params, c.initialVersion, c.config.Versions, c.version, c.logger) + mintConf, err := tlsToMintConfig(c.tlsConf, protocol.PerspectiveClient) + if err != nil { + return err + } + mintConf.ExtensionHandler = extHandler + mintConf.ServerName = c.hostname + c.mintConf = mintConf + + if err := c.createNewTLSSession(extHandler.GetPeerParams(), c.version); err != nil { + return err + } + err = c.establishSecureConnection(ctx) + if err == errCloseSessionForRetry || err == errCloseSessionForNewVersion { + return c.dial(ctx) + } + return err +} + +// establishSecureConnection runs the session, and tries to establish a secure connection +// It returns: +// - errCloseSessionForNewVersion when the server sends a version negotiation packet +// - handshake.ErrCloseSessionForRetry when the server performs a stateless retry (for IETF QUIC) +// - any other error that might occur +// - when the connection is secure (for gQUIC), or forward-secure (for IETF QUIC) +func (c *client) establishSecureConnection(ctx context.Context) error { + errorChan := make(chan error, 1) + + go func() { + err := c.session.run() // returns as soon as the session is closed + if err != errCloseSessionForRetry && err != errCloseSessionForNewVersion && c.createdPacketConn { + c.conn.Close() + } + errorChan <- err + }() + + select { + case <-ctx.Done(): + // The session will send a PeerGoingAway error to the server. + c.session.Close() + return ctx.Err() + case err := <-errorChan: + return err + case <-c.handshakeChan: + // handshake successfully completed + return nil + } +} + +func (c *client) handlePacket(p *receivedPacket) { + if err := c.handlePacketImpl(p); err != nil { + c.logger.Errorf("error handling packet: %s", err) + } +} + +func (c *client) handlePacketImpl(p *receivedPacket) error { + c.mutex.Lock() + defer c.mutex.Unlock() + + // handle Version Negotiation Packets + if p.header.IsVersionNegotiation { + err := c.handleVersionNegotiationPacket(p.header) + if err != nil { + c.session.destroy(err) + } + // version negotiation packets have no payload + return err + } + + if !c.version.UsesIETFHeaderFormat() { + connID := p.header.DestConnectionID + // reject packets with truncated connection id if we didn't request truncation + if !c.config.RequestConnectionIDOmission && connID.Len() == 0 { + return errors.New("received packet with truncated connection ID, but didn't request truncation") + } + // reject packets with the wrong connection ID + if connID.Len() > 0 && !connID.Equal(c.srcConnID) { + return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", connID, c.srcConnID) + } + if p.header.ResetFlag { + return c.handlePublicReset(p) + } + } else { + // reject packets with the wrong connection ID + if !p.header.DestConnectionID.Equal(c.srcConnID) { + return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", p.header.DestConnectionID, c.srcConnID) + } + } + + if p.header.IsLongHeader { + switch p.header.Type { + case protocol.PacketTypeRetry: + c.handleRetryPacket(p.header) + return nil + case protocol.PacketTypeHandshake, protocol.PacketType0RTT: + default: + return fmt.Errorf("Received unsupported packet type: %s", p.header.Type) + } + } + + // this is the first packet we are receiving + // since it is not a Version Negotiation Packet, this means the server supports the suggested version + if !c.versionNegotiated { + c.versionNegotiated = true + } + + c.session.handlePacket(p) + return nil +} + +func (c *client) handlePublicReset(p *receivedPacket) error { + cr := c.conn.RemoteAddr() + // check if the remote address and the connection ID match + // otherwise this might be an attacker trying to inject a PUBLIC_RESET to kill the connection + if cr.Network() != p.remoteAddr.Network() || cr.String() != p.remoteAddr.String() || !p.header.DestConnectionID.Equal(c.srcConnID) { + return errors.New("Received a spoofed Public Reset") + } + pr, err := wire.ParsePublicReset(bytes.NewReader(p.data)) + if err != nil { + return fmt.Errorf("Received a Public Reset. An error occurred parsing the packet: %s", err) + } + c.session.closeRemote(qerr.Error(qerr.PublicReset, fmt.Sprintf("Received a Public Reset for packet number %#x", pr.RejectedPacketNumber))) + c.logger.Infof("Received Public Reset, rejected packet number: %#x", pr.RejectedPacketNumber) + return nil +} + +func (c *client) handleVersionNegotiationPacket(hdr *wire.Header) error { + // ignore delayed / duplicated version negotiation packets + if c.receivedVersionNegotiationPacket || c.versionNegotiated { + c.logger.Debugf("Received a delayed Version Negotiation Packet.") + return nil + } + + for _, v := range hdr.SupportedVersions { + if v == c.version { + // the version negotiation packet contains the version that we offered + // this might be a packet sent by an attacker (or by a terribly broken server implementation) + // ignore it + return nil + } + } + + c.logger.Infof("Received a Version Negotiation Packet. Supported Versions: %s", hdr.SupportedVersions) + newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, hdr.SupportedVersions) + if !ok { + return qerr.InvalidVersion + } + c.receivedVersionNegotiationPacket = true + c.negotiatedVersions = hdr.SupportedVersions + + // switch to negotiated version + c.initialVersion = c.version + c.version = newVersion + if err := c.generateConnectionIDs(); err != nil { + return err + } + + c.logger.Infof("Switching to QUIC version %s. New connection ID: %s", newVersion, c.destConnID) + c.session.destroy(errCloseSessionForNewVersion) + return nil +} + +func (c *client) handleRetryPacket(hdr *wire.Header) { + c.logger.Debugf("<- Received Retry") + hdr.Log(c.logger) + // A server that performs multiple retries must use a source connection ID of at least 8 bytes. + // Only a server that won't send additional Retries can use shorter connection IDs. + if hdr.OrigDestConnectionID.Len() < protocol.MinConnectionIDLenInitial { + c.logger.Debugf("Received a Retry with a too short Original Destination Connection ID: %d bytes, must have at least %d bytes.", hdr.OrigDestConnectionID.Len(), protocol.MinConnectionIDLenInitial) + return + } + if !hdr.OrigDestConnectionID.Equal(c.destConnID) { + c.logger.Debugf("Received spoofed Retry. Original Destination Connection ID: %s, expected: %s", hdr.OrigDestConnectionID, c.destConnID) + return + } + c.numRetries++ + if c.numRetries > protocol.MaxRetries { + c.session.destroy(qerr.CryptoTooManyRejects) + return + } + c.destConnID = hdr.SrcConnectionID + c.token = hdr.Token + c.session.destroy(errCloseSessionForRetry) +} + +func (c *client) createNewGQUICSession() error { + c.mutex.Lock() + defer c.mutex.Unlock() + runner := &runner{ + onHandshakeCompleteImpl: func(_ Session) { close(c.handshakeChan) }, + removeConnectionIDImpl: c.closeCallback, + } + sess, err := newClientSession( + c.conn, + runner, + c.hostname, + c.version, + c.destConnID, + c.srcConnID, + c.tlsConf, + c.config, + c.initialVersion, + c.negotiatedVersions, + c.logger, + ) + if err != nil { + return err + } + c.session = sess + c.packetHandlers.Add(c.srcConnID, c) + if c.config.RequestConnectionIDOmission { + c.packetHandlers.Add(protocol.ConnectionID{}, c) + } + return nil +} + +func (c *client) createNewTLSSession( + paramsChan <-chan handshake.TransportParameters, + version protocol.VersionNumber, +) error { + c.mutex.Lock() + defer c.mutex.Unlock() + runner := &runner{ + onHandshakeCompleteImpl: func(_ Session) { close(c.handshakeChan) }, + removeConnectionIDImpl: c.closeCallback, + } + sess, err := newTLSClientSession( + c.conn, + runner, + c.token, + c.destConnID, + c.srcConnID, + c.config, + c.mintConf, + paramsChan, + 1, + c.logger, + c.version, + ) + if err != nil { + return err + } + c.session = sess + c.packetHandlers.Add(c.srcConnID, c) + return nil +} + +func (c *client) Close() error { + c.mutex.Lock() + defer c.mutex.Unlock() + if c.session == nil { + return nil + } + return c.session.Close() +} + +func (c *client) destroy(e error) { + c.mutex.Lock() + defer c.mutex.Unlock() + if c.session == nil { + return + } + c.session.destroy(e) +} + +func (c *client) GetVersion() protocol.VersionNumber { + c.mutex.Lock() + v := c.version + c.mutex.Unlock() + return v +} + +func (c *client) GetPerspective() protocol.Perspective { + return protocol.PerspectiveClient +} diff --git a/vendor/lucas-clemente/quic-go/client_test.go b/vendor/lucas-clemente/quic-go/client_test.go new file mode 100644 index 00000000..ef39eec2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/client_test.go @@ -0,0 +1,1030 @@ +package quic + +import ( + "bytes" + "context" + "crypto/tls" + "errors" + "fmt" + "net" + "os" + "time" + + "github.com/bifurcation/mint" + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Client", func() { + var ( + cl *client + packetConn *mockPacketConn + addr net.Addr + connID protocol.ConnectionID + mockMultiplexer *MockMultiplexer + origMultiplexer multiplexer + + supportedVersionsWithoutGQUIC44 []protocol.VersionNumber + + originalClientSessConstructor func(connection, sessionRunner, string, protocol.VersionNumber, protocol.ConnectionID, protocol.ConnectionID, *tls.Config, *Config, protocol.VersionNumber, []protocol.VersionNumber, utils.Logger) (quicSession, error) + ) + + // generate a packet sent by the server that accepts the QUIC version suggested by the client + acceptClientVersionPacket := func(connID protocol.ConnectionID) []byte { + b := &bytes.Buffer{} + err := (&wire.Header{ + DestConnectionID: connID, + PacketNumber: 1, + PacketNumberLen: 1, + }).Write(b, protocol.PerspectiveServer, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + return b.Bytes() + } + + composeVersionNegotiationPacket := func(connID protocol.ConnectionID, versions []protocol.VersionNumber) *receivedPacket { + return &receivedPacket{ + rcvTime: time.Now(), + header: &wire.Header{ + IsVersionNegotiation: true, + DestConnectionID: connID, + SupportedVersions: versions, + }, + } + } + + BeforeEach(func() { + connID = protocol.ConnectionID{0, 0, 0, 0, 0, 0, 0x13, 0x37} + originalClientSessConstructor = newClientSession + Eventually(areSessionsRunning).Should(BeFalse()) + // sess = NewMockQuicSession(mockCtrl) + addr = &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337} + packetConn = newMockPacketConn() + packetConn.addr = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1234} + packetConn.dataReadFrom = addr + cl = &client{ + srcConnID: connID, + destConnID: connID, + version: protocol.SupportedVersions[0], + conn: &conn{pconn: packetConn, currentAddr: addr}, + logger: utils.DefaultLogger, + } + getMultiplexer() // make the sync.Once execute + // replace the clientMuxer. getClientMultiplexer will now return the MockMultiplexer + mockMultiplexer = NewMockMultiplexer(mockCtrl) + origMultiplexer = connMuxer + connMuxer = mockMultiplexer + for _, v := range protocol.SupportedVersions { + if v != protocol.Version44 { + supportedVersionsWithoutGQUIC44 = append(supportedVersionsWithoutGQUIC44, v) + } + } + Expect(supportedVersionsWithoutGQUIC44).ToNot(BeEmpty()) + }) + + AfterEach(func() { + connMuxer = origMultiplexer + newClientSession = originalClientSessConstructor + }) + + AfterEach(func() { + if s, ok := cl.session.(*session); ok { + s.Close() + } + Eventually(areSessionsRunning).Should(BeFalse()) + }) + + Context("Dialing", func() { + var origGenerateConnectionID func(int) (protocol.ConnectionID, error) + var origGenerateConnectionIDForInitial func() (protocol.ConnectionID, error) + + BeforeEach(func() { + origGenerateConnectionID = generateConnectionID + origGenerateConnectionIDForInitial = generateConnectionIDForInitial + generateConnectionID = func(int) (protocol.ConnectionID, error) { + return connID, nil + } + generateConnectionIDForInitial = func() (protocol.ConnectionID, error) { + return connID, nil + } + }) + + AfterEach(func() { + generateConnectionID = origGenerateConnectionID + generateConnectionIDForInitial = origGenerateConnectionIDForInitial + }) + + It("resolves the address", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil) + + if os.Getenv("APPVEYOR") == "True" { + Skip("This test is flaky on AppVeyor.") + } + remoteAddrChan := make(chan string, 1) + newClientSession = func( + conn connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + remoteAddrChan <- conn.RemoteAddr().String() + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run() + return sess, nil + } + _, err := DialAddr("localhost:17890", nil, &Config{HandshakeTimeout: time.Millisecond}) + Expect(err).ToNot(HaveOccurred()) + Eventually(remoteAddrChan).Should(Receive(Equal("127.0.0.1:17890"))) + }) + + It("uses the tls.Config.ServerName as the hostname, if present", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil) + + hostnameChan := make(chan string, 1) + newClientSession = func( + _ connection, + _ sessionRunner, + h string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + hostnameChan <- h + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run() + return sess, nil + } + _, err := DialAddr("localhost:17890", &tls.Config{ServerName: "foobar"}, nil) + Expect(err).ToNot(HaveOccurred()) + Eventually(hostnameChan).Should(Receive(Equal("foobar"))) + }) + + It("returns after the handshake is complete", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + run := make(chan struct{}) + newClientSession = func( + _ connection, + runner sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run().Do(func() { close(run) }) + runner.onHandshakeComplete(sess) + return sess, nil + } + s, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) + Expect(err).ToNot(HaveOccurred()) + Expect(s).ToNot(BeNil()) + Eventually(run).Should(BeClosed()) + }) + + It("refuses to multiplex gQUIC 44", func() { + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: []protocol.VersionNumber{protocol.Version44}}, + ) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Cannot multiplex connections using gQUIC 44")) + }) + + It("returns an error that occurs while waiting for the connection to become secure", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + testErr := errors.New("early handshake error") + newClientSession = func( + conn connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run().Return(testErr) + return sess, nil + } + packetConn.dataToRead <- acceptClientVersionPacket(cl.srcConnID) + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) + Expect(err).To(MatchError(testErr)) + }) + + It("closes the session when the context is canceled", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + sessionRunning := make(chan struct{}) + defer close(sessionRunning) + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run().Do(func() { + <-sessionRunning + }) + newClientSession = func( + conn connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + return sess, nil + } + ctx, cancel := context.WithCancel(context.Background()) + dialed := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := DialContext( + ctx, + packetConn, + addr, + "quic.clemnte.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) + Expect(err).To(MatchError(context.Canceled)) + close(dialed) + }() + Consistently(dialed).ShouldNot(BeClosed()) + sess.EXPECT().Close() + cancel() + Eventually(dialed).Should(BeClosed()) + }) + + It("removes closed sessions from the multiplexer", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(connID, gomock.Any()) + manager.EXPECT().Remove(connID) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + var runner sessionRunner + sess := NewMockQuicSession(mockCtrl) + newClientSession = func( + conn connection, + runnerP sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + runner = runnerP + return sess, nil + } + sess.EXPECT().run().Do(func() { + runner.removeConnectionID(connID) + }) + + _, err := DialContext( + context.Background(), + packetConn, + addr, + "quic.clemnte.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) + Expect(err).ToNot(HaveOccurred()) + }) + + It("closes the connection when it was created by DialAddr", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + + var conn connection + run := make(chan struct{}) + sessionCreated := make(chan struct{}) + sess := NewMockQuicSession(mockCtrl) + newClientSession = func( + connP connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + conn = connP + close(sessionCreated) + return sess, nil + } + sess.EXPECT().run().Do(func() { + <-run + }) + + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := DialAddr("quic.clemente.io:1337", nil, nil) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + + Eventually(sessionCreated).Should(BeClosed()) + + // check that the connection is not closed + Expect(conn.Write([]byte("foobar"))).To(Succeed()) + + close(run) + time.Sleep(50 * time.Millisecond) + // check that the connection is closed + err := conn.Write([]byte("foobar")) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("use of closed network connection")) + + Eventually(done).Should(BeClosed()) + }) + + Context("quic.Config", func() { + It("setups with the right values", func() { + config := &Config{ + HandshakeTimeout: 1337 * time.Minute, + IdleTimeout: 42 * time.Hour, + RequestConnectionIDOmission: true, + MaxIncomingStreams: 1234, + MaxIncomingUniStreams: 4321, + ConnectionIDLength: 13, + Versions: supportedVersionsWithoutGQUIC44, + } + c := populateClientConfig(config, false) + Expect(c.HandshakeTimeout).To(Equal(1337 * time.Minute)) + Expect(c.IdleTimeout).To(Equal(42 * time.Hour)) + Expect(c.RequestConnectionIDOmission).To(BeTrue()) + Expect(c.MaxIncomingStreams).To(Equal(1234)) + Expect(c.MaxIncomingUniStreams).To(Equal(4321)) + Expect(c.ConnectionIDLength).To(Equal(13)) + }) + + It("uses a 0 byte connection IDs if gQUIC 44 is supported", func() { + config := &Config{ + Versions: []protocol.VersionNumber{protocol.Version43, protocol.Version44}, + ConnectionIDLength: 13, + } + c := populateClientConfig(config, false) + Expect(c.Versions).To(Equal([]protocol.VersionNumber{protocol.Version43, protocol.Version44})) + Expect(c.ConnectionIDLength).To(BeZero()) + }) + + It("doesn't use 0-byte connection IDs when dialing an address", func() { + config := &Config{Versions: supportedVersionsWithoutGQUIC44} + c := populateClientConfig(config, false) + Expect(c.ConnectionIDLength).To(Equal(protocol.DefaultConnectionIDLength)) + }) + + It("errors when the Config contains an invalid version", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + version := protocol.VersionNumber(0x1234) + _, err := Dial(packetConn, nil, "localhost:1234", &tls.Config{}, &Config{Versions: []protocol.VersionNumber{version}}) + Expect(err).To(MatchError("0x1234 is not a valid QUIC version")) + }) + + It("disables bidirectional streams", func() { + config := &Config{ + MaxIncomingStreams: -1, + MaxIncomingUniStreams: 4321, + } + c := populateClientConfig(config, false) + Expect(c.MaxIncomingStreams).To(BeZero()) + Expect(c.MaxIncomingUniStreams).To(Equal(4321)) + }) + + It("disables unidirectional streams", func() { + config := &Config{ + MaxIncomingStreams: 1234, + MaxIncomingUniStreams: -1, + } + c := populateClientConfig(config, false) + Expect(c.MaxIncomingStreams).To(Equal(1234)) + Expect(c.MaxIncomingUniStreams).To(BeZero()) + }) + + It("uses 0-byte connection IDs when dialing an address", func() { + config := &Config{} + c := populateClientConfig(config, true) + Expect(c.ConnectionIDLength).To(BeZero()) + }) + + It("fills in default values if options are not set in the Config", func() { + c := populateClientConfig(&Config{}, false) + Expect(c.Versions).To(Equal(protocol.SupportedVersions)) + Expect(c.HandshakeTimeout).To(Equal(protocol.DefaultHandshakeTimeout)) + Expect(c.IdleTimeout).To(Equal(protocol.DefaultIdleTimeout)) + Expect(c.RequestConnectionIDOmission).To(BeFalse()) + }) + }) + + Context("gQUIC", func() { + It("errors if it can't create a session", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + testErr := errors.New("error creating session") + newClientSession = func( + _ connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + return nil, testErr + } + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) + Expect(err).To(MatchError(testErr)) + }) + }) + + Context("IETF QUIC", func() { + It("creates new TLS sessions with the right parameters", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(connID, gomock.Any()) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + config := &Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}} + c := make(chan struct{}) + var cconn connection + var version protocol.VersionNumber + var conf *Config + newTLSClientSession = func( + connP connection, + _ sessionRunner, + tokenP []byte, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + configP *Config, + _ *mint.Config, + paramsChan <-chan handshake.TransportParameters, + _ protocol.PacketNumber, + _ utils.Logger, + versionP protocol.VersionNumber, + ) (quicSession, error) { + cconn = connP + version = versionP + conf = configP + close(c) + // TODO: check connection IDs? + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run() + return sess, nil + } + _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config) + Expect(err).ToNot(HaveOccurred()) + Eventually(c).Should(BeClosed()) + Expect(cconn.(*conn).pconn).To(Equal(packetConn)) + Expect(version).To(Equal(config.Versions[0])) + Expect(conf.Versions).To(Equal(config.Versions)) + }) + + It("creates a new session when the server performs a retry", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()).Do(func(id protocol.ConnectionID, handler packetHandler) { + go handler.handlePacket(&receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeRetry, + Token: []byte("foobar"), + DestConnectionID: id, + OrigDestConnectionID: connID, + }, + }) + }) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + config := &Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}} + cl.config = config + run1 := make(chan error) + sess1 := NewMockQuicSession(mockCtrl) + sess1.EXPECT().run().DoAndReturn(func() error { + return <-run1 + }) + sess1.EXPECT().destroy(errCloseSessionForRetry).Do(func(e error) { + run1 <- e + }) + sess2 := NewMockQuicSession(mockCtrl) + sess2.EXPECT().run() + sessions := make(chan quicSession, 2) + sessions <- sess1 + sessions <- sess2 + newTLSClientSession = func( + _ connection, + _ sessionRunner, + _ []byte, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *Config, + _ *mint.Config, + _ <-chan handshake.TransportParameters, + _ protocol.PacketNumber, + _ utils.Logger, + _ protocol.VersionNumber, + ) (quicSession, error) { + return <-sessions, nil + } + _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config) + Expect(err).ToNot(HaveOccurred()) + Expect(sessions).To(BeEmpty()) + }) + + It("only accepts 3 retries", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()).Do(func(id protocol.ConnectionID, handler packetHandler) { + go handler.handlePacket(&receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeRetry, + Token: []byte("foobar"), + SrcConnectionID: connID, + DestConnectionID: id, + OrigDestConnectionID: connID, + Version: protocol.VersionTLS, + }, + }) + }).AnyTimes() + manager.EXPECT().Add(gomock.Any(), gomock.Any()).AnyTimes() + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + config := &Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}} + cl.config = config + + sessions := make(chan quicSession, protocol.MaxRetries+1) + for i := 0; i < protocol.MaxRetries+1; i++ { + run := make(chan error) + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run().DoAndReturn(func() error { + return <-run + }) + sess.EXPECT().destroy(gomock.Any()).Do(func(e error) { + run <- e + }) + sessions <- sess + } + + newTLSClientSession = func( + _ connection, + _ sessionRunner, + _ []byte, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *Config, + _ *mint.Config, + _ <-chan handshake.TransportParameters, + _ protocol.PacketNumber, + _ utils.Logger, + _ protocol.VersionNumber, + ) (quicSession, error) { + return <-sessions, nil + } + _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config) + Expect(err).To(HaveOccurred()) + Expect(err.(qerr.ErrorCode)).To(Equal(qerr.CryptoTooManyRejects)) + Expect(sessions).To(BeEmpty()) + }) + }) + + Context("version negotiation", func() { + var origSupportedVersions []protocol.VersionNumber + + BeforeEach(func() { + origSupportedVersions = protocol.SupportedVersions + protocol.SupportedVersions = append(protocol.SupportedVersions, []protocol.VersionNumber{77, 78}...) + }) + + AfterEach(func() { + protocol.SupportedVersions = origSupportedVersions + }) + + It("returns an error that occurs during version negotiation", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(connID, gomock.Any()) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + testErr := errors.New("early handshake error") + newClientSession = func( + conn connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + Expect(conn.Write([]byte("0 fake CHLO"))).To(Succeed()) + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run().Return(testErr) + return sess, nil + } + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) + Expect(err).To(MatchError(testErr)) + }) + + It("recognizes that a packet without VersionFlag means that the server accepted the suggested version", func() { + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().handlePacket(gomock.Any()) + cl.session = sess + cl.config = &Config{} + ph := &wire.Header{ + PacketNumber: 1, + PacketNumberLen: protocol.PacketNumberLen2, + DestConnectionID: connID, + SrcConnectionID: connID, + } + err := cl.handlePacketImpl(&receivedPacket{header: ph}) + Expect(err).ToNot(HaveOccurred()) + Expect(cl.versionNegotiated).To(BeTrue()) + }) + + It("changes the version after receiving a Version Negotiation Packet", func() { + phm := NewMockPacketHandlerManager(mockCtrl) + phm.EXPECT().Add(connID, gomock.Any()).Times(2) + cl.packetHandlers = phm + + version1 := protocol.Version39 + version2 := protocol.Version39 + 1 + Expect(version2.UsesTLS()).To(BeFalse()) + sess1 := NewMockQuicSession(mockCtrl) + run1 := make(chan struct{}) + sess1.EXPECT().run().Do(func() { <-run1 }).Return(errCloseSessionForNewVersion) + sess1.EXPECT().destroy(errCloseSessionForNewVersion).Do(func(error) { close(run1) }) + sess2 := NewMockQuicSession(mockCtrl) + sess2.EXPECT().run() + sessionChan := make(chan *MockQuicSession, 2) + sessionChan <- sess1 + sessionChan <- sess2 + newClientSession = func( + _ connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + return <-sessionChan, nil + } + + cl.config = &Config{Versions: []protocol.VersionNumber{version1, version2}} + dialed := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cl.dial(context.Background()) + Expect(err).ToNot(HaveOccurred()) + close(dialed) + }() + Eventually(sessionChan).Should(HaveLen(1)) + cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{version2})) + Eventually(sessionChan).Should(BeEmpty()) + }) + + It("only accepts one version negotiation packet", func() { + phm := NewMockPacketHandlerManager(mockCtrl) + phm.EXPECT().Add(connID, gomock.Any()).Times(2) + cl.packetHandlers = phm + version1 := protocol.Version39 + version2 := protocol.Version39 + 1 + version3 := protocol.Version39 + 2 + Expect(version2.UsesTLS()).To(BeFalse()) + Expect(version3.UsesTLS()).To(BeFalse()) + sess1 := NewMockQuicSession(mockCtrl) + run1 := make(chan struct{}) + sess1.EXPECT().run().Do(func() { <-run1 }).Return(errCloseSessionForNewVersion) + sess1.EXPECT().destroy(errCloseSessionForNewVersion).Do(func(error) { close(run1) }) + sess2 := NewMockQuicSession(mockCtrl) + sess2.EXPECT().run() + sessionChan := make(chan *MockQuicSession, 2) + sessionChan <- sess1 + sessionChan <- sess2 + newClientSession = func( + _ connection, + _ sessionRunner, + _ string, + _ protocol.VersionNumber, + _ protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + _ *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + return <-sessionChan, nil + } + + cl.config = &Config{Versions: []protocol.VersionNumber{version1, version2, version3}} + dialed := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cl.dial(context.Background()) + Expect(err).ToNot(HaveOccurred()) + close(dialed) + }() + Eventually(sessionChan).Should(HaveLen(1)) + cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{version2})) + Eventually(sessionChan).Should(BeEmpty()) + Expect(cl.version).To(Equal(version2)) + cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{version3})) + Eventually(dialed).Should(BeClosed()) + Expect(cl.version).To(Equal(version2)) + }) + + It("errors if no matching version is found", func() { + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().destroy(qerr.InvalidVersion) + cl.session = sess + cl.config = &Config{Versions: protocol.SupportedVersions} + cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{1})) + }) + + It("errors if the version is supported by quic-go, but disabled by the quic.Config", func() { + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().destroy(qerr.InvalidVersion) + cl.session = sess + v := protocol.VersionNumber(1234) + Expect(v).ToNot(Equal(cl.version)) + cl.config = &Config{Versions: protocol.SupportedVersions} + cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{v})) + }) + + It("changes to the version preferred by the quic.Config", func() { + phm := NewMockPacketHandlerManager(mockCtrl) + cl.packetHandlers = phm + + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().destroy(errCloseSessionForNewVersion) + cl.session = sess + versions := []protocol.VersionNumber{1234, 4321} + cl.config = &Config{Versions: versions} + cl.handlePacket(composeVersionNegotiationPacket(connID, versions)) + Expect(cl.version).To(Equal(protocol.VersionNumber(1234))) + }) + + It("drops version negotiation packets that contain the offered version", func() { + cl.config = &Config{} + ver := cl.version + cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{ver})) + Expect(cl.version).To(Equal(ver)) + }) + }) + }) + + It("tells its version", func() { + Expect(cl.version).ToNot(BeZero()) + Expect(cl.GetVersion()).To(Equal(cl.version)) + }) + + It("ignores packets with the wrong Long Header Type", func() { + cl.config = &Config{} + hdr := &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeInitial, + PayloadLen: 123, + SrcConnectionID: connID, + DestConnectionID: connID, + PacketNumberLen: protocol.PacketNumberLen1, + Version: versionIETFFrames, + } + err := cl.handlePacketImpl(&receivedPacket{ + remoteAddr: addr, + header: hdr, + data: make([]byte, 456), + }) + Expect(err).To(MatchError("Received unsupported packet type: Initial")) + }) + + It("ignores packets without connection id, if it didn't request connection id trunctation", func() { + cl.version = versionGQUICFrames + cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any handlePacket calls + cl.config = &Config{RequestConnectionIDOmission: false} + hdr := &wire.Header{ + IsPublicHeader: true, + PacketNumber: 1, + PacketNumberLen: 1, + } + err := cl.handlePacketImpl(&receivedPacket{ + remoteAddr: addr, + header: hdr, + }) + Expect(err).To(MatchError("received packet with truncated connection ID, but didn't request truncation")) + }) + + It("ignores packets with the wrong destination connection ID", func() { + cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any handlePacket calls + cl.version = versionIETFFrames + cl.config = &Config{RequestConnectionIDOmission: false} + connID2 := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + Expect(connID).ToNot(Equal(connID2)) + hdr := &wire.Header{ + DestConnectionID: connID2, + SrcConnectionID: connID, + PacketNumber: 1, + PacketNumberLen: protocol.PacketNumberLen1, + Version: versionIETFFrames, + } + err := cl.handlePacketImpl(&receivedPacket{ + remoteAddr: addr, + header: hdr, + }) + Expect(err).To(MatchError(fmt.Sprintf("received a packet with an unexpected connection ID (0x0807060504030201, expected %s)", connID))) + }) + + It("creates new gQUIC sessions with the right parameters", func() { + manager := NewMockPacketHandlerManager(mockCtrl) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) + mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) + + c := make(chan struct{}) + var cconn connection + var hostname string + var version protocol.VersionNumber + var conf *Config + newClientSession = func( + connP connection, + _ sessionRunner, + hostnameP string, + versionP protocol.VersionNumber, + connIDP protocol.ConnectionID, + _ protocol.ConnectionID, + _ *tls.Config, + configP *Config, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (quicSession, error) { + cconn = connP + hostname = hostnameP + version = versionP + conf = configP + connID = connIDP + close(c) + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().run() + return sess, nil + } + + config := &Config{Versions: supportedVersionsWithoutGQUIC44} + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + config, + ) + Expect(err).ToNot(HaveOccurred()) + Eventually(c).Should(BeClosed()) + Expect(cconn.(*conn).pconn).To(Equal(packetConn)) + Expect(hostname).To(Equal("quic.clemente.io")) + Expect(version).To(Equal(config.Versions[0])) + Expect(conf.Versions).To(Equal(config.Versions)) + }) + + Context("Public Reset handling", func() { + var ( + pr []byte + hdr *wire.Header + hdrLen int + ) + + BeforeEach(func() { + cl.config = &Config{} + + pr = wire.WritePublicReset(cl.destConnID, 1, 0) + r := bytes.NewReader(pr) + iHdr, err := wire.ParseInvariantHeader(r, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err = iHdr.Parse(r, protocol.PerspectiveServer, versionGQUICFrames) + Expect(err).ToNot(HaveOccurred()) + hdrLen = r.Len() + }) + + It("closes the session when receiving a Public Reset", func() { + cl.version = versionGQUICFrames + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().closeRemote(gomock.Any()).Do(func(err error) { + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.PublicReset)) + }) + cl.session = sess + cl.handlePacketImpl(&receivedPacket{ + remoteAddr: addr, + header: hdr, + data: pr[len(pr)-hdrLen:], + }) + }) + + It("ignores Public Resets from the wrong remote address", func() { + cl.version = versionGQUICFrames + cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls + spoofedAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 5678} + err := cl.handlePacketImpl(&receivedPacket{ + remoteAddr: spoofedAddr, + header: hdr, + data: pr[len(pr)-hdrLen:], + }) + Expect(err).To(MatchError("Received a spoofed Public Reset")) + }) + + It("ignores unparseable Public Resets", func() { + cl.version = versionGQUICFrames + cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls + err := cl.handlePacketImpl(&receivedPacket{ + remoteAddr: addr, + header: hdr, + data: pr[len(pr)-hdrLen : len(pr)-5], // cut off the last 5 bytes + }) + Expect(err.Error()).To(ContainSubstring("Received a Public Reset. An error occurred parsing the packet")) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/codecov.yml b/vendor/lucas-clemente/quic-go/codecov.yml new file mode 100644 index 00000000..f077c1ad --- /dev/null +++ b/vendor/lucas-clemente/quic-go/codecov.yml @@ -0,0 +1,18 @@ +coverage: + round: nearest + ignore: + - streams_map_incoming_bidi.go + - streams_map_incoming_uni.go + - streams_map_outgoing_bidi.go + - streams_map_outgoing_uni.go + - h2quic/gzipreader.go + - h2quic/response.go + - internal/ackhandler/packet_linkedlist.go + - internal/utils/byteinterval_linkedlist.go + - internal/utils/packetinterval_linkedlist.go + - internal/utils/linkedlist/linkedlist.go + status: + project: + default: + threshold: 0.5 + patch: false diff --git a/vendor/lucas-clemente/quic-go/conn.go b/vendor/lucas-clemente/quic-go/conn.go new file mode 100644 index 00000000..700c1471 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/conn.go @@ -0,0 +1,54 @@ +package quic + +import ( + "net" + "sync" +) + +type connection interface { + Write([]byte) error + Read([]byte) (int, net.Addr, error) + Close() error + LocalAddr() net.Addr + RemoteAddr() net.Addr + SetCurrentRemoteAddr(net.Addr) +} + +type conn struct { + mutex sync.RWMutex + + pconn net.PacketConn + currentAddr net.Addr +} + +var _ connection = &conn{} + +func (c *conn) Write(p []byte) error { + _, err := c.pconn.WriteTo(p, c.currentAddr) + return err +} + +func (c *conn) Read(p []byte) (int, net.Addr, error) { + return c.pconn.ReadFrom(p) +} + +func (c *conn) SetCurrentRemoteAddr(addr net.Addr) { + c.mutex.Lock() + c.currentAddr = addr + c.mutex.Unlock() +} + +func (c *conn) LocalAddr() net.Addr { + return c.pconn.LocalAddr() +} + +func (c *conn) RemoteAddr() net.Addr { + c.mutex.RLock() + addr := c.currentAddr + c.mutex.RUnlock() + return addr +} + +func (c *conn) Close() error { + return c.pconn.Close() +} diff --git a/vendor/lucas-clemente/quic-go/conn_test.go b/vendor/lucas-clemente/quic-go/conn_test.go new file mode 100644 index 00000000..f7e00cac --- /dev/null +++ b/vendor/lucas-clemente/quic-go/conn_test.go @@ -0,0 +1,119 @@ +package quic + +import ( + "bytes" + "errors" + "net" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockPacketConn struct { + addr net.Addr + dataToRead chan []byte + dataReadFrom net.Addr + readErr error + dataWritten bytes.Buffer + dataWrittenTo net.Addr + closed bool +} + +func newMockPacketConn() *mockPacketConn { + return &mockPacketConn{ + dataToRead: make(chan []byte, 1000), + } +} + +func (c *mockPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { + if c.readErr != nil { + return 0, nil, c.readErr + } + data, ok := <-c.dataToRead + if !ok { + return 0, nil, errors.New("connection closed") + } + n := copy(b, data) + return n, c.dataReadFrom, nil +} +func (c *mockPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + c.dataWrittenTo = addr + return c.dataWritten.Write(b) +} +func (c *mockPacketConn) Close() error { + if !c.closed { + close(c.dataToRead) + } + c.closed = true + return nil +} +func (c *mockPacketConn) LocalAddr() net.Addr { return c.addr } +func (c *mockPacketConn) SetDeadline(t time.Time) error { panic("not implemented") } +func (c *mockPacketConn) SetReadDeadline(t time.Time) error { panic("not implemented") } +func (c *mockPacketConn) SetWriteDeadline(t time.Time) error { panic("not implemented") } + +var _ net.PacketConn = &mockPacketConn{} + +var _ = Describe("Connection", func() { + var c *conn + var packetConn *mockPacketConn + + BeforeEach(func() { + addr := &net.UDPAddr{ + IP: net.IPv4(192, 168, 100, 200), + Port: 1337, + } + packetConn = newMockPacketConn() + c = &conn{ + currentAddr: addr, + pconn: packetConn, + } + }) + + It("writes", func() { + err := c.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + Expect(packetConn.dataWritten.Bytes()).To(Equal([]byte("foobar"))) + Expect(packetConn.dataWrittenTo.String()).To(Equal("192.168.100.200:1337")) + }) + + It("reads", func() { + packetConn.dataToRead <- []byte("foo") + packetConn.dataReadFrom = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1336} + p := make([]byte, 10) + n, raddr, err := c.Read(p) + Expect(err).ToNot(HaveOccurred()) + Expect(raddr.String()).To(Equal("127.0.0.1:1336")) + Expect(n).To(Equal(3)) + Expect(p[0:3]).To(Equal([]byte("foo"))) + }) + + It("gets the remote address", func() { + Expect(c.RemoteAddr().String()).To(Equal("192.168.100.200:1337")) + }) + + It("gets the local address", func() { + addr := &net.UDPAddr{ + IP: net.IPv4(192, 168, 0, 1), + Port: 1234, + } + packetConn.addr = addr + Expect(c.LocalAddr()).To(Equal(addr)) + }) + + It("changes the remote address", func() { + addr := &net.UDPAddr{ + IP: net.IPv4(127, 0, 0, 1), + Port: 7331, + } + c.SetCurrentRemoteAddr(addr) + Expect(c.RemoteAddr().String()).To(Equal(addr.String())) + }) + + It("closes", func() { + err := c.Close() + Expect(err).ToNot(HaveOccurred()) + Expect(packetConn.closed).To(BeTrue()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/crypto_stream.go b/vendor/lucas-clemente/quic-go/crypto_stream.go new file mode 100644 index 00000000..a5ec4ecf --- /dev/null +++ b/vendor/lucas-clemente/quic-go/crypto_stream.go @@ -0,0 +1,41 @@ +package quic + +import ( + "io" + + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type cryptoStream interface { + StreamID() protocol.StreamID + io.Reader + io.Writer + handleStreamFrame(*wire.StreamFrame) error + popStreamFrame(protocol.ByteCount) (*wire.StreamFrame, bool) + closeForShutdown(error) + setReadOffset(protocol.ByteCount) + // methods needed for flow control + getWindowUpdate() protocol.ByteCount + handleMaxStreamDataFrame(*wire.MaxStreamDataFrame) +} + +type cryptoStreamImpl struct { + *stream +} + +var _ cryptoStream = &cryptoStreamImpl{} + +func newCryptoStream(sender streamSender, flowController flowcontrol.StreamFlowController, version protocol.VersionNumber) cryptoStream { + str := newStream(version.CryptoStreamID(), sender, flowController, version) + return &cryptoStreamImpl{str} +} + +// SetReadOffset sets the read offset. +// It is only needed for the crypto stream. +// It must not be called concurrently with any other stream methods, especially Read and Write. +func (s *cryptoStreamImpl) setReadOffset(offset protocol.ByteCount) { + s.receiveStream.readOffset = offset + s.receiveStream.frameQueue.readPos = offset +} diff --git a/vendor/lucas-clemente/quic-go/crypto_stream_test.go b/vendor/lucas-clemente/quic-go/crypto_stream_test.go new file mode 100644 index 00000000..ce97e94a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/crypto_stream_test.go @@ -0,0 +1,26 @@ +package quic + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Crypto Stream", func() { + var ( + str *cryptoStreamImpl + mockSender *MockStreamSender + ) + + BeforeEach(func() { + mockSender = NewMockStreamSender(mockCtrl) + str = newCryptoStream(mockSender, nil, protocol.VersionWhatever).(*cryptoStreamImpl) + }) + + It("sets the read offset", func() { + str.setReadOffset(0x42) + Expect(str.receiveStream.readOffset).To(Equal(protocol.ByteCount(0x42))) + Expect(str.receiveStream.frameQueue.readPos).To(Equal(protocol.ByteCount(0x42))) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/docs/quic.png b/vendor/lucas-clemente/quic-go/docs/quic.png new file mode 100644 index 0000000000000000000000000000000000000000..c8cccab34adb9a3571829bab6510c8a1994e1e0e GIT binary patch literal 17299 zcmYLx1yoeu*Y?oe(w)*FE#2KI-JJq5bax|2Hw<0UNT(tp-K}(Y3E$QK&-a_fI_u88 zXZG1==d<@2CQ4OV1`U}A83Y2M$;nEpgFw(m!1Wy>JTMA9?iqkU5_)oyVwzy6qdAz- z1yus+&BbQN<^TT1Y=8@%uAIfkILA}D+%l(A$3rQGk`#6MzXLyO_t&t@y_-}gf z5g4yU@}0uF?hMQQrHQGQeY2>_na^d5Zdn)s&;EMk_^Oy>Nf@wVk^@qV#S*@uGN4wE zO?J{9=u%bG09h{?gA{QL=6?Q;u(lp1k|E|sF=5F-`(j{czxt^ctovM(L<3aDM;ri7PJi6lXo{u7}&o1-Dt?I^~&<7Em zA@9zC5==mt>;|D2B9-sjG3ubVt@X;K?5oda;64?tyC}@IriRI7_H}@-A1d8eL+S5Q zpO4p_yCdPutbY#s=Dh)jc*Uo;yG!!susw~qc~j+ATd8TT>CwbSfJ zIS6Ooxhe1?I3g48 zPFeOmwlat3>ldH2hOh=~AR~H$bR2A<>%Fk9niJq1c_XEWJ$hHtTKle0dTQ4Rv*oYO zSacMFa-CCKN!3|dKfdEDOAf~9&b1B(7tZ_6K$4|t+_$BMVq)>5V&_XA?(a*L z5RQ3|8)n?2xD~>^OCHZ}`Nd%L5!;XW%YVMzGD9#mKHS#mSyY8YC}Jiw<*`*OffLWE z{*aIyVhX#iyPpoO5!UbUnqzMKJ1G*OH*_Q~E~J=2oo@vm&Av0w zimwx&Pn_;a*`6gHv#)XRL~h!cRf2n6Vkm}UTZ(GCBplUQT6YRIo%C3|f1|`+NuD%! za`B2y`7(MrfJo<})ydl{V_zMTkiK+*T7DrI$U?0lFZ}Q+oB@U0qvETNfrlB*wxnC}0_JIxcI_^^UF! z+z<~%Xdl~QP;R#Ow(E8?^1okSR#$F0d#U0iF3(-dFm*+2DjsZef9 zC7zFrH&Vvii{QxGXpo4UHt9W4;%cBK2=wT}Xbe@}@P6#D6@E6;`?g;1#kKx1wH$-o z&>Qmb)G%Llcx9Awz^l3P%&Fywc5#_sC+PHc6%|=Jg!TL`thgS$*~16vW)VJ}wCKPV zwCIR@uSh{D5*Mj-G<&LaTpQrJ>Uq9k=^P90+!(8`ybPbNPc?zuX4Ehc9lxI~UP(`w z`&MC4ovWCY9lIvD<$AxG0~=`7*!pV%&OcagTUB_G0Mgyz&;^~2>{7Inf`KN(5%%$% z>MJcmMi3*C-mrxHcUqCN0-HS(#fHx2b{H z#- zI95StTt9Q|TxGLZrs6wI7D@dcO_tnHPyC&*XOq-u_Y+%Q^}?$_&w=Al_Q`h~ekR#O zIBwF=4ZESJwDJ<|UrFu~`2-gD6=~Z-;87YQRGfzp^w@X)M<>f2MnoAs*|&X)Y`xe(R!A~l;K65J4dj*)9t4Ko&htdYjAeS>f&uXxTR zi?ZuA-z}5xWM8iZ|L7Z}@G?nkI4xHg`d$gJ@D+?TIH>Iv2N|1RZ&-Miu^Dp6xVgkm zxl_g_b9P;iKK#^e`GxnE_Ol(!c|(z+oTXhNdXxYngR1P;8un83teb6;rc{h!TS$lA z6NGfSTidXq_}fQ`nuoZ8olx?8AXA~A;-Xupk=?Pz8!SEMI%i-fonH`HbRfPl8gTzj zwkZ<7T)jS~Gy1NJqS_Mr5Fr+pgQanc2=C;_7(pgczoxv~M=nL{0XEj#aTh;XCHZnr ztIu0di=!z#P@P}Nz}{n26>}E-c`_?q#@s^z5pfc6>%6H99DidXAzPoltAeNGrKRhu zN%}5v4$A4lWGSZ?0qFZUx?V+BJLH_~s!eg+{i*5b2n%UwU(wG#L@i0oT8!BbsqM~& zx4EBNB)!NqsNNVE1;yfv4aLycQ26f+y(lta^QYhF@iC?8xqZ~$N}I{P3z30T_SQC3 z^ChV?g(_f9qbIzr*=395XH&n$u)jfWJh6Eir?lwkfd9+cd7JL(uY#TB+!B z^lva7icwY8f>`5~jCsx(h@qN9Cvh2uaUls$cGEaY^6a_Z6<);$0 zBOATG82(pkvG@g{%y^apxn?89SSRYy`?)dpUy?lizE#OhNxXaxWX6K%u;U$0sz?Pc zbB$q15*RS%eO*Z#PuP;gOd?%3v_w9D%0)%_jS-}tG^@2>>`1MRi+7Zz~Z zi5c>Y1?77I4r3oL3AY4YO9)0%S-Xg`hH1NYTXrASXU^5s&LNxJx@xh5v)Gq=<_<6e z>X1kC)Fj`5)~EltG-beHkst5iOB<%yYzH+2Nu$X*TUKQjN#W zb^D^e^Y*pr&^Hmo{B5nodt~uioOzP9Tj=Vyk;^Z#|LLW!u?tafMpNMtABQ&M857#N zzj~w&q#3<&wS&FSOJ29+E@aMFhIMjQb96oAEm#_M*Du4@aqB#$OYh_p_>U!|Bt;cL z-!xV&YH<>Pts|12T$f<5CIij9zJ3v>30 zm_WNR^xnwdM;WY63ZxlelOGsdU^ zj?~L)287e_&G{MW)_0e~*P@)CqfER%>d+!`Vf zPQ0szr%w!NJG69r0u$I;-%|GbI@pA@Xp1%#r8Cc<#p+5E6EW$HI`}lJ^>8z}Y@x@p zcq5Q;8Aans_$e&qOUGJOIIkmV6&$|5@$0!_nzrgq60!CkKpP-@2C`~Pdf$rfuU4HM z|6)|6FyApfiFvohI@s|x!9HP!)91p~2`nd`rh$Y!3HfGO z>quP^mV6XUxmJJ}DQ1{`+xlF4?;0!whkzi_8w^)qHJ16KLW`-)xLf!EetF{Q_is|e z<@qNAYOcYbm@xdr%DKB2aM`=nJAf{5AwR=yKbH?3CpY9zpp(Asx!RxJ>%m_90n z(sb*T2Y~8{=gA?l__Nvy2izKtC^y}aS$K=)3%xR#eZH6_GdcU^=dGWu#*l@)uL9fL zcKcSpc=i%b<{OhmG8EsphZ9Vn?#?j@32j$ynIQE>j1^1+jkAkQvZ;)?KPU3YFMfST zc=y>NC_kU#?DCS6GfYpyZPX&;F}c&q(6jVYZDA1IAGQJBTczG$ln!cveKt?C8tbK&3N`lqRd?YmQFMe&_oo}1a zmMZ7;eWu%PtJb*REe^6Fc#|3x3{*nI#I)w)ACDw7G(4-fBoaByrI*pP215`q^8Frf zhRpeUQjB`(=SjB_*KXGXFm6v)Vct2dv_b)Lim0n&_mL%V z8^ay?U%1^w_ZRHOrqPn3YBFg*_ZdlHfZ?+pOJ)Y)a8pr?te##ju^Guq-u#VO7=p`iy2!)>TJ~aYyDC8CWwDD6!zSf zQ8X+fqJJ<3zn54s=PhpXb8Qgc_g6NX#@;FeL`@084_~LS1bqpt#p|LNOd***APQ$gNxR0tmbuH=O3nL8*%P8!Pv*dE_|KNZs_S2y>r$2 zan!~V++Lq!np|7oZtYK(ZlK|@=vnywz(-Q5y!=+>g8CI33M;j8`OzU^VJ+&PO7R@i zMb(Y%cfQenx_HH+mx2LXW)1Y>_|R<1N^fki`utr*w-ZF3LB>BSb=c0c;|ufDa_mGD zcooRX@Y!0It6!=V(pWbXTxN?ljd5scI8{IFt%vkizdS#(fj>6c&lBmGJ~5N5tD`7h zk}LkcCgJ*%dB>u{a{zIiS8Y4K|SH)iz~g#>k5F=MdUR}hEK<#?3NM8$dz{{ zRr)RHzTW_|h*OBa_O1=VzCD7=t9bRd&;)|l*LvfNwH24`=ag9lnX}IDddV(Wm>+|8 z)Qe7U-zc>I~8m&lC?zu|8A_93?+nX%v9o|62l$MIxP1fg> zNz~=-40!QZjeY_R(Nv3vY9~p#qNWFPB_QqziFpT4-5BK`|xc=UX z89Ksp(5<{blsU$e!JwpZCn19vI|>c4{dNaXEx!sOc24uP4(OW!a*6AAu8?&_^1)@A2=7C7->3EoEgS0|9&p@=xC*sm4=nhh_ zyWVD2D-0D%O9&_%fP+!FH?H^=N~UvSL;1HXB4iWK^e~bwcOD5q2x&Tw$21L)s^69y z&*tC!a@wVVS9V~*zM(P3FEv=FnPfj-gLEny5_*R^J6+|rGm3S~Z>%wZkc=^|uPE#E z+nWFVPf%)pIg@&EWQI9syk-<3X>A6y!P6mC__t=ZS(C3-y7@MmdBT3N7({OaT(d3| zzqVlCo;eE||8wAFix~t`8qIf{Q445R=Uamm!HYV4;y)cQx6ZeR^RbVVw}+scg&&%M z-19+IdfUK!I9^M*mHNgvUg^8Z3-&X6+O4+G3=oQy$f<99uo>QcE_S7bP)F}AH#x29 zd91)$<+cgplRUiYAxqlYUCl_Or%P0&{Gwg8_xHPbQ1{pK#yMoW@uUI+_vRYZMrIWIKfiqx!~On=#qBUNjY$XH9i4=a!kS71m3ztb_kjzmSVd@AGC^Hhed7tNfhIY~+b zA$gSsj&%)0B@ex#CpES2navIvOmV)EZHbLEF9NJWTn1Z2ioX#{(Ymb3YYn|3;R_mm#gIW{kDyBHy0X}rz4$nBUxoqjK9eD4H{6I z1#T64Ck13sNQ9&I^fr2yJ|baY4Bw{lZS85wM98bszuNhRS;X-csaFYK4n$_3G(qRY<98hE1aGa6A(md1j&bVhXe;-`H4(se@wackS?NyFMFGF-Ro`BdA(jJ z6(dTUK2CA;rQV8TnuaVpz)Qk``uN&0lgAO6vCaQ?`}7La%-Lpt&aV)z*=(E&=PZ!` z|6ftvcWhV&C6QLhXhr7+R|r=C+|B27*$}mM#Z>!*=bQYeFBkPEA<3;pP-eoKy~eFN zoh9UPNT22_xxd`~gZIy0mY-V~f#Q$q#HVv7lh!OJjR5_Gi%i0A0EbA73tYG^SN?8P zDhk0m!YWS`q9bSyqXS2;;$5rXQggn*em(c;EmN?EiH*(5kqTJ73`fI`>fF1n{p7Uc z5*;xz$m@k&>P^%ghfrE;OU^$HiDHnD$=?g{L zdS071nATYD(kxe}2)sA=pu<;4*!Pw_cc8Z8CeyynienQ9&XPFQI0O5fzmOWh(<0Az z=Gj|~I>zB~JY&k7(Z2n~zSpq9O5!l=r&@oYw@;-~*oTUn|F%ZFb&KMDK=v552yOvO=CdnijiwhP?i-dgQYR z`zf?n;5B4|&ndsaOstQ*$>{IYIuil|pB(k{Y)170AkN-2lblS-#7-bH7-D0@XY4(x z`VB%O>riZcR&fr2z&&ap4aX0^V*K(RF68isj6z3++?_=`I8CK#~S~;oVL>Gua#lGF_KjNcId3NoH1#Z zMnE!ihTFQwtN~Hn;`h)0#v$S0A2(gL25Ub|MMX7m**ajI%=}vOV)I^;Q$^+6lbFlK z{}NpI_Fg{}K(>w0OQPAQY1lz=)T_UG2-nnG)V*O;|kuIuF;3fr#S zm`u78;%?Zx?A9`+RM&w>I@e9o1BN^)by!|(>=DMc+JM2+UUrRa;^xm3eluliX76ii zI2565x>jsXT_VaOa%NFALLKXjQy%s;o&zIoZ=UqDXGSOWw#Y>OrV(IRuq^p`%~odT zN|G5-u2CAy+v>I(@47>qSstEKR*~2G4I0P0XC{oHfdjr=G77uy{V(}CWCPzo>C{_C zJP*C5eeteTuuJY`s{fmx`1)j#y|xY36GL@c`-tIK)Y1!_1_2lD4~^b&pF+=|5Z{C* zkH2aWlW@O2&{BovfgVPf0AtwM?=Vn$o%~;U3*)Ofq||9456S-;kZjWhk4g|&q$Yn! zhsJF$SqRw~K!;rt;^Ifgw=%*?6(ku;dDEHJ zcb8aY-N)A^eIyA$FT?Z^q(6TS)ONk(0Z#?BciOAURPT^EwSw zsWM*-OTjnWenY?@TYzV7c33n!oLB)GYltW)ZjH5JPM1Bx!(c&=f)W6atGKd5>xRY1k;yd-osfNHk%w(pSIkSJR}s%CbIzpCBDtYY=*J;YmCpK(!$ z{=%!xyRup!?c$mDDtrr%Z2fUP=Uuzb8~ky_>D8=L-bllblEU&kHXxlVPRqAwPf#W>>HMkH9Nqr#_OFUZj*(t_Oa(X zvqSLvdt*ZIx7*fJLZhgh=@B1$a1uMBCYd}ugBBKaoA6AN+8*pE$%~{G*$MIRo%pKe z@Zu2i~7jb_H9ysQ;wzitkUj>^GU_|t?ZN6`X$&J|EP;N!`M;Y$> zR2Rz*ss{F>NkCvtT~Pn9M4ghAm>s?+lSsotK%%&`OZj89o~ik~%{}ts%p43#E>7EI zHdg8R>a>53NcMAM(B*7vW3cs%mTA!pd2D~I=(qvgnR^yWH zH#e`?6ifM3Z4ni%da}sI#Y{0%x=u3K)n6^i>~sLO)Q%{$utkGp{3s;TLS~{~$1+)* zvb@SG_lQITT9qXQXLMzV`n~loAx=L}a-9?+HP}(c!-Y)70&K?HQU^SYH~+EXqWqpW zQ1tv%?UgXX$4$Fde5*sdNft2tNifPrX&nb@n2}h#jh#+P_sXG}O@a7D6W-8#jretL z*@>F7+VZfeSSK7Z=iW7i?59=+PZKDKaMmxKNJP8XG-GL5b0yUx=%ra-x{6V{M+;Sw zjY_BrC=>Vw31k`kmZtLV?s08@m#=<5cOva;-&YfWK@6m%axO=b>l6QHkGL_-xwlxW zl(7-+EYZ!26$jR-W{d(hE(td&+|D#P2E1Xp)yBV*9<5Tiv;DJwXjISZG)(Qsq_ApI zvn~~_X;_XTdFEs2 zaTgGAU|H0|dZW92VwP938&+FaMsl|q1Sd?$D(%bPDf?log!g?7W|zfg{KsOdd?HOY z+Y_uH7v4ek^Ynr7?^3%THBv=F2R|MLnh!Clm)!mKX5-3?k7z4;j((hSWPR7ahC5s3 z<$*dizBZ>AzRFKw=*Q$N4*9_@1Y^JW6tSgp@%UFhdj$pJTAIz}(*H5H1Te??1RF8C zBvt7*YhJk5b8#+wNGn}8^Wbf=sQdP_9klcy-66cRuYjWq!h3qw5K^}S_RmHb!H(fR zBTCR;3Vm-q_bQ|#w3Stf8QBzln}ceo7vRNAEqZCAcmm@7^Sh!c?Br0G-*jLpT?~5< zHkK0m+}Y(?>01}V`wEAKPQ);^>kq0QE@x`vW}!$t+>4a24kx}{pfPPe?dP?Q3P}Lu z#P*LR_`n<_9l#(&A(u|07~ib)QTsCcu$J{D=~F4Ur|Rv8V!v)q5VjiVmGsOu2r+SG z%&)2-IIS>tmZ)Ij5$OVraeq;1`g%G}CvFLetCwznedZs@A_}>?H(Wv=2A?yvFW2O4 za(B6Jx15btl~#j&BKp<7bJ=%@63Sxx+tt|)4eG&+W<06odP0w?9YzSBW>A2~l58$* z|4*vUlyY}8TtcbT4#!QI^T)?J7maInU0DlTr~A@_bLhy_2d*H^Aev2tA)@oo!$Sl~iDW_7O(jD^?Bc;ZeU zg^$NeB#!j>GApE|g!$I_VNt?@QVj{(|Id_?SzIR?!pKc^QfMEbFkqPy9>8AuMAaiC zqU3(*cR#pqf6;l+n@jSxpB*ySa^Fs!mfPu0J2KSIYA(wK!UCe?-6*R5=n+?XlIvr( z`pV?&l41=trjryFo%3Qw6+r~md34uur9Pe#`rAZtu_Z+!;vZ=LVCyU-kY{xF( z81ru~DSEH9l}mnBxq)k%AhY@fqL1p4$e2@smS& zOhqfSDzym?JMr$bg?(?{>9t!Rt#$|Gajp5Bb|TD2+}po@f4QTi*JwiNak7w9Avyf> zIV1Z03TlA@PU9z=OU~f`Bx4SkHk<05>D|N3{oJRO1M`0GYuklH%9JLSm~4mT=CNO0 zM{Au~Ts1~*@w=TaPDOJ_2H%A!4od@H(M7M zb}w_FSGLqtzRAq{*5kmU)sdS9tXw!&i}as@6yM2Wv*J8Yc*`ocI4p{<-JN_nH8}YW z9GZU10Z_AA!1%;?Zyb=8;KWUNgwO*MDCKk&(_^9&v$e}qgF4QEv&Jt5+d#AbD{-gK z?OfixVLHa5qvQ$lfAmMUfq4G<0F24XDu4X=@f$I4-gQaX zp`7!!q}#bPG>=2B@N$Ly(wUyye$Kay+lZf^|K~Vx%2h5J1ii$6YZA%+nj?{hIc?%U ztHr^P>qF{WpLA54ZM4<6kd~GXpWrqEPHj^cI+g`vllFjm#R!!U3rlQ`K*+mM!J5zi ziLZ?l=&t_u(`6i0;FiVy^mX^Y09ph#UP7~H}a3N z7j$x{EmZ(JLh^KRG0jv#%_A~0^7}S6z$oZEr>3W`cSpmXG>ha)7g)vKM|XD8b8>2| z%6c3xH618lJ2@x5F5TSRv_o*Id8q(eSI^ngKax-V&9_U52>&4bbX_3FFLY47}*T>6g$oQ;PFE2P@#+2O&IK#H?`;P3a!kH+vKJjxquvD>(knzAvao5WqqmN zKN4=Q{AT0>z7W1#cRdMo7V+rZv-FN%<6(9n8WF4>-7DFVN=UEHBnTU5E@zf;9;`fH z9fpry)rR{{$oZ1I0T+zl zi$XMhbZ=3dQB+!W^Wey$8;5AvFHVoh0G92#Y#{cnZR(XIs1L-v$5@D0|;5&UDI&i@!QaK7=A z&*)JKevNE-Q^s*AglHrrdPW7_)ND9KK|(wwirIZrFuL}}stc>P65-EQj%;uISfDmJ zK5RJhuM=|`|6^#5^RcTzal=1vH|#Uf=u=O6+<%GG`A6f5g~2c=Y?J z5j{t(n>c0{HWiDE*UHZYDrEj~1jow$d_(H2Z`10u1>3~m(z{^<(U`cws3oxX5NN4h zHiH3Sn4&e@mLen06UOX%q@qc4iO^f=xK&$qK%7%wGcRpn{KV{Fw;cHx*ON4~buUz* zVHv!L>|OZ$e#rho%d79r(CCo12WH0)!t0pH$6DCXxX~C-aV=7PIp6Xf{ZX*t>IjbZ zrY&nQ{#Ehf%cKqI4hR0kMaA2$MPJ=9-n_PFcrBy4W{%ndzzSb?*OB6Q$6B%GN@&ux zPNbiE!L2C;5d4B8CcZq-Y{KlQi(7o@hYeMU9dwHrfj-_*{w`2<4`ErA4qX`GvqFVs z%RM<}5Tc?muxHM7E?m-tPak;-OqUqrEx%tH(l)C5=z63%3v8!j@x@3@VoLbPiZx$O z6JB@S_q_)@_j>EjQkJ+^@AHrZk(T6H-{B4_9>l}N*~Li1GEgIKQMkY%R=vH5*F`U< z;X!p4n8C1viVpE0V614V2ghp=ZZMcPzh)rrPbW91tYltrzgN=2=|%aT#R*mw1&`|r zVwCT(r+bm@>WxT85I(f%7@g_nGS$)UOHKBT zHTCu&dlsz%kRTbyZe8T79<&8%7P?o9lymXdi{4ZbLPNfHP2=x!Y7PLy2Dzad;P?I9 z+2U8G|7;zbv1Sl_tmuS0a)J1}>ko+?p4~GkO@!nAh@mYnE&7Vd!uGg~6NBK_A-TXL zlqKmuliCaYP4toQ$GPw)z~WfdI>|zxZ+@n{OzF;~&tg~b1min#S-Zkl_rKrSTGXU3 z{2u$ROQY}+MMh(;E`+0WU(*qm&B1YeOJSU2P*trPuq&bho418sZ>+pNe{PAqFK7z< z9NxgM(@=|Ov@$oDRZ48wx~j{!4!8;OovM-eV%C&zwLX(Qc!tlrLTOg!tdC_!aJ<-K zVa`BM0a@yOEJuHy+ftgNuG?5n1#5M=V5HW+_CPKOtf#gW`? zbEUY-B)!Zzj_{gsL!)dW^U%?W8-4jn%EJwT5?nI?RqH*5bL(BOTa=-BMAmJfiV@SxG&=HLw}xS}N1^ znnx`M{q)nrv@*36VjiXH*(d1U!}WA6Pw_iF9h-ML88JI!;l@Yl9F&M`1!lyH_mC28 zgi0)S@XW6Ci^$R8H(UzvW=H78HR&!zOAR5m`Xj3yjiAZ+CShuS>dxaMot+Kk?3~pL zhWdKoMwpsC)Ciif=Vc1@tv7#^pC&i7wn8g-*Ewhm!4q5EU8>Vsc#JRT0S@pnova}J zWt5d4Ip3W+u3p?4UUX8A!e?&BZtt-~43ew9hj78NaYdc6X8^uTJY4I=8 znr=E!;x83CDYc&a`lfz=MmluR=V#ZQ(YKnIe}!mNcf(j!)b)#b*dT!HH(8Uekq=9! zDQjk45uMK5UFL&H>I7JA6)9ke%<#G|2kOqdc@Vzx=SVm%b*8 zeC{UZ{`96 zYtqOOaWjf1k|X@`*0k3bm%IE2Zx*dlY^AGRUtUx058i&s&deY4)PNnUqvBrc!Su~L zs!1R+EEUCbKE6oKWqBqLT)S@J5EUT>w2X>$?fmT7V<>!}@&EF+^UTvxZJzGxDkA*p z6GAXPB<7(FYV)w5Z1ZPNzM2lrO@O_nL(+f?`U7w>?pY09LJsOSpC0$M)gFv&6!%y zewx~+xz+R=aq@djGzMl9N9BuO&i{SOXu>oQe2&QPRp!Jn5PU2fO74R?Pl@LX&2~#K zIh-c(;sq@$W|*!ry;;%}PLLSwj5XA)>@(fNu+}DvA@eCh9lZo5`L8&xDL| zS(_`W*`!rUD0y@~^*~{@EQV4*)!(3--^Zj@V+OFhd~u%ul-7Pk}TN-ECo5ABEyH zBc)>0NQ@4|vbo%`EUBIrYB6Ed&q>A4^jfxG4FrDr0dPCX6#R@ClKcayZ8IVmOgKyl z&+OK3$#@JbGDPg+vxw@SSd)+Uq=#uv8D1rc1}^B>3wsp_Ww@!BiOzPc5NW#mg9HoQ z^q}i_7imh@y&?q%(oiFDI&vam2S-;?J{d_@1rj6&pL~Vm#q0Cov%dRI2fO=6Otln9 zW(!Uo2}fu0xE!cvKR}_I6>Fl=y%HszNr=4eD4#@8`NQlerY=m`2J)wEq8wZ#Oaov4U!WL{Ob6viXj`B|uJyM3#7V#UbcecWF?7@2% zF$BAOW(MQAQHCFjLpKH(zSDY!I-oHqqb<4ZM(E@D)2LwY>h8ND5q zF;TbdWf2|O;BI>KbRvC5tfGs|+YUeuxOHS(ff~AjPGF3ddHq=hW(yYA$F@KXAv+vB@NHG^L?03JEH<@dTrFCh=hEaT$QAk)`=1$1s9K zTltj>@u}$v1|xTAPQ^U_2R0;YK{P{0z3(+C~ZDZ#z=Z*@TdJi02J`Ene(3gX3(WW`DD zk0%Y-)N|~&X4rF^uLcS=NrvrWhuOgJzc7O#wwW4XYD5@?r0^!Rtm3Gxk-zprc3RQG z^4nU2`HFRlrJNw@ z@31yseG;SezihWI^|{HesIAiPg1~?RIfxcYg&CkgKcIHGTt1o=Yhr;w4JGOgh8hSU zkV^m~x3|Ex5(uQ(XvN5_F8~DsDu^p5;4Uv(8VFQolcs6+LA(MH6xcgmiPpg`?EL5Y zmwNf)rET3GQu6?*-x^XNkYZ++LW%Tx>AgDeh9p~lOju>Q1o#mK0>;i9`LQ)692yXa zQCBDx-kTvV6QH~itx2?(#HIK^4g#TONtbM7`J}{GA)0;7s?%G0+?l%kwG^D@= znHo5eyM%OuKqe_ys*Fk}?Tz9@%ut}Sh=S?3a(8j#;)bcIa$};OP@pS?-IA#&zf5H% zg<`C!o;SLB9Ai0p&>+!TcSS~+a^9&_+wMm7OulP}DL#mN7NlW%x4d{;T>%QTK%2^H zC+f|&n!+kq3MrZvw*AuRs>faZiAPqygmemPf9lHSVaxa>%RvkTVk)`S*q8pD2(Q9| z05S=6*JE5QYg7LY4br9W%$Dc1S)Q2!fx=}YAmkdh+pMx6kfUk%l`NyDslHQisn1nvui2NMX? zUpzR~wLf>|!DzT}yC2jTa4-h~JwV<~Hv`OxG3G4j?-w>YW^$r^f`11BeT4j)p4(4! zS8nI*Okb1Bd+zW3T|2G6f9`JI&X<#jE-z4=I;~p{{FsJ!31z#*?4RG+`2R0|sNH#~ U#>d~UT>jjXlTwzf5jP3`e>LfjkN^Mx literal 0 HcmV?d00001 diff --git a/vendor/lucas-clemente/quic-go/docs/quic.sketch b/vendor/lucas-clemente/quic-go/docs/quic.sketch new file mode 100644 index 0000000000000000000000000000000000000000..535e9a3d8d0bd276d69c693de69cc4667d5a0a1f GIT binary patch literal 90112 zcmeFa2Ygf2-#>m=lAC=qnjk~aIzR|!4?t+9qAb}Uh@~x1DJ`@G0U0@ph+9#ds3^lN zZUtPp6}N(0+=?6L*ZqH=dz0HHX%&1Pe_x;ft5r%kNzOgze9n1)_UDW`dPr?^O^;~} zjk7A7djyys49hYVJ$f(N{4O4p!X0`5a-Pq}JKeNzXb!9U? zsQk?p^ptOHuPf@CH+GrNbicIw=_ZohSXvg^XGjxG4_4p^qtJzD=T$b=R@OHQ#-`@Rn#x(t3uf0;lTY|%Y{jx=%fw-$Mm0Cq)=y{U z*TbhCUsKi0oU)AVZ5%dySbW5YQKN^COfMg95V{koa&B`&Q{}vx>UR4YHh0$4nnq^X zGTpFIW2r9@FY$<$ZVy?ujIFweSze4YxJ##dn-o7-Cj z)38yg+Nx$eud=ap+}hG{^Odt_FJHOr!izdrHO%TewP8lhEYPc}p&C@_+cdMLxoSp0 zeqW3CXVo^#uX}m}(`sUsQ>((>=+r>FbwY>T>%@{zt(kp>xpX)*A1w zzVwRAMlN4osTJI0z_fHPk!lozRV8Tzurz*>zBByxx~tju$jqmwWsHIl*}R0S&T_)imLN%Eqc0 zwP+rFKy$-vJHswtvsNcs#~e^Ux32Cby}@WQTgD9=)pusif~JZ1JNLb@2UOKnHZ`qT zljUBNY<9;)<=-@jbG-7hrfG`g7&dC?Tsd^JMHyLZca}|Rt(}a|Yi3g<>#$Kr)hwu~ zj_1boLZ^L3H#RghXIatKx!mKA^p77g;+Uyb)zfCqTe|9!4I8&U@}xpJlyXvjIu}uL z+p-%fSxwoBR|d?gtgTm91SOp~hDVVn4WsR3?Ii8l%51c0jf{>FnR4a;rZ3}Xf=quV z&ZL+OGnhGw8P1GlCNRe^Q<-T@Ei;p8W=>!hGK-i~m=(+!%vsFE%w^1#%nQtm%p1(x z%sb5c%!kb9%=gT%%x|ogHM0`C9~)qUY(KU?JCKdDN3ut;L)fA0Xm%VsfvsexvQ=y? zJDXj=p2?oYu4GrS7qOSJtJ!tzdUgYQJ$n;-EBgfdB>OD;0{arXgMF3V$-cvW!hXhn z$^M7^nbUA)PU0L~H*SByN!E*dy#vIdzE{Gdy9LAdym`2eaY?SzTDFmc{ksg@5*=Q_u~)dd-Hwy5I=xFj33Ak;t%JK;0NpWn(q%s<6H&%ea);9uw8 zjAp!MvSzBLMl(Y*U$a27L_;(uYnE$P zXwK4{r@26LiDr%FD$UiJwVLZSH)w9u+@!ffbEoDm&E1-(G}|=KYhKc9*SxBEUGuKy zBh4<&=bGJ`Z#6$?e$wi-2CY?V*E+Rs?LOM>+H&ndT8}oU4Qa#Lh<2cMkhVe_*B+rA ztUXeDly;Awzg3_S9^kXsWz)6+EcVEv}bCs)UMI4*Iui=UVD>v zqxLTCz1jz~4{0CMKB3*FeOCLD_Eqg0+PAe|YQNHcr~Og;llE8b?>dc6uQTavx=y-% zbe(lwbo=YdbqDAU)b-JMbbWP)>Jqx7?g-scx}mxex{fx@ujmZlu%KDq`O(SQFoW_Zrwe)O}YnlTXhfV9@agj+opS3 z_l$0*?j7BSx=(bU>b}r@rTbC$AKg#7-$X_ z5N{N35+4+|ijRp;ird6z#plIW#J9wE#P`Kd#81U9#IMEg#UI6=#ozR1y+!ZPyY!v( zUG&}b2k3k1d+WXWh(4;1>HF#9`h-5IPw9`+577_R57Srbr|PHckJs1f8}xJZ^Yu&g zM88bGLVvpcEd9CqRr-tcm+CLq-=x1;f4lxJ{XP0E`up?`=^xWSsef7jhW<_cTl%;4 zAL>8Sf2{vR|CRo0{cim?`k(Ya>wnSzYTylmL1WMw%m$0WYLE>38_Eqm4ZRH>gV*3U z#0>omgA55n+Hj;{h+(*4lwq1-x}na{V3=cQHq0|DHY_omY*=nM&2YBiT*LW>3k@3# z*BEXzY&6_zxWjOl;a`(@fJ%GfcIn*`_(BMpKh%q3J}^BGY2ixu)|> z7n&|HU1qw%w8nIe=|ou&^=pO`)~ePjB` z^t0&~)30XUESNQBt=Vk0n5|~X>^65Y?_=(4_L%#c1Lm+fYVL17%$zbGX&!1GVIFNB zYo1`9WUe$n%50ZnE5L*=V`Ta<}Ck%O=Z%maUeDEDu|rvTU zj^$m;N0wcd&n#bBzP9{m`PK4=m9y%sdaKE5wRX4mupVgbX+6a1u^ws-TBFwf)`WGi z^+@Yc)*;qW*3s56*0I*f)?=+xtjAfWTW45nt;bszSr=PRvYui+)q1-1OzZj93#_ZG zmsnR@ue083z0dlP^-=5N)~BpbTVJxiW_{DT)B1t+BkL~f=hofUZ>>LAf0Fc)L9$AA z$tk&|eWdPExpa`!Tk=Z*DJX@c0n%a8KxvSakq(!RkOoVWq{-4$sYaSE9WT{MP0|8s zk+f7=CM}mvlg^aRlg^helrE93ldhLGO1DXONOwz{qz9!(q{pSFrI)0arR~xV=`HDP zX{Yp#^s)4bv`hL_`c3-X#@n`&OY z*`Kw)ZQp7C!2Yp)m;H15m-cV%KiYqGuny6ocNiQ-huz_DI2~nzLT-?ciTc#^Bm08PdWzI5JS(mcz zW&4-)D)W~4%KT-4vVLX#%LbGkR+cJDmklW!S~jd~cv)rH)UxSi$CuTWHI&UMn_srL zEL(PR*^08$%g!o0uWVh}`m*cGZYtYYc3asUWn0R&mOWDTc-gkH=gVFy+fnvL**j(L zmwioU5mF1xFn>j2k*u7g|$yZX8gb$MMrSJV}A^>g)iC0t2Y z%9VBvaSe41a}9Tmb&Ye4cTI5Bxn{Wz?AC z=04tC@1E_Rv68ChHa6DOH;=$S2iI5E%+Kj#$5hod%&i{N zRMR*(1$9d9c{FnBl-|{DhtMas>UNU+wNW!F8*2uqj;U^#qG)-8Q1AP8a)E^4OJc(F5=n2M>UQayci+BRb zWHROt2V$XQa65A#a}aYd(-SMzi#dep&GcbB6Q(y-R@Y);O=GJX>KYm`Rcq}mOfuO} zR|lUU{8?k=e>Y{ttdKQiEm`SB=1_FuWqji+sgrI>bwgH@)xChWKvw%A6Jo+lgo(DL zpdPELr?Pu*Ej|}x`a#>3|EcPwN*@E5!?5l{M-84eOHpa%53OScGJ}{3re7QHO_7|f zK0XxQqPj$7Q_bX|qvY4aWer>zeS-02^{oa?7v*r~h^#SdrV}|bYf=U=gc;h7R?Q4y zhB5sL6l>)xBbcM7NS#{^WN_hnu4hIvqnOdm7&?bP`P>w#%arze*^9Z3!(6Sc=1K`P ziJ4sZ@HjmOEks|>9Lr2$j$J0g)HGhh)H4mtY-SGA$TZO@{M8qxNIhCFc3XYoBPCB& zwv_tVDbjwWy_9@rkJn@_GcW7Pc2d@2KGworv=)n*C52QRB?E^#o@RYHaN5&1$pVcS@a^ zHOy7a)y!IE9kZUt5c4qe2;SMmJkC5J^J4nBXXH9Hu1w~&LtwE@&!1fhrd~Z7K{5c=+WM-xxz*tF zNtwCNrn&SJ7B)1@l4Dz@NH$n+n`^5o>(s8%rjB-O?#*MUZFX=|rglC$rmx4!&uf}c z+cdVesTRV<__02zv_9emJ?s&S-NAf;;eE+`#eB`|#;*SctMVQG+j8^*e7_1Ct+^3|Lf8r&8{K$g zPN=PJo-uYt4UJ+sdVaR2SYFZipiDGHfcSy=5nH;|yhcJ0ThIK5`HA_N`GroW_)RQ& z>sipx@6q7LQgOD2ZwF@ZJ5KH&EN*CEIncB#E8t{y#yM(gu54^h)l@Y!$|sJVkco&! zs%acji@zo`=Ve`-fSUU1!VhM9XBi2ysyr=L$BKnAo6NG;vwGIR8d(#aS8HiceiyyA zo>;DJj~FO+4Qs)!@nm(cu{PF@e>zwvTgJMW)vTNC#O}ic*e+~Wwi~-I+nw#v3jX}9 zUPoHJ4z_yjYxO$Z>UE&i>rnP4qInF)Ty}OgPWWdDYsvN{>@N^we^cH3f zyFXhF8e9bwr3g!L^;YboE$o5pLHHY*3wsE&iS2{eo0!h*p-d;%#{f00Q!A@xP6y=G zS3`7bXq+P1frN>|MltKn_7~}4A1G!kaP$w=XAhIlyEhsL2Qt2pCz1~Mpfv=%ohY=oY9HYR3$*%%J3A6zmJizP$;c*v8A##5f4HwxfD z5Sqv9i^d|cXfzSagypl%4gf_0D$`*rz-WRy*aRM7VQyxVYzos$vl;eq_6T+`HpDyy zDMtZpYvjE*t+uX40gW+Dv@sjXMzfJ@xO~vp@)4pq7EJhqLBHSYNyd{g3?~`#B$BCs z#~%x&Lf)V^kn|=-&90w5LfM$Z*x^$ocdPTJpn&p}_3Q}tXm%t!itf+$J_LYiy-izx ze~-?gvNmI|HvLqLdj%`}E9li11F22}scH19=Qr?9rYEU_vuVm zF?&>bMZX-uhh&r4Bj|w!*UsLE1Dz1FN6H5}l}?2MA#cdz3kIT|U@{f;#NytFCliUJ z{9$h}6!xbJ7&v>5e3;J@vl$%al(G-c$39G}`%r1S7;T5EZKZqj3ie8N4aRykyO!?F z!}^p`3=o{tX!H(5&ty)``_# z&E5>4za@JTpk~-k$yFfJUJK$l*xT^28`;}|yO3ttJ7n~|Jtxa{V($hH--D@bX1B2S z;`euKyRl?kzvs;KCSe^OD6S|3y)Rc*~O`s}#u7*S%g zBeKJ@1ca>Ci`lWDt0ImC(t$w08x4B`i44TCSUTc~1rt$^FB1<(V_|CL@fT8an@r7T z#Ox?g^Jrx;p2K2{R4J#ly^OZeYFmK_!@fpE81_x}E%xp5L3i2D+rH8`MV3)w8-F`F z#Oz;QG2o5CtM>7HR6c0s4c#|Lw>OW0wmiG$RrXyfL?AA}!oG*#fIryxF&YRFEXRIC z1&VP~8yc$-Ts#I4Ue}Zz4|?^^9-F7xF80&xgzV&;Ho|@ZYE9h1e#L%`?sl`^u-~%Z zp{wt)=AGFeCp6E1uwP%()HI%UMi~R7>a=XZs~$hQp{Z8Z4yq_mEUyrA=Vp>VdrSew zfv|%ivTe!3*)Qy`0EgDtLbZ*AJnZY(-`L;TKRAYCIgaBwfdWiBp9P~RK$wh%}&Wy<#r2a$8I_9HSCmc zIVbxySH`(GH`j^X&F#aQ)Hcax-g;~m2nR-+ zB~Z$>jE1}+OCJ++-+}EnJ2hL0(_65YxbEy=t_QbYc2N1C*DsZS$_IUZFa5c%e9)&q z)1O~tuE~{i2NX_KUTga3>$n5CgSdmao?I{P5Uw}Zhi%G&)rwczIclE!yxxzrl8dXN+`eAcT+bP)#MRslgcNjMi zBD+zb?{#@19rrK%o{ zJvT$l&dAQ9+}-gqrrqH8u9tP z;bbZpPsIut12>W~25z*Noe9QJD>DIZET(z9$^?|QW6)NowiPf2?l{UAxGJuit0^C_ zd-4rGzINQrtr&wj<WbzxOluX<0J%ozWvOpO?59TrFeaj>lTmjh)?43tt0F9Wbpl z)l_F^>$6LhN7v)gbF#XZaf+Q_+BPP@HF8Z{GgkkEY-9GsSGjrI3Fv1&w}4y7oyaXh ze@nQfT$Uru7Vacw(I+8v z_~rNd{7~{R#om~`9~xgYQl5iN*T#zybz>!Du8Fi2A}|uOE#8c|qFgsEy&U zn?dNyxYZcW<;*5JoF&;s*~OsG-&yfL`IbVAwcNTQ*rfsv-OTH`_1p&T8t&Q>V9tM{ z7?@ky_ka@0qi+uMd9F{DpWYA{&0HsG%>p@d$O!O zoKv7ZgriBoQzQwS3|0I6>8K~3fe|E>iuqE(WH6KP!6n?vn9FUKnZzq%_Ea#5QxsHw z4XC_aWe7^!+h|*%wiPmo_hlyW5%)3oNqI%NYv7_6tf$IMV*f2)Z2kI*9px1V4m3Wq zCa|r%V&A8=&$!2!sV*t&4LPkrHa~(}eol1;S*trErz3D*LFzlRMe6$&tl_M-rM@4i z;?W}YL0~((SYT@{{6lHve#NZLRk=RTp!4(gg6s1 z6NbM^C5qD44Q&^xZ3ToNqn$asxV&JzuUqQO8Q%rz3A%sA);%k{$e z7;MFN+j^^w(eQC@DWBw17!4#hy~JZYYqM8nuLj@iLzx>M84U%4u}~-m=H`vc%*`8# z1~86jAd2G_2uCAyM6%rA3xvbSNcKiTK_A2hFPNdXZx|nqMIyeiFC2tC;iGZ`<(%jS zZ$)A-$@wE*zb`0D88oOP?DNL_QEwz1_4>n$OUEs9Yknv{4C5ZIaO-Qb>$4kLachV# z7(oPG_+!41-=BMCI7qvVMZ$O-RxbvQ3~r6(_6Ng3uy9NX_9R8JQMh$UM{Nv;a%+AZ zKOV!Gpm6IOve#v=&vWaxh>>H-d-;~kb@(a#afMu`1^ln$EBUE>6<^KQ@YDF|{ET9b z)AG@OF9X?QLn1$uuj6O&^?ZW@MEI>568ZVeCVn9`B;H;AU@T`4xhK0Zdq-}|A zE?L9y`NQd8AQJTi!ZGRzOv6H#3?w~}d4usl0RJbVg_yKd#v~$UZv!UXqTtWTfQVaF z{88FgpzU_Gt;CSXpUt1cp9|)=loingLRah^BeeUTG%;%Ln%9dD7#h6-kaSbv-52Q?A#Yj#9$GH6+iBeV18ai zc!j-jk2jV8IHVFjUo=rjk-KDy+#_Zm07dRoR(~^QcE7s%O4|cydr)mF;1c{Jl%4aB z^H1^P>x49HWXq-+M{ zpOsnq!?NM;@f=gI-69{??{{?juC~eex`jXmKurUh@079>SxyiR5)Njz2t5@!;f?HT+1J5R zDC-1Y3woi0Lq-UO!@f{hQ98q3I5?qrMj%8)!1xqFLDpU&ScD?sh~F28Mq|N1_|M)d z9gfU!1+U=4aQq6x-I;wW`?kz*VJ?7aAOhYQjRk!0uu?`&Edaev^z{u!;1>lihuVyo z%y57XCgKl=qG1RTUcWzvX+)I4wB1b`gQ4tJ=qL2YUKa|05cOm#C6KQWa6ZC}RaEAo_8J{PS z@p(OgOvVei2OVRD1}|ZpyvHYq*^pXi*t`_boH$;uDpW#vc9D-PaRxwF@C54NMr2=%Hi^FtdWL0zqL3X7!BCs;b7Vq^JfaUlyIR;sEftye?X`o6rxc6 z`=d$}rR_?z{iL=P5^9}HsB464nJszC>q?>a2TmV6NSnW zg=G+qcP{`!5%JqoXhMEi%Y2bgjJic*(O4@(Vw-QZF&?VW2#*MlVmyyQp~=o8tcI{W zVTGJV6Y=|f&@`Z70YC#VaJH|}Q1~iRXk?Y3Eq#X0HAcZzR%W2m#G*bK>-Jck5uO#E z!>FH^(Uq`z!s-YsV$|*vy*YGht@79Dnbvy@(qS-o=346W$j-C>8gGFMwQMLEI;7C&KPS zSc$M@tt5TITJe@!mi4Jhmx)E_QeAwc|q z9vs<&2y0VL=zka=VeRS>RT_VzjZU?(4S8R~YhXBG7iqNFo`iLkS5#KWGCzchCBKi~ zcwu-8`dE-j2s)4hbz5%vJW?vKUmM%b>D*%8)L!0jU5 zU<^?Z0Z-hQLNrx00}xGN#{P65?oS3GxTN9*1koHq38LwPo_bJ%>?^OmrZ1gicXjQR z#sF>HPi-tAh$g1#r|HjZ(j2B4NENW0d{5Z&oB|MKRB^9YPU;^|gRWvJif%EVC+fclKov2^NZYl95C(8AX&YQicjQ)`{}QT8vJDbYuCIJ+zcg15tcx$`2GE z%`(~;QX306w4yF(&d{9sC+Y%J1v+mEn` zQplDWv1YaAavaJla*X&e!uBWZfd8h-pxL0g1|zyQ$JFA49YolQ|DM*MxkYm;#&cVa zsig^?pGQ61I`BClu%ub8zw&$T~&b?}Y^*19?40Mc6HZziYSnzFXJopX=;y` z&u$%hm`l%YlX6V!={agvkEznwL>uR+jU^(ic7b-G_CySJv35yIF!CD0&WCbwTwb|Q zqmfVUBsWnJHj#l03#rHlzZ^`d0r+I$bMplJ5#(2=L$IfMb6Q4lPqYl}ayrsQs+OTW z4Ipp^VXvV;y7+Hs8QOC|9_k(0tX-)+zlAGmFKUA;ojQ~`X=qcKD7*^EFaoj@Y0NiOz!kMu%OqNdK2M?~$|}^@K<7wQYAB6}z$Wa; zYGWb1-Xg>6?bQH=nbdmn4|VSsyCdf>J8eh zbj??^qc>k0lwcFXj+8x?g{#tL) zA_{}B=ct@m`xbrlxqHEhweM)(ZN-T{QaSObDkok^*o$(U7}hwdHy|q@7jKvd`Mlw1 z!V`)_5St&5WjwJ|BISvsGHE0XM*Y5I(N@_lZ4&R2HD_jDQ;sJlXG{Fydh zs5TaEl|SfK(Q!InC*&=AZN?mat;QVYOnf@6!jdn^vt*rtKIhT`O+shUS#=U!%PR?c z8DZD9!+&*7T^X}Q=gRTlD+s%qu$Rl4#6KM!SUMuv`JmfZ*Bv8*+<{;?!d^{Sz}r=_ zCecn*-9H_kr|YTfg%Kf5O&-w(!mcCi`W!Rc+nC5)I6zyGlz#&?b$$#iKv7c{(uG@4 zQ`fHz)Z9qeo3U-LBkZ*bYTi+Rn#n{m0fQ4*1UMT_Q-QH8lb|m0WZ0MS$C8Oip|?$! zrbj_{IQqPi9);`WU9THVcjFD}u2&j|(Z-w9#)6}u8zmowvAS`(@%hNA<*jrHHL~i- zzlyBVO={64Zpp!=ZVCmrTUBt=Rnb#%Tbtmfn^p>Lw-sFx_Gm!R{gKeK`cXUqP_D^9UA*WoT7=zb6%k7b)nA$6;K{ zq&#VV(w|DeP7R}c0khLBlgYLmWZOc?wn?E7q8A9eS*4KDcouEES8XgHn_~IUU7%Z~ zyRa3t)Hth`isP(w7c0Q^fC^lzY4>o@=OV3iS5jR!=dkP%!ahXUhjY5beZcbo2Z4Cs!WF7X6mA0zDJIbGu49C4+) zS9c!A7K1eWV*Qt={=;Ok0I zQaX_ch9R*=!-z);CPMI0gb?!(^QJPHbSx4|MGLbVb??cC_yhE?gC63SmGk-$Jy6@# z^Qts{MjH{8kh5u)C>6Thx^HyfVzA%qexORlh?~a$*7Xax(r}ck*5s9naWnoHYN)=j zydqnXS1SB5j1HDpk2eleD-7g5C>4Q_2S%qb;}e4u)gdKi3kCDV~qG?7U~lRj?&bc^Mb>f(Xu^LbU0i@<9(>YJYR- z$IT^riWtRMWIaXfujnZsD|*UjImRmvq<|{S<2JDEavI?lyI6Z35<o-W?kDo+|Kxc3PYO@}CePEoh-mdkfoJ2%i zI^&5WX&6TfhTTwMdaO8G-WZM87(dXB@trb_W;%`U)jgmzE})GqF$jelV~M;mhNZ%Xk%QTQ%1yPm=ElGKa06!CsCFoeko8!#52XS#IxxEWC;5!;e>V=xVTb0 zAE)br90Nym!Ec299U$KePIsi`Ah-zHT1bvOj?kEazE}re5D`Y9kS~IW0vh~FqnW)} zz)-;F3wfh4AN;5hpB$e|LleTtc7n_vjfBHN8oIPsA8%vaG!8*rEy5imUZL=Ljwc*T zI1cQRMsP*tNa$G5ABrJhDiFm;pjr6?z8LbK5oisce$W@AUjCkP7y>P67lTy>NpLYA zjr2zNv@aHjAk-RR))41tu$LT#5DkT*_+~VSi=jeLC}{8ijl4jd03yGl=sxK4wHH(^ zZV=(H5pxb3PDeNm;j}r~WG~jQFU=zJ29OShU~3;u-o|)nW*BXz0Th0p7am|A|^mcSh;}|$4jzRCF(G#){=gmg9w%Qn;{KjyU z-}}>h=lyubcl~ontv^skYVLqMQtNxs=Nwpo)OwG;ul`WFmWL1y!|dAz;?V?3eLx>% zw&+6&QggiscQE04=8-z&4*@L z^DrHwKp*hO5bTDq*^oRzWT1or(e&HEbfnm}2h;k)^+#aHgB4AT1Hld@oHsXQ?;bB+ zABxgGcpVY9izx-bN-zU?hA@AEM1VPP805xy>A3fXGJgZ2^+#h$BPm4dN9)J5K(u~B z8xY-(a50>kAmIWEL?;U%It>W`QA1G==;Vd@1F7SP3r~3v`GxHVI%NDsC$U;SiPO+$ zgr3BZjD`9c^e}`~G*%jC(Z;CSSa=c}<&!v9KTm%GK)Bxjzzy#yCvkuMZ(j^t_(^%i zp=W)*Y{HM>@`}X1zj%Hb_IL?I>lfr9TE9qv=>7^s56VHbekq0M0V+i6Po`({umXr~ zsUD&~RYvB4e}>HZGbl1wsK~58hxQn66PfiZOOZM87s#x?n66n$MP~hK+JAa4kXe7F z9_4oO<}m$w6`8M7k@;}K4ap(%Pz9MYd1Q_wnH`yGK2I7l9$0oL4xJP=gQ050Bi^Jp zj1yO&Q|WJ!_rq=24@c7daD+noJLoh9tE5*NH_^tU)W(ASpqRt-59+t(0)dLQ!BKe} zept4Gal`UfFug1t4A1JIn6ozhQ>;_JjajXKnhEHi)jy|yUjKsrMg2?dXuO3r*|5^% z33nXfMiXul;YJXyx(z6l0sIyHt2l(Ozl@1t(0RFH~PEN%6 zqWOwQs)KzPIHAP-BN!HfA58=dAfpaabr2Z}fSM4^9E|yZZBYOu#S|*T@7ZVD8}hsQ z_b}x5bLc&eaAOEJ7EnlgMrtDbm;s;~@(kqMd^`=1CX3gRAOzx&oXAf@eUSu+AW$kZ zV{RdDF4Q-O0_#k0IOy!cD}8srU{oj=hWmLU<%n6H$*L5~d5+6CcKa zu*O(*ya*tA1k8!9CPLi6mgpPNP`(mF2>1>oOb8@E-X*XRys6y*ey{%l1N<>JKo~|Q z6Yf}K)ss*K0gN2u0m$rgbifV39MZ=;xMq^)7gE+YLO28P*UU~^2d zig1;Ln~GuYgMpySD8e!kl?|ST*zyqFy*X;q^v^H|3APIX0~(3Ej`%cW4V1q?Y%mx& zKHGjjrF#=xj9Y5Z8w?ncQ87<)(+O8YxM?|gXwP>2-kgxV`RtxrG@&vX?3jbY;53ve z_>14vnhCoW)7h{u-tQsH#d8QZk8sBmu0geC>VclM_%mC!W`9rwCr>ZjJP&MmL#J^qGCiIY*$Wt26(U-~M~7&)}Mo!B(PVU#OV z3nk$ib1d0VK^bV1%0LY%%HW#YWT1w_OBv|gVg_2|PcjUp6FfnUtT2pV0)~-NqNG873Gewn$rsV<}|~l^7zez1fu(%;gAyIfHNu3AaFzww6=UX4S%N z@l+hfT|W%f3Dm^I5l(pGX+I*@;)!r7?9F6CvBHRYL#<5OndoIPCGCj{6=lf^;Ulf% zYz>Wc=1bJZ0`_V+K_=}&!-@rH(lUpdef-d>8wkdl?DP>RjE6Scn=Xa_q8W~p6 z{#WdUXk@t9a0y7IcnUWe5dUkSqEctW)p)f|KAfi$?i~4867D>#IYL^v)9~k9`CuZR zA%Rr+AVg#&MFdf9fX2imQIEk(Yn-MczC>XTli@mP^fnkoyeIgp_Ink zXye&xVv-H7 zIhK1F;VvQErSijMmRZuN{4n{glA+*X@*APH_`5u}_YEK5VISrmb|v91C)^denUy?A z;gju5+MA!5x7~+*VfYdc`zrUawS>EhaJ0SzdZdCw>G0LJN`^uoCJP&j6;rHV5Md~Mu$``e2{})sl`Wv`z0N9*KaGtb$=omOQ%ucI0Y#VYEu**hd>C)j=^{wwb#<9 zn_L)?Y%HV5V05F?>nSo^D}#Vhwq0GPf`HPvFFmj=5g`T0U@WJ|U_8ipuo14u&h>^9 zqVqP$$e{D|seC3oth~Z#y>;}*A6$Uok0(MEPp>_&9Y{C!X@T^cbC7O4ltTJO71E6| zCfw2{q#MJfkbY}1q!&4gj05P@Q1l^Zhcu$jua}RusaE}n~(SHcRjb|8A_sstk!S_M|F|{bX+;6? zqwqH^QV7>6?sy2sB59ymfW~NN(#cRLoQlN@{Wiv1yvf^>DjzxWs z<)$p^OZ-t-R0d9fh3|$(}g;tDL_x7DTE%rp@jQd zS*Qq|$nHWGWs({2w`ya-X*9)U!lg`UQzox<^lL@98}fv6l^>>iZGz_WBj@LsmgxwE zY5kCATBafN;fR{ZF)h<@%Ct;Jn?{;OnMM~gEyOtdhwuX7nRb|#X}oCyv&A$qhqS*C z?kB?ioP+feLHU2Ea+s!?s_?Mt+{6AL+;4>YU4GdAzRF>$GtI)o>XnD_JmFcw(^v?q zSCq*4|3j6-G|zMb9yUMsFdgAFgr`9a|09*-ZvdSsi(wE7bf%L{%UXcWw4xN~c!}@` zI^YcicODYt$n#}|Ko?9zlE^5JdjM%Ddz8u0Ky1pw5G>|{V>uE`7Y1UR&X>>2Ds)Ao z4tOQ%z;qF|EMF9LV4@+nd^=GGrmN)hvd*;Lv>`8xUoW2*?Nj$n-Z3bdm+e-US9I^( zsox>*ywD!dU9SQikEjFX{N4nhI#gxzA#@M-kHFGN%`3<|qJ<}- zDb$)kg#+-c!a`=aiID=`%OG4=O1RF-Lea!qzV)4O2uU-&K^wcZ4RneuZhFu3eohuw z=#|LR>$*Iw!4d#l3g1J8wOzDV#2Vyb?Q@Yj=u(I64K%qkkPo4h%k72Eoxf_N7!#}&(+{3(I3#^$Bq_9>P?8^5eJRJ3W zknoD5o-cINhkXc+N#oL@RDjl9OyJ57IB3G24BUeVB95hEfx^RK_R_;)_M=bgsOJ?& zy*WsCY>}hh9HWixIO@#diCFbt+tTGSA67>dkZW zj(YxZ!si_IyyB?mRY!d+=?kXg2pP{HPzVJJG7t!9Fcr3l&zpi(6(;He!-aW~ydRce zKTtSvrj(N4@zJ+W4oAdh?m)vvOdmYy)F{8yuJeOY=DjSgMYCGj0zeJRJ2o zuryyt!P0!O`4aP`=F5t~ax~#b5dIj#k8cAksSDnGrFjjG7gSvtzeW-MXu?w$yi#Bn z(XI&KL@*~@@o>b;o=TMB_XVi09f3b^n}(t=4$HARv^a1SrGjWE5p^od;jV~`MGagZ z4ZMOU8P3kV{B(QczRr9-#*G@E^0>zlehlHMA6^bhg|i$%UT}^_VyO0;cNs^+{%{Zh zUhpKtU{1qysdL?rvRrV{()*pG7$zOHuWtas1yp-SY%JyxRKuvkD6<0>ase7#?i|5&IEu z3opCulg3owN=Gm*3L4Xz#*sFx-+)I@^IkJjX3Y019$@}h!cQXnWSN@qN&h4C**n_r zg&D?-s%qxP%#WLqZUdmF{z26YgFB>iW*B}t;UP;@5`J21GYo$mha)U z2jfUOk0bLOv02dAW8rWD#z|zR6$-Lu`O;1E>p0@o^oUQDDe4B!-`KMB3o>?r&7MWqpf6%GTQq3?H zjtN-6a@Ntu)c+0b#3C|VEQo7mH(QJrQwtlnNX2X%3lC9hF8-QL_y$EgSy~WphwS-y zFqleslBlc)mX5$MfKTvNM zw8YuLmV_lqbKkd~M}Jn94|-6Nf650v&|UsfrkkewXpy>)EQ9I87Pq;NEJI57(URhQ zWH}m-9%&gxAN}Rq^k--JpbtjNKe(uAqWq&g8W%DWKC9|VmI?IHWG{3j%OndfY^3Nw zlU6NL^UU8eO=bQk6Mh9n21q)m$x(XzN%<(fNE!;Q7r_JmIK7?|u{bDzdkGYX&RjdR*#@I z$`TR8i}1Z*j0z1Qnt73z5fICVm{=?@xGpki=p_R9G>T*5DjUS;LCnB6Bl+_Ad-~}% z22LZbEmv5s#K70&WQ6kxe;(miLPnr$AD8MN6dI9*K?IATo-lQ(<8~c-uMR|km=8SO zM_dy2wA7& zfQ*LVX+%{k*9FNzcvP0a^(2U&L~I+v^8yGgSK`|c6pqMtpmAK1fYh1xmijgeL>o&k$(X;4@Rtyt1{BDljz}efkrgYB zICEs@&@tn2h-jc?r7;gAE93(?As}M;v7;~o1j5k>K9og89H^Jh2Dv;K9u35oWhI3A zVQ9E-7B@uEdCH3sLG&efyVnQd$%nk8Hij(6?^*7(KvuHk(u?^k34b}^^I-|HJcrf5 z#z4hg2u|oa_f%|mBs^h9gy051ZdX3kG=L|f3F0PpFVJvWqRb z>|%Z`;jbe6)j8p9PmhAK1OJ&%{~e}}s1^%^H8A~`EHAfW`meUZ^lv0QVtn`wgkP^P z{aXu|eu`E{@#Erj;00h0|aa+aT41i72?-2OMpfNxeAu$84;aATVc*eaAV;9H6raFHNq zrG;7e+f*)Vwb1@=-wQ5lwOQ>gT-NH&b6IN_mCN2q_{}*kyG7x$cjUROKMXF5L+MG! zX&ny~Xh&8#y)zf5KbA^HaIgtGb24kd`N7LKy3H9!V&+3E#w$Ua3(HPRe|A^89G5yV-8(^BMv&W(-`6AjQo@P)r6herLzpMJWH z;nVOf>u~D`4FBjHJ9?Dx4-@_oKs(J81;0kjGGdq!enwdeMQbktY;mDZAOU+tUr(KFnBi0|QAJlG=; z?T<>UuspOeX3F`k6RZ<4=3{bWevfj3%Ltf<3XiALD~)8vf#nC*BeNAh z$Q%pNWLU~&!0u_H6bu;1n?jI0z5Ren3Xpkd$h)kQ$69j3{_a}KJjq&Rt;V=(au$MT z2)~W+Ph;FlF4Ug&{ZD>+FZ6e79cD7iT5m19Ek};yw$5iZSr^h!QT|oJzef1y3BSES ze@AUl{uMb~l$NH>gaI8fFTHG@78XsQswi$-5BmIZ+)INh+6Az0m9NUN67=vA#g7*h zsK8}8gnv~Q_y%i#1iIM(&!oLUVAgJR_h0%Xr!03@)9!1$8+|cHymmGxf z3+jHrlgy+;G{PHzSr}tseL&_IThZq`l;UqI#C@19+fJ3ZO5+o>@m;mCfYDo@p^V=8 zy!8d^i)~e;sM~{z6xNq97FoNuzM^RNA1K=WCpms^eVuCeAFA5D^=-;UJ}S`et?%R$ zo~`c}RHWcPE>QD}Sv{>-%kOFtC1}N3{?oQaiPDO-xQD0c(&ZxOru93zcwe-L60~A1 z|K;9@62DkmRjifRyeJ{j)Mq*2ng5#b-{(Y$9~4pItGp-?j(dFx$k-m5&x88fNz{)F z!7+_;m(gGn*YiXZg`$KcSFDv#v6laqZj9aX9*}6oTK*e#4=9baVlDrj+E}nLB)MX( z)J>ulYul(up>B+PMGC10<^#LrkNG@jNwzBery$Q+>M8Y-4xvl<8{vN<0^0^RqY9za zS2~p0B6)KH#IJ<^nee|rfROdre{V$!DJtROK?zmhsNf?og#VrJf8@B?zqBHSl#r4b zb4uaBfXiXQ*EiWJfiObg+>>}F}WG@=EdrO~ATEtrX55{aNAf>s7- z!Bqgz0Yo+iyzwXsMd8{6lw3lc`zRs~{K&`4q~mEMDii{=G=&1RREa(fIER9$964I9 zU(l;ZPHCh$(1KBIEIfy^C_qcIr8!b#TNNpK<_iy~6)7GlF~3U9d4QHqkO5kNnGIJW z2=*L6OA7(ef>i}*X$g*~AQb?#l+6RQbaFvO3c>bg04<#gfEFAoKuc%PuAOZHv~+ff zt|y>qhQ6TxB7l}Ipo`~L0a~JE{Dn??0npNA(&`pnPl8`isYoHw3}_jkh0a9it^l;q zLk4JJpFBYO!*SeQm_$w%vNG`tdGHCj%5NITos4^f-gIFFG3iEmW1u3W(2Z`4F3KLb zg-)ZZx(Ad-8V4)vt2P#HjLq`KxKFxYdZ4X}6fo8+rAkUFQb=26q!#v5k@`{koc#-t z`bp_2X&YV3gNaa1gx>8T^>Y#o9uf>5GU8!E2N2=FJW~H#D^f_WNyrA0a@jz_Aw=j& zgkCwE{&!ZSklvS&QzU(ugXz9R=tBgLswnMgIgfu=MGEN)OzBG*qQ91Qw}NO|o2)3% zMTig~j8lWH>Qx}Rq5z^1*MJHlL6jUoJ|wiJAd>9Ds11`w_^U7MPh`S@!X!HzLr_UWtT#+J}uSoGk z2}IjyT8}J4+u+(kpo8Y!*0KlgtANiv5FM7^|lQd(KSjul2A>AsYIyC$wU8VDpJ^P#vC@tu2`Xt?{HpBBes%Br2^&JmGK}waw#cFU%K#j3uw&TFEy-NA9T#G`e&okpUDC=x!VVyfEYn$CR>wK@2b}K0{w(ncyEZa|1&N39#q7W7l;Y6%I z>=$ztIg1qLNd$bzS@z>T=pc9~%I79gVFWjs(Cb)2s6U(v#FK^LWp;rQ)viUS3n)=f zkm+X^=_Kc?^ivwmv~i)@SU^;}of6evW_Q`$`Gm06wJ1=$&(P4sd*CcIHi-wa)E>#hlHF;#*xVfqkS6j z61ej?iLlYa&|iB}CR`eXTR{o8T%pn7bRsQ*K1w4^)Dli>hj2&Bgd1%i({>q(ae2a7 za-xxaoFW>XnHP=hxM`UPXQ>WK`?1tPX+O?hX`gDZY9$g;2c@u*2xk-FQX*W~hR{Pj zeD>+~8O#=YZI0cYM}%{Ta4z_U9KrCvTzbMj$KHsCHRT?*iU{Wu;R5+#vKy`>J4=qF zkl!jvN&Cyv6ZRABi}0|;xrbdsgo}u9ac*WMPf}t$+L`oUm!7bnVqcDjotk^t2{4MbRv9leGKS1R~+ zLm|G!;z4gRNGma*@)**I5=bZVAxs`6)xzmCN|%Kag|aOEHc17}k#_KHZU^5$jpQwS11`q{ zB$Y5p-8RP6Z(|%dP1{a-l?9RRpsu?tr<@#k*W(9~7@X1|TmU%MK*>f>dsqk@l>D^g zpjz9+xD6n@8iMeuw&Zk=@G#Xoa@uNqL};wtY5YleTW@_-FR1?5e(T%fWjOmyX5V-j zs9tSBTf+{t5fY4-ZIFd=2WELhFhDj!V+JX-Oh1lAH^9soUcRa`f=L7t+z=J3RHfn2zXPdq2Q*A1fky9l3zIC zAs2S!x78R$XasB&e-&YdxU?zMctips@!J;sM^1*F)c$|U$$&`tF4Wa;LQN+Kb?v)Q zvk0@j{?|gy{j*Rv{+UpV36FMf$3!8@2=~ALFPJDqC8FxPi9*zWGf@aY<+r^B{|zR2 zvTdH8ZkwkEJLU<*g%e0KM1Z7tfFBVMHFApZ0-9Vt9zq@mNX_9D{y7^H(X}bK9w4~i z34(jLC8IvVgFM=i(N^Q80e-yG__H>SZwl@vVhS<+SDXyx-?rd?;$%R~ZW*j+-wYN= z9S5C*DjnMf3$aKrScqlB3St$p_N&2q4U@cpNj}3Q@BhwV-9y|5s_|eOXEH7%Vg}P&u0>D<2rDVqmrq#5KTNl@ZqhQ&mY+MO?ROuxf!}YXmCU zj3foaAR_=Bk^)Kj9q5p#KLZ`KABF%E1GF24c5MP3MD{b#31hKf*9~Z;PZ3g90Rb=; zr1pcoxGX3=0^IQ;{4#Ps(`+Fb2>OC#1UKCS^aUc>R1G8{76pQKRAa001fg;7PUBDd zg5)CT3z7%Pi{$&Z7yrkc4AXyOy^umXKnESz20ElD06OU44$vXb03d=6{Uy*LrTzqT z5Xip$`K;lWy*QF!m?82VphGGV?oaVA03A{lsrDV{klNpX4ypeQ=pZT>!fXK@MBrio zuRjpw4$uLnds!JdDLw#nAbuUxGL!*aw7h`w5~L*ZfI4|{f>J++t|K=CCXgUt0zwf4 zhuD%4!6gDAcVx8HNC=pK0OQ18S*WdjIMNyEvb_)g8%_qK+a|0*G~ZwiNyuM*G-vIs!v<{~=gI#vnmf zH8O6yGe#I@ zQEg-s)y9z%NRWE>XHJIw-;(huzHu_V{gbO2Ngz+zbX9{=G~kp0hWIyK)e!JlZ;jwK za8*MBJFaTvA_05^|Hf5~TqU@wA@EZELo(+tn{nh_0$hrGhs)mxcNG0=xcvRka0y5w z{xMv>Ak3Ngces2_xc`}d1uowq-|xUBHS)_hS2b$aH&-L9p@3}HP;ZB9Ij zaCi<$?}&b@k&4g=_$K}yEKxKlaMrV#-m}HYaOm4IVBS8DMIG4!OZjhLiDDq!6*$1R z!4kzp0811LiWPMn#r7*$s=$x}3~9lT#$SLXA>I?kf#M`;MS)jc!mB-`3`2@Aqy)TX z|K*$vC_$7E7`N~?I;q2uDh#OsblP;D|2K0oprp4mE;czCAkA-M28o*gJ{be*EJ^`P zhvJs=6VintZ5Yzo6e9>F{r?vk0}2$&L2072P+;prIFbba?zlivAO(Bt`~@p~oV7~b2KoYfC zCqr(3T$(FxD@-L8&iY7c7Zs+_36$jwu zG7J&Q+CbL-#`y~>5y&%%V82nxsFd&a8U(lr27V*yhfsA3`jIL9_?E&MFgqD{Om0r#{g$n^Y{_z2Db$Zkh`TaAQB zP{?7Y@n@OV6YMvt3Dt~hVcI5RQ2l|7VJDwn=kLiFP;KArH>z{Xemig3Z})Ga?IGB2 zmmT|!8X(NM>)+UK)bOVLcKgYGqsE98P~)hHe@@1Lx=C0^`0wjzme85UU#}zJiU(u= z(JKLY{<@A(OQ7pz)XG06V?Yt8Od#NZ-X@Vo-6M4E^DkI^)NiPV->p6h1Tt=g4x@mO zwnB#?KNt$$w)*gv)%X2o^+iAxLsXR;grS#eolTqDQR9|KwKvx{WCu& z>iy;_`UqB0AYm2xZ!H)Chbk1XvtTwG(YpwZK|75{qH7YK=Y#oz_10khkXf#Vqqw5d)WV_WDMvtXbCW8$?Y*Gz|a*K+Ty(+WbFPo zk};sqqQPDXt+=%fgOXt=35Is6Ul7Q({*TER(3)s1Fd(qq*+T_8%7^(1fB?N)`(lsrf9S8Mjs7Gd4GOs2bh`7 z#mf(9Vgb7^pk(+(bQPPTs{*2{B8aYHOG<=NJ5c2>qH82HevcIRNp#zmwgcU{ZE3d% z8D8&5?3<FZ@d(xLykDbl5ZN(D%^5rG?&hX+hmE)CogfV9fvJWDMwMXy6?~1Mk?T3FwERUKk<}U;OuwF;IVZ zN1@+txuekU(C^V7&>zvC2yUs(_=zeIK~anTOw@q>LU?n>5EHdxc42lC(PBt2AnzKy zy^j%)3P4K>|jbkZi_o_V~baCmvK1n;)1gRm69CJJK?lk%q`D5*+}DT%{|XMd${SjxZym{ zP7r~E5`+#CIOG^uaTIpCo z#2_dQ3iJvA@?TJM3}lW=ost7=B2rj6sh>T~7&HO%Fu;`qjS?_#XcO}=v;-g;-hpq- zQ3BwM%o0n3$*v%lA;yBVP&s0G;~+jO{%?LZ~LApJx$fjNm`$ACfx z7%mKVFi2wc%m&y_LCPf%j>SE7APlA&FjzcNV%ZZ(1D5|k0Z3h>LxaAE;j42a1C zsh8m0TZB_e034ZucylRXS**5(j)Ke_=<*A2Nq!|JA|@u@1s)C@R$~N+Xg6cIAy8_B z3?qaQ#)z0wP~w~{ovm01VdODq^;NaF>~TI^yx)G|`S#1HA94CyBXA9@z|b-b{RTseFth|iGca@)hGt=C z!<2$vMQdje+si@@tiYW%!l0Ef$`}<>3R+by!X+%u-O}y63*Omn=R;uh3otY{yESg2 z4DcN_j5E6DqYVP>`GWe1f zSl5;~88Bz+ZqA&_1U1+!7=|&x7=o4k>&S93=LqG&{?x9ks-=W;b7Jb^-|A0KRZGU% z!P#vFV}>!uSb%X`61QNiFgP7mElqi8qwUKC4a1pIP=P-^+=0SuerK~$?i2&~AFQHP z7+Rmg*nm6OV$N%;YAIkTh+$}LYmoLBho5ehi*Y0p{i$W^b0!$)T#U)~$kol=%x&Dv zU2L`RJ`T7Uj2p%sg9l6O$bm78C&tTARZH94LJRNgLMWvq<#67{$r0y-2Y1ybsJ(-; zr9C)bfuVaa^Z=a1V|-xf{$?*kA{f71A`v3dtv+2a0l65L?Z1drF+sURs^6}`n2?{V zu@P>)Ih+DaC?*UOj*0lS3fs;neyPItLpxGMOTp3618;8OfKveyb&xi9#~G_=ZT_xi zVTZE>vL(Y@#6)7EfZNU7&C>R~=MTEFy-Z=~3k>}}gNeb!V&cH(4`D82u3+N9vj2u| zTM}* zLtx%MfH@>Ag#pYU<^}=JEPU`dAh}Q2-2h^@*6%Q8#8_2JWotQM&GF`Wm|@H)kti4n z;jgU^jbkP@)ptky+iNHnGf7y$K(T+lvh}?w%rvi40p~`LT><7P<{9QW=Ebj*vGa*vCgX?p|G|*Y z`2o%-z`+R!$pgL*{}tvQyl3yuklzx9yziGGf5LnQyRjeUPTkxFcOCNu^Oc&2nwWYQ z^=@hsYKVFd^pcF{s%`L&QkLP9#7iN+fZ};E?H|#6#JKiVk%h8aOn6X!X$JLtjWSq|BtJ zNX1E&NL5JHNYzO-NwrD!NDWBOks6VjkeZQNkXn&OlV+2al2()Uk`9xOl8%#3l1`D% zkS>wlC;bgjjz1%PLHdCVA|oTCBVz`H)dFN^$TY|d$sEbT$l}S;$uh~Z$nwbw$tuaJ z$!f`($XdvH$>zyc$)1qCAxDrOB|i-~^jydT$uE#cl1GzYCXXjiCvPI}C0`}~LV==S zqTrz5rw{}TKT;Gj6tWbG6v`Aj6kZe&6vY%H6i-3&{|QPVN=Zs-N-U)cr5dFMr7opD zr8#9FWh`YW2qe@XXQTI_V&?IO|G(9+RXGAljS<&2R9yA|X7%hsHLCd1$(aLC5v>w_G9e_?j z*MXymdGsIXSD1qsN(?oI7IOqchhfEVgZ;5G#suREb_`d6Wp2QX0-#;PyvDr6yvKaR zd&1kwc4z%(H=VKfmm7ic1BqG+ONVrk-NF4M%*G}BDcOw-KL+@hJM zS)koTdytltmYkNFmX`JitpM#=S}j@w+H%)ArFW)4o4U zaro%rM6>;rYXl z55GNf;K{~NHRkJGc!pP*-_=cMPN=cebO*Qa-+ccOQpccaJC2ha!6 z!}JmK7wNCiC(tL+r_pE7*VA{}EK~K*@k$Krvt#Xc!JNFf*_+ zurcs3@G%H5s50m?m^0Wj;2C@wLK(stA{Z_*WHMwi6f<-)%rHDTw)Ys*G09_k$DEHv z97{Zwd93T$*sRHBFZn4a>++o>ZdCc;fk(EK*5j-vSVdXISkJIZvP!dBvbwPPvIet8u_m)-v6ix4XDw%~WUXecWvypz zV7<%w^*HTursJoN%N;j4?sYuwc*gPe;~mGlj`tkzJ3erH@c23#1sgk?GMfsU8k+{2 z7Ml*6E}JV`3|kRf726=&6x+iS#3!gvu%6&Pp>)FVgy)Hb6NM*QPTV}Pa^km>L?k?awv1?aOiOua0GG$bA)h&afEZEab$25a1?QraMWs?nvWDQhf|N!fb$%u6{j_)EvF-= zGp9GFFQ-2z%o)m=!Fi1{i?f)snzMy-kaLK0m~)hKmh%?pJm*u+51gMkzi<(8?cyTg zV&P)tV&gi=#lgkJ#m!~J<;4}xRm)Y!)xg!n)xy=r)xp)t^_2Svw<5Paw*$8mw+pu$ zH=f&r`!aV2_dNFp?vLD`xxbzwKDGN4$tn6%qNj9DnVj-G6?rP>RLiO9Q%`t^c#u5o zfI0OdPb5z?Pa@A%o)n%mo^+lJo@+c=JUKjhJo!8YJViXkJf%EkJkvbC@jT@Do#zS9 zGoE)mA9z0T67%lnJ;Y1KOTmlc#Q-OdAg=_k6t5z$60bI|AMZup9Ns+M0^TCtD&892 zI^J&HUfzD*K|V%4WSF<3jB)v%KYa1mi!L(pe3LqpeGP0 zkRXsKa8)2hAWa}opg^EVpiH1bpi!V%pjDttphsXqU`b$E;DNw%fzJY81&IWA2_6(A z6(kpA5M&f&7GxD<6I2jX6jT;e6;v106x0%g1v3O21#b(^3oZyQ39bmP39bu%7CIq> z6~YNw3)u?U2{{Nk2{{Wz2^9!+2_F`w6Fw@;Aj~MtB+MdwT=<0WNnv)t=f)+>4eIv* zetu97M@ZO2*j*Se>?!Om>?<5994>r8I7T>5I9WJVI9)hfI9Iq;xKDUMcu;s!cwTs2 z_^Sx9$ZioxWUmN?2$cv@gieHBTm7H^pbf=fvm5*TwINKM;Q`{#5*}_y_S%XNb@2KErT^@eIou zt~10-(Gsx|@e+v= z)e^N5Z4#XlHzbB6rX&_5cS!<=izJ)mNl8vgZb@Ou(~{zna*}5yl_aesttD+F?IeRF zVaX`TSjkJ0DUxZDnUXz{eUgKcLz2UiE0SxHk0f78ev*Qu_DLO(LP(*csHH5WtfXwD z?4<0a9HgA2oTc2P+@(CEJf(c3e5L%Q0;LM1TBKT~I;6U!dZk9CCZujk%}L#sT9djf zbzkatsVCBVr1wehm!^_FEX^j(F3lm$B`qW^DlI0hBCRH^DXk-|FYP1kEA1~GBpo6h zE*&9VCp{tkNamo-AsI3mN*SaKMuu93PsUWnS0-I1L*|-Hj!eExkxa2nugtQ{d#pBA z7psRg#2RBwu;y4RtTomKYm2qVI$#~K&RAEh8`d4`fz7~HV{5SW*hXv%wii2qy@4IW zPGE0i7qCm%b?ja2XW2cn`(*daQpp~cWd zxqEU?AXOquXpItfoUV&EOumYU|g94KRtHN;wX$4~i zZ-qgH8ww)|;|ezwW)x-><`ix#%quJ?EGaB2tSGE2Y$)7U_)U>qky(*NkxlWWBB!FD zqKM*YMM*_zMI}X5MRi3TMLk8lqNiezVu)h2VvJ&v;x)y7#WBVEioYp7QhcoVTJfFY z2c^AA2b2yekt^9LIVd?QxhT0S;g!6Ue3kr_0+a%kV5JbHP^ECC3rZK2B9)?*YLo_* zZYYf?jVVnk%_}V`Eh}v(-BWt1^g`*S(mSOO$_V8n%14#ymD!Yeltq=#DVr#pDO)Jx zlx>tjgDd#FTDmN?lDEBK5Do-j;DbFf@Q2wO+RfSk(mkLIO zMuky@U4>soTt!kvT181kMMYgDT_r;$OC?t&PbFWaP^CzvROPx#xk`mfwMvajol1ks zlFA<{FIC>Cyi@t8N}{?~b-yZ^DupVI>JinWs!XaZs%KQ?RTWefRkc)&RB@_qsvfGI zs@|%wYM5$-YO-poYKCf-YOZRpYM<(W>X7QF>V)c~>K8Q{HGVZ6HC;7*wR37FYUXMd zY5{83)dtiasQsq)NbQN*bG4UhuhhxaPpZqRXRGI`=cyN}m#CMjm#bH)*QnR3*QqzE zH>o$Px2m_Rcc^!&cdP%V{#pHt2C>F&jXfIV8dMrc4H}KZ8q6BUHBM-7X`Iqf(9qNX zo&yaN4I2#?jaZFK8do$DHLhx8Y2<3;Ym{qLYSd`l(wNs+)L7P7(RiitM&qmIE=>|m zQcZGADotZe6HRkXD@~lHwWh7+c})jRM@?r<7fp9fyr!q7w`P`Roo2melV*!%yXJuA zkmiWyq~?_7g66X3s^&e-2U#|9nwN+9o1sj;?m;Q;?WY-64#Q@($+H5ve3e5 z*=pHqIcZ(ex~vtim86xTm9CYcHKcV{>#H_{_AzZHZC33Q+8o-P+D6(@+D+Q?+IO@U zwO6#)weM-)*CE#7)=|{4*KyEs(s9+n>v-vS>m=w@=nUyn>(b~R(WTdA)Me3S)jh6z zLieODhc1^cx9%xjK3#rYAzcw&GhGi|PhB5fKixpx3%XIdF}hcD6Ld3lvvhNG3w4Wi z`*jC(Cv~TF7j>6(@9RF(L+c&Y6VemWJFO?KC#R>Nr=;hg=dBl}cUdn(FH0{+FJG@n zuT-yGuS&00pG==ZpHd&GkI|>rKdgULpF#haKBGR1KCAw5{S*4^`W*V4`rP`u`u6$` z`pyJ5fxfFgUOzxTSU*Jnf_|iaynd2?vVMmCHT_2YF8v<;Uj0%1S^Z`GuLipeNDTHE z>^C@QfHc4u&=@cpFdG~gtQf2tavE|O@)+_P3K$9+3LArIaMEzzaKUiV@SfpQ!;gkv48NWuK6l_8 z={fRq4Cffnv7BQ&$9_)voXR=1bDHOL&gq{sI2V4d?%akEi4kP9*XV!|sS$+{rICb@ zol&w;lTou#t5Jthw^5%_ztJmW7GrJWO5c>yrt_wEOqWcTO;=6V zOz)cBGkswC(2T;2#f;VLgc-XTmzj{6sF|3Vl$nf~vYDEhhMBIJzL~3;ubIDDfLVmu zC9@Q>0<&VX60_@Ob!Lrb&1S=9qh=FkQ)aVfZ_M7By*K-0_SJls`EGM=b7S*p^D^^t z^Gfp?^Lq0p^Jeo07L*oeEKDuTEG#T=7Pc1l77i9^7DEjXwv^Y8(a5Uo_aLzavoGZ>9 zhsSy0ym7ubKU^R#2nXXraizFUToEhq&Ky&vAcPAG9X5 zCbPy^Ggxz4pR(q$=Cc;FmavwxHnFy|_OuSM4zs>s9c3MBec3v}`l@xKb(3|Ab-Q(! zb+2`w^$Qz18wDFX8+#i^8y6dQ8&4ZAn>?Edn~%0fZ0T(2Z5eG@Y}ss2*y`HCwi&kV zwjH)zw!O9kwnMhVw(rifoYy*!Kksqg>%8yzfb+rU;q#g2htA)#+he!aZol0jJ90ZJ zJA|EtoxNSM-F>?Uc8~0y*gdy7Z?m7bU$9@YU$tMi z|K0wn{d4>G_8;xPI50V|IIuaKbYORobdYvXa!_?pcQAG^a{wMNhc1U6hhB#Pharby zhcSmqhbf0?hZ%=k4!0fV9Tpvy9abDx9o8N9J05kUcVu*Ac0BHQ%8}1ez){pu%u&|y ztfQi%nxlrJouj*>hoh%skmE(iD~?wkYaQzy8y#C5+Z_8HZ#WJ+PCL#z-gf-#_|<8b z6NwY#MC)|KiN%S{>7)~%lYo=3Q>asz(*>s}r)Z}br#PoePVr6&PFJ0hozk4rovt}$ zI}JK5IxRV^I;}h1b9(CZ!s(^cJEsrMyPfwq?{g+~CU<6Y=5gk8=64o%mUC8jHg-01 zHg~oJu2pAeSLX=lc;`gtWal*JOy_LpZs#87KIZ}FA?H!&3Fk@Y-(B{&kh`36;c?+} z5p)r85pxlD(RXoo@ps8|x#p7XlIK$BQsPqT((khB^3e5w>p@piR|;2zE7}#~%Im7) zs_Sa%>ggKkn(f-;I^+7njl_-GjoVG!EyXR(E#2*!TaH_q~5w??-nw-&cGw>NHY-9ET|a{KDO&;6h~sXLWB(w)wo!JX0lxcdorX?G=e6?av4 zJ$Ezr^X?Ju7u}=WW8E*gr?{uPXSx@<7rS3~pLCycpLM_Ge%t+t`!n}F%@5cAx2k;~K zG5j2U9>0KJ#joQ(;y>fRc)q(x?A_zt?>*=}<9*9} z-h0tU$VbFS)JNP$(nrb%>m%=@;G^iH!asm;1leV__4U z`R()D?{~lfq)`=$Bi`4#vT z`c?Wh`E~n^``z@L@|*En@>}&=_j~KV+aL1Z=YP z5C1^_EdOl(T>k?9V*l&@W&VTy>;At7910)}AP=AlKm||-&;;-Ys0HW;_yqU{_y+_9 zgam{KLvVOzzczw0}}$10@DIB0t*6*14{!d1FHjv1E&LL1Lp!)0)Gp95kwY55kwV) z3c>_21Th7%1aSqO3gQdW4>Alg4l)fg3-So^3JMMi4GIs63%VSX5VRb$60{z4FX(>I zgP?~&kAj{AJq>yh^heO^pf^G9gFXf`g4iA5;M2k4!IHrW!OFp^!CJvO!6v~V#V6P{ z*e*CUI6OEa_)>66a6xc!a7pm>;JV<(;O5}*;5)&K!7IV*!S{lHgZIM+;6pGuOa-H0 zG|U4l!#c1h>;?P4{%{Z+0*Aua;AXf7-hl7I_u+@|WB3{TJmg>qYY2CUdWc4dR)}th zL5NX^afo+FLP$o)+mQDmA3{Ed5`_|nl7#LJ-5+`&^k67iD0wJFC{-vj6cvgNr4E${ z)ehAO)ekicH4e27Js)Zx>JsV}>K7Uq8XOuPdLcABv?TO;Xjy1|Xh-N^=x?FFhdv2? z7Wzl%tI*G3L}9za4u+A2QG}fcV-Mp9;|{}y$%UzfX@+Ts8HbsMS%h5(iwuhiiwnCH zmLFCaRvA_kRu|SD)*03lP8v=YP8p62M}?!qsl#c)kA%~O(}y#JGlesUvxc*UtA$&I z65ke6n5n>S%5z-Md5v~zg5n~ZgBc4UPhg{d-1?U(u))qDKAP~bi9~;@zKTKFFw8a z;^M1|Z!f;P`2OO@i=Qrji6n|7j@%UqMed2*A9*m6H&Q{EK>R1$0 z6l)Y))QPAwQIb&#QOZ%OQRkveqRgT!qdKCxqPnB{q6VXGM2$p^M@>fEjGBs?jhc(P z6*V8V5VaV!6txn)C;D*ok!bqpW6{jfoYAMEd837*MWUsnWuxVzm7`UoZK7SG-J;#2 z{iDO9U4c z#+Juc##Y5P$M(cd#7@Od$Iiws$F9Y0#1X|EildHWj$@5G5yuh79mg9d5GNdG5N8-? z6lWS|5r>Pjj!TN`jeBv4>Js7->Js&(!I%;lzAJ)PM6QTk5x=5;CHzYEmF_D& zSNg6DUKzeJc4hp^r}&fc`th~#_3;hy&GBvV?eSglz486=1M!3L!|@~Wqw(YMlkqp> zr{ZVgKPFHlP$nP~&iKs+OB10l$B1@u6qH7{P z(JRqA(I?R_(LXULF*q?KF*GqE@j_x`Vsv6n;$Y&9#F50Y#L2|@#Kpwr#EryziBA(> zB)&|1m-rzGk%US@C($RdB?%-6Cy6ATPQoV1Cn+SEB-tf7BsnL!C3z%yC#5E(C1oUK zCFLd+Bo!vzx(Z$8yQ+Ov=c?XS!>h(u&90hXjk(%#^+EE!$BvNYN>*0d98>}gzSJZb!CLTRFD;%O;qX=&+c z*V1y*a?=XZiqlHduBVlyRi;&?Rj1Xa)u%P2HKsMEt){(Bdz1D)?PJ=P^u6f^(hsFm zrX$jiq|>J#OJ_}IOP5MlOjk}^Yr)WpVGf%?9JGpaVUc)gD*ocLpVbuLp4J^!yv;b!z9Bd<9vog zMq@@(Mr%e#MrTG>Mo&g>#z4kk#!$v^##qL9#$?7+#`{dNO!7>sOk^e|lOdBSlO^+H zCP$_~rf{ZcrbMPxreUUKCN9%D(>c>SGd%NRW@Kh`W@2V?W@=_>W?5!sW=&>&=3M5j z%=yg4%$3ab%#Ca0*UnsXycT!u(zPqs60ap+OS_hSZRpyotYcZySu$C&S!c79vQ)Fw zvI4UzvzD_(vQKA=WlLmBXUk;EWh-PWWh-Z^WUFUuWNT(?XX|F`W$R}fX2aQ6vy-#a zvNN)?vWv5?XP0N!WY=Z4XLn`yWDjN!Wv^%dp8X{IY4+P3qMZFXCv!M+xN~@N_;Unv zByyy4usJF@YB`!Y_Br?*&m6BD-<(T1S8~#FGIO$WigQYH%5$c2W^!)j%;((6d6x4c z=R?ltoUgh2au4K^=IZAfQSS(mBSSeU9xL0t$;9LDix|0su$`M>J^$5S{C98?Ft+`j^`+}yu752fE+Z-1TXvxAVA=69tup7b%Vk%}63VWYrIuxsWtI(bQ`AYeE z`Q7q|<-eD|Dt}x4zWhrCQ3Xu}V+C^sO9fYjP=#cLafNAxd4*Mlb%k?na;7n=3miyDEn&M=QrGrz>YGpH{xD zd|&yYYIoJ4DpVD36@Qgrl}Od;Dr}W}l|q$fm3Eb0m48)W6iyLRst;C^R+CjzR#R1@s?pUn)wI=g)%4YJ)#s{>s!glStF5XX zt6i$ys=caxsza*7t1nc?RL4~pRaaHlRM%FwRrgmRo|{&tG-)(zxrd%-kSY2 zhib@csA^C(f;B=lA~j+)5;f8_GBqYOJ~bgVc{TYpg*7ELWi^#GRW&0u_iLWjQq)q` zB5KjKG_^-+>1u^*wQ7xO18M_ngKI-;BWfdSqiPFkyK0B(nCn>Uj@O;6SL;7hRWFmt2=xcdahFuB5K4uA;8C zuD))(?pED=-JQCPy2o{|>#6FI_2_z<`os0i^~dW^)brN!*9+Af)tl6t*IU+G)%(=@ z)rZwzsE@3VuTQK`u3xX;sJ~zTu>Mi~@AXgWpVq&q|D*nO{hRvt^&jd#*MDtbZ8+T^ z)*#U!)qrhKX;5#_Y|v{kXs~F&HP|#bG&nU}XozfxYDj3vXeenYYbbB1Y-nm|ZD?

EaU*FXStCUwq7mIl(@5JW(5T*M(CFLf*BHp!r}kSu;hmP_uHgO0#;iX0uMSNwaygWwULwU9)?$ zXR~*6Kyy%YN^?$gUUPnPd2>T^XY*q7a`S5QM)SSqr_C>#Up9Yg{?bC+!rH>t!rsE! z!qp22w68E6@58EqMBnQWPEnQfVCxz%!~WuaxUWu;}U zWxZvi z+KJmq+V`{{Y$t7JZRc+1Y3FS}-HvTnX*X;)ZZ~N+Yd_!a(C*Y8+J341N_%2^a(h~P zW_w3_XM1;hU;AMDaQjI6{SM-e10C!g935O8JRSTULLI^#S{+UuUL7eNsU7JZ*E(`K z@;eGTx;hp*?sh_*dph@Z9_%FRr0k^X1SUyH0nBcj|y8^n>x-z=1b>(#Bb(M8hc2#$^bhUMLcHQl|-}SKT_pZm?#NE5Q4|S7w zQ+CsKAL*v=w(GX?e_89h9_t^H> z_c-;q_TYPxdam}Q^rZJ(>&fZK?P>41-Luxat9N%V)Vr_uU@uuOdGEsl#ondfmEQHUj07(e*J;{!Tpi_G5vA<$^EJQ8U6MBjr~pit^Jez zQ~eA5%l)hU5Bq=be>#8|Kn+k2&<-3PI5ogKaC+d(faHL}fYN~KKk3%K=DAy!1aN$fy#lZftrE3frWwR11|<%4ZIn6Ke%fU8r(a0Xpn3WGe|plWboJ^ z)1cVknL&xcvx6FgCWGdK7K2uUj)N|PZi5#F69$t8QwGxquMOr5_6+t8_7C0|92p!R zoEZFkgZ+lV4c{AnHv(=1-w3@CapS^`x*MxQq(fXo+(SG={6j)RqC=;LY=KpoFm|@s?*k#y#*mKxt*nc=+IB+<47#Z4ktI-|OydZUJ;=SGc2O-9W|%||Uptwy6qvqy7A^G6FuOGax(>qi?$+eSM^ z2SB6$>S;GY2)eR*T%EPbH;PW3&sn_i^ogHZ;sy|e=z=N{PFm+ z@pt1N$3IW(njo1VouHVYn!rrZOz=+dPY6t$nUJ5*p3s}npD>)ToUop-od}<}GLbn^ zGI4#PVxoGYZlZCbWukpzd17T^ZQ}04gNa8IzfaOmo}KiZOrA`cOq@!Get9{Gi5W?Gqp2qGo3TtGXpa> zX4YmN%{-oYGV^BU>+HT+mf7R8CuTWjxn_lCMQ6okWoPAQ6=$7iU1#yLp0i%FF|%>A z$+Ky*8M6hmMYE-|uV>%PzMuUx`+4@u9MK%{9LXFsw|8#e+`+j+b7XTAb3${-epcx7cqP-HN)^bZh?Bom-2yR&K4|x_9gTZOYpc zw;gWB-j2I{`F6tXtG82cr`;a9{brtdUUpt?{_MQcyz0EhyykrHe8v3Y9f>B6&ci#8?>xKn{LYIzFYmm$^Y+fWJ0I_Sy7T4E*M(gR zyBA0n*cT)hq!zFXatjIznhQD$dJAR?77Mrq-v$4Lz=hz2$c31NxP^p;q=lM=x`pS-QSdv(&oO zyELO+H%Hn)^hH0 z(Q@f>?Q+v{_wvB<#PZDY((&1B7H z&1KDf&3g@AyR>$7Epx4Kt#z$yZFX&W?d96Lb<%a_b(bPxqeVJ->Sq_oDAz X-bw@9Mac69|4}2het!G+Ui|+9fQCUF literal 0 HcmV?d00001 diff --git a/vendor/lucas-clemente/quic-go/docs/quic.svg b/vendor/lucas-clemente/quic-go/docs/quic.svg new file mode 100644 index 00000000..a37e0af4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/docs/quic.svg @@ -0,0 +1,65 @@ + + + + quic + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + QUI + C + + + \ No newline at end of file diff --git a/vendor/lucas-clemente/quic-go/example/Dockerfile b/vendor/lucas-clemente/quic-go/example/Dockerfile new file mode 100644 index 00000000..d0723ee4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/example/Dockerfile @@ -0,0 +1,9 @@ +FROM scratch + +VOLUME /certs +VOLUME /www +EXPOSE 6121 + +ADD main /main + +CMD ["/main", "-bind=0.0.0.0", "-certpath=/certs/", "-www=/www"] diff --git a/vendor/lucas-clemente/quic-go/example/Readme.md b/vendor/lucas-clemente/quic-go/example/Readme.md new file mode 100644 index 00000000..f8785233 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/example/Readme.md @@ -0,0 +1,7 @@ +# About the certificate + +Yes, this folder contains a private key and a certificate for quic.clemente.io. + +Unfortunately we need a valid certificate for the integration tests with Chrome and `quic_client`. No important data is served on the "real" `quic.clemente.io` (only a test page), and the MITM problem is imho negligible. + +If you figure out a way to test with Chrome without having a cert and key here, let us now in an issue. diff --git a/vendor/lucas-clemente/quic-go/example/client/main.go b/vendor/lucas-clemente/quic-go/example/client/main.go new file mode 100644 index 00000000..23f045c8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/example/client/main.go @@ -0,0 +1,66 @@ +package main + +import ( + "bytes" + "flag" + "io" + "net/http" + "sync" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/h2quic" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +func main() { + verbose := flag.Bool("v", false, "verbose") + tls := flag.Bool("tls", false, "activate support for IETF QUIC (work in progress)") + flag.Parse() + urls := flag.Args() + + logger := utils.DefaultLogger + + if *verbose { + logger.SetLogLevel(utils.LogLevelDebug) + } else { + logger.SetLogLevel(utils.LogLevelInfo) + } + logger.SetLogTimeFormat("") + + versions := protocol.SupportedVersions + if *tls { + versions = append([]protocol.VersionNumber{protocol.VersionTLS}, versions...) + } + + roundTripper := &h2quic.RoundTripper{ + QuicConfig: &quic.Config{Versions: versions}, + } + defer roundTripper.Close() + hclient := &http.Client{ + Transport: roundTripper, + } + + var wg sync.WaitGroup + wg.Add(len(urls)) + for _, addr := range urls { + logger.Infof("GET %s", addr) + go func(addr string) { + rsp, err := hclient.Get(addr) + if err != nil { + panic(err) + } + logger.Infof("Got response for %s: %#v", addr, rsp) + + body := &bytes.Buffer{} + _, err = io.Copy(body, rsp.Body) + if err != nil { + panic(err) + } + logger.Infof("Request Body:") + logger.Infof("%s", body.Bytes()) + wg.Done() + }(addr) + } + wg.Wait() +} diff --git a/vendor/lucas-clemente/quic-go/example/echo/echo.go b/vendor/lucas-clemente/quic-go/example/echo/echo.go new file mode 100644 index 00000000..0f39c127 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/example/echo/echo.go @@ -0,0 +1,105 @@ +package main + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "fmt" + "io" + "log" + "math/big" + + quic "github.com/lucas-clemente/quic-go" +) + +const addr = "localhost:4242" + +const message = "foobar" + +// We start a server echoing data on the first stream the client opens, +// then connect with a client, send the message, and wait for its receipt. +func main() { + go func() { log.Fatal(echoServer()) }() + + err := clientMain() + if err != nil { + panic(err) + } +} + +// Start a server that echos all data on the first stream opened by the client +func echoServer() error { + listener, err := quic.ListenAddr(addr, generateTLSConfig(), nil) + if err != nil { + return err + } + sess, err := listener.Accept() + if err != nil { + return err + } + stream, err := sess.AcceptStream() + if err != nil { + panic(err) + } + // Echo through the loggingWriter + _, err = io.Copy(loggingWriter{stream}, stream) + return err +} + +func clientMain() error { + session, err := quic.DialAddr(addr, &tls.Config{InsecureSkipVerify: true}, nil) + if err != nil { + return err + } + + stream, err := session.OpenStreamSync() + if err != nil { + return err + } + + fmt.Printf("Client: Sending '%s'\n", message) + _, err = stream.Write([]byte(message)) + if err != nil { + return err + } + + buf := make([]byte, len(message)) + _, err = io.ReadFull(stream, buf) + if err != nil { + return err + } + fmt.Printf("Client: Got '%s'\n", buf) + + return nil +} + +// A wrapper for io.Writer that also logs the message. +type loggingWriter struct{ io.Writer } + +func (w loggingWriter) Write(b []byte) (int, error) { + fmt.Printf("Server: Got '%s'\n", string(b)) + return w.Writer.Write(b) +} + +// Setup a bare-bones TLS config for the server +func generateTLSConfig() *tls.Config { + key, err := rsa.GenerateKey(rand.Reader, 1024) + if err != nil { + panic(err) + } + template := x509.Certificate{SerialNumber: big.NewInt(1)} + certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) + if err != nil { + panic(err) + } + keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) + + tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) + if err != nil { + panic(err) + } + return &tls.Config{Certificates: []tls.Certificate{tlsCert}} +} diff --git a/vendor/lucas-clemente/quic-go/example/fullchain.pem b/vendor/lucas-clemente/quic-go/example/fullchain.pem new file mode 100644 index 00000000..76c34db9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/example/fullchain.pem @@ -0,0 +1,62 @@ +-----BEGIN CERTIFICATE----- +MIIGCzCCBPOgAwIBAgISA6pwet1vq9IjS9ThcggZYGfyMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODA2MDkwODI2MjVaFw0x +ODA5MDcwODI2MjVaMBsxGTAXBgNVBAMTEHF1aWMuY2xlbWVudGUuaW8wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDqON9RKCMK4dHxLTLiv3n+b/v4KCbY +Fo38rxCcv4/qoWI1Zoz4XMyPnTZPrzVMz6rhDKWTve1v7g+itgQDp1OoRo5ihtqC +m9Dr1Ed+qb3hHtFRBBOTiWQy1Y0fvUDYGlSHQ4R7xXYVzCYkQ9zopqr2otJp/9ZA +1Yy3ATITSgcds9wJaAOpkSxCx+D7cqpGbaNtxogRZ4ZT1vVs3l7Kr26fvnALMM4K +nf2Rpq1ZjgPRoLNcfUWCZO7gr+VNCFaI2AQRaAzZkSXAk0B91waTtaFD87kYXl9Z +8Jgx1PhJnO8WBUz/7+OAO6M+kuT78e6FltMN004Q8WmuNww6PzmVwnmpAgMBAAGj +ggMYMIIDFDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFIs3yJaLnEw7MRtNf9EbzESy +TrHwMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEB +BGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0 +Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0 +Lm9yZy8wGwYDVR0RBBQwEoIQcXVpYy5jbGVtZW50ZS5pbzCB/gYDVR0gBIH2MIHz +MAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYBBQUHAgEWGmh0dHA6 +Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCBngyBm1RoaXMgQ2Vy +dGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkgUmVseWluZyBQYXJ0 +aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUgQ2VydGlmaWNhdGUg +UG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQub3JnL3JlcG9zaXRv +cnkvMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYA23Sv7ssp7LH+yj5xbSzluaq7 +NveEcYPHXZ1PN7Yfv2QAAAFj495INQAABAMARzBFAiEApF0BFCWyGIUrJrsYuugt +tshGVdg2+7f6d4B1D/xF2s0CIGGsVL2nRlXJXrkk3aa83lH4HzP9vcQSnMFHdXOf +9XeZAHYAKTxRllTIOWW6qlD8WAfUt2+/WHopctykwwz05UVH9HgAAAFj495IQwAA +BAMARzBFAiEAkV4gbM6hucL7ZwqTzb5fKxYhk6WHr5y8pzClZD3qqv4CIBYH7MSA +P05CXv7tHiHEizIvhWJJvVa2E6XLjbDRQMnUMA0GCSqGSIb3DQEBCwUAA4IBAQA2 +CALjtlxGXkkfKsRgKDoPpzg/IAl7crq5OrGGwW/bxbeDeiRHVt0Hlhr+0XPYlh/A +m8qBlg7TMHJa2zIt7wkG/MX3d9bO2bxXxsdjfMXLtxQu7eZ5nzGuXL8WGnZwtSqz +M5pOF/AU1JQojIhehKCeqqUi5UobxXUm+9D6OVmr8s732X3n/TL6pgsWRhay9tjB +kdZ9TSe0tLYyXnbwHp0rgwNWOMMN1Tc+Fpqc8UlrCq5REb0bLIQ6A2IJH08MEPWG +ukXHPAaHLz9oB1emR3flCoMKB0KrXUpDFXemOIPN6QVBO16LNNuRffKwXnzp60+b +MoB4Krxrab7TzlfT+HnP +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- diff --git a/vendor/lucas-clemente/quic-go/example/main.go b/vendor/lucas-clemente/quic-go/example/main.go new file mode 100644 index 00000000..e83fb870 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/example/main.go @@ -0,0 +1,174 @@ +package main + +import ( + "crypto/md5" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "mime/multipart" + "net/http" + "path" + "runtime" + "strings" + "sync" + + _ "net/http/pprof" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/h2quic" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type binds []string + +func (b binds) String() string { + return strings.Join(b, ",") +} + +func (b *binds) Set(v string) error { + *b = strings.Split(v, ",") + return nil +} + +// Size is needed by the /demo/upload handler to determine the size of the uploaded file +type Size interface { + Size() int64 +} + +func init() { + http.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) { + // Small 40x40 png + w.Write([]byte{ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00, + 0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb, + 0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18, + 0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + }) + }) + + http.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, "") + for i := 0; i < 200; i++ { + fmt.Fprintf(w, ``, i) + } + io.WriteString(w, "") + }) + + http.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) { + body, err := ioutil.ReadAll(r.Body) + if err != nil { + fmt.Printf("error reading body while handling /echo: %s\n", err.Error()) + } + w.Write(body) + }) + + // accept file uploads and return the MD5 of the uploaded file + // maximum accepted file size is 1 GB + http.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + err := r.ParseMultipartForm(1 << 30) // 1 GB + if err == nil { + var file multipart.File + file, _, err = r.FormFile("uploadfile") + if err == nil { + var size int64 + if sizeInterface, ok := file.(Size); ok { + size = sizeInterface.Size() + b := make([]byte, size) + file.Read(b) + md5 := md5.Sum(b) + fmt.Fprintf(w, "%x", md5) + return + } + err = errors.New("couldn't get uploaded file size") + } + } + if err != nil { + utils.DefaultLogger.Infof("Error receiving upload: %#v", err) + } + } + io.WriteString(w, `

+
+ + `) + }) +} + +func getBuildDir() string { + _, filename, _, ok := runtime.Caller(0) + if !ok { + panic("Failed to get current frame") + } + + return path.Dir(filename) +} + +func main() { + // defer profile.Start().Stop() + go func() { + log.Println(http.ListenAndServe("localhost:6060", nil)) + }() + // runtime.SetBlockProfileRate(1) + + verbose := flag.Bool("v", false, "verbose") + bs := binds{} + flag.Var(&bs, "bind", "bind to") + certPath := flag.String("certpath", getBuildDir(), "certificate directory") + www := flag.String("www", "/var/www", "www data") + tcp := flag.Bool("tcp", false, "also listen on TCP") + tls := flag.Bool("tls", false, "activate support for IETF QUIC (work in progress)") + flag.Parse() + + logger := utils.DefaultLogger + + if *verbose { + logger.SetLogLevel(utils.LogLevelDebug) + } else { + logger.SetLogLevel(utils.LogLevelInfo) + } + logger.SetLogTimeFormat("") + + versions := protocol.SupportedVersions + if *tls { + versions = append([]protocol.VersionNumber{protocol.VersionTLS}, versions...) + } + + certFile := *certPath + "/fullchain.pem" + keyFile := *certPath + "/privkey.pem" + + http.Handle("/", http.FileServer(http.Dir(*www))) + + if len(bs) == 0 { + bs = binds{"localhost:6121"} + } + + var wg sync.WaitGroup + wg.Add(len(bs)) + for _, b := range bs { + bCap := b + go func() { + var err error + if *tcp { + err = h2quic.ListenAndServe(bCap, certFile, keyFile, nil) + } else { + server := h2quic.Server{ + Server: &http.Server{Addr: bCap}, + QuicConfig: &quic.Config{Versions: versions}, + } + err = server.ListenAndServeTLS(certFile, keyFile) + } + if err != nil { + fmt.Println(err) + } + wg.Done() + }() + } + wg.Wait() +} diff --git a/vendor/lucas-clemente/quic-go/example/privkey.pem b/vendor/lucas-clemente/quic-go/example/privkey.pem new file mode 100644 index 00000000..50681cfc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/example/privkey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDqON9RKCMK4dHx +LTLiv3n+b/v4KCbYFo38rxCcv4/qoWI1Zoz4XMyPnTZPrzVMz6rhDKWTve1v7g+i +tgQDp1OoRo5ihtqCm9Dr1Ed+qb3hHtFRBBOTiWQy1Y0fvUDYGlSHQ4R7xXYVzCYk +Q9zopqr2otJp/9ZA1Yy3ATITSgcds9wJaAOpkSxCx+D7cqpGbaNtxogRZ4ZT1vVs +3l7Kr26fvnALMM4Knf2Rpq1ZjgPRoLNcfUWCZO7gr+VNCFaI2AQRaAzZkSXAk0B9 +1waTtaFD87kYXl9Z8Jgx1PhJnO8WBUz/7+OAO6M+kuT78e6FltMN004Q8WmuNww6 +PzmVwnmpAgMBAAECggEAAW7hpux48msZTsF5CzwisfTbdNRCEJZqvf4QOvVNGyFr +qWn8ONTQh5xtpaUrzVGD+SaLqNDDsCijvdohQih28ZOk8WNj2OK9L4Q3/8VoHQWE +QFunBwMTMuBtoaEV0XyvwbgfCmbV5yI9pYEoy9+hMisi4HUpSXJFDyWZudZ9Hqhl +FBf5UPxF1AjZViODVfnKkrWh85jaENyWjWrMEDSohzxP8IStFMK8E0feXaQb+G0f +uTelpG2JmVcO3xaYgtRVeS4p5liMQg5gE5oa2Jh7Vp3TwMhQVg0aLmslSLAYlPoh +hyBeOS3ucyFHoC/6Stnnx3jdOEf2lEUObJj3QVEeBQKBgQD3qptNY9R62UQFO8gT +pseEO5CAZRGuKG0VLPNqKKerYQreiT3xYOTPmwEy+xXzYV6DKHtlKDetHuOB862M +E1bKmjDedafQ3KMc4tywLW+U9I8GyooT8uoetzARzgoftRcMzdeu4fexWTsi+kOh +5/PeXUBnFph8E68nXHQR5+MWAwKBgQDyGnT9KUVuLvzrFAghe9Eu1iZJSDs/IrJj +we3XQ7loqMc/Qv34eVKATsgtb2cTSeTivQcSvQO+Uu9dgo17BoWAABDTaV8NAOZ6 +cV2kedrWnxaTRXzB6Z5EKLg+DOMTpCV4Nf3OwzGq/mnKAe8cNM/hS+8HcZywKwr2 +UwLKSq6n4wKBgQDXGUaOnVCSbZZlETnAz43i67ShvqXvY07yIDs8jRiqgLrm8b1p +oaS4JkCRXX8ABSYHtaYOAjLw2a3wVIn66WTsy6P74aWhga7szJ+tJ5kMfqal2Ey5 +7LSnfqRyIkeqqCXfyfsz+S+dyQjSZRdOS90C2Gyx2+8NfC8YeXSZhJM2rwKBgQDB +pL28G/2nsrejQ2N5fLKE9s6qwLZ6ukLbHasiCc5L0uuDQw8mZcvCSsE77iYQvILx +hGYa68oJugYw0hJdu4qeJe9PWbGoEfdHKlPPEZQjJB4Hb4XpB/YJ6FPtdZtPA3Tg +4LaAYYnhjhqJc+CPvAIl3vlyB8Je+h6LhTvvF6r5JwKBgHBkpQ2Y+N3dMgfE8T38 ++Vy+75i9ew3F0TB8o2MWJzYLYCzNLqrB4GkZieudoYP1Cmh50wYIifsk2zNpxOG0 +27tUfMxza4ITUfmtVHS22DGWCqb1TgfQt7jajdioK4TUOZFEmiQiOYMZoFMenbzZ +miz6s3fWx1/b3wNd1J5uV2QS +-----END PRIVATE KEY----- diff --git a/vendor/lucas-clemente/quic-go/frame_sorter.go b/vendor/lucas-clemente/quic-go/frame_sorter.go new file mode 100644 index 00000000..47062c06 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/frame_sorter.go @@ -0,0 +1,158 @@ +package quic + +import ( + "errors" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type frameSorter struct { + queue map[protocol.ByteCount][]byte + readPos protocol.ByteCount + finalOffset protocol.ByteCount + gaps *utils.ByteIntervalList +} + +var errDuplicateStreamData = errors.New("Duplicate Stream Data") + +func newFrameSorter() *frameSorter { + s := frameSorter{ + gaps: utils.NewByteIntervalList(), + queue: make(map[protocol.ByteCount][]byte), + finalOffset: protocol.MaxByteCount, + } + s.gaps.PushFront(utils.ByteInterval{Start: 0, End: protocol.MaxByteCount}) + return &s +} + +func (s *frameSorter) Push(data []byte, offset protocol.ByteCount, fin bool) error { + err := s.push(data, offset, fin) + if err == errDuplicateStreamData { + return nil + } + return err +} + +func (s *frameSorter) push(data []byte, offset protocol.ByteCount, fin bool) error { + if fin { + s.finalOffset = offset + protocol.ByteCount(len(data)) + } + if len(data) == 0 { + return nil + } + + var wasCut bool + if oldData, ok := s.queue[offset]; ok { + if len(data) <= len(oldData) { + return errDuplicateStreamData + } + data = data[len(oldData):] + offset += protocol.ByteCount(len(oldData)) + wasCut = true + } + + start := offset + end := offset + protocol.ByteCount(len(data)) + + // skip all gaps that are before this stream frame + var gap *utils.ByteIntervalElement + for gap = s.gaps.Front(); gap != nil; gap = gap.Next() { + // the frame is a duplicate. Ignore it + if end <= gap.Value.Start { + return errDuplicateStreamData + } + if end > gap.Value.Start && start <= gap.Value.End { + break + } + } + + if gap == nil { + return errors.New("StreamFrameSorter BUG: no gap found") + } + + if start < gap.Value.Start { + add := gap.Value.Start - start + offset += add + start += add + data = data[add:] + wasCut = true + } + + // find the highest gaps whose Start lies before the end of the frame + endGap := gap + for end >= endGap.Value.End { + nextEndGap := endGap.Next() + if nextEndGap == nil { + return errors.New("StreamFrameSorter BUG: no end gap found") + } + if endGap != gap { + s.gaps.Remove(endGap) + } + if end <= nextEndGap.Value.Start { + break + } + // delete queued frames completely covered by the current frame + delete(s.queue, endGap.Value.End) + endGap = nextEndGap + } + + if end > endGap.Value.End { + cutLen := end - endGap.Value.End + len := protocol.ByteCount(len(data)) - cutLen + end -= cutLen + data = data[:len] + wasCut = true + } + + if start == gap.Value.Start { + if end >= gap.Value.End { + // the frame completely fills this gap + // delete the gap + s.gaps.Remove(gap) + } + if end < endGap.Value.End { + // the frame covers the beginning of the gap + // adjust the Start value to shrink the gap + endGap.Value.Start = end + } + } else if end == endGap.Value.End { + // the frame covers the end of the gap + // adjust the End value to shrink the gap + gap.Value.End = start + } else { + if gap == endGap { + // the frame lies within the current gap, splitting it into two + // insert a new gap and adjust the current one + intv := utils.ByteInterval{Start: end, End: gap.Value.End} + s.gaps.InsertAfter(intv, gap) + gap.Value.End = start + } else { + gap.Value.End = start + endGap.Value.Start = end + } + } + + if s.gaps.Len() > protocol.MaxStreamFrameSorterGaps { + return errors.New("Too many gaps in received data") + } + + if wasCut { + newData := make([]byte, len(data)) + copy(newData, data) + data = newData + } + + s.queue[offset] = data + return nil +} + +func (s *frameSorter) Pop() ([]byte /* data */, bool /* fin */) { + data, ok := s.queue[s.readPos] + if !ok { + return nil, s.readPos >= s.finalOffset + } + delete(s.queue, s.readPos) + s.readPos += protocol.ByteCount(len(data)) + return data, s.readPos >= s.finalOffset +} diff --git a/vendor/lucas-clemente/quic-go/frame_sorter_test.go b/vendor/lucas-clemente/quic-go/frame_sorter_test.go new file mode 100644 index 00000000..9def2100 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/frame_sorter_test.go @@ -0,0 +1,435 @@ +package quic + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("STREAM frame sorter", func() { + var s *frameSorter + + checkGaps := func(expectedGaps []utils.ByteInterval) { + Expect(s.gaps.Len()).To(Equal(len(expectedGaps))) + var i int + for gap := s.gaps.Front(); gap != nil; gap = gap.Next() { + Expect(gap.Value).To(Equal(expectedGaps[i])) + i++ + } + } + + BeforeEach(func() { + s = newFrameSorter() + }) + + It("head returns nil when empty", func() { + Expect(s.Pop()).To(BeNil()) + }) + + Context("Push", func() { + It("inserts and pops a single frame", func() { + Expect(s.Push([]byte("foobar"), 0, false)).To(Succeed()) + data, fin := s.Pop() + Expect(data).To(Equal([]byte("foobar"))) + Expect(fin).To(BeFalse()) + Expect(s.Pop()).To(BeNil()) + }) + + It("inserts and pops two consecutive frame", func() { + Expect(s.Push([]byte("foo"), 0, false)).To(Succeed()) + Expect(s.Push([]byte("bar"), 3, false)).To(Succeed()) + data, fin := s.Pop() + Expect(data).To(Equal([]byte("foo"))) + Expect(fin).To(BeFalse()) + data, fin = s.Pop() + Expect(data).To(Equal([]byte("bar"))) + Expect(fin).To(BeFalse()) + Expect(s.Pop()).To(BeNil()) + }) + + It("ignores empty frames", func() { + Expect(s.Push(nil, 0, false)).To(Succeed()) + Expect(s.Pop()).To(BeNil()) + }) + + Context("FIN handling", func() { + It("saves a FIN at offset 0", func() { + Expect(s.Push(nil, 0, true)).To(Succeed()) + data, fin := s.Pop() + Expect(data).To(BeEmpty()) + Expect(fin).To(BeTrue()) + data, fin = s.Pop() + Expect(data).To(BeNil()) + Expect(fin).To(BeTrue()) + }) + + It("saves a FIN frame at non-zero offset", func() { + Expect(s.Push([]byte("foobar"), 0, true)).To(Succeed()) + data, fin := s.Pop() + Expect(data).To(Equal([]byte("foobar"))) + Expect(fin).To(BeTrue()) + data, fin = s.Pop() + Expect(data).To(BeNil()) + Expect(fin).To(BeTrue()) + }) + + It("sets the FIN if a stream is closed after receiving some data", func() { + Expect(s.Push([]byte("foobar"), 0, false)).To(Succeed()) + Expect(s.Push(nil, 6, true)).To(Succeed()) + data, fin := s.Pop() + Expect(data).To(Equal([]byte("foobar"))) + Expect(fin).To(BeTrue()) + data, fin = s.Pop() + Expect(data).To(BeNil()) + Expect(fin).To(BeTrue()) + }) + }) + + Context("Gap handling", func() { + It("finds the first gap", func() { + Expect(s.Push([]byte("foobar"), 10, false)).To(Succeed()) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 10}, + {Start: 16, End: protocol.MaxByteCount}, + }) + }) + + It("correctly sets the first gap for a frame with offset 0", func() { + Expect(s.Push([]byte("foobar"), 0, false)).To(Succeed()) + checkGaps([]utils.ByteInterval{ + {Start: 6, End: protocol.MaxByteCount}, + }) + }) + + It("finds the two gaps", func() { + Expect(s.Push([]byte("foobar"), 10, false)).To(Succeed()) + Expect(s.Push([]byte("foobar"), 20, false)).To(Succeed()) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 10}, + {Start: 16, End: 20}, + {Start: 26, End: protocol.MaxByteCount}, + }) + }) + + It("finds the two gaps in reverse order", func() { + Expect(s.Push([]byte("foobar"), 20, false)).To(Succeed()) + Expect(s.Push([]byte("foobar"), 10, false)).To(Succeed()) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 10}, + {Start: 16, End: 20}, + {Start: 26, End: protocol.MaxByteCount}, + }) + }) + + It("shrinks a gap when it is partially filled", func() { + Expect(s.Push([]byte("test"), 10, false)).To(Succeed()) + Expect(s.Push([]byte("foobar"), 4, false)).To(Succeed()) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 4}, + {Start: 14, End: protocol.MaxByteCount}, + }) + }) + + It("deletes a gap at the beginning, when it is filled", func() { + Expect(s.Push([]byte("test"), 6, false)).To(Succeed()) + Expect(s.Push([]byte("foobar"), 0, false)).To(Succeed()) + checkGaps([]utils.ByteInterval{ + {Start: 10, End: protocol.MaxByteCount}, + }) + }) + + It("deletes a gap in the middle, when it is filled", func() { + Expect(s.Push([]byte("test"), 0, false)).To(Succeed()) + Expect(s.Push([]byte("test2"), 10, false)).To(Succeed()) + Expect(s.Push([]byte("foobar"), 4, false)).To(Succeed()) + Expect(s.queue).To(HaveLen(3)) + checkGaps([]utils.ByteInterval{ + {Start: 15, End: protocol.MaxByteCount}, + }) + }) + + It("splits a gap into two", func() { + Expect(s.Push([]byte("test"), 100, false)).To(Succeed()) + Expect(s.Push([]byte("foobar"), 50, false)).To(Succeed()) + Expect(s.queue).To(HaveLen(2)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 50}, + {Start: 56, End: 100}, + {Start: 104, End: protocol.MaxByteCount}, + }) + }) + + Context("Overlapping Stream Data detection", func() { + // create gaps: 0-5, 10-15, 20-25, 30-inf + BeforeEach(func() { + Expect(s.Push([]byte("12345"), 5, false)).To(Succeed()) + Expect(s.Push([]byte("12345"), 15, false)).To(Succeed()) + Expect(s.Push([]byte("12345"), 25, false)).To(Succeed()) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 5}, + {Start: 10, End: 15}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("cuts a frame with offset 0 that overlaps at the end", func() { + Expect(s.Push([]byte("foobar"), 0, false)).To(Succeed()) + Expect(s.queue).To(HaveKey(protocol.ByteCount(0))) + Expect(s.queue[0]).To(Equal([]byte("fooba"))) + Expect(s.queue[0]).To(HaveCap(5)) + checkGaps([]utils.ByteInterval{ + {Start: 10, End: 15}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("cuts a frame that overlaps at the end", func() { + // 4 to 7 + Expect(s.Push([]byte("foo"), 4, false)).To(Succeed()) + Expect(s.queue).To(HaveKey(protocol.ByteCount(4))) + Expect(s.queue[4]).To(Equal([]byte("f"))) + Expect(s.queue[4]).To(HaveCap(1)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 4}, + {Start: 10, End: 15}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("cuts a frame that completely fills a gap, but overlaps at the end", func() { + // 10 to 16 + Expect(s.Push([]byte("foobar"), 10, false)).To(Succeed()) + Expect(s.queue).To(HaveKey(protocol.ByteCount(10))) + Expect(s.queue[10]).To(Equal([]byte("fooba"))) + Expect(s.queue[10]).To(HaveCap(5)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 5}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("cuts a frame that overlaps at the beginning", func() { + // 8 to 14 + Expect(s.Push([]byte("foobar"), 8, false)).To(Succeed()) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(8))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(10))) + Expect(s.queue[10]).To(Equal([]byte("obar"))) + Expect(s.queue[10]).To(HaveCap(4)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 5}, + {Start: 14, End: 15}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("processes a frame that overlaps at the beginning and at the end, starting in a gap", func() { + // 2 to 12 + Expect(s.Push([]byte("1234567890"), 2, false)).To(Succeed()) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(5))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(2))) + Expect(s.queue[2]).To(Equal([]byte("1234567890"))) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 2}, + {Start: 12, End: 15}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("processes a frame that overlaps at the beginning and at the end, starting in a gap, ending in data", func() { + // 2 to 17 + Expect(s.Push([]byte("123456789012345"), 2, false)).To(Succeed()) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(5))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(2))) + Expect(s.queue[2]).To(Equal([]byte("1234567890123"))) + Expect(s.queue[2]).To(HaveCap(13)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 2}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("processes a frame that overlaps at the beginning and at the end, starting in a gap, ending in data", func() { + // 5 to 22 + Expect(s.Push([]byte("12345678901234567"), 5, false)).To(Succeed()) + Expect(s.queue).To(HaveKey(protocol.ByteCount(5))) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(15))) + Expect(s.queue[10]).To(Equal([]byte("678901234567"))) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 5}, + {Start: 22, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("processes a frame that closes multiple gaps", func() { + // 2 to 27 + Expect(s.Push(bytes.Repeat([]byte{'e'}, 25), 2, false)).To(Succeed()) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(5))) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(15))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(25))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(2))) + Expect(s.queue[2]).To(Equal(bytes.Repeat([]byte{'e'}, 23))) + Expect(s.queue[2]).To(HaveCap(23)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 2}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("processes a frame that closes multiple gaps", func() { + // 5 to 27 + Expect(s.Push(bytes.Repeat([]byte{'d'}, 22), 5, false)).To(Succeed()) + Expect(s.queue).To(HaveKey(protocol.ByteCount(5))) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(15))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(25))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(10))) + Expect(s.queue[10]).To(Equal(bytes.Repeat([]byte{'d'}, 15))) + Expect(s.queue[10]).To(HaveCap(15)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 5}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("processes a frame that covers multiple gaps and ends at the end of a gap", func() { + data := bytes.Repeat([]byte{'e'}, 14) + // 1 to 15 + Expect(s.Push(data, 1, false)).To(Succeed()) + Expect(s.queue).To(HaveKey(protocol.ByteCount(1))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(15))) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(5))) + Expect(s.queue[1]).To(Equal(data)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 1}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("processes a frame that closes all gaps (except for the last one)", func() { + data := bytes.Repeat([]byte{'f'}, 32) + // 0 to 32 + Expect(s.Push(data, 0, false)).To(Succeed()) + Expect(s.queue).To(HaveLen(1)) + Expect(s.queue).To(HaveKey(protocol.ByteCount(0))) + Expect(s.queue[0]).To(Equal(data)) + checkGaps([]utils.ByteInterval{ + {Start: 32, End: protocol.MaxByteCount}, + }) + }) + + It("cuts a frame that overlaps at the beginning and at the end, starting in data already received", func() { + // 8 to 17 + Expect(s.Push([]byte("123456789"), 8, false)).To(Succeed()) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(8))) + Expect(s.queue).To(HaveKey(protocol.ByteCount(10))) + Expect(s.queue[10]).To(Equal([]byte("34567"))) + Expect(s.queue[10]).To(HaveCap(5)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 5}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + + It("cuts a frame that completely covers two gaps", func() { + // 10 to 20 + Expect(s.Push([]byte("1234567890"), 10, false)).To(Succeed()) + Expect(s.queue).To(HaveKey(protocol.ByteCount(10))) + Expect(s.queue[10]).To(Equal([]byte("12345"))) + Expect(s.queue[10]).To(HaveCap(5)) + checkGaps([]utils.ByteInterval{ + {Start: 0, End: 5}, + {Start: 20, End: 25}, + {Start: 30, End: protocol.MaxByteCount}, + }) + }) + }) + + Context("duplicate data", func() { + expectedGaps := []utils.ByteInterval{ + {Start: 5, End: 10}, + {Start: 15, End: protocol.MaxByteCount}, + } + + BeforeEach(func() { + // create gaps: 5-10, 15-inf + Expect(s.Push([]byte("12345"), 0, false)).To(Succeed()) + Expect(s.Push([]byte("12345"), 10, false)).To(Succeed()) + checkGaps(expectedGaps) + }) + + AfterEach(func() { + // check that the gaps were not modified + checkGaps(expectedGaps) + }) + + It("does not modify data when receiving a duplicate", func() { + err := s.push([]byte("fffff"), 0, false) + Expect(err).To(MatchError(errDuplicateStreamData)) + Expect(s.queue[0]).ToNot(Equal([]byte("fffff"))) + }) + + It("detects a duplicate frame that is smaller than the original, starting at the beginning", func() { + // 10 to 12 + err := s.push([]byte("12"), 10, false) + Expect(err).To(MatchError(errDuplicateStreamData)) + Expect(s.queue[10]).To(HaveLen(5)) + }) + + It("detects a duplicate frame that is smaller than the original, somewhere in the middle", func() { + // 1 to 4 + err := s.push([]byte("123"), 1, false) + Expect(err).To(MatchError(errDuplicateStreamData)) + Expect(s.queue[0]).To(HaveLen(5)) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(1))) + }) + + It("detects a duplicate frame that is smaller than the original, somewhere in the middle in the last block", func() { + // 11 to 14 + err := s.push([]byte("123"), 11, false) + Expect(err).To(MatchError(errDuplicateStreamData)) + Expect(s.queue[10]).To(HaveLen(5)) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(11))) + }) + + It("detects a duplicate frame that is smaller than the original, with aligned end in the last block", func() { + // 11 to 15 + err := s.push([]byte("1234"), 1, false) + Expect(err).To(MatchError(errDuplicateStreamData)) + Expect(s.queue[10]).To(HaveLen(5)) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(11))) + }) + + It("detects a duplicate frame that is smaller than the original, with aligned end", func() { + // 3 to 5 + err := s.push([]byte("12"), 3, false) + Expect(err).To(MatchError(errDuplicateStreamData)) + Expect(s.queue[0]).To(HaveLen(5)) + Expect(s.queue).ToNot(HaveKey(protocol.ByteCount(3))) + }) + }) + + Context("DoS protection", func() { + It("errors when too many gaps are created", func() { + for i := 0; i < protocol.MaxStreamFrameSorterGaps; i++ { + Expect(s.Push([]byte("foobar"), protocol.ByteCount(i*7), false)).To(Succeed()) + } + Expect(s.gaps.Len()).To(Equal(protocol.MaxStreamFrameSorterGaps)) + err := s.Push([]byte("foobar"), protocol.ByteCount(protocol.MaxStreamFrameSorterGaps*7)+100, false) + Expect(err).To(MatchError("Too many gaps in received data")) + }) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/h2quic/client.go b/vendor/lucas-clemente/quic-go/h2quic/client.go new file mode 100644 index 00000000..ac28a7f0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/client.go @@ -0,0 +1,314 @@ +package h2quic + +import ( + "crypto/tls" + "errors" + "fmt" + "io" + "net" + "net/http" + "strings" + "sync" + + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" + "golang.org/x/net/idna" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +type roundTripperOpts struct { + DisableCompression bool +} + +var dialAddr = quic.DialAddr + +// client is a HTTP2 client doing QUIC requests +type client struct { + mutex sync.RWMutex + + tlsConf *tls.Config + config *quic.Config + opts *roundTripperOpts + + hostname string + handshakeErr error + dialOnce sync.Once + dialer func(network, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.Session, error) + + session quic.Session + headerStream quic.Stream + headerErr *qerr.QuicError + headerErrored chan struct{} // this channel is closed if an error occurs on the header stream + requestWriter *requestWriter + + responses map[protocol.StreamID]chan *http.Response + + logger utils.Logger +} + +var _ http.RoundTripper = &client{} + +var defaultQuicConfig = &quic.Config{ + RequestConnectionIDOmission: true, + KeepAlive: true, +} + +// newClient creates a new client +func newClient( + hostname string, + tlsConfig *tls.Config, + opts *roundTripperOpts, + quicConfig *quic.Config, + dialer func(network, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.Session, error), +) *client { + config := defaultQuicConfig + if quicConfig != nil { + config = quicConfig + } + return &client{ + hostname: authorityAddr("https", hostname), + responses: make(map[protocol.StreamID]chan *http.Response), + tlsConf: tlsConfig, + config: config, + opts: opts, + headerErrored: make(chan struct{}), + dialer: dialer, + logger: utils.DefaultLogger.WithPrefix("client"), + } +} + +// dial dials the connection +func (c *client) dial() error { + var err error + if c.dialer != nil { + c.session, err = c.dialer("udp", c.hostname, c.tlsConf, c.config) + } else { + c.session, err = dialAddr(c.hostname, c.tlsConf, c.config) + } + if err != nil { + return err + } + + // once the version has been negotiated, open the header stream + c.headerStream, err = c.session.OpenStream() + if err != nil { + return err + } + c.requestWriter = newRequestWriter(c.headerStream, c.logger) + go c.handleHeaderStream() + return nil +} + +func (c *client) handleHeaderStream() { + decoder := hpack.NewDecoder(4096, func(hf hpack.HeaderField) {}) + h2framer := http2.NewFramer(nil, c.headerStream) + + var err error + for err == nil { + err = c.readResponse(h2framer, decoder) + } + if quicErr, ok := err.(*qerr.QuicError); !ok || quicErr.ErrorCode != qerr.PeerGoingAway { + c.logger.Debugf("Error handling header stream: %s", err) + } + c.headerErr = qerr.Error(qerr.InvalidHeadersStreamData, err.Error()) + // stop all running request + close(c.headerErrored) +} + +func (c *client) readResponse(h2framer *http2.Framer, decoder *hpack.Decoder) error { + frame, err := h2framer.ReadFrame() + if err != nil { + return err + } + hframe, ok := frame.(*http2.HeadersFrame) + if !ok { + return errors.New("not a headers frame") + } + mhframe := &http2.MetaHeadersFrame{HeadersFrame: hframe} + mhframe.Fields, err = decoder.DecodeFull(hframe.HeaderBlockFragment()) + if err != nil { + return fmt.Errorf("cannot read header fields: %s", err.Error()) + } + + c.mutex.RLock() + responseChan, ok := c.responses[protocol.StreamID(hframe.StreamID)] + c.mutex.RUnlock() + if !ok { + return fmt.Errorf("response channel for stream %d not found", hframe.StreamID) + } + + rsp, err := responseFromHeaders(mhframe) + if err != nil { + return err + } + responseChan <- rsp + return nil +} + +// Roundtrip executes a request and returns a response +func (c *client) RoundTrip(req *http.Request) (*http.Response, error) { + // TODO: add port to address, if it doesn't have one + if req.URL.Scheme != "https" { + return nil, errors.New("quic http2: unsupported scheme") + } + if authorityAddr("https", hostnameFromRequest(req)) != c.hostname { + return nil, fmt.Errorf("h2quic Client BUG: RoundTrip called for the wrong client (expected %s, got %s)", c.hostname, req.Host) + } + + c.dialOnce.Do(func() { + c.handshakeErr = c.dial() + }) + + if c.handshakeErr != nil { + return nil, c.handshakeErr + } + + hasBody := (req.Body != nil) + + responseChan := make(chan *http.Response) + dataStream, err := c.session.OpenStreamSync() + if err != nil { + _ = c.closeWithError(err) + return nil, err + } + c.mutex.Lock() + c.responses[dataStream.StreamID()] = responseChan + c.mutex.Unlock() + + var requestedGzip bool + if !c.opts.DisableCompression && req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" && req.Method != "HEAD" { + requestedGzip = true + } + // TODO: add support for trailers + endStream := !hasBody + err = c.requestWriter.WriteRequest(req, dataStream.StreamID(), endStream, requestedGzip) + if err != nil { + _ = c.closeWithError(err) + return nil, err + } + + resc := make(chan error, 1) + if hasBody { + go func() { + resc <- c.writeRequestBody(dataStream, req.Body) + }() + } + + var res *http.Response + + var receivedResponse bool + var bodySent bool + + if !hasBody { + bodySent = true + } + + ctx := req.Context() + for !(bodySent && receivedResponse) { + select { + case res = <-responseChan: + receivedResponse = true + c.mutex.Lock() + delete(c.responses, dataStream.StreamID()) + c.mutex.Unlock() + case err := <-resc: + bodySent = true + if err != nil { + return nil, err + } + case <-ctx.Done(): + // error code 6 signals that stream was canceled + dataStream.CancelRead(6) + dataStream.CancelWrite(6) + c.mutex.Lock() + delete(c.responses, dataStream.StreamID()) + c.mutex.Unlock() + return nil, ctx.Err() + case <-c.headerErrored: + // an error occurred on the header stream + _ = c.closeWithError(c.headerErr) + return nil, c.headerErr + } + } + + // TODO: correctly set this variable + var streamEnded bool + isHead := (req.Method == "HEAD") + + res = setLength(res, isHead, streamEnded) + + if streamEnded || isHead { + res.Body = noBody + } else { + res.Body = dataStream + if requestedGzip && res.Header.Get("Content-Encoding") == "gzip" { + res.Header.Del("Content-Encoding") + res.Header.Del("Content-Length") + res.ContentLength = -1 + res.Body = &gzipReader{body: res.Body} + res.Uncompressed = true + } + } + + res.Request = req + return res, nil +} + +func (c *client) writeRequestBody(dataStream quic.Stream, body io.ReadCloser) (err error) { + defer func() { + cerr := body.Close() + if err == nil { + // TODO: what to do with dataStream here? Maybe reset it? + err = cerr + } + }() + + _, err = io.Copy(dataStream, body) + if err != nil { + // TODO: what to do with dataStream here? Maybe reset it? + return err + } + return dataStream.Close() +} + +func (c *client) closeWithError(e error) error { + if c.session == nil { + return nil + } + return c.session.CloseWithError(quic.ErrorCode(qerr.InternalError), e) +} + +// Close closes the client +func (c *client) Close() error { + if c.session == nil { + return nil + } + return c.session.Close() +} + +// copied from net/transport.go + +// authorityAddr returns a given authority (a host/IP, or host:port / ip:port) +// and returns a host:port. The port 443 is added if needed. +func authorityAddr(scheme string, authority string) (addr string) { + host, port, err := net.SplitHostPort(authority) + if err != nil { // authority didn't have a port + port = "443" + if scheme == "http" { + port = "80" + } + host = authority + } + if a, err := idna.ToASCII(host); err == nil { + host = a + } + // IPv6 address literal, without a port: + if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { + return host + ":" + port + } + return net.JoinHostPort(host, port) +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/client_test.go b/vendor/lucas-clemente/quic-go/h2quic/client_test.go new file mode 100644 index 00000000..d4732c63 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/client_test.go @@ -0,0 +1,639 @@ +package h2quic + +import ( + "bytes" + "compress/gzip" + "context" + "crypto/tls" + "errors" + "io" + "net/http" + + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Client", func() { + var ( + client *client + session *mockSession + headerStream *mockStream + req *http.Request + origDialAddr = dialAddr + ) + + injectResponse := func(id protocol.StreamID, rsp *http.Response) { + EventuallyWithOffset(0, func() bool { + client.mutex.Lock() + defer client.mutex.Unlock() + _, ok := client.responses[id] + return ok + }).Should(BeTrue()) + rspChan := client.responses[5] + ExpectWithOffset(0, rspChan).ToNot(BeClosed()) + rspChan <- rsp + } + + BeforeEach(func() { + origDialAddr = dialAddr + hostname := "quic.clemente.io:1337" + client = newClient(hostname, nil, &roundTripperOpts{}, nil, nil) + Expect(client.hostname).To(Equal(hostname)) + session = newMockSession() + session.ctx, session.ctxCancel = context.WithCancel(context.Background()) + client.session = session + + headerStream = newMockStream(3) + client.headerStream = headerStream + client.requestWriter = newRequestWriter(headerStream, utils.DefaultLogger) + var err error + req, err = http.NewRequest("GET", "https://localhost:1337", nil) + Expect(err).ToNot(HaveOccurred()) + }) + + AfterEach(func() { + dialAddr = origDialAddr + }) + + It("saves the TLS config", func() { + tlsConf := &tls.Config{InsecureSkipVerify: true} + client = newClient("", tlsConf, &roundTripperOpts{}, nil, nil) + Expect(client.tlsConf).To(Equal(tlsConf)) + }) + + It("saves the QUIC config", func() { + quicConf := &quic.Config{HandshakeTimeout: time.Nanosecond} + client = newClient("", &tls.Config{}, &roundTripperOpts{}, quicConf, nil) + Expect(client.config).To(Equal(quicConf)) + }) + + It("uses the default QUIC config if none is give", func() { + client = newClient("", &tls.Config{}, &roundTripperOpts{}, nil, nil) + Expect(client.config).ToNot(BeNil()) + Expect(client.config).To(Equal(defaultQuicConfig)) + }) + + It("adds the port to the hostname, if none is given", func() { + client = newClient("quic.clemente.io", nil, &roundTripperOpts{}, nil, nil) + Expect(client.hostname).To(Equal("quic.clemente.io:443")) + }) + + It("dials", func() { + client = newClient("localhost:1337", nil, &roundTripperOpts{}, nil, nil) + session.streamsToOpen = []quic.Stream{newMockStream(3), newMockStream(5)} + dialAddr = func(hostname string, _ *tls.Config, _ *quic.Config) (quic.Session, error) { + return session, nil + } + close(headerStream.unblockRead) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := client.RoundTrip(req) + Expect(err).ToNot(HaveOccurred()) + close(done) + // fmt.Println("done") + }() + Eventually(func() quic.Session { return client.session }).Should(Equal(session)) + // make the go routine return + injectResponse(5, &http.Response{}) + Eventually(done).Should(BeClosed()) + }) + + It("errors when dialing fails", func() { + testErr := errors.New("handshake error") + client = newClient("localhost:1337", nil, &roundTripperOpts{}, nil, nil) + dialAddr = func(hostname string, _ *tls.Config, _ *quic.Config) (quic.Session, error) { + return nil, testErr + } + _, err := client.RoundTrip(req) + Expect(err).To(MatchError(testErr)) + }) + + It("uses the custom dialer, if provided", func() { + var tlsCfg *tls.Config + var qCfg *quic.Config + session.streamsToOpen = []quic.Stream{newMockStream(3), newMockStream(5)} + dialer := func(_, _ string, tlsCfgP *tls.Config, cfg *quic.Config) (quic.Session, error) { + tlsCfg = tlsCfgP + qCfg = cfg + return session, nil + } + client = newClient("localhost:1337", nil, &roundTripperOpts{}, nil, dialer) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := client.RoundTrip(req) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + Eventually(func() quic.Session { return client.session }).Should(Equal(session)) + Expect(qCfg).To(Equal(client.config)) + Expect(tlsCfg).To(Equal(client.tlsConf)) + // make the go routine return + injectResponse(5, &http.Response{}) + Eventually(done).Should(BeClosed()) + }) + + It("errors if it can't open a stream", func() { + testErr := errors.New("you shall not pass") + client = newClient("localhost:1337", nil, &roundTripperOpts{}, nil, nil) + session.streamOpenErr = testErr + dialAddr = func(hostname string, _ *tls.Config, _ *quic.Config) (quic.Session, error) { + return session, nil + } + _, err := client.RoundTrip(req) + Expect(err).To(MatchError(testErr)) + }) + + It("returns a request when dial fails", func() { + testErr := errors.New("dial error") + dialAddr = func(hostname string, _ *tls.Config, _ *quic.Config) (quic.Session, error) { + return nil, testErr + } + request, err := http.NewRequest("https", "https://quic.clemente.io:1337/file1.dat", nil) + Expect(err).ToNot(HaveOccurred()) + + done := make(chan struct{}) + go func() { + _, err := client.RoundTrip(request) + Expect(err).To(MatchError(testErr)) + close(done) + }() + _, err = client.RoundTrip(request) + Expect(err).To(MatchError(testErr)) + Eventually(done).Should(BeClosed()) + }) + + Context("Doing requests", func() { + var request *http.Request + var dataStream *mockStream + + getRequest := func(data []byte) *http2.MetaHeadersFrame { + r := bytes.NewReader(data) + decoder := hpack.NewDecoder(4096, func(hf hpack.HeaderField) {}) + h2framer := http2.NewFramer(nil, r) + frame, err := h2framer.ReadFrame() + Expect(err).ToNot(HaveOccurred()) + mhframe := &http2.MetaHeadersFrame{HeadersFrame: frame.(*http2.HeadersFrame)} + mhframe.Fields, err = decoder.DecodeFull(mhframe.HeadersFrame.HeaderBlockFragment()) + Expect(err).ToNot(HaveOccurred()) + return mhframe + } + + getHeaderFields := func(f *http2.MetaHeadersFrame) map[string]string { + fields := make(map[string]string) + for _, hf := range f.Fields { + fields[hf.Name] = hf.Value + } + return fields + } + + BeforeEach(func() { + var err error + dialAddr = func(hostname string, _ *tls.Config, _ *quic.Config) (quic.Session, error) { + return session, nil + } + dataStream = newMockStream(5) + session.streamsToOpen = []quic.Stream{headerStream, dataStream} + request, err = http.NewRequest("https", "https://quic.clemente.io:1337/file1.dat", nil) + Expect(err).ToNot(HaveOccurred()) + }) + + It("does a request", func() { + teapot := &http.Response{ + Status: "418 I'm a teapot", + StatusCode: 418, + } + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).ToNot(HaveOccurred()) + Expect(rsp).To(Equal(teapot)) + Expect(rsp.Body).To(Equal(dataStream)) + Expect(rsp.ContentLength).To(BeEquivalentTo(-1)) + Expect(rsp.Request).To(Equal(request)) + close(done) + }() + + Eventually(func() []byte { return headerStream.dataWritten.Bytes() }).ShouldNot(BeEmpty()) + injectResponse(5, teapot) + Expect(client.headerErrored).ToNot(BeClosed()) + Eventually(done).Should(BeClosed()) + }) + + It("errors if a request without a body is canceled", func() { + done := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + defer GinkgoRecover() + request = request.WithContext(ctx) + rsp, err := client.RoundTrip(request) + Expect(err).To(MatchError(context.Canceled)) + Expect(rsp).To(BeNil()) + close(done) + }() + + cancel() + Eventually(done).Should(BeClosed()) + Expect(dataStream.reset).To(BeTrue()) + Expect(dataStream.canceledWrite).To(BeTrue()) + Expect(client.headerErrored).ToNot(BeClosed()) + }) + + It("errors if a request with a body is canceled after the body is sent", func() { + done := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + defer GinkgoRecover() + request = request.WithContext(ctx) + request.Body = &mockBody{} + rsp, err := client.RoundTrip(request) + Expect(err).To(MatchError(context.Canceled)) + Expect(rsp).To(BeNil()) + close(done) + }() + + time.Sleep(10 * time.Millisecond) + cancel() + Eventually(done).Should(BeClosed()) + Expect(dataStream.reset).To(BeTrue()) + Expect(dataStream.canceledWrite).To(BeTrue()) + Expect(client.headerErrored).ToNot(BeClosed()) + }) + + It("errors if a request with a body is canceled before the body is sent", func() { + done := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + defer GinkgoRecover() + request = request.WithContext(ctx) + request.Body = &mockBody{} + cancel() + time.Sleep(10 * time.Millisecond) + rsp, err := client.RoundTrip(request) + Expect(err).To(MatchError(context.Canceled)) + Expect(rsp).To(BeNil()) + close(done) + }() + + Eventually(done).Should(BeClosed()) + Expect(dataStream.reset).To(BeTrue()) + Expect(dataStream.canceledWrite).To(BeTrue()) + Expect(client.headerErrored).ToNot(BeClosed()) + }) + + It("closes the quic client when encountering an error on the header stream", func() { + headerStream.dataToRead.Write(bytes.Repeat([]byte{0}, 100)) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).To(MatchError(client.headerErr)) + Expect(rsp).To(BeNil()) + close(done) + }() + + Eventually(done).Should(BeClosed()) + Expect(client.headerErr.ErrorCode).To(Equal(qerr.InvalidHeadersStreamData)) + Expect(client.session.(*mockSession).closedWithError).To(MatchError(client.headerErr)) + }) + + It("returns subsequent request if there was an error on the header stream before", func() { + session.streamsToOpen = []quic.Stream{headerStream, dataStream, newMockStream(7)} + headerStream.dataToRead.Write(bytes.Repeat([]byte{0}, 100)) + _, err := client.RoundTrip(request) + Expect(err).To(BeAssignableToTypeOf(&qerr.QuicError{})) + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.InvalidHeadersStreamData)) + // now that the first request failed due to an error on the header stream, try another request + _, nextErr := client.RoundTrip(request) + Expect(nextErr).To(MatchError(err)) + }) + + It("blocks if no stream is available", func() { + session.streamsToOpen = []quic.Stream{headerStream, dataStream} + session.blockOpenStreamSync = true + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := client.RoundTrip(request) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + + Consistently(done).ShouldNot(BeClosed()) + // make the go routine return + client.Close() + injectResponse(5, &http.Response{}) + Eventually(done).Should(BeClosed()) + }) + + Context("validating the address", func() { + It("refuses to do requests for the wrong host", func() { + req, err := http.NewRequest("https", "https://quic.clemente.io:1336/foobar.html", nil) + Expect(err).ToNot(HaveOccurred()) + _, err = client.RoundTrip(req) + Expect(err).To(MatchError("h2quic Client BUG: RoundTrip called for the wrong client (expected quic.clemente.io:1337, got quic.clemente.io:1336)")) + }) + + It("refuses to do plain HTTP requests", func() { + req, err := http.NewRequest("https", "http://quic.clemente.io:1337/foobar.html", nil) + Expect(err).ToNot(HaveOccurred()) + _, err = client.RoundTrip(req) + Expect(err).To(MatchError("quic http2: unsupported scheme")) + }) + + It("adds the port for request URLs without one", func() { + client = newClient("quic.clemente.io", nil, &roundTripperOpts{}, nil, nil) + req, err := http.NewRequest("https", "https://quic.clemente.io/foobar.html", nil) + Expect(err).ToNot(HaveOccurred()) + + done := make(chan struct{}) + // the client.RoundTrip will block, because the encryption level is still set to Unencrypted + go func() { + defer GinkgoRecover() + _, err := client.RoundTrip(req) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + + Consistently(done).ShouldNot(BeClosed()) + // make the go routine return + injectResponse(5, &http.Response{}) + Eventually(done).Should(BeClosed()) + }) + }) + + It("sets the EndStream header for requests without a body", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + client.RoundTrip(request) + close(done) + }() + Eventually(func() []byte { return headerStream.dataWritten.Bytes() }).ShouldNot(BeNil()) + mhf := getRequest(headerStream.dataWritten.Bytes()) + Expect(mhf.HeadersFrame.StreamEnded()).To(BeTrue()) + // make the go routine return + injectResponse(5, &http.Response{}) + Eventually(done).Should(BeClosed()) + }) + + It("sets the EndStream header to false for requests with a body", func() { + request.Body = &mockBody{} + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + client.RoundTrip(request) + close(done) + }() + Eventually(func() []byte { return headerStream.dataWritten.Bytes() }).ShouldNot(BeNil()) + mhf := getRequest(headerStream.dataWritten.Bytes()) + Expect(mhf.HeadersFrame.StreamEnded()).To(BeFalse()) + // make the go routine return + injectResponse(5, &http.Response{}) + Eventually(done).Should(BeClosed()) + }) + + Context("requests containing a Body", func() { + var requestBody []byte + var response *http.Response + + BeforeEach(func() { + requestBody = []byte("request body") + body := &mockBody{} + body.SetData(requestBody) + request.Body = body + response = &http.Response{ + StatusCode: 200, + Header: http.Header{"Content-Length": []string{"1000"}}, + } + // fake a handshake + client.dialOnce.Do(func() {}) + session.streamsToOpen = []quic.Stream{dataStream} + }) + + It("sends a request", func() { + rspChan := make(chan *http.Response) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).ToNot(HaveOccurred()) + rspChan <- rsp + }() + injectResponse(5, response) + Eventually(rspChan).Should(Receive(Equal(response))) + Expect(dataStream.dataWritten.Bytes()).To(Equal(requestBody)) + Expect(dataStream.closed).To(BeTrue()) + Expect(request.Body.(*mockBody).closed).To(BeTrue()) + }) + + It("returns the error that occurred when reading the body", func() { + testErr := errors.New("testErr") + request.Body.(*mockBody).readErr = testErr + + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).To(MatchError(testErr)) + Expect(rsp).To(BeNil()) + close(done) + }() + Eventually(done).Should(BeClosed()) + Expect(request.Body.(*mockBody).closed).To(BeTrue()) + }) + + It("returns the error that occurred when closing the body", func() { + testErr := errors.New("testErr") + request.Body.(*mockBody).closeErr = testErr + + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).To(MatchError(testErr)) + Expect(rsp).To(BeNil()) + close(done) + }() + Eventually(done).Should(BeClosed()) + Expect(request.Body.(*mockBody).closed).To(BeTrue()) + }) + }) + + Context("gzip compression", func() { + var gzippedData []byte // a gzipped foobar + var response *http.Response + + BeforeEach(func() { + var b bytes.Buffer + w := gzip.NewWriter(&b) + w.Write([]byte("foobar")) + w.Close() + gzippedData = b.Bytes() + response = &http.Response{ + StatusCode: 200, + Header: http.Header{"Content-Length": []string{"1000"}}, + } + }) + + It("adds the gzip header to requests", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).ToNot(HaveOccurred()) + Expect(rsp).ToNot(BeNil()) + Expect(rsp.ContentLength).To(BeEquivalentTo(-1)) + Expect(rsp.Header.Get("Content-Encoding")).To(BeEmpty()) + Expect(rsp.Header.Get("Content-Length")).To(BeEmpty()) + data := make([]byte, 6) + _, err = io.ReadFull(rsp.Body, data) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal([]byte("foobar"))) + close(done) + }() + + dataStream.dataToRead.Write(gzippedData) + response.Header.Add("Content-Encoding", "gzip") + injectResponse(5, response) + headers := getHeaderFields(getRequest(headerStream.dataWritten.Bytes())) + Expect(headers).To(HaveKeyWithValue("accept-encoding", "gzip")) + close(dataStream.unblockRead) + Eventually(done).Should(BeClosed()) + }) + + It("doesn't add gzip if the header disable it", func() { + client.opts.DisableCompression = true + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := client.RoundTrip(request) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + + Eventually(func() []byte { return headerStream.dataWritten.Bytes() }).ShouldNot(BeEmpty()) + headers := getHeaderFields(getRequest(headerStream.dataWritten.Bytes())) + Expect(headers).ToNot(HaveKey("accept-encoding")) + // make the go routine return + injectResponse(5, &http.Response{}) + Eventually(done).Should(BeClosed()) + }) + + It("only decompresses the response if the response contains the right content-encoding header", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).ToNot(HaveOccurred()) + Expect(rsp).ToNot(BeNil()) + data := make([]byte, 11) + rsp.Body.Read(data) + Expect(rsp.ContentLength).ToNot(BeEquivalentTo(-1)) + Expect(data).To(Equal([]byte("not gzipped"))) + close(done) + }() + + dataStream.dataToRead.Write([]byte("not gzipped")) + injectResponse(5, response) + headers := getHeaderFields(getRequest(headerStream.dataWritten.Bytes())) + Expect(headers).To(HaveKeyWithValue("accept-encoding", "gzip")) + Eventually(done).Should(BeClosed()) + }) + + It("doesn't add the gzip header for requests that have the accept-enconding set", func() { + request.Header.Add("accept-encoding", "gzip") + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + rsp, err := client.RoundTrip(request) + Expect(err).ToNot(HaveOccurred()) + data := make([]byte, 12) + _, err = rsp.Body.Read(data) + Expect(err).ToNot(HaveOccurred()) + Expect(rsp.ContentLength).ToNot(BeEquivalentTo(-1)) + Expect(data).To(Equal([]byte("gzipped data"))) + close(done) + }() + + dataStream.dataToRead.Write([]byte("gzipped data")) + injectResponse(5, response) + headers := getHeaderFields(getRequest(headerStream.dataWritten.Bytes())) + Expect(headers).To(HaveKeyWithValue("accept-encoding", "gzip")) + Eventually(done).Should(BeClosed()) + }) + }) + + Context("handling the header stream", func() { + var h2framer *http2.Framer + + BeforeEach(func() { + h2framer = http2.NewFramer(&headerStream.dataToRead, nil) + client.responses[23] = make(chan *http.Response) + }) + + It("reads header values from a response", func() { + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + data := []byte{0x48, 0x03, 0x33, 0x30, 0x32, 0x58, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x6e, 0x17, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d} + headerStream.dataToRead.Write([]byte{0x0, 0x0, byte(len(data)), 0x1, 0x5, 0x0, 0x0, 0x0, 23}) + headerStream.dataToRead.Write(data) + go client.handleHeaderStream() + var rsp *http.Response + Eventually(client.responses[23]).Should(Receive(&rsp)) + Expect(rsp).ToNot(BeNil()) + Expect(rsp.Proto).To(Equal("HTTP/2.0")) + Expect(rsp.ProtoMajor).To(BeEquivalentTo(2)) + Expect(rsp.StatusCode).To(BeEquivalentTo(302)) + Expect(rsp.Status).To(Equal("302 Found")) + Expect(rsp.Header).To(HaveKeyWithValue("Location", []string{"https://www.example.com"})) + Expect(rsp.Header).To(HaveKeyWithValue("Cache-Control", []string{"private"})) + }) + + It("errors if the H2 frame is not a HeadersFrame", func() { + h2framer.WritePing(true, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}) + client.handleHeaderStream() + Eventually(client.headerErrored).Should(BeClosed()) + Expect(client.headerErr).To(MatchError(qerr.Error(qerr.InvalidHeadersStreamData, "not a headers frame"))) + }) + + It("errors if it can't read the HPACK encoded header fields", func() { + h2framer.WriteHeaders(http2.HeadersFrameParam{ + StreamID: 23, + EndHeaders: true, + BlockFragment: []byte("invalid HPACK data"), + }) + client.handleHeaderStream() + Eventually(client.headerErrored).Should(BeClosed()) + Expect(client.headerErr.ErrorCode).To(Equal(qerr.InvalidHeadersStreamData)) + Expect(client.headerErr.ErrorMessage).To(ContainSubstring("cannot read header fields")) + }) + + It("errors if the stream cannot be found", func() { + var headers bytes.Buffer + enc := hpack.NewEncoder(&headers) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + err := h2framer.WriteHeaders(http2.HeadersFrameParam{ + StreamID: 1337, + EndHeaders: true, + BlockFragment: headers.Bytes(), + }) + Expect(err).ToNot(HaveOccurred()) + client.handleHeaderStream() + Eventually(client.headerErrored).Should(BeClosed()) + Expect(client.headerErr.ErrorCode).To(Equal(qerr.InvalidHeadersStreamData)) + Expect(client.headerErr.ErrorMessage).To(ContainSubstring("response channel for stream 1337 not found")) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/h2quic/gzipreader.go b/vendor/lucas-clemente/quic-go/h2quic/gzipreader.go new file mode 100644 index 00000000..91c226b1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/gzipreader.go @@ -0,0 +1,35 @@ +package h2quic + +// copied from net/transport.go + +// gzipReader wraps a response body so it can lazily +// call gzip.NewReader on the first call to Read +import ( + "compress/gzip" + "io" +) + +// call gzip.NewReader on the first call to Read +type gzipReader struct { + body io.ReadCloser // underlying Response.Body + zr *gzip.Reader // lazily-initialized gzip reader + zerr error // sticky error +} + +func (gz *gzipReader) Read(p []byte) (n int, err error) { + if gz.zerr != nil { + return 0, gz.zerr + } + if gz.zr == nil { + gz.zr, err = gzip.NewReader(gz.body) + if err != nil { + gz.zerr = err + return 0, err + } + } + return gz.zr.Read(p) +} + +func (gz *gzipReader) Close() error { + return gz.body.Close() +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/h2quic_suite_test.go b/vendor/lucas-clemente/quic-go/h2quic/h2quic_suite_test.go new file mode 100644 index 00000000..f0b26552 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/h2quic_suite_test.go @@ -0,0 +1,13 @@ +package h2quic + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestH2quic(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "H2quic Suite") +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/request.go b/vendor/lucas-clemente/quic-go/h2quic/request.go new file mode 100644 index 00000000..b27e37e2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/request.go @@ -0,0 +1,77 @@ +package h2quic + +import ( + "crypto/tls" + "errors" + "net/http" + "net/url" + "strconv" + "strings" + + "golang.org/x/net/http2/hpack" +) + +func requestFromHeaders(headers []hpack.HeaderField) (*http.Request, error) { + var path, authority, method, contentLengthStr string + httpHeaders := http.Header{} + + for _, h := range headers { + switch h.Name { + case ":path": + path = h.Value + case ":method": + method = h.Value + case ":authority": + authority = h.Value + case "content-length": + contentLengthStr = h.Value + default: + if !h.IsPseudo() { + httpHeaders.Add(h.Name, h.Value) + } + } + } + + // concatenate cookie headers, see https://tools.ietf.org/html/rfc6265#section-5.4 + if len(httpHeaders["Cookie"]) > 0 { + httpHeaders.Set("Cookie", strings.Join(httpHeaders["Cookie"], "; ")) + } + + if len(path) == 0 || len(authority) == 0 || len(method) == 0 { + return nil, errors.New(":path, :authority and :method must not be empty") + } + + u, err := url.Parse(path) + if err != nil { + return nil, err + } + + var contentLength int64 + if len(contentLengthStr) > 0 { + contentLength, err = strconv.ParseInt(contentLengthStr, 10, 64) + if err != nil { + return nil, err + } + } + + return &http.Request{ + Method: method, + URL: u, + Proto: "HTTP/2.0", + ProtoMajor: 2, + ProtoMinor: 0, + Header: httpHeaders, + Body: nil, + ContentLength: contentLength, + Host: authority, + RequestURI: path, + TLS: &tls.ConnectionState{}, + }, nil +} + +func hostnameFromRequest(req *http.Request) string { + if req.URL != nil { + return req.URL.Host + } + return "" +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/request_body.go b/vendor/lucas-clemente/quic-go/h2quic/request_body.go new file mode 100644 index 00000000..2d4d5954 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/request_body.go @@ -0,0 +1,29 @@ +package h2quic + +import ( + "io" + + quic "github.com/lucas-clemente/quic-go" +) + +type requestBody struct { + requestRead bool + dataStream quic.Stream +} + +// make sure the requestBody can be used as a http.Request.Body +var _ io.ReadCloser = &requestBody{} + +func newRequestBody(stream quic.Stream) *requestBody { + return &requestBody{dataStream: stream} +} + +func (b *requestBody) Read(p []byte) (int, error) { + b.requestRead = true + return b.dataStream.Read(p) +} + +func (b *requestBody) Close() error { + // stream's Close() closes the write side, not the read side + return nil +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/request_body_test.go b/vendor/lucas-clemente/quic-go/h2quic/request_body_test.go new file mode 100644 index 00000000..a12053bf --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/request_body_test.go @@ -0,0 +1,39 @@ +package h2quic + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Request body", func() { + var ( + stream *mockStream + rb *requestBody + ) + + BeforeEach(func() { + stream = &mockStream{} + stream.dataToRead.Write([]byte("foobar")) // provides data to be read + rb = newRequestBody(stream) + }) + + It("reads from the stream", func() { + b := make([]byte, 10) + n, _ := stream.Read(b) + Expect(n).To(Equal(6)) + Expect(b[0:6]).To(Equal([]byte("foobar"))) + }) + + It("saves if the stream was read from", func() { + Expect(rb.requestRead).To(BeFalse()) + rb.Read(make([]byte, 1)) + Expect(rb.requestRead).To(BeTrue()) + }) + + It("doesn't close the stream when closing the request body", func() { + Expect(stream.closed).To(BeFalse()) + err := rb.Close() + Expect(err).ToNot(HaveOccurred()) + Expect(stream.closed).To(BeFalse()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/h2quic/request_test.go b/vendor/lucas-clemente/quic-go/h2quic/request_test.go new file mode 100644 index 00000000..55085add --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/request_test.go @@ -0,0 +1,121 @@ +package h2quic + +import ( + "net/http" + "net/url" + + "golang.org/x/net/http2/hpack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Request", func() { + It("populates request", func() { + headers := []hpack.HeaderField{ + {Name: ":path", Value: "/foo"}, + {Name: ":authority", Value: "quic.clemente.io"}, + {Name: ":method", Value: "GET"}, + {Name: "content-length", Value: "42"}, + } + req, err := requestFromHeaders(headers) + Expect(err).NotTo(HaveOccurred()) + Expect(req.Method).To(Equal("GET")) + Expect(req.URL.Path).To(Equal("/foo")) + Expect(req.Proto).To(Equal("HTTP/2.0")) + Expect(req.ProtoMajor).To(Equal(2)) + Expect(req.ProtoMinor).To(Equal(0)) + Expect(req.ContentLength).To(Equal(int64(42))) + Expect(req.Header).To(BeEmpty()) + Expect(req.Body).To(BeNil()) + Expect(req.Host).To(Equal("quic.clemente.io")) + Expect(req.RequestURI).To(Equal("/foo")) + Expect(req.TLS).ToNot(BeNil()) + }) + + It("concatenates the cookie headers", func() { + headers := []hpack.HeaderField{ + {Name: ":path", Value: "/foo"}, + {Name: ":authority", Value: "quic.clemente.io"}, + {Name: ":method", Value: "GET"}, + {Name: "cookie", Value: "cookie1=foobar1"}, + {Name: "cookie", Value: "cookie2=foobar2"}, + } + req, err := requestFromHeaders(headers) + Expect(err).NotTo(HaveOccurred()) + Expect(req.Header).To(Equal(http.Header{ + "Cookie": []string{"cookie1=foobar1; cookie2=foobar2"}, + })) + }) + + It("handles other headers", func() { + headers := []hpack.HeaderField{ + {Name: ":path", Value: "/foo"}, + {Name: ":authority", Value: "quic.clemente.io"}, + {Name: ":method", Value: "GET"}, + {Name: "cache-control", Value: "max-age=0"}, + {Name: "duplicate-header", Value: "1"}, + {Name: "duplicate-header", Value: "2"}, + } + req, err := requestFromHeaders(headers) + Expect(err).NotTo(HaveOccurred()) + Expect(req.Header).To(Equal(http.Header{ + "Cache-Control": []string{"max-age=0"}, + "Duplicate-Header": []string{"1", "2"}, + })) + }) + + It("errors with missing path", func() { + headers := []hpack.HeaderField{ + {Name: ":authority", Value: "quic.clemente.io"}, + {Name: ":method", Value: "GET"}, + } + _, err := requestFromHeaders(headers) + Expect(err).To(MatchError(":path, :authority and :method must not be empty")) + }) + + It("errors with missing method", func() { + headers := []hpack.HeaderField{ + {Name: ":path", Value: "/foo"}, + {Name: ":authority", Value: "quic.clemente.io"}, + } + _, err := requestFromHeaders(headers) + Expect(err).To(MatchError(":path, :authority and :method must not be empty")) + }) + + It("errors with missing authority", func() { + headers := []hpack.HeaderField{ + {Name: ":path", Value: "/foo"}, + {Name: ":method", Value: "GET"}, + } + _, err := requestFromHeaders(headers) + Expect(err).To(MatchError(":path, :authority and :method must not be empty")) + }) + + Context("extracting the hostname from a request", func() { + var url *url.URL + + BeforeEach(func() { + var err error + url, err = url.Parse("https://quic.clemente.io:1337") + Expect(err).ToNot(HaveOccurred()) + }) + + It("uses req.URL.Host", func() { + req := &http.Request{URL: url} + Expect(hostnameFromRequest(req)).To(Equal("quic.clemente.io:1337")) + }) + + It("uses req.URL.Host even if req.Host is available", func() { + req := &http.Request{ + Host: "www.example.org", + URL: url, + } + Expect(hostnameFromRequest(req)).To(Equal("quic.clemente.io:1337")) + }) + + It("returns an empty hostname if nothing is set", func() { + Expect(hostnameFromRequest(&http.Request{})).To(BeEmpty()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/h2quic/request_writer.go b/vendor/lucas-clemente/quic-go/h2quic/request_writer.go new file mode 100644 index 00000000..b5ee9751 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/request_writer.go @@ -0,0 +1,203 @@ +package h2quic + +import ( + "bytes" + "fmt" + "net/http" + "strconv" + "strings" + "sync" + + "golang.org/x/net/http/httpguts" + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type requestWriter struct { + mutex sync.Mutex + headerStream quic.Stream + + henc *hpack.Encoder + hbuf bytes.Buffer // HPACK encoder writes into this + + logger utils.Logger +} + +const defaultUserAgent = "quic-go" + +func newRequestWriter(headerStream quic.Stream, logger utils.Logger) *requestWriter { + rw := &requestWriter{ + headerStream: headerStream, + logger: logger, + } + rw.henc = hpack.NewEncoder(&rw.hbuf) + return rw +} + +func (w *requestWriter) WriteRequest(req *http.Request, dataStreamID protocol.StreamID, endStream, requestGzip bool) error { + // TODO: add support for trailers + // TODO: add support for gzip compression + // TODO: write continuation frames, if the header frame is too long + + w.mutex.Lock() + defer w.mutex.Unlock() + + w.encodeHeaders(req, requestGzip, "", actualContentLength(req)) + h2framer := http2.NewFramer(w.headerStream, nil) + return h2framer.WriteHeaders(http2.HeadersFrameParam{ + StreamID: uint32(dataStreamID), + EndHeaders: true, + EndStream: endStream, + BlockFragment: w.hbuf.Bytes(), + Priority: http2.PriorityParam{Weight: 0xff}, + }) +} + +// the rest of this files is copied from http2.Transport +func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) { + w.hbuf.Reset() + + host := req.Host + if host == "" { + host = req.URL.Host + } + host, err := httpguts.PunycodeHostPort(host) + if err != nil { + return nil, err + } + + var path string + if req.Method != "CONNECT" { + path = req.URL.RequestURI() + if !validPseudoPath(path) { + orig := path + path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host) + if !validPseudoPath(path) { + if req.URL.Opaque != "" { + return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque) + } + return nil, fmt.Errorf("invalid request :path %q", orig) + } + } + } + + // Check for any invalid headers and return an error before we + // potentially pollute our hpack state. (We want to be able to + // continue to reuse the hpack encoder for future requests) + for k, vv := range req.Header { + if !httpguts.ValidHeaderFieldName(k) { + return nil, fmt.Errorf("invalid HTTP header name %q", k) + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k) + } + } + } + + // 8.1.2.3 Request Pseudo-Header Fields + // The :path pseudo-header field includes the path and query parts of the + // target URI (the path-absolute production and optionally a '?' character + // followed by the query production (see Sections 3.3 and 3.4 of + // [RFC3986]). + w.writeHeader(":authority", host) + w.writeHeader(":method", req.Method) + if req.Method != "CONNECT" { + w.writeHeader(":path", path) + w.writeHeader(":scheme", req.URL.Scheme) + } + if trailers != "" { + w.writeHeader("trailer", trailers) + } + + var didUA bool + for k, vv := range req.Header { + lowKey := strings.ToLower(k) + switch lowKey { + case "host", "content-length": + // Host is :authority, already sent. + // Content-Length is automatic, set below. + continue + case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive": + // Per 8.1.2.2 Connection-Specific Header + // Fields, don't send connection-specific + // fields. We have already checked if any + // are error-worthy so just ignore the rest. + continue + case "user-agent": + // Match Go's http1 behavior: at most one + // User-Agent. If set to nil or empty string, + // then omit it. Otherwise if not mentioned, + // include the default (below). + didUA = true + if len(vv) < 1 { + continue + } + vv = vv[:1] + if vv[0] == "" { + continue + } + } + for _, v := range vv { + w.writeHeader(lowKey, v) + } + } + if shouldSendReqContentLength(req.Method, contentLength) { + w.writeHeader("content-length", strconv.FormatInt(contentLength, 10)) + } + if addGzipHeader { + w.writeHeader("accept-encoding", "gzip") + } + if !didUA { + w.writeHeader("user-agent", defaultUserAgent) + } + return w.hbuf.Bytes(), nil +} + +func (w *requestWriter) writeHeader(name, value string) { + w.logger.Debugf("http2: Transport encoding header %q = %q", name, value) + w.henc.WriteField(hpack.HeaderField{Name: name, Value: value}) +} + +// shouldSendReqContentLength reports whether the http2.Transport should send +// a "content-length" request header. This logic is basically a copy of the net/http +// transferWriter.shouldSendContentLength. +// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown). +// -1 means unknown. +func shouldSendReqContentLength(method string, contentLength int64) bool { + if contentLength > 0 { + return true + } + if contentLength < 0 { + return false + } + // For zero bodies, whether we send a content-length depends on the method. + // It also kinda doesn't matter for http2 either way, with END_STREAM. + switch method { + case "POST", "PUT", "PATCH": + return true + default: + return false + } +} + +func validPseudoPath(v string) bool { + return (len(v) > 0 && v[0] == '/' && (len(v) == 1 || v[1] != '/')) || v == "*" +} + +// actualContentLength returns a sanitized version of +// req.ContentLength, where 0 actually means zero (not unknown) and -1 +// means unknown. +func actualContentLength(req *http.Request) int64 { + if req.Body == nil { + return 0 + } + if req.ContentLength != 0 { + return req.ContentLength + } + return -1 +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/request_writer_test.go b/vendor/lucas-clemente/quic-go/h2quic/request_writer_test.go new file mode 100644 index 00000000..2b33fe7d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/request_writer_test.go @@ -0,0 +1,118 @@ +package h2quic + +import ( + "bytes" + "net/http" + "net/url" + "strconv" + "strings" + + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" + + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Request", func() { + var ( + rw *requestWriter + headerStream *mockStream + decoder *hpack.Decoder + ) + + BeforeEach(func() { + headerStream = &mockStream{} + rw = newRequestWriter(headerStream, utils.DefaultLogger) + decoder = hpack.NewDecoder(4096, func(hf hpack.HeaderField) {}) + }) + + decode := func(p []byte) (*http2.HeadersFrame, map[string] /* HeaderField.Name */ string /* HeaderField.Value */) { + framer := http2.NewFramer(nil, bytes.NewReader(p)) + frame, err := framer.ReadFrame() + Expect(err).ToNot(HaveOccurred()) + headerFrame := frame.(*http2.HeadersFrame) + fields, err := decoder.DecodeFull(headerFrame.HeaderBlockFragment()) + Expect(err).ToNot(HaveOccurred()) + values := make(map[string]string) + for _, headerField := range fields { + values[headerField.Name] = headerField.Value + } + return headerFrame, values + } + + It("writes a GET request", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/index.html?foo=bar", nil) + Expect(err).ToNot(HaveOccurred()) + rw.WriteRequest(req, 1337, true, false) + headerFrame, headerFields := decode(headerStream.dataWritten.Bytes()) + Expect(headerFrame.StreamID).To(Equal(uint32(1337))) + Expect(headerFrame.HasPriority()).To(BeTrue()) + Expect(headerFields).To(HaveKeyWithValue(":authority", "quic.clemente.io")) + Expect(headerFields).To(HaveKeyWithValue(":method", "GET")) + Expect(headerFields).To(HaveKeyWithValue(":path", "/index.html?foo=bar")) + Expect(headerFields).To(HaveKeyWithValue(":scheme", "https")) + Expect(headerFields).ToNot(HaveKey("accept-encoding")) + }) + + It("sets the EndStream header", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil) + Expect(err).ToNot(HaveOccurred()) + rw.WriteRequest(req, 1337, true, false) + headerFrame, _ := decode(headerStream.dataWritten.Bytes()) + Expect(headerFrame.StreamEnded()).To(BeTrue()) + }) + + It("doesn't set the EndStream header, if requested", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil) + Expect(err).ToNot(HaveOccurred()) + rw.WriteRequest(req, 1337, false, false) + headerFrame, _ := decode(headerStream.dataWritten.Bytes()) + Expect(headerFrame.StreamEnded()).To(BeFalse()) + }) + + It("requests gzip compression, if requested", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/index.html?foo=bar", nil) + Expect(err).ToNot(HaveOccurred()) + rw.WriteRequest(req, 1337, true, true) + _, headerFields := decode(headerStream.dataWritten.Bytes()) + Expect(headerFields).To(HaveKeyWithValue("accept-encoding", "gzip")) + }) + + It("writes a POST request", func() { + form := url.Values{} + form.Add("foo", "bar") + req, err := http.NewRequest("POST", "https://quic.clemente.io/upload.html", strings.NewReader(form.Encode())) + Expect(err).ToNot(HaveOccurred()) + rw.WriteRequest(req, 5, true, false) + _, headerFields := decode(headerStream.dataWritten.Bytes()) + Expect(headerFields).To(HaveKeyWithValue(":method", "POST")) + Expect(headerFields).To(HaveKey("content-length")) + contentLength, err := strconv.Atoi(headerFields["content-length"]) + Expect(err).ToNot(HaveOccurred()) + Expect(contentLength).To(BeNumerically(">", 0)) + }) + + It("sends cookies", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil) + Expect(err).ToNot(HaveOccurred()) + cookie1 := &http.Cookie{ + Name: "Cookie #1", + Value: "Value #1", + } + cookie2 := &http.Cookie{ + Name: "Cookie #2", + Value: "Value #2", + } + req.AddCookie(cookie1) + req.AddCookie(cookie2) + rw.WriteRequest(req, 11, true, false) + _, headerFields := decode(headerStream.dataWritten.Bytes()) + // TODO(lclemente): Remove Or() once we drop support for Go 1.8. + Expect(headerFields).To(Or( + HaveKeyWithValue("cookie", "Cookie #1=Value #1; Cookie #2=Value #2"), + HaveKeyWithValue("cookie", `Cookie #1="Value #1"; Cookie #2="Value #2"`), + )) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/h2quic/response.go b/vendor/lucas-clemente/quic-go/h2quic/response.go new file mode 100644 index 00000000..d5dd2194 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/response.go @@ -0,0 +1,95 @@ +package h2quic + +import ( + "bytes" + "errors" + "io/ioutil" + "net/http" + "net/textproto" + "strconv" + "strings" + + "golang.org/x/net/http2" +) + +// copied from net/http2/transport.go + +var errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") +var noBody = ioutil.NopCloser(bytes.NewReader(nil)) + +// from the handleResponse function +func responseFromHeaders(f *http2.MetaHeadersFrame) (*http.Response, error) { + if f.Truncated { + return nil, errResponseHeaderListSize + } + + status := f.PseudoValue("status") + if status == "" { + return nil, errors.New("missing status pseudo header") + } + statusCode, err := strconv.Atoi(status) + if err != nil { + return nil, errors.New("malformed non-numeric status pseudo header") + } + + // TODO: handle statusCode == 100 + + header := make(http.Header) + res := &http.Response{ + Proto: "HTTP/2.0", + ProtoMajor: 2, + Header: header, + StatusCode: statusCode, + Status: status + " " + http.StatusText(statusCode), + } + for _, hf := range f.RegularFields() { + key := http.CanonicalHeaderKey(hf.Name) + if key == "Trailer" { + t := res.Trailer + if t == nil { + t = make(http.Header) + res.Trailer = t + } + foreachHeaderElement(hf.Value, func(v string) { + t[http.CanonicalHeaderKey(v)] = nil + }) + } else { + header[key] = append(header[key], hf.Value) + } + } + + return res, nil +} + +// continuation of the handleResponse function +func setLength(res *http.Response, isHead, streamEnded bool) *http.Response { + if !streamEnded || isHead { + res.ContentLength = -1 + if clens := res.Header["Content-Length"]; len(clens) == 1 { + if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { + res.ContentLength = clen64 + } + } + } + return res +} + +// copied from net/http/server.go + +// foreachHeaderElement splits v according to the "#rule" construction +// in RFC 2616 section 2.1 and calls fn for each non-empty element. +func foreachHeaderElement(v string, fn func(string)) { + v = textproto.TrimString(v) + if v == "" { + return + } + if !strings.Contains(v, ",") { + fn(v) + return + } + for _, f := range strings.Split(v, ",") { + if f = textproto.TrimString(f); f != "" { + fn(f) + } + } +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/response_writer.go b/vendor/lucas-clemente/quic-go/h2quic/response_writer.go new file mode 100644 index 00000000..02841227 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/response_writer.go @@ -0,0 +1,114 @@ +package h2quic + +import ( + "bytes" + "net/http" + "strconv" + "strings" + "sync" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" +) + +type responseWriter struct { + dataStreamID protocol.StreamID + dataStream quic.Stream + + headerStream quic.Stream + headerStreamMutex *sync.Mutex + + header http.Header + status int // status code passed to WriteHeader + headerWritten bool + + logger utils.Logger +} + +func newResponseWriter( + headerStream quic.Stream, + headerStreamMutex *sync.Mutex, + dataStream quic.Stream, + dataStreamID protocol.StreamID, + logger utils.Logger, +) *responseWriter { + return &responseWriter{ + header: http.Header{}, + headerStream: headerStream, + headerStreamMutex: headerStreamMutex, + dataStream: dataStream, + dataStreamID: dataStreamID, + logger: logger, + } +} + +func (w *responseWriter) Header() http.Header { + return w.header +} + +func (w *responseWriter) WriteHeader(status int) { + if w.headerWritten { + return + } + w.headerWritten = true + w.status = status + + var headers bytes.Buffer + enc := hpack.NewEncoder(&headers) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)}) + + for k, v := range w.header { + for index := range v { + enc.WriteField(hpack.HeaderField{Name: strings.ToLower(k), Value: v[index]}) + } + } + + w.logger.Infof("Responding with %d", status) + w.headerStreamMutex.Lock() + defer w.headerStreamMutex.Unlock() + h2framer := http2.NewFramer(w.headerStream, nil) + err := h2framer.WriteHeaders(http2.HeadersFrameParam{ + StreamID: uint32(w.dataStreamID), + EndHeaders: true, + BlockFragment: headers.Bytes(), + }) + if err != nil { + w.logger.Errorf("could not write h2 header: %s", err.Error()) + } +} + +func (w *responseWriter) Write(p []byte) (int, error) { + if !w.headerWritten { + w.WriteHeader(200) + } + if !bodyAllowedForStatus(w.status) { + return 0, http.ErrBodyNotAllowed + } + return w.dataStream.Write(p) +} + +func (w *responseWriter) Flush() {} + +// This is a NOP. Use http.Request.Context +func (w *responseWriter) CloseNotify() <-chan bool { return make(<-chan bool) } + +// test that we implement http.Flusher +var _ http.Flusher = &responseWriter{} + +// copied from http2/http2.go +// bodyAllowedForStatus reports whether a given response status code +// permits a body. See RFC 2616, section 4.4. +func bodyAllowedForStatus(status int) bool { + switch { + case status >= 100 && status <= 199: + return false + case status == 204: + return false + case status == 304: + return false + } + return true +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/response_writer_closenotifier.go b/vendor/lucas-clemente/quic-go/h2quic/response_writer_closenotifier.go new file mode 100644 index 00000000..b26f91c1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/response_writer_closenotifier.go @@ -0,0 +1,9 @@ +package h2quic + +import "net/http" + +// The CloseNotifier is a deprecated interface, and staticcheck will report that from Go 1.11. +// By defining it in a separate file, we can exclude this file from staticcheck. + +// test that we implement http.CloseNotifier +var _ http.CloseNotifier = &responseWriter{} diff --git a/vendor/lucas-clemente/quic-go/h2quic/response_writer_test.go b/vendor/lucas-clemente/quic-go/h2quic/response_writer_test.go new file mode 100644 index 00000000..77c67a93 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/response_writer_test.go @@ -0,0 +1,163 @@ +package h2quic + +import ( + "bytes" + "context" + "io" + "net/http" + "sync" + "time" + + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockStream struct { + id protocol.StreamID + dataToRead bytes.Buffer + dataWritten bytes.Buffer + reset bool + canceledWrite bool + closed bool + remoteClosed bool + + unblockRead chan struct{} + ctx context.Context + ctxCancel context.CancelFunc +} + +var _ quic.Stream = &mockStream{} + +func newMockStream(id protocol.StreamID) *mockStream { + s := &mockStream{ + id: id, + unblockRead: make(chan struct{}), + } + s.ctx, s.ctxCancel = context.WithCancel(context.Background()) + return s +} + +func (s *mockStream) Close() error { s.closed = true; s.ctxCancel(); return nil } +func (s *mockStream) CancelRead(quic.ErrorCode) error { s.reset = true; return nil } +func (s *mockStream) CancelWrite(quic.ErrorCode) error { s.canceledWrite = true; return nil } +func (s *mockStream) CloseRemote(offset protocol.ByteCount) { s.remoteClosed = true; s.ctxCancel() } +func (s mockStream) StreamID() protocol.StreamID { return s.id } +func (s *mockStream) Context() context.Context { return s.ctx } +func (s *mockStream) SetDeadline(time.Time) error { panic("not implemented") } +func (s *mockStream) SetReadDeadline(time.Time) error { panic("not implemented") } +func (s *mockStream) SetWriteDeadline(time.Time) error { panic("not implemented") } + +func (s *mockStream) Read(p []byte) (int, error) { + n, _ := s.dataToRead.Read(p) + if n == 0 { // block if there's no data + <-s.unblockRead + return 0, io.EOF + } + return n, nil // never return an EOF +} +func (s *mockStream) Write(p []byte) (int, error) { return s.dataWritten.Write(p) } + +var _ = Describe("Response Writer", func() { + var ( + w *responseWriter + headerStream *mockStream + dataStream *mockStream + ) + + BeforeEach(func() { + headerStream = &mockStream{} + dataStream = &mockStream{} + w = newResponseWriter(headerStream, &sync.Mutex{}, dataStream, 5, utils.DefaultLogger) + }) + + decodeHeaderFields := func() map[string][]string { + fields := make(map[string][]string) + decoder := hpack.NewDecoder(4096, func(hf hpack.HeaderField) {}) + h2framer := http2.NewFramer(nil, bytes.NewReader(headerStream.dataWritten.Bytes())) + + frame, err := h2framer.ReadFrame() + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(BeAssignableToTypeOf(&http2.HeadersFrame{})) + hframe := frame.(*http2.HeadersFrame) + mhframe := &http2.MetaHeadersFrame{HeadersFrame: hframe} + Expect(mhframe.StreamID).To(BeEquivalentTo(5)) + mhframe.Fields, err = decoder.DecodeFull(hframe.HeaderBlockFragment()) + Expect(err).ToNot(HaveOccurred()) + for _, p := range mhframe.Fields { + fields[p.Name] = append(fields[p.Name], p.Value) + } + return fields + } + + It("writes status", func() { + w.WriteHeader(http.StatusTeapot) + fields := decodeHeaderFields() + Expect(fields).To(HaveLen(1)) + Expect(fields).To(HaveKeyWithValue(":status", []string{"418"})) + }) + + It("writes headers", func() { + w.Header().Add("content-length", "42") + w.WriteHeader(http.StatusTeapot) + fields := decodeHeaderFields() + Expect(fields).To(HaveKeyWithValue("content-length", []string{"42"})) + }) + + It("writes multiple headers with the same name", func() { + const cookie1 = "test1=1; Max-Age=7200; path=/" + const cookie2 = "test2=2; Max-Age=7200; path=/" + w.Header().Add("set-cookie", cookie1) + w.Header().Add("set-cookie", cookie2) + w.WriteHeader(http.StatusTeapot) + fields := decodeHeaderFields() + Expect(fields).To(HaveKey("set-cookie")) + cookies := fields["set-cookie"] + Expect(cookies).To(ContainElement(cookie1)) + Expect(cookies).To(ContainElement(cookie2)) + }) + + It("writes data", func() { + n, err := w.Write([]byte("foobar")) + Expect(n).To(Equal(6)) + Expect(err).ToNot(HaveOccurred()) + // Should have written 200 on the header stream + fields := decodeHeaderFields() + Expect(fields).To(HaveKeyWithValue(":status", []string{"200"})) + // And foobar on the data stream + Expect(dataStream.dataWritten.Bytes()).To(Equal([]byte("foobar"))) + }) + + It("writes data after WriteHeader is called", func() { + w.WriteHeader(http.StatusTeapot) + n, err := w.Write([]byte("foobar")) + Expect(n).To(Equal(6)) + Expect(err).ToNot(HaveOccurred()) + // Should have written 418 on the header stream + fields := decodeHeaderFields() + Expect(fields).To(HaveKeyWithValue(":status", []string{"418"})) + // And foobar on the data stream + Expect(dataStream.dataWritten.Bytes()).To(Equal([]byte("foobar"))) + }) + + It("does not WriteHeader() twice", func() { + w.WriteHeader(200) + w.WriteHeader(500) + fields := decodeHeaderFields() + Expect(fields).To(HaveLen(1)) + Expect(fields).To(HaveKeyWithValue(":status", []string{"200"})) + }) + + It("doesn't allow writes if the status code doesn't allow a body", func() { + w.WriteHeader(304) + n, err := w.Write([]byte("foobar")) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(http.ErrBodyNotAllowed)) + Expect(dataStream.dataWritten.Bytes()).To(HaveLen(0)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/h2quic/roundtrip.go b/vendor/lucas-clemente/quic-go/h2quic/roundtrip.go new file mode 100644 index 00000000..27732b5e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/roundtrip.go @@ -0,0 +1,179 @@ +package h2quic + +import ( + "crypto/tls" + "errors" + "fmt" + "io" + "net/http" + "strings" + "sync" + + quic "github.com/lucas-clemente/quic-go" + + "golang.org/x/net/http/httpguts" +) + +type roundTripCloser interface { + http.RoundTripper + io.Closer +} + +// RoundTripper implements the http.RoundTripper interface +type RoundTripper struct { + mutex sync.Mutex + + // DisableCompression, if true, prevents the Transport from + // requesting compression with an "Accept-Encoding: gzip" + // request header when the Request contains no existing + // Accept-Encoding value. If the Transport requests gzip on + // its own and gets a gzipped response, it's transparently + // decoded in the Response.Body. However, if the user + // explicitly requested gzip it is not automatically + // uncompressed. + DisableCompression bool + + // TLSClientConfig specifies the TLS configuration to use with + // tls.Client. If nil, the default configuration is used. + TLSClientConfig *tls.Config + + // QuicConfig is the quic.Config used for dialing new connections. + // If nil, reasonable default values will be used. + QuicConfig *quic.Config + + // Dial specifies an optional dial function for creating QUIC + // connections for requests. + // If Dial is nil, quic.DialAddr will be used. + Dial func(network, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.Session, error) + + clients map[string]roundTripCloser +} + +// RoundTripOpt are options for the Transport.RoundTripOpt method. +type RoundTripOpt struct { + // OnlyCachedConn controls whether the RoundTripper may + // create a new QUIC connection. If set true and + // no cached connection is available, RoundTrip + // will return ErrNoCachedConn. + OnlyCachedConn bool +} + +var _ roundTripCloser = &RoundTripper{} + +// ErrNoCachedConn is returned when RoundTripper.OnlyCachedConn is set +var ErrNoCachedConn = errors.New("h2quic: no cached connection was available") + +// RoundTripOpt is like RoundTrip, but takes options. +func (r *RoundTripper) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) { + if req.URL == nil { + closeRequestBody(req) + return nil, errors.New("quic: nil Request.URL") + } + if req.URL.Host == "" { + closeRequestBody(req) + return nil, errors.New("quic: no Host in request URL") + } + if req.Header == nil { + closeRequestBody(req) + return nil, errors.New("quic: nil Request.Header") + } + + if req.URL.Scheme == "https" { + for k, vv := range req.Header { + if !httpguts.ValidHeaderFieldName(k) { + return nil, fmt.Errorf("quic: invalid http header field name %q", k) + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + return nil, fmt.Errorf("quic: invalid http header field value %q for key %v", v, k) + } + } + } + } else { + closeRequestBody(req) + return nil, fmt.Errorf("quic: unsupported protocol scheme: %s", req.URL.Scheme) + } + + if req.Method != "" && !validMethod(req.Method) { + closeRequestBody(req) + return nil, fmt.Errorf("quic: invalid method %q", req.Method) + } + + hostname := authorityAddr("https", hostnameFromRequest(req)) + cl, err := r.getClient(hostname, opt.OnlyCachedConn) + if err != nil { + return nil, err + } + return cl.RoundTrip(req) +} + +// RoundTrip does a round trip. +func (r *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + return r.RoundTripOpt(req, RoundTripOpt{}) +} + +func (r *RoundTripper) getClient(hostname string, onlyCached bool) (http.RoundTripper, error) { + r.mutex.Lock() + defer r.mutex.Unlock() + + if r.clients == nil { + r.clients = make(map[string]roundTripCloser) + } + + client, ok := r.clients[hostname] + if !ok { + if onlyCached { + return nil, ErrNoCachedConn + } + client = newClient( + hostname, + r.TLSClientConfig, + &roundTripperOpts{DisableCompression: r.DisableCompression}, + r.QuicConfig, + r.Dial, + ) + r.clients[hostname] = client + } + return client, nil +} + +// Close closes the QUIC connections that this RoundTripper has used +func (r *RoundTripper) Close() error { + r.mutex.Lock() + defer r.mutex.Unlock() + for _, client := range r.clients { + if err := client.Close(); err != nil { + return err + } + } + r.clients = nil + return nil +} + +func closeRequestBody(req *http.Request) { + if req.Body != nil { + req.Body.Close() + } +} + +func validMethod(method string) bool { + /* + Method = "OPTIONS" ; Section 9.2 + | "GET" ; Section 9.3 + | "HEAD" ; Section 9.4 + | "POST" ; Section 9.5 + | "PUT" ; Section 9.6 + | "DELETE" ; Section 9.7 + | "TRACE" ; Section 9.8 + | "CONNECT" ; Section 9.9 + | extension-method + extension-method = token + token = 1* + */ + return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1 +} + +// copied from net/http/http.go +func isNotToken(r rune) bool { + return !httpguts.IsTokenRune(r) +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/roundtrip_test.go b/vendor/lucas-clemente/quic-go/h2quic/roundtrip_test.go new file mode 100644 index 00000000..cec802f0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/roundtrip_test.go @@ -0,0 +1,218 @@ +package h2quic + +import ( + "bytes" + "crypto/tls" + "errors" + "io" + "net/http" + "time" + + quic "github.com/lucas-clemente/quic-go" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockClient struct { + closed bool +} + +func (m *mockClient) RoundTrip(req *http.Request) (*http.Response, error) { + return &http.Response{Request: req}, nil +} +func (m *mockClient) Close() error { + m.closed = true + return nil +} + +var _ roundTripCloser = &mockClient{} + +type mockBody struct { + reader bytes.Reader + readErr error + closeErr error + closed bool +} + +func (m *mockBody) Read(p []byte) (int, error) { + if m.readErr != nil { + return 0, m.readErr + } + return m.reader.Read(p) +} + +func (m *mockBody) SetData(data []byte) { + m.reader = *bytes.NewReader(data) +} + +func (m *mockBody) Close() error { + m.closed = true + return m.closeErr +} + +// make sure the mockBody can be used as a http.Request.Body +var _ io.ReadCloser = &mockBody{} + +var _ = Describe("RoundTripper", func() { + var ( + rt *RoundTripper + req1 *http.Request + ) + + BeforeEach(func() { + rt = &RoundTripper{} + var err error + req1, err = http.NewRequest("GET", "https://www.example.org/file1.html", nil) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("dialing hosts", func() { + origDialAddr := dialAddr + streamOpenErr := errors.New("error opening stream") + + BeforeEach(func() { + origDialAddr = dialAddr + dialAddr = func(addr string, tlsConf *tls.Config, config *quic.Config) (quic.Session, error) { + // return an error when trying to open a stream + // we don't want to test all the dial logic here, just that dialing happens at all + return &mockSession{streamOpenErr: streamOpenErr}, nil + } + }) + + AfterEach(func() { + dialAddr = origDialAddr + }) + + It("creates new clients", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/foobar.html", nil) + Expect(err).ToNot(HaveOccurred()) + _, err = rt.RoundTrip(req) + Expect(err).To(MatchError(streamOpenErr)) + Expect(rt.clients).To(HaveLen(1)) + }) + + It("uses the quic.Config, if provided", func() { + config := &quic.Config{HandshakeTimeout: time.Millisecond} + var receivedConfig *quic.Config + dialAddr = func(addr string, tlsConf *tls.Config, config *quic.Config) (quic.Session, error) { + receivedConfig = config + return nil, errors.New("err") + } + rt.QuicConfig = config + rt.RoundTrip(req1) + Expect(receivedConfig).To(Equal(config)) + }) + + It("uses the custom dialer, if provided", func() { + var dialed bool + dialer := func(_, _ string, tlsCfgP *tls.Config, cfg *quic.Config) (quic.Session, error) { + dialed = true + return nil, errors.New("err") + } + rt.Dial = dialer + rt.RoundTrip(req1) + Expect(dialed).To(BeTrue()) + }) + + It("reuses existing clients", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/file1.html", nil) + Expect(err).ToNot(HaveOccurred()) + _, err = rt.RoundTrip(req) + Expect(err).To(MatchError(streamOpenErr)) + Expect(rt.clients).To(HaveLen(1)) + req2, err := http.NewRequest("GET", "https://quic.clemente.io/file2.html", nil) + Expect(err).ToNot(HaveOccurred()) + _, err = rt.RoundTrip(req2) + Expect(err).To(MatchError(streamOpenErr)) + Expect(rt.clients).To(HaveLen(1)) + }) + + It("doesn't create new clients if RoundTripOpt.OnlyCachedConn is set", func() { + req, err := http.NewRequest("GET", "https://quic.clemente.io/foobar.html", nil) + Expect(err).ToNot(HaveOccurred()) + _, err = rt.RoundTripOpt(req, RoundTripOpt{OnlyCachedConn: true}) + Expect(err).To(MatchError(ErrNoCachedConn)) + }) + }) + + Context("validating request", func() { + It("rejects plain HTTP requests", func() { + req, err := http.NewRequest("GET", "http://www.example.org/", nil) + req.Body = &mockBody{} + Expect(err).ToNot(HaveOccurred()) + _, err = rt.RoundTrip(req) + Expect(err).To(MatchError("quic: unsupported protocol scheme: http")) + Expect(req.Body.(*mockBody).closed).To(BeTrue()) + }) + + It("rejects requests without a URL", func() { + req1.URL = nil + req1.Body = &mockBody{} + _, err := rt.RoundTrip(req1) + Expect(err).To(MatchError("quic: nil Request.URL")) + Expect(req1.Body.(*mockBody).closed).To(BeTrue()) + }) + + It("rejects request without a URL Host", func() { + req1.URL.Host = "" + req1.Body = &mockBody{} + _, err := rt.RoundTrip(req1) + Expect(err).To(MatchError("quic: no Host in request URL")) + Expect(req1.Body.(*mockBody).closed).To(BeTrue()) + }) + + It("doesn't try to close the body if the request doesn't have one", func() { + req1.URL = nil + Expect(req1.Body).To(BeNil()) + _, err := rt.RoundTrip(req1) + Expect(err).To(MatchError("quic: nil Request.URL")) + }) + + It("rejects requests without a header", func() { + req1.Header = nil + req1.Body = &mockBody{} + _, err := rt.RoundTrip(req1) + Expect(err).To(MatchError("quic: nil Request.Header")) + Expect(req1.Body.(*mockBody).closed).To(BeTrue()) + }) + + It("rejects requests with invalid header name fields", func() { + req1.Header.Add("foobär", "value") + _, err := rt.RoundTrip(req1) + Expect(err).To(MatchError("quic: invalid http header field name \"foobär\"")) + }) + + It("rejects requests with invalid header name values", func() { + req1.Header.Add("foo", string([]byte{0x7})) + _, err := rt.RoundTrip(req1) + Expect(err.Error()).To(ContainSubstring("quic: invalid http header field value")) + }) + + It("rejects requests with an invalid request method", func() { + req1.Method = "foobär" + req1.Body = &mockBody{} + _, err := rt.RoundTrip(req1) + Expect(err).To(MatchError("quic: invalid method \"foobär\"")) + Expect(req1.Body.(*mockBody).closed).To(BeTrue()) + }) + }) + + Context("closing", func() { + It("closes", func() { + rt.clients = make(map[string]roundTripCloser) + cl := &mockClient{} + rt.clients["foo.bar"] = cl + err := rt.Close() + Expect(err).ToNot(HaveOccurred()) + Expect(len(rt.clients)).To(BeZero()) + Expect(cl.closed).To(BeTrue()) + }) + + It("closes a RoundTripper that has never been used", func() { + Expect(len(rt.clients)).To(BeZero()) + err := rt.Close() + Expect(err).ToNot(HaveOccurred()) + Expect(len(rt.clients)).To(BeZero()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/h2quic/server.go b/vendor/lucas-clemente/quic-go/h2quic/server.go new file mode 100644 index 00000000..0d787bdd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/server.go @@ -0,0 +1,402 @@ +package h2quic + +import ( + "crypto/tls" + "errors" + "fmt" + "net" + "net/http" + "runtime" + "strings" + "sync" + "sync/atomic" + "time" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" +) + +type streamCreator interface { + quic.Session + GetOrOpenStream(protocol.StreamID) (quic.Stream, error) +} + +type remoteCloser interface { + CloseRemote(protocol.ByteCount) +} + +// allows mocking of quic.Listen and quic.ListenAddr +var ( + quicListen = quic.Listen + quicListenAddr = quic.ListenAddr +) + +// Server is a HTTP2 server listening for QUIC connections. +type Server struct { + *http.Server + + // By providing a quic.Config, it is possible to set parameters of the QUIC connection. + // If nil, it uses reasonable default values. + QuicConfig *quic.Config + + // Private flag for demo, do not use + CloseAfterFirstRequest bool + + port uint32 // used atomically + + listenerMutex sync.Mutex + listener quic.Listener + closed bool + + supportedVersionsAsString string + + logger utils.Logger // will be set by Server.serveImpl() +} + +// ListenAndServe listens on the UDP address s.Addr and calls s.Handler to handle HTTP/2 requests on incoming connections. +func (s *Server) ListenAndServe() error { + if s.Server == nil { + return errors.New("use of h2quic.Server without http.Server") + } + return s.serveImpl(s.TLSConfig, nil) +} + +// ListenAndServeTLS listens on the UDP address s.Addr and calls s.Handler to handle HTTP/2 requests on incoming connections. +func (s *Server) ListenAndServeTLS(certFile, keyFile string) error { + var err error + certs := make([]tls.Certificate, 1) + certs[0], err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } + // We currently only use the cert-related stuff from tls.Config, + // so we don't need to make a full copy. + config := &tls.Config{ + Certificates: certs, + } + return s.serveImpl(config, nil) +} + +// Serve an existing UDP connection. +func (s *Server) Serve(conn net.PacketConn) error { + return s.serveImpl(s.TLSConfig, conn) +} + +func (s *Server) serveImpl(tlsConfig *tls.Config, conn net.PacketConn) error { + if s.Server == nil { + return errors.New("use of h2quic.Server without http.Server") + } + s.logger = utils.DefaultLogger.WithPrefix("server") + s.listenerMutex.Lock() + if s.closed { + s.listenerMutex.Unlock() + return errors.New("Server is already closed") + } + if s.listener != nil { + s.listenerMutex.Unlock() + return errors.New("ListenAndServe may only be called once") + } + + var ln quic.Listener + var err error + if conn == nil { + ln, err = quicListenAddr(s.Addr, tlsConfig, s.QuicConfig) + } else { + ln, err = quicListen(conn, tlsConfig, s.QuicConfig) + } + if err != nil { + s.listenerMutex.Unlock() + return err + } + s.listener = ln + s.listenerMutex.Unlock() + + for { + sess, err := ln.Accept() + if err != nil { + return err + } + go s.handleHeaderStream(sess.(streamCreator)) + } +} + +func (s *Server) handleHeaderStream(session streamCreator) { + stream, err := session.AcceptStream() + if err != nil { + session.CloseWithError(quic.ErrorCode(qerr.InvalidHeadersStreamData), err) + return + } + + hpackDecoder := hpack.NewDecoder(4096, nil) + h2framer := http2.NewFramer(nil, stream) + + var headerStreamMutex sync.Mutex // Protects concurrent calls to Write() + for { + if err := s.handleRequest(session, stream, &headerStreamMutex, hpackDecoder, h2framer); err != nil { + // QuicErrors must originate from stream.Read() returning an error. + // In this case, the session has already logged the error, so we don't + // need to log it again. + errorCode := qerr.InternalError + if qerr, ok := err.(*qerr.QuicError); !ok { + errorCode = qerr.ErrorCode + s.logger.Errorf("error handling h2 request: %s", err.Error()) + } + session.CloseWithError(quic.ErrorCode(errorCode), err) + return + } + } +} + +func (s *Server) handleRequest(session streamCreator, headerStream quic.Stream, headerStreamMutex *sync.Mutex, hpackDecoder *hpack.Decoder, h2framer *http2.Framer) error { + h2frame, err := h2framer.ReadFrame() + if err != nil { + return qerr.Error(qerr.HeadersStreamDataDecompressFailure, "cannot read frame") + } + var h2headersFrame *http2.HeadersFrame + switch f := h2frame.(type) { + case *http2.PriorityFrame: + // ignore PRIORITY frames + s.logger.Debugf("Ignoring H2 PRIORITY frame: %#v", f) + return nil + case *http2.HeadersFrame: + h2headersFrame = f + default: + return qerr.Error(qerr.InvalidHeadersStreamData, "expected a header frame") + } + + if !h2headersFrame.HeadersEnded() { + return errors.New("http2 header continuation not implemented") + } + headers, err := hpackDecoder.DecodeFull(h2headersFrame.HeaderBlockFragment()) + if err != nil { + s.logger.Errorf("invalid http2 headers encoding: %s", err.Error()) + return err + } + + req, err := requestFromHeaders(headers) + if err != nil { + return err + } + + if s.logger.Debug() { + s.logger.Infof("%s %s%s, on data stream %d", req.Method, req.Host, req.RequestURI, h2headersFrame.StreamID) + } else { + s.logger.Infof("%s %s%s", req.Method, req.Host, req.RequestURI) + } + + dataStream, err := session.GetOrOpenStream(protocol.StreamID(h2headersFrame.StreamID)) + if err != nil { + return err + } + // this can happen if the client immediately closes the data stream after sending the request and the runtime processes the reset before the request + if dataStream == nil { + return nil + } + + // handleRequest should be as non-blocking as possible to minimize + // head-of-line blocking. Potentially blocking code is run in a separate + // goroutine, enabling handleRequest to return before the code is executed. + go func() { + streamEnded := h2headersFrame.StreamEnded() + if streamEnded { + dataStream.(remoteCloser).CloseRemote(0) + streamEnded = true + _, _ = dataStream.Read([]byte{0}) // read the eof + } + + req = req.WithContext(dataStream.Context()) + reqBody := newRequestBody(dataStream) + req.Body = reqBody + + req.RemoteAddr = session.RemoteAddr().String() + + responseWriter := newResponseWriter(headerStream, headerStreamMutex, dataStream, protocol.StreamID(h2headersFrame.StreamID), s.logger) + + handler := s.Handler + if handler == nil { + handler = http.DefaultServeMux + } + panicked := false + func() { + defer func() { + if p := recover(); p != nil { + // Copied from net/http/server.go + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + s.logger.Errorf("http: panic serving: %v\n%s", p, buf) + panicked = true + } + }() + handler.ServeHTTP(responseWriter, req) + }() + if panicked { + responseWriter.WriteHeader(500) + } else { + responseWriter.WriteHeader(200) + } + if responseWriter.dataStream != nil { + if !streamEnded && !reqBody.requestRead { + // in gQUIC, the error code doesn't matter, so just use 0 here + responseWriter.dataStream.CancelRead(0) + } + responseWriter.dataStream.Close() + } + if s.CloseAfterFirstRequest { + time.Sleep(100 * time.Millisecond) + session.Close() + } + }() + + return nil +} + +// Close the server immediately, aborting requests and sending CONNECTION_CLOSE frames to connected clients. +// Close in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established. +func (s *Server) Close() error { + s.listenerMutex.Lock() + defer s.listenerMutex.Unlock() + s.closed = true + if s.listener != nil { + err := s.listener.Close() + s.listener = nil + return err + } + return nil +} + +// CloseGracefully shuts down the server gracefully. The server sends a GOAWAY frame first, then waits for either timeout to trigger, or for all running requests to complete. +// CloseGracefully in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established. +func (s *Server) CloseGracefully(timeout time.Duration) error { + // TODO: implement + return nil +} + +// SetQuicHeaders can be used to set the proper headers that announce that this server supports QUIC. +// The values that are set depend on the port information from s.Server.Addr, and currently look like this (if Addr has port 443): +// Alt-Svc: quic=":443"; ma=2592000; v="33,32,31,30" +func (s *Server) SetQuicHeaders(hdr http.Header) error { + port := atomic.LoadUint32(&s.port) + + if port == 0 { + // Extract port from s.Server.Addr + _, portStr, err := net.SplitHostPort(s.Server.Addr) + if err != nil { + return err + } + portInt, err := net.LookupPort("tcp", portStr) + if err != nil { + return err + } + port = uint32(portInt) + atomic.StoreUint32(&s.port, port) + } + + if s.supportedVersionsAsString == "" { + var versions []string + for _, v := range protocol.SupportedVersions { + versions = append(versions, v.ToAltSvc()) + } + s.supportedVersionsAsString = strings.Join(versions, ",") + } + + hdr.Add("Alt-Svc", fmt.Sprintf(`quic=":%d"; ma=2592000; v="%s"`, port, s.supportedVersionsAsString)) + + return nil +} + +// ListenAndServeQUIC listens on the UDP network address addr and calls the +// handler for HTTP/2 requests on incoming connections. http.DefaultServeMux is +// used when handler is nil. +func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) error { + server := &Server{ + Server: &http.Server{ + Addr: addr, + Handler: handler, + }, + } + return server.ListenAndServeTLS(certFile, keyFile) +} + +// ListenAndServe listens on the given network address for both, TLS and QUIC +// connetions in parallel. It returns if one of the two returns an error. +// http.DefaultServeMux is used when handler is nil. +// The correct Alt-Svc headers for QUIC are set. +func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error { + // Load certs + var err error + certs := make([]tls.Certificate, 1) + certs[0], err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } + // We currently only use the cert-related stuff from tls.Config, + // so we don't need to make a full copy. + config := &tls.Config{ + Certificates: certs, + } + + // Open the listeners + udpAddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + return err + } + udpConn, err := net.ListenUDP("udp", udpAddr) + if err != nil { + return err + } + defer udpConn.Close() + + tcpAddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return err + } + tcpConn, err := net.ListenTCP("tcp", tcpAddr) + if err != nil { + return err + } + defer tcpConn.Close() + + tlsConn := tls.NewListener(tcpConn, config) + defer tlsConn.Close() + + // Start the servers + httpServer := &http.Server{ + Addr: addr, + TLSConfig: config, + } + + quicServer := &Server{ + Server: httpServer, + } + + if handler == nil { + handler = http.DefaultServeMux + } + httpServer.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + quicServer.SetQuicHeaders(w.Header()) + handler.ServeHTTP(w, r) + }) + + hErr := make(chan error) + qErr := make(chan error) + go func() { + hErr <- httpServer.Serve(tlsConn) + }() + go func() { + qErr <- quicServer.Serve(udpConn) + }() + + select { + case err := <-hErr: + quicServer.Close() + return err + case err := <-qErr: + // Cannot close the HTTP server or wait for requests to complete properly :/ + return err + } +} diff --git a/vendor/lucas-clemente/quic-go/h2quic/server_test.go b/vendor/lucas-clemente/quic-go/h2quic/server_test.go new file mode 100644 index 00000000..6125f2bc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/h2quic/server_test.go @@ -0,0 +1,536 @@ +package h2quic + +import ( + "bytes" + "context" + "crypto/tls" + "errors" + "fmt" + "io" + "net" + "net/http" + "strings" + "sync" + "time" + + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockSession struct { + closed bool + closedWithError error + dataStream quic.Stream + streamToAccept quic.Stream + streamsToOpen []quic.Stream + blockOpenStreamSync bool + blockOpenStreamChan chan struct{} // close this chan (or call Close) to make OpenStreamSync return + streamOpenErr error + ctx context.Context + ctxCancel context.CancelFunc +} + +func newMockSession() *mockSession { + return &mockSession{blockOpenStreamChan: make(chan struct{})} +} + +func (s *mockSession) GetOrOpenStream(id protocol.StreamID) (quic.Stream, error) { + return s.dataStream, nil +} +func (s *mockSession) AcceptStream() (quic.Stream, error) { return s.streamToAccept, nil } +func (s *mockSession) OpenStream() (quic.Stream, error) { + if s.streamOpenErr != nil { + return nil, s.streamOpenErr + } + str := s.streamsToOpen[0] + s.streamsToOpen = s.streamsToOpen[1:] + return str, nil +} +func (s *mockSession) OpenStreamSync() (quic.Stream, error) { + if s.blockOpenStreamSync { + <-s.blockOpenStreamChan + } + return s.OpenStream() +} +func (s *mockSession) Close() error { + s.ctxCancel() + if !s.closed { + close(s.blockOpenStreamChan) + } + s.closed = true + return nil +} +func (s *mockSession) CloseWithError(_ quic.ErrorCode, e error) error { + s.closedWithError = e + return s.Close() +} +func (s *mockSession) LocalAddr() net.Addr { + panic("not implemented") +} +func (s *mockSession) RemoteAddr() net.Addr { + return &net.UDPAddr{IP: []byte{127, 0, 0, 1}, Port: 42} +} +func (s *mockSession) Context() context.Context { + return s.ctx +} +func (s *mockSession) ConnectionState() quic.ConnectionState { panic("not implemented") } +func (s *mockSession) AcceptUniStream() (quic.ReceiveStream, error) { panic("not implemented") } +func (s *mockSession) OpenUniStream() (quic.SendStream, error) { panic("not implemented") } +func (s *mockSession) OpenUniStreamSync() (quic.SendStream, error) { panic("not implemented") } + +var _ = Describe("H2 server", func() { + var ( + s *Server + session *mockSession + dataStream *mockStream + origQuicListenAddr = quicListenAddr + ) + + BeforeEach(func() { + s = &Server{ + Server: &http.Server{ + TLSConfig: testdata.GetTLSConfig(), + }, + logger: utils.DefaultLogger, + } + dataStream = newMockStream(0) + close(dataStream.unblockRead) + session = newMockSession() + session.dataStream = dataStream + session.ctx, session.ctxCancel = context.WithCancel(context.Background()) + origQuicListenAddr = quicListenAddr + }) + + AfterEach(func() { + quicListenAddr = origQuicListenAddr + }) + + Context("handling requests", func() { + var ( + h2framer *http2.Framer + hpackDecoder *hpack.Decoder + headerStream *mockStream + ) + + BeforeEach(func() { + headerStream = &mockStream{} + hpackDecoder = hpack.NewDecoder(4096, nil) + h2framer = http2.NewFramer(nil, headerStream) + }) + + It("handles a sample GET request", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + Expect(r.Host).To(Equal("www.example.com")) + Expect(r.RemoteAddr).To(Equal("127.0.0.1:42")) + handlerCalled = true + }) + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x5, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() bool { return handlerCalled }).Should(BeTrue()) + Expect(dataStream.remoteClosed).To(BeTrue()) + Expect(dataStream.reset).To(BeFalse()) + }) + + It("returns 200 with an empty handler", func() { + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x5, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() []byte { + return headerStream.dataWritten.Bytes() + }).Should(Equal([]byte{0x0, 0x0, 0x1, 0x1, 0x4, 0x0, 0x0, 0x0, 0x5, 0x88})) // 0x88 is 200 + }) + + It("correctly handles a panicking handler", func() { + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + panic("foobar") + }) + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x5, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() []byte { + return headerStream.dataWritten.Bytes() + }).Should(Equal([]byte{0x0, 0x0, 0x1, 0x1, 0x4, 0x0, 0x0, 0x0, 0x5, 0x8e})) // 0x82 is 500 + }) + + It("resets the dataStream when client sends a body in GET request", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Expect(r.Host).To(Equal("www.example.com")) + handlerCalled = true + }) + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x4, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() bool { return handlerCalled }).Should(BeTrue()) + Eventually(func() bool { return dataStream.reset }).Should(BeTrue()) + Expect(dataStream.remoteClosed).To(BeFalse()) + }) + + It("resets the dataStream when the body of POST request is not read", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Expect(r.Host).To(Equal("www.example.com")) + Expect(r.Method).To(Equal("POST")) + handlerCalled = true + }) + headerStream.dataToRead.Write([]byte{0x0, 0x0, 0x20, 0x1, 0x24, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0xff, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, 0x83, 0x84, 0x87, 0x5c, 0x1, 0x37, 0x7a, 0x85, 0xed, 0x69, 0x88, 0xb4, 0xc7}) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() bool { return dataStream.reset }).Should(BeTrue()) + Consistently(func() bool { return dataStream.remoteClosed }).Should(BeFalse()) + Expect(handlerCalled).To(BeTrue()) + }) + + It("handles a request for which the client immediately resets the data stream", func() { + session.dataStream = nil + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handlerCalled = true + }) + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x5, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Consistently(func() bool { return handlerCalled }).Should(BeFalse()) + }) + + It("resets the dataStream when the body of POST request is not read, and the request handler replaces the request.Body", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r.Body = struct { + io.Reader + io.Closer + }{} + handlerCalled = true + }) + headerStream.dataToRead.Write([]byte{0x0, 0x0, 0x20, 0x1, 0x24, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0xff, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, 0x83, 0x84, 0x87, 0x5c, 0x1, 0x37, 0x7a, 0x85, 0xed, 0x69, 0x88, 0xb4, 0xc7}) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() bool { return dataStream.reset }).Should(BeTrue()) + Consistently(func() bool { return dataStream.remoteClosed }).Should(BeFalse()) + Expect(handlerCalled).To(BeTrue()) + }) + + It("closes the dataStream if the body of POST request was read", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Expect(r.Host).To(Equal("www.example.com")) + Expect(r.Method).To(Equal("POST")) + handlerCalled = true + // read the request body + b := make([]byte, 1000) + n, _ := r.Body.Read(b) + Expect(n).ToNot(BeZero()) + }) + headerStream.dataToRead.Write([]byte{0x0, 0x0, 0x20, 0x1, 0x24, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0xff, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, 0x83, 0x84, 0x87, 0x5c, 0x1, 0x37, 0x7a, 0x85, 0xed, 0x69, 0x88, 0xb4, 0xc7}) + dataStream.dataToRead.Write([]byte("foo=bar")) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() bool { return handlerCalled }).Should(BeTrue()) + Expect(dataStream.reset).To(BeFalse()) + }) + + It("ignores PRIORITY frames", func() { + handlerCalled := make(chan struct{}) + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + close(handlerCalled) + }) + buf := &bytes.Buffer{} + framer := http2.NewFramer(buf, nil) + err := framer.WritePriority(10, http2.PriorityParam{Weight: 42}) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).ToNot(BeEmpty()) + headerStream.dataToRead.Write(buf.Bytes()) + err = s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).ToNot(HaveOccurred()) + Consistently(handlerCalled).ShouldNot(BeClosed()) + Expect(dataStream.reset).To(BeFalse()) + Expect(dataStream.closed).To(BeFalse()) + }) + + It("errors when non-header frames are received", func() { + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x06, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, + 'f', 'o', 'o', 'b', 'a', 'r', + }) + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).To(MatchError("InvalidHeadersStreamData: expected a header frame")) + }) + + It("Cancels the request context when the datstream is closed", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + err := r.Context().Err() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("context canceled")) + handlerCalled = true + }) + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x5, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + dataStream.Close() + err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) + Expect(err).NotTo(HaveOccurred()) + Eventually(func() bool { return handlerCalled }).Should(BeTrue()) + Expect(dataStream.remoteClosed).To(BeTrue()) + Expect(dataStream.reset).To(BeFalse()) + }) + }) + + It("handles the header stream", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Expect(r.Host).To(Equal("www.example.com")) + handlerCalled = true + }) + headerStream := &mockStream{id: 3} + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x4, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + session.streamToAccept = headerStream + go s.handleHeaderStream(session) + Eventually(func() bool { return handlerCalled }).Should(BeTrue()) + }) + + It("closes the connection if it encounters an error on the header stream", func() { + var handlerCalled bool + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handlerCalled = true + }) + headerStream := &mockStream{id: 3} + headerStream.dataToRead.Write(bytes.Repeat([]byte{0}, 100)) + session.streamToAccept = headerStream + go s.handleHeaderStream(session) + Consistently(func() bool { return handlerCalled }).Should(BeFalse()) + Eventually(func() bool { return session.closed }).Should(BeTrue()) + Expect(session.closedWithError).To(MatchError(qerr.Error(qerr.HeadersStreamDataDecompressFailure, "cannot read frame"))) + }) + + It("supports closing after first request", func() { + s.CloseAfterFirstRequest = true + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) + headerStream := &mockStream{id: 3} + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x4, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + session.streamToAccept = headerStream + Expect(session.closed).To(BeFalse()) + go s.handleHeaderStream(session) + Eventually(func() bool { return session.closed }).Should(BeTrue()) + }) + + It("uses the default handler as fallback", func() { + var handlerCalled bool + http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Expect(r.Host).To(Equal("www.example.com")) + handlerCalled = true + })) + headerStream := &mockStream{id: 3} + headerStream.dataToRead.Write([]byte{ + 0x0, 0x0, 0x11, 0x1, 0x4, 0x0, 0x0, 0x0, 0x5, + // Taken from https://http2.github.io/http2-spec/compression.html#request.examples.with.huffman.coding + 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, + }) + session.streamToAccept = headerStream + go s.handleHeaderStream(session) + Eventually(func() bool { return handlerCalled }).Should(BeTrue()) + }) + + Context("setting http headers", func() { + var expected http.Header + + getExpectedHeader := func(versions []protocol.VersionNumber) http.Header { + var versionsAsString []string + for _, v := range versions { + versionsAsString = append(versionsAsString, v.ToAltSvc()) + } + return http.Header{ + "Alt-Svc": {fmt.Sprintf(`quic=":443"; ma=2592000; v="%s"`, strings.Join(versionsAsString, ","))}, + } + } + + BeforeEach(func() { + Expect(getExpectedHeader([]protocol.VersionNumber{99, 90, 9})).To(Equal(http.Header{"Alt-Svc": {`quic=":443"; ma=2592000; v="99,90,9"`}})) + expected = getExpectedHeader(protocol.SupportedVersions) + }) + + It("sets proper headers with numeric port", func() { + s.Server.Addr = ":443" + hdr := http.Header{} + err := s.SetQuicHeaders(hdr) + Expect(err).NotTo(HaveOccurred()) + Expect(hdr).To(Equal(expected)) + }) + + It("sets proper headers with full addr", func() { + s.Server.Addr = "127.0.0.1:443" + hdr := http.Header{} + err := s.SetQuicHeaders(hdr) + Expect(err).NotTo(HaveOccurred()) + Expect(hdr).To(Equal(expected)) + }) + + It("sets proper headers with string port", func() { + s.Server.Addr = ":https" + hdr := http.Header{} + err := s.SetQuicHeaders(hdr) + Expect(err).NotTo(HaveOccurred()) + Expect(hdr).To(Equal(expected)) + }) + + It("works multiple times", func() { + s.Server.Addr = ":https" + hdr := http.Header{} + err := s.SetQuicHeaders(hdr) + Expect(err).NotTo(HaveOccurred()) + Expect(hdr).To(Equal(expected)) + hdr = http.Header{} + err = s.SetQuicHeaders(hdr) + Expect(err).NotTo(HaveOccurred()) + Expect(hdr).To(Equal(expected)) + }) + }) + + It("should error when ListenAndServe is called with s.Server nil", func() { + err := (&Server{}).ListenAndServe() + Expect(err).To(MatchError("use of h2quic.Server without http.Server")) + }) + + It("should error when ListenAndServeTLS is called with s.Server nil", func() { + err := (&Server{}).ListenAndServeTLS(testdata.GetCertificatePaths()) + Expect(err).To(MatchError("use of h2quic.Server without http.Server")) + }) + + It("should nop-Close() when s.server is nil", func() { + err := (&Server{}).Close() + Expect(err).NotTo(HaveOccurred()) + }) + + It("errors when ListenAndServer is called after Close", func() { + serv := &Server{Server: &http.Server{}} + Expect(serv.Close()).To(Succeed()) + err := serv.ListenAndServe() + Expect(err).To(MatchError("Server is already closed")) + }) + + Context("ListenAndServe", func() { + BeforeEach(func() { + s.Server.Addr = "localhost:0" + }) + + AfterEach(func() { + Expect(s.Close()).To(Succeed()) + }) + + It("may only be called once", func() { + cErr := make(chan error) + for i := 0; i < 2; i++ { + go func() { + defer GinkgoRecover() + err := s.ListenAndServe() + if err != nil { + cErr <- err + } + }() + } + err := <-cErr + Expect(err).To(MatchError("ListenAndServe may only be called once")) + err = s.Close() + Expect(err).NotTo(HaveOccurred()) + }, 0.5) + + It("uses the quic.Config to start the quic server", func() { + conf := &quic.Config{HandshakeTimeout: time.Nanosecond} + var receivedConf *quic.Config + quicListenAddr = func(addr string, tlsConf *tls.Config, config *quic.Config) (quic.Listener, error) { + receivedConf = config + return nil, errors.New("listen err") + } + s.QuicConfig = conf + go s.ListenAndServe() + Eventually(func() *quic.Config { return receivedConf }).Should(Equal(conf)) + }) + }) + + Context("ListenAndServeTLS", func() { + BeforeEach(func() { + s.Server.Addr = "localhost:0" + }) + + AfterEach(func() { + err := s.Close() + Expect(err).NotTo(HaveOccurred()) + }) + + It("may only be called once", func() { + cErr := make(chan error) + for i := 0; i < 2; i++ { + go func() { + defer GinkgoRecover() + err := s.ListenAndServeTLS(testdata.GetCertificatePaths()) + if err != nil { + cErr <- err + } + }() + } + err := <-cErr + Expect(err).To(MatchError("ListenAndServe may only be called once")) + err = s.Close() + Expect(err).NotTo(HaveOccurred()) + }, 0.5) + }) + + It("closes gracefully", func() { + err := s.CloseGracefully(0) + Expect(err).NotTo(HaveOccurred()) + }) + + It("errors when listening fails", func() { + testErr := errors.New("listen error") + quicListenAddr = func(addr string, tlsConf *tls.Config, config *quic.Config) (quic.Listener, error) { + return nil, testErr + } + fullpem, privkey := testdata.GetCertificatePaths() + err := ListenAndServeQUIC("", fullpem, privkey, nil) + Expect(err).To(MatchError(testErr)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_suite_test.go b/vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_suite_test.go new file mode 100644 index 00000000..d54edfd1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_suite_test.go @@ -0,0 +1,210 @@ +package chrome_test + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "os/exec" + "runtime" + "strconv" + "strings" + "sync/atomic" + + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + + _ "github.com/lucas-clemente/quic-go/integrationtests/tools/testlog" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" + + "testing" +) + +const ( + dataLen = 500 * 1024 // 500 KB + dataLongLen = 50 * 1024 * 1024 // 50 MB +) + +var ( + nFilesUploaded int32 // should be used atomically + doneCalled utils.AtomicBool +) + +func TestChrome(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Chrome Suite") +} + +func init() { + // Requires the len & num GET parameters, e.g. /uploadtest?len=100&num=1 + http.HandleFunc("/uploadtest", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + response := uploadHTML + response = strings.Replace(response, "LENGTH", r.URL.Query().Get("len"), -1) + response = strings.Replace(response, "NUM", r.URL.Query().Get("num"), -1) + _, err := io.WriteString(w, response) + Expect(err).NotTo(HaveOccurred()) + }) + + // Requires the len & num GET parameters, e.g. /downloadtest?len=100&num=1 + http.HandleFunc("/downloadtest", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + response := downloadHTML + response = strings.Replace(response, "LENGTH", r.URL.Query().Get("len"), -1) + response = strings.Replace(response, "NUM", r.URL.Query().Get("num"), -1) + _, err := io.WriteString(w, response) + Expect(err).NotTo(HaveOccurred()) + }) + + http.HandleFunc("/uploadhandler", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + + l, err := strconv.Atoi(r.URL.Query().Get("len")) + Expect(err).NotTo(HaveOccurred()) + + defer r.Body.Close() + actual, err := ioutil.ReadAll(r.Body) + Expect(err).NotTo(HaveOccurred()) + + Expect(bytes.Equal(actual, testserver.GeneratePRData(l))).To(BeTrue()) + + atomic.AddInt32(&nFilesUploaded, 1) + }) + + http.HandleFunc("/done", func(w http.ResponseWriter, r *http.Request) { + doneCalled.Set(true) + }) +} + +var _ = AfterEach(func() { + testserver.StopQuicServer() + + atomic.StoreInt32(&nFilesUploaded, 0) + doneCalled.Set(false) +}) + +func getChromePath() string { + if runtime.GOOS == "darwin" { + return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" + } + if path, err := exec.LookPath("google-chrome"); err == nil { + return path + } + if path, err := exec.LookPath("chromium-browser"); err == nil { + return path + } + Fail("No Chrome executable found.") + return "" +} + +func chromeTest(version protocol.VersionNumber, url string, blockUntilDone func()) { + userDataDir, err := ioutil.TempDir("", "quic-go-test-chrome-dir") + Expect(err).NotTo(HaveOccurred()) + defer os.RemoveAll(userDataDir) + path := getChromePath() + args := []string{ + "--disable-gpu", + "--no-first-run=true", + "--no-default-browser-check=true", + "--user-data-dir=" + userDataDir, + "--enable-quic=true", + "--no-proxy-server=true", + "--no-sandbox", + "--origin-to-force-quic-on=quic.clemente.io:443", + fmt.Sprintf(`--host-resolver-rules=MAP quic.clemente.io:443 127.0.0.1:%s`, testserver.Port()), + fmt.Sprintf("--quic-version=QUIC_VERSION_%s", version.ToAltSvc()), + url, + } + utils.DefaultLogger.Infof("Running chrome: %s '%s'", getChromePath(), strings.Join(args, "' '")) + command := exec.Command(path, args...) + session, err := gexec.Start(command, nil, nil) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + blockUntilDone() +} + +func waitForDone() { + Eventually(func() bool { return doneCalled.Get() }, 60).Should(BeTrue()) +} + +func waitForNUploaded(expected int) func() { + return func() { + Eventually(func() int32 { + return atomic.LoadInt32(&nFilesUploaded) + }, 60).Should(BeEquivalentTo(expected)) + } +} + +const commonJS = ` +var buf = new ArrayBuffer(LENGTH); +var prng = new Uint8Array(buf); +var seed = 1; +for (var i = 0; i < LENGTH; i++) { + // https://en.wikipedia.org/wiki/Lehmer_random_number_generator + seed = seed * 48271 % 2147483647; + prng[i] = seed; +} +` + +const uploadHTML = ` + + + + + +` + +const downloadHTML = ` + + + + + +` diff --git a/vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_test.go b/vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_test.go new file mode 100644 index 00000000..60eb9e95 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/chrome/chrome_test.go @@ -0,0 +1,76 @@ +package chrome_test + +import ( + "fmt" + + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" +) + +var _ = Describe("Chrome tests", func() { + for i := range protocol.SupportedVersions { + version := protocol.SupportedVersions[i] + + // TODO: activate Chrome integration tests with gQUIC 44 + if version == protocol.Version44 { + continue + } + + Context(fmt.Sprintf("with version %s", version), func() { + JustBeforeEach(func() { + testserver.StartQuicServer([]protocol.VersionNumber{version}) + }) + + It("downloads a small file", func() { + chromeTest( + version, + fmt.Sprintf("https://quic.clemente.io/downloadtest?num=1&len=%d", dataLen), + waitForDone, + ) + }) + + It("downloads a large file", func() { + chromeTest( + version, + fmt.Sprintf("https://quic.clemente.io/downloadtest?num=1&len=%d", dataLongLen), + waitForDone, + ) + }) + + It("loads a large number of files", func() { + chromeTest( + version, + "https://quic.clemente.io/downloadtest?num=4&len=100", + waitForDone, + ) + }) + + It("uploads a small file", func() { + chromeTest( + version, + fmt.Sprintf("https://quic.clemente.io/uploadtest?num=1&len=%d", dataLen), + waitForNUploaded(1), + ) + }) + + It("uploads a large file", func() { + chromeTest( + version, + fmt.Sprintf("https://quic.clemente.io/uploadtest?num=1&len=%d", dataLongLen), + waitForNUploaded(1), + ) + }) + + It("uploads many small files", func() { + num := protocol.DefaultMaxIncomingStreams + 20 + chromeTest( + version, + fmt.Sprintf("https://quic.clemente.io/uploadtest?num=%d&len=%d", num, dataLen), + waitForNUploaded(num), + ) + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/gquic/drop_test.go b/vendor/lucas-clemente/quic-go/integrationtests/gquic/drop_test.go new file mode 100644 index 00000000..4bb7e51e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/gquic/drop_test.go @@ -0,0 +1,137 @@ +package gquic_test + +import ( + "bytes" + "fmt" + mrand "math/rand" + "os/exec" + "strconv" + + _ "github.com/lucas-clemente/quic-clients" // download clients + "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var directions = []quicproxy.Direction{quicproxy.DirectionIncoming, quicproxy.DirectionOutgoing, quicproxy.DirectionBoth} + +var _ = Describe("Drop tests", func() { + var proxy *quicproxy.QuicProxy + + startProxy := func(dropCallback quicproxy.DropCallback, version protocol.VersionNumber) { + var err error + proxy, err = quicproxy.NewQuicProxy("localhost:0", version, &quicproxy.Opts{ + RemoteAddr: "localhost:" + testserver.Port(), + DropPacket: dropCallback, + }) + Expect(err).ToNot(HaveOccurred()) + } + + downloadFile := func(version protocol.VersionNumber) { + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+strconv.Itoa(proxy.LocalPort()), + "https://quic.clemente.io/prdata", + ) + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 20).Should(Exit(0)) + Expect(bytes.Contains(session.Out.Contents(), testserver.PRData)).To(BeTrue()) + } + + downloadHello := func(version protocol.VersionNumber) { + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+strconv.Itoa(proxy.LocalPort()), + "https://quic.clemente.io/hello", + ) + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 20).Should(Exit(0)) + Expect(session.Out).To(Say(":status 200")) + Expect(session.Out).To(Say("body: Hello, World!\n")) + } + + deterministicDropper := func(p, interval, dropInARow uint64) bool { + return (p % interval) < dropInARow + } + + stochasticDropper := func(freq int) bool { + return mrand.Int63n(int64(freq)) == 0 + } + + AfterEach(func() { + Expect(proxy.Close()).To(Succeed()) + }) + + for _, v := range protocol.SupportedVersions { + version := v + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + Context("during the crypto handshake", func() { + for _, d := range directions { + direction := d + + It(fmt.Sprintf("establishes a connection when the first packet is lost in %s direction", d), func() { + startProxy(func(d quicproxy.Direction, p uint64) bool { + return p == 1 && d.Is(direction) + }, version) + downloadHello(version) + }) + + It(fmt.Sprintf("establishes a connection when the second packet is lost in %s direction", d), func() { + startProxy(func(d quicproxy.Direction, p uint64) bool { + return p == 2 && d.Is(direction) + }, version) + downloadHello(version) + }) + + It(fmt.Sprintf("establishes a connection when 1/5 of the packets are lost in %s direction", d), func() { + startProxy(func(d quicproxy.Direction, p uint64) bool { + return d.Is(direction) && stochasticDropper(5) + }, version) + downloadHello(version) + }) + } + }) + + Context("after the crypto handshake", func() { + for _, d := range directions { + direction := d + + It(fmt.Sprintf("downloads a file when every 5th packet is dropped in %s direction", d), func() { + startProxy(func(d quicproxy.Direction, p uint64) bool { + return p >= 10 && d.Is(direction) && deterministicDropper(p, 5, 1) + }, version) + downloadFile(version) + }) + + It(fmt.Sprintf("downloads a file when 1/5th of all packet are dropped randomly in %s direction", d), func() { + startProxy(func(d quicproxy.Direction, p uint64) bool { + return p >= 10 && d.Is(direction) && stochasticDropper(5) + }, version) + downloadFile(version) + }) + + It(fmt.Sprintf("downloads a file when 10 packets every 100 packet are dropped in %s direction", d), func() { + startProxy(func(d quicproxy.Direction, p uint64) bool { + return p >= 10 && d.Is(direction) && deterministicDropper(p, 100, 10) + }, version) + downloadFile(version) + }) + } + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/gquic/gquic_suite_test.go b/vendor/lucas-clemente/quic-go/integrationtests/gquic/gquic_suite_test.go new file mode 100644 index 00000000..f8183fdd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/gquic/gquic_suite_test.go @@ -0,0 +1,45 @@ +package gquic_test + +import ( + "fmt" + "math/rand" + "path/filepath" + "runtime" + + _ "github.com/lucas-clemente/quic-go/integrationtests/tools/testlog" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +var ( + clientPath string + serverPath string +) + +func TestIntegration(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "GQuic Tests Suite") +} + +var _ = BeforeSuite(func() { + rand.Seed(GinkgoRandomSeed()) +}) + +var _ = JustBeforeEach(func() { + testserver.StartQuicServer(nil) +}) + +var _ = AfterEach(testserver.StopQuicServer) + +func init() { + _, thisfile, _, ok := runtime.Caller(0) + if !ok { + panic("Failed to get current path") + } + clientPath = filepath.Join(thisfile, fmt.Sprintf("../../../../quic-clients/client-%s-debug", runtime.GOOS)) + serverPath = filepath.Join(thisfile, fmt.Sprintf("../../../../quic-clients/server-%s-debug", runtime.GOOS)) +} diff --git a/vendor/lucas-clemente/quic-go/integrationtests/gquic/integration_test.go b/vendor/lucas-clemente/quic-go/integrationtests/gquic/integration_test.go new file mode 100644 index 00000000..595a5582 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/gquic/integration_test.go @@ -0,0 +1,98 @@ +package gquic_test + +import ( + "bytes" + "fmt" + "os/exec" + "sync" + + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + + _ "github.com/lucas-clemente/quic-clients" // download clients + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Integration tests", func() { + for i := range protocol.SupportedVersions { + version := protocol.SupportedVersions[i] + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + It("gets a simple file", func() { + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+testserver.Port(), + "https://quic.clemente.io/hello", + ) + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 5).Should(Exit(0)) + Expect(session.Out).To(Say(":status 200")) + Expect(session.Out).To(Say("body: Hello, World!\n")) + }) + + It("posts and reads a body", func() { + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+testserver.Port(), + "--body=foo", + "https://quic.clemente.io/echo", + ) + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 5).Should(Exit(0)) + Expect(session.Out).To(Say(":status 200")) + Expect(session.Out).To(Say("body: foo\n")) + }) + + It("gets a file", func() { + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+testserver.Port(), + "https://quic.clemente.io/prdata", + ) + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 10).Should(Exit(0)) + Expect(bytes.Contains(session.Out.Contents(), testserver.PRData)).To(BeTrue()) + }) + + It("gets many copies of a file in parallel", func() { + wg := sync.WaitGroup{} + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + defer GinkgoRecover() + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+testserver.Port(), + "https://quic.clemente.io/prdata", + ) + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 20).Should(Exit(0)) + Expect(bytes.Contains(session.Out.Contents(), testserver.PRData)).To(BeTrue()) + }() + } + wg.Wait() + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/gquic/random_rtt_test.go b/vendor/lucas-clemente/quic-go/integrationtests/gquic/random_rtt_test.go new file mode 100644 index 00000000..f51aa8d1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/gquic/random_rtt_test.go @@ -0,0 +1,95 @@ +package gquic_test + +import ( + "bytes" + "fmt" + "math/rand" + "os/exec" + "strconv" + "time" + + _ "github.com/lucas-clemente/quic-clients" // download clients + "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +// get a random duration between min and max +func getRandomDuration(min, max time.Duration) time.Duration { + return min + time.Duration(rand.Int63n(int64(max-min))) +} + +var _ = Describe("Random Duration Generator", func() { + It("gets a random RTT", func() { + var min time.Duration = time.Hour + var max time.Duration + + var sum time.Duration + rep := 10000 + for i := 0; i < rep; i++ { + val := getRandomDuration(100*time.Millisecond, 500*time.Millisecond) + sum += val + if val < min { + min = val + } + if val > max { + max = val + } + } + avg := sum / time.Duration(rep) + Expect(avg).To(BeNumerically("~", 300*time.Millisecond, 5*time.Millisecond)) + Expect(min).To(BeNumerically(">=", 100*time.Millisecond)) + Expect(min).To(BeNumerically("<", 105*time.Millisecond)) + Expect(max).To(BeNumerically(">", 495*time.Millisecond)) + Expect(max).To(BeNumerically("<=", 500*time.Millisecond)) + }) +}) + +var _ = Describe("Random RTT", func() { + var proxy *quicproxy.QuicProxy + + runRTTTest := func(minRtt, maxRtt time.Duration, version protocol.VersionNumber) { + var err error + proxy, err = quicproxy.NewQuicProxy("localhost:", version, &quicproxy.Opts{ + RemoteAddr: "localhost:" + testserver.Port(), + DelayPacket: func(_ quicproxy.Direction, _ uint64) time.Duration { + return getRandomDuration(minRtt, maxRtt) + }, + }) + Expect(err).ToNot(HaveOccurred()) + + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+strconv.Itoa(proxy.LocalPort()), + "https://quic.clemente.io/prdata", + ) + + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 20).Should(Exit(0)) + Expect(bytes.Contains(session.Out.Contents(), testserver.PRData)).To(BeTrue()) + } + + AfterEach(func() { + err := proxy.Close() + Expect(err).ToNot(HaveOccurred()) + time.Sleep(time.Millisecond) + }) + + for i := range protocol.SupportedVersions { + version := protocol.SupportedVersions[i] + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + It("gets a file a random RTT between 10ms and 30ms", func() { + runRTTTest(10*time.Millisecond, 30*time.Millisecond, version) + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/gquic/rtt_test.go b/vendor/lucas-clemente/quic-go/integrationtests/gquic/rtt_test.go new file mode 100644 index 00000000..669200ee --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/gquic/rtt_test.go @@ -0,0 +1,66 @@ +package gquic_test + +import ( + "bytes" + "fmt" + "os/exec" + "strconv" + "time" + + _ "github.com/lucas-clemente/quic-clients" // download clients + "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("non-zero RTT", func() { + var proxy *quicproxy.QuicProxy + + runRTTTest := func(rtt time.Duration, version protocol.VersionNumber) { + var err error + proxy, err = quicproxy.NewQuicProxy("localhost:", version, &quicproxy.Opts{ + RemoteAddr: "localhost:" + testserver.Port(), + DelayPacket: func(_ quicproxy.Direction, _ uint64) time.Duration { + return rtt / 2 + }, + }) + Expect(err).ToNot(HaveOccurred()) + + command := exec.Command( + clientPath, + "--quic-version="+version.ToAltSvc(), + "--host=127.0.0.1", + "--port="+strconv.Itoa(proxy.LocalPort()), + "https://quic.clemente.io/prdata", + ) + + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 20).Should(Exit(0)) + Expect(bytes.Contains(session.Out.Contents(), testserver.PRData)).To(BeTrue()) + } + + AfterEach(func() { + err := proxy.Close() + Expect(err).ToNot(HaveOccurred()) + time.Sleep(time.Millisecond) + }) + + for i := range protocol.SupportedVersions { + version := protocol.SupportedVersions[i] + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + roundTrips := [...]int{10, 50, 100, 200} + for _, rtt := range roundTrips { + It(fmt.Sprintf("gets a 500kB file with %dms RTT", rtt), func() { + runRTTTest(time.Duration(rtt)*time.Millisecond, version) + }) + } + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/gquic/server_test.go b/vendor/lucas-clemente/quic-go/integrationtests/gquic/server_test.go new file mode 100644 index 00000000..993ebd03 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/gquic/server_test.go @@ -0,0 +1,218 @@ +package gquic_test + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/pem" + "fmt" + "io/ioutil" + "math/big" + mrand "math/rand" + "net/http" + "os" + "os/exec" + "path/filepath" + "strconv" + "time" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/h2quic" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Server tests", func() { + for i := range protocol.SupportedVersions { + version := protocol.SupportedVersions[i] + + var ( + serverPort string + tmpDir string + session *Session + client *http.Client + ) + + generateCA := func() (*rsa.PrivateKey, *x509.Certificate) { + key, err := rsa.GenerateKey(rand.Reader, 1024) + Expect(err).ToNot(HaveOccurred()) + + templateRoot := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + IsCA: true, + BasicConstraintsValid: true, + } + certDER, err := x509.CreateCertificate(rand.Reader, templateRoot, templateRoot, &key.PublicKey, key) + Expect(err).ToNot(HaveOccurred()) + cert, err := x509.ParseCertificate(certDER) + Expect(err).ToNot(HaveOccurred()) + return key, cert + } + + // prepare the file such that it can be by the quic_server + // some HTTP headers neeed to be prepended, see https://www.chromium.org/quic/playing-with-quic + createDownloadFile := func(filename string, data []byte) { + dataDir := filepath.Join(tmpDir, "quic.clemente.io") + err := os.Mkdir(dataDir, 0777) + Expect(err).ToNot(HaveOccurred()) + f, err := os.Create(filepath.Join(dataDir, filename)) + Expect(err).ToNot(HaveOccurred()) + defer f.Close() + _, err = f.Write([]byte("HTTP/1.1 200 OK\n")) + Expect(err).ToNot(HaveOccurred()) + _, err = f.Write([]byte("Content-Type: text/html\n")) + Expect(err).ToNot(HaveOccurred()) + _, err = f.Write([]byte("X-Original-Url: https://quic.clemente.io:" + serverPort + "/" + filename + "\n")) + Expect(err).ToNot(HaveOccurred()) + _, err = f.Write([]byte("Content-Length: " + strconv.Itoa(len(data)) + "\n\n")) + Expect(err).ToNot(HaveOccurred()) + _, err = f.Write(data) + Expect(err).ToNot(HaveOccurred()) + } + + // download files must be create *before* the quic_server is started + // the quic_server reads its data dir on startup, and only serves those files that were already present then + startServer := func(version protocol.VersionNumber) { + defer GinkgoRecover() + var err error + command := exec.Command( + serverPath, + "--quic_response_cache_dir="+filepath.Join(tmpDir, "quic.clemente.io"), + "--key_file="+filepath.Join(tmpDir, "key.pkcs8"), + "--certificate_file="+filepath.Join(tmpDir, "cert.pem"), + "--quic-version="+strconv.Itoa(int(version)), + "--port="+serverPort, + ) + session, err = Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + } + + stopServer := func() { + session.Kill() + } + + BeforeEach(func() { + serverPort = strconv.Itoa(20000 + int(mrand.Int31n(10000))) + + var err error + tmpDir, err = ioutil.TempDir("", "quic-server-certs") + Expect(err).ToNot(HaveOccurred()) + + // generate an RSA key pair for the server + key, err := rsa.GenerateKey(rand.Reader, 1024) + Expect(err).ToNot(HaveOccurred()) + + // save the private key in PKCS8 format to disk (required by quic_server) + pkcs8key, err := asn1.Marshal(struct { // copied from the x509 package + Version int + Algo pkix.AlgorithmIdentifier + PrivateKey []byte + }{ + PrivateKey: x509.MarshalPKCS1PrivateKey(key), + Algo: pkix.AlgorithmIdentifier{ + Algorithm: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}, + Parameters: asn1.RawValue{Tag: 5}, + }, + }) + Expect(err).ToNot(HaveOccurred()) + f, err := os.Create(filepath.Join(tmpDir, "key.pkcs8")) + Expect(err).ToNot(HaveOccurred()) + _, err = f.Write(pkcs8key) + Expect(err).ToNot(HaveOccurred()) + f.Close() + + // generate a Certificate Authority + // this CA is used to sign the server's key + // it is set as a valid CA in the QUIC client + rootKey, CACert := generateCA() + // generate the server certificate + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-30 * time.Minute), + NotAfter: time.Now().Add(30 * time.Minute), + Subject: pkix.Name{CommonName: "quic.clemente.io"}, + } + certDER, err := x509.CreateCertificate(rand.Reader, template, CACert, &key.PublicKey, rootKey) + Expect(err).ToNot(HaveOccurred()) + // save the certificate to disk + certOut, err := os.Create(filepath.Join(tmpDir, "cert.pem")) + Expect(err).ToNot(HaveOccurred()) + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certDER}) + certOut.Close() + + // prepare the h2quic.client + certPool := x509.NewCertPool() + certPool.AddCert(CACert) + client = &http.Client{ + Transport: &h2quic.RoundTripper{ + TLSClientConfig: &tls.Config{RootCAs: certPool}, + QuicConfig: &quic.Config{ + Versions: []protocol.VersionNumber{version}, + }, + }, + } + }) + + AfterEach(func() { + Expect(tmpDir).ToNot(BeEmpty()) + err := os.RemoveAll(tmpDir) + Expect(err).ToNot(HaveOccurred()) + tmpDir = "" + }) + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + It("downloads a hello", func() { + data := []byte("Hello world!\n") + createDownloadFile("hello", data) + + startServer(version) + defer stopServer() + + rsp, err := client.Get("https://quic.clemente.io:" + serverPort + "/hello") + Expect(err).ToNot(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(200)) + body, err := ioutil.ReadAll(gbytes.TimeoutReader(rsp.Body, 5*time.Second)) + Expect(err).ToNot(HaveOccurred()) + Expect(body).To(Equal(data)) + }) + + It("downloads a small file", func() { + createDownloadFile("file.dat", testserver.PRData) + + startServer(version) + defer stopServer() + + rsp, err := client.Get("https://quic.clemente.io:" + serverPort + "/file.dat") + Expect(err).ToNot(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(200)) + body, err := ioutil.ReadAll(gbytes.TimeoutReader(rsp.Body, 5*time.Second)) + Expect(err).ToNot(HaveOccurred()) + Expect(body).To(Equal(testserver.PRData)) + }) + + It("downloads a large file", func() { + createDownloadFile("file.dat", testserver.PRDataLong) + + startServer(version) + defer stopServer() + + rsp, err := client.Get("https://quic.clemente.io:" + serverPort + "/file.dat") + Expect(err).ToNot(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(200)) + body, err := ioutil.ReadAll(gbytes.TimeoutReader(rsp.Body, 20*time.Second)) + Expect(err).ToNot(HaveOccurred()) + Expect(body).To(Equal(testserver.PRDataLong)) + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/client_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/client_test.go new file mode 100644 index 00000000..fcb9cb5a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/client_test.go @@ -0,0 +1,97 @@ +package self_test + +import ( + "bytes" + "fmt" + "io/ioutil" + "net" + "net/http" + "os" + "time" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/h2quic" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" +) + +var _ = Describe("Client tests", func() { + var client *http.Client + + // also run some tests with the TLS handshake + versions := append(protocol.SupportedVersions, protocol.VersionTLS) + + BeforeEach(func() { + err := os.Setenv("HOSTALIASES", "quic.clemente.io 127.0.0.1") + Expect(err).ToNot(HaveOccurred()) + addr, err := net.ResolveUDPAddr("udp4", "quic.clemente.io:0") + Expect(err).ToNot(HaveOccurred()) + if addr.String() != "127.0.0.1:0" { + Fail("quic.clemente.io does not resolve to 127.0.0.1. Consider adding it to /etc/hosts.") + } + testserver.StartQuicServer(versions) + }) + + AfterEach(func() { + testserver.StopQuicServer() + }) + + for _, v := range versions { + version := v + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + BeforeEach(func() { + client = &http.Client{ + Transport: &h2quic.RoundTripper{ + QuicConfig: &quic.Config{ + Versions: []protocol.VersionNumber{version}, + }, + }, + } + }) + + It("downloads a hello", func() { + resp, err := client.Get("https://quic.clemente.io:" + testserver.Port() + "/hello") + Expect(err).ToNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(200)) + body, err := ioutil.ReadAll(gbytes.TimeoutReader(resp.Body, 3*time.Second)) + Expect(err).ToNot(HaveOccurred()) + Expect(string(body)).To(Equal("Hello, World!\n")) + }) + + It("downloads a small file", func() { + resp, err := client.Get("https://quic.clemente.io:" + testserver.Port() + "/prdata") + Expect(err).ToNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(200)) + body, err := ioutil.ReadAll(gbytes.TimeoutReader(resp.Body, 5*time.Second)) + Expect(err).ToNot(HaveOccurred()) + Expect(body).To(Equal(testserver.PRData)) + }) + + It("downloads a large file", func() { + resp, err := client.Get("https://quic.clemente.io:" + testserver.Port() + "/prdatalong") + Expect(err).ToNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(200)) + body, err := ioutil.ReadAll(gbytes.TimeoutReader(resp.Body, 20*time.Second)) + Expect(err).ToNot(HaveOccurred()) + Expect(body).To(Equal(testserver.PRDataLong)) + }) + + It("uploads a file", func() { + resp, err := client.Post( + "https://quic.clemente.io:"+testserver.Port()+"/echo", + "text/plain", + bytes.NewReader(testserver.PRData), + ) + Expect(err).ToNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(200)) + body, err := ioutil.ReadAll(gbytes.TimeoutReader(resp.Body, 5*time.Second)) + Expect(err).ToNot(HaveOccurred()) + Expect(bytes.Equal(body, testserver.PRData)).To(BeTrue()) + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/conn_id_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/conn_id_test.go new file mode 100644 index 00000000..991154f2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/conn_id_test.go @@ -0,0 +1,101 @@ +package self_test + +import ( + "crypto/tls" + "fmt" + "io/ioutil" + "math/rand" + "net" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Connection ID lengths tests", func() { + randomConnIDLen := func() int { + return 4 + int(rand.Int31n(15)) + } + + runServer := func(conf *quic.Config) quic.Listener { + GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID for the server\n", conf.ConnectionIDLength))) + ln, err := quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), conf) + Expect(err).ToNot(HaveOccurred()) + go func() { + defer GinkgoRecover() + for { + sess, err := ln.Accept() + if err != nil { + return + } + go func() { + defer GinkgoRecover() + str, err := sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + defer str.Close() + _, err = str.Write(testserver.PRData) + Expect(err).ToNot(HaveOccurred()) + }() + } + }() + return ln + } + + runClient := func(addr net.Addr, conf *quic.Config) { + GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID for the client\n", conf.ConnectionIDLength))) + cl, err := quic.DialAddr( + fmt.Sprintf("quic.clemente.io:%d", addr.(*net.UDPAddr).Port), + &tls.Config{InsecureSkipVerify: true}, + conf, + ) + Expect(err).ToNot(HaveOccurred()) + defer cl.Close() + str, err := cl.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + data, err := ioutil.ReadAll(str) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(testserver.PRData)) + } + + Context("IETF QUIC", func() { + It("downloads a file using a 0-byte connection ID for the client", func() { + serverConf := &quic.Config{ + ConnectionIDLength: randomConnIDLen(), + Versions: []protocol.VersionNumber{protocol.VersionTLS}, + } + clientConf := &quic.Config{ + Versions: []protocol.VersionNumber{protocol.VersionTLS}, + } + + ln := runServer(serverConf) + defer ln.Close() + runClient(ln.Addr(), clientConf) + }) + + It("downloads a file when both client and server use a random connection ID length", func() { + serverConf := &quic.Config{ + ConnectionIDLength: randomConnIDLen(), + Versions: []protocol.VersionNumber{protocol.VersionTLS}, + } + clientConf := &quic.Config{ + ConnectionIDLength: randomConnIDLen(), + Versions: []protocol.VersionNumber{protocol.VersionTLS}, + } + + ln := runServer(serverConf) + defer ln.Close() + runClient(ln.Addr(), clientConf) + }) + }) + + Context("gQUIC", func() { + It("downloads a file using a 0-byte connection ID for the client", func() { + ln := runServer(&quic.Config{}) + defer ln.Close() + runClient(ln.Addr(), &quic.Config{RequestConnectionIDOmission: true}) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_drop_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_drop_test.go new file mode 100644 index 00000000..dd83c9dd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_drop_test.go @@ -0,0 +1,189 @@ +package self_test + +import ( + "fmt" + mrand "math/rand" + "net" + "time" + + _ "github.com/lucas-clemente/quic-clients" // download clients + "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" +) + +var directions = []quicproxy.Direction{quicproxy.DirectionIncoming, quicproxy.DirectionOutgoing, quicproxy.DirectionBoth} + +type applicationProtocol struct { + name string + run func(protocol.VersionNumber) +} + +var _ = Describe("Handshake drop tests", func() { + var ( + proxy *quicproxy.QuicProxy + ln quic.Listener + ) + + startListenerAndProxy := func(dropCallback quicproxy.DropCallback, version protocol.VersionNumber) { + var err error + ln, err = quic.ListenAddr( + "localhost:0", + testdata.GetTLSConfig(), + &quic.Config{ + Versions: []protocol.VersionNumber{version}, + }, + ) + Expect(err).ToNot(HaveOccurred()) + serverPort := ln.Addr().(*net.UDPAddr).Port + proxy, err = quicproxy.NewQuicProxy("localhost:0", version, &quicproxy.Opts{ + RemoteAddr: fmt.Sprintf("localhost:%d", serverPort), + DropPacket: dropCallback, + }, + ) + Expect(err).ToNot(HaveOccurred()) + } + + stochasticDropper := func(freq int) bool { + return mrand.Int63n(int64(freq)) == 0 + } + + clientSpeaksFirst := &applicationProtocol{ + name: "client speaks first", + run: func(version protocol.VersionNumber) { + serverSessionChan := make(chan quic.Session) + go func() { + defer GinkgoRecover() + sess, err := ln.Accept() + Expect(err).ToNot(HaveOccurred()) + defer sess.Close() + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 6) + _, err = gbytes.TimeoutReader(str, 10*time.Second).Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(string(b)).To(Equal("foobar")) + serverSessionChan <- sess + }() + sess, err := quic.DialAddr( + fmt.Sprintf("quic.clemente.io:%d", proxy.LocalPort()), + nil, + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + str, err := sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + _, err = str.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + + var serverSession quic.Session + Eventually(serverSessionChan, 10*time.Second).Should(Receive(&serverSession)) + sess.Close() + serverSession.Close() + }, + } + + serverSpeaksFirst := &applicationProtocol{ + name: "server speaks first", + run: func(version protocol.VersionNumber) { + serverSessionChan := make(chan quic.Session) + go func() { + defer GinkgoRecover() + sess, err := ln.Accept() + Expect(err).ToNot(HaveOccurred()) + str, err := sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + _, err = str.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + serverSessionChan <- sess + }() + sess, err := quic.DialAddr( + fmt.Sprintf("quic.clemente.io:%d", proxy.LocalPort()), + nil, + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 6) + _, err = gbytes.TimeoutReader(str, 10*time.Second).Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(string(b)).To(Equal("foobar")) + + var serverSession quic.Session + Eventually(serverSessionChan, 10*time.Second).Should(Receive(&serverSession)) + sess.Close() + serverSession.Close() + }, + } + + nobodySpeaks := &applicationProtocol{ + name: "nobody speaks", + run: func(version protocol.VersionNumber) { + serverSessionChan := make(chan quic.Session) + go func() { + defer GinkgoRecover() + sess, err := ln.Accept() + Expect(err).ToNot(HaveOccurred()) + serverSessionChan <- sess + }() + sess, err := quic.DialAddr( + fmt.Sprintf("quic.clemente.io:%d", proxy.LocalPort()), + nil, + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + var serverSession quic.Session + Eventually(serverSessionChan, 10*time.Second).Should(Receive(&serverSession)) + // both server and client accepted a session. Close now. + sess.Close() + serverSession.Close() + }, + } + + AfterEach(func() { + Expect(proxy.Close()).To(Succeed()) + }) + + for _, v := range append(protocol.SupportedVersions, protocol.VersionTLS) { + version := v + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + for _, d := range directions { + direction := d + + for _, a := range []*applicationProtocol{clientSpeaksFirst, serverSpeaksFirst, nobodySpeaks} { + app := a + + Context(app.name, func() { + It(fmt.Sprintf("establishes a connection when the first packet is lost in %s direction", d), func() { + startListenerAndProxy(func(d quicproxy.Direction, p uint64) bool { + return p == 1 && d.Is(direction) + }, version) + app.run(version) + }) + + It(fmt.Sprintf("establishes a connection when the second packet is lost in %s direction", d), func() { + startListenerAndProxy(func(d quicproxy.Direction, p uint64) bool { + return p == 2 && d.Is(direction) + }, version) + app.run(version) + }) + + It(fmt.Sprintf("establishes a connection when 1/5 of the packets are lost in %s direction", d), func() { + startListenerAndProxy(func(d quicproxy.Direction, p uint64) bool { + return d.Is(direction) && stochasticDropper(5) + }, version) + app.run(version) + }) + }) + } + } + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_rtt_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_rtt_test.go new file mode 100644 index 00000000..67cc74ae --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_rtt_test.go @@ -0,0 +1,213 @@ +package self_test + +import ( + "crypto/tls" + "net" + "time" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/qerr" + + "github.com/lucas-clemente/quic-go/internal/testdata" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Handshake RTT tests", func() { + var ( + proxy *quicproxy.QuicProxy + server quic.Listener + serverConfig *quic.Config + testStartedAt time.Time + acceptStopped chan struct{} + ) + + rtt := 400 * time.Millisecond + + BeforeEach(func() { + acceptStopped = make(chan struct{}) + serverConfig = &quic.Config{} + }) + + AfterEach(func() { + Expect(proxy.Close()).To(Succeed()) + Expect(server.Close()).To(Succeed()) + <-acceptStopped + }) + + runServerAndProxy := func() { + var err error + // start the server + server, err = quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), serverConfig) + Expect(err).ToNot(HaveOccurred()) + // start the proxy + proxy, err = quicproxy.NewQuicProxy("localhost:0", protocol.VersionWhatever, &quicproxy.Opts{ + RemoteAddr: server.Addr().String(), + DelayPacket: func(_ quicproxy.Direction, _ uint64) time.Duration { return rtt / 2 }, + }) + Expect(err).ToNot(HaveOccurred()) + + testStartedAt = time.Now() + + go func() { + defer GinkgoRecover() + defer close(acceptStopped) + for { + _, err := server.Accept() + if err != nil { + return + } + } + }() + } + + expectDurationInRTTs := func(num int) { + testDuration := time.Since(testStartedAt) + rtts := float32(testDuration) / float32(rtt) + Expect(rtts).To(SatisfyAll( + BeNumerically(">=", num), + BeNumerically("<", num+1), + )) + } + + It("fails when there's no matching version, after 1 RTT", func() { + if len(protocol.SupportedVersions) == 1 { + Skip("Test requires at least 2 supported versions.") + } + serverConfig.Versions = protocol.SupportedVersions[:1] + runServerAndProxy() + clientConfig := &quic.Config{ + Versions: protocol.SupportedVersions[1:2], + } + _, err := quic.DialAddr(proxy.LocalAddr().String(), nil, clientConfig) + Expect(err).To(HaveOccurred()) + Expect(err.(qerr.ErrorCode)).To(Equal(qerr.InvalidVersion)) + expectDurationInRTTs(1) + }) + + Context("gQUIC", func() { + // 1 RTT for verifying the source address + // 1 RTT to become secure + // 1 RTT to become forward-secure + It("is forward-secure after 3 RTTs", func() { + runServerAndProxy() + _, err := quic.DialAddr(proxy.LocalAddr().String(), &tls.Config{InsecureSkipVerify: true}, nil) + Expect(err).ToNot(HaveOccurred()) + expectDurationInRTTs(3) + }) + + It("does version negotiation in 1 RTT, IETF QUIC => gQUIC", func() { + clientConfig := &quic.Config{ + Versions: []protocol.VersionNumber{protocol.VersionTLS, protocol.SupportedVersions[0]}, + } + runServerAndProxy() + _, err := quic.DialAddr( + proxy.LocalAddr().String(), + &tls.Config{InsecureSkipVerify: true}, + clientConfig, + ) + Expect(err).ToNot(HaveOccurred()) + expectDurationInRTTs(4) + }) + + It("is forward-secure after 2 RTTs when the server doesn't require a Cookie", func() { + serverConfig.AcceptCookie = func(_ net.Addr, _ *quic.Cookie) bool { + return true + } + runServerAndProxy() + _, err := quic.DialAddr(proxy.LocalAddr().String(), &tls.Config{InsecureSkipVerify: true}, nil) + Expect(err).ToNot(HaveOccurred()) + expectDurationInRTTs(2) + }) + + It("doesn't complete the handshake when the server never accepts the Cookie", func() { + serverConfig.AcceptCookie = func(_ net.Addr, _ *quic.Cookie) bool { + return false + } + runServerAndProxy() + _, err := quic.DialAddr(proxy.LocalAddr().String(), &tls.Config{InsecureSkipVerify: true}, nil) + Expect(err).To(HaveOccurred()) + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.CryptoTooManyRejects)) + }) + + It("doesn't complete the handshake when the handshake timeout is too short", func() { + serverConfig.HandshakeTimeout = 2 * rtt + runServerAndProxy() + _, err := quic.DialAddr(proxy.LocalAddr().String(), &tls.Config{InsecureSkipVerify: true}, nil) + Expect(err).To(HaveOccurred()) + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.HandshakeTimeout)) + // 2 RTTs during the timeout + // plus 1 RTT: the timer starts 0.5 RTTs after sending the first packet, and the CONNECTION_CLOSE needs another 0.5 RTTs to reach the client + expectDurationInRTTs(3) + }) + }) + + Context("IETF QUIC", func() { + var clientConfig *quic.Config + var clientTLSConfig *tls.Config + + BeforeEach(func() { + serverConfig.Versions = []protocol.VersionNumber{protocol.VersionTLS} + clientConfig = &quic.Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}} + clientTLSConfig = &tls.Config{ + InsecureSkipVerify: true, + ServerName: "quic.clemente.io", + } + }) + + // 1 RTT for verifying the source address + // 1 RTT for the TLS handshake + It("is forward-secure after 2 RTTs", func() { + runServerAndProxy() + _, err := quic.DialAddr( + proxy.LocalAddr().String(), + clientTLSConfig, + clientConfig, + ) + Expect(err).ToNot(HaveOccurred()) + expectDurationInRTTs(2) + }) + + It("does version negotiation in 1 RTT, gQUIC => IETF QUIC", func() { + clientConfig.Versions = []protocol.VersionNumber{protocol.SupportedVersions[0], protocol.VersionTLS} + runServerAndProxy() + _, err := quic.DialAddr( + proxy.LocalAddr().String(), + clientTLSConfig, + clientConfig, + ) + Expect(err).ToNot(HaveOccurred()) + expectDurationInRTTs(3) + }) + + It("is forward-secure after 1 RTTs when the server doesn't require a Cookie", func() { + serverConfig.AcceptCookie = func(_ net.Addr, _ *quic.Cookie) bool { + return true + } + runServerAndProxy() + _, err := quic.DialAddr( + proxy.LocalAddr().String(), + clientTLSConfig, + clientConfig, + ) + Expect(err).ToNot(HaveOccurred()) + expectDurationInRTTs(1) + }) + + It("doesn't complete the handshake when the server never accepts the Cookie", func() { + serverConfig.AcceptCookie = func(_ net.Addr, _ *quic.Cookie) bool { + return false + } + runServerAndProxy() + _, err := quic.DialAddr( + proxy.LocalAddr().String(), + clientTLSConfig, + clientConfig, + ) + Expect(err).To(HaveOccurred()) + Expect(err.(qerr.ErrorCode)).To(Equal(qerr.CryptoTooManyRejects)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_test.go new file mode 100644 index 00000000..b3a77194 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/handshake_test.go @@ -0,0 +1,128 @@ +package self_test + +import ( + "crypto/tls" + "fmt" + "net" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type versioner interface { + GetVersion() protocol.VersionNumber +} + +var _ = Describe("Handshake tests", func() { + var ( + server quic.Listener + serverConfig *quic.Config + acceptStopped chan struct{} + ) + + BeforeEach(func() { + server = nil + acceptStopped = make(chan struct{}) + serverConfig = &quic.Config{} + }) + + AfterEach(func() { + if server != nil { + server.Close() + <-acceptStopped + } + }) + + runServer := func() { + var err error + // start the server + server, err = quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), serverConfig) + Expect(err).ToNot(HaveOccurred()) + + go func() { + defer GinkgoRecover() + defer close(acceptStopped) + for { + _, err := server.Accept() + if err != nil { + return + } + } + }() + } + + Context("Version Negotiation", func() { + var supportedVersions []protocol.VersionNumber + + BeforeEach(func() { + supportedVersions = protocol.SupportedVersions + protocol.SupportedVersions = append(protocol.SupportedVersions, []protocol.VersionNumber{7, 8, 9, 10}...) + }) + + AfterEach(func() { + protocol.SupportedVersions = supportedVersions + }) + + It("when the server supports more versions than the client", func() { + // the server doesn't support the highest supported version, which is the first one the client will try + // but it supports a bunch of versions that the client doesn't speak + serverConfig.Versions = []protocol.VersionNumber{protocol.SupportedVersions[1], 7, 8, 9} + runServer() + sess, err := quic.DialAddr(server.Addr().String(), &tls.Config{InsecureSkipVerify: true}, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.(versioner).GetVersion()).To(Equal(protocol.SupportedVersions[1])) + }) + + It("when the client supports more versions than the server supports", func() { + // the server doesn't support the highest supported version, which is the first one the client will try + // but it supports a bunch of versions that the client doesn't speak + serverConfig.Versions = supportedVersions + runServer() + conf := &quic.Config{ + Versions: []protocol.VersionNumber{7, 8, 9, protocol.SupportedVersions[1], 10}, + } + sess, err := quic.DialAddr(server.Addr().String(), &tls.Config{InsecureSkipVerify: true}, conf) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.(versioner).GetVersion()).To(Equal(protocol.SupportedVersions[1])) + }) + }) + + Context("Certifiate validation", func() { + for _, v := range []protocol.VersionNumber{protocol.Version39, protocol.VersionTLS} { + version := v + + Context(fmt.Sprintf("using %s", version), func() { + var clientConfig *quic.Config + + BeforeEach(func() { + serverConfig.Versions = []protocol.VersionNumber{version} + clientConfig = &quic.Config{ + Versions: []protocol.VersionNumber{version}, + } + }) + + It("accepts the certificate", func() { + runServer() + _, err := quic.DialAddr(fmt.Sprintf("quic.clemente.io:%d", server.Addr().(*net.UDPAddr).Port), nil, clientConfig) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors if the server name doesn't match", func() { + runServer() + _, err := quic.DialAddr(fmt.Sprintf("127.0.0.1:%d", server.Addr().(*net.UDPAddr).Port), nil, clientConfig) + Expect(err).To(HaveOccurred()) + }) + + It("uses the ServerName in the tls.Config", func() { + runServer() + conf := &tls.Config{ServerName: "quic.clemente.io"} + _, err := quic.DialAddr(fmt.Sprintf("127.0.0.1:%d", server.Addr().(*net.UDPAddr).Port), conf, clientConfig) + Expect(err).ToNot(HaveOccurred()) + }) + }) + } + }) +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/multiplex_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/multiplex_test.go new file mode 100644 index 00000000..0960f49b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/multiplex_test.go @@ -0,0 +1,232 @@ +package self_test + +import ( + "fmt" + "io/ioutil" + "net" + "os" + "time" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testlog" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Multiplexing", func() { + for _, v := range append(protocol.SupportedVersions, protocol.VersionTLS) { + version := v + + // gQUIC 44 uses 0 byte connection IDs for packets sent to the client + // It's not possible to do demultiplexing. + if v == protocol.Version44 { + continue + } + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + runServer := func(ln quic.Listener) { + go func() { + defer GinkgoRecover() + for { + sess, err := ln.Accept() + if err != nil { + return + } + go func() { + defer GinkgoRecover() + str, err := sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + defer str.Close() + _, err = str.Write(testserver.PRDataLong) + Expect(err).ToNot(HaveOccurred()) + }() + } + }() + } + + dial := func(conn net.PacketConn, addr net.Addr) { + sess, err := quic.Dial( + conn, + addr, + fmt.Sprintf("quic.clemente.io:%d", addr.(*net.UDPAddr).Port), + nil, + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + data, err := ioutil.ReadAll(str) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(testserver.PRDataLong)) + } + + Context("multiplexing clients on the same conn", func() { + getListener := func() quic.Listener { + ln, err := quic.ListenAddr( + "localhost:0", + testdata.GetTLSConfig(), + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + return ln + } + + It("multiplexes connections to the same server", func() { + server := getListener() + runServer(server) + defer server.Close() + + addr, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + conn, err := net.ListenUDP("udp", addr) + Expect(err).ToNot(HaveOccurred()) + defer conn.Close() + + done1 := make(chan struct{}) + done2 := make(chan struct{}) + go func() { + defer GinkgoRecover() + dial(conn, server.Addr()) + close(done1) + }() + go func() { + defer GinkgoRecover() + dial(conn, server.Addr()) + close(done2) + }() + timeout := 30 * time.Second + if testlog.Debug() { + timeout = time.Minute + } + Eventually(done1, timeout).Should(BeClosed()) + Eventually(done2, timeout).Should(BeClosed()) + }) + + It("multiplexes connections to different servers", func() { + server1 := getListener() + runServer(server1) + defer server1.Close() + server2 := getListener() + runServer(server2) + defer server2.Close() + + addr, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + conn, err := net.ListenUDP("udp", addr) + Expect(err).ToNot(HaveOccurred()) + defer conn.Close() + + done1 := make(chan struct{}) + done2 := make(chan struct{}) + go func() { + defer GinkgoRecover() + dial(conn, server1.Addr()) + close(done1) + }() + go func() { + defer GinkgoRecover() + dial(conn, server2.Addr()) + close(done2) + }() + timeout := 30 * time.Second + if testlog.Debug() { + timeout = time.Minute + } + Eventually(done1, timeout).Should(BeClosed()) + Eventually(done2, timeout).Should(BeClosed()) + }) + }) + + Context("multiplexing server and client on the same conn", func() { + It("connects to itself", func() { + if version != protocol.VersionTLS { + Skip("Connecting to itself only works with IETF QUIC.") + } + + addr, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + conn, err := net.ListenUDP("udp", addr) + Expect(err).ToNot(HaveOccurred()) + defer conn.Close() + + server, err := quic.Listen( + conn, + testdata.GetTLSConfig(), + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + runServer(server) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + dial(conn, server.Addr()) + close(done) + }() + timeout := 30 * time.Second + if testlog.Debug() { + timeout = time.Minute + } + Eventually(done, timeout).Should(BeClosed()) + }) + + It("runs a server and client on the same conn", func() { + if os.Getenv("CI") == "true" { + Skip("This test is flaky on CIs, see see https://github.com/golang/go/issues/17677.") + } + addr1, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + conn1, err := net.ListenUDP("udp", addr1) + Expect(err).ToNot(HaveOccurred()) + defer conn1.Close() + + addr2, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + conn2, err := net.ListenUDP("udp", addr2) + Expect(err).ToNot(HaveOccurred()) + defer conn2.Close() + + server1, err := quic.Listen( + conn1, + testdata.GetTLSConfig(), + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + runServer(server1) + defer server1.Close() + + server2, err := quic.Listen( + conn2, + testdata.GetTLSConfig(), + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + runServer(server2) + defer server2.Close() + + done1 := make(chan struct{}) + done2 := make(chan struct{}) + go func() { + defer GinkgoRecover() + dial(conn2, server1.Addr()) + close(done1) + }() + go func() { + defer GinkgoRecover() + dial(conn1, server2.Addr()) + close(done2) + }() + timeout := 30 * time.Second + if testlog.Debug() { + timeout = time.Minute + } + Eventually(done1, timeout).Should(BeClosed()) + Eventually(done2, timeout).Should(BeClosed()) + }) + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/rtt_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/rtt_test.go new file mode 100644 index 00000000..40cca5b9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/rtt_test.go @@ -0,0 +1,83 @@ +package self + +import ( + "fmt" + "io/ioutil" + "net" + "time" + + _ "github.com/lucas-clemente/quic-clients" // download clients + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("non-zero RTT", func() { + for _, v := range append(protocol.SupportedVersions, protocol.VersionTLS) { + version := v + + Context(fmt.Sprintf("with QUIC version %s", version), func() { + roundTrips := [...]time.Duration{ + 10 * time.Millisecond, + 50 * time.Millisecond, + 100 * time.Millisecond, + 200 * time.Millisecond, + } + + for _, r := range roundTrips { + rtt := r + + It(fmt.Sprintf("downloads a message with %s RTT", rtt), func() { + ln, err := quic.ListenAddr( + "localhost:0", + testdata.GetTLSConfig(), + &quic.Config{ + Versions: []protocol.VersionNumber{version}, + }, + ) + Expect(err).ToNot(HaveOccurred()) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess, err := ln.Accept() + Expect(err).ToNot(HaveOccurred()) + str, err := sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + _, err = str.Write(testserver.PRData) + Expect(err).ToNot(HaveOccurred()) + str.Close() + close(done) + }() + serverPort := ln.Addr().(*net.UDPAddr).Port + proxy, err := quicproxy.NewQuicProxy("localhost:0", version, &quicproxy.Opts{ + RemoteAddr: fmt.Sprintf("localhost:%d", serverPort), + DelayPacket: func(d quicproxy.Direction, p uint64) time.Duration { + return rtt / 2 + }, + }) + Expect(err).ToNot(HaveOccurred()) + defer proxy.Close() + + sess, err := quic.DialAddr( + fmt.Sprintf("quic.clemente.io:%d", proxy.LocalPort()), + nil, + &quic.Config{Versions: []protocol.VersionNumber{version}}, + ) + Expect(err).ToNot(HaveOccurred()) + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + data, err := ioutil.ReadAll(str) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(testserver.PRData)) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + } + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/self_suite_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/self_suite_test.go new file mode 100644 index 00000000..dd607a84 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/self_suite_test.go @@ -0,0 +1,20 @@ +package self_test + +import ( + "math/rand" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + _ "github.com/lucas-clemente/quic-go/integrationtests/tools/testlog" +) + +func TestSelf(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Self integration tests") +} + +var _ = BeforeSuite(func() { + rand.Seed(GinkgoRandomSeed()) +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/stream_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/stream_test.go new file mode 100644 index 00000000..64039698 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/stream_test.go @@ -0,0 +1,152 @@ +package self_test + +import ( + "fmt" + "io/ioutil" + "net" + "sync" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Bidirectional streams", func() { + const numStreams = 300 + + var ( + server quic.Listener + serverAddr string + qconf *quic.Config + ) + + for _, v := range []protocol.VersionNumber{protocol.VersionTLS} { + version := v + + Context(fmt.Sprintf("with QUIC %s", version), func() { + BeforeEach(func() { + var err error + qconf = &quic.Config{ + Versions: []protocol.VersionNumber{version}, + MaxIncomingStreams: 0, + } + server, err = quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), qconf) + Expect(err).ToNot(HaveOccurred()) + serverAddr = fmt.Sprintf("quic.clemente.io:%d", server.Addr().(*net.UDPAddr).Port) + }) + + AfterEach(func() { + server.Close() + }) + + runSendingPeer := func(sess quic.Session) { + var wg sync.WaitGroup + wg.Add(numStreams) + for i := 0; i < numStreams; i++ { + str, err := sess.OpenStreamSync() + Expect(err).ToNot(HaveOccurred()) + data := testserver.GeneratePRData(25 * i) + go func() { + defer GinkgoRecover() + _, err := str.Write(data) + Expect(err).ToNot(HaveOccurred()) + Expect(str.Close()).To(Succeed()) + }() + go func() { + defer GinkgoRecover() + defer wg.Done() + dataRead, err := ioutil.ReadAll(str) + Expect(err).ToNot(HaveOccurred()) + Expect(dataRead).To(Equal(data)) + }() + } + wg.Wait() + } + + runReceivingPeer := func(sess quic.Session) { + var wg sync.WaitGroup + wg.Add(numStreams) + for i := 0; i < numStreams; i++ { + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + go func() { + defer GinkgoRecover() + defer wg.Done() + // shouldn't use io.Copy here + // we should read from the stream as early as possible, to free flow control credit + data, err := ioutil.ReadAll(str) + Expect(err).ToNot(HaveOccurred()) + _, err = str.Write(data) + Expect(err).ToNot(HaveOccurred()) + Expect(str.Close()).To(Succeed()) + }() + } + wg.Wait() + } + + It(fmt.Sprintf("client opening %d streams to a server", numStreams), func() { + var sess quic.Session + go func() { + defer GinkgoRecover() + var err error + sess, err = server.Accept() + Expect(err).ToNot(HaveOccurred()) + runReceivingPeer(sess) + }() + + client, err := quic.DialAddr(serverAddr, nil, qconf) + Expect(err).ToNot(HaveOccurred()) + runSendingPeer(client) + }) + + It(fmt.Sprintf("server opening %d streams to a client", numStreams), func() { + go func() { + defer GinkgoRecover() + sess, err := server.Accept() + Expect(err).ToNot(HaveOccurred()) + runSendingPeer(sess) + sess.Close() + }() + + client, err := quic.DialAddr(serverAddr, nil, qconf) + Expect(err).ToNot(HaveOccurred()) + runReceivingPeer(client) + Eventually(client.Context().Done()).Should(BeClosed()) + }) + + It(fmt.Sprintf("client and server opening %d each and sending data to the peer", numStreams), func() { + done1 := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess, err := server.Accept() + Expect(err).ToNot(HaveOccurred()) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + runReceivingPeer(sess) + close(done) + }() + runSendingPeer(sess) + <-done + close(done1) + }() + + client, err := quic.DialAddr(serverAddr, nil, qconf) + Expect(err).ToNot(HaveOccurred()) + done2 := make(chan struct{}) + go func() { + defer GinkgoRecover() + runSendingPeer(client) + close(done2) + }() + runReceivingPeer(client) + <-done1 + <-done2 + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/self/uni_stream_test.go b/vendor/lucas-clemente/quic-go/integrationtests/self/uni_stream_test.go new file mode 100644 index 00000000..ba3d7e4d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/self/uni_stream_test.go @@ -0,0 +1,132 @@ +package self_test + +import ( + "fmt" + "io/ioutil" + "net" + "sync" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Unidirectional Streams", func() { + const numStreams = 500 + + var ( + server quic.Listener + serverAddr string + qconf *quic.Config + ) + + BeforeEach(func() { + var err error + qconf = &quic.Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}} + server, err = quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), qconf) + Expect(err).ToNot(HaveOccurred()) + serverAddr = fmt.Sprintf("quic.clemente.io:%d", server.Addr().(*net.UDPAddr).Port) + }) + + AfterEach(func() { + server.Close() + }) + + dataForStream := func(id protocol.StreamID) []byte { + return testserver.GeneratePRData(10 * int(id)) + } + + runSendingPeer := func(sess quic.Session) { + for i := 0; i < numStreams; i++ { + str, err := sess.OpenUniStreamSync() + Expect(err).ToNot(HaveOccurred()) + go func() { + defer GinkgoRecover() + _, err := str.Write(dataForStream(str.StreamID())) + Expect(err).ToNot(HaveOccurred()) + Expect(str.Close()).To(Succeed()) + }() + } + } + + runReceivingPeer := func(sess quic.Session) { + var wg sync.WaitGroup + wg.Add(numStreams) + for i := 0; i < numStreams; i++ { + str, err := sess.AcceptUniStream() + Expect(err).ToNot(HaveOccurred()) + go func() { + defer GinkgoRecover() + defer wg.Done() + data, err := ioutil.ReadAll(str) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(dataForStream(str.StreamID()))) + }() + } + wg.Wait() + } + + It(fmt.Sprintf("client opening %d streams to a server", numStreams), func() { + var sess quic.Session + go func() { + defer GinkgoRecover() + var err error + sess, err = server.Accept() + Expect(err).ToNot(HaveOccurred()) + runReceivingPeer(sess) + sess.Close() + }() + + client, err := quic.DialAddr(serverAddr, nil, qconf) + Expect(err).ToNot(HaveOccurred()) + runSendingPeer(client) + <-client.Context().Done() + }) + + It(fmt.Sprintf("server opening %d streams to a client", numStreams), func() { + go func() { + defer GinkgoRecover() + sess, err := server.Accept() + Expect(err).ToNot(HaveOccurred()) + runSendingPeer(sess) + }() + + client, err := quic.DialAddr(serverAddr, nil, qconf) + Expect(err).ToNot(HaveOccurred()) + runReceivingPeer(client) + }) + + It(fmt.Sprintf("client and server opening %d streams each and sending data to the peer", numStreams), func() { + done1 := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess, err := server.Accept() + Expect(err).ToNot(HaveOccurred()) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + runReceivingPeer(sess) + close(done) + }() + runSendingPeer(sess) + <-done + close(done1) + }() + + client, err := quic.DialAddr(serverAddr, nil, qconf) + Expect(err).ToNot(HaveOccurred()) + done2 := make(chan struct{}) + go func() { + defer GinkgoRecover() + runSendingPeer(client) + close(done2) + }() + runReceivingPeer(client) + <-done1 + <-done2 + }) +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy.go b/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy.go new file mode 100644 index 00000000..d0bd9710 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy.go @@ -0,0 +1,270 @@ +package quicproxy + +import ( + "net" + "sync" + "sync/atomic" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// Connection is a UDP connection +type connection struct { + ClientAddr *net.UDPAddr // Address of the client + ServerConn *net.UDPConn // UDP connection to server + + incomingPacketCounter uint64 + outgoingPacketCounter uint64 +} + +// Direction is the direction a packet is sent. +type Direction int + +const ( + // DirectionIncoming is the direction from the client to the server. + DirectionIncoming Direction = iota + // DirectionOutgoing is the direction from the server to the client. + DirectionOutgoing + // DirectionBoth is both incoming and outgoing + DirectionBoth +) + +func (d Direction) String() string { + switch d { + case DirectionIncoming: + return "incoming" + case DirectionOutgoing: + return "outgoing" + case DirectionBoth: + return "both" + default: + panic("unknown direction") + } +} + +// Is says if one direction matches another direction. +// For example, incoming matches both incoming and both, but not outgoing. +func (d Direction) Is(dir Direction) bool { + if d == DirectionBoth || dir == DirectionBoth { + return true + } + return d == dir +} + +// DropCallback is a callback that determines which packet gets dropped. +type DropCallback func(dir Direction, packetCount uint64) bool + +// NoDropper doesn't drop packets. +var NoDropper DropCallback = func(Direction, uint64) bool { + return false +} + +// DelayCallback is a callback that determines how much delay to apply to a packet. +type DelayCallback func(dir Direction, packetCount uint64) time.Duration + +// NoDelay doesn't apply a delay. +var NoDelay DelayCallback = func(Direction, uint64) time.Duration { + return 0 +} + +// Opts are proxy options. +type Opts struct { + // The address this proxy proxies packets to. + RemoteAddr string + // DropPacket determines whether a packet gets dropped. + DropPacket DropCallback + // DelayPacket determines how long a packet gets delayed. This allows + // simulating a connection with non-zero RTTs. + // Note that the RTT is the sum of the delay for the incoming and the outgoing packet. + DelayPacket DelayCallback +} + +// QuicProxy is a QUIC proxy that can drop and delay packets. +type QuicProxy struct { + mutex sync.Mutex + + version protocol.VersionNumber + + conn *net.UDPConn + serverAddr *net.UDPAddr + + dropPacket DropCallback + delayPacket DelayCallback + + // Mapping from client addresses (as host:port) to connection + clientDict map[string]*connection + + logger utils.Logger +} + +// NewQuicProxy creates a new UDP proxy +func NewQuicProxy(local string, version protocol.VersionNumber, opts *Opts) (*QuicProxy, error) { + if opts == nil { + opts = &Opts{} + } + laddr, err := net.ResolveUDPAddr("udp", local) + if err != nil { + return nil, err + } + conn, err := net.ListenUDP("udp", laddr) + if err != nil { + return nil, err + } + raddr, err := net.ResolveUDPAddr("udp", opts.RemoteAddr) + if err != nil { + return nil, err + } + + packetDropper := NoDropper + if opts.DropPacket != nil { + packetDropper = opts.DropPacket + } + + packetDelayer := NoDelay + if opts.DelayPacket != nil { + packetDelayer = opts.DelayPacket + } + + p := QuicProxy{ + clientDict: make(map[string]*connection), + conn: conn, + serverAddr: raddr, + dropPacket: packetDropper, + delayPacket: packetDelayer, + version: version, + logger: utils.DefaultLogger.WithPrefix("proxy"), + } + + p.logger.Debugf("Starting UDP Proxy %s <-> %s", conn.LocalAddr(), raddr) + go p.runProxy() + return &p, nil +} + +// Close stops the UDP Proxy +func (p *QuicProxy) Close() error { + p.mutex.Lock() + defer p.mutex.Unlock() + for _, c := range p.clientDict { + if err := c.ServerConn.Close(); err != nil { + return err + } + } + return p.conn.Close() +} + +// LocalAddr is the address the proxy is listening on. +func (p *QuicProxy) LocalAddr() net.Addr { + return p.conn.LocalAddr() +} + +// LocalPort is the UDP port number the proxy is listening on. +func (p *QuicProxy) LocalPort() int { + return p.conn.LocalAddr().(*net.UDPAddr).Port +} + +func (p *QuicProxy) newConnection(cliAddr *net.UDPAddr) (*connection, error) { + srvudp, err := net.DialUDP("udp", nil, p.serverAddr) + if err != nil { + return nil, err + } + return &connection{ + ClientAddr: cliAddr, + ServerConn: srvudp, + }, nil +} + +// runProxy listens on the proxy address and handles incoming packets. +func (p *QuicProxy) runProxy() error { + for { + buffer := make([]byte, protocol.MaxReceivePacketSize) + n, cliaddr, err := p.conn.ReadFromUDP(buffer) + if err != nil { + return err + } + raw := buffer[0:n] + + saddr := cliaddr.String() + p.mutex.Lock() + conn, ok := p.clientDict[saddr] + + if !ok { + conn, err = p.newConnection(cliaddr) + if err != nil { + p.mutex.Unlock() + return err + } + p.clientDict[saddr] = conn + go p.runConnection(conn) + } + p.mutex.Unlock() + + packetCount := atomic.AddUint64(&conn.incomingPacketCounter, 1) + + if p.dropPacket(DirectionIncoming, packetCount) { + if p.logger.Debug() { + p.logger.Debugf("dropping incoming packet %d (%d bytes)", packetCount, n) + } + continue + } + + // Send the packet to the server + delay := p.delayPacket(DirectionIncoming, packetCount) + if delay != 0 { + if p.logger.Debug() { + p.logger.Debugf("delaying incoming packet %d (%d bytes) to %s by %s", packetCount, n, conn.ServerConn.RemoteAddr(), delay) + } + time.AfterFunc(delay, func() { + // TODO: handle error + _, _ = conn.ServerConn.Write(raw) + }) + } else { + if p.logger.Debug() { + p.logger.Debugf("forwarding incoming packet %d (%d bytes) to %s", packetCount, n, conn.ServerConn.RemoteAddr()) + } + if _, err := conn.ServerConn.Write(raw); err != nil { + return err + } + } + } +} + +// runConnection handles packets from server to a single client +func (p *QuicProxy) runConnection(conn *connection) error { + for { + buffer := make([]byte, protocol.MaxReceivePacketSize) + n, err := conn.ServerConn.Read(buffer) + if err != nil { + return err + } + raw := buffer[0:n] + + packetCount := atomic.AddUint64(&conn.outgoingPacketCounter, 1) + + if p.dropPacket(DirectionOutgoing, packetCount) { + if p.logger.Debug() { + p.logger.Debugf("dropping outgoing packet %d (%d bytes)", packetCount, n) + } + continue + } + + delay := p.delayPacket(DirectionOutgoing, packetCount) + if delay != 0 { + if p.logger.Debug() { + p.logger.Debugf("delaying outgoing packet %d (%d bytes) to %s by %s", packetCount, n, conn.ClientAddr, delay) + } + time.AfterFunc(delay, func() { + // TODO: handle error + _, _ = p.conn.WriteToUDP(raw, conn.ClientAddr) + }) + } else { + if p.logger.Debug() { + p.logger.Debugf("forwarding outgoing packet %d (%d bytes) to %s", packetCount, n, conn.ClientAddr) + } + if _, err := p.conn.WriteToUDP(raw, conn.ClientAddr); err != nil { + return err + } + } + } +} diff --git a/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_suite_test.go b/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_suite_test.go new file mode 100644 index 00000000..6e413a82 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_suite_test.go @@ -0,0 +1,13 @@ +package quicproxy + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestQuicGo(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "QUIC Proxy") +} diff --git a/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_test.go b/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_test.go new file mode 100644 index 00000000..945a9c48 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/tools/proxy/proxy_test.go @@ -0,0 +1,394 @@ +package quicproxy + +import ( + "bytes" + "net" + "runtime/pprof" + "strconv" + "strings" + "sync/atomic" + "time" + + "fmt" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type packetData []byte + +var _ = Describe("QUIC Proxy", func() { + makePacket := func(p protocol.PacketNumber, payload []byte) []byte { + b := &bytes.Buffer{} + hdr := wire.Header{ + PacketNumber: p, + PacketNumberLen: protocol.PacketNumberLen6, + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0, 0, 0x13, 0x37}, + SrcConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0, 0, 0x13, 0x37}, + } + hdr.Write(b, protocol.PerspectiveServer, protocol.VersionWhatever) + raw := b.Bytes() + raw = append(raw, payload...) + return raw + } + + Context("Proxy setup and teardown", func() { + It("sets up the UDPProxy", func() { + proxy, err := NewQuicProxy("localhost:0", protocol.VersionWhatever, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(proxy.clientDict).To(HaveLen(0)) + + // check that the proxy port is in use + addr, err := net.ResolveUDPAddr("udp", "localhost:"+strconv.Itoa(proxy.LocalPort())) + Expect(err).ToNot(HaveOccurred()) + _, err = net.ListenUDP("udp", addr) + Expect(err).To(MatchError(fmt.Sprintf("listen udp 127.0.0.1:%d: bind: address already in use", proxy.LocalPort()))) + Expect(proxy.Close()).To(Succeed()) // stopping is tested in the next test + }) + + It("stops the UDPProxy", func() { + isProxyRunning := func() bool { + var b bytes.Buffer + pprof.Lookup("goroutine").WriteTo(&b, 1) + return strings.Contains(b.String(), "proxy.(*QuicProxy).runProxy") + } + + proxy, err := NewQuicProxy("localhost:0", protocol.VersionWhatever, nil) + Expect(err).ToNot(HaveOccurred()) + port := proxy.LocalPort() + Expect(isProxyRunning()).To(BeTrue()) + err = proxy.Close() + Expect(err).ToNot(HaveOccurred()) + + // check that the proxy port is not in use anymore + addr, err := net.ResolveUDPAddr("udp", "localhost:"+strconv.Itoa(port)) + Expect(err).ToNot(HaveOccurred()) + // sometimes it takes a while for the OS to free the port + Eventually(func() error { + ln, err := net.ListenUDP("udp", addr) + if err != nil { + return err + } + ln.Close() + return nil + }).ShouldNot(HaveOccurred()) + Eventually(isProxyRunning).Should(BeFalse()) + }) + + It("stops listening for proxied connections", func() { + isConnRunning := func() bool { + var b bytes.Buffer + pprof.Lookup("goroutine").WriteTo(&b, 1) + return strings.Contains(b.String(), "proxy.(*QuicProxy).runConnection") + } + + serverAddr, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + serverConn, err := net.ListenUDP("udp", serverAddr) + Expect(err).ToNot(HaveOccurred()) + defer serverConn.Close() + + proxy, err := NewQuicProxy("localhost:0", protocol.VersionWhatever, &Opts{RemoteAddr: serverConn.LocalAddr().String()}) + Expect(err).ToNot(HaveOccurred()) + Expect(isConnRunning()).To(BeFalse()) + + // check that the proxy port is not in use anymore + conn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr)) + Expect(err).ToNot(HaveOccurred()) + _, err = conn.Write(makePacket(1, []byte("foobar"))) + Expect(err).ToNot(HaveOccurred()) + Eventually(isConnRunning).Should(BeTrue()) + Expect(proxy.Close()).To(Succeed()) + Eventually(isConnRunning).Should(BeFalse()) + }) + + It("has the correct LocalAddr and LocalPort", func() { + proxy, err := NewQuicProxy("localhost:0", protocol.VersionWhatever, nil) + Expect(err).ToNot(HaveOccurred()) + + Expect(proxy.LocalAddr().String()).To(Equal("127.0.0.1:" + strconv.Itoa(proxy.LocalPort()))) + Expect(proxy.LocalPort()).ToNot(BeZero()) + + Expect(proxy.Close()).To(Succeed()) + }) + }) + + Context("Proxy tests", func() { + var ( + serverConn *net.UDPConn + serverNumPacketsSent int32 + serverReceivedPackets chan packetData + clientConn *net.UDPConn + proxy *QuicProxy + ) + + startProxy := func(opts *Opts) { + var err error + proxy, err = NewQuicProxy("localhost:0", protocol.VersionWhatever, opts) + Expect(err).ToNot(HaveOccurred()) + clientConn, err = net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr)) + Expect(err).ToNot(HaveOccurred()) + } + + // getClientDict returns a copy of the clientDict map + getClientDict := func() map[string]*connection { + d := make(map[string]*connection) + proxy.mutex.Lock() + defer proxy.mutex.Unlock() + for k, v := range proxy.clientDict { + d[k] = v + } + return d + } + + BeforeEach(func() { + serverReceivedPackets = make(chan packetData, 100) + atomic.StoreInt32(&serverNumPacketsSent, 0) + + // setup a dump UDP server + // in production this would be a QUIC server + raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") + Expect(err).ToNot(HaveOccurred()) + serverConn, err = net.ListenUDP("udp", raddr) + Expect(err).ToNot(HaveOccurred()) + + go func() { + for { + buf := make([]byte, protocol.MaxReceivePacketSize) + // the ReadFromUDP will error as soon as the UDP conn is closed + n, addr, err2 := serverConn.ReadFromUDP(buf) + if err2 != nil { + return + } + data := buf[0:n] + serverReceivedPackets <- packetData(data) + // echo the packet + serverConn.WriteToUDP(data, addr) + atomic.AddInt32(&serverNumPacketsSent, 1) + } + }() + }) + + AfterEach(func() { + err := proxy.Close() + Expect(err).ToNot(HaveOccurred()) + err = serverConn.Close() + Expect(err).ToNot(HaveOccurred()) + err = clientConn.Close() + Expect(err).ToNot(HaveOccurred()) + time.Sleep(200 * time.Millisecond) + }) + + Context("no packet drop", func() { + It("relays packets from the client to the server", func() { + startProxy(&Opts{RemoteAddr: serverConn.LocalAddr().String()}) + // send the first packet + _, err := clientConn.Write(makePacket(1, []byte("foobar"))) + Expect(err).ToNot(HaveOccurred()) + + Eventually(getClientDict).Should(HaveLen(1)) + var conn *connection + for _, conn = range getClientDict() { + Eventually(func() uint64 { return atomic.LoadUint64(&conn.incomingPacketCounter) }).Should(Equal(uint64(1))) + } + + // send the second packet + _, err = clientConn.Write(makePacket(2, []byte("decafbad"))) + Expect(err).ToNot(HaveOccurred()) + + Eventually(serverReceivedPackets).Should(HaveLen(2)) + Expect(getClientDict()).To(HaveLen(1)) + Expect(string(<-serverReceivedPackets)).To(ContainSubstring("foobar")) + Expect(string(<-serverReceivedPackets)).To(ContainSubstring("decafbad")) + }) + + It("relays packets from the server to the client", func() { + startProxy(&Opts{RemoteAddr: serverConn.LocalAddr().String()}) + // send the first packet + _, err := clientConn.Write(makePacket(1, []byte("foobar"))) + Expect(err).ToNot(HaveOccurred()) + + Eventually(getClientDict).Should(HaveLen(1)) + var key string + var conn *connection + for key, conn = range getClientDict() { + Eventually(func() uint64 { return atomic.LoadUint64(&conn.outgoingPacketCounter) }).Should(Equal(uint64(1))) + } + + // send the second packet + _, err = clientConn.Write(makePacket(2, []byte("decafbad"))) + Expect(err).ToNot(HaveOccurred()) + + Expect(getClientDict()).To(HaveLen(1)) + Eventually(func() uint64 { + conn := getClientDict()[key] + return atomic.LoadUint64(&conn.outgoingPacketCounter) + }).Should(BeEquivalentTo(2)) + + clientReceivedPackets := make(chan packetData, 2) + // receive the packets echoed by the server on client side + go func() { + for { + buf := make([]byte, protocol.MaxReceivePacketSize) + // the ReadFromUDP will error as soon as the UDP conn is closed + n, _, err2 := clientConn.ReadFromUDP(buf) + if err2 != nil { + return + } + data := buf[0:n] + clientReceivedPackets <- packetData(data) + } + }() + + Eventually(serverReceivedPackets).Should(HaveLen(2)) + Expect(atomic.LoadInt32(&serverNumPacketsSent)).To(BeEquivalentTo(2)) + Eventually(clientReceivedPackets).Should(HaveLen(2)) + Expect(string(<-clientReceivedPackets)).To(ContainSubstring("foobar")) + Expect(string(<-clientReceivedPackets)).To(ContainSubstring("decafbad")) + }) + }) + + Context("Drop Callbacks", func() { + It("drops incoming packets", func() { + opts := &Opts{ + RemoteAddr: serverConn.LocalAddr().String(), + DropPacket: func(d Direction, p uint64) bool { + return d == DirectionIncoming && p%2 == 0 + }, + } + startProxy(opts) + + for i := 1; i <= 6; i++ { + _, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i)))) + Expect(err).ToNot(HaveOccurred()) + } + Eventually(serverReceivedPackets).Should(HaveLen(3)) + Consistently(serverReceivedPackets).Should(HaveLen(3)) + }) + + It("drops outgoing packets", func() { + const numPackets = 6 + opts := &Opts{ + RemoteAddr: serverConn.LocalAddr().String(), + DropPacket: func(d Direction, p uint64) bool { + return d == DirectionOutgoing && p%2 == 0 + }, + } + startProxy(opts) + + clientReceivedPackets := make(chan packetData, numPackets) + // receive the packets echoed by the server on client side + go func() { + for { + buf := make([]byte, protocol.MaxReceivePacketSize) + // the ReadFromUDP will error as soon as the UDP conn is closed + n, _, err2 := clientConn.ReadFromUDP(buf) + if err2 != nil { + return + } + data := buf[0:n] + clientReceivedPackets <- packetData(data) + } + }() + + for i := 1; i <= numPackets; i++ { + _, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i)))) + Expect(err).ToNot(HaveOccurred()) + } + + Eventually(clientReceivedPackets).Should(HaveLen(numPackets / 2)) + Consistently(clientReceivedPackets).Should(HaveLen(numPackets / 2)) + }) + }) + + Context("Delay Callback", func() { + expectDelay := func(startTime time.Time, rtt time.Duration, numRTTs int) { + expectedReceiveTime := startTime.Add(time.Duration(numRTTs) * rtt) + Expect(time.Now()).To(SatisfyAll( + BeTemporally(">=", expectedReceiveTime), + BeTemporally("<", expectedReceiveTime.Add(rtt/2)), + )) + } + + It("delays incoming packets", func() { + delay := 300 * time.Millisecond + opts := &Opts{ + RemoteAddr: serverConn.LocalAddr().String(), + // delay packet 1 by 200 ms + // delay packet 2 by 400 ms + // ... + DelayPacket: func(d Direction, p uint64) time.Duration { + if d == DirectionOutgoing { + return 0 + } + return time.Duration(p) * delay + }, + } + startProxy(opts) + + // send 3 packets + start := time.Now() + for i := 1; i <= 3; i++ { + _, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i)))) + Expect(err).ToNot(HaveOccurred()) + } + Eventually(serverReceivedPackets).Should(HaveLen(1)) + expectDelay(start, delay, 1) + Eventually(serverReceivedPackets).Should(HaveLen(2)) + expectDelay(start, delay, 2) + Eventually(serverReceivedPackets).Should(HaveLen(3)) + expectDelay(start, delay, 3) + }) + + It("delays outgoing packets", func() { + const numPackets = 3 + delay := 300 * time.Millisecond + opts := &Opts{ + RemoteAddr: serverConn.LocalAddr().String(), + // delay packet 1 by 200 ms + // delay packet 2 by 400 ms + // ... + DelayPacket: func(d Direction, p uint64) time.Duration { + if d == DirectionIncoming { + return 0 + } + return time.Duration(p) * delay + }, + } + startProxy(opts) + + clientReceivedPackets := make(chan packetData, numPackets) + // receive the packets echoed by the server on client side + go func() { + for { + buf := make([]byte, protocol.MaxReceivePacketSize) + // the ReadFromUDP will error as soon as the UDP conn is closed + n, _, err2 := clientConn.ReadFromUDP(buf) + if err2 != nil { + return + } + data := buf[0:n] + clientReceivedPackets <- packetData(data) + } + }() + + start := time.Now() + for i := 1; i <= numPackets; i++ { + _, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i)))) + Expect(err).ToNot(HaveOccurred()) + } + // the packets should have arrived immediately at the server + Eventually(serverReceivedPackets).Should(HaveLen(3)) + expectDelay(start, delay, 0) + Eventually(clientReceivedPackets).Should(HaveLen(1)) + expectDelay(start, delay, 1) + Eventually(clientReceivedPackets).Should(HaveLen(2)) + expectDelay(start, delay, 2) + Eventually(clientReceivedPackets).Should(HaveLen(3)) + expectDelay(start, delay, 3) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/integrationtests/tools/testlog/testlog.go b/vendor/lucas-clemente/quic-go/integrationtests/tools/testlog/testlog.go new file mode 100644 index 00000000..d3206ba1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/tools/testlog/testlog.go @@ -0,0 +1,46 @@ +package testlog + +import ( + "flag" + "log" + "os" + + "github.com/lucas-clemente/quic-go/internal/utils" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var ( + logFileName string // the log file set in the ginkgo flags + logFile *os.File +) + +// read the logfile command line flag +// to set call ginkgo -- -logfile=log.txt +func init() { + flag.StringVar(&logFileName, "logfile", "", "log file") +} + +var _ = BeforeEach(func() { + log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds) + + if len(logFileName) > 0 { + var err error + logFile, err = os.Create(logFileName) + Expect(err).ToNot(HaveOccurred()) + log.SetOutput(logFile) + utils.DefaultLogger.SetLogLevel(utils.LogLevelDebug) + } +}) + +var _ = AfterEach(func() { + if len(logFileName) > 0 { + _ = logFile.Close() + } +}) + +// Debug says if this test is being logged +func Debug() bool { + return len(logFileName) > 0 +} diff --git a/vendor/lucas-clemente/quic-go/integrationtests/tools/testserver/server.go b/vendor/lucas-clemente/quic-go/integrationtests/tools/testserver/server.go new file mode 100644 index 00000000..70ba2dda --- /dev/null +++ b/vendor/lucas-clemente/quic-go/integrationtests/tools/testserver/server.go @@ -0,0 +1,119 @@ +package testserver + +import ( + "io" + "io/ioutil" + "net" + "net/http" + "strconv" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/h2quic" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const ( + dataLen = 500 * 1024 // 500 KB + dataLenLong = 50 * 1024 * 1024 // 50 MB +) + +var ( + // PRData contains dataLen bytes of pseudo-random data. + PRData = GeneratePRData(dataLen) + // PRDataLong contains dataLenLong bytes of pseudo-random data. + PRDataLong = GeneratePRData(dataLenLong) + + server *h2quic.Server + stoppedServing chan struct{} + port string +) + +func init() { + http.HandleFunc("/prdata", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + sl := r.URL.Query().Get("len") + if sl != "" { + var err error + l, err := strconv.Atoi(sl) + Expect(err).NotTo(HaveOccurred()) + _, err = w.Write(GeneratePRData(l)) + Expect(err).NotTo(HaveOccurred()) + } else { + _, err := w.Write(PRData) + Expect(err).NotTo(HaveOccurred()) + } + }) + + http.HandleFunc("/prdatalong", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + _, err := w.Write(PRDataLong) + Expect(err).NotTo(HaveOccurred()) + }) + + http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + _, err := io.WriteString(w, "Hello, World!\n") + Expect(err).NotTo(HaveOccurred()) + }) + + http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + body, err := ioutil.ReadAll(r.Body) + Expect(err).NotTo(HaveOccurred()) + _, err = w.Write(body) + Expect(err).NotTo(HaveOccurred()) + }) +} + +// See https://en.wikipedia.org/wiki/Lehmer_random_number_generator +func GeneratePRData(l int) []byte { + res := make([]byte, l) + seed := uint64(1) + for i := 0; i < l; i++ { + seed = seed * 48271 % 2147483647 + res[i] = byte(seed) + } + return res +} + +// StartQuicServer starts a h2quic.Server. +// versions is a slice of supported QUIC versions. It may be nil, then all supported versions are used. +func StartQuicServer(versions []protocol.VersionNumber) { + server = &h2quic.Server{ + Server: &http.Server{ + TLSConfig: testdata.GetTLSConfig(), + }, + QuicConfig: &quic.Config{ + Versions: versions, + }, + } + + addr, err := net.ResolveUDPAddr("udp", "0.0.0.0:0") + Expect(err).NotTo(HaveOccurred()) + conn, err := net.ListenUDP("udp", addr) + Expect(err).NotTo(HaveOccurred()) + port = strconv.Itoa(conn.LocalAddr().(*net.UDPAddr).Port) + + stoppedServing = make(chan struct{}) + + go func() { + defer GinkgoRecover() + server.Serve(conn) + close(stoppedServing) + }() +} + +// StopQuicServer stops the h2quic.Server. +func StopQuicServer() { + Expect(server.Close()).NotTo(HaveOccurred()) + Eventually(stoppedServing).Should(BeClosed()) +} + +// Port returns the UDP port of the QUIC server. +func Port() string { + return port +} diff --git a/vendor/lucas-clemente/quic-go/interface.go b/vendor/lucas-clemente/quic-go/interface.go new file mode 100644 index 00000000..d7048097 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/interface.go @@ -0,0 +1,223 @@ +package quic + +import ( + "context" + "io" + "net" + "time" + + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// The StreamID is the ID of a QUIC stream. +type StreamID = protocol.StreamID + +// A VersionNumber is a QUIC version number. +type VersionNumber = protocol.VersionNumber + +const ( + // VersionGQUIC39 is gQUIC version 39. + VersionGQUIC39 = protocol.Version39 + // VersionGQUIC43 is gQUIC version 43. + VersionGQUIC43 = protocol.Version43 + // VersionGQUIC44 is gQUIC version 44. + VersionGQUIC44 = protocol.Version44 + // VersionMilestone0_10_0 uses TLS + VersionMilestone0_10_0 = protocol.VersionMilestone0_10_0 +) + +// A Cookie can be used to verify the ownership of the client address. +type Cookie = handshake.Cookie + +// ConnectionState records basic details about the QUIC connection. +type ConnectionState = handshake.ConnectionState + +// An ErrorCode is an application-defined error code. +type ErrorCode = protocol.ApplicationErrorCode + +// Stream is the interface implemented by QUIC streams +type Stream interface { + // StreamID returns the stream ID. + StreamID() StreamID + // Read reads data from the stream. + // Read can be made to time out and return a net.Error with Timeout() == true + // after a fixed time limit; see SetDeadline and SetReadDeadline. + // If the stream was canceled by the peer, the error implements the StreamError + // interface, and Canceled() == true. + io.Reader + // Write writes data to the stream. + // Write can be made to time out and return a net.Error with Timeout() == true + // after a fixed time limit; see SetDeadline and SetWriteDeadline. + // If the stream was canceled by the peer, the error implements the StreamError + // interface, and Canceled() == true. + io.Writer + // Close closes the write-direction of the stream. + // Future calls to Write are not permitted after calling Close. + // It must not be called concurrently with Write. + // It must not be called after calling CancelWrite. + io.Closer + // CancelWrite aborts sending on this stream. + // It must not be called after Close. + // Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably. + // Write will unblock immediately, and future calls to Write will fail. + CancelWrite(ErrorCode) error + // CancelRead aborts receiving on this stream. + // It will ask the peer to stop transmitting stream data. + // Read will unblock immediately, and future Read calls will fail. + CancelRead(ErrorCode) error + // The context is canceled as soon as the write-side of the stream is closed. + // This happens when Close() is called, or when the stream is reset (either locally or remotely). + // Warning: This API should not be considered stable and might change soon. + Context() context.Context + // SetReadDeadline sets the deadline for future Read calls and + // any currently-blocked Read call. + // A zero value for t means Read will not time out. + SetReadDeadline(t time.Time) error + // SetWriteDeadline sets the deadline for future Write calls + // and any currently-blocked Write call. + // Even if write times out, it may return n > 0, indicating that + // some of the data was successfully written. + // A zero value for t means Write will not time out. + SetWriteDeadline(t time.Time) error + // SetDeadline sets the read and write deadlines associated + // with the connection. It is equivalent to calling both + // SetReadDeadline and SetWriteDeadline. + SetDeadline(t time.Time) error +} + +// A ReceiveStream is a unidirectional Receive Stream. +type ReceiveStream interface { + // see Stream.StreamID + StreamID() StreamID + // see Stream.Read + io.Reader + // see Stream.CancelRead + CancelRead(ErrorCode) error + // see Stream.SetReadDealine + SetReadDeadline(t time.Time) error +} + +// A SendStream is a unidirectional Send Stream. +type SendStream interface { + // see Stream.StreamID + StreamID() StreamID + // see Stream.Write + io.Writer + // see Stream.Close + io.Closer + // see Stream.CancelWrite + CancelWrite(ErrorCode) error + // see Stream.Context + Context() context.Context + // see Stream.SetWriteDeadline + SetWriteDeadline(t time.Time) error +} + +// StreamError is returned by Read and Write when the peer cancels the stream. +type StreamError interface { + error + Canceled() bool + ErrorCode() ErrorCode +} + +// A Session is a QUIC connection between two peers. +type Session interface { + // AcceptStream returns the next stream opened by the peer, blocking until one is available. + AcceptStream() (Stream, error) + // AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available. + AcceptUniStream() (ReceiveStream, error) + // OpenStream opens a new bidirectional QUIC stream. + // It returns a special error when the peer's concurrent stream limit is reached. + // There is no signaling to the peer about new streams: + // The peer can only accept the stream after data has been sent on the stream. + // TODO(#1152): Enable testing for the special error + OpenStream() (Stream, error) + // OpenStreamSync opens a new bidirectional QUIC stream. + // It blocks until the peer's concurrent stream limit allows a new stream to be opened. + OpenStreamSync() (Stream, error) + // OpenUniStream opens a new outgoing unidirectional QUIC stream. + // It returns a special error when the peer's concurrent stream limit is reached. + // TODO(#1152): Enable testing for the special error + OpenUniStream() (SendStream, error) + // OpenUniStreamSync opens a new outgoing unidirectional QUIC stream. + // It blocks until the peer's concurrent stream limit allows a new stream to be opened. + OpenUniStreamSync() (SendStream, error) + // LocalAddr returns the local address. + LocalAddr() net.Addr + // RemoteAddr returns the address of the peer. + RemoteAddr() net.Addr + // Close the connection. + io.Closer + // Close the connection with an error. + // The error must not be nil. + CloseWithError(ErrorCode, error) error + // The context is cancelled when the session is closed. + // Warning: This API should not be considered stable and might change soon. + Context() context.Context + // ConnectionState returns basic details about the QUIC connection. + // Warning: This API should not be considered stable and might change soon. + ConnectionState() ConnectionState +} + +// Config contains all configuration data needed for a QUIC server or client. +type Config struct { + // The QUIC versions that can be negotiated. + // If not set, it uses all versions available. + // Warning: This API should not be considered stable and will change soon. + Versions []VersionNumber + // Ask the server to omit the connection ID sent in the Public Header. + // This saves 8 bytes in the Public Header in every packet. However, if the IP address of the server changes, the connection cannot be migrated. + // Currently only valid for the client. + RequestConnectionIDOmission bool + // The length of the connection ID in bytes. Only valid for IETF QUIC. + // It can be 0, or any value between 4 and 18. + // If not set, the interpretation depends on where the Config is used: + // If used for dialing an address, a 0 byte connection ID will be used. + // If used for a server, or dialing on a packet conn, a 4 byte connection ID will be used. + // When dialing on a packet conn, the ConnectionIDLength value must be the same for every Dial call. + ConnectionIDLength int + // HandshakeTimeout is the maximum duration that the cryptographic handshake may take. + // If the timeout is exceeded, the connection is closed. + // If this value is zero, the timeout is set to 10 seconds. + HandshakeTimeout time.Duration + // IdleTimeout is the maximum duration that may pass without any incoming network activity. + // This value only applies after the handshake has completed. + // If the timeout is exceeded, the connection is closed. + // If this value is zero, the timeout is set to 30 seconds. + IdleTimeout time.Duration + // AcceptCookie determines if a Cookie is accepted. + // It is called with cookie = nil if the client didn't send an Cookie. + // If not set, it verifies that the address matches, and that the Cookie was issued within the last 24 hours. + // This option is only valid for the server. + AcceptCookie func(clientAddr net.Addr, cookie *Cookie) bool + // MaxReceiveStreamFlowControlWindow is the maximum stream-level flow control window for receiving data. + // If this value is zero, it will default to 1 MB for the server and 6 MB for the client. + MaxReceiveStreamFlowControlWindow uint64 + // MaxReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data. + // If this value is zero, it will default to 1.5 MB for the server and 15 MB for the client. + MaxReceiveConnectionFlowControlWindow uint64 + // MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open. + // If not set, it will default to 100. + // If set to a negative value, it doesn't allow any bidirectional streams. + // Values larger than 65535 (math.MaxUint16) are invalid. + MaxIncomingStreams int + // MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open. + // This value doesn't have any effect in Google QUIC. + // If not set, it will default to 100. + // If set to a negative value, it doesn't allow any unidirectional streams. + // Values larger than 65535 (math.MaxUint16) are invalid. + MaxIncomingUniStreams int + // KeepAlive defines whether this peer will periodically send PING frames to keep the connection alive. + KeepAlive bool +} + +// A Listener for incoming QUIC connections +type Listener interface { + // Close the server, sending CONNECTION_CLOSE frames to each peer. + Close() error + // Addr returns the local network addr that the server is listening on. + Addr() net.Addr + // Accept returns new sessions. It should be called in a loop. + Accept() (Session, error) +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/ackhandler_suite_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/ackhandler_suite_test.go new file mode 100644 index 00000000..9e7e0777 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/ackhandler_suite_test.go @@ -0,0 +1,24 @@ +package ackhandler + +import ( + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCrypto(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "AckHandler Suite") +} + +var mockCtrl *gomock.Controller + +var _ = BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) +}) + +var _ = AfterEach(func() { + mockCtrl.Finish() +}) diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/gen.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/gen.go new file mode 100644 index 00000000..32235f81 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/gen.go @@ -0,0 +1,3 @@ +package ackhandler + +//go:generate genny -pkg ackhandler -in ../utils/linkedlist/linkedlist.go -out packet_linkedlist.go gen Item=Packet diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/interfaces.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/interfaces.go new file mode 100644 index 00000000..1924cdc9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/interfaces.go @@ -0,0 +1,47 @@ +package ackhandler + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +// SentPacketHandler handles ACKs received for outgoing packets +type SentPacketHandler interface { + // SentPacket may modify the packet + SentPacket(packet *Packet) + SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) + ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, recvTime time.Time) error + SetHandshakeComplete() + + // The SendMode determines if and what kind of packets can be sent. + SendMode() SendMode + // TimeUntilSend is the time when the next packet should be sent. + // It is used for pacing packets. + TimeUntilSend() time.Time + // ShouldSendNumPackets returns the number of packets that should be sent immediately. + // It always returns a number greater or equal than 1. + // A number greater than 1 is returned when the pacing delay is smaller than the minimum pacing delay. + // Note that the number of packets is only calculated based on the pacing algorithm. + // Before sending any packet, SendingAllowed() must be called to learn if we can actually send it. + ShouldSendNumPackets() int + + GetStopWaitingFrame(force bool) *wire.StopWaitingFrame + GetLowestPacketNotConfirmedAcked() protocol.PacketNumber + DequeuePacketForRetransmission() *Packet + DequeueProbePacket() (*Packet, error) + GetPacketNumberLen(protocol.PacketNumber) protocol.PacketNumberLen + + GetAlarmTimeout() time.Time + OnAlarm() error +} + +// ReceivedPacketHandler handles ACKs needed to send for incoming packets +type ReceivedPacketHandler interface { + ReceivedPacket(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck bool) error + IgnoreBelow(protocol.PacketNumber) + + GetAlarmTimeout() time.Time + GetAckFrame() *wire.AckFrame +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/packet.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/packet.go new file mode 100644 index 00000000..9673a85c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/packet.go @@ -0,0 +1,29 @@ +package ackhandler + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +// A Packet is a packet +type Packet struct { + PacketNumber protocol.PacketNumber + PacketType protocol.PacketType + Frames []wire.Frame + Length protocol.ByteCount + EncryptionLevel protocol.EncryptionLevel + SendTime time.Time + + largestAcked protocol.PacketNumber // if the packet contains an ACK, the LargestAcked value of that ACK + + // There are two reasons why a packet cannot be retransmitted: + // * it was already retransmitted + // * this packet is a retransmission, and we already received an ACK for the original packet + canBeRetransmitted bool + includedInBytesInFlight bool + retransmittedAs []protocol.PacketNumber + isRetransmission bool // we need a separate bool here because 0 is a valid packet number + retransmissionOf protocol.PacketNumber +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/packet_linkedlist.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/packet_linkedlist.go new file mode 100644 index 00000000..bb74f4ef --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/packet_linkedlist.go @@ -0,0 +1,217 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package ackhandler + +// Linked list implementation from the Go standard library. + +// PacketElement is an element of a linked list. +type PacketElement struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *PacketElement + + // The list to which this element belongs. + list *PacketList + + // The value stored with this element. + Value Packet +} + +// Next returns the next list element or nil. +func (e *PacketElement) Next() *PacketElement { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// Prev returns the previous list element or nil. +func (e *PacketElement) Prev() *PacketElement { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// PacketList is a linked list of Packets. +type PacketList struct { + root PacketElement // sentinel list element, only &root, root.prev, and root.next are used + len int // current list length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *PacketList) Init() *PacketList { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// NewPacketList returns an initialized list. +func NewPacketList() *PacketList { return new(PacketList).Init() } + +// Len returns the number of elements of list l. +// The complexity is O(1). +func (l *PacketList) Len() int { return l.len } + +// Front returns the first element of list l or nil if the list is empty. +func (l *PacketList) Front() *PacketElement { + if l.len == 0 { + return nil + } + return l.root.next +} + +// Back returns the last element of list l or nil if the list is empty. +func (l *PacketList) Back() *PacketElement { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero List value. +func (l *PacketList) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *PacketList) insert(e, at *PacketElement) *PacketElement { + n := at.next + at.next = e + e.prev = at + e.next = n + n.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). +func (l *PacketList) insertValue(v Packet, at *PacketElement) *PacketElement { + return l.insert(&PacketElement{Value: v}, at) +} + +// remove removes e from its list, decrements l.len, and returns e. +func (l *PacketList) remove(e *PacketElement) *PacketElement { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + return e +} + +// Remove removes e from l if e is an element of list l. +// It returns the element value e.Value. +// The element must not be nil. +func (l *PacketList) Remove(e *PacketElement) Packet { + if e.list == l { + // if e.list == l, l must have been initialized when e was inserted + // in l or l == nil (e is a zero Element) and l.remove will crash + l.remove(e) + } + return e.Value +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *PacketList) PushFront(v Packet) *PacketElement { + l.lazyInit() + return l.insertValue(v, &l.root) +} + +// PushBack inserts a new element e with value v at the back of list l and returns e. +func (l *PacketList) PushBack(v Packet) *PacketElement { + l.lazyInit() + return l.insertValue(v, l.root.prev) +} + +// InsertBefore inserts a new element e with value v immediately before mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *PacketList) InsertBefore(v Packet, mark *PacketElement) *PacketElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark.prev) +} + +// InsertAfter inserts a new element e with value v immediately after mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *PacketList) InsertAfter(v Packet, mark *PacketElement) *PacketElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *PacketList) MoveToFront(e *PacketElement) { + if e.list != l || l.root.next == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), &l.root) +} + +// MoveToBack moves element e to the back of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *PacketList) MoveToBack(e *PacketElement) { + if e.list != l || l.root.prev == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), l.root.prev) +} + +// MoveBefore moves element e to its new position before mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *PacketList) MoveBefore(e, mark *PacketElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark.prev) +} + +// MoveAfter moves element e to its new position after mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *PacketList) MoveAfter(e, mark *PacketElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark) +} + +// PushBackList inserts a copy of an other list at the back of list l. +// The lists l and other may be the same. They must not be nil. +func (l *PacketList) PushBackList(other *PacketList) { + l.lazyInit() + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +// PushFrontList inserts a copy of an other list at the front of list l. +// The lists l and other may be the same. They must not be nil. +func (l *PacketList) PushFrontList(other *PacketList) { + l.lazyInit() + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, &l.root) + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go new file mode 100644 index 00000000..8af21324 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go @@ -0,0 +1,215 @@ +package ackhandler + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type receivedPacketHandler struct { + largestObserved protocol.PacketNumber + ignoreBelow protocol.PacketNumber + largestObservedReceivedTime time.Time + + packetHistory *receivedPacketHistory + + ackSendDelay time.Duration + rttStats *congestion.RTTStats + + packetsReceivedSinceLastAck int + retransmittablePacketsReceivedSinceLastAck int + ackQueued bool + ackAlarm time.Time + lastAck *wire.AckFrame + + logger utils.Logger + + version protocol.VersionNumber +} + +const ( + // maximum delay that can be applied to an ACK for a retransmittable packet + ackSendDelay = 25 * time.Millisecond + // initial maximum number of retransmittable packets received before sending an ack. + initialRetransmittablePacketsBeforeAck = 2 + // number of retransmittable that an ACK is sent for + retransmittablePacketsBeforeAck = 10 + // 1/5 RTT delay when doing ack decimation + ackDecimationDelay = 1.0 / 4 + // 1/8 RTT delay when doing ack decimation + shortAckDecimationDelay = 1.0 / 8 + // Minimum number of packets received before ack decimation is enabled. + // This intends to avoid the beginning of slow start, when CWNDs may be + // rapidly increasing. + minReceivedBeforeAckDecimation = 100 + // Maximum number of packets to ack immediately after a missing packet for + // fast retransmission to kick in at the sender. This limit is created to + // reduce the number of acks sent that have no benefit for fast retransmission. + // Set to the number of nacks needed for fast retransmit plus one for protection + // against an ack loss + maxPacketsAfterNewMissing = 4 +) + +// NewReceivedPacketHandler creates a new receivedPacketHandler +func NewReceivedPacketHandler( + rttStats *congestion.RTTStats, + logger utils.Logger, + version protocol.VersionNumber, +) ReceivedPacketHandler { + return &receivedPacketHandler{ + packetHistory: newReceivedPacketHistory(), + ackSendDelay: ackSendDelay, + rttStats: rttStats, + logger: logger, + version: version, + } +} + +func (h *receivedPacketHandler) ReceivedPacket(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck bool) error { + if packetNumber < h.ignoreBelow { + return nil + } + + isMissing := h.isMissing(packetNumber) + if packetNumber > h.largestObserved { + h.largestObserved = packetNumber + h.largestObservedReceivedTime = rcvTime + } + + if err := h.packetHistory.ReceivedPacket(packetNumber); err != nil { + return err + } + h.maybeQueueAck(packetNumber, rcvTime, shouldInstigateAck, isMissing) + return nil +} + +// IgnoreBelow sets a lower limit for acking packets. +// Packets with packet numbers smaller than p will not be acked. +func (h *receivedPacketHandler) IgnoreBelow(p protocol.PacketNumber) { + if p <= h.ignoreBelow { + return + } + h.ignoreBelow = p + h.packetHistory.DeleteBelow(p) + if h.logger.Debug() { + h.logger.Debugf("\tIgnoring all packets below %#x.", p) + } +} + +// isMissing says if a packet was reported missing in the last ACK. +func (h *receivedPacketHandler) isMissing(p protocol.PacketNumber) bool { + if h.lastAck == nil || p < h.ignoreBelow { + return false + } + return p < h.lastAck.LargestAcked() && !h.lastAck.AcksPacket(p) +} + +func (h *receivedPacketHandler) hasNewMissingPackets() bool { + if h.lastAck == nil { + return false + } + highestRange := h.packetHistory.GetHighestAckRange() + return highestRange.Smallest >= h.lastAck.LargestAcked() && highestRange.Len() <= maxPacketsAfterNewMissing +} + +// maybeQueueAck queues an ACK, if necessary. +// It is implemented analogously to Chrome's QuicConnection::MaybeQueueAck() +// in ACK_DECIMATION_WITH_REORDERING mode. +func (h *receivedPacketHandler) maybeQueueAck(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck, wasMissing bool) { + h.packetsReceivedSinceLastAck++ + + // always ack the first packet + if h.lastAck == nil { + h.logger.Debugf("\tQueueing ACK because the first packet should be acknowledged.") + h.ackQueued = true + return + } + + // Send an ACK if this packet was reported missing in an ACK sent before. + // Ack decimation with reordering relies on the timer to send an ACK, but if + // missing packets we reported in the previous ack, send an ACK immediately. + if wasMissing { + if h.logger.Debug() { + h.logger.Debugf("\tQueueing ACK because packet %#x was missing before.", packetNumber) + } + h.ackQueued = true + } + + if !h.ackQueued && shouldInstigateAck { + h.retransmittablePacketsReceivedSinceLastAck++ + + if packetNumber > minReceivedBeforeAckDecimation { + // ack up to 10 packets at once + if h.retransmittablePacketsReceivedSinceLastAck >= retransmittablePacketsBeforeAck { + h.ackQueued = true + if h.logger.Debug() { + h.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using threshold: %d).", h.retransmittablePacketsReceivedSinceLastAck, retransmittablePacketsBeforeAck) + } + } else if h.ackAlarm.IsZero() { + // wait for the minimum of the ack decimation delay or the delayed ack time before sending an ack + ackDelay := utils.MinDuration(ackSendDelay, time.Duration(float64(h.rttStats.MinRTT())*float64(ackDecimationDelay))) + h.ackAlarm = rcvTime.Add(ackDelay) + if h.logger.Debug() { + h.logger.Debugf("\tSetting ACK timer to min(1/4 min-RTT, max ack delay): %s (%s from now)", ackDelay, time.Until(h.ackAlarm)) + } + } + } else { + // send an ACK every 2 retransmittable packets + if h.retransmittablePacketsReceivedSinceLastAck >= initialRetransmittablePacketsBeforeAck { + if h.logger.Debug() { + h.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d).", h.retransmittablePacketsReceivedSinceLastAck, initialRetransmittablePacketsBeforeAck) + } + h.ackQueued = true + } else if h.ackAlarm.IsZero() { + if h.logger.Debug() { + h.logger.Debugf("\tSetting ACK timer to max ack delay: %s", ackSendDelay) + } + h.ackAlarm = rcvTime.Add(ackSendDelay) + } + } + // If there are new missing packets to report, set a short timer to send an ACK. + if h.hasNewMissingPackets() { + // wait the minimum of 1/8 min RTT and the existing ack time + ackDelay := time.Duration(float64(h.rttStats.MinRTT()) * float64(shortAckDecimationDelay)) + ackTime := rcvTime.Add(ackDelay) + if h.ackAlarm.IsZero() || h.ackAlarm.After(ackTime) { + h.ackAlarm = ackTime + if h.logger.Debug() { + h.logger.Debugf("\tSetting ACK timer to 1/8 min-RTT: %s (%s from now)", ackDelay, time.Until(h.ackAlarm)) + } + } + } + } + + if h.ackQueued { + // cancel the ack alarm + h.ackAlarm = time.Time{} + } +} + +func (h *receivedPacketHandler) GetAckFrame() *wire.AckFrame { + now := time.Now() + if !h.ackQueued && (h.ackAlarm.IsZero() || h.ackAlarm.After(now)) { + return nil + } + if h.logger.Debug() && !h.ackQueued && !h.ackAlarm.IsZero() { + h.logger.Debugf("Sending ACK because the ACK timer expired.") + } + + ack := &wire.AckFrame{ + AckRanges: h.packetHistory.GetAckRanges(), + DelayTime: now.Sub(h.largestObservedReceivedTime), + } + + h.lastAck = ack + h.ackAlarm = time.Time{} + h.ackQueued = false + h.packetsReceivedSinceLastAck = 0 + h.retransmittablePacketsReceivedSinceLastAck = 0 + return ack +} + +func (h *receivedPacketHandler) GetAlarmTimeout() time.Time { return h.ackAlarm } diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler_test.go new file mode 100644 index 00000000..d845efe8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler_test.go @@ -0,0 +1,382 @@ +package ackhandler + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("receivedPacketHandler", func() { + var ( + handler *receivedPacketHandler + rttStats *congestion.RTTStats + ) + + BeforeEach(func() { + rttStats = &congestion.RTTStats{} + handler = NewReceivedPacketHandler(rttStats, utils.DefaultLogger, protocol.VersionWhatever).(*receivedPacketHandler) + }) + + Context("accepting packets", func() { + It("handles a packet that arrives late", func() { + err := handler.ReceivedPacket(protocol.PacketNumber(1), time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(protocol.PacketNumber(3), time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(protocol.PacketNumber(2), time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + }) + + It("saves the time when each packet arrived", func() { + err := handler.ReceivedPacket(protocol.PacketNumber(3), time.Now(), true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestObservedReceivedTime).To(BeTemporally("~", time.Now(), 10*time.Millisecond)) + }) + + It("updates the largestObserved and the largestObservedReceivedTime", func() { + now := time.Now() + handler.largestObserved = 3 + handler.largestObservedReceivedTime = now.Add(-1 * time.Second) + err := handler.ReceivedPacket(5, now, true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestObserved).To(Equal(protocol.PacketNumber(5))) + Expect(handler.largestObservedReceivedTime).To(Equal(now)) + }) + + It("doesn't update the largestObserved and the largestObservedReceivedTime for a belated packet", func() { + now := time.Now() + timestamp := now.Add(-1 * time.Second) + handler.largestObserved = 5 + handler.largestObservedReceivedTime = timestamp + err := handler.ReceivedPacket(4, now, true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestObserved).To(Equal(protocol.PacketNumber(5))) + Expect(handler.largestObservedReceivedTime).To(Equal(timestamp)) + }) + + It("passes on errors from receivedPacketHistory", func() { + var err error + for i := protocol.PacketNumber(0); i < 5*protocol.MaxTrackedReceivedAckRanges; i++ { + err = handler.ReceivedPacket(2*i+1, time.Time{}, true) + // this will eventually return an error + // details about when exactly the receivedPacketHistory errors are tested there + if err != nil { + break + } + } + Expect(err).To(MatchError(errTooManyOutstandingReceivedAckRanges)) + }) + }) + + Context("ACKs", func() { + Context("queueing ACKs", func() { + receiveAndAck10Packets := func() { + for i := 1; i <= 10; i++ { + err := handler.ReceivedPacket(protocol.PacketNumber(i), time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + } + Expect(handler.GetAckFrame()).ToNot(BeNil()) + Expect(handler.ackQueued).To(BeFalse()) + } + + receiveAndAckPacketsUntilAckDecimation := func() { + for i := 1; i <= minReceivedBeforeAckDecimation; i++ { + err := handler.ReceivedPacket(protocol.PacketNumber(i), time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + } + Expect(handler.GetAckFrame()).ToNot(BeNil()) + Expect(handler.ackQueued).To(BeFalse()) + } + + It("always queues an ACK for the first packet", func() { + err := handler.ReceivedPacket(1, time.Time{}, false) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeTrue()) + Expect(handler.GetAlarmTimeout()).To(BeZero()) + }) + + It("works with packet number 0", func() { + err := handler.ReceivedPacket(0, time.Time{}, false) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeTrue()) + Expect(handler.GetAlarmTimeout()).To(BeZero()) + }) + + It("queues an ACK for every second retransmittable packet at the beginning", func() { + receiveAndAck10Packets() + p := protocol.PacketNumber(11) + for i := 0; i <= 20; i++ { + err := handler.ReceivedPacket(p, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeFalse()) + p++ + err = handler.ReceivedPacket(p, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeTrue()) + p++ + // dequeue the ACK frame + Expect(handler.GetAckFrame()).ToNot(BeNil()) + } + }) + + It("queues an ACK for every 10 retransmittable packet, if they are arriving fast", func() { + receiveAndAck10Packets() + p := protocol.PacketNumber(10000) + for i := 0; i < 9; i++ { + err := handler.ReceivedPacket(p, time.Now(), true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeFalse()) + p++ + } + Expect(handler.GetAlarmTimeout()).NotTo(BeZero()) + err := handler.ReceivedPacket(p, time.Now(), true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeTrue()) + Expect(handler.GetAlarmTimeout()).To(BeZero()) + }) + + It("only sets the timer when receiving a retransmittable packets", func() { + receiveAndAck10Packets() + err := handler.ReceivedPacket(11, time.Now(), false) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeFalse()) + Expect(handler.GetAlarmTimeout()).To(BeZero()) + rcvTime := time.Now().Add(10 * time.Millisecond) + err = handler.ReceivedPacket(12, rcvTime, true) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeFalse()) + Expect(handler.GetAlarmTimeout()).To(Equal(rcvTime.Add(ackSendDelay))) + }) + + It("queues an ACK if it was reported missing before", func() { + receiveAndAck10Packets() + err := handler.ReceivedPacket(11, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(13, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() // ACK: 1-11 and 13, missing: 12 + Expect(ack).ToNot(BeNil()) + Expect(ack.HasMissingRanges()).To(BeTrue()) + Expect(handler.ackQueued).To(BeFalse()) + err = handler.ReceivedPacket(12, time.Time{}, false) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeTrue()) + }) + + It("doesn't queue an ACK if it was reported missing before, but is below the threshold", func() { + receiveAndAck10Packets() + // 11 is missing + err := handler.ReceivedPacket(12, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(13, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() // ACK: 1-10, 12-13 + Expect(ack).ToNot(BeNil()) + // now receive 11 + handler.IgnoreBelow(12) + err = handler.ReceivedPacket(11, time.Time{}, false) + Expect(err).ToNot(HaveOccurred()) + ack = handler.GetAckFrame() + Expect(ack).To(BeNil()) + }) + + It("doesn't queue an ACK if the packet closes a gap that was not yet reported", func() { + receiveAndAckPacketsUntilAckDecimation() + p := protocol.PacketNumber(minReceivedBeforeAckDecimation + 1) + err := handler.ReceivedPacket(p+1, time.Now(), true) // p is missing now + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeFalse()) + Expect(handler.GetAlarmTimeout()).ToNot(BeZero()) + err = handler.ReceivedPacket(p, time.Now(), true) // p is not missing any more + Expect(err).ToNot(HaveOccurred()) + Expect(handler.ackQueued).To(BeFalse()) + }) + + It("sets an ACK alarm after 1/4 RTT if it creates a new missing range", func() { + now := time.Now().Add(-time.Hour) + rtt := 80 * time.Millisecond + rttStats.UpdateRTT(rtt, 0, now) + receiveAndAckPacketsUntilAckDecimation() + p := protocol.PacketNumber(minReceivedBeforeAckDecimation + 1) + for i := p; i < p+6; i++ { + err := handler.ReceivedPacket(i, now, true) + Expect(err).ToNot(HaveOccurred()) + } + err := handler.ReceivedPacket(p+10, now, true) // we now know that packets p+7, p+8 and p+9 + Expect(err).ToNot(HaveOccurred()) + Expect(rttStats.MinRTT()).To(Equal(rtt)) + Expect(handler.ackAlarm.Sub(now)).To(Equal(rtt / 8)) + ack := handler.GetAckFrame() + Expect(ack.HasMissingRanges()).To(BeTrue()) + Expect(ack).ToNot(BeNil()) + }) + }) + + Context("ACK generation", func() { + BeforeEach(func() { + handler.ackQueued = true + }) + + It("generates a simple ACK frame", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(2, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(2))) + Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(ack.HasMissingRanges()).To(BeFalse()) + }) + + It("generates an ACK for packet number 0", func() { + err := handler.ReceivedPacket(0, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(0))) + Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(0))) + Expect(ack.HasMissingRanges()).To(BeFalse()) + }) + + It("sets the delay time", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(2, time.Now().Add(-1337*time.Millisecond), true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.DelayTime).To(BeNumerically("~", 1337*time.Millisecond, 50*time.Millisecond)) + }) + + It("saves the last sent ACK", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(handler.lastAck).To(Equal(ack)) + err = handler.ReceivedPacket(2, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + handler.ackQueued = true + ack = handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(handler.lastAck).To(Equal(ack)) + }) + + It("generates an ACK frame with missing packets", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(4, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(4))) + Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(ack.AckRanges).To(Equal([]wire.AckRange{ + {Smallest: 4, Largest: 4}, + {Smallest: 1, Largest: 1}, + })) + }) + + It("generates an ACK for packet number 0 and other packets", func() { + err := handler.ReceivedPacket(0, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(3, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(3))) + Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(0))) + Expect(ack.AckRanges).To(Equal([]wire.AckRange{ + {Smallest: 3, Largest: 3}, + {Smallest: 0, Largest: 1}, + })) + }) + + It("accepts packets below the lower limit", func() { + handler.IgnoreBelow(6) + err := handler.ReceivedPacket(2, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't add delayed packets to the packetHistory", func() { + handler.IgnoreBelow(7) + err := handler.ReceivedPacket(4, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + err = handler.ReceivedPacket(10, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(10))) + Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(10))) + }) + + It("deletes packets from the packetHistory when a lower limit is set", func() { + for i := 1; i <= 12; i++ { + err := handler.ReceivedPacket(protocol.PacketNumber(i), time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + } + handler.IgnoreBelow(7) + // check that the packets were deleted from the receivedPacketHistory by checking the values in an ACK frame + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(12))) + Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(7))) + Expect(ack.HasMissingRanges()).To(BeFalse()) + }) + + // TODO: remove this test when dropping support for STOP_WAITINGs + It("handles a lower limit of 0", func() { + handler.IgnoreBelow(0) + err := handler.ReceivedPacket(1337, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + ack := handler.GetAckFrame() + Expect(ack).ToNot(BeNil()) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(1337))) + }) + + It("resets all counters needed for the ACK queueing decision when sending an ACK", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + handler.ackAlarm = time.Now().Add(-time.Minute) + Expect(handler.GetAckFrame()).ToNot(BeNil()) + Expect(handler.packetsReceivedSinceLastAck).To(BeZero()) + Expect(handler.GetAlarmTimeout()).To(BeZero()) + Expect(handler.retransmittablePacketsReceivedSinceLastAck).To(BeZero()) + Expect(handler.ackQueued).To(BeFalse()) + }) + + It("doesn't generate an ACK when none is queued and the timer is not set", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + handler.ackQueued = false + handler.ackAlarm = time.Time{} + Expect(handler.GetAckFrame()).To(BeNil()) + }) + + It("doesn't generate an ACK when none is queued and the timer has not yet expired", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + handler.ackQueued = false + handler.ackAlarm = time.Now().Add(time.Minute) + Expect(handler.GetAckFrame()).To(BeNil()) + }) + + It("generates an ACK when the timer has expired", func() { + err := handler.ReceivedPacket(1, time.Time{}, true) + Expect(err).ToNot(HaveOccurred()) + handler.ackQueued = false + handler.ackAlarm = time.Now().Add(-time.Minute) + Expect(handler.GetAckFrame()).ToNot(BeNil()) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go new file mode 100644 index 00000000..758286df --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go @@ -0,0 +1,121 @@ +package ackhandler + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +// The receivedPacketHistory stores if a packet number has already been received. +// It does not store packet contents. +type receivedPacketHistory struct { + ranges *utils.PacketIntervalList + + lowestInReceivedPacketNumbers protocol.PacketNumber +} + +var errTooManyOutstandingReceivedAckRanges = qerr.Error(qerr.TooManyOutstandingReceivedPackets, "Too many outstanding received ACK ranges") + +// newReceivedPacketHistory creates a new received packet history +func newReceivedPacketHistory() *receivedPacketHistory { + return &receivedPacketHistory{ + ranges: utils.NewPacketIntervalList(), + } +} + +// ReceivedPacket registers a packet with PacketNumber p and updates the ranges +func (h *receivedPacketHistory) ReceivedPacket(p protocol.PacketNumber) error { + if h.ranges.Len() >= protocol.MaxTrackedReceivedAckRanges { + return errTooManyOutstandingReceivedAckRanges + } + + if h.ranges.Len() == 0 { + h.ranges.PushBack(utils.PacketInterval{Start: p, End: p}) + return nil + } + + for el := h.ranges.Back(); el != nil; el = el.Prev() { + // p already included in an existing range. Nothing to do here + if p >= el.Value.Start && p <= el.Value.End { + return nil + } + + var rangeExtended bool + if el.Value.End == p-1 { // extend a range at the end + rangeExtended = true + el.Value.End = p + } else if el.Value.Start == p+1 { // extend a range at the beginning + rangeExtended = true + el.Value.Start = p + } + + // if a range was extended (either at the beginning or at the end, maybe it is possible to merge two ranges into one) + if rangeExtended { + prev := el.Prev() + if prev != nil && prev.Value.End+1 == el.Value.Start { // merge two ranges + prev.Value.End = el.Value.End + h.ranges.Remove(el) + return nil + } + return nil // if the two ranges were not merge, we're done here + } + + // create a new range at the end + if p > el.Value.End { + h.ranges.InsertAfter(utils.PacketInterval{Start: p, End: p}, el) + return nil + } + } + + // create a new range at the beginning + h.ranges.InsertBefore(utils.PacketInterval{Start: p, End: p}, h.ranges.Front()) + + return nil +} + +// DeleteBelow deletes all entries below (but not including) p +func (h *receivedPacketHistory) DeleteBelow(p protocol.PacketNumber) { + if p <= h.lowestInReceivedPacketNumbers { + return + } + h.lowestInReceivedPacketNumbers = p + + nextEl := h.ranges.Front() + for el := h.ranges.Front(); nextEl != nil; el = nextEl { + nextEl = el.Next() + + if p > el.Value.Start && p <= el.Value.End { + el.Value.Start = p + } else if el.Value.End < p { // delete a whole range + h.ranges.Remove(el) + } else { // no ranges affected. Nothing to do + return + } + } +} + +// GetAckRanges gets a slice of all AckRanges that can be used in an AckFrame +func (h *receivedPacketHistory) GetAckRanges() []wire.AckRange { + if h.ranges.Len() == 0 { + return nil + } + + ackRanges := make([]wire.AckRange, h.ranges.Len()) + i := 0 + for el := h.ranges.Back(); el != nil; el = el.Prev() { + ackRanges[i] = wire.AckRange{Smallest: el.Value.Start, Largest: el.Value.End} + i++ + } + return ackRanges +} + +func (h *receivedPacketHistory) GetHighestAckRange() wire.AckRange { + ackRange := wire.AckRange{} + if h.ranges.Len() > 0 { + r := h.ranges.Back().Value + ackRange.Smallest = r.Start + ackRange.Largest = r.End + } + return ackRange +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history_test.go new file mode 100644 index 00000000..4a24b95c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/received_packet_history_test.go @@ -0,0 +1,248 @@ +package ackhandler + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("receivedPacketHistory", func() { + var ( + hist *receivedPacketHistory + ) + + BeforeEach(func() { + hist = newReceivedPacketHistory() + }) + + Context("ranges", func() { + It("adds the first packet", func() { + hist.ReceivedPacket(4) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + }) + + It("doesn't care about duplicate packets", func() { + hist.ReceivedPacket(4) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + }) + + It("adds a few consecutive packets", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(6) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 6})) + }) + + It("doesn't care about a duplicate packet contained in an existing range", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(6) + hist.ReceivedPacket(5) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 6})) + }) + + It("extends a range at the front", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(3) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 3, End: 4})) + }) + + It("creates a new range when a packet is lost", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(6) + Expect(hist.ranges.Len()).To(Equal(2)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 6, End: 6})) + }) + + It("creates a new range in between two ranges", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(10) + Expect(hist.ranges.Len()).To(Equal(2)) + hist.ReceivedPacket(7) + Expect(hist.ranges.Len()).To(Equal(3)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + Expect(hist.ranges.Front().Next().Value).To(Equal(utils.PacketInterval{Start: 7, End: 7})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + + It("creates a new range before an existing range for a belated packet", func() { + hist.ReceivedPacket(6) + hist.ReceivedPacket(4) + Expect(hist.ranges.Len()).To(Equal(2)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 6, End: 6})) + }) + + It("extends a previous range at the end", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(7) + hist.ReceivedPacket(5) + Expect(hist.ranges.Len()).To(Equal(2)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 5})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 7, End: 7})) + }) + + It("extends a range at the front", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(7) + hist.ReceivedPacket(6) + Expect(hist.ranges.Len()).To(Equal(2)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 6, End: 7})) + }) + + It("closes a range", func() { + hist.ReceivedPacket(6) + hist.ReceivedPacket(4) + Expect(hist.ranges.Len()).To(Equal(2)) + hist.ReceivedPacket(5) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 6})) + }) + + It("closes a range in the middle", func() { + hist.ReceivedPacket(1) + hist.ReceivedPacket(10) + hist.ReceivedPacket(4) + hist.ReceivedPacket(6) + Expect(hist.ranges.Len()).To(Equal(4)) + hist.ReceivedPacket(5) + Expect(hist.ranges.Len()).To(Equal(3)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 1, End: 1})) + Expect(hist.ranges.Front().Next().Value).To(Equal(utils.PacketInterval{Start: 4, End: 6})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + }) + + Context("deleting", func() { + It("does nothing when the history is empty", func() { + hist.DeleteBelow(5) + Expect(hist.ranges.Len()).To(BeZero()) + }) + + It("deletes a range", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(10) + hist.DeleteBelow(6) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + + It("deletes multiple ranges", func() { + hist.ReceivedPacket(1) + hist.ReceivedPacket(5) + hist.ReceivedPacket(10) + hist.DeleteBelow(8) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + + It("adjusts a range, if packets are delete from an existing range", func() { + hist.ReceivedPacket(3) + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(6) + hist.ReceivedPacket(7) + hist.DeleteBelow(5) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 5, End: 7})) + }) + + It("adjusts a range, if only one packet remains in the range", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(10) + hist.DeleteBelow(5) + Expect(hist.ranges.Len()).To(Equal(2)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 5, End: 5})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + + It("keeps a one-packet range, if deleting up to the packet directly below", func() { + hist.ReceivedPacket(4) + hist.DeleteBelow(4) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + }) + + Context("DoS protection", func() { + It("doesn't create more than MaxTrackedReceivedAckRanges ranges", func() { + for i := protocol.PacketNumber(1); i <= protocol.MaxTrackedReceivedAckRanges; i++ { + err := hist.ReceivedPacket(2 * i) + Expect(err).ToNot(HaveOccurred()) + } + err := hist.ReceivedPacket(2*protocol.MaxTrackedReceivedAckRanges + 2) + Expect(err).To(MatchError(errTooManyOutstandingReceivedAckRanges)) + }) + + It("doesn't consider already deleted ranges for MaxTrackedReceivedAckRanges", func() { + for i := protocol.PacketNumber(1); i <= protocol.MaxTrackedReceivedAckRanges; i++ { + err := hist.ReceivedPacket(2 * i) + Expect(err).ToNot(HaveOccurred()) + } + err := hist.ReceivedPacket(2*protocol.MaxTrackedReceivedAckRanges + 2) + Expect(err).To(MatchError(errTooManyOutstandingReceivedAckRanges)) + hist.DeleteBelow(protocol.MaxTrackedReceivedAckRanges) // deletes about half of the ranges + err = hist.ReceivedPacket(2*protocol.MaxTrackedReceivedAckRanges + 4) + Expect(err).ToNot(HaveOccurred()) + }) + }) + }) + + Context("ACK range export", func() { + It("returns nil if there are no ranges", func() { + Expect(hist.GetAckRanges()).To(BeNil()) + }) + + It("gets a single ACK range", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + ackRanges := hist.GetAckRanges() + Expect(ackRanges).To(HaveLen(1)) + Expect(ackRanges[0]).To(Equal(wire.AckRange{Smallest: 4, Largest: 5})) + }) + + It("gets multiple ACK ranges", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(6) + hist.ReceivedPacket(1) + hist.ReceivedPacket(11) + hist.ReceivedPacket(10) + hist.ReceivedPacket(2) + ackRanges := hist.GetAckRanges() + Expect(ackRanges).To(HaveLen(3)) + Expect(ackRanges[0]).To(Equal(wire.AckRange{Smallest: 10, Largest: 11})) + Expect(ackRanges[1]).To(Equal(wire.AckRange{Smallest: 4, Largest: 6})) + Expect(ackRanges[2]).To(Equal(wire.AckRange{Smallest: 1, Largest: 2})) + }) + }) + + Context("Getting the highest ACK range", func() { + It("returns the zero value if there are no ranges", func() { + Expect(hist.GetHighestAckRange()).To(BeZero()) + }) + + It("gets a single ACK range", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + Expect(hist.GetHighestAckRange()).To(Equal(wire.AckRange{Smallest: 4, Largest: 5})) + }) + + It("gets the highest of multiple ACK ranges", func() { + hist.ReceivedPacket(3) + hist.ReceivedPacket(6) + hist.ReceivedPacket(7) + Expect(hist.GetHighestAckRange()).To(Equal(wire.AckRange{Smallest: 6, Largest: 7})) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable.go new file mode 100644 index 00000000..e6ce46f8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable.go @@ -0,0 +1,36 @@ +package ackhandler + +import "github.com/lucas-clemente/quic-go/internal/wire" + +// Returns a new slice with all non-retransmittable frames deleted. +func stripNonRetransmittableFrames(fs []wire.Frame) []wire.Frame { + res := make([]wire.Frame, 0, len(fs)) + for _, f := range fs { + if IsFrameRetransmittable(f) { + res = append(res, f) + } + } + return res +} + +// IsFrameRetransmittable returns true if the frame should be retransmitted. +func IsFrameRetransmittable(f wire.Frame) bool { + switch f.(type) { + case *wire.StopWaitingFrame: + return false + case *wire.AckFrame: + return false + default: + return true + } +} + +// HasRetransmittableFrames returns true if at least one frame is retransmittable. +func HasRetransmittableFrames(fs []wire.Frame) bool { + for _, f := range fs { + if IsFrameRetransmittable(f) { + return true + } + } + return false +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable_test.go new file mode 100644 index 00000000..63d0a589 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/retransmittable_test.go @@ -0,0 +1,45 @@ +package ackhandler + +import ( + "reflect" + + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("retransmittable frames", func() { + for fl, el := range map[wire.Frame]bool{ + &wire.AckFrame{}: false, + &wire.StopWaitingFrame{}: false, + &wire.BlockedFrame{}: true, + &wire.ConnectionCloseFrame{}: true, + &wire.GoawayFrame{}: true, + &wire.PingFrame{}: true, + &wire.RstStreamFrame{}: true, + &wire.StreamFrame{}: true, + &wire.MaxDataFrame{}: true, + &wire.MaxStreamDataFrame{}: true, + } { + f := fl + e := el + fName := reflect.ValueOf(f).Elem().Type().Name() + + It("works for "+fName, func() { + Expect(IsFrameRetransmittable(f)).To(Equal(e)) + }) + + It("stripping non-retransmittable frames works for "+fName, func() { + s := []wire.Frame{f} + if e { + Expect(stripNonRetransmittableFrames(s)).To(Equal([]wire.Frame{f})) + } else { + Expect(stripNonRetransmittableFrames(s)).To(BeEmpty()) + } + }) + + It("HasRetransmittableFrames works for "+fName, func() { + Expect(HasRetransmittableFrames([]wire.Frame{f})).To(Equal(e)) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode.go new file mode 100644 index 00000000..76c833c4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode.go @@ -0,0 +1,40 @@ +package ackhandler + +import "fmt" + +// The SendMode says what kind of packets can be sent. +type SendMode uint8 + +const ( + // SendNone means that no packets should be sent + SendNone SendMode = iota + // SendAck means an ACK-only packet should be sent + SendAck + // SendRetransmission means that retransmissions should be sent + SendRetransmission + // SendRTO means that an RTO probe packet should be sent + SendRTO + // SendTLP means that a TLP probe packet should be sent + SendTLP + // SendAny means that any packet should be sent + SendAny +) + +func (s SendMode) String() string { + switch s { + case SendNone: + return "none" + case SendAck: + return "ack" + case SendRetransmission: + return "retransmission" + case SendRTO: + return "rto" + case SendTLP: + return "tlp" + case SendAny: + return "any" + default: + return fmt.Sprintf("invalid send mode: %d", s) + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode_test.go new file mode 100644 index 00000000..c267d38c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/send_mode_test.go @@ -0,0 +1,18 @@ +package ackhandler + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Send Mode", func() { + It("has a string representation", func() { + Expect(SendNone.String()).To(Equal("none")) + Expect(SendAny.String()).To(Equal("any")) + Expect(SendAck.String()).To(Equal("ack")) + Expect(SendRTO.String()).To(Equal("rto")) + Expect(SendTLP.String()).To(Equal("tlp")) + Expect(SendRetransmission.String()).To(Equal("retransmission")) + Expect(SendMode(123).String()).To(Equal("invalid send mode: 123")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go new file mode 100644 index 00000000..4fdb8c36 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go @@ -0,0 +1,658 @@ +package ackhandler + +import ( + "errors" + "fmt" + "math" + "time" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +const ( + // Maximum reordering in time space before time based loss detection considers a packet lost. + // In fraction of an RTT. + timeReorderingFraction = 1.0 / 8 + // defaultRTOTimeout is the RTO time on new connections + defaultRTOTimeout = 500 * time.Millisecond + // Minimum time in the future a tail loss probe alarm may be set for. + minTPLTimeout = 10 * time.Millisecond + // Maximum number of tail loss probes before an RTO fires. + maxTLPs = 2 + // Minimum time in the future an RTO alarm may be set for. + minRTOTimeout = 200 * time.Millisecond + // maxRTOTimeout is the maximum RTO time + maxRTOTimeout = 60 * time.Second +) + +type sentPacketHandler struct { + lastSentPacketNumber protocol.PacketNumber + lastSentRetransmittablePacketTime time.Time + lastSentHandshakePacketTime time.Time + + nextPacketSendTime time.Time + skippedPackets []protocol.PacketNumber + + largestAcked protocol.PacketNumber + largestReceivedPacketWithAck protocol.PacketNumber + // lowestPacketNotConfirmedAcked is the lowest packet number that we sent an ACK for, but haven't received confirmation, that this ACK actually arrived + // example: we send an ACK for packets 90-100 with packet number 20 + // once we receive an ACK from the peer for packet 20, the lowestPacketNotConfirmedAcked is 101 + lowestPacketNotConfirmedAcked protocol.PacketNumber + largestSentBeforeRTO protocol.PacketNumber + + packetHistory *sentPacketHistory + stopWaitingManager stopWaitingManager + + retransmissionQueue []*Packet + + bytesInFlight protocol.ByteCount + + congestion congestion.SendAlgorithm + rttStats *congestion.RTTStats + + handshakeComplete bool + // The number of times the handshake packets have been retransmitted without receiving an ack. + handshakeCount uint32 + + // The number of times a TLP has been sent without receiving an ack. + tlpCount uint32 + allowTLP bool + + // The number of times an RTO has been sent without receiving an ack. + rtoCount uint32 + // The number of RTO probe packets that should be sent. + numRTOs int + + // The time at which the next packet will be considered lost based on early transmit or exceeding the reordering window in time. + lossTime time.Time + + // The alarm timeout + alarm time.Time + + logger utils.Logger + + version protocol.VersionNumber +} + +// NewSentPacketHandler creates a new sentPacketHandler +func NewSentPacketHandler(rttStats *congestion.RTTStats, logger utils.Logger, version protocol.VersionNumber) SentPacketHandler { + congestion := congestion.NewCubicSender( + congestion.DefaultClock{}, + rttStats, + false, /* don't use reno since chromium doesn't (why?) */ + protocol.InitialCongestionWindow, + protocol.DefaultMaxCongestionWindow, + ) + + return &sentPacketHandler{ + packetHistory: newSentPacketHistory(), + stopWaitingManager: stopWaitingManager{}, + rttStats: rttStats, + congestion: congestion, + logger: logger, + version: version, + } +} + +func (h *sentPacketHandler) lowestUnacked() protocol.PacketNumber { + if p := h.packetHistory.FirstOutstanding(); p != nil { + return p.PacketNumber + } + return h.largestAcked + 1 +} + +func (h *sentPacketHandler) SetHandshakeComplete() { + h.logger.Debugf("Handshake complete. Discarding all outstanding handshake packets.") + var queue []*Packet + for _, packet := range h.retransmissionQueue { + if packet.EncryptionLevel == protocol.EncryptionForwardSecure { + queue = append(queue, packet) + } + } + var handshakePackets []*Packet + h.packetHistory.Iterate(func(p *Packet) (bool, error) { + if p.EncryptionLevel != protocol.EncryptionForwardSecure { + handshakePackets = append(handshakePackets, p) + } + return true, nil + }) + for _, p := range handshakePackets { + h.packetHistory.Remove(p.PacketNumber) + } + h.retransmissionQueue = queue + h.handshakeComplete = true +} + +func (h *sentPacketHandler) SentPacket(packet *Packet) { + if isRetransmittable := h.sentPacketImpl(packet); isRetransmittable { + h.packetHistory.SentPacket(packet) + h.updateLossDetectionAlarm() + } +} + +func (h *sentPacketHandler) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) { + var p []*Packet + for _, packet := range packets { + if isRetransmittable := h.sentPacketImpl(packet); isRetransmittable { + p = append(p, packet) + } + } + h.packetHistory.SentPacketsAsRetransmission(p, retransmissionOf) + h.updateLossDetectionAlarm() +} + +func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* isRetransmittable */ { + for p := h.lastSentPacketNumber + 1; p < packet.PacketNumber; p++ { + h.skippedPackets = append(h.skippedPackets, p) + if len(h.skippedPackets) > protocol.MaxTrackedSkippedPackets { + h.skippedPackets = h.skippedPackets[1:] + } + } + + h.lastSentPacketNumber = packet.PacketNumber + + if len(packet.Frames) > 0 { + if ackFrame, ok := packet.Frames[0].(*wire.AckFrame); ok { + packet.largestAcked = ackFrame.LargestAcked() + } + } + + packet.Frames = stripNonRetransmittableFrames(packet.Frames) + isRetransmittable := len(packet.Frames) != 0 + + if isRetransmittable { + if packet.EncryptionLevel < protocol.EncryptionForwardSecure { + h.lastSentHandshakePacketTime = packet.SendTime + } + h.lastSentRetransmittablePacketTime = packet.SendTime + packet.includedInBytesInFlight = true + h.bytesInFlight += packet.Length + packet.canBeRetransmitted = true + if h.numRTOs > 0 { + h.numRTOs-- + } + h.allowTLP = false + } + h.congestion.OnPacketSent(packet.SendTime, h.bytesInFlight, packet.PacketNumber, packet.Length, isRetransmittable) + + h.nextPacketSendTime = utils.MaxTime(h.nextPacketSendTime, packet.SendTime).Add(h.congestion.TimeUntilSend(h.bytesInFlight)) + return isRetransmittable +} + +func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, rcvTime time.Time) error { + largestAcked := ackFrame.LargestAcked() + if largestAcked > h.lastSentPacketNumber { + return qerr.Error(qerr.InvalidAckData, "Received ACK for an unsent package") + } + + // duplicate or out of order ACK + if withPacketNumber != 0 && withPacketNumber <= h.largestReceivedPacketWithAck { + h.logger.Debugf("Ignoring ACK frame (duplicate or out of order).") + return nil + } + h.largestReceivedPacketWithAck = withPacketNumber + h.largestAcked = utils.MaxPacketNumber(h.largestAcked, largestAcked) + + if h.skippedPacketsAcked(ackFrame) { + return qerr.Error(qerr.InvalidAckData, "Received an ACK for a skipped packet number") + } + + if rttUpdated := h.maybeUpdateRTT(largestAcked, ackFrame.DelayTime, rcvTime); rttUpdated { + h.congestion.MaybeExitSlowStart() + } + + ackedPackets, err := h.determineNewlyAckedPackets(ackFrame) + if err != nil { + return err + } + + priorInFlight := h.bytesInFlight + for _, p := range ackedPackets { + if encLevel < p.EncryptionLevel { + return fmt.Errorf("Received ACK with encryption level %s that acks a packet %d (encryption level %s)", encLevel, p.PacketNumber, p.EncryptionLevel) + } + // largestAcked == 0 either means that the packet didn't contain an ACK, or it just acked packet 0 + // It is safe to ignore the corner case of packets that just acked packet 0, because + // the lowestPacketNotConfirmedAcked is only used to limit the number of ACK ranges we will send. + if p.largestAcked != 0 { + h.lowestPacketNotConfirmedAcked = utils.MaxPacketNumber(h.lowestPacketNotConfirmedAcked, p.largestAcked+1) + } + if err := h.onPacketAcked(p, rcvTime); err != nil { + return err + } + if p.includedInBytesInFlight { + h.congestion.OnPacketAcked(p.PacketNumber, p.Length, priorInFlight, rcvTime) + } + } + + if err := h.detectLostPackets(rcvTime, priorInFlight); err != nil { + return err + } + h.updateLossDetectionAlarm() + + h.garbageCollectSkippedPackets() + h.stopWaitingManager.ReceivedAck(ackFrame) + + return nil +} + +func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNumber { + return h.lowestPacketNotConfirmedAcked +} + +func (h *sentPacketHandler) determineNewlyAckedPackets(ackFrame *wire.AckFrame) ([]*Packet, error) { + var ackedPackets []*Packet + ackRangeIndex := 0 + lowestAcked := ackFrame.LowestAcked() + largestAcked := ackFrame.LargestAcked() + err := h.packetHistory.Iterate(func(p *Packet) (bool, error) { + // Ignore packets below the lowest acked + if p.PacketNumber < lowestAcked { + return true, nil + } + // Break after largest acked is reached + if p.PacketNumber > largestAcked { + return false, nil + } + + if ackFrame.HasMissingRanges() { + ackRange := ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex] + + for p.PacketNumber > ackRange.Largest && ackRangeIndex < len(ackFrame.AckRanges)-1 { + ackRangeIndex++ + ackRange = ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex] + } + + if p.PacketNumber >= ackRange.Smallest { // packet i contained in ACK range + if p.PacketNumber > ackRange.Largest { + return false, fmt.Errorf("BUG: ackhandler would have acked wrong packet 0x%x, while evaluating range 0x%x -> 0x%x", p.PacketNumber, ackRange.Smallest, ackRange.Largest) + } + ackedPackets = append(ackedPackets, p) + } + } else { + ackedPackets = append(ackedPackets, p) + } + return true, nil + }) + if h.logger.Debug() && len(ackedPackets) > 0 { + pns := make([]protocol.PacketNumber, len(ackedPackets)) + for i, p := range ackedPackets { + pns[i] = p.PacketNumber + } + h.logger.Debugf("\tnewly acked packets (%d): %#x", len(pns), pns) + } + return ackedPackets, err +} + +func (h *sentPacketHandler) maybeUpdateRTT(largestAcked protocol.PacketNumber, ackDelay time.Duration, rcvTime time.Time) bool { + if p := h.packetHistory.GetPacket(largestAcked); p != nil { + h.rttStats.UpdateRTT(rcvTime.Sub(p.SendTime), ackDelay, rcvTime) + if h.logger.Debug() { + h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation()) + } + return true + } + return false +} + +func (h *sentPacketHandler) updateLossDetectionAlarm() { + // Cancel the alarm if no packets are outstanding + if !h.packetHistory.HasOutstandingPackets() { + h.alarm = time.Time{} + return + } + + if h.packetHistory.HasOutstandingHandshakePackets() { + h.alarm = h.lastSentHandshakePacketTime.Add(h.computeHandshakeTimeout()) + } else if !h.lossTime.IsZero() { + // Early retransmit timer or time loss detection. + h.alarm = h.lossTime + } else { + // RTO or TLP alarm + alarmDuration := h.computeRTOTimeout() + if h.tlpCount < maxTLPs { + tlpAlarm := h.computeTLPTimeout() + // if the RTO duration is shorter than the TLP duration, use the RTO duration + alarmDuration = utils.MinDuration(alarmDuration, tlpAlarm) + } + h.alarm = h.lastSentRetransmittablePacketTime.Add(alarmDuration) + } +} + +func (h *sentPacketHandler) detectLostPackets(now time.Time, priorInFlight protocol.ByteCount) error { + h.lossTime = time.Time{} + + maxRTT := float64(utils.MaxDuration(h.rttStats.LatestRTT(), h.rttStats.SmoothedRTT())) + delayUntilLost := time.Duration((1.0 + timeReorderingFraction) * maxRTT) + + var lostPackets []*Packet + h.packetHistory.Iterate(func(packet *Packet) (bool, error) { + if packet.PacketNumber > h.largestAcked { + return false, nil + } + + timeSinceSent := now.Sub(packet.SendTime) + if timeSinceSent > delayUntilLost { + lostPackets = append(lostPackets, packet) + } else if h.lossTime.IsZero() { + if h.logger.Debug() { + h.logger.Debugf("\tsetting loss timer for packet %#x to %s (in %s)", packet.PacketNumber, delayUntilLost, delayUntilLost-timeSinceSent) + } + // Note: This conditional is only entered once per call + h.lossTime = now.Add(delayUntilLost - timeSinceSent) + } + return true, nil + }) + if h.logger.Debug() && len(lostPackets) > 0 { + pns := make([]protocol.PacketNumber, len(lostPackets)) + for i, p := range lostPackets { + pns[i] = p.PacketNumber + } + h.logger.Debugf("\tlost packets (%d): %#x", len(pns), pns) + } + + for _, p := range lostPackets { + // the bytes in flight need to be reduced no matter if this packet will be retransmitted + if p.includedInBytesInFlight { + h.bytesInFlight -= p.Length + h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight) + } + if p.canBeRetransmitted { + // queue the packet for retransmission, and report the loss to the congestion controller + if err := h.queuePacketForRetransmission(p); err != nil { + return err + } + } + h.packetHistory.Remove(p.PacketNumber) + } + return nil +} + +func (h *sentPacketHandler) OnAlarm() error { + // When all outstanding are acknowledged, the alarm is canceled in + // updateLossDetectionAlarm. This doesn't reset the timer in the session though. + // When OnAlarm is called, we therefore need to make sure that there are + // actually packets outstanding. + if h.packetHistory.HasOutstandingPackets() { + if err := h.onVerifiedAlarm(); err != nil { + return err + } + } + h.updateLossDetectionAlarm() + return nil +} + +func (h *sentPacketHandler) onVerifiedAlarm() error { + var err error + if h.packetHistory.HasOutstandingHandshakePackets() { + if h.logger.Debug() { + h.logger.Debugf("Loss detection alarm fired in handshake mode. Handshake count: %d", h.handshakeCount) + } + h.handshakeCount++ + err = h.queueHandshakePacketsForRetransmission() + } else if !h.lossTime.IsZero() { + if h.logger.Debug() { + h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", h.lossTime) + } + // Early retransmit or time loss detection + err = h.detectLostPackets(time.Now(), h.bytesInFlight) + } else if h.tlpCount < maxTLPs { // TLP + if h.logger.Debug() { + h.logger.Debugf("Loss detection alarm fired in TLP mode. TLP count: %d", h.tlpCount) + } + h.allowTLP = true + h.tlpCount++ + } else { // RTO + if h.logger.Debug() { + h.logger.Debugf("Loss detection alarm fired in RTO mode. RTO count: %d", h.rtoCount) + } + if h.rtoCount == 0 { + h.largestSentBeforeRTO = h.lastSentPacketNumber + } + h.rtoCount++ + h.numRTOs += 2 + } + return err +} + +func (h *sentPacketHandler) GetAlarmTimeout() time.Time { + return h.alarm +} + +func (h *sentPacketHandler) onPacketAcked(p *Packet, rcvTime time.Time) error { + // This happens if a packet and its retransmissions is acked in the same ACK. + // As soon as we process the first one, this will remove all the retransmissions, + // so we won't find the retransmitted packet number later. + if packet := h.packetHistory.GetPacket(p.PacketNumber); packet == nil { + return nil + } + + // only report the acking of this packet to the congestion controller if: + // * it is a retransmittable packet + // * this packet wasn't retransmitted yet + if p.isRetransmission { + // that the parent doesn't exist is expected to happen every time the original packet was already acked + if parent := h.packetHistory.GetPacket(p.retransmissionOf); parent != nil { + if len(parent.retransmittedAs) == 1 { + parent.retransmittedAs = nil + } else { + // remove this packet from the slice of retransmission + retransmittedAs := make([]protocol.PacketNumber, 0, len(parent.retransmittedAs)-1) + for _, pn := range parent.retransmittedAs { + if pn != p.PacketNumber { + retransmittedAs = append(retransmittedAs, pn) + } + } + parent.retransmittedAs = retransmittedAs + } + } + } + // this also applies to packets that have been retransmitted as probe packets + if p.includedInBytesInFlight { + h.bytesInFlight -= p.Length + } + if h.rtoCount > 0 { + h.verifyRTO(p.PacketNumber) + } + if err := h.stopRetransmissionsFor(p); err != nil { + return err + } + h.rtoCount = 0 + h.tlpCount = 0 + h.handshakeCount = 0 + return h.packetHistory.Remove(p.PacketNumber) +} + +func (h *sentPacketHandler) stopRetransmissionsFor(p *Packet) error { + if err := h.packetHistory.MarkCannotBeRetransmitted(p.PacketNumber); err != nil { + return err + } + for _, r := range p.retransmittedAs { + packet := h.packetHistory.GetPacket(r) + if packet == nil { + return fmt.Errorf("sent packet handler BUG: marking packet as not retransmittable %d (retransmission of %d) not found in history", r, p.PacketNumber) + } + h.stopRetransmissionsFor(packet) + } + return nil +} + +func (h *sentPacketHandler) verifyRTO(pn protocol.PacketNumber) { + if pn <= h.largestSentBeforeRTO { + h.logger.Debugf("Spurious RTO detected. Received an ACK for %#x (largest sent before RTO: %#x)", pn, h.largestSentBeforeRTO) + // Replace SRTT with latest_rtt and increase the variance to prevent + // a spurious RTO from happening again. + h.rttStats.ExpireSmoothedMetrics() + return + } + h.logger.Debugf("RTO verified. Received an ACK for %#x (largest sent before RTO: %#x", pn, h.largestSentBeforeRTO) + h.congestion.OnRetransmissionTimeout(true) +} + +func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet { + if len(h.retransmissionQueue) == 0 { + return nil + } + packet := h.retransmissionQueue[0] + // Shift the slice and don't retain anything that isn't needed. + copy(h.retransmissionQueue, h.retransmissionQueue[1:]) + h.retransmissionQueue[len(h.retransmissionQueue)-1] = nil + h.retransmissionQueue = h.retransmissionQueue[:len(h.retransmissionQueue)-1] + return packet +} + +func (h *sentPacketHandler) DequeueProbePacket() (*Packet, error) { + if len(h.retransmissionQueue) == 0 { + p := h.packetHistory.FirstOutstanding() + if p == nil { + return nil, errors.New("cannot dequeue a probe packet. No outstanding packets") + } + if err := h.queuePacketForRetransmission(p); err != nil { + return nil, err + } + } + return h.DequeuePacketForRetransmission(), nil +} + +func (h *sentPacketHandler) GetPacketNumberLen(p protocol.PacketNumber) protocol.PacketNumberLen { + return protocol.GetPacketNumberLengthForHeader(p, h.lowestUnacked(), h.version) +} + +func (h *sentPacketHandler) GetStopWaitingFrame(force bool) *wire.StopWaitingFrame { + return h.stopWaitingManager.GetStopWaitingFrame(force) +} + +func (h *sentPacketHandler) SendMode() SendMode { + numTrackedPackets := len(h.retransmissionQueue) + h.packetHistory.Len() + + // Don't send any packets if we're keeping track of the maximum number of packets. + // Note that since MaxOutstandingSentPackets is smaller than MaxTrackedSentPackets, + // we will stop sending out new data when reaching MaxOutstandingSentPackets, + // but still allow sending of retransmissions and ACKs. + if numTrackedPackets >= protocol.MaxTrackedSentPackets { + if h.logger.Debug() { + h.logger.Debugf("Limited by the number of tracked packets: tracking %d packets, maximum %d", numTrackedPackets, protocol.MaxTrackedSentPackets) + } + return SendNone + } + if h.allowTLP { + return SendTLP + } + if h.numRTOs > 0 { + return SendRTO + } + // Only send ACKs if we're congestion limited. + if cwnd := h.congestion.GetCongestionWindow(); h.bytesInFlight > cwnd { + if h.logger.Debug() { + h.logger.Debugf("Congestion limited: bytes in flight %d, window %d", h.bytesInFlight, cwnd) + } + return SendAck + } + // Send retransmissions first, if there are any. + if len(h.retransmissionQueue) > 0 { + return SendRetransmission + } + if numTrackedPackets >= protocol.MaxOutstandingSentPackets { + if h.logger.Debug() { + h.logger.Debugf("Max outstanding limited: tracking %d packets, maximum: %d", numTrackedPackets, protocol.MaxOutstandingSentPackets) + } + return SendAck + } + return SendAny +} + +func (h *sentPacketHandler) TimeUntilSend() time.Time { + return h.nextPacketSendTime +} + +func (h *sentPacketHandler) ShouldSendNumPackets() int { + if h.numRTOs > 0 { + // RTO probes should not be paced, but must be sent immediately. + return h.numRTOs + } + delay := h.congestion.TimeUntilSend(h.bytesInFlight) + if delay == 0 || delay > protocol.MinPacingDelay { + return 1 + } + return int(math.Ceil(float64(protocol.MinPacingDelay) / float64(delay))) +} + +func (h *sentPacketHandler) queueHandshakePacketsForRetransmission() error { + var handshakePackets []*Packet + h.packetHistory.Iterate(func(p *Packet) (bool, error) { + if p.canBeRetransmitted && p.EncryptionLevel < protocol.EncryptionForwardSecure { + handshakePackets = append(handshakePackets, p) + } + return true, nil + }) + for _, p := range handshakePackets { + h.logger.Debugf("Queueing packet %#x as a handshake retransmission", p.PacketNumber) + if err := h.queuePacketForRetransmission(p); err != nil { + return err + } + } + return nil +} + +func (h *sentPacketHandler) queuePacketForRetransmission(p *Packet) error { + if !p.canBeRetransmitted { + return fmt.Errorf("sent packet handler BUG: packet %d already queued for retransmission", p.PacketNumber) + } + if err := h.packetHistory.MarkCannotBeRetransmitted(p.PacketNumber); err != nil { + return err + } + h.retransmissionQueue = append(h.retransmissionQueue, p) + h.stopWaitingManager.QueuedRetransmissionForPacketNumber(p.PacketNumber) + return nil +} + +func (h *sentPacketHandler) computeHandshakeTimeout() time.Duration { + duration := utils.MaxDuration(2*h.rttStats.SmoothedOrInitialRTT(), minTPLTimeout) + // exponential backoff + // There's an implicit limit to this set by the handshake timeout. + return duration << h.handshakeCount +} + +func (h *sentPacketHandler) computeTLPTimeout() time.Duration { + // TODO(#1236): include the max_ack_delay + return utils.MaxDuration(h.rttStats.SmoothedOrInitialRTT()*3/2, minTPLTimeout) +} + +func (h *sentPacketHandler) computeRTOTimeout() time.Duration { + var rto time.Duration + rtt := h.rttStats.SmoothedRTT() + if rtt == 0 { + rto = defaultRTOTimeout + } else { + rto = rtt + 4*h.rttStats.MeanDeviation() + } + rto = utils.MaxDuration(rto, minRTOTimeout) + // Exponential backoff + rto = rto << h.rtoCount + return utils.MinDuration(rto, maxRTOTimeout) +} + +func (h *sentPacketHandler) skippedPacketsAcked(ackFrame *wire.AckFrame) bool { + for _, p := range h.skippedPackets { + if ackFrame.AcksPacket(p) { + return true + } + } + return false +} + +func (h *sentPacketHandler) garbageCollectSkippedPackets() { + lowestUnacked := h.lowestUnacked() + deleteIndex := 0 + for i, p := range h.skippedPackets { + if p < lowestUnacked { + deleteIndex = i + 1 + } + } + h.skippedPackets = h.skippedPackets[deleteIndex:] +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler_test.go new file mode 100644 index 00000000..9960e537 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler_test.go @@ -0,0 +1,1080 @@ +package ackhandler + +import ( + "time" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/mocks" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func retransmittablePacket(p *Packet) *Packet { + if p.EncryptionLevel == protocol.EncryptionUnspecified { + p.EncryptionLevel = protocol.EncryptionForwardSecure + } + if p.Length == 0 { + p.Length = 1 + } + if p.SendTime.IsZero() { + p.SendTime = time.Now() + } + p.Frames = []wire.Frame{&wire.PingFrame{}} + return p +} + +func nonRetransmittablePacket(p *Packet) *Packet { + p = retransmittablePacket(p) + p.Frames = []wire.Frame{ + &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}, + } + return p +} + +func handshakePacket(p *Packet) *Packet { + p = retransmittablePacket(p) + p.EncryptionLevel = protocol.EncryptionUnencrypted + return p +} + +var _ = Describe("SentPacketHandler", func() { + var ( + handler *sentPacketHandler + streamFrame wire.StreamFrame + ) + + BeforeEach(func() { + rttStats := &congestion.RTTStats{} + handler = NewSentPacketHandler(rttStats, utils.DefaultLogger, protocol.VersionWhatever).(*sentPacketHandler) + handler.SetHandshakeComplete() + streamFrame = wire.StreamFrame{ + StreamID: 5, + Data: []byte{0x13, 0x37}, + } + }) + + getPacket := func(pn protocol.PacketNumber) *Packet { + if el, ok := handler.packetHistory.packetMap[pn]; ok { + return &el.Value + } + return nil + } + + losePacket := func(pn protocol.PacketNumber) { + p := getPacket(pn) + ExpectWithOffset(1, p).ToNot(BeNil()) + handler.queuePacketForRetransmission(p) + if p.includedInBytesInFlight { + p.includedInBytesInFlight = false + handler.bytesInFlight -= p.Length + } + r := handler.DequeuePacketForRetransmission() + ExpectWithOffset(1, r).ToNot(BeNil()) + ExpectWithOffset(1, r.PacketNumber).To(Equal(pn)) + } + + expectInPacketHistory := func(expected []protocol.PacketNumber) { + ExpectWithOffset(1, handler.packetHistory.Len()).To(Equal(len(expected))) + for _, p := range expected { + ExpectWithOffset(1, handler.packetHistory.packetMap).To(HaveKey(p)) + } + } + + updateRTT := func(rtt time.Duration) { + handler.rttStats.UpdateRTT(rtt, 0, time.Now()) + ExpectWithOffset(1, handler.rttStats.SmoothedRTT()).To(Equal(rtt)) + } + + It("determines the packet number length", func() { + handler.largestAcked = 0x1337 + Expect(handler.GetPacketNumberLen(0x1338)).To(Equal(protocol.PacketNumberLen2)) + Expect(handler.GetPacketNumberLen(0xfffffff)).To(Equal(protocol.PacketNumberLen4)) + }) + + Context("registering sent packets", func() { + It("accepts two consecutive packets", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2})) + Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(2))) + expectInPacketHistory([]protocol.PacketNumber{1, 2}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) + Expect(handler.skippedPackets).To(BeEmpty()) + }) + + It("accepts packet number 0", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 0})) + Expect(handler.lastSentPacketNumber).To(BeZero()) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(1))) + expectInPacketHistory([]protocol.PacketNumber{0, 1}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) + Expect(handler.skippedPackets).To(BeEmpty()) + }) + + It("stores the sent time", func() { + sendTime := time.Now().Add(-time.Minute) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: sendTime})) + Expect(handler.lastSentRetransmittablePacketTime).To(Equal(sendTime)) + }) + + It("stores the sent time of handshake packets", func() { + sendTime := time.Now().Add(-time.Minute) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: sendTime, EncryptionLevel: protocol.EncryptionUnencrypted})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: sendTime.Add(time.Hour), EncryptionLevel: protocol.EncryptionForwardSecure})) + Expect(handler.lastSentHandshakePacketTime).To(Equal(sendTime)) + }) + + It("does not store non-retransmittable packets", func() { + handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 1})) + Expect(handler.packetHistory.Len()).To(BeZero()) + Expect(handler.lastSentRetransmittablePacketTime).To(BeZero()) + Expect(handler.bytesInFlight).To(BeZero()) + }) + + Context("skipped packet numbers", func() { + It("works with non-consecutive packet numbers", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(3))) + expectInPacketHistory([]protocol.PacketNumber{1, 3}) + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2})) + }) + + It("works with non-retransmittable packets", func() { + handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 3})) + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2})) + }) + + It("recognizes multiple skipped packets", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5})) + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 4})) + }) + + It("recognizes multiple consecutive skipped packets", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4})) + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 3})) + }) + + It("limits the lengths of the skipped packet slice", func() { + for i := protocol.PacketNumber(0); i < protocol.MaxTrackedSkippedPackets+5; i++ { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2*i + 1})) + } + Expect(handler.skippedPackets).To(HaveLen(protocol.MaxUndecryptablePackets)) + Expect(handler.skippedPackets[0]).To(Equal(protocol.PacketNumber(10))) + Expect(handler.skippedPackets[protocol.MaxTrackedSkippedPackets-1]).To(Equal(protocol.PacketNumber(10 + 2*(protocol.MaxTrackedSkippedPackets-1)))) + }) + + Context("garbage collection", func() { + It("keeps all packet numbers above the LargestAcked", func() { + handler.skippedPackets = []protocol.PacketNumber{2, 5, 8, 10} + handler.largestAcked = 1 + handler.garbageCollectSkippedPackets() + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 5, 8, 10})) + }) + + It("doesn't keep packet numbers below the LargestAcked", func() { + handler.skippedPackets = []protocol.PacketNumber{1, 5, 8, 10} + handler.largestAcked = 5 + handler.garbageCollectSkippedPackets() + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{8, 10})) + }) + + It("deletes all packet numbers if LargestAcked is sufficiently high", func() { + handler.skippedPackets = []protocol.PacketNumber{1, 5, 10} + handler.largestAcked = 15 + handler.garbageCollectSkippedPackets() + Expect(handler.skippedPackets).To(BeEmpty()) + }) + }) + + Context("ACK handling", func() { + BeforeEach(func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 10})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 12})) + }) + + It("rejects ACKs for skipped packets", func() { + ack := &wire.AckFrame{ + AckRanges: []wire.AckRange{{Smallest: 10, Largest: 12}}, + } + err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).To(MatchError("InvalidAckData: Received an ACK for a skipped packet number")) + }) + + It("accepts an ACK that correctly nacks a skipped packet", func() { + ack := &wire.AckFrame{ + AckRanges: []wire.AckRange{ + {Smallest: 12, Largest: 12}, + {Smallest: 10, Largest: 10}, + }, + } + err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).ToNot(BeZero()) + }) + }) + }) + }) + + Context("ACK processing", func() { + BeforeEach(func() { + for i := protocol.PacketNumber(0); i < 10; i++ { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: i})) + } + // Increase RTT, because the tests would be flaky otherwise + updateRTT(time.Hour) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10))) + }) + + Context("ACK validation", func() { + It("accepts ACKs sent in packet 0", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 5}}} + err := handler.ReceivedAck(ack, 0, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(5))) + }) + + It("rejects duplicate ACKs", func() { + ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 3}}} + ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 4}}} + err := handler.ReceivedAck(ack1, 1337, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3))) + // this wouldn't happen in practice + // for testing purposes, we pretend send a different ACK frame in a duplicated packet, to be able to verify that it actually doesn't get processed + err = handler.ReceivedAck(ack2, 1337, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3))) + }) + + It("rejects out of order ACKs", func() { + // acks packets 0, 1, 2, 3 + ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 3}}} + ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 4}}} + err := handler.ReceivedAck(ack1, 1337, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + // this wouldn't happen in practive + // a receiver wouldn't send an ACK for a lower largest acked in a packet sent later + err = handler.ReceivedAck(ack2, 1337-1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3))) + }) + + It("rejects ACKs with a too high LargestAcked packet number", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 9999}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).To(MatchError("InvalidAckData: Received ACK for an unsent package")) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10))) + }) + + It("ignores repeated ACKs", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 3}}} + err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(7))) + err = handler.ReceivedAck(ack, 1337+1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3))) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(7))) + }) + }) + + Context("acks and nacks the right packets", func() { + It("adjusts the LargestAcked, and adjusts the bytes in flight", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 5}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(5))) + expectInPacketHistory([]protocol.PacketNumber{6, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4))) + }) + + It("acks packet 0", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 0}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(getPacket(0)).To(BeNil()) + expectInPacketHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 6, 7, 8, 9}) + }) + + It("handles an ACK frame with one missing packet range", func() { + ack := &wire.AckFrame{ // lose 4 and 5 + AckRanges: []wire.AckRange{ + {Smallest: 6, Largest: 9}, + {Smallest: 1, Largest: 3}, + }, + } + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{0, 4, 5}) + }) + + It("does not ack packets below the LowestAcked", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 3, Largest: 8}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{0, 1, 2, 9}) + }) + + It("handles an ACK with multiple missing packet ranges", func() { + ack := &wire.AckFrame{ // packets 2, 4 and 5, and 8 were lost + AckRanges: []wire.AckRange{ + {Smallest: 9, Largest: 9}, + {Smallest: 6, Largest: 7}, + {Smallest: 3, Largest: 3}, + {Smallest: 1, Largest: 1}, + }, + } + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{0, 2, 4, 5, 8}) + }) + + It("processes an ACK frame that would be sent after a late arrival of a packet", func() { + ack1 := &wire.AckFrame{ // 3 lost + AckRanges: []wire.AckRange{ + {Smallest: 4, Largest: 6}, + {Smallest: 1, Largest: 2}, + }, + } + err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{0, 3, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(5))) + ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 6}}} // now ack 3 + err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{0, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4))) + }) + + It("processes an ACK frame that would be sent after a late arrival of a packet and another packet", func() { + ack1 := &wire.AckFrame{ + AckRanges: []wire.AckRange{ + {Smallest: 4, Largest: 6}, + {Smallest: 0, Largest: 2}, + }, + } + err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{3, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4))) + ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 7}}} + err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) + expectInPacketHistory([]protocol.PacketNumber{8, 9}) + }) + + It("processes an ACK that contains old ACK ranges", func() { + ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 6}}} + err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{0, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4))) + ack2 := &wire.AckFrame{ + AckRanges: []wire.AckRange{ + {Smallest: 8, Largest: 8}, + {Smallest: 3, Largest: 3}, + {Smallest: 1, Largest: 1}, + }, + } + err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{0, 7, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(3))) + }) + }) + + Context("calculating RTT", func() { + It("computes the RTT", func() { + now := time.Now() + // First, fake the sent times of the first, second and last packet + getPacket(1).SendTime = now.Add(-10 * time.Minute) + getPacket(2).SendTime = now.Add(-5 * time.Minute) + getPacket(6).SendTime = now.Add(-1 * time.Minute) + // Now, check that the proper times are used when calculating the deltas + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 10*time.Minute, 1*time.Second)) + ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 2}}} + err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second)) + ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 6}}} + err = handler.ReceivedAck(ack, 3, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 1*time.Minute, 1*time.Second)) + }) + + It("uses the DelayTime in the ACK frame", func() { + now := time.Now() + // make sure the rttStats have a min RTT, so that the delay is used + handler.rttStats.UpdateRTT(5*time.Minute, 0, time.Now()) + getPacket(1).SendTime = now.Add(-10 * time.Minute) + ack := &wire.AckFrame{ + AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}, + DelayTime: 5 * time.Minute, + } + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second)) + }) + }) + + Context("determining which ACKs we have received an ACK for", func() { + BeforeEach(func() { + ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 80, Largest: 100}}} + ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 50, Largest: 200}}} + morePackets := []*Packet{ + {PacketNumber: 13, Frames: []wire.Frame{ack1, &streamFrame}, Length: 1}, + {PacketNumber: 14, Frames: []wire.Frame{ack2, &streamFrame}, Length: 1}, + {PacketNumber: 15, Frames: []wire.Frame{&streamFrame}, Length: 1}, + } + for _, packet := range morePackets { + handler.SentPacket(packet) + } + }) + + It("determines which ACK we have received an ACK for", func() { + err := handler.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 15}}}, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201))) + }) + + It("doesn't do anything when the acked packet didn't contain an ACK", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(101))) + ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 15, Largest: 15}}} + err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(101))) + }) + + It("doesn't decrease the value", func() { + err := handler.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 14, Largest: 14}}}, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201))) + err = handler.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}}, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201))) + }) + }) + }) + + Context("ACK processing, for retransmitted packets", func() { + It("sends a packet as retransmission", func() { + // packet 5 was retransmitted as packet 6 + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, Length: 10})) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10))) + losePacket(5) + Expect(handler.bytesInFlight).To(BeZero()) + handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 6, Length: 11})}, 5) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11))) + }) + + It("removes a packet when it is acked", func() { + // packet 5 was retransmitted as packet 6 + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, Length: 10})) + losePacket(5) + handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 6, Length: 11})}, 5) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11))) + // ack 5 + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{6}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11))) + }) + + It("handles ACKs that ack the original packet as well as the retransmission", func() { + // packet 5 was retransmitted as packet 7 + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, Length: 10})) + losePacket(5) + handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 7, Length: 11})}, 5) + // ack 5 and 7 + ack := &wire.AckFrame{ + AckRanges: []wire.AckRange{ + {Smallest: 7, Largest: 7}, + {Smallest: 5, Largest: 5}, + }, + } + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.packetHistory.Len()).To(BeZero()) + Expect(handler.bytesInFlight).To(BeZero()) + }) + }) + + Context("Retransmission handling", func() { + It("does not dequeue a packet if no ack has been received", func() { + handler.SentPacket(&Packet{PacketNumber: 1}) + Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) + }) + + Context("STOP_WAITINGs", func() { + It("gets a STOP_WAITING frame", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 3, Largest: 3}}} + err := handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 4})) + }) + + It("gets a STOP_WAITING frame after queueing a retransmission", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5})) + handler.queuePacketForRetransmission(getPacket(5)) + Expect(handler.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 6})) + }) + }) + }) + + Context("congestion", func() { + var cong *mocks.MockSendAlgorithm + + BeforeEach(func() { + cong = mocks.NewMockSendAlgorithm(mockCtrl) + handler.congestion = cong + }) + + It("should call OnSent", func() { + cong.EXPECT().OnPacketSent( + gomock.Any(), + protocol.ByteCount(42), + protocol.PacketNumber(1), + protocol.ByteCount(42), + true, + ) + cong.EXPECT().TimeUntilSend(gomock.Any()) + p := &Packet{ + PacketNumber: 1, + Length: 42, + Frames: []wire.Frame{&wire.PingFrame{}}, + } + handler.SentPacket(p) + }) + + It("should call MaybeExitSlowStart and OnPacketAcked", func() { + rcvTime := time.Now().Add(-5 * time.Second) + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(3) + cong.EXPECT().TimeUntilSend(gomock.Any()).Times(3) + gomock.InOrder( + cong.EXPECT().MaybeExitSlowStart(), // must be called before packets are acked + cong.EXPECT().OnPacketAcked(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(3), rcvTime), + cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(3), rcvTime), + ) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 2}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, rcvTime) + Expect(err).NotTo(HaveOccurred()) + }) + + It("doesn't call OnPacketLost and OnRetransmissionTimeout when queuing RTOs", func() { + for i := protocol.PacketNumber(1); i < 3; i++ { + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) + cong.EXPECT().TimeUntilSend(gomock.Any()) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: i})) + } + handler.OnAlarm() // TLP + handler.OnAlarm() // TLP + handler.OnAlarm() // RTO + }) + + It("declares all lower packets lost and call OnRetransmissionTimeout when verifying an RTO", func() { + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(5) + cong.EXPECT().TimeUntilSend(gomock.Any()).Times(5) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4, SendTime: time.Now().Add(-time.Hour)})) + handler.OnAlarm() // TLP + handler.OnAlarm() // TLP + handler.OnAlarm() // RTO + // send one probe packet and receive an ACK for it + rcvTime := time.Now() + gomock.InOrder( + cong.EXPECT().MaybeExitSlowStart(), + cong.EXPECT().OnRetransmissionTimeout(true), + cong.EXPECT().OnPacketAcked(protocol.PacketNumber(5), protocol.ByteCount(1), protocol.ByteCount(5), rcvTime), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(5)), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(5)), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(3), protocol.ByteCount(1), protocol.ByteCount(5)), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(4), protocol.ByteCount(1), protocol.ByteCount(5)), + ) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5})) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, rcvTime) + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't call OnRetransmissionTimeout when a spurious RTO occurs", func() { + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(3) + cong.EXPECT().TimeUntilSend(gomock.Any()).Times(3) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now()})) + handler.OnAlarm() // TLP + handler.OnAlarm() // TLP + handler.OnAlarm() // RTO + + // send one probe packet + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + // receive an ACK for a packet send *before* the probe packet + // don't EXPECT any call to OnRetransmissionTimeout + gomock.InOrder( + cong.EXPECT().MaybeExitSlowStart(), + cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(3), gomock.Any()), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(3)), + ) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't call OnPacketAcked when a retransmitted packet is acked", func() { + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2) + cong.EXPECT().TimeUntilSend(gomock.Any()).Times(2) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2})) + // lose packet 1 + gomock.InOrder( + cong.EXPECT().MaybeExitSlowStart(), + cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(2), gomock.Any()), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(2)), + ) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + // don't EXPECT any further calls to the congestion controller + ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 2}}} + err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("calls OnPacketAcked and OnPacketLost with the right bytes_in_flight value", func() { + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(4) + cong.EXPECT().TimeUntilSend(gomock.Any()).Times(4) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-30 * time.Minute)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: time.Now().Add(-30 * time.Minute)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4, SendTime: time.Now()})) + // receive the first ACK + gomock.InOrder( + cong.EXPECT().MaybeExitSlowStart(), + cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(4), gomock.Any()), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(4)), + ) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now().Add(-30*time.Minute)) + Expect(err).ToNot(HaveOccurred()) + // receive the second ACK + gomock.InOrder( + cong.EXPECT().MaybeExitSlowStart(), + cong.EXPECT().OnPacketAcked(protocol.PacketNumber(4), protocol.ByteCount(1), protocol.ByteCount(2), gomock.Any()), + cong.EXPECT().OnPacketLost(protocol.PacketNumber(3), protocol.ByteCount(1), protocol.ByteCount(2)), + ) + ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 4, Largest: 4}}} + err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("only allows sending of ACKs when congestion limited", func() { + handler.bytesInFlight = 100 + cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(200)) + Expect(handler.SendMode()).To(Equal(SendAny)) + cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(75)) + Expect(handler.SendMode()).To(Equal(SendAck)) + }) + + It("only allows sending of ACKs when we're keeping track of MaxOutstandingSentPackets packets", func() { + cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount).AnyTimes() + cong.EXPECT().TimeUntilSend(gomock.Any()).AnyTimes() + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + for i := protocol.PacketNumber(1); i < protocol.MaxOutstandingSentPackets; i++ { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: i})) + Expect(handler.SendMode()).To(Equal(SendAny)) + } + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: protocol.MaxOutstandingSentPackets})) + Expect(handler.SendMode()).To(Equal(SendAck)) + }) + + It("doesn't allow retransmission if congestion limited", func() { + handler.bytesInFlight = 100 + handler.retransmissionQueue = []*Packet{{PacketNumber: 3}} + cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(50)) + Expect(handler.SendMode()).To(Equal(SendAck)) + }) + + It("allows sending retransmissions", func() { + cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount) + handler.retransmissionQueue = []*Packet{{PacketNumber: 3}} + Expect(handler.SendMode()).To(Equal(SendRetransmission)) + }) + + It("allow retransmissions, if we're keeping track of between MaxOutstandingSentPackets and MaxTrackedSentPackets packets", func() { + cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount) + Expect(protocol.MaxOutstandingSentPackets).To(BeNumerically("<", protocol.MaxTrackedSentPackets)) + handler.retransmissionQueue = make([]*Packet, protocol.MaxOutstandingSentPackets+10) + Expect(handler.SendMode()).To(Equal(SendRetransmission)) + handler.retransmissionQueue = make([]*Packet, protocol.MaxTrackedSentPackets) + Expect(handler.SendMode()).To(Equal(SendNone)) + }) + + It("allows RTOs, even when congestion limited", func() { + // note that we don't EXPECT a call to GetCongestionWindow + // that means retransmissions are sent without considering the congestion window + handler.numRTOs = 1 + handler.retransmissionQueue = []*Packet{{PacketNumber: 3}} + Expect(handler.SendMode()).To(Equal(SendRTO)) + }) + + It("gets the pacing delay", func() { + sendTime := time.Now().Add(-time.Minute) + handler.bytesInFlight = 100 + cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) + cong.EXPECT().TimeUntilSend(protocol.ByteCount(100)).Return(time.Hour) + handler.SentPacket(&Packet{PacketNumber: 1, SendTime: sendTime}) + Expect(handler.TimeUntilSend()).To(Equal(sendTime.Add(time.Hour))) + }) + + It("allows sending of all RTO probe packets", func() { + handler.numRTOs = 5 + Expect(handler.ShouldSendNumPackets()).To(Equal(5)) + }) + + It("allows sending of one packet, if it should be sent immediately", func() { + cong.EXPECT().TimeUntilSend(gomock.Any()).Return(time.Duration(0)) + Expect(handler.ShouldSendNumPackets()).To(Equal(1)) + }) + + It("allows sending of multiple packets, if the pacing delay is smaller than the minimum", func() { + pacingDelay := protocol.MinPacingDelay / 10 + cong.EXPECT().TimeUntilSend(gomock.Any()).Return(pacingDelay) + Expect(handler.ShouldSendNumPackets()).To(Equal(10)) + }) + + It("allows sending of multiple packets, if the pacing delay is smaller than the minimum, and not a fraction", func() { + pacingDelay := protocol.MinPacingDelay * 2 / 5 + cong.EXPECT().TimeUntilSend(gomock.Any()).Return(pacingDelay) + Expect(handler.ShouldSendNumPackets()).To(Equal(3)) + }) + }) + + It("doesn't set an alarm if there are no outstanding packets", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 10})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 11})) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 10, Largest: 11}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.GetAlarmTimeout()).To(BeZero()) + }) + + It("does nothing on OnAlarm if there are no outstanding packets", func() { + Expect(handler.OnAlarm()).To(Succeed()) + Expect(handler.SendMode()).To(Equal(SendAny)) + }) + + Context("TLPs", func() { + It("uses the RTT from RTT stats", func() { + rtt := 2 * time.Second + updateRTT(rtt) + Expect(handler.computeTLPTimeout()).To(Equal(rtt * 3 / 2)) + }) + + It("uses the minTLPTimeout for short RTTs", func() { + rtt := 2 * time.Microsecond + updateRTT(rtt) + Expect(handler.computeTLPTimeout()).To(Equal(minTPLTimeout)) + }) + + It("sets the TLP send mode until one retransmittable packet is sent", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.OnAlarm() + Expect(handler.SendMode()).To(Equal(SendTLP)) + // Send a non-retransmittable packet. + // It doesn't count as a probe packet. + handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 2})) + Expect(handler.SendMode()).To(Equal(SendTLP)) + // Send a retransmittable packet. + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + Expect(handler.SendMode()).ToNot(Equal(SendTLP)) + }) + + It("sends two TLPs, then RTOs", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)})) + // first TLP + handler.OnAlarm() + Expect(handler.SendMode()).To(Equal(SendTLP)) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + // second TLP + handler.OnAlarm() + Expect(handler.SendMode()).To(Equal(SendTLP)) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4})) + // fire alarm a third time + handler.OnAlarm() + Expect(handler.SendMode()).To(Equal(SendRTO)) + }) + }) + + Context("RTOs", func() { + It("uses default RTO", func() { + Expect(handler.computeRTOTimeout()).To(Equal(defaultRTOTimeout)) + }) + + It("uses RTO from rttStats", func() { + rtt := time.Second + handler.rttStats.UpdateRTT(rtt, 0, time.Now()) + Expect(handler.rttStats.SmoothedRTT()).To(Equal(rtt)) + Expect(handler.rttStats.MeanDeviation()).To(Equal(rtt / 2)) + expected := rtt + rtt/2*4 + Expect(handler.computeRTOTimeout()).To(Equal(expected)) + }) + + It("limits RTO min", func() { + rtt := 3 * time.Millisecond + updateRTT(rtt) + Expect(handler.computeRTOTimeout()).To(Equal(minRTOTimeout)) + }) + + It("limits RTO max", func() { + updateRTT(time.Hour) + Expect(handler.computeRTOTimeout()).To(Equal(maxRTOTimeout)) + }) + + It("implements exponential backoff", func() { + handler.rtoCount = 0 + Expect(handler.computeRTOTimeout()).To(Equal(defaultRTOTimeout)) + handler.rtoCount = 1 + Expect(handler.computeRTOTimeout()).To(Equal(2 * defaultRTOTimeout)) + handler.rtoCount = 2 + Expect(handler.computeRTOTimeout()).To(Equal(4 * defaultRTOTimeout)) + }) + + It("gets two probe packets if RTO expires", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2})) + + updateRTT(time.Hour) + Expect(handler.lossTime.IsZero()).To(BeTrue()) + Expect(time.Until(handler.GetAlarmTimeout())).To(BeNumerically("~", handler.computeRTOTimeout(), time.Minute)) + + handler.OnAlarm() // TLP + handler.OnAlarm() // TLP + handler.OnAlarm() // RTO + p, err := handler.DequeueProbePacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).ToNot(BeNil()) + Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(1))) + p, err = handler.DequeueProbePacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).ToNot(BeNil()) + Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(2))) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) + + Expect(handler.rtoCount).To(BeEquivalentTo(1)) + }) + + It("doesn't delete packets transmitted as RTO from the history", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)})) + handler.rttStats.UpdateRTT(time.Second, 0, time.Now()) + handler.OnAlarm() // TLP + handler.OnAlarm() // TLP + handler.OnAlarm() // RTO + _, err := handler.DequeueProbePacket() + Expect(err).ToNot(HaveOccurred()) + _, err = handler.DequeueProbePacket() + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{1, 2}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) + // Send a probe packet and receive an ACK for it. + // This verifies the RTO. + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 3, Largest: 3}}} + err = handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.packetHistory.Len()).To(BeZero()) + Expect(handler.bytesInFlight).To(BeZero()) + Expect(handler.retransmissionQueue).To(BeEmpty()) // 1 and 2 were already sent as probe packets + }) + + It("allows sending of two probe packets", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.OnAlarm() // TLP + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2})) // send the first TLP + handler.OnAlarm() // TLP + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) // send the second TLP + handler.OnAlarm() // RTO + Expect(handler.SendMode()).To(Equal(SendRTO)) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4})) + Expect(handler.SendMode()).To(Equal(SendRTO)) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5})) + Expect(handler.SendMode()).ToNot(Equal(SendRTO)) + }) + + It("gets packets sent before the probe packet for retransmission", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4, SendTime: time.Now().Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)})) + handler.OnAlarm() // TLP + handler.OnAlarm() // TLP + handler.OnAlarm() // RTO + _, err := handler.DequeueProbePacket() + Expect(err).ToNot(HaveOccurred()) + _, err = handler.DequeueProbePacket() + Expect(err).ToNot(HaveOccurred()) + expectInPacketHistory([]protocol.PacketNumber{1, 2, 3, 4, 5}) + // Send a probe packet and receive an ACK for it. + // This verifies the RTO. + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 6})) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 6, Largest: 6}}} + err = handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.packetHistory.Len()).To(BeZero()) + Expect(handler.bytesInFlight).To(BeZero()) + Expect(handler.retransmissionQueue).To(HaveLen(3)) // packets 3, 4, 5 + }) + + It("handles ACKs for the original packet", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)})) + handler.rttStats.UpdateRTT(time.Second, 0, time.Now()) + handler.OnAlarm() // TLP + handler.OnAlarm() // TLP + handler.OnAlarm() // RTO + handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 6})}, 5) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + err = handler.OnAlarm() + Expect(err).ToNot(HaveOccurred()) + }) + + It("handles ACKs for the original packet", func() { + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)})) + handler.rttStats.UpdateRTT(time.Second, 0, time.Now()) + err := handler.OnAlarm() + Expect(err).ToNot(HaveOccurred()) + err = handler.OnAlarm() + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("Delay-based loss detection", func() { + It("immediately detects old packets as lost when receiving an ACK", func() { + now := time.Now() + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: now.Add(-time.Hour)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: now.Add(-time.Second)})) + Expect(handler.lossTime.IsZero()).To(BeTrue()) + + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, now) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil()) + Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) + // no need to set an alarm, since packet 1 was already declared lost + Expect(handler.lossTime.IsZero()).To(BeTrue()) + Expect(handler.bytesInFlight).To(BeZero()) + }) + + It("sets the early retransmit alarm", func() { + now := time.Now() + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: now.Add(-2 * time.Second)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: now.Add(-2 * time.Second)})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: now.Add(-time.Second)})) + Expect(handler.lossTime.IsZero()).To(BeTrue()) + + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, now.Add(-time.Second)) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.rttStats.SmoothedRTT()).To(Equal(time.Second)) + + // Packet 1 should be considered lost (1+1/8) RTTs after it was sent. + Expect(handler.lossTime.IsZero()).To(BeFalse()) + Expect(handler.lossTime.Sub(getPacket(1).SendTime)).To(Equal(time.Second * 9 / 8)) + + err = handler.OnAlarm() + Expect(err).ToNot(HaveOccurred()) + Expect(handler.DequeuePacketForRetransmission()).NotTo(BeNil()) + // make sure this is not an RTO: only packet 1 is retransmissted + Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) + }) + }) + + Context("handshake packets", func() { + BeforeEach(func() { + handler.handshakeComplete = false + }) + + It("detects the handshake timeout", func() { + now := time.Now() + sendTime := now.Add(-time.Minute) + lastHandshakePacketSendTime := now.Add(-30 * time.Second) + // send handshake packets: 1, 3 + // send a forward-secure packet: 2 + handler.SentPacket(handshakePacket(&Packet{PacketNumber: 1, SendTime: sendTime})) + handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: sendTime})) + handler.SentPacket(handshakePacket(&Packet{PacketNumber: 3, SendTime: sendTime})) + + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, now) + // RTT is now 1 minute + Expect(handler.rttStats.SmoothedRTT()).To(Equal(time.Minute)) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.lossTime.IsZero()).To(BeTrue()) + Expect(handler.GetAlarmTimeout().Sub(sendTime)).To(Equal(2 * time.Minute)) + + err = handler.OnAlarm() + Expect(err).ToNot(HaveOccurred()) + p := handler.DequeuePacketForRetransmission() + Expect(p).ToNot(BeNil()) + Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(3))) + Expect(handler.handshakeCount).To(BeEquivalentTo(1)) + handler.SentPacket(handshakePacket(&Packet{PacketNumber: 4, SendTime: lastHandshakePacketSendTime})) + // make sure the exponential backoff is used + Expect(handler.GetAlarmTimeout().Sub(lastHandshakePacketSendTime)).To(Equal(4 * time.Minute)) + }) + + It("rejects an ACK that acks packets with a higher encryption level", func() { + handler.SentPacket(&Packet{ + PacketNumber: 13, + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: []wire.Frame{&streamFrame}, + Length: 1, + }) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}} + err := handler.ReceivedAck(ack, 1, protocol.EncryptionSecure, time.Now()) + Expect(err).To(MatchError("Received ACK with encryption level encrypted (not forward-secure) that acks a packet 13 (encryption level forward-secure)")) + }) + + It("deletes non forward-secure packets when the handshake completes", func() { + for i := protocol.PacketNumber(1); i <= 6; i++ { + p := retransmittablePacket(&Packet{PacketNumber: i}) + p.EncryptionLevel = protocol.EncryptionSecure + handler.SentPacket(p) + } + handler.queuePacketForRetransmission(getPacket(1)) + handler.queuePacketForRetransmission(getPacket(3)) + handler.SetHandshakeComplete() + Expect(handler.packetHistory.Len()).To(BeZero()) + packet := handler.DequeuePacketForRetransmission() + Expect(packet).To(BeNil()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go new file mode 100644 index 00000000..91aa2697 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go @@ -0,0 +1,168 @@ +package ackhandler + +import ( + "fmt" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +type sentPacketHistory struct { + packetList *PacketList + packetMap map[protocol.PacketNumber]*PacketElement + + numOutstandingPackets int + numOutstandingHandshakePackets int + + firstOutstanding *PacketElement +} + +func newSentPacketHistory() *sentPacketHistory { + return &sentPacketHistory{ + packetList: NewPacketList(), + packetMap: make(map[protocol.PacketNumber]*PacketElement), + } +} + +func (h *sentPacketHistory) SentPacket(p *Packet) { + h.sentPacketImpl(p) +} + +func (h *sentPacketHistory) sentPacketImpl(p *Packet) *PacketElement { + el := h.packetList.PushBack(*p) + h.packetMap[p.PacketNumber] = el + if h.firstOutstanding == nil { + h.firstOutstanding = el + } + if p.canBeRetransmitted { + h.numOutstandingPackets++ + if p.EncryptionLevel < protocol.EncryptionForwardSecure { + h.numOutstandingHandshakePackets++ + } + } + return el +} + +func (h *sentPacketHistory) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) { + retransmission, ok := h.packetMap[retransmissionOf] + // The retransmitted packet is not present anymore. + // This can happen if it was acked in between dequeueing of the retransmission and sending. + // Just treat the retransmissions as normal packets. + // TODO: This won't happen if we clear packets queued for retransmission on new ACKs. + if !ok { + for _, packet := range packets { + h.sentPacketImpl(packet) + } + return + } + retransmission.Value.retransmittedAs = make([]protocol.PacketNumber, len(packets)) + for i, packet := range packets { + retransmission.Value.retransmittedAs[i] = packet.PacketNumber + el := h.sentPacketImpl(packet) + el.Value.isRetransmission = true + el.Value.retransmissionOf = retransmissionOf + } +} + +func (h *sentPacketHistory) GetPacket(p protocol.PacketNumber) *Packet { + if el, ok := h.packetMap[p]; ok { + return &el.Value + } + return nil +} + +// Iterate iterates through all packets. +// The callback must not modify the history. +func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) error { + cont := true + for el := h.packetList.Front(); cont && el != nil; el = el.Next() { + var err error + cont, err = cb(&el.Value) + if err != nil { + return err + } + } + return nil +} + +// FirstOutStanding returns the first outstanding packet. +// It must not be modified (e.g. retransmitted). +// Use DequeueFirstPacketForRetransmission() to retransmit it. +func (h *sentPacketHistory) FirstOutstanding() *Packet { + if h.firstOutstanding == nil { + return nil + } + return &h.firstOutstanding.Value +} + +// QueuePacketForRetransmission marks a packet for retransmission. +// A packet can only be queued once. +func (h *sentPacketHistory) MarkCannotBeRetransmitted(pn protocol.PacketNumber) error { + el, ok := h.packetMap[pn] + if !ok { + return fmt.Errorf("sent packet history: packet %d not found", pn) + } + if el.Value.canBeRetransmitted { + h.numOutstandingPackets-- + if h.numOutstandingPackets < 0 { + panic("numOutstandingHandshakePackets negative") + } + if el.Value.EncryptionLevel < protocol.EncryptionForwardSecure { + h.numOutstandingHandshakePackets-- + if h.numOutstandingHandshakePackets < 0 { + panic("numOutstandingHandshakePackets negative") + } + } + } + el.Value.canBeRetransmitted = false + if el == h.firstOutstanding { + h.readjustFirstOutstanding() + } + return nil +} + +// readjustFirstOutstanding readjusts the pointer to the first outstanding packet. +// This is necessary every time the first outstanding packet is deleted or retransmitted. +func (h *sentPacketHistory) readjustFirstOutstanding() { + el := h.firstOutstanding.Next() + for el != nil && !el.Value.canBeRetransmitted { + el = el.Next() + } + h.firstOutstanding = el +} + +func (h *sentPacketHistory) Len() int { + return len(h.packetMap) +} + +func (h *sentPacketHistory) Remove(p protocol.PacketNumber) error { + el, ok := h.packetMap[p] + if !ok { + return fmt.Errorf("packet %d not found in sent packet history", p) + } + if el == h.firstOutstanding { + h.readjustFirstOutstanding() + } + if el.Value.canBeRetransmitted { + h.numOutstandingPackets-- + if h.numOutstandingPackets < 0 { + panic("numOutstandingHandshakePackets negative") + } + if el.Value.EncryptionLevel < protocol.EncryptionForwardSecure { + h.numOutstandingHandshakePackets-- + if h.numOutstandingHandshakePackets < 0 { + panic("numOutstandingHandshakePackets negative") + } + } + } + h.packetList.Remove(el) + delete(h.packetMap, p) + return nil +} + +func (h *sentPacketHistory) HasOutstandingPackets() bool { + return h.numOutstandingPackets > 0 +} + +func (h *sentPacketHistory) HasOutstandingHandshakePackets() bool { + return h.numOutstandingHandshakePackets > 0 +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history_test.go new file mode 100644 index 00000000..dc6ed5dd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history_test.go @@ -0,0 +1,297 @@ +package ackhandler + +import ( + "errors" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("SentPacketHistory", func() { + var hist *sentPacketHistory + + expectInHistory := func(packetNumbers []protocol.PacketNumber) { + ExpectWithOffset(1, hist.packetMap).To(HaveLen(len(packetNumbers))) + ExpectWithOffset(1, hist.packetList.Len()).To(Equal(len(packetNumbers))) + i := 0 + hist.Iterate(func(p *Packet) (bool, error) { + pn := packetNumbers[i] + ExpectWithOffset(1, p.PacketNumber).To(Equal(pn)) + ExpectWithOffset(1, hist.packetMap[pn].Value.PacketNumber).To(Equal(pn)) + i++ + return true, nil + }) + } + + BeforeEach(func() { + hist = newSentPacketHistory() + }) + + It("saves sent packets", func() { + hist.SentPacket(&Packet{PacketNumber: 1}) + hist.SentPacket(&Packet{PacketNumber: 3}) + hist.SentPacket(&Packet{PacketNumber: 4}) + expectInHistory([]protocol.PacketNumber{1, 3, 4}) + }) + + It("gets the length", func() { + hist.SentPacket(&Packet{PacketNumber: 1}) + hist.SentPacket(&Packet{PacketNumber: 10}) + Expect(hist.Len()).To(Equal(2)) + }) + + Context("getting the first outstanding packet", func() { + It("gets nil, if there are no packets", func() { + Expect(hist.FirstOutstanding()).To(BeNil()) + }) + + It("gets the first outstanding packet", func() { + hist.SentPacket(&Packet{PacketNumber: 2}) + hist.SentPacket(&Packet{PacketNumber: 3}) + front := hist.FirstOutstanding() + Expect(front).ToNot(BeNil()) + Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(2))) + }) + + It("gets the second packet if the first one is retransmitted", func() { + hist.SentPacket(&Packet{PacketNumber: 1, canBeRetransmitted: true}) + hist.SentPacket(&Packet{PacketNumber: 3, canBeRetransmitted: true}) + hist.SentPacket(&Packet{PacketNumber: 4, canBeRetransmitted: true}) + front := hist.FirstOutstanding() + Expect(front).ToNot(BeNil()) + Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(1))) + // Queue the first packet for retransmission. + // The first outstanding packet should now be 3. + err := hist.MarkCannotBeRetransmitted(1) + Expect(err).ToNot(HaveOccurred()) + front = hist.FirstOutstanding() + Expect(front).ToNot(BeNil()) + Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(3))) + }) + + It("gets the third packet if the first two are retransmitted", func() { + hist.SentPacket(&Packet{PacketNumber: 1, canBeRetransmitted: true}) + hist.SentPacket(&Packet{PacketNumber: 3, canBeRetransmitted: true}) + hist.SentPacket(&Packet{PacketNumber: 4, canBeRetransmitted: true}) + front := hist.FirstOutstanding() + Expect(front).ToNot(BeNil()) + Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(1))) + // Queue the second packet for retransmission. + // The first outstanding packet should still be 3. + err := hist.MarkCannotBeRetransmitted(3) + Expect(err).ToNot(HaveOccurred()) + front = hist.FirstOutstanding() + Expect(front).ToNot(BeNil()) + Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(1))) + // Queue the first packet for retransmission. + // The first outstanding packet should still be 4. + err = hist.MarkCannotBeRetransmitted(1) + Expect(err).ToNot(HaveOccurred()) + front = hist.FirstOutstanding() + Expect(front).ToNot(BeNil()) + Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(4))) + }) + }) + + It("gets a packet by packet number", func() { + p := &Packet{PacketNumber: 2} + hist.SentPacket(p) + Expect(hist.GetPacket(2)).To(Equal(p)) + }) + + It("returns nil if the packet doesn't exist", func() { + Expect(hist.GetPacket(1337)).To(BeNil()) + }) + + It("removes packets", func() { + hist.SentPacket(&Packet{PacketNumber: 1}) + hist.SentPacket(&Packet{PacketNumber: 4}) + hist.SentPacket(&Packet{PacketNumber: 8}) + err := hist.Remove(4) + Expect(err).ToNot(HaveOccurred()) + expectInHistory([]protocol.PacketNumber{1, 8}) + }) + + It("errors when trying to remove a non existing packet", func() { + hist.SentPacket(&Packet{PacketNumber: 1}) + err := hist.Remove(2) + Expect(err).To(MatchError("packet 2 not found in sent packet history")) + }) + + Context("iterating", func() { + BeforeEach(func() { + hist.SentPacket(&Packet{PacketNumber: 10}) + hist.SentPacket(&Packet{PacketNumber: 14}) + hist.SentPacket(&Packet{PacketNumber: 18}) + }) + + It("iterates over all packets", func() { + var iterations []protocol.PacketNumber + err := hist.Iterate(func(p *Packet) (bool, error) { + iterations = append(iterations, p.PacketNumber) + return true, nil + }) + Expect(err).ToNot(HaveOccurred()) + Expect(iterations).To(Equal([]protocol.PacketNumber{10, 14, 18})) + }) + + It("stops iterating", func() { + var iterations []protocol.PacketNumber + err := hist.Iterate(func(p *Packet) (bool, error) { + iterations = append(iterations, p.PacketNumber) + return p.PacketNumber != 14, nil + }) + Expect(err).ToNot(HaveOccurred()) + Expect(iterations).To(Equal([]protocol.PacketNumber{10, 14})) + }) + + It("returns the error", func() { + testErr := errors.New("test error") + var iterations []protocol.PacketNumber + err := hist.Iterate(func(p *Packet) (bool, error) { + iterations = append(iterations, p.PacketNumber) + if p.PacketNumber == 14 { + return false, testErr + } + return true, nil + }) + Expect(err).To(MatchError(testErr)) + Expect(iterations).To(Equal([]protocol.PacketNumber{10, 14})) + }) + }) + + Context("retransmissions", func() { + BeforeEach(func() { + for i := protocol.PacketNumber(1); i <= 5; i++ { + hist.SentPacket(&Packet{PacketNumber: i}) + } + }) + + It("errors if the packet doesn't exist", func() { + err := hist.MarkCannotBeRetransmitted(100) + Expect(err).To(MatchError("sent packet history: packet 100 not found")) + }) + + It("adds a sent packets as a retransmission", func() { + hist.SentPacketsAsRetransmission([]*Packet{{PacketNumber: 13}}, 2) + expectInHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 13}) + Expect(hist.GetPacket(13).isRetransmission).To(BeTrue()) + Expect(hist.GetPacket(13).retransmissionOf).To(Equal(protocol.PacketNumber(2))) + Expect(hist.GetPacket(2).retransmittedAs).To(Equal([]protocol.PacketNumber{13})) + }) + + It("adds multiple packets sent as a retransmission", func() { + hist.SentPacketsAsRetransmission([]*Packet{{PacketNumber: 13}, {PacketNumber: 15}}, 2) + expectInHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 13, 15}) + Expect(hist.GetPacket(13).isRetransmission).To(BeTrue()) + Expect(hist.GetPacket(13).retransmissionOf).To(Equal(protocol.PacketNumber(2))) + Expect(hist.GetPacket(15).retransmissionOf).To(Equal(protocol.PacketNumber(2))) + Expect(hist.GetPacket(2).retransmittedAs).To(Equal([]protocol.PacketNumber{13, 15})) + }) + + It("adds a packet as a normal packet if the retransmitted packet doesn't exist", func() { + hist.SentPacketsAsRetransmission([]*Packet{{PacketNumber: 13}}, 7) + expectInHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 13}) + Expect(hist.GetPacket(13).isRetransmission).To(BeFalse()) + Expect(hist.GetPacket(13).retransmissionOf).To(BeZero()) + }) + }) + + Context("outstanding packets", func() { + It("says if it has outstanding handshake packets", func() { + Expect(hist.HasOutstandingHandshakePackets()).To(BeFalse()) + hist.SentPacket(&Packet{ + EncryptionLevel: protocol.EncryptionUnencrypted, + canBeRetransmitted: true, + }) + Expect(hist.HasOutstandingHandshakePackets()).To(BeTrue()) + }) + + It("says if it has outstanding packets", func() { + Expect(hist.HasOutstandingHandshakePackets()).To(BeFalse()) + Expect(hist.HasOutstandingPackets()).To(BeFalse()) + hist.SentPacket(&Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + canBeRetransmitted: true, + }) + Expect(hist.HasOutstandingHandshakePackets()).To(BeFalse()) + Expect(hist.HasOutstandingPackets()).To(BeTrue()) + }) + + It("doesn't consider non-retransmittable packets as outstanding", func() { + hist.SentPacket(&Packet{ + EncryptionLevel: protocol.EncryptionUnencrypted, + }) + Expect(hist.HasOutstandingHandshakePackets()).To(BeFalse()) + Expect(hist.HasOutstandingPackets()).To(BeFalse()) + }) + + It("accounts for deleted handshake packets", func() { + hist.SentPacket(&Packet{ + PacketNumber: 5, + EncryptionLevel: protocol.EncryptionSecure, + canBeRetransmitted: true, + }) + Expect(hist.HasOutstandingHandshakePackets()).To(BeTrue()) + err := hist.Remove(5) + Expect(err).ToNot(HaveOccurred()) + Expect(hist.HasOutstandingHandshakePackets()).To(BeFalse()) + }) + + It("accounts for deleted packets", func() { + hist.SentPacket(&Packet{ + PacketNumber: 10, + EncryptionLevel: protocol.EncryptionForwardSecure, + canBeRetransmitted: true, + }) + Expect(hist.HasOutstandingPackets()).To(BeTrue()) + err := hist.Remove(10) + Expect(err).ToNot(HaveOccurred()) + Expect(hist.HasOutstandingPackets()).To(BeFalse()) + }) + + It("doesn't count handshake packets marked as non-retransmittable", func() { + hist.SentPacket(&Packet{ + PacketNumber: 5, + EncryptionLevel: protocol.EncryptionUnencrypted, + canBeRetransmitted: true, + }) + Expect(hist.HasOutstandingHandshakePackets()).To(BeTrue()) + err := hist.MarkCannotBeRetransmitted(5) + Expect(err).ToNot(HaveOccurred()) + Expect(hist.HasOutstandingHandshakePackets()).To(BeFalse()) + }) + + It("doesn't count packets marked as non-retransmittable", func() { + hist.SentPacket(&Packet{ + PacketNumber: 10, + EncryptionLevel: protocol.EncryptionForwardSecure, + canBeRetransmitted: true, + }) + Expect(hist.HasOutstandingPackets()).To(BeTrue()) + err := hist.MarkCannotBeRetransmitted(10) + Expect(err).ToNot(HaveOccurred()) + Expect(hist.HasOutstandingPackets()).To(BeFalse()) + }) + + It("counts the number of packets", func() { + hist.SentPacket(&Packet{ + PacketNumber: 10, + EncryptionLevel: protocol.EncryptionForwardSecure, + canBeRetransmitted: true, + }) + hist.SentPacket(&Packet{ + PacketNumber: 11, + EncryptionLevel: protocol.EncryptionForwardSecure, + canBeRetransmitted: true, + }) + err := hist.Remove(11) + Expect(err).ToNot(HaveOccurred()) + Expect(hist.HasOutstandingPackets()).To(BeTrue()) + err = hist.Remove(10) + Expect(err).ToNot(HaveOccurred()) + Expect(hist.HasOutstandingPackets()).To(BeFalse()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager.go new file mode 100644 index 00000000..40ad88cd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager.go @@ -0,0 +1,43 @@ +package ackhandler + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +// This stopWaitingManager is not supposed to satisfy the StopWaitingManager interface, which is a remnant of the legacy AckHandler, and should be remove once we drop support for QUIC 33 +type stopWaitingManager struct { + largestLeastUnackedSent protocol.PacketNumber + nextLeastUnacked protocol.PacketNumber + + lastStopWaitingFrame *wire.StopWaitingFrame +} + +func (s *stopWaitingManager) GetStopWaitingFrame(force bool) *wire.StopWaitingFrame { + if s.nextLeastUnacked <= s.largestLeastUnackedSent { + if force { + return s.lastStopWaitingFrame + } + return nil + } + + s.largestLeastUnackedSent = s.nextLeastUnacked + swf := &wire.StopWaitingFrame{ + LeastUnacked: s.nextLeastUnacked, + } + s.lastStopWaitingFrame = swf + return swf +} + +func (s *stopWaitingManager) ReceivedAck(ack *wire.AckFrame) { + largestAcked := ack.LargestAcked() + if largestAcked >= s.nextLeastUnacked { + s.nextLeastUnacked = largestAcked + 1 + } +} + +func (s *stopWaitingManager) QueuedRetransmissionForPacketNumber(p protocol.PacketNumber) { + if p >= s.nextLeastUnacked { + s.nextLeastUnacked = p + 1 + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager_test.go b/vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager_test.go new file mode 100644 index 00000000..c549bee8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/ackhandler/stop_waiting_manager_test.go @@ -0,0 +1,55 @@ +package ackhandler + +import ( + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("StopWaitingManager", func() { + var manager *stopWaitingManager + BeforeEach(func() { + manager = &stopWaitingManager{} + }) + + It("returns nil in the beginning", func() { + Expect(manager.GetStopWaitingFrame(false)).To(BeNil()) + Expect(manager.GetStopWaitingFrame(true)).To(BeNil()) + }) + + It("returns a StopWaitingFrame, when a new ACK arrives", func() { + manager.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + Expect(manager.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 11})) + }) + + It("does not decrease the LeastUnacked", func() { + manager.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + manager.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 9}}}) + Expect(manager.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 11})) + }) + + It("does not send the same StopWaitingFrame twice", func() { + manager.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + Expect(manager.GetStopWaitingFrame(false)).ToNot(BeNil()) + Expect(manager.GetStopWaitingFrame(false)).To(BeNil()) + }) + + It("gets the same StopWaitingFrame twice, if forced", func() { + manager.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + Expect(manager.GetStopWaitingFrame(false)).ToNot(BeNil()) + Expect(manager.GetStopWaitingFrame(true)).ToNot(BeNil()) + Expect(manager.GetStopWaitingFrame(true)).ToNot(BeNil()) + }) + + It("increases the LeastUnacked when a retransmission is queued", func() { + manager.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + manager.QueuedRetransmissionForPacketNumber(20) + Expect(manager.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 21})) + }) + + It("does not decrease the LeastUnacked when a retransmission is queued", func() { + manager.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + manager.QueuedRetransmissionForPacketNumber(9) + Expect(manager.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 11})) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/bandwidth.go b/vendor/lucas-clemente/quic-go/internal/congestion/bandwidth.go new file mode 100644 index 00000000..54269c56 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/bandwidth.go @@ -0,0 +1,22 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// Bandwidth of a connection +type Bandwidth uint64 + +const ( + // BitsPerSecond is 1 bit per second + BitsPerSecond Bandwidth = 1 + // BytesPerSecond is 1 byte per second + BytesPerSecond = 8 * BitsPerSecond +) + +// BandwidthFromDelta calculates the bandwidth from a number of bytes and a time delta +func BandwidthFromDelta(bytes protocol.ByteCount, delta time.Duration) Bandwidth { + return Bandwidth(bytes) * Bandwidth(time.Second) / Bandwidth(delta) * BytesPerSecond +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/bandwidth_test.go b/vendor/lucas-clemente/quic-go/internal/congestion/bandwidth_test.go new file mode 100644 index 00000000..03162747 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/bandwidth_test.go @@ -0,0 +1,14 @@ +package congestion + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Bandwidth", func() { + It("converts from time delta", func() { + Expect(BandwidthFromDelta(1, time.Millisecond)).To(Equal(1000 * BytesPerSecond)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/clock.go b/vendor/lucas-clemente/quic-go/internal/congestion/clock.go new file mode 100644 index 00000000..405fae70 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/clock.go @@ -0,0 +1,18 @@ +package congestion + +import "time" + +// A Clock returns the current time +type Clock interface { + Now() time.Time +} + +// DefaultClock implements the Clock interface using the Go stdlib clock. +type DefaultClock struct{} + +var _ Clock = DefaultClock{} + +// Now gets the current time +func (DefaultClock) Now() time.Time { + return time.Now() +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/congestion_suite_test.go b/vendor/lucas-clemente/quic-go/internal/congestion/congestion_suite_test.go new file mode 100644 index 00000000..577ee5bf --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/congestion_suite_test.go @@ -0,0 +1,13 @@ +package congestion + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCongestion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Congestion Suite") +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/cubic.go b/vendor/lucas-clemente/quic-go/internal/congestion/cubic.go new file mode 100644 index 00000000..dcf91fc6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/cubic.go @@ -0,0 +1,210 @@ +package congestion + +import ( + "math" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// This cubic implementation is based on the one found in Chromiums's QUIC +// implementation, in the files net/quic/congestion_control/cubic.{hh,cc}. + +// Constants based on TCP defaults. +// The following constants are in 2^10 fractions of a second instead of ms to +// allow a 10 shift right to divide. + +// 1024*1024^3 (first 1024 is from 0.100^3) +// where 0.100 is 100 ms which is the scaling round trip time. +const cubeScale = 40 +const cubeCongestionWindowScale = 410 +const cubeFactor protocol.ByteCount = 1 << cubeScale / cubeCongestionWindowScale / protocol.DefaultTCPMSS + +const defaultNumConnections = 2 + +// Default Cubic backoff factor +const beta float32 = 0.7 + +// Additional backoff factor when loss occurs in the concave part of the Cubic +// curve. This additional backoff factor is expected to give up bandwidth to +// new concurrent flows and speed up convergence. +const betaLastMax float32 = 0.85 + +// Cubic implements the cubic algorithm from TCP +type Cubic struct { + clock Clock + + // Number of connections to simulate. + numConnections int + + // Time when this cycle started, after last loss event. + epoch time.Time + + // Max congestion window used just before last loss event. + // Note: to improve fairness to other streams an additional back off is + // applied to this value if the new value is below our latest value. + lastMaxCongestionWindow protocol.ByteCount + + // Number of acked bytes since the cycle started (epoch). + ackedBytesCount protocol.ByteCount + + // TCP Reno equivalent congestion window in packets. + estimatedTCPcongestionWindow protocol.ByteCount + + // Origin point of cubic function. + originPointCongestionWindow protocol.ByteCount + + // Time to origin point of cubic function in 2^10 fractions of a second. + timeToOriginPoint uint32 + + // Last congestion window in packets computed by cubic function. + lastTargetCongestionWindow protocol.ByteCount +} + +// NewCubic returns a new Cubic instance +func NewCubic(clock Clock) *Cubic { + c := &Cubic{ + clock: clock, + numConnections: defaultNumConnections, + } + c.Reset() + return c +} + +// Reset is called after a timeout to reset the cubic state +func (c *Cubic) Reset() { + c.epoch = time.Time{} + c.lastMaxCongestionWindow = 0 + c.ackedBytesCount = 0 + c.estimatedTCPcongestionWindow = 0 + c.originPointCongestionWindow = 0 + c.timeToOriginPoint = 0 + c.lastTargetCongestionWindow = 0 +} + +func (c *Cubic) alpha() float32 { + // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that + // beta here is a cwnd multiplier, and is equal to 1-beta from the paper. + // We derive the equivalent alpha for an N-connection emulation as: + b := c.beta() + return 3 * float32(c.numConnections) * float32(c.numConnections) * (1 - b) / (1 + b) +} + +func (c *Cubic) beta() float32 { + // kNConnectionBeta is the backoff factor after loss for our N-connection + // emulation, which emulates the effective backoff of an ensemble of N + // TCP-Reno connections on a single loss event. The effective multiplier is + // computed as: + return (float32(c.numConnections) - 1 + beta) / float32(c.numConnections) +} + +func (c *Cubic) betaLastMax() float32 { + // betaLastMax is the additional backoff factor after loss for our + // N-connection emulation, which emulates the additional backoff of + // an ensemble of N TCP-Reno connections on a single loss event. The + // effective multiplier is computed as: + return (float32(c.numConnections) - 1 + betaLastMax) / float32(c.numConnections) +} + +// OnApplicationLimited is called on ack arrival when sender is unable to use +// the available congestion window. Resets Cubic state during quiescence. +func (c *Cubic) OnApplicationLimited() { + // When sender is not using the available congestion window, the window does + // not grow. But to be RTT-independent, Cubic assumes that the sender has been + // using the entire window during the time since the beginning of the current + // "epoch" (the end of the last loss recovery period). Since + // application-limited periods break this assumption, we reset the epoch when + // in such a period. This reset effectively freezes congestion window growth + // through application-limited periods and allows Cubic growth to continue + // when the entire window is being used. + c.epoch = time.Time{} +} + +// CongestionWindowAfterPacketLoss computes a new congestion window to use after +// a loss event. Returns the new congestion window in packets. The new +// congestion window is a multiplicative decrease of our current window. +func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow protocol.ByteCount) protocol.ByteCount { + if currentCongestionWindow+protocol.DefaultTCPMSS < c.lastMaxCongestionWindow { + // We never reached the old max, so assume we are competing with another + // flow. Use our extra back off factor to allow the other flow to go up. + c.lastMaxCongestionWindow = protocol.ByteCount(c.betaLastMax() * float32(currentCongestionWindow)) + } else { + c.lastMaxCongestionWindow = currentCongestionWindow + } + c.epoch = time.Time{} // Reset time. + return protocol.ByteCount(float32(currentCongestionWindow) * c.beta()) +} + +// CongestionWindowAfterAck computes a new congestion window to use after a received ACK. +// Returns the new congestion window in packets. The new congestion window +// follows a cubic function that depends on the time passed since last +// packet loss. +func (c *Cubic) CongestionWindowAfterAck( + ackedBytes protocol.ByteCount, + currentCongestionWindow protocol.ByteCount, + delayMin time.Duration, + eventTime time.Time, +) protocol.ByteCount { + c.ackedBytesCount += ackedBytes + + if c.epoch.IsZero() { + // First ACK after a loss event. + c.epoch = eventTime // Start of epoch. + c.ackedBytesCount = ackedBytes // Reset count. + // Reset estimated_tcp_congestion_window_ to be in sync with cubic. + c.estimatedTCPcongestionWindow = currentCongestionWindow + if c.lastMaxCongestionWindow <= currentCongestionWindow { + c.timeToOriginPoint = 0 + c.originPointCongestionWindow = currentCongestionWindow + } else { + c.timeToOriginPoint = uint32(math.Cbrt(float64(cubeFactor * (c.lastMaxCongestionWindow - currentCongestionWindow)))) + c.originPointCongestionWindow = c.lastMaxCongestionWindow + } + } + + // Change the time unit from microseconds to 2^10 fractions per second. Take + // the round trip time in account. This is done to allow us to use shift as a + // divide operator. + elapsedTime := int64(eventTime.Add(delayMin).Sub(c.epoch)/time.Microsecond) << 10 / (1000 * 1000) + + // Right-shifts of negative, signed numbers have implementation-dependent + // behavior, so force the offset to be positive, as is done in the kernel. + offset := int64(c.timeToOriginPoint) - elapsedTime + if offset < 0 { + offset = -offset + } + + deltaCongestionWindow := protocol.ByteCount(cubeCongestionWindowScale*offset*offset*offset) * protocol.DefaultTCPMSS >> cubeScale + var targetCongestionWindow protocol.ByteCount + if elapsedTime > int64(c.timeToOriginPoint) { + targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow + } else { + targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow + } + // Limit the CWND increase to half the acked bytes. + targetCongestionWindow = utils.MinByteCount(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) + + // Increase the window by approximately Alpha * 1 MSS of bytes every + // time we ack an estimated tcp window of bytes. For small + // congestion windows (less than 25), the formula below will + // increase slightly slower than linearly per estimated tcp window + // of bytes. + c.estimatedTCPcongestionWindow += protocol.ByteCount(float32(c.ackedBytesCount) * c.alpha() * float32(protocol.DefaultTCPMSS) / float32(c.estimatedTCPcongestionWindow)) + c.ackedBytesCount = 0 + + // We have a new cubic congestion window. + c.lastTargetCongestionWindow = targetCongestionWindow + + // Compute target congestion_window based on cubic target and estimated TCP + // congestion_window, use highest (fastest). + if targetCongestionWindow < c.estimatedTCPcongestionWindow { + targetCongestionWindow = c.estimatedTCPcongestionWindow + } + return targetCongestionWindow +} + +// SetNumConnections sets the number of emulated connections +func (c *Cubic) SetNumConnections(n int) { + c.numConnections = n +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender.go b/vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender.go new file mode 100644 index 00000000..b9f67e6c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender.go @@ -0,0 +1,318 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +const ( + maxBurstBytes = 3 * protocol.DefaultTCPMSS + renoBeta float32 = 0.7 // Reno backoff factor. + defaultMinimumCongestionWindow protocol.ByteCount = 2 * protocol.DefaultTCPMSS +) + +type cubicSender struct { + hybridSlowStart HybridSlowStart + prr PrrSender + rttStats *RTTStats + stats connectionStats + cubic *Cubic + + reno bool + + // Track the largest packet that has been sent. + largestSentPacketNumber protocol.PacketNumber + + // Track the largest packet that has been acked. + largestAckedPacketNumber protocol.PacketNumber + + // Track the largest packet number outstanding when a CWND cutback occurs. + largestSentAtLastCutback protocol.PacketNumber + + // Whether the last loss event caused us to exit slowstart. + // Used for stats collection of slowstartPacketsLost + lastCutbackExitedSlowstart bool + + // When true, exit slow start with large cutback of congestion window. + slowStartLargeReduction bool + + // Congestion window in packets. + congestionWindow protocol.ByteCount + + // Minimum congestion window in packets. + minCongestionWindow protocol.ByteCount + + // Maximum congestion window. + maxCongestionWindow protocol.ByteCount + + // Slow start congestion window in bytes, aka ssthresh. + slowstartThreshold protocol.ByteCount + + // Number of connections to simulate. + numConnections int + + // ACK counter for the Reno implementation. + numAckedPackets uint64 + + initialCongestionWindow protocol.ByteCount + initialMaxCongestionWindow protocol.ByteCount + + minSlowStartExitWindow protocol.ByteCount +} + +var _ SendAlgorithm = &cubicSender{} +var _ SendAlgorithmWithDebugInfo = &cubicSender{} + +// NewCubicSender makes a new cubic sender +func NewCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestionWindow, initialMaxCongestionWindow protocol.ByteCount) SendAlgorithmWithDebugInfo { + return &cubicSender{ + rttStats: rttStats, + initialCongestionWindow: initialCongestionWindow, + initialMaxCongestionWindow: initialMaxCongestionWindow, + congestionWindow: initialCongestionWindow, + minCongestionWindow: defaultMinimumCongestionWindow, + slowstartThreshold: initialMaxCongestionWindow, + maxCongestionWindow: initialMaxCongestionWindow, + numConnections: defaultNumConnections, + cubic: NewCubic(clock), + reno: reno, + } +} + +// TimeUntilSend returns when the next packet should be sent. +func (c *cubicSender) TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration { + if c.InRecovery() { + // PRR is used when in recovery. + if c.prr.CanSend(c.GetCongestionWindow(), bytesInFlight, c.GetSlowStartThreshold()) { + return 0 + } + } + delay := c.rttStats.SmoothedRTT() / time.Duration(2*c.GetCongestionWindow()) + if !c.InSlowStart() { // adjust delay, such that it's 1.25*cwd/rtt + delay = delay * 8 / 5 + } + return delay +} + +func (c *cubicSender) OnPacketSent( + sentTime time.Time, + bytesInFlight protocol.ByteCount, + packetNumber protocol.PacketNumber, + bytes protocol.ByteCount, + isRetransmittable bool, +) { + if !isRetransmittable { + return + } + if c.InRecovery() { + // PRR is used when in recovery. + c.prr.OnPacketSent(bytes) + } + c.largestSentPacketNumber = packetNumber + c.hybridSlowStart.OnPacketSent(packetNumber) +} + +func (c *cubicSender) InRecovery() bool { + return c.largestAckedPacketNumber <= c.largestSentAtLastCutback && c.largestAckedPacketNumber != 0 +} + +func (c *cubicSender) InSlowStart() bool { + return c.GetCongestionWindow() < c.GetSlowStartThreshold() +} + +func (c *cubicSender) GetCongestionWindow() protocol.ByteCount { + return c.congestionWindow +} + +func (c *cubicSender) GetSlowStartThreshold() protocol.ByteCount { + return c.slowstartThreshold +} + +func (c *cubicSender) ExitSlowstart() { + c.slowstartThreshold = c.congestionWindow +} + +func (c *cubicSender) SlowstartThreshold() protocol.ByteCount { + return c.slowstartThreshold +} + +func (c *cubicSender) MaybeExitSlowStart() { + if c.InSlowStart() && c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/protocol.DefaultTCPMSS) { + c.ExitSlowstart() + } +} + +func (c *cubicSender) OnPacketAcked( + ackedPacketNumber protocol.PacketNumber, + ackedBytes protocol.ByteCount, + priorInFlight protocol.ByteCount, + eventTime time.Time, +) { + c.largestAckedPacketNumber = utils.MaxPacketNumber(ackedPacketNumber, c.largestAckedPacketNumber) + if c.InRecovery() { + // PRR is used when in recovery. + c.prr.OnPacketAcked(ackedBytes) + return + } + c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime) + if c.InSlowStart() { + c.hybridSlowStart.OnPacketAcked(ackedPacketNumber) + } +} + +func (c *cubicSender) OnPacketLost( + packetNumber protocol.PacketNumber, + lostBytes protocol.ByteCount, + priorInFlight protocol.ByteCount, +) { + // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets + // already sent should be treated as a single loss event, since it's expected. + if packetNumber <= c.largestSentAtLastCutback { + if c.lastCutbackExitedSlowstart { + c.stats.slowstartPacketsLost++ + c.stats.slowstartBytesLost += lostBytes + if c.slowStartLargeReduction { + // Reduce congestion window by lost_bytes for every loss. + c.congestionWindow = utils.MaxByteCount(c.congestionWindow-lostBytes, c.minSlowStartExitWindow) + c.slowstartThreshold = c.congestionWindow + } + } + return + } + c.lastCutbackExitedSlowstart = c.InSlowStart() + if c.InSlowStart() { + c.stats.slowstartPacketsLost++ + } + + c.prr.OnPacketLost(priorInFlight) + + // TODO(chromium): Separate out all of slow start into a separate class. + if c.slowStartLargeReduction && c.InSlowStart() { + if c.congestionWindow >= 2*c.initialCongestionWindow { + c.minSlowStartExitWindow = c.congestionWindow / 2 + } + c.congestionWindow = c.congestionWindow - protocol.DefaultTCPMSS + } else if c.reno { + c.congestionWindow = protocol.ByteCount(float32(c.congestionWindow) * c.RenoBeta()) + } else { + c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow) + } + if c.congestionWindow < c.minCongestionWindow { + c.congestionWindow = c.minCongestionWindow + } + c.slowstartThreshold = c.congestionWindow + c.largestSentAtLastCutback = c.largestSentPacketNumber + // reset packet count from congestion avoidance mode. We start + // counting again when we're out of recovery. + c.numAckedPackets = 0 +} + +func (c *cubicSender) RenoBeta() float32 { + // kNConnectionBeta is the backoff factor after loss for our N-connection + // emulation, which emulates the effective backoff of an ensemble of N + // TCP-Reno connections on a single loss event. The effective multiplier is + // computed as: + return (float32(c.numConnections) - 1. + renoBeta) / float32(c.numConnections) +} + +// Called when we receive an ack. Normal TCP tracks how many packets one ack +// represents, but quic has a separate ack for each packet. +func (c *cubicSender) maybeIncreaseCwnd( + ackedPacketNumber protocol.PacketNumber, + ackedBytes protocol.ByteCount, + priorInFlight protocol.ByteCount, + eventTime time.Time, +) { + // Do not increase the congestion window unless the sender is close to using + // the current window. + if !c.isCwndLimited(priorInFlight) { + c.cubic.OnApplicationLimited() + return + } + if c.congestionWindow >= c.maxCongestionWindow { + return + } + if c.InSlowStart() { + // TCP slow start, exponential growth, increase by one for each ACK. + c.congestionWindow += protocol.DefaultTCPMSS + return + } + // Congestion avoidance + if c.reno { + // Classic Reno congestion avoidance. + c.numAckedPackets++ + // Divide by num_connections to smoothly increase the CWND at a faster + // rate than conventional Reno. + if c.numAckedPackets*uint64(c.numConnections) >= uint64(c.congestionWindow)/uint64(protocol.DefaultTCPMSS) { + c.congestionWindow += protocol.DefaultTCPMSS + c.numAckedPackets = 0 + } + } else { + c.congestionWindow = utils.MinByteCount(c.maxCongestionWindow, c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) + } +} + +func (c *cubicSender) isCwndLimited(bytesInFlight protocol.ByteCount) bool { + congestionWindow := c.GetCongestionWindow() + if bytesInFlight >= congestionWindow { + return true + } + availableBytes := congestionWindow - bytesInFlight + slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2 + return slowStartLimited || availableBytes <= maxBurstBytes +} + +// BandwidthEstimate returns the current bandwidth estimate +func (c *cubicSender) BandwidthEstimate() Bandwidth { + srtt := c.rttStats.SmoothedRTT() + if srtt == 0 { + // If we haven't measured an rtt, the bandwidth estimate is unknown. + return 0 + } + return BandwidthFromDelta(c.GetCongestionWindow(), srtt) +} + +// HybridSlowStart returns the hybrid slow start instance for testing +func (c *cubicSender) HybridSlowStart() *HybridSlowStart { + return &c.hybridSlowStart +} + +// SetNumEmulatedConnections sets the number of emulated connections +func (c *cubicSender) SetNumEmulatedConnections(n int) { + c.numConnections = utils.Max(n, 1) + c.cubic.SetNumConnections(c.numConnections) +} + +// OnRetransmissionTimeout is called on an retransmission timeout +func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { + c.largestSentAtLastCutback = 0 + if !packetsRetransmitted { + return + } + c.hybridSlowStart.Restart() + c.cubic.Reset() + c.slowstartThreshold = c.congestionWindow / 2 + c.congestionWindow = c.minCongestionWindow +} + +// OnConnectionMigration is called when the connection is migrated (?) +func (c *cubicSender) OnConnectionMigration() { + c.hybridSlowStart.Restart() + c.prr = PrrSender{} + c.largestSentPacketNumber = 0 + c.largestAckedPacketNumber = 0 + c.largestSentAtLastCutback = 0 + c.lastCutbackExitedSlowstart = false + c.cubic.Reset() + c.numAckedPackets = 0 + c.congestionWindow = c.initialCongestionWindow + c.slowstartThreshold = c.initialMaxCongestionWindow + c.maxCongestionWindow = c.initialMaxCongestionWindow +} + +// SetSlowStartLargeReduction allows enabling the SSLR experiment +func (c *cubicSender) SetSlowStartLargeReduction(enabled bool) { + c.slowStartLargeReduction = enabled +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender_test.go b/vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender_test.go new file mode 100644 index 00000000..de3b74fc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/cubic_sender_test.go @@ -0,0 +1,640 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const initialCongestionWindowPackets = 10 +const defaultWindowTCP = protocol.ByteCount(initialCongestionWindowPackets) * protocol.DefaultTCPMSS + +type mockClock time.Time + +func (c *mockClock) Now() time.Time { + return time.Time(*c) +} + +func (c *mockClock) Advance(d time.Duration) { + *c = mockClock(time.Time(*c).Add(d)) +} + +const MaxCongestionWindow protocol.ByteCount = 200 * protocol.DefaultTCPMSS + +var _ = Describe("Cubic Sender", func() { + var ( + sender SendAlgorithmWithDebugInfo + clock mockClock + bytesInFlight protocol.ByteCount + packetNumber protocol.PacketNumber + ackedPacketNumber protocol.PacketNumber + rttStats *RTTStats + ) + + BeforeEach(func() { + bytesInFlight = 0 + packetNumber = 1 + ackedPacketNumber = 0 + clock = mockClock{} + rttStats = NewRTTStats() + sender = NewCubicSender(&clock, rttStats, true /*reno*/, initialCongestionWindowPackets*protocol.DefaultTCPMSS, MaxCongestionWindow) + }) + + canSend := func() bool { + return bytesInFlight < sender.GetCongestionWindow() + } + + SendAvailableSendWindowLen := func(packetLength protocol.ByteCount) int { + packetsSent := 0 + for canSend() { + sender.OnPacketSent(clock.Now(), bytesInFlight, packetNumber, packetLength, true) + packetNumber++ + packetsSent++ + bytesInFlight += packetLength + } + return packetsSent + } + + // Normal is that TCP acks every other segment. + AckNPackets := func(n int) { + rttStats.UpdateRTT(60*time.Millisecond, 0, clock.Now()) + sender.MaybeExitSlowStart() + for i := 0; i < n; i++ { + ackedPacketNumber++ + sender.OnPacketAcked(ackedPacketNumber, protocol.DefaultTCPMSS, bytesInFlight, clock.Now()) + } + bytesInFlight -= protocol.ByteCount(n) * protocol.DefaultTCPMSS + clock.Advance(time.Millisecond) + } + + LoseNPacketsLen := func(n int, packetLength protocol.ByteCount) { + for i := 0; i < n; i++ { + ackedPacketNumber++ + sender.OnPacketLost(ackedPacketNumber, packetLength, bytesInFlight) + } + bytesInFlight -= protocol.ByteCount(n) * packetLength + } + + // Does not increment acked_packet_number_. + LosePacket := func(number protocol.PacketNumber) { + sender.OnPacketLost(number, protocol.DefaultTCPMSS, bytesInFlight) + bytesInFlight -= protocol.DefaultTCPMSS + } + + SendAvailableSendWindow := func() int { return SendAvailableSendWindowLen(protocol.DefaultTCPMSS) } + LoseNPackets := func(n int) { LoseNPacketsLen(n, protocol.DefaultTCPMSS) } + + It("has the right values at startup", func() { + // At startup make sure we are at the default. + Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) + // Make sure we can send. + Expect(sender.TimeUntilSend(0)).To(BeZero()) + Expect(canSend()).To(BeTrue()) + // And that window is un-affected. + Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) + + // Fill the send window with data, then verify that we can't send. + SendAvailableSendWindow() + Expect(canSend()).To(BeFalse()) + }) + + It("paces", func() { + clock.Advance(time.Hour) + // Fill the send window with data, then verify that we can't send. + SendAvailableSendWindow() + AckNPackets(1) + delay := sender.TimeUntilSend(bytesInFlight) + Expect(delay).ToNot(BeZero()) + Expect(delay).ToNot(Equal(utils.InfDuration)) + }) + + It("application limited slow start", func() { + // Send exactly 10 packets and ensure the CWND ends at 14 packets. + const numberOfAcks = 5 + // At startup make sure we can send. + Expect(sender.TimeUntilSend(0)).To(BeZero()) + // Make sure we can send. + Expect(sender.TimeUntilSend(0)).To(BeZero()) + + SendAvailableSendWindow() + for i := 0; i < numberOfAcks; i++ { + AckNPackets(2) + } + bytesToSend := sender.GetCongestionWindow() + // It's expected 2 acks will arrive when the bytes_in_flight are greater than + // half the CWND. + Expect(bytesToSend).To(Equal(defaultWindowTCP + protocol.DefaultTCPMSS*2*2)) + }) + + It("exponential slow start", func() { + const numberOfAcks = 20 + // At startup make sure we can send. + Expect(sender.TimeUntilSend(0)).To(BeZero()) + Expect(sender.BandwidthEstimate()).To(BeZero()) + // Make sure we can send. + Expect(sender.TimeUntilSend(0)).To(BeZero()) + + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + cwnd := sender.GetCongestionWindow() + Expect(cwnd).To(Equal(defaultWindowTCP + protocol.DefaultTCPMSS*2*numberOfAcks)) + Expect(sender.BandwidthEstimate()).To(Equal(BandwidthFromDelta(cwnd, rttStats.SmoothedRTT()))) + }) + + It("slow start packet loss", func() { + sender.SetNumEmulatedConnections(1) + const numberOfAcks = 10 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + SendAvailableSendWindow() + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Lose a packet to exit slow start. + LoseNPackets(1) + packetsInRecoveryWindow := expectedSendWindow / protocol.DefaultTCPMSS + + // We should now have fallen out of slow start with a reduced window. + expectedSendWindow = protocol.ByteCount(float32(expectedSendWindow) * renoBeta) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Recovery phase. We need to ack every packet in the recovery window before + // we exit recovery. + numberOfPacketsInWindow := expectedSendWindow / protocol.DefaultTCPMSS + AckNPackets(int(packetsInRecoveryWindow)) + SendAvailableSendWindow() + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // We need to ack an entire window before we increase CWND by 1. + AckNPackets(int(numberOfPacketsInWindow) - 2) + SendAvailableSendWindow() + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Next ack should increase cwnd by 1. + AckNPackets(1) + expectedSendWindow += protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Now RTO and ensure slow start gets reset. + Expect(sender.HybridSlowStart().Started()).To(BeTrue()) + sender.OnRetransmissionTimeout(true) + Expect(sender.HybridSlowStart().Started()).To(BeFalse()) + }) + + It("slow start packet loss with large reduction", func() { + sender.SetSlowStartLargeReduction(true) + + sender.SetNumEmulatedConnections(1) + const numberOfAcks = 10 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + SendAvailableSendWindow() + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Lose a packet to exit slow start. We should now have fallen out of + // slow start with a window reduced by 1. + LoseNPackets(1) + expectedSendWindow -= protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Lose 5 packets in recovery and verify that congestion window is reduced + // further. + LoseNPackets(5) + expectedSendWindow -= 5 * protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + packetsInRecoveryWindow := expectedSendWindow / protocol.DefaultTCPMSS + + // Recovery phase. We need to ack every packet in the recovery window before + // we exit recovery. + numberOfPacketsInWindow := expectedSendWindow / protocol.DefaultTCPMSS + AckNPackets(int(packetsInRecoveryWindow)) + SendAvailableSendWindow() + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // We need to ack the rest of the window before cwnd increases by 1. + AckNPackets(int(numberOfPacketsInWindow - 1)) + SendAvailableSendWindow() + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Next ack should increase cwnd by 1. + AckNPackets(1) + expectedSendWindow += protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Now RTO and ensure slow start gets reset. + Expect(sender.HybridSlowStart().Started()).To(BeTrue()) + sender.OnRetransmissionTimeout(true) + Expect(sender.HybridSlowStart().Started()).To(BeFalse()) + }) + + It("slow start half packet loss with large reduction", func() { + sender.SetSlowStartLargeReduction(true) + + sender.SetNumEmulatedConnections(1) + const numberOfAcks = 10 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window in half sized packets. + SendAvailableSendWindowLen(protocol.DefaultTCPMSS / 2) + AckNPackets(2) + } + SendAvailableSendWindowLen(protocol.DefaultTCPMSS / 2) + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Lose a packet to exit slow start. We should now have fallen out of + // slow start with a window reduced by 1. + LoseNPackets(1) + expectedSendWindow -= protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Lose 10 packets in recovery and verify that congestion window is reduced + // by 5 packets. + LoseNPacketsLen(10, protocol.DefaultTCPMSS/2) + expectedSendWindow -= 5 * protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + }) + + // this test doesn't work any more after introducing the pacing needed for QUIC + PIt("no PRR when less than one packet in flight", func() { + SendAvailableSendWindow() + LoseNPackets(int(initialCongestionWindowPackets) - 1) + AckNPackets(1) + // PRR will allow 2 packets for every ack during recovery. + Expect(SendAvailableSendWindow()).To(Equal(2)) + // Simulate abandoning all packets by supplying a bytes_in_flight of 0. + // PRR should now allow a packet to be sent, even though prr's state + // variables believe it has sent enough packets. + Expect(sender.TimeUntilSend(0)).To(BeZero()) + }) + + It("slow start packet loss PRR", func() { + sender.SetNumEmulatedConnections(1) + // Test based on the first example in RFC6937. + // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example. + const numberOfAcks = 5 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + SendAvailableSendWindow() + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + LoseNPackets(1) + + // We should now have fallen out of slow start with a reduced window. + sendWindowBeforeLoss := expectedSendWindow + expectedSendWindow = protocol.ByteCount(float32(expectedSendWindow) * renoBeta) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Testing TCP proportional rate reduction. + // We should send packets paced over the received acks for the remaining + // outstanding packets. The number of packets before we exit recovery is the + // original CWND minus the packet that has been lost and the one which + // triggered the loss. + remainingPacketsInRecovery := sendWindowBeforeLoss/protocol.DefaultTCPMSS - 2 + + for i := protocol.ByteCount(0); i < remainingPacketsInRecovery; i++ { + AckNPackets(1) + SendAvailableSendWindow() + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + } + + // We need to ack another window before we increase CWND by 1. + numberOfPacketsInWindow := expectedSendWindow / protocol.DefaultTCPMSS + for i := protocol.ByteCount(0); i < numberOfPacketsInWindow; i++ { + AckNPackets(1) + Expect(SendAvailableSendWindow()).To(Equal(1)) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + } + + AckNPackets(1) + expectedSendWindow += protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + }) + + It("slow start burst packet loss PRR", func() { + sender.SetNumEmulatedConnections(1) + // Test based on the second example in RFC6937, though we also implement + // forward acknowledgements, so the first two incoming acks will trigger + // PRR immediately. + // Ack 20 packets in 10 acks to raise the CWND to 30. + const numberOfAcks = 10 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + SendAvailableSendWindow() + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Lose one more than the congestion window reduction, so that after loss, + // bytes_in_flight is lesser than the congestion window. + sendWindowAfterLoss := protocol.ByteCount(renoBeta * float32(expectedSendWindow)) + numPacketsToLose := (expectedSendWindow-sendWindowAfterLoss)/protocol.DefaultTCPMSS + 1 + LoseNPackets(int(numPacketsToLose)) + // Immediately after the loss, ensure at least one packet can be sent. + // Losses without subsequent acks can occur with timer based loss detection. + Expect(sender.TimeUntilSend(bytesInFlight)).To(BeZero()) + AckNPackets(1) + + // We should now have fallen out of slow start with a reduced window. + expectedSendWindow = protocol.ByteCount(float32(expectedSendWindow) * renoBeta) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Only 2 packets should be allowed to be sent, per PRR-SSRB + Expect(SendAvailableSendWindow()).To(Equal(2)) + + // Ack the next packet, which triggers another loss. + LoseNPackets(1) + AckNPackets(1) + + // Send 2 packets to simulate PRR-SSRB. + Expect(SendAvailableSendWindow()).To(Equal(2)) + + // Ack the next packet, which triggers another loss. + LoseNPackets(1) + AckNPackets(1) + + // Send 2 packets to simulate PRR-SSRB. + Expect(SendAvailableSendWindow()).To(Equal(2)) + + // Exit recovery and return to sending at the new rate. + for i := 0; i < numberOfAcks; i++ { + AckNPackets(1) + Expect(SendAvailableSendWindow()).To(Equal(1)) + } + }) + + It("RTO congestion window", func() { + Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) + Expect(sender.SlowstartThreshold()).To(Equal(MaxCongestionWindow)) + + // Expect the window to decrease to the minimum once the RTO fires + // and slow start threshold to be set to 1/2 of the CWND. + sender.OnRetransmissionTimeout(true) + Expect(sender.GetCongestionWindow()).To(Equal(2 * protocol.DefaultTCPMSS)) + Expect(sender.SlowstartThreshold()).To(Equal(5 * protocol.DefaultTCPMSS)) + }) + + It("RTO congestion window no retransmission", func() { + Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) + + // Expect the window to remain unchanged if the RTO fires but no + // packets are retransmitted. + sender.OnRetransmissionTimeout(false) + Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) + }) + + It("tcp cubic reset epoch on quiescence", func() { + const maxCongestionWindow = 50 + const maxCongestionWindowBytes = maxCongestionWindow * protocol.DefaultTCPMSS + sender = NewCubicSender(&clock, rttStats, false, initialCongestionWindowPackets*protocol.DefaultTCPMSS, maxCongestionWindowBytes) + + numSent := SendAvailableSendWindow() + + // Make sure we fall out of slow start. + savedCwnd := sender.GetCongestionWindow() + LoseNPackets(1) + Expect(savedCwnd).To(BeNumerically(">", sender.GetCongestionWindow())) + + // Ack the rest of the outstanding packets to get out of recovery. + for i := 1; i < numSent; i++ { + AckNPackets(1) + } + Expect(bytesInFlight).To(BeZero()) + + // Send a new window of data and ack all; cubic growth should occur. + savedCwnd = sender.GetCongestionWindow() + numSent = SendAvailableSendWindow() + for i := 0; i < numSent; i++ { + AckNPackets(1) + } + Expect(savedCwnd).To(BeNumerically("<", sender.GetCongestionWindow())) + Expect(maxCongestionWindowBytes).To(BeNumerically(">", sender.GetCongestionWindow())) + Expect(bytesInFlight).To(BeZero()) + + // Quiescent time of 100 seconds + clock.Advance(100 * time.Second) + + // Send new window of data and ack one packet. Cubic epoch should have + // been reset; ensure cwnd increase is not dramatic. + savedCwnd = sender.GetCongestionWindow() + SendAvailableSendWindow() + AckNPackets(1) + Expect(savedCwnd).To(BeNumerically("~", sender.GetCongestionWindow(), protocol.DefaultTCPMSS)) + Expect(maxCongestionWindowBytes).To(BeNumerically(">", sender.GetCongestionWindow())) + }) + + It("multiple losses in one window", func() { + SendAvailableSendWindow() + initialWindow := sender.GetCongestionWindow() + LosePacket(ackedPacketNumber + 1) + postLossWindow := sender.GetCongestionWindow() + Expect(initialWindow).To(BeNumerically(">", postLossWindow)) + LosePacket(ackedPacketNumber + 3) + Expect(sender.GetCongestionWindow()).To(Equal(postLossWindow)) + LosePacket(packetNumber - 1) + Expect(sender.GetCongestionWindow()).To(Equal(postLossWindow)) + + // Lose a later packet and ensure the window decreases. + LosePacket(packetNumber) + Expect(postLossWindow).To(BeNumerically(">", sender.GetCongestionWindow())) + }) + + It("2 connection congestion avoidance at end of recovery", func() { + sender.SetNumEmulatedConnections(2) + // Ack 10 packets in 5 acks to raise the CWND to 20. + const numberOfAcks = 5 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + SendAvailableSendWindow() + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + LoseNPackets(1) + + // We should now have fallen out of slow start with a reduced window. + expectedSendWindow = protocol.ByteCount(float32(expectedSendWindow) * sender.RenoBeta()) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // No congestion window growth should occur in recovery phase, i.e., until the + // currently outstanding 20 packets are acked. + for i := 0; i < 10; i++ { + // Send our full send window. + SendAvailableSendWindow() + Expect(sender.InRecovery()).To(BeTrue()) + AckNPackets(2) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + } + Expect(sender.InRecovery()).To(BeFalse()) + + // Out of recovery now. Congestion window should not grow for half an RTT. + packetsInSendWindow := expectedSendWindow / protocol.DefaultTCPMSS + SendAvailableSendWindow() + AckNPackets(int(packetsInSendWindow/2 - 2)) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Next ack should increase congestion window by 1MSS. + SendAvailableSendWindow() + AckNPackets(2) + expectedSendWindow += protocol.DefaultTCPMSS + packetsInSendWindow++ + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Congestion window should remain steady again for half an RTT. + SendAvailableSendWindow() + AckNPackets(int(packetsInSendWindow/2 - 1)) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Next ack should cause congestion window to grow by 1MSS. + SendAvailableSendWindow() + AckNPackets(2) + expectedSendWindow += protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + }) + + It("1 connection congestion avoidance at end of recovery", func() { + sender.SetNumEmulatedConnections(1) + // Ack 10 packets in 5 acks to raise the CWND to 20. + const numberOfAcks = 5 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + SendAvailableSendWindow() + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + LoseNPackets(1) + + // We should now have fallen out of slow start with a reduced window. + expectedSendWindow = protocol.ByteCount(float32(expectedSendWindow) * renoBeta) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // No congestion window growth should occur in recovery phase, i.e., until the + // currently outstanding 20 packets are acked. + for i := 0; i < 10; i++ { + // Send our full send window. + SendAvailableSendWindow() + Expect(sender.InRecovery()).To(BeTrue()) + AckNPackets(2) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + } + Expect(sender.InRecovery()).To(BeFalse()) + + // Out of recovery now. Congestion window should not grow during RTT. + for i := protocol.ByteCount(0); i < expectedSendWindow/protocol.DefaultTCPMSS-2; i += 2 { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + } + + // Next ack should cause congestion window to grow by 1MSS. + SendAvailableSendWindow() + AckNPackets(2) + expectedSendWindow += protocol.DefaultTCPMSS + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + }) + + It("reset after connection migration", func() { + Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) + Expect(sender.SlowstartThreshold()).To(Equal(MaxCongestionWindow)) + + // Starts with slow start. + sender.SetNumEmulatedConnections(1) + const numberOfAcks = 10 + for i := 0; i < numberOfAcks; i++ { + // Send our full send window. + SendAvailableSendWindow() + AckNPackets(2) + } + SendAvailableSendWindow() + expectedSendWindow := defaultWindowTCP + (protocol.DefaultTCPMSS * 2 * numberOfAcks) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + + // Loses a packet to exit slow start. + LoseNPackets(1) + + // We should now have fallen out of slow start with a reduced window. Slow + // start threshold is also updated. + expectedSendWindow = protocol.ByteCount(float32(expectedSendWindow) * renoBeta) + Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) + Expect(sender.SlowstartThreshold()).To(Equal(expectedSendWindow)) + + // Resets cwnd and slow start threshold on connection migrations. + sender.OnConnectionMigration() + Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) + Expect(sender.SlowstartThreshold()).To(Equal(MaxCongestionWindow)) + Expect(sender.HybridSlowStart().Started()).To(BeFalse()) + }) + + It("default max cwnd", func() { + sender = NewCubicSender(&clock, rttStats, true /*reno*/, initialCongestionWindowPackets*protocol.DefaultTCPMSS, protocol.DefaultMaxCongestionWindow) + + defaultMaxCongestionWindowPackets := protocol.DefaultMaxCongestionWindow / protocol.DefaultTCPMSS + for i := 1; i < int(defaultMaxCongestionWindowPackets); i++ { + sender.MaybeExitSlowStart() + sender.OnPacketAcked(protocol.PacketNumber(i), 1350, sender.GetCongestionWindow(), clock.Now()) + } + Expect(sender.GetCongestionWindow()).To(Equal(protocol.DefaultMaxCongestionWindow)) + }) + + It("limit cwnd increase in congestion avoidance", func() { + // Enable Cubic. + sender = NewCubicSender(&clock, rttStats, false, initialCongestionWindowPackets*protocol.DefaultTCPMSS, MaxCongestionWindow) + numSent := SendAvailableSendWindow() + + // Make sure we fall out of slow start. + savedCwnd := sender.GetCongestionWindow() + LoseNPackets(1) + Expect(savedCwnd).To(BeNumerically(">", sender.GetCongestionWindow())) + + // Ack the rest of the outstanding packets to get out of recovery. + for i := 1; i < numSent; i++ { + AckNPackets(1) + } + Expect(bytesInFlight).To(BeZero()) + + savedCwnd = sender.GetCongestionWindow() + SendAvailableSendWindow() + + // Ack packets until the CWND increases. + for sender.GetCongestionWindow() == savedCwnd { + AckNPackets(1) + SendAvailableSendWindow() + } + // Bytes in flight may be larger than the CWND if the CWND isn't an exact + // multiple of the packet sizes being sent. + Expect(bytesInFlight).To(BeNumerically(">=", sender.GetCongestionWindow())) + savedCwnd = sender.GetCongestionWindow() + + // Advance time 2 seconds waiting for an ack. + clock.Advance(2 * time.Second) + + // Ack two packets. The CWND should increase by only one packet. + AckNPackets(2) + Expect(sender.GetCongestionWindow()).To(Equal(savedCwnd + protocol.DefaultTCPMSS)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/cubic_test.go b/vendor/lucas-clemente/quic-go/internal/congestion/cubic_test.go new file mode 100644 index 00000000..52cae145 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/cubic_test.go @@ -0,0 +1,236 @@ +package congestion + +import ( + "math" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const numConnections uint32 = 2 +const nConnectionBeta float32 = (float32(numConnections) - 1 + beta) / float32(numConnections) +const nConnectionBetaLastMax float32 = (float32(numConnections) - 1 + betaLastMax) / float32(numConnections) +const nConnectionAlpha float32 = 3 * float32(numConnections) * float32(numConnections) * (1 - nConnectionBeta) / (1 + nConnectionBeta) +const maxCubicTimeInterval = 30 * time.Millisecond + +var _ = Describe("Cubic", func() { + var ( + clock mockClock + cubic *Cubic + ) + + BeforeEach(func() { + clock = mockClock{} + cubic = NewCubic(&clock) + }) + + renoCwnd := func(currentCwnd protocol.ByteCount) protocol.ByteCount { + return currentCwnd + protocol.ByteCount(float32(protocol.DefaultTCPMSS)*nConnectionAlpha*float32(protocol.DefaultTCPMSS)/float32(currentCwnd)) + } + + cubicConvexCwnd := func(initialCwnd protocol.ByteCount, rtt, elapsedTime time.Duration) protocol.ByteCount { + offset := protocol.ByteCount((elapsedTime+rtt)/time.Microsecond) << 10 / 1000000 + deltaCongestionWindow := 410 * offset * offset * offset * protocol.DefaultTCPMSS >> 40 + return initialCwnd + deltaCongestionWindow + } + + It("works above origin (with tighter bounds)", func() { + // Convex growth. + const rttMin = 100 * time.Millisecond + const rttMinS = float32(rttMin/time.Millisecond) / 1000.0 + currentCwnd := 10 * protocol.DefaultTCPMSS + initialCwnd := currentCwnd + + clock.Advance(time.Millisecond) + initialTime := clock.Now() + expectedFirstCwnd := renoCwnd(currentCwnd) + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, initialTime) + Expect(expectedFirstCwnd).To(Equal(currentCwnd)) + + // Normal TCP phase. + // The maximum number of expected reno RTTs can be calculated by + // finding the point where the cubic curve and the reno curve meet. + maxRenoRtts := int(math.Sqrt(float64(nConnectionAlpha/(0.4*rttMinS*rttMinS*rttMinS))) - 2) + for i := 0; i < maxRenoRtts; i++ { + // Alternatively, we expect it to increase by one, every time we + // receive current_cwnd/Alpha acks back. (This is another way of + // saying we expect cwnd to increase by approximately Alpha once + // we receive current_cwnd number ofacks back). + numAcksThisEpoch := int(float32(currentCwnd/protocol.DefaultTCPMSS) / nConnectionAlpha) + + initialCwndThisEpoch := currentCwnd + for n := 0; n < numAcksThisEpoch; n++ { + // Call once per ACK. + expectedNextCwnd := renoCwnd(currentCwnd) + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + Expect(currentCwnd).To(Equal(expectedNextCwnd)) + } + // Our byte-wise Reno implementation is an estimate. We expect + // the cwnd to increase by approximately one MSS every + // cwnd/kDefaultTCPMSS/Alpha acks, but it may be off by as much as + // half a packet for smaller values of current_cwnd. + cwndChangeThisEpoch := currentCwnd - initialCwndThisEpoch + Expect(cwndChangeThisEpoch).To(BeNumerically("~", protocol.DefaultTCPMSS, protocol.DefaultTCPMSS/2)) + clock.Advance(100 * time.Millisecond) + } + + for i := 0; i < 54; i++ { + maxAcksThisEpoch := currentCwnd / protocol.DefaultTCPMSS + interval := time.Duration(100*1000/maxAcksThisEpoch) * time.Microsecond + for n := 0; n < int(maxAcksThisEpoch); n++ { + clock.Advance(interval) + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + expectedCwnd := cubicConvexCwnd(initialCwnd, rttMin, clock.Now().Sub(initialTime)) + // If we allow per-ack updates, every update is a small cubic update. + Expect(currentCwnd).To(Equal(expectedCwnd)) + } + } + expectedCwnd := cubicConvexCwnd(initialCwnd, rttMin, clock.Now().Sub(initialTime)) + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + Expect(currentCwnd).To(Equal(expectedCwnd)) + }) + + It("works above the origin with fine grained cubing", func() { + // Start the test with an artificially large cwnd to prevent Reno + // from over-taking cubic. + currentCwnd := 1000 * protocol.DefaultTCPMSS + initialCwnd := currentCwnd + rttMin := 100 * time.Millisecond + clock.Advance(time.Millisecond) + initialTime := clock.Now() + + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + clock.Advance(600 * time.Millisecond) + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + + // We expect the algorithm to perform only non-zero, fine-grained cubic + // increases on every ack in this case. + for i := 0; i < 100; i++ { + clock.Advance(10 * time.Millisecond) + expectedCwnd := cubicConvexCwnd(initialCwnd, rttMin, clock.Now().Sub(initialTime)) + nextCwnd := cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + // Make sure we are performing cubic increases. + Expect(nextCwnd).To(Equal(expectedCwnd)) + // Make sure that these are non-zero, less-than-packet sized increases. + Expect(nextCwnd).To(BeNumerically(">", currentCwnd)) + cwndDelta := nextCwnd - currentCwnd + Expect(protocol.DefaultTCPMSS / 10).To(BeNumerically(">", cwndDelta)) + currentCwnd = nextCwnd + } + }) + + It("handles per ack updates", func() { + // Start the test with a large cwnd and RTT, to force the first + // increase to be a cubic increase. + initialCwndPackets := 150 + currentCwnd := protocol.ByteCount(initialCwndPackets) * protocol.DefaultTCPMSS + rttMin := 350 * time.Millisecond + + // Initialize the epoch + clock.Advance(time.Millisecond) + // Keep track of the growth of the reno-equivalent cwnd. + rCwnd := renoCwnd(currentCwnd) + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + initialCwnd := currentCwnd + + // Simulate the return of cwnd packets in less than + // MaxCubicInterval() time. + maxAcks := int(float32(initialCwndPackets) / nConnectionAlpha) + interval := maxCubicTimeInterval / time.Duration(maxAcks+1) + + // In this scenario, the first increase is dictated by the cubic + // equation, but it is less than one byte, so the cwnd doesn't + // change. Normally, without per-ack increases, any cwnd plateau + // will cause the cwnd to be pinned for MaxCubicTimeInterval(). If + // we enable per-ack updates, the cwnd will continue to grow, + // regardless of the temporary plateau. + clock.Advance(interval) + rCwnd = renoCwnd(rCwnd) + Expect(cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now())).To(Equal(currentCwnd)) + for i := 1; i < maxAcks; i++ { + clock.Advance(interval) + nextCwnd := cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + rCwnd = renoCwnd(rCwnd) + // The window shoud increase on every ack. + Expect(nextCwnd).To(BeNumerically(">", currentCwnd)) + Expect(nextCwnd).To(Equal(rCwnd)) + currentCwnd = nextCwnd + } + + // After all the acks are returned from the epoch, we expect the + // cwnd to have increased by nearly one packet. (Not exactly one + // packet, because our byte-wise Reno algorithm is always a slight + // under-estimation). Without per-ack updates, the current_cwnd + // would otherwise be unchanged. + minimumExpectedIncrease := protocol.DefaultTCPMSS * 9 / 10 + Expect(currentCwnd).To(BeNumerically(">", initialCwnd+minimumExpectedIncrease)) + }) + + It("handles loss events", func() { + rttMin := 100 * time.Millisecond + currentCwnd := 422 * protocol.DefaultTCPMSS + expectedCwnd := renoCwnd(currentCwnd) + // Initialize the state. + clock.Advance(time.Millisecond) + Expect(cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now())).To(Equal(expectedCwnd)) + + // On the first loss, the last max congestion window is set to the + // congestion window before the loss. + preLossCwnd := currentCwnd + Expect(cubic.lastMaxCongestionWindow).To(BeZero()) + expectedCwnd = protocol.ByteCount(float32(currentCwnd) * nConnectionBeta) + Expect(cubic.CongestionWindowAfterPacketLoss(currentCwnd)).To(Equal(expectedCwnd)) + Expect(cubic.lastMaxCongestionWindow).To(Equal(preLossCwnd)) + currentCwnd = expectedCwnd + + // On the second loss, the current congestion window has not yet + // reached the last max congestion window. The last max congestion + // window will be reduced by an additional backoff factor to allow + // for competition. + preLossCwnd = currentCwnd + expectedCwnd = protocol.ByteCount(float32(currentCwnd) * nConnectionBeta) + Expect(cubic.CongestionWindowAfterPacketLoss(currentCwnd)).To(Equal(expectedCwnd)) + currentCwnd = expectedCwnd + Expect(preLossCwnd).To(BeNumerically(">", cubic.lastMaxCongestionWindow)) + expectedLastMax := protocol.ByteCount(float32(preLossCwnd) * nConnectionBetaLastMax) + Expect(cubic.lastMaxCongestionWindow).To(Equal(expectedLastMax)) + Expect(expectedCwnd).To(BeNumerically("<", cubic.lastMaxCongestionWindow)) + // Simulate an increase, and check that we are below the origin. + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + Expect(cubic.lastMaxCongestionWindow).To(BeNumerically(">", currentCwnd)) + + // On the final loss, simulate the condition where the congestion + // window had a chance to grow nearly to the last congestion window. + currentCwnd = cubic.lastMaxCongestionWindow - 1 + preLossCwnd = currentCwnd + expectedCwnd = protocol.ByteCount(float32(currentCwnd) * nConnectionBeta) + Expect(cubic.CongestionWindowAfterPacketLoss(currentCwnd)).To(Equal(expectedCwnd)) + expectedLastMax = preLossCwnd + Expect(cubic.lastMaxCongestionWindow).To(Equal(expectedLastMax)) + }) + + It("works below origin", func() { + // Concave growth. + rttMin := 100 * time.Millisecond + currentCwnd := 422 * protocol.DefaultTCPMSS + expectedCwnd := renoCwnd(currentCwnd) + // Initialize the state. + clock.Advance(time.Millisecond) + Expect(cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now())).To(Equal(expectedCwnd)) + + expectedCwnd = protocol.ByteCount(float32(currentCwnd) * nConnectionBeta) + Expect(cubic.CongestionWindowAfterPacketLoss(currentCwnd)).To(Equal(expectedCwnd)) + currentCwnd = expectedCwnd + // First update after loss to initialize the epoch. + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + // Cubic phase. + for i := 0; i < 40; i++ { + clock.Advance(100 * time.Millisecond) + currentCwnd = cubic.CongestionWindowAfterAck(protocol.DefaultTCPMSS, currentCwnd, rttMin, clock.Now()) + } + expectedCwnd = 553632 + Expect(currentCwnd).To(Equal(expectedCwnd)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start.go b/vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start.go new file mode 100644 index 00000000..f41c1e5c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start.go @@ -0,0 +1,111 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// Note(pwestin): the magic clamping numbers come from the original code in +// tcp_cubic.c. +const hybridStartLowWindow = protocol.ByteCount(16) + +// Number of delay samples for detecting the increase of delay. +const hybridStartMinSamples = uint32(8) + +// Exit slow start if the min rtt has increased by more than 1/8th. +const hybridStartDelayFactorExp = 3 // 2^3 = 8 +// The original paper specifies 2 and 8ms, but those have changed over time. +const hybridStartDelayMinThresholdUs = int64(4000) +const hybridStartDelayMaxThresholdUs = int64(16000) + +// HybridSlowStart implements the TCP hybrid slow start algorithm +type HybridSlowStart struct { + endPacketNumber protocol.PacketNumber + lastSentPacketNumber protocol.PacketNumber + started bool + currentMinRTT time.Duration + rttSampleCount uint32 + hystartFound bool +} + +// StartReceiveRound is called for the start of each receive round (burst) in the slow start phase. +func (s *HybridSlowStart) StartReceiveRound(lastSent protocol.PacketNumber) { + s.endPacketNumber = lastSent + s.currentMinRTT = 0 + s.rttSampleCount = 0 + s.started = true +} + +// IsEndOfRound returns true if this ack is the last packet number of our current slow start round. +func (s *HybridSlowStart) IsEndOfRound(ack protocol.PacketNumber) bool { + return s.endPacketNumber < ack +} + +// ShouldExitSlowStart should be called on every new ack frame, since a new +// RTT measurement can be made then. +// rtt: the RTT for this ack packet. +// minRTT: is the lowest delay (RTT) we have seen during the session. +// congestionWindow: the congestion window in packets. +func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT time.Duration, congestionWindow protocol.ByteCount) bool { + if !s.started { + // Time to start the hybrid slow start. + s.StartReceiveRound(s.lastSentPacketNumber) + } + if s.hystartFound { + return true + } + // Second detection parameter - delay increase detection. + // Compare the minimum delay (s.currentMinRTT) of the current + // burst of packets relative to the minimum delay during the session. + // Note: we only look at the first few(8) packets in each burst, since we + // only want to compare the lowest RTT of the burst relative to previous + // bursts. + s.rttSampleCount++ + if s.rttSampleCount <= hybridStartMinSamples { + if s.currentMinRTT == 0 || s.currentMinRTT > latestRTT { + s.currentMinRTT = latestRTT + } + } + // We only need to check this once per round. + if s.rttSampleCount == hybridStartMinSamples { + // Divide minRTT by 8 to get a rtt increase threshold for exiting. + minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) + // Ensure the rtt threshold is never less than 2ms or more than 16ms. + minRTTincreaseThresholdUs = utils.MinInt64(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) + minRTTincreaseThreshold := time.Duration(utils.MaxInt64(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond + + if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { + s.hystartFound = true + } + } + // Exit from slow start if the cwnd is greater than 16 and + // increasing delay is found. + return congestionWindow >= hybridStartLowWindow && s.hystartFound +} + +// OnPacketSent is called when a packet was sent +func (s *HybridSlowStart) OnPacketSent(packetNumber protocol.PacketNumber) { + s.lastSentPacketNumber = packetNumber +} + +// OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end +// the round when the final packet of the burst is received and start it on +// the next incoming ack. +func (s *HybridSlowStart) OnPacketAcked(ackedPacketNumber protocol.PacketNumber) { + if s.IsEndOfRound(ackedPacketNumber) { + s.started = false + } +} + +// Started returns true if started +func (s *HybridSlowStart) Started() bool { + return s.started +} + +// Restart the slow start phase +func (s *HybridSlowStart) Restart() { + s.started = false + s.hystartFound = false +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start_test.go b/vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start_test.go new file mode 100644 index 00000000..fee8945e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start_test.go @@ -0,0 +1,75 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Hybrid slow start", func() { + var ( + slowStart HybridSlowStart + ) + + BeforeEach(func() { + slowStart = HybridSlowStart{} + }) + + It("works in a simple case", func() { + packetNumber := protocol.PacketNumber(1) + endPacketNumber := protocol.PacketNumber(3) + slowStart.StartReceiveRound(endPacketNumber) + + packetNumber++ + Expect(slowStart.IsEndOfRound(packetNumber)).To(BeFalse()) + + // Test duplicates. + Expect(slowStart.IsEndOfRound(packetNumber)).To(BeFalse()) + + packetNumber++ + Expect(slowStart.IsEndOfRound(packetNumber)).To(BeFalse()) + packetNumber++ + Expect(slowStart.IsEndOfRound(packetNumber)).To(BeTrue()) + + // Test without a new registered end_packet_number; + packetNumber++ + Expect(slowStart.IsEndOfRound(packetNumber)).To(BeTrue()) + + endPacketNumber = 20 + slowStart.StartReceiveRound(endPacketNumber) + for packetNumber < endPacketNumber { + packetNumber++ + Expect(slowStart.IsEndOfRound(packetNumber)).To(BeFalse()) + } + packetNumber++ + Expect(slowStart.IsEndOfRound(packetNumber)).To(BeTrue()) + }) + + It("works with delay", func() { + rtt := 60 * time.Millisecond + // We expect to detect the increase at +1/8 of the RTT; hence at a typical + // RTT of 60ms the detection will happen at 67.5 ms. + const hybridStartMinSamples = 8 // Number of acks required to trigger. + + endPacketNumber := protocol.PacketNumber(1) + endPacketNumber++ + slowStart.StartReceiveRound(endPacketNumber) + + // Will not trigger since our lowest RTT in our burst is the same as the long + // term RTT provided. + for n := 0; n < hybridStartMinSamples; n++ { + Expect(slowStart.ShouldExitSlowStart(rtt+time.Duration(n)*time.Millisecond, rtt, 100)).To(BeFalse()) + } + endPacketNumber++ + slowStart.StartReceiveRound(endPacketNumber) + for n := 1; n < hybridStartMinSamples; n++ { + Expect(slowStart.ShouldExitSlowStart(rtt+(time.Duration(n)+10)*time.Millisecond, rtt, 100)).To(BeFalse()) + } + // Expect to trigger since all packets in this burst was above the long term + // RTT provided. + Expect(slowStart.ShouldExitSlowStart(rtt+10*time.Millisecond, rtt, 100)).To(BeTrue()) + }) + +}) diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/interface.go b/vendor/lucas-clemente/quic-go/internal/congestion/interface.go new file mode 100644 index 00000000..7c27da64 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/interface.go @@ -0,0 +1,36 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// A SendAlgorithm performs congestion control and calculates the congestion window +type SendAlgorithm interface { + TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration + OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool) + GetCongestionWindow() protocol.ByteCount + MaybeExitSlowStart() + OnPacketAcked(number protocol.PacketNumber, ackedBytes protocol.ByteCount, priorInFlight protocol.ByteCount, eventTime time.Time) + OnPacketLost(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount) + SetNumEmulatedConnections(n int) + OnRetransmissionTimeout(packetsRetransmitted bool) + OnConnectionMigration() + + // Experiments + SetSlowStartLargeReduction(enabled bool) +} + +// SendAlgorithmWithDebugInfo adds some debug functions to SendAlgorithm +type SendAlgorithmWithDebugInfo interface { + SendAlgorithm + BandwidthEstimate() Bandwidth + + // Stuff only used in testing + + HybridSlowStart() *HybridSlowStart + SlowstartThreshold() protocol.ByteCount + RenoBeta() float32 + InRecovery() bool +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/prr_sender.go b/vendor/lucas-clemente/quic-go/internal/congestion/prr_sender.go new file mode 100644 index 00000000..5c807d19 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/prr_sender.go @@ -0,0 +1,54 @@ +package congestion + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// PrrSender implements the Proportional Rate Reduction (PRR) per RFC 6937 +type PrrSender struct { + bytesSentSinceLoss protocol.ByteCount + bytesDeliveredSinceLoss protocol.ByteCount + ackCountSinceLoss protocol.ByteCount + bytesInFlightBeforeLoss protocol.ByteCount +} + +// OnPacketSent should be called after a packet was sent +func (p *PrrSender) OnPacketSent(sentBytes protocol.ByteCount) { + p.bytesSentSinceLoss += sentBytes +} + +// OnPacketLost should be called on the first loss that triggers a recovery +// period and all other methods in this class should only be called when in +// recovery. +func (p *PrrSender) OnPacketLost(priorInFlight protocol.ByteCount) { + p.bytesSentSinceLoss = 0 + p.bytesInFlightBeforeLoss = priorInFlight + p.bytesDeliveredSinceLoss = 0 + p.ackCountSinceLoss = 0 +} + +// OnPacketAcked should be called after a packet was acked +func (p *PrrSender) OnPacketAcked(ackedBytes protocol.ByteCount) { + p.bytesDeliveredSinceLoss += ackedBytes + p.ackCountSinceLoss++ +} + +// CanSend returns if packets can be sent +func (p *PrrSender) CanSend(congestionWindow, bytesInFlight, slowstartThreshold protocol.ByteCount) bool { + // Return QuicTime::Zero In order to ensure limited transmit always works. + if p.bytesSentSinceLoss == 0 || bytesInFlight < protocol.DefaultTCPMSS { + return true + } + if congestionWindow > bytesInFlight { + // During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead + // of sending the entire available window. This prevents burst retransmits + // when more packets are lost than the CWND reduction. + // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS + return p.bytesDeliveredSinceLoss+p.ackCountSinceLoss*protocol.DefaultTCPMSS > p.bytesSentSinceLoss + } + // Implement Proportional Rate Reduction (RFC6937). + // Checks a simplified version of the PRR formula that doesn't use division: + // AvailableSendWindow = + // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent + return p.bytesDeliveredSinceLoss*slowstartThreshold > p.bytesSentSinceLoss*p.bytesInFlightBeforeLoss +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/prr_sender_test.go b/vendor/lucas-clemente/quic-go/internal/congestion/prr_sender_test.go new file mode 100644 index 00000000..0786b9bd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/prr_sender_test.go @@ -0,0 +1,107 @@ +package congestion + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +var _ = Describe("PRR sender", func() { + var ( + prr PrrSender + ) + + BeforeEach(func() { + prr = PrrSender{} + }) + + It("single loss results in send on every other ack", func() { + numPacketsInFlight := protocol.ByteCount(50) + bytesInFlight := numPacketsInFlight * protocol.DefaultTCPMSS + sshthreshAfterLoss := numPacketsInFlight / 2 + congestionWindow := sshthreshAfterLoss * protocol.DefaultTCPMSS + + prr.OnPacketLost(bytesInFlight) + // Ack a packet. PRR allows one packet to leave immediately. + prr.OnPacketAcked(protocol.DefaultTCPMSS) + bytesInFlight -= protocol.DefaultTCPMSS + Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeTrue()) + // Send retransmission. + prr.OnPacketSent(protocol.DefaultTCPMSS) + // PRR shouldn't allow sending any more packets. + Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeFalse()) + + // One packet is lost, and one ack was consumed above. PRR now paces + // transmissions through the remaining 48 acks. PRR will alternatively + // disallow and allow a packet to be sent in response to an ack. + for i := protocol.ByteCount(0); i < sshthreshAfterLoss-1; i++ { + // Ack a packet. PRR shouldn't allow sending a packet in response. + prr.OnPacketAcked(protocol.DefaultTCPMSS) + bytesInFlight -= protocol.DefaultTCPMSS + Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeFalse()) + // Ack another packet. PRR should now allow sending a packet in response. + prr.OnPacketAcked(protocol.DefaultTCPMSS) + bytesInFlight -= protocol.DefaultTCPMSS + Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeTrue()) + // Send a packet in response. + prr.OnPacketSent(protocol.DefaultTCPMSS) + bytesInFlight += protocol.DefaultTCPMSS + } + + // Since bytes_in_flight is now equal to congestion_window, PRR now maintains + // packet conservation, allowing one packet to be sent in response to an ack. + Expect(bytesInFlight).To(Equal(congestionWindow)) + for i := 0; i < 10; i++ { + // Ack a packet. + prr.OnPacketAcked(protocol.DefaultTCPMSS) + bytesInFlight -= protocol.DefaultTCPMSS + Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeTrue()) + // Send a packet in response, since PRR allows it. + prr.OnPacketSent(protocol.DefaultTCPMSS) + bytesInFlight += protocol.DefaultTCPMSS + + // Since bytes_in_flight is equal to the congestion_window, + // PRR disallows sending. + Expect(bytesInFlight).To(Equal(congestionWindow)) + Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeFalse()) + } + + }) + + It("burst loss results in slow start", func() { + bytesInFlight := protocol.ByteCount(20 * protocol.DefaultTCPMSS) + const numPacketsLost = 13 + const ssthreshAfterLoss = 10 + const congestionWindow = ssthreshAfterLoss * protocol.DefaultTCPMSS + + // Lose 13 packets. + bytesInFlight -= numPacketsLost * protocol.DefaultTCPMSS + prr.OnPacketLost(bytesInFlight) + + // PRR-SSRB will allow the following 3 acks to send up to 2 packets. + for i := 0; i < 3; i++ { + prr.OnPacketAcked(protocol.DefaultTCPMSS) + bytesInFlight -= protocol.DefaultTCPMSS + // PRR-SSRB should allow two packets to be sent. + for j := 0; j < 2; j++ { + Expect(prr.CanSend(congestionWindow, bytesInFlight, ssthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeTrue()) + // Send a packet in response. + prr.OnPacketSent(protocol.DefaultTCPMSS) + bytesInFlight += protocol.DefaultTCPMSS + } + // PRR should allow no more than 2 packets in response to an ack. + Expect(prr.CanSend(congestionWindow, bytesInFlight, ssthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeFalse()) + } + + // Out of SSRB mode, PRR allows one send in response to each ack. + for i := 0; i < 10; i++ { + prr.OnPacketAcked(protocol.DefaultTCPMSS) + bytesInFlight -= protocol.DefaultTCPMSS + Expect(prr.CanSend(congestionWindow, bytesInFlight, ssthreshAfterLoss*protocol.DefaultTCPMSS)).To(BeTrue()) + // Send a packet in response. + prr.OnPacketSent(protocol.DefaultTCPMSS) + bytesInFlight += protocol.DefaultTCPMSS + } + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats.go b/vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats.go new file mode 100644 index 00000000..f0ebbb23 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats.go @@ -0,0 +1,101 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/utils" +) + +const ( + rttAlpha float32 = 0.125 + oneMinusAlpha float32 = (1 - rttAlpha) + rttBeta float32 = 0.25 + oneMinusBeta float32 = (1 - rttBeta) + // The default RTT used before an RTT sample is taken. + defaultInitialRTT = 100 * time.Millisecond +) + +// RTTStats provides round-trip statistics +type RTTStats struct { + minRTT time.Duration + latestRTT time.Duration + smoothedRTT time.Duration + meanDeviation time.Duration +} + +// NewRTTStats makes a properly initialized RTTStats object +func NewRTTStats() *RTTStats { + return &RTTStats{} +} + +// MinRTT Returns the minRTT for the entire connection. +// May return Zero if no valid updates have occurred. +func (r *RTTStats) MinRTT() time.Duration { return r.minRTT } + +// LatestRTT returns the most recent rtt measurement. +// May return Zero if no valid updates have occurred. +func (r *RTTStats) LatestRTT() time.Duration { return r.latestRTT } + +// SmoothedRTT returns the EWMA smoothed RTT for the connection. +// May return Zero if no valid updates have occurred. +func (r *RTTStats) SmoothedRTT() time.Duration { return r.smoothedRTT } + +// SmoothedOrInitialRTT returns the EWMA smoothed RTT for the connection. +// If no valid updates have occurred, it returns the initial RTT. +func (r *RTTStats) SmoothedOrInitialRTT() time.Duration { + if r.smoothedRTT != 0 { + return r.smoothedRTT + } + return defaultInitialRTT +} + +// MeanDeviation gets the mean deviation +func (r *RTTStats) MeanDeviation() time.Duration { return r.meanDeviation } + +// UpdateRTT updates the RTT based on a new sample. +func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration, now time.Time) { + if sendDelta == utils.InfDuration || sendDelta <= 0 { + return + } + + // Update r.minRTT first. r.minRTT does not use an rttSample corrected for + // ackDelay but the raw observed sendDelta, since poor clock granularity at + // the client may cause a high ackDelay to result in underestimation of the + // r.minRTT. + if r.minRTT == 0 || r.minRTT > sendDelta { + r.minRTT = sendDelta + } + + // Correct for ackDelay if information received from the peer results in a + // an RTT sample at least as large as minRTT. Otherwise, only use the + // sendDelta. + sample := sendDelta + if sample-r.minRTT >= ackDelay { + sample -= ackDelay + } + r.latestRTT = sample + // First time call. + if r.smoothedRTT == 0 { + r.smoothedRTT = sample + r.meanDeviation = sample / 2 + } else { + r.meanDeviation = time.Duration(oneMinusBeta*float32(r.meanDeviation/time.Microsecond)+rttBeta*float32(utils.AbsDuration(r.smoothedRTT-sample)/time.Microsecond)) * time.Microsecond + r.smoothedRTT = time.Duration((float32(r.smoothedRTT/time.Microsecond)*oneMinusAlpha)+(float32(sample/time.Microsecond)*rttAlpha)) * time.Microsecond + } +} + +// OnConnectionMigration is called when connection migrates and rtt measurement needs to be reset. +func (r *RTTStats) OnConnectionMigration() { + r.latestRTT = 0 + r.minRTT = 0 + r.smoothedRTT = 0 + r.meanDeviation = 0 +} + +// ExpireSmoothedMetrics causes the smoothed_rtt to be increased to the latest_rtt if the latest_rtt +// is larger. The mean deviation is increased to the most recent deviation if +// it's larger. +func (r *RTTStats) ExpireSmoothedMetrics() { + r.meanDeviation = utils.MaxDuration(r.meanDeviation, utils.AbsDuration(r.smoothedRTT-r.latestRTT)) + r.smoothedRTT = utils.MaxDuration(r.smoothedRTT, r.latestRTT) +} diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats_test.go b/vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats_test.go new file mode 100644 index 00000000..e8f8c69c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/rtt_stats_test.go @@ -0,0 +1,131 @@ +package congestion + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("RTT stats", func() { + var ( + rttStats *RTTStats + ) + + BeforeEach(func() { + rttStats = NewRTTStats() + }) + + It("DefaultsBeforeUpdate", func() { + Expect(rttStats.MinRTT()).To(Equal(time.Duration(0))) + Expect(rttStats.SmoothedRTT()).To(Equal(time.Duration(0))) + }) + + It("SmoothedRTT", func() { + // Verify that ack_delay is ignored in the first measurement. + rttStats.UpdateRTT((300 * time.Millisecond), (100 * time.Millisecond), time.Time{}) + Expect(rttStats.LatestRTT()).To(Equal((300 * time.Millisecond))) + Expect(rttStats.SmoothedRTT()).To(Equal((300 * time.Millisecond))) + // Verify that Smoothed RTT includes max ack delay if it's reasonable. + rttStats.UpdateRTT((350 * time.Millisecond), (50 * time.Millisecond), time.Time{}) + Expect(rttStats.LatestRTT()).To(Equal((300 * time.Millisecond))) + Expect(rttStats.SmoothedRTT()).To(Equal((300 * time.Millisecond))) + // Verify that large erroneous ack_delay does not change Smoothed RTT. + rttStats.UpdateRTT((200 * time.Millisecond), (300 * time.Millisecond), time.Time{}) + Expect(rttStats.LatestRTT()).To(Equal((200 * time.Millisecond))) + Expect(rttStats.SmoothedRTT()).To(Equal((287500 * time.Microsecond))) + }) + + It("SmoothedOrInitialRTT", func() { + Expect(rttStats.SmoothedOrInitialRTT()).To(Equal(defaultInitialRTT)) + rttStats.UpdateRTT((300 * time.Millisecond), (100 * time.Millisecond), time.Time{}) + Expect(rttStats.SmoothedOrInitialRTT()).To(Equal((300 * time.Millisecond))) + }) + + It("MinRTT", func() { + rttStats.UpdateRTT((200 * time.Millisecond), 0, time.Time{}) + Expect(rttStats.MinRTT()).To(Equal((200 * time.Millisecond))) + rttStats.UpdateRTT((10 * time.Millisecond), 0, time.Time{}.Add((10 * time.Millisecond))) + Expect(rttStats.MinRTT()).To(Equal((10 * time.Millisecond))) + rttStats.UpdateRTT((50 * time.Millisecond), 0, time.Time{}.Add((20 * time.Millisecond))) + Expect(rttStats.MinRTT()).To(Equal((10 * time.Millisecond))) + rttStats.UpdateRTT((50 * time.Millisecond), 0, time.Time{}.Add((30 * time.Millisecond))) + Expect(rttStats.MinRTT()).To(Equal((10 * time.Millisecond))) + rttStats.UpdateRTT((50 * time.Millisecond), 0, time.Time{}.Add((40 * time.Millisecond))) + Expect(rttStats.MinRTT()).To(Equal((10 * time.Millisecond))) + // Verify that ack_delay does not go into recording of MinRTT_. + rttStats.UpdateRTT((7 * time.Millisecond), (2 * time.Millisecond), time.Time{}.Add((50 * time.Millisecond))) + Expect(rttStats.MinRTT()).To(Equal((7 * time.Millisecond))) + }) + + It("ExpireSmoothedMetrics", func() { + initialRtt := (10 * time.Millisecond) + rttStats.UpdateRTT(initialRtt, 0, time.Time{}) + Expect(rttStats.MinRTT()).To(Equal(initialRtt)) + Expect(rttStats.SmoothedRTT()).To(Equal(initialRtt)) + + Expect(rttStats.MeanDeviation()).To(Equal(initialRtt / 2)) + + // Update once with a 20ms RTT. + doubledRtt := initialRtt * (2) + rttStats.UpdateRTT(doubledRtt, 0, time.Time{}) + Expect(rttStats.SmoothedRTT()).To(Equal(time.Duration(float32(initialRtt) * 1.125))) + + // Expire the smoothed metrics, increasing smoothed rtt and mean deviation. + rttStats.ExpireSmoothedMetrics() + Expect(rttStats.SmoothedRTT()).To(Equal(doubledRtt)) + Expect(rttStats.MeanDeviation()).To(Equal(time.Duration(float32(initialRtt) * 0.875))) + + // Now go back down to 5ms and expire the smoothed metrics, and ensure the + // mean deviation increases to 15ms. + halfRtt := initialRtt / 2 + rttStats.UpdateRTT(halfRtt, 0, time.Time{}) + Expect(doubledRtt).To(BeNumerically(">", rttStats.SmoothedRTT())) + Expect(initialRtt).To(BeNumerically("<", rttStats.MeanDeviation())) + }) + + It("UpdateRTTWithBadSendDeltas", func() { + // Make sure we ignore bad RTTs. + // base::test::MockLog log; + + initialRtt := (10 * time.Millisecond) + rttStats.UpdateRTT(initialRtt, 0, time.Time{}) + Expect(rttStats.MinRTT()).To(Equal(initialRtt)) + Expect(rttStats.SmoothedRTT()).To(Equal(initialRtt)) + + badSendDeltas := []time.Duration{ + 0, + utils.InfDuration, + -1000 * time.Microsecond, + } + // log.StartCapturingLogs(); + + for _, badSendDelta := range badSendDeltas { + // SCOPED_TRACE(Message() << "bad_send_delta = " + // << bad_send_delta.ToMicroseconds()); + // EXPECT_CALL(log, Log(LOG_WARNING, _, _, _, HasSubstr("Ignoring"))); + rttStats.UpdateRTT(badSendDelta, 0, time.Time{}) + Expect(rttStats.MinRTT()).To(Equal(initialRtt)) + Expect(rttStats.SmoothedRTT()).To(Equal(initialRtt)) + } + }) + + It("ResetAfterConnectionMigrations", func() { + rttStats.UpdateRTT((200 * time.Millisecond), 0, time.Time{}) + Expect(rttStats.LatestRTT()).To(Equal((200 * time.Millisecond))) + Expect(rttStats.SmoothedRTT()).To(Equal((200 * time.Millisecond))) + Expect(rttStats.MinRTT()).To(Equal((200 * time.Millisecond))) + rttStats.UpdateRTT((300 * time.Millisecond), (100 * time.Millisecond), time.Time{}) + Expect(rttStats.LatestRTT()).To(Equal((200 * time.Millisecond))) + Expect(rttStats.SmoothedRTT()).To(Equal((200 * time.Millisecond))) + Expect(rttStats.MinRTT()).To(Equal((200 * time.Millisecond))) + + // Reset rtt stats on connection migrations. + rttStats.OnConnectionMigration() + Expect(rttStats.LatestRTT()).To(Equal(time.Duration(0))) + Expect(rttStats.SmoothedRTT()).To(Equal(time.Duration(0))) + Expect(rttStats.MinRTT()).To(Equal(time.Duration(0))) + }) + +}) diff --git a/vendor/lucas-clemente/quic-go/internal/congestion/stats.go b/vendor/lucas-clemente/quic-go/internal/congestion/stats.go new file mode 100644 index 00000000..ed669c14 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/congestion/stats.go @@ -0,0 +1,8 @@ +package congestion + +import "github.com/lucas-clemente/quic-go/internal/protocol" + +type connectionStats struct { + slowstartPacketsLost protocol.PacketNumber + slowstartBytesLost protocol.ByteCount +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/AEAD.go b/vendor/lucas-clemente/quic-go/internal/crypto/AEAD.go new file mode 100644 index 00000000..d1905159 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/AEAD.go @@ -0,0 +1,10 @@ +package crypto + +import "github.com/lucas-clemente/quic-go/internal/protocol" + +// An AEAD implements QUIC's authenticated encryption and associated data +type AEAD interface { + Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) + Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte + Overhead() int +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead.go b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead.go new file mode 100644 index 00000000..55e45be6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead.go @@ -0,0 +1,72 @@ +package crypto + +import ( + "crypto/cipher" + "encoding/binary" + "errors" + + "github.com/lucas-clemente/aes12" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +type aeadAESGCM12 struct { + otherIV []byte + myIV []byte + encrypter cipher.AEAD + decrypter cipher.AEAD +} + +var _ AEAD = &aeadAESGCM12{} + +// NewAEADAESGCM12 creates a AEAD using AES-GCM with 12 bytes tag size +// +// AES-GCM support is a bit hacky, since the go stdlib does not support 12 byte +// tag size, and couples the cipher and aes packages closely. +// See https://github.com/lucas-clemente/aes12. +func NewAEADAESGCM12(otherKey []byte, myKey []byte, otherIV []byte, myIV []byte) (AEAD, error) { + if len(myKey) != 16 || len(otherKey) != 16 || len(myIV) != 4 || len(otherIV) != 4 { + return nil, errors.New("AES-GCM: expected 16-byte keys and 4-byte IVs") + } + encrypterCipher, err := aes12.NewCipher(myKey) + if err != nil { + return nil, err + } + encrypter, err := aes12.NewGCM(encrypterCipher) + if err != nil { + return nil, err + } + decrypterCipher, err := aes12.NewCipher(otherKey) + if err != nil { + return nil, err + } + decrypter, err := aes12.NewGCM(decrypterCipher) + if err != nil { + return nil, err + } + return &aeadAESGCM12{ + otherIV: otherIV, + myIV: myIV, + encrypter: encrypter, + decrypter: decrypter, + }, nil +} + +func (aead *aeadAESGCM12) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { + return aead.decrypter.Open(dst, aead.makeNonce(aead.otherIV, packetNumber), src, associatedData) +} + +func (aead *aeadAESGCM12) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte { + return aead.encrypter.Seal(dst, aead.makeNonce(aead.myIV, packetNumber), src, associatedData) +} + +func (aead *aeadAESGCM12) makeNonce(iv []byte, packetNumber protocol.PacketNumber) []byte { + res := make([]byte, 12) + copy(res[0:4], iv) + binary.LittleEndian.PutUint64(res[4:12], uint64(packetNumber)) + return res +} + +func (aead *aeadAESGCM12) Overhead() int { + return aead.encrypter.Overhead() +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead_test.go new file mode 100644 index 00000000..6b896a52 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm12_aead_test.go @@ -0,0 +1,69 @@ +package crypto + +import ( + "crypto/rand" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("AES-GCM", func() { + var ( + alice, bob AEAD + keyAlice, keyBob, ivAlice, ivBob []byte + ) + + BeforeEach(func() { + keyAlice = make([]byte, 16) + keyBob = make([]byte, 16) + ivAlice = make([]byte, 4) + ivBob = make([]byte, 4) + rand.Reader.Read(keyAlice) + rand.Reader.Read(keyBob) + rand.Reader.Read(ivAlice) + rand.Reader.Read(ivBob) + var err error + alice, err = NewAEADAESGCM12(keyBob, keyAlice, ivBob, ivAlice) + Expect(err).ToNot(HaveOccurred()) + bob, err = NewAEADAESGCM12(keyAlice, keyBob, ivAlice, ivBob) + Expect(err).ToNot(HaveOccurred()) + }) + + It("seals and opens", func() { + b := alice.Seal(nil, []byte("foobar"), 42, []byte("aad")) + text, err := bob.Open(nil, b, 42, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(text).To(Equal([]byte("foobar"))) + }) + + It("seals and opens reverse", func() { + b := bob.Seal(nil, []byte("foobar"), 42, []byte("aad")) + text, err := alice.Open(nil, b, 42, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(text).To(Equal([]byte("foobar"))) + }) + + It("has the proper length", func() { + b := bob.Seal(nil, []byte("foobar"), 42, []byte("aad")) + Expect(b).To(HaveLen(6 + bob.Overhead())) + }) + + It("fails with wrong aad", func() { + b := alice.Seal(nil, []byte("foobar"), 42, []byte("aad")) + _, err := bob.Open(nil, b, 42, []byte("aad2")) + Expect(err).To(HaveOccurred()) + }) + + It("rejects wrong key and iv sizes", func() { + var err error + e := "AES-GCM: expected 16-byte keys and 4-byte IVs" + _, err = NewAEADAESGCM12(keyBob[1:], keyAlice, ivBob, ivAlice) + Expect(err).To(MatchError(e)) + _, err = NewAEADAESGCM12(keyBob, keyAlice[1:], ivBob, ivAlice) + Expect(err).To(MatchError(e)) + _, err = NewAEADAESGCM12(keyBob, keyAlice, ivBob[1:], ivAlice) + Expect(err).To(MatchError(e)) + _, err = NewAEADAESGCM12(keyBob, keyAlice, ivBob, ivAlice[1:]) + Expect(err).To(MatchError(e)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead.go b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead.go new file mode 100644 index 00000000..d55974e6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead.go @@ -0,0 +1,74 @@ +package crypto + +import ( + "crypto/aes" + "crypto/cipher" + "encoding/binary" + "errors" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +type aeadAESGCM struct { + otherIV []byte + myIV []byte + encrypter cipher.AEAD + decrypter cipher.AEAD +} + +var _ AEAD = &aeadAESGCM{} + +const ivLen = 12 + +// NewAEADAESGCM creates a AEAD using AES-GCM +func NewAEADAESGCM(otherKey []byte, myKey []byte, otherIV []byte, myIV []byte) (AEAD, error) { + // the IVs need to be at least 8 bytes long, otherwise we can't compute the nonce + if len(otherIV) != ivLen || len(myIV) != ivLen { + return nil, errors.New("AES-GCM: expected 12 byte IVs") + } + + encrypterCipher, err := aes.NewCipher(myKey) + if err != nil { + return nil, err + } + encrypter, err := cipher.NewGCM(encrypterCipher) + if err != nil { + return nil, err + } + decrypterCipher, err := aes.NewCipher(otherKey) + if err != nil { + return nil, err + } + decrypter, err := cipher.NewGCM(decrypterCipher) + if err != nil { + return nil, err + } + + return &aeadAESGCM{ + otherIV: otherIV, + myIV: myIV, + encrypter: encrypter, + decrypter: decrypter, + }, nil +} + +func (aead *aeadAESGCM) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { + return aead.decrypter.Open(dst, aead.makeNonce(aead.otherIV, packetNumber), src, associatedData) +} + +func (aead *aeadAESGCM) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte { + return aead.encrypter.Seal(dst, aead.makeNonce(aead.myIV, packetNumber), src, associatedData) +} + +func (aead *aeadAESGCM) makeNonce(iv []byte, packetNumber protocol.PacketNumber) []byte { + nonce := make([]byte, ivLen) + binary.BigEndian.PutUint64(nonce[ivLen-8:], uint64(packetNumber)) + for i := 0; i < ivLen; i++ { + nonce[i] ^= iv[i] + } + return nonce +} + +func (aead *aeadAESGCM) Overhead() int { + return aead.encrypter.Overhead() +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead_test.go new file mode 100644 index 00000000..6b7fa100 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/aesgcm_aead_test.go @@ -0,0 +1,84 @@ +package crypto + +import ( + "crypto/rand" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("AES-GCM", func() { + var ( + alice, bob AEAD + keyAlice, keyBob, ivAlice, ivBob []byte + ) + + BeforeEach(func() { + ivAlice = make([]byte, 12) + ivBob = make([]byte, 12) + }) + + // 16 bytes for TLS_AES_128_GCM_SHA256 + // 32 bytes for TLS_AES_256_GCM_SHA384 + for _, ks := range []int{16, 32} { + keySize := ks + + Context(fmt.Sprintf("with %d byte keys", keySize), func() { + BeforeEach(func() { + keyAlice = make([]byte, keySize) + keyBob = make([]byte, keySize) + rand.Reader.Read(keyAlice) + rand.Reader.Read(keyBob) + rand.Reader.Read(ivAlice) + rand.Reader.Read(ivBob) + var err error + alice, err = NewAEADAESGCM(keyBob, keyAlice, ivBob, ivAlice) + Expect(err).ToNot(HaveOccurred()) + bob, err = NewAEADAESGCM(keyAlice, keyBob, ivAlice, ivBob) + Expect(err).ToNot(HaveOccurred()) + }) + + It("seals and opens", func() { + b := alice.Seal(nil, []byte("foobar"), 42, []byte("aad")) + text, err := bob.Open(nil, b, 42, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(text).To(Equal([]byte("foobar"))) + }) + + It("seals and opens reverse", func() { + b := bob.Seal(nil, []byte("foobar"), 42, []byte("aad")) + text, err := alice.Open(nil, b, 42, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(text).To(Equal([]byte("foobar"))) + }) + + It("has the proper length", func() { + b := bob.Seal(nil, []byte("foobar"), 42, []byte("aad")) + Expect(b).To(HaveLen(6 + bob.Overhead())) + }) + + It("fails with wrong aad", func() { + b := alice.Seal(nil, []byte("foobar"), 42, []byte("aad")) + _, err := bob.Open(nil, b, 42, []byte("aad2")) + Expect(err).To(HaveOccurred()) + }) + + It("rejects wrong key and iv sizes", func() { + e := "AES-GCM: expected 12 byte IVs" + var err error + _, err = NewAEADAESGCM(keyBob, keyAlice, ivBob[1:], ivAlice) + Expect(err).To(MatchError(e)) + _, err = NewAEADAESGCM(keyBob, keyAlice, ivBob, ivAlice[1:]) + Expect(err).To(MatchError(e)) + }) + }) + } + + It("errors when an invalid key size is used", func() { + keyAlice = make([]byte, 17) + keyBob = make([]byte, 17) + _, err := NewAEADAESGCM(keyBob, keyAlice, ivBob, ivAlice) + Expect(err).To(MatchError("crypto/aes: invalid key size 17")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_cache.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_cache.go new file mode 100644 index 00000000..d8e8d8f3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_cache.go @@ -0,0 +1,48 @@ +package crypto + +import ( + "fmt" + "hash/fnv" + + "github.com/hashicorp/golang-lru" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +var ( + compressedCertsCache *lru.Cache +) + +func getCompressedCert(chain [][]byte, pCommonSetHashes, pCachedHashes []byte) ([]byte, error) { + // Hash all inputs + hasher := fnv.New64a() + for _, v := range chain { + hasher.Write(v) + } + hasher.Write(pCommonSetHashes) + hasher.Write(pCachedHashes) + hash := hasher.Sum64() + + var result []byte + + resultI, isCached := compressedCertsCache.Get(hash) + if isCached { + result = resultI.([]byte) + } else { + var err error + result, err = compressChain(chain, pCommonSetHashes, pCachedHashes) + if err != nil { + return nil, err + } + compressedCertsCache.Add(hash, result) + } + + return result, nil +} + +func init() { + var err error + compressedCertsCache, err = lru.New(protocol.NumCachedCertificates) + if err != nil { + panic(fmt.Sprintf("fatal error in quic-go: could not create lru cache: %s", err.Error())) + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_cache_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_cache_test.go new file mode 100644 index 00000000..1ecc26f6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_cache_test.go @@ -0,0 +1,51 @@ +package crypto + +import ( + lru "github.com/hashicorp/golang-lru" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Certificate cache", func() { + BeforeEach(func() { + var err error + compressedCertsCache, err = lru.New(2) + Expect(err).NotTo(HaveOccurred()) + }) + + It("gives a compressed cert", func() { + chain := [][]byte{{0xde, 0xca, 0xfb, 0xad}} + expected, err := compressChain(chain, nil, nil) + Expect(err).NotTo(HaveOccurred()) + compressed, err := getCompressedCert(chain, nil, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(compressed).To(Equal(expected)) + }) + + It("gets the same result multiple times", func() { + chain := [][]byte{{0xde, 0xca, 0xfb, 0xad}} + compressed, err := getCompressedCert(chain, nil, nil) + Expect(err).NotTo(HaveOccurred()) + compressed2, err := getCompressedCert(chain, nil, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(compressed).To(Equal(compressed2)) + }) + + It("stores cached values", func() { + chain := [][]byte{{0xde, 0xca, 0xfb, 0xad}} + _, err := getCompressedCert(chain, nil, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(compressedCertsCache.Len()).To(Equal(1)) + Expect(compressedCertsCache.Contains(uint64(3838929964809501833))).To(BeTrue()) + }) + + It("evicts old values", func() { + _, err := getCompressedCert([][]byte{{0x00}}, nil, nil) + Expect(err).NotTo(HaveOccurred()) + _, err = getCompressedCert([][]byte{{0x01}}, nil, nil) + Expect(err).NotTo(HaveOccurred()) + _, err = getCompressedCert([][]byte{{0x02}}, nil, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(compressedCertsCache.Len()).To(Equal(2)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_chain.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_chain.go new file mode 100644 index 00000000..0c728fd2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_chain.go @@ -0,0 +1,113 @@ +package crypto + +import ( + "crypto/tls" + "errors" + "strings" +) + +// A CertChain holds a certificate and a private key +type CertChain interface { + SignServerProof(sni string, chlo []byte, serverConfigData []byte) ([]byte, error) + GetCertsCompressed(sni string, commonSetHashes, cachedHashes []byte) ([]byte, error) + GetLeafCert(sni string) ([]byte, error) +} + +// proofSource stores a key and a certificate for the server proof +type certChain struct { + config *tls.Config +} + +var _ CertChain = &certChain{} + +var errNoMatchingCertificate = errors.New("no matching certificate found") + +// NewCertChain loads the key and cert from files +func NewCertChain(tlsConfig *tls.Config) CertChain { + return &certChain{config: tlsConfig} +} + +// SignServerProof signs CHLO and server config for use in the server proof +func (c *certChain) SignServerProof(sni string, chlo []byte, serverConfigData []byte) ([]byte, error) { + cert, err := c.getCertForSNI(sni) + if err != nil { + return nil, err + } + + return signServerProof(cert, chlo, serverConfigData) +} + +// GetCertsCompressed gets the certificate in the format described by the QUIC crypto doc +func (c *certChain) GetCertsCompressed(sni string, pCommonSetHashes, pCachedHashes []byte) ([]byte, error) { + cert, err := c.getCertForSNI(sni) + if err != nil { + return nil, err + } + return getCompressedCert(cert.Certificate, pCommonSetHashes, pCachedHashes) +} + +// GetLeafCert gets the leaf certificate +func (c *certChain) GetLeafCert(sni string) ([]byte, error) { + cert, err := c.getCertForSNI(sni) + if err != nil { + return nil, err + } + return cert.Certificate[0], nil +} + +func (c *certChain) getCertForSNI(sni string) (*tls.Certificate, error) { + conf := c.config + conf, err := maybeGetConfigForClient(conf, sni) + if err != nil { + return nil, err + } + // The rest of this function is mostly copied from crypto/tls.getCertificate + + if conf.GetCertificate != nil { + cert, err := conf.GetCertificate(&tls.ClientHelloInfo{ServerName: sni}) + if cert != nil || err != nil { + return cert, err + } + } + + if len(conf.Certificates) == 0 { + return nil, errNoMatchingCertificate + } + + if len(conf.Certificates) == 1 || conf.NameToCertificate == nil { + // There's only one choice, so no point doing any work. + return &conf.Certificates[0], nil + } + + name := strings.ToLower(sni) + for len(name) > 0 && name[len(name)-1] == '.' { + name = name[:len(name)-1] + } + + if cert, ok := conf.NameToCertificate[name]; ok { + return cert, nil + } + + // try replacing labels in the name with wildcards until we get a + // match. + labels := strings.Split(name, ".") + for i := range labels { + labels[i] = "*" + candidate := strings.Join(labels, ".") + if cert, ok := conf.NameToCertificate[candidate]; ok { + return cert, nil + } + } + + // If nothing matches, return the first certificate. + return &conf.Certificates[0], nil +} + +func maybeGetConfigForClient(c *tls.Config, sni string) (*tls.Config, error) { + if c.GetConfigForClient == nil { + return c, nil + } + return c.GetConfigForClient(&tls.ClientHelloInfo{ + ServerName: sni, + }) +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_chain_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_chain_test.go new file mode 100644 index 00000000..fd60a46a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_chain_test.go @@ -0,0 +1,148 @@ +package crypto + +import ( + "bytes" + "compress/flate" + "compress/zlib" + "crypto/tls" + "reflect" + + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Proof", func() { + var ( + cc *certChain + config *tls.Config + cert tls.Certificate + ) + + BeforeEach(func() { + cert = testdata.GetCertificate() + config = &tls.Config{} + cc = NewCertChain(config).(*certChain) + }) + + Context("certificate compression", func() { + It("compresses certs", func() { + cert := []byte{0xde, 0xca, 0xfb, 0xad} + certZlib := &bytes.Buffer{} + z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, certDictZlib) + Expect(err).ToNot(HaveOccurred()) + z.Write([]byte{0x04, 0x00, 0x00, 0x00}) + z.Write(cert) + z.Close() + kd := &certChain{ + config: &tls.Config{ + Certificates: []tls.Certificate{ + {Certificate: [][]byte{cert}}, + }, + }, + } + certCompressed, err := kd.GetCertsCompressed("", nil, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(certCompressed).To(Equal(append([]byte{ + 0x01, 0x00, + 0x08, 0x00, 0x00, 0x00, + }, certZlib.Bytes()...))) + }) + + It("errors when it can't retrieve a certificate", func() { + _, err := cc.GetCertsCompressed("invalid domain", nil, nil) + Expect(err).To(MatchError(errNoMatchingCertificate)) + }) + }) + + Context("signing server configs", func() { + It("errors when it can't retrieve a certificate for the requested SNI", func() { + _, err := cc.SignServerProof("invalid", []byte("chlo"), []byte("scfg")) + Expect(err).To(MatchError(errNoMatchingCertificate)) + }) + + It("signs the server config", func() { + config.Certificates = []tls.Certificate{cert} + proof, err := cc.SignServerProof("", []byte("chlo"), []byte("scfg")) + Expect(err).ToNot(HaveOccurred()) + Expect(proof).ToNot(BeEmpty()) + }) + }) + + Context("retrieving certificates", func() { + It("errors without certificates", func() { + _, err := cc.getCertForSNI("") + Expect(err).To(MatchError(errNoMatchingCertificate)) + }) + + It("uses first certificate in config.Certificates", func() { + config.Certificates = []tls.Certificate{cert} + cert, err := cc.getCertForSNI("") + Expect(err).ToNot(HaveOccurred()) + Expect(cert.PrivateKey).ToNot(BeNil()) + Expect(cert.Certificate[0]).ToNot(BeNil()) + }) + + It("uses NameToCertificate entries", func() { + config.Certificates = []tls.Certificate{cert, cert} // two entries so the long path is used + config.NameToCertificate = map[string]*tls.Certificate{ + "quic.clemente.io": &cert, + } + cert, err := cc.getCertForSNI("quic.clemente.io") + Expect(err).ToNot(HaveOccurred()) + Expect(cert.PrivateKey).ToNot(BeNil()) + Expect(cert.Certificate[0]).ToNot(BeNil()) + }) + + It("uses NameToCertificate entries with wildcard", func() { + config.Certificates = []tls.Certificate{cert, cert} // two entries so the long path is used + config.NameToCertificate = map[string]*tls.Certificate{ + "*.clemente.io": &cert, + } + cert, err := cc.getCertForSNI("quic.clemente.io") + Expect(err).ToNot(HaveOccurred()) + Expect(cert.PrivateKey).ToNot(BeNil()) + Expect(cert.Certificate[0]).ToNot(BeNil()) + }) + + It("uses GetCertificate", func() { + config.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { + Expect(clientHello.ServerName).To(Equal("quic.clemente.io")) + return &cert, nil + } + cert, err := cc.getCertForSNI("quic.clemente.io") + Expect(err).ToNot(HaveOccurred()) + Expect(cert.PrivateKey).ToNot(BeNil()) + Expect(cert.Certificate[0]).ToNot(BeNil()) + }) + + It("gets leaf certificates", func() { + config.Certificates = []tls.Certificate{cert} + cert2, err := cc.GetLeafCert("") + Expect(err).ToNot(HaveOccurred()) + Expect(cert2).To(Equal(cert.Certificate[0])) + }) + + It("errors when it can't retrieve a leaf certificate", func() { + _, err := cc.GetLeafCert("invalid domain") + Expect(err).To(MatchError(errNoMatchingCertificate)) + }) + + It("respects GetConfigForClient", func() { + if !reflect.ValueOf(tls.Config{}).FieldByName("GetConfigForClient").IsValid() { + // Pre 1.8, we don't have to do anything + return + } + nestedConfig := &tls.Config{Certificates: []tls.Certificate{cert}} + l := func(chi *tls.ClientHelloInfo) (*tls.Config, error) { + Expect(chi.ServerName).To(Equal("quic.clemente.io")) + return nestedConfig, nil + } + reflect.ValueOf(config).Elem().FieldByName("GetConfigForClient").Set(reflect.ValueOf(l)) + resultCert, err := cc.getCertForSNI("quic.clemente.io") + Expect(err).NotTo(HaveOccurred()) + Expect(*resultCert).To(Equal(cert)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_compression.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_compression.go new file mode 100644 index 00000000..908b7ce9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_compression.go @@ -0,0 +1,272 @@ +package crypto + +import ( + "bytes" + "compress/flate" + "compress/zlib" + "encoding/binary" + "errors" + "fmt" + "hash/fnv" + + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type entryType uint8 + +const ( + entryCompressed entryType = 1 + entryCached entryType = 2 + entryCommon entryType = 3 +) + +type entry struct { + t entryType + h uint64 // set hash + i uint32 // index +} + +func compressChain(chain [][]byte, pCommonSetHashes, pCachedHashes []byte) ([]byte, error) { + res := &bytes.Buffer{} + + cachedHashes, err := splitHashes(pCachedHashes) + if err != nil { + return nil, err + } + + setHashes, err := splitHashes(pCommonSetHashes) + if err != nil { + return nil, err + } + + chainHashes := make([]uint64, len(chain)) + for i := range chain { + chainHashes[i] = HashCert(chain[i]) + } + + entries := buildEntries(chain, chainHashes, cachedHashes, setHashes) + + totalUncompressedLen := 0 + for i, e := range entries { + res.WriteByte(uint8(e.t)) + switch e.t { + case entryCached: + utils.LittleEndian.WriteUint64(res, e.h) + case entryCommon: + utils.LittleEndian.WriteUint64(res, e.h) + utils.LittleEndian.WriteUint32(res, e.i) + case entryCompressed: + totalUncompressedLen += 4 + len(chain[i]) + } + } + res.WriteByte(0) // end of list + + if totalUncompressedLen > 0 { + gz, err := zlib.NewWriterLevelDict(res, flate.BestCompression, buildZlibDictForEntries(entries, chain)) + if err != nil { + return nil, fmt.Errorf("cert compression failed: %s", err.Error()) + } + + utils.LittleEndian.WriteUint32(res, uint32(totalUncompressedLen)) + + for i, e := range entries { + if e.t != entryCompressed { + continue + } + lenCert := len(chain[i]) + gz.Write([]byte{ + byte(lenCert & 0xff), + byte((lenCert >> 8) & 0xff), + byte((lenCert >> 16) & 0xff), + byte((lenCert >> 24) & 0xff), + }) + gz.Write(chain[i]) + } + + gz.Close() + } + + return res.Bytes(), nil +} + +func decompressChain(data []byte) ([][]byte, error) { + var chain [][]byte + var entries []entry + r := bytes.NewReader(data) + + var numCerts int + var hasCompressedCerts bool + for { + entryTypeByte, err := r.ReadByte() + if entryTypeByte == 0 { + break + } + + et := entryType(entryTypeByte) + if err != nil { + return nil, err + } + + numCerts++ + + switch et { + case entryCached: + // we're not sending any certificate hashes in the CHLO, so there shouldn't be any cached certificates in the chain + return nil, errors.New("unexpected cached certificate") + case entryCommon: + e := entry{t: entryCommon} + e.h, err = utils.LittleEndian.ReadUint64(r) + if err != nil { + return nil, err + } + e.i, err = utils.LittleEndian.ReadUint32(r) + if err != nil { + return nil, err + } + certSet, ok := certSets[e.h] + if !ok { + return nil, errors.New("unknown certSet") + } + if e.i >= uint32(len(certSet)) { + return nil, errors.New("certificate not found in certSet") + } + entries = append(entries, e) + chain = append(chain, certSet[e.i]) + case entryCompressed: + hasCompressedCerts = true + entries = append(entries, entry{t: entryCompressed}) + chain = append(chain, nil) + default: + return nil, errors.New("unknown entryType") + } + } + + if numCerts == 0 { + return make([][]byte, 0), nil + } + + if hasCompressedCerts { + uncompressedLength, err := utils.LittleEndian.ReadUint32(r) + if err != nil { + fmt.Println(4) + return nil, err + } + + zlibDict := buildZlibDictForEntries(entries, chain) + gz, err := zlib.NewReaderDict(r, zlibDict) + if err != nil { + return nil, err + } + defer gz.Close() + + var totalLength uint32 + var certIndex int + for totalLength < uncompressedLength { + lenBytes := make([]byte, 4) + _, err := gz.Read(lenBytes) + if err != nil { + return nil, err + } + certLen := binary.LittleEndian.Uint32(lenBytes) + + cert := make([]byte, certLen) + n, err := gz.Read(cert) + if uint32(n) != certLen && err != nil { + return nil, err + } + + for { + if certIndex >= len(entries) { + return nil, errors.New("CertCompression BUG: no element to save uncompressed certificate") + } + if entries[certIndex].t == entryCompressed { + chain[certIndex] = cert + certIndex++ + break + } + certIndex++ + } + + totalLength += 4 + certLen + } + } + + return chain, nil +} + +func buildEntries(chain [][]byte, chainHashes, cachedHashes, setHashes []uint64) []entry { + res := make([]entry, len(chain)) +chainLoop: + for i := range chain { + // Check if hash is in cachedHashes + for j := range cachedHashes { + if chainHashes[i] == cachedHashes[j] { + res[i] = entry{t: entryCached, h: chainHashes[i]} + continue chainLoop + } + } + + // Go through common sets and check if it's in there + for _, setHash := range setHashes { + set, ok := certSets[setHash] + if !ok { + // We don't have this set + continue + } + // We have this set, check if chain[i] is in the set + pos := set.findCertInSet(chain[i]) + if pos >= 0 { + // Found + res[i] = entry{t: entryCommon, h: setHash, i: uint32(pos)} + continue chainLoop + } + } + + res[i] = entry{t: entryCompressed} + } + return res +} + +func buildZlibDictForEntries(entries []entry, chain [][]byte) []byte { + var dict bytes.Buffer + + // First the cached and common in reverse order + for i := len(entries) - 1; i >= 0; i-- { + if entries[i].t == entryCompressed { + continue + } + dict.Write(chain[i]) + } + + dict.Write(certDictZlib) + return dict.Bytes() +} + +func splitHashes(hashes []byte) ([]uint64, error) { + if len(hashes)%8 != 0 { + return nil, errors.New("expected a multiple of 8 bytes for CCS / CCRT hashes") + } + n := len(hashes) / 8 + res := make([]uint64, n) + for i := 0; i < n; i++ { + res[i] = binary.LittleEndian.Uint64(hashes[i*8 : (i+1)*8]) + } + return res, nil +} + +func getCommonCertificateHashes() []byte { + ccs := make([]byte, 8*len(certSets)) + i := 0 + for certSetHash := range certSets { + binary.LittleEndian.PutUint64(ccs[i*8:(i+1)*8], certSetHash) + i++ + } + return ccs +} + +// HashCert calculates the FNV1a hash of a certificate +func HashCert(cert []byte) uint64 { + h := fnv.New64a() + h.Write(cert) + return h.Sum64() +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_compression_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_compression_test.go new file mode 100644 index 00000000..74744d2d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_compression_test.go @@ -0,0 +1,294 @@ +package crypto + +import ( + "bytes" + "compress/flate" + "compress/zlib" + "encoding/binary" + "errors" + "hash/fnv" + + "github.com/lucas-clemente/quic-go-certificates" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func byteHash(d []byte) []byte { + h := fnv.New64a() + h.Write(d) + s := h.Sum64() + res := make([]byte, 8) + binary.LittleEndian.PutUint64(res, s) + return res +} + +var _ = Describe("Cert compression and decompression", func() { + var certSetsOld map[uint64]certSet + + BeforeEach(func() { + certSetsOld = make(map[uint64]certSet) + for s := range certSets { + certSetsOld[s] = certSets[s] + } + }) + + AfterEach(func() { + certSets = certSetsOld + }) + + It("compresses empty", func() { + compressed, err := compressChain(nil, nil, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(compressed).To(Equal([]byte{0})) + }) + + It("decompresses empty", func() { + compressed, err := compressChain(nil, nil, nil) + Expect(err).ToNot(HaveOccurred()) + uncompressed, err := decompressChain(compressed) + Expect(err).ToNot(HaveOccurred()) + Expect(uncompressed).To(BeEmpty()) + }) + + It("gives correct single cert", func() { + cert := []byte{0xde, 0xca, 0xfb, 0xad} + certZlib := &bytes.Buffer{} + z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, certDictZlib) + Expect(err).ToNot(HaveOccurred()) + z.Write([]byte{0x04, 0x00, 0x00, 0x00}) + z.Write(cert) + z.Close() + chain := [][]byte{cert} + compressed, err := compressChain(chain, nil, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(compressed).To(Equal(append([]byte{ + 0x01, 0x00, + 0x08, 0x00, 0x00, 0x00, + }, certZlib.Bytes()...))) + }) + + It("decompresses a single cert", func() { + cert := []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe} + chain := [][]byte{cert} + compressed, err := compressChain(chain, nil, nil) + Expect(err).ToNot(HaveOccurred()) + uncompressed, err := decompressChain(compressed) + Expect(err).ToNot(HaveOccurred()) + Expect(uncompressed).To(Equal(chain)) + }) + + It("gives correct cert and intermediate", func() { + cert1 := []byte{0xde, 0xca, 0xfb, 0xad} + cert2 := []byte{0xde, 0xad, 0xbe, 0xef} + certZlib := &bytes.Buffer{} + z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, certDictZlib) + Expect(err).ToNot(HaveOccurred()) + z.Write([]byte{0x04, 0x00, 0x00, 0x00}) + z.Write(cert1) + z.Write([]byte{0x04, 0x00, 0x00, 0x00}) + z.Write(cert2) + z.Close() + chain := [][]byte{cert1, cert2} + compressed, err := compressChain(chain, nil, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(compressed).To(Equal(append([]byte{ + 0x01, 0x01, 0x00, + 0x10, 0x00, 0x00, 0x00, + }, certZlib.Bytes()...))) + }) + + It("decompresses the chain with a cert and an intermediate", func() { + cert1 := []byte{0xde, 0xca, 0xfb, 0xad} + cert2 := []byte{0xde, 0xad, 0xbe, 0xef} + chain := [][]byte{cert1, cert2} + compressed, err := compressChain(chain, nil, nil) + Expect(err).ToNot(HaveOccurred()) + decompressed, err := decompressChain(compressed) + Expect(err).ToNot(HaveOccurred()) + Expect(decompressed).To(Equal(chain)) + }) + + It("uses cached certificates", func() { + cert := []byte{0xde, 0xca, 0xfb, 0xad} + certHash := byteHash(cert) + chain := [][]byte{cert} + compressed, err := compressChain(chain, nil, certHash) + Expect(err).ToNot(HaveOccurred()) + expected := append([]byte{0x02}, certHash...) + expected = append(expected, 0x00) + Expect(compressed).To(Equal(expected)) + }) + + It("uses cached certificates and compressed combined", func() { + cert1 := []byte{0xde, 0xca, 0xfb, 0xad} + cert2 := []byte{0xde, 0xad, 0xbe, 0xef} + cert2Hash := byteHash(cert2) + certZlib := &bytes.Buffer{} + z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, append(cert2, certDictZlib...)) + Expect(err).ToNot(HaveOccurred()) + z.Write([]byte{0x04, 0x00, 0x00, 0x00}) + z.Write(cert1) + z.Close() + chain := [][]byte{cert1, cert2} + compressed, err := compressChain(chain, nil, cert2Hash) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x01, 0x02} + expected = append(expected, cert2Hash...) + expected = append(expected, 0x00) + expected = append(expected, []byte{0x08, 0, 0, 0}...) + expected = append(expected, certZlib.Bytes()...) + Expect(compressed).To(Equal(expected)) + }) + + It("uses common certificate sets", func() { + cert := certsets.CertSet3[42] + setHash := make([]byte, 8) + binary.LittleEndian.PutUint64(setHash, certsets.CertSet3Hash) + chain := [][]byte{cert} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x03} + expected = append(expected, setHash...) + expected = append(expected, []byte{42, 0, 0, 0}...) + expected = append(expected, 0x00) + Expect(compressed).To(Equal(expected)) + }) + + It("decompresses a single cert form a common certificate set", func() { + cert := certsets.CertSet3[42] + setHash := make([]byte, 8) + binary.LittleEndian.PutUint64(setHash, certsets.CertSet3Hash) + chain := [][]byte{cert} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + decompressed, err := decompressChain(compressed) + Expect(err).ToNot(HaveOccurred()) + Expect(decompressed).To(Equal(chain)) + }) + + It("decompresses multiple certs form common certificate sets", func() { + cert1 := certsets.CertSet3[42] + cert2 := certsets.CertSet2[24] + setHash := make([]byte, 16) + binary.LittleEndian.PutUint64(setHash[0:8], certsets.CertSet3Hash) + binary.LittleEndian.PutUint64(setHash[8:16], certsets.CertSet2Hash) + chain := [][]byte{cert1, cert2} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + decompressed, err := decompressChain(compressed) + Expect(err).ToNot(HaveOccurred()) + Expect(decompressed).To(Equal(chain)) + }) + + It("ignores uncommon certificate sets", func() { + cert := []byte{0xde, 0xca, 0xfb, 0xad} + setHash := make([]byte, 8) + binary.LittleEndian.PutUint64(setHash, 0xdeadbeef) + chain := [][]byte{cert} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + certZlib := &bytes.Buffer{} + z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, certDictZlib) + Expect(err).ToNot(HaveOccurred()) + z.Write([]byte{0x04, 0x00, 0x00, 0x00}) + z.Write(cert) + z.Close() + Expect(compressed).To(Equal(append([]byte{ + 0x01, 0x00, + 0x08, 0x00, 0x00, 0x00, + }, certZlib.Bytes()...))) + }) + + It("errors if a common set does not exist", func() { + cert := certsets.CertSet3[42] + setHash := make([]byte, 8) + binary.LittleEndian.PutUint64(setHash, certsets.CertSet3Hash) + chain := [][]byte{cert} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + delete(certSets, certsets.CertSet3Hash) + _, err = decompressChain(compressed) + Expect(err).To(MatchError(errors.New("unknown certSet"))) + }) + + It("errors if a cert in a common set does not exist", func() { + certSet := [][]byte{ + {0x1, 0x2, 0x3, 0x4}, + {0x5, 0x6, 0x7, 0x8}, + } + certSets[0x1337] = certSet + cert := certSet[1] + setHash := make([]byte, 8) + binary.LittleEndian.PutUint64(setHash, 0x1337) + chain := [][]byte{cert} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + certSets[0x1337] = certSet[:1] // delete the last certificate from the certSet + _, err = decompressChain(compressed) + Expect(err).To(MatchError(errors.New("certificate not found in certSet"))) + }) + + It("uses common certificates and compressed combined", func() { + cert1 := []byte{0xde, 0xca, 0xfb, 0xad} + cert2 := certsets.CertSet3[42] + setHash := make([]byte, 8) + binary.LittleEndian.PutUint64(setHash, certsets.CertSet3Hash) + certZlib := &bytes.Buffer{} + z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, append(cert2, certDictZlib...)) + Expect(err).ToNot(HaveOccurred()) + z.Write([]byte{0x04, 0x00, 0x00, 0x00}) + z.Write(cert1) + z.Close() + chain := [][]byte{cert1, cert2} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x01, 0x03} + expected = append(expected, setHash...) + expected = append(expected, []byte{42, 0, 0, 0}...) + expected = append(expected, 0x00) + expected = append(expected, []byte{0x08, 0, 0, 0}...) + expected = append(expected, certZlib.Bytes()...) + Expect(compressed).To(Equal(expected)) + }) + + It("decompresses a certficate from a common set and a compressed cert combined", func() { + cert1 := []byte{0xde, 0xca, 0xfb, 0xad} + cert2 := certsets.CertSet3[42] + setHash := make([]byte, 8) + binary.LittleEndian.PutUint64(setHash, certsets.CertSet3Hash) + chain := [][]byte{cert1, cert2} + compressed, err := compressChain(chain, setHash, nil) + Expect(err).ToNot(HaveOccurred()) + decompressed, err := decompressChain(compressed) + Expect(err).ToNot(HaveOccurred()) + Expect(decompressed).To(Equal(chain)) + }) + + It("rejects invalid CCS / CCRT hashes", func() { + cert := []byte{0xde, 0xca, 0xfb, 0xad} + chain := [][]byte{cert} + _, err := compressChain(chain, []byte("foo"), nil) + Expect(err).To(MatchError("expected a multiple of 8 bytes for CCS / CCRT hashes")) + _, err = compressChain(chain, nil, []byte("foo")) + Expect(err).To(MatchError("expected a multiple of 8 bytes for CCS / CCRT hashes")) + }) + + Context("common certificate hashes", func() { + It("gets the hashes", func() { + ccs := getCommonCertificateHashes() + Expect(ccs).ToNot(BeEmpty()) + hashes, err := splitHashes(ccs) + Expect(err).ToNot(HaveOccurred()) + for _, hash := range hashes { + Expect(certSets).To(HaveKey(hash)) + } + }) + + It("returns an empty slice if there are not common sets", func() { + certSets = make(map[uint64]certSet) + ccs := getCommonCertificateHashes() + Expect(ccs).ToNot(BeNil()) + Expect(ccs).To(HaveLen(0)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_dict.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_dict.go new file mode 100644 index 00000000..300ec713 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_dict.go @@ -0,0 +1,128 @@ +package crypto + +var certDictZlib = []byte{ + 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, + 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, + 0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, + 0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07, + 0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, + 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34, + 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x2d, 0x61, 0x69, 0x61, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x45, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, + 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x45, 0x2e, 0x63, 0x65, + 0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd2, + 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0xb4, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, + 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x30, 0x0b, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, + 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, + 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33, + 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, + 0x30, 0x1d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x02, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, + 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x67, 0x64, 0x73, 0x31, 0x2d, 0x32, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, + 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x70, 0x73, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, + 0x0d, 0x31, 0x33, 0x30, 0x35, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x73, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, + 0xf8, 0x45, 0x01, 0x07, 0x17, 0x06, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x53, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, + 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, + 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, 0x39, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, 0x73, + 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, + 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x31, 0x10, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x47, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01, + 0x03, 0x13, 0x02, 0x55, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x14, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x13, 0x14, 0x50, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x12, 0x31, 0x21, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, 0x61, + 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x14, 0x31, 0x31, + 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65, + 0x20, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x2e, 0x67, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, + 0x69, 0x67, 0x6e, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41, + 0x2e, 0x63, 0x72, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x63, 0x72, + 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x64, 0x31, 0x1a, + 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x45, 0x56, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x63, 0x72, + 0x74, 0x2e, 0x67, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x31, 0x6f, 0x63, 0x73, 0x70, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x39, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x2f, 0x30, 0x81, 0x80, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x74, 0x30, 0x72, 0x30, 0x24, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, + 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x4a, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, + 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, + 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee, + 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x27, + 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x86, 0x30, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_manager.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_manager.go new file mode 100644 index 00000000..8b8c9faa --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_manager.go @@ -0,0 +1,135 @@ +package crypto + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "hash/fnv" + "time" + + "github.com/lucas-clemente/quic-go/qerr" +) + +// CertManager manages the certificates sent by the server +type CertManager interface { + SetData([]byte) error + GetCommonCertificateHashes() []byte + GetLeafCert() []byte + GetLeafCertHash() (uint64, error) + VerifyServerProof(proof, chlo, serverConfigData []byte) bool + Verify(hostname string) error + GetChain() []*x509.Certificate +} + +type certManager struct { + chain []*x509.Certificate + config *tls.Config +} + +var _ CertManager = &certManager{} + +var errNoCertificateChain = errors.New("CertManager BUG: No certicifate chain loaded") + +// NewCertManager creates a new CertManager +func NewCertManager(tlsConfig *tls.Config) CertManager { + return &certManager{config: tlsConfig} +} + +// SetData takes the byte-slice sent in the SHLO and decompresses it into the certificate chain +func (c *certManager) SetData(data []byte) error { + byteChain, err := decompressChain(data) + if err != nil { + return qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid") + } + + chain := make([]*x509.Certificate, len(byteChain)) + for i, data := range byteChain { + cert, err := x509.ParseCertificate(data) + if err != nil { + return err + } + chain[i] = cert + } + + c.chain = chain + return nil +} + +func (c *certManager) GetChain() []*x509.Certificate { + return c.chain +} + +func (c *certManager) GetCommonCertificateHashes() []byte { + return getCommonCertificateHashes() +} + +// GetLeafCert returns the leaf certificate of the certificate chain +// it returns nil if the certificate chain has not yet been set +func (c *certManager) GetLeafCert() []byte { + if len(c.chain) == 0 { + return nil + } + return c.chain[0].Raw +} + +// GetLeafCertHash calculates the FNV1a_64 hash of the leaf certificate +func (c *certManager) GetLeafCertHash() (uint64, error) { + leafCert := c.GetLeafCert() + if leafCert == nil { + return 0, errNoCertificateChain + } + + h := fnv.New64a() + _, err := h.Write(leafCert) + if err != nil { + return 0, err + } + return h.Sum64(), nil +} + +// VerifyServerProof verifies the signature of the server config +// it should only be called after the certificate chain has been set, otherwise it returns false +func (c *certManager) VerifyServerProof(proof, chlo, serverConfigData []byte) bool { + if len(c.chain) == 0 { + return false + } + + return verifyServerProof(proof, c.chain[0], chlo, serverConfigData) +} + +// Verify verifies the certificate chain +func (c *certManager) Verify(hostname string) error { + if len(c.chain) == 0 { + return errNoCertificateChain + } + + if c.config != nil && c.config.InsecureSkipVerify { + return nil + } + + leafCert := c.chain[0] + + var opts x509.VerifyOptions + if c.config != nil { + opts.Roots = c.config.RootCAs + if c.config.Time == nil { + opts.CurrentTime = time.Now() + } else { + opts.CurrentTime = c.config.Time() + } + } + // we don't need to care about the tls.Config.ServerName here, since hostname has already been set to that value in the session setup + opts.DNSName = hostname + + // the first certificate is the leaf certificate, all others are intermediates + if len(c.chain) > 1 { + intermediates := x509.NewCertPool() + for i := 1; i < len(c.chain); i++ { + intermediates.AddCert(c.chain[i]) + } + opts.Intermediates = intermediates + } + + _, err := leafCert.Verify(opts) + return err +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_manager_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_manager_test.go new file mode 100644 index 00000000..25a49bc7 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_manager_test.go @@ -0,0 +1,348 @@ +package crypto + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "math/big" + "runtime" + "time" + + "github.com/lucas-clemente/quic-go/internal/testdata" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Cert Manager", func() { + var cm *certManager + var key1, key2 *rsa.PrivateKey + var cert1, cert2 []byte + + BeforeEach(func() { + var err error + cm = NewCertManager(nil).(*certManager) + key1, err = rsa.GenerateKey(rand.Reader, 768) + Expect(err).ToNot(HaveOccurred()) + key2, err = rsa.GenerateKey(rand.Reader, 768) + Expect(err).ToNot(HaveOccurred()) + template := &x509.Certificate{SerialNumber: big.NewInt(1)} + cert1, err = x509.CreateCertificate(rand.Reader, template, template, &key1.PublicKey, key1) + Expect(err).ToNot(HaveOccurred()) + cert2, err = x509.CreateCertificate(rand.Reader, template, template, &key2.PublicKey, key2) + Expect(err).ToNot(HaveOccurred()) + }) + + It("saves a client TLS config", func() { + tlsConf := &tls.Config{ServerName: "quic.clemente.io"} + cm = NewCertManager(tlsConf).(*certManager) + Expect(cm.config.ServerName).To(Equal("quic.clemente.io")) + }) + + It("errors when given invalid data", func() { + err := cm.SetData([]byte("foobar")) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid"))) + }) + + It("gets the common certificate hashes", func() { + ccs := cm.GetCommonCertificateHashes() + Expect(ccs).ToNot(BeEmpty()) + }) + + Context("setting the data", func() { + It("decompresses a certificate chain", func() { + chain := [][]byte{cert1, cert2} + compressed, err := compressChain(chain, nil, nil) + Expect(err).ToNot(HaveOccurred()) + err = cm.SetData(compressed) + Expect(err).ToNot(HaveOccurred()) + Expect(cm.chain[0].Raw).To(Equal(cert1)) + Expect(cm.chain[1].Raw).To(Equal(cert2)) + }) + + It("errors if it can't decompress the chain", func() { + err := cm.SetData([]byte("invalid data")) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid"))) + }) + + It("errors if it can't parse a certificate", func() { + chain := [][]byte{[]byte("cert1"), []byte("cert2")} + compressed, err := compressChain(chain, nil, nil) + Expect(err).ToNot(HaveOccurred()) + err = cm.SetData(compressed) + _, ok := err.(asn1.StructuralError) + Expect(ok).To(BeTrue()) + }) + }) + + Context("getting the leaf cert", func() { + It("gets it", func() { + xcert1, err := x509.ParseCertificate(cert1) + Expect(err).ToNot(HaveOccurred()) + xcert2, err := x509.ParseCertificate(cert2) + Expect(err).ToNot(HaveOccurred()) + cm.chain = []*x509.Certificate{xcert1, xcert2} + leafCert := cm.GetLeafCert() + Expect(leafCert).To(Equal(cert1)) + }) + + It("returns nil if the chain hasn't been set yet", func() { + leafCert := cm.GetLeafCert() + Expect(leafCert).To(BeNil()) + }) + }) + + Context("getting the leaf cert hash", func() { + It("calculates the FVN1a 64 hash", func() { + cm.chain = make([]*x509.Certificate, 1) + cm.chain[0] = &x509.Certificate{ + Raw: []byte("test fnv hash"), + } + hash, err := cm.GetLeafCertHash() + Expect(err).ToNot(HaveOccurred()) + // hash calculated on http://www.nitrxgen.net/hashgen/ + Expect(hash).To(Equal(uint64(0x4770f6141fa0f5ad))) + }) + + It("errors if the certificate chain is not loaded", func() { + _, err := cm.GetLeafCertHash() + Expect(err).To(MatchError(errNoCertificateChain)) + }) + }) + + Context("verifying the server config signature", func() { + It("returns false when the chain hasn't been set yet", func() { + valid := cm.VerifyServerProof([]byte("proof"), []byte("chlo"), []byte("scfg")) + Expect(valid).To(BeFalse()) + }) + + It("verifies the signature", func() { + chlo := []byte("client hello") + scfg := []byte("server config data") + xcert1, err := x509.ParseCertificate(cert1) + Expect(err).ToNot(HaveOccurred()) + cm.chain = []*x509.Certificate{xcert1} + proof, err := signServerProof(&tls.Certificate{PrivateKey: key1}, chlo, scfg) + Expect(err).ToNot(HaveOccurred()) + valid := cm.VerifyServerProof(proof, chlo, scfg) + Expect(valid).To(BeTrue()) + }) + + It("rejects an invalid signature", func() { + xcert1, err := x509.ParseCertificate(cert1) + Expect(err).ToNot(HaveOccurred()) + cm.chain = []*x509.Certificate{xcert1} + valid := cm.VerifyServerProof([]byte("invalid proof"), []byte("chlo"), []byte("scfg")) + Expect(valid).To(BeFalse()) + }) + }) + + Context("verifying the certificate chain", func() { + generateCertificate := func(template, parent *x509.Certificate, pubKey *rsa.PublicKey, privKey *rsa.PrivateKey) *x509.Certificate { + certDER, err := x509.CreateCertificate(rand.Reader, template, parent, pubKey, privKey) + Expect(err).ToNot(HaveOccurred()) + cert, err := x509.ParseCertificate(certDER) + Expect(err).ToNot(HaveOccurred()) + return cert + } + + getCertificate := func(template *x509.Certificate) (*rsa.PrivateKey, *x509.Certificate) { + key, err := rsa.GenerateKey(rand.Reader, 1024) + Expect(err).ToNot(HaveOccurred()) + return key, generateCertificate(template, template, &key.PublicKey, key) + } + + It("accepts a valid certificate", func() { + cc := NewCertChain(testdata.GetTLSConfig()).(*certChain) + tlsCert, err := cc.getCertForSNI("quic.clemente.io") + Expect(err).ToNot(HaveOccurred()) + for _, data := range tlsCert.Certificate { + var cert *x509.Certificate + cert, err = x509.ParseCertificate(data) + Expect(err).ToNot(HaveOccurred()) + cm.chain = append(cm.chain, cert) + } + err = cm.Verify("quic.clemente.io") + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't accept an expired certificate", func() { + if runtime.GOOS == "windows" { + // certificate validation works different on windows, see https://golang.org/src/crypto/x509/verify.go line 238 + Skip("windows") + } + + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-25 * time.Hour), + NotAfter: time.Now().Add(-time.Hour), + } + _, leafCert := getCertificate(template) + + cm.chain = []*x509.Certificate{leafCert} + err := cm.Verify("") + Expect(err).To(HaveOccurred()) + Expect(err.(x509.CertificateInvalidError).Reason).To(Equal(x509.Expired)) + }) + + It("doesn't accept a certificate that is not yet valid", func() { + if runtime.GOOS == "windows" { + // certificate validation works different on windows, see https://golang.org/src/crypto/x509/verify.go line 238 + Skip("windows") + } + + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(time.Hour), + NotAfter: time.Now().Add(25 * time.Hour), + } + _, leafCert := getCertificate(template) + + cm.chain = []*x509.Certificate{leafCert} + err := cm.Verify("") + Expect(err).To(HaveOccurred()) + Expect(err.(x509.CertificateInvalidError).Reason).To(Equal(x509.Expired)) + }) + + It("doesn't accept an certificate for the wrong hostname", func() { + if runtime.GOOS == "windows" { + // certificate validation works different on windows, see https://golang.org/src/crypto/x509/verify.go line 238 + Skip("windows") + } + + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + Subject: pkix.Name{CommonName: "google.com"}, + } + _, leafCert := getCertificate(template) + + cm.chain = []*x509.Certificate{leafCert} + err := cm.Verify("quic.clemente.io") + Expect(err).To(HaveOccurred()) + _, ok := err.(x509.HostnameError) + Expect(ok).To(BeTrue()) + }) + + It("errors if the chain hasn't been set yet", func() { + err := cm.Verify("example.com") + Expect(err).To(HaveOccurred()) + }) + + // this tests relies on LetsEncrypt not being contained in the Root CAs + It("rejects valid certificate with missing certificate chain", func() { + if runtime.GOOS == "windows" { + Skip("LetsEncrypt Root CA is included in Windows") + } + + cert := testdata.GetCertificate() + xcert, err := x509.ParseCertificate(cert.Certificate[0]) + Expect(err).ToNot(HaveOccurred()) + cm.chain = []*x509.Certificate{xcert} + err = cm.Verify("quic.clemente.io") + _, ok := err.(x509.UnknownAuthorityError) + Expect(ok).To(BeTrue()) + }) + + It("doesn't do any certificate verification if InsecureSkipVerify is set", func() { + if runtime.GOOS == "windows" { + // certificate validation works different on windows, see https://golang.org/src/crypto/x509/verify.go line 238 + Skip("windows") + } + + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + } + + _, leafCert := getCertificate(template) + cm.config = &tls.Config{ + InsecureSkipVerify: true, + } + cm.chain = []*x509.Certificate{leafCert} + err := cm.Verify("quic.clemente.io") + Expect(err).ToNot(HaveOccurred()) + }) + + It("uses the time specified in a client TLS config", func() { + if runtime.GOOS == "windows" { + // certificate validation works different on windows, see https://golang.org/src/crypto/x509/verify.go line 238 + Skip("windows") + } + + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-25 * time.Hour), + NotAfter: time.Now().Add(-23 * time.Hour), + Subject: pkix.Name{CommonName: "quic.clemente.io"}, + } + _, leafCert := getCertificate(template) + cm.chain = []*x509.Certificate{leafCert} + cm.config = &tls.Config{ + Time: func() time.Time { return time.Now().Add(-24 * time.Hour) }, + } + err := cm.Verify("quic.clemente.io") + _, ok := err.(x509.UnknownAuthorityError) + Expect(ok).To(BeTrue()) + }) + + It("rejects certificates that are expired at the time specified in a client TLS config", func() { + if runtime.GOOS == "windows" { + // certificate validation works different on windows, see https://golang.org/src/crypto/x509/verify.go line 238 + Skip("windows") + } + + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + } + _, leafCert := getCertificate(template) + cm.chain = []*x509.Certificate{leafCert} + cm.config = &tls.Config{ + Time: func() time.Time { return time.Now().Add(-24 * time.Hour) }, + } + err := cm.Verify("quic.clemente.io") + Expect(err.(x509.CertificateInvalidError).Reason).To(Equal(x509.Expired)) + }) + + It("uses the Root CA given in the client config", func() { + if runtime.GOOS == "windows" { + // certificate validation works different on windows, see https://golang.org/src/crypto/x509/verify.go line 238 + Skip("windows") + } + + templateRoot := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + IsCA: true, + BasicConstraintsValid: true, + } + rootKey, rootCert := getCertificate(templateRoot) + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + Subject: pkix.Name{CommonName: "google.com"}, + } + key, err := rsa.GenerateKey(rand.Reader, 1024) + Expect(err).ToNot(HaveOccurred()) + leafCert := generateCertificate(template, rootCert, &key.PublicKey, rootKey) + + rootCAPool := x509.NewCertPool() + rootCAPool.AddCert(rootCert) + + cm.chain = []*x509.Certificate{leafCert} + cm.config = &tls.Config{ + RootCAs: rootCAPool, + } + err = cm.Verify("google.com") + Expect(err).ToNot(HaveOccurred()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/cert_sets.go b/vendor/lucas-clemente/quic-go/internal/crypto/cert_sets.go new file mode 100644 index 00000000..1552668c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/cert_sets.go @@ -0,0 +1,24 @@ +package crypto + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go-certificates" +) + +type certSet [][]byte + +var certSets = map[uint64]certSet{ + certsets.CertSet2Hash: certsets.CertSet2, + certsets.CertSet3Hash: certsets.CertSet3, +} + +// findCertInSet searches for the cert in the set. Negative return value means not found. +func (s *certSet) findCertInSet(cert []byte) int { + for i, c := range *s { + if bytes.Equal(c, cert) { + return i + } + } + return -1 +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead.go b/vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead.go new file mode 100644 index 00000000..5d2e36f9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead.go @@ -0,0 +1,61 @@ +// +build ignore + +package crypto + +import ( + "crypto/cipher" + "encoding/binary" + "errors" + + "github.com/aead/chacha20" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +type aeadChacha20Poly1305 struct { + otherIV []byte + myIV []byte + encrypter cipher.AEAD + decrypter cipher.AEAD +} + +// NewAEADChacha20Poly1305 creates a AEAD using chacha20poly1305 +func NewAEADChacha20Poly1305(otherKey []byte, myKey []byte, otherIV []byte, myIV []byte) (AEAD, error) { + if len(myKey) != 32 || len(otherKey) != 32 || len(myIV) != 4 || len(otherIV) != 4 { + return nil, errors.New("chacha20poly1305: expected 32-byte keys and 4-byte IVs") + } + // copy because ChaCha20Poly1305 expects array pointers + var MyKey, OtherKey [32]byte + copy(MyKey[:], myKey) + copy(OtherKey[:], otherKey) + + encrypter, err := chacha20.NewChaCha20Poly1305WithTagSize(&MyKey, 12) + if err != nil { + return nil, err + } + decrypter, err := chacha20.NewChaCha20Poly1305WithTagSize(&OtherKey, 12) + if err != nil { + return nil, err + } + return &aeadChacha20Poly1305{ + otherIV: otherIV, + myIV: myIV, + encrypter: encrypter, + decrypter: decrypter, + }, nil +} + +func (aead *aeadChacha20Poly1305) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { + return aead.decrypter.Open(dst, aead.makeNonce(aead.otherIV, packetNumber), src, associatedData) +} + +func (aead *aeadChacha20Poly1305) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte { + return aead.encrypter.Seal(dst, aead.makeNonce(aead.myIV, packetNumber), src, associatedData) +} + +func (aead *aeadChacha20Poly1305) makeNonce(iv []byte, packetNumber protocol.PacketNumber) []byte { + res := make([]byte, 12) + copy(res[0:4], iv) + binary.LittleEndian.PutUint64(res[4:12], uint64(packetNumber)) + return res +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead_test.go new file mode 100644 index 00000000..9d5197bd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/chacha20poly1305_aead_test.go @@ -0,0 +1,71 @@ +// +build ignore + +package crypto + +import ( + "crypto/rand" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Chacha20poly1305", func() { + var ( + alice, bob AEAD + keyAlice, keyBob, ivAlice, ivBob []byte + ) + + BeforeEach(func() { + keyAlice = make([]byte, 32) + keyBob = make([]byte, 32) + ivAlice = make([]byte, 4) + ivBob = make([]byte, 4) + rand.Reader.Read(keyAlice) + rand.Reader.Read(keyBob) + rand.Reader.Read(ivAlice) + rand.Reader.Read(ivBob) + var err error + alice, err = NewAEADChacha20Poly1305(keyBob, keyAlice, ivBob, ivAlice) + Expect(err).ToNot(HaveOccurred()) + bob, err = NewAEADChacha20Poly1305(keyAlice, keyBob, ivAlice, ivBob) + Expect(err).ToNot(HaveOccurred()) + }) + + It("seals and opens", func() { + b := alice.Seal(nil, []byte("foobar"), 42, []byte("aad")) + text, err := bob.Open(nil, b, 42, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(text).To(Equal([]byte("foobar"))) + }) + + It("seals and opens reverse", func() { + b := bob.Seal(nil, []byte("foobar"), 42, []byte("aad")) + text, err := alice.Open(nil, b, 42, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(text).To(Equal([]byte("foobar"))) + }) + + It("has the proper length", func() { + b := bob.Seal(nil, []byte("foobar"), 42, []byte("aad")) + Expect(b).To(HaveLen(6 + 12)) + }) + + It("fails with wrong aad", func() { + b := alice.Seal(nil, []byte("foobar"), 42, []byte("aad")) + _, err := bob.Open(nil, b, 42, []byte("aad2")) + Expect(err).To(HaveOccurred()) + }) + + It("rejects wrong key and iv sizes", func() { + var err error + e := "chacha20poly1305: expected 32-byte keys and 4-byte IVs" + _, err = NewAEADChacha20Poly1305(keyBob[1:], keyAlice, ivBob, ivAlice) + Expect(err).To(MatchError(e)) + _, err = NewAEADChacha20Poly1305(keyBob, keyAlice[1:], ivBob, ivAlice) + Expect(err).To(MatchError(e)) + _, err = NewAEADChacha20Poly1305(keyBob, keyAlice, ivBob[1:], ivAlice) + Expect(err).To(MatchError(e)) + _, err = NewAEADChacha20Poly1305(keyBob, keyAlice, ivBob, ivAlice[1:]) + Expect(err).To(MatchError(e)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/crypto_suite_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/crypto_suite_test.go new file mode 100644 index 00000000..23989a3e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/crypto_suite_test.go @@ -0,0 +1,13 @@ +package crypto + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCrypto(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Crypto Suite") +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/curve_25519.go b/vendor/lucas-clemente/quic-go/internal/crypto/curve_25519.go new file mode 100644 index 00000000..fd25b00f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/curve_25519.go @@ -0,0 +1,41 @@ +package crypto + +import ( + "crypto/rand" + "errors" + + "golang.org/x/crypto/curve25519" +) + +// KeyExchange manages the exchange of keys +type curve25519KEX struct { + secret [32]byte + public [32]byte +} + +var _ KeyExchange = &curve25519KEX{} + +// NewCurve25519KEX creates a new KeyExchange using Curve25519, see https://cr.yp.to/ecdh.html +func NewCurve25519KEX() (KeyExchange, error) { + c := &curve25519KEX{} + if _, err := rand.Read(c.secret[:]); err != nil { + return nil, errors.New("Curve25519: could not create private key") + } + curve25519.ScalarBaseMult(&c.public, &c.secret) + return c, nil +} + +func (c *curve25519KEX) PublicKey() []byte { + return c.public[:] +} + +func (c *curve25519KEX) CalculateSharedKey(otherPublic []byte) ([]byte, error) { + if len(otherPublic) != 32 { + return nil, errors.New("Curve25519: expected public key of 32 byte") + } + var res [32]byte + var otherPublicArray [32]byte + copy(otherPublicArray[:], otherPublic) + curve25519.ScalarMult(&res, &c.secret, &otherPublicArray) + return res[:], nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/curve_25519_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/curve_25519_test.go new file mode 100644 index 00000000..44d1d11f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/curve_25519_test.go @@ -0,0 +1,27 @@ +package crypto + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ProofRsa", func() { + It("works", func() { + a, err := NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + b, err := NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + sA, err := a.CalculateSharedKey(b.PublicKey()) + Expect(err).ToNot(HaveOccurred()) + sB, err := b.CalculateSharedKey(a.PublicKey()) + Expect(err).ToNot(HaveOccurred()) + Expect(sA).To(Equal(sB)) + }) + + It("rejects short public keys", func() { + a, err := NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + _, err = a.CalculateSharedKey(nil) + Expect(err).To(MatchError("Curve25519: expected public key of 32 byte")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation.go b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation.go new file mode 100644 index 00000000..8aa187ff --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation.go @@ -0,0 +1,60 @@ +package crypto + +import ( + "crypto" + "encoding/binary" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +const ( + clientExporterLabel = "EXPORTER-QUIC client 1rtt" + serverExporterLabel = "EXPORTER-QUIC server 1rtt" +) + +// A TLSExporter gets the negotiated ciphersuite and computes exporter +type TLSExporter interface { + ConnectionState() mint.ConnectionState + ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) +} + +func qhkdfExpand(secret []byte, label string, length int) []byte { + qlabel := make([]byte, 2+1+5+len(label)) + binary.BigEndian.PutUint16(qlabel[0:2], uint16(length)) + qlabel[2] = uint8(5 + len(label)) + copy(qlabel[3:], []byte("QUIC "+label)) + return mint.HkdfExpand(crypto.SHA256, secret, qlabel, length) +} + +// DeriveAESKeys derives the AES keys and creates a matching AES-GCM AEAD instance +func DeriveAESKeys(tls TLSExporter, pers protocol.Perspective) (AEAD, error) { + var myLabel, otherLabel string + if pers == protocol.PerspectiveClient { + myLabel = clientExporterLabel + otherLabel = serverExporterLabel + } else { + myLabel = serverExporterLabel + otherLabel = clientExporterLabel + } + myKey, myIV, err := computeKeyAndIV(tls, myLabel) + if err != nil { + return nil, err + } + otherKey, otherIV, err := computeKeyAndIV(tls, otherLabel) + if err != nil { + return nil, err + } + return NewAEADAESGCM(otherKey, myKey, otherIV, myIV) +} + +func computeKeyAndIV(tls TLSExporter, label string) (key, iv []byte, err error) { + cs := tls.ConnectionState().CipherSuite + secret, err := tls.ComputeExporter(label, nil, cs.Hash.Size()) + if err != nil { + return nil, nil, err + } + key = qhkdfExpand(secret, "key", cs.KeyLen) + iv = qhkdfExpand(secret, "iv", cs.IvLen) + return key, iv, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto.go b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto.go new file mode 100644 index 00000000..6c294178 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto.go @@ -0,0 +1,100 @@ +package crypto + +import ( + "bytes" + "crypto/sha256" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + + "golang.org/x/crypto/hkdf" +) + +// DeriveKeysChacha20 derives the client and server keys and creates a matching chacha20poly1305 AEAD instance +// func DeriveKeysChacha20(version protocol.VersionNumber, forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte) (AEAD, error) { +// otherKey, myKey, otherIV, myIV, err := deriveKeys(version, forwardSecure, sharedSecret, nonces, connID, chlo, scfg, cert, divNonce, 32) +// if err != nil { +// return nil, err +// } +// return NewAEADChacha20Poly1305(otherKey, myKey, otherIV, myIV) +// } + +// DeriveQuicCryptoAESKeys derives the client and server keys and creates a matching AES-GCM AEAD instance +func DeriveQuicCryptoAESKeys(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (AEAD, error) { + var swap bool + if pers == protocol.PerspectiveClient { + swap = true + } + otherKey, myKey, otherIV, myIV, err := deriveKeys(forwardSecure, sharedSecret, nonces, connID, chlo, scfg, cert, divNonce, 16, swap) + if err != nil { + return nil, err + } + return NewAEADAESGCM12(otherKey, myKey, otherIV, myIV) +} + +// deriveKeys derives the keys and the IVs +// swap should be set true if generating the values for the client, and false for the server +func deriveKeys(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo, scfg, cert, divNonce []byte, keyLen int, swap bool) ([]byte, []byte, []byte, []byte, error) { + var info bytes.Buffer + if forwardSecure { + info.Write([]byte("QUIC forward secure key expansion\x00")) + } else { + info.Write([]byte("QUIC key expansion\x00")) + } + info.Write(connID) + info.Write(chlo) + info.Write(scfg) + info.Write(cert) + + r := hkdf.New(sha256.New, sharedSecret, nonces, info.Bytes()) + + s := make([]byte, 2*keyLen+2*4) + if _, err := io.ReadFull(r, s); err != nil { + return nil, nil, nil, nil, err + } + + key1 := s[:keyLen] + key2 := s[keyLen : 2*keyLen] + iv1 := s[2*keyLen : 2*keyLen+4] + iv2 := s[2*keyLen+4:] + + var otherKey, myKey []byte + var otherIV, myIV []byte + + if !forwardSecure { + if err := diversify(key2, iv2, divNonce); err != nil { + return nil, nil, nil, nil, err + } + } + + if swap { + otherKey = key2 + myKey = key1 + otherIV = iv2 + myIV = iv1 + } else { + otherKey = key1 + myKey = key2 + otherIV = iv1 + myIV = iv2 + } + + return otherKey, myKey, otherIV, myIV, nil +} + +func diversify(key, iv, divNonce []byte) error { + secret := make([]byte, len(key)+len(iv)) + copy(secret, key) + copy(secret[len(key):], iv) + + r := hkdf.New(sha256.New, secret, divNonce, []byte("QUIC key diversification")) + + if _, err := io.ReadFull(r, key); err != nil { + return err + } + if _, err := io.ReadFull(r, iv); err != nil { + return err + } + + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto_test.go new file mode 100644 index 00000000..d866121c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_quic_crypto_test.go @@ -0,0 +1,197 @@ +package crypto + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("QUIC Crypto Key Derivation", func() { + // Context("chacha20poly1305", func() { + // It("derives non-fs keys", func() { + // aead, err := DeriveKeysChacha20( + // protocol.Version32, + // false, + // []byte("0123456789012345678901"), + // []byte("nonce"), + // protocol.ConnectionID(42), + // []byte("chlo"), + // []byte("scfg"), + // []byte("cert"), + // nil, + // ) + // Expect(err).ToNot(HaveOccurred()) + // chacha := aead.(*aeadChacha20Poly1305) + // // If the IVs match, the keys will match too, since the keys are read earlier + // Expect(chacha.myIV).To(Equal([]byte{0xf0, 0xf5, 0x4c, 0xa8})) + // Expect(chacha.otherIV).To(Equal([]byte{0x75, 0xd8, 0xa2, 0x8d})) + // }) + // + // It("derives fs keys", func() { + // aead, err := DeriveKeysChacha20( + // protocol.Version32, + // true, + // []byte("0123456789012345678901"), + // []byte("nonce"), + // protocol.ConnectionID(42), + // []byte("chlo"), + // []byte("scfg"), + // []byte("cert"), + // nil, + // ) + // Expect(err).ToNot(HaveOccurred()) + // chacha := aead.(*aeadChacha20Poly1305) + // // If the IVs match, the keys will match too, since the keys are read earlier + // Expect(chacha.myIV).To(Equal([]byte{0xf5, 0x73, 0x11, 0x79})) + // Expect(chacha.otherIV).To(Equal([]byte{0xf7, 0x26, 0x4d, 0x2c})) + // }) + // + // It("does not use diversification nonces in FS key derivation", func() { + // aead, err := DeriveKeysChacha20( + // protocol.Version33, + // true, + // []byte("0123456789012345678901"), + // []byte("nonce"), + // protocol.ConnectionID(42), + // []byte("chlo"), + // []byte("scfg"), + // []byte("cert"), + // []byte("divnonce"), + // ) + // Expect(err).ToNot(HaveOccurred()) + // chacha := aead.(*aeadChacha20Poly1305) + // // If the IVs match, the keys will match too, since the keys are read earlier + // Expect(chacha.myIV).To(Equal([]byte{0xf5, 0x73, 0x11, 0x79})) + // Expect(chacha.otherIV).To(Equal([]byte{0xf7, 0x26, 0x4d, 0x2c})) + // }) + // + // It("uses diversification nonces in initial key derivation", func() { + // aead, err := DeriveKeysChacha20( + // protocol.Version33, + // false, + // []byte("0123456789012345678901"), + // []byte("nonce"), + // protocol.ConnectionID(42), + // []byte("chlo"), + // []byte("scfg"), + // []byte("cert"), + // []byte("divnonce"), + // ) + // Expect(err).ToNot(HaveOccurred()) + // chacha := aead.(*aeadChacha20Poly1305) + // // If the IVs match, the keys will match too, since the keys are read earlier + // Expect(chacha.myIV).To(Equal([]byte{0xc4, 0x12, 0x25, 0x64})) + // Expect(chacha.otherIV).To(Equal([]byte{0x75, 0xd8, 0xa2, 0x8d})) + // }) + // }) + + Context("AES-GCM", func() { + It("derives non-forward secure keys", func() { + aead, err := DeriveQuicCryptoAESKeys( + false, + []byte("0123456789012345678901"), + []byte("nonce"), + protocol.ConnectionID([]byte{42, 0, 0, 0, 0, 0, 0, 0}), + []byte("chlo"), + []byte("scfg"), + []byte("cert"), + []byte("divnonce"), + protocol.PerspectiveServer, + ) + Expect(err).ToNot(HaveOccurred()) + aesgcm := aead.(*aeadAESGCM12) + // If the IVs match, the keys will match too, since the keys are read earlier + Expect(aesgcm.myIV).To(Equal([]byte{0x1c, 0xec, 0xac, 0x9b})) + Expect(aesgcm.otherIV).To(Equal([]byte{0x64, 0xef, 0x3c, 0x9})) + }) + + It("uses the diversification nonce when generating non-forwared secure keys", func() { + aead1, err := DeriveQuicCryptoAESKeys( + false, + []byte("0123456789012345678901"), + []byte("nonce"), + protocol.ConnectionID([]byte{42, 0, 0, 0, 0, 0, 0, 0}), + []byte("chlo"), + []byte("scfg"), + []byte("cert"), + []byte("divnonce"), + protocol.PerspectiveServer, + ) + Expect(err).ToNot(HaveOccurred()) + aead2, err := DeriveQuicCryptoAESKeys( + false, + []byte("0123456789012345678901"), + []byte("nonce"), + protocol.ConnectionID([]byte{42, 0, 0, 0, 0, 0, 0, 0}), + []byte("chlo"), + []byte("scfg"), + []byte("cert"), + []byte("ecnonvid"), + protocol.PerspectiveServer, + ) + Expect(err).ToNot(HaveOccurred()) + aesgcm1 := aead1.(*aeadAESGCM12) + aesgcm2 := aead2.(*aeadAESGCM12) + Expect(aesgcm1.myIV).ToNot(Equal(aesgcm2.myIV)) + Expect(aesgcm1.otherIV).To(Equal(aesgcm2.otherIV)) + }) + + It("derives non-forward secure keys, for the other side", func() { + aead, err := DeriveQuicCryptoAESKeys( + false, + []byte("0123456789012345678901"), + []byte("nonce"), + protocol.ConnectionID([]byte{42, 0, 0, 0, 0, 0, 0, 0}), + []byte("chlo"), + []byte("scfg"), + []byte("cert"), + []byte("divnonce"), + protocol.PerspectiveClient, + ) + Expect(err).ToNot(HaveOccurred()) + aesgcm := aead.(*aeadAESGCM12) + // If the IVs match, the keys will match too, since the keys are read earlier + Expect(aesgcm.otherIV).To(Equal([]byte{0x1c, 0xec, 0xac, 0x9b})) + Expect(aesgcm.myIV).To(Equal([]byte{0x64, 0xef, 0x3c, 0x9})) + }) + + It("derives forward secure keys", func() { + aead, err := DeriveQuicCryptoAESKeys( + true, + []byte("0123456789012345678901"), + []byte("nonce"), + protocol.ConnectionID([]byte{42, 0, 0, 0, 0, 0, 0, 0}), + []byte("chlo"), + []byte("scfg"), + []byte("cert"), + nil, + protocol.PerspectiveServer, + ) + Expect(err).ToNot(HaveOccurred()) + aesgcm := aead.(*aeadAESGCM12) + // If the IVs match, the keys will match too, since the keys are read earlier + Expect(aesgcm.myIV).To(Equal([]byte{0x7, 0xad, 0xab, 0xb8})) + Expect(aesgcm.otherIV).To(Equal([]byte{0xf2, 0x7a, 0xcc, 0x42})) + }) + + It("does not use div-nonce for FS key derivation", func() { + aead, err := DeriveQuicCryptoAESKeys( + true, + []byte("0123456789012345678901"), + []byte("nonce"), + protocol.ConnectionID([]byte{42, 0, 0, 0, 0, 0, 0, 0}), + []byte("chlo"), + []byte("scfg"), + []byte("cert"), + []byte("divnonce"), + protocol.PerspectiveServer, + ) + Expect(err).ToNot(HaveOccurred()) + aesgcm := aead.(*aeadAESGCM12) + // If the IVs match, the keys will match too, since the keys are read earlier + Expect(aesgcm.myIV).To(Equal([]byte{0x7, 0xad, 0xab, 0xb8})) + Expect(aesgcm.otherIV).To(Equal([]byte{0xf2, 0x7a, 0xcc, 0x42})) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_test.go new file mode 100644 index 00000000..5b530ff8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/key_derivation_test.go @@ -0,0 +1,56 @@ +package crypto + +import ( + "crypto" + "errors" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockTLSExporter struct { + hash crypto.Hash + computerError error +} + +var _ TLSExporter = &mockTLSExporter{} + +func (c *mockTLSExporter) Handshake() mint.Alert { panic("not implemented") } + +func (c *mockTLSExporter) ConnectionState() mint.ConnectionState { + return mint.ConnectionState{ + CipherSuite: mint.CipherSuiteParams{ + Hash: c.hash, + KeyLen: 32, + IvLen: 12, + }, + } +} + +func (c *mockTLSExporter) ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) { + if c.computerError != nil { + return nil, c.computerError + } + return append([]byte(label), context...), nil +} + +var _ = Describe("Key Derivation", func() { + It("derives keys", func() { + clientAEAD, err := DeriveAESKeys(&mockTLSExporter{hash: crypto.SHA256}, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + serverAEAD, err := DeriveAESKeys(&mockTLSExporter{hash: crypto.SHA256}, protocol.PerspectiveServer) + Expect(err).ToNot(HaveOccurred()) + ciphertext := clientAEAD.Seal(nil, []byte("foobar"), 0, []byte("aad")) + data, err := serverAEAD.Open(nil, ciphertext, 0, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal([]byte("foobar"))) + }) + + It("fails when computing the exporter fails", func() { + testErr := errors.New("test error") + _, err := DeriveAESKeys(&mockTLSExporter{hash: crypto.SHA256, computerError: testErr}, protocol.PerspectiveClient) + Expect(err).To(MatchError(testErr)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/key_exchange.go b/vendor/lucas-clemente/quic-go/internal/crypto/key_exchange.go new file mode 100644 index 00000000..d240b9c9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/key_exchange.go @@ -0,0 +1,7 @@ +package crypto + +// KeyExchange manages the exchange of keys +type KeyExchange interface { + PublicKey() []byte + CalculateSharedKey(otherPublic []byte) ([]byte, error) +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/null_aead.go b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead.go new file mode 100644 index 00000000..27158bee --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead.go @@ -0,0 +1,11 @@ +package crypto + +import "github.com/lucas-clemente/quic-go/internal/protocol" + +// NewNullAEAD creates a NullAEAD +func NewNullAEAD(p protocol.Perspective, connID protocol.ConnectionID, v protocol.VersionNumber) (AEAD, error) { + if v.UsesTLS() { + return newNullAEADAESGCM(connID, p) + } + return &nullAEADFNV128a{perspective: p}, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go new file mode 100644 index 00000000..4abc6229 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go @@ -0,0 +1,41 @@ +package crypto + +import ( + "crypto" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +var quicVersion1Salt = []byte{0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38} + +func newNullAEADAESGCM(connectionID protocol.ConnectionID, pers protocol.Perspective) (AEAD, error) { + clientSecret, serverSecret := computeSecrets(connectionID) + + var mySecret, otherSecret []byte + if pers == protocol.PerspectiveClient { + mySecret = clientSecret + otherSecret = serverSecret + } else { + mySecret = serverSecret + otherSecret = clientSecret + } + + myKey, myIV := computeNullAEADKeyAndIV(mySecret) + otherKey, otherIV := computeNullAEADKeyAndIV(otherSecret) + + return NewAEADAESGCM(otherKey, myKey, otherIV, myIV) +} + +func computeSecrets(connID protocol.ConnectionID) (clientSecret, serverSecret []byte) { + handshakeSecret := mint.HkdfExtract(crypto.SHA256, quicVersion1Salt, connID) + clientSecret = qhkdfExpand(handshakeSecret, "client hs", crypto.SHA256.Size()) + serverSecret = qhkdfExpand(handshakeSecret, "server hs", crypto.SHA256.Size()) + return +} + +func computeNullAEADKeyAndIV(secret []byte) (key, iv []byte) { + key = qhkdfExpand(secret, "key", 16) + iv = qhkdfExpand(secret, "iv", 12) + return +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm_test.go new file mode 100644 index 00000000..8f45a956 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm_test.go @@ -0,0 +1,86 @@ +package crypto + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("NullAEAD using AES-GCM", func() { + // values taken from https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation + Context("using the test vector from the QUIC WG Wiki", func() { + connID := protocol.ConnectionID([]byte{0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08}) + + It("computes the secrets", func() { + clientSecret, serverSecret := computeSecrets(connID) + Expect(clientSecret).To(Equal([]byte{ + 0x83, 0x55, 0xf2, 0x1a, 0x3d, 0x8f, 0x83, 0xec, + 0xb3, 0xd0, 0xf9, 0x71, 0x08, 0xd3, 0xf9, 0x5e, + 0x0f, 0x65, 0xb4, 0xd8, 0xae, 0x88, 0xa0, 0x61, + 0x1e, 0xe4, 0x9d, 0xb0, 0xb5, 0x23, 0x59, 0x1d, + })) + Expect(serverSecret).To(Equal([]byte{ + 0xf8, 0x0e, 0x57, 0x71, 0x48, 0x4b, 0x21, 0xcd, + 0xeb, 0xb5, 0xaf, 0xe0, 0xa2, 0x56, 0xa3, 0x17, + 0x41, 0xef, 0xe2, 0xb5, 0xc6, 0xb6, 0x17, 0xba, + 0xe1, 0xb2, 0xf1, 0x5a, 0x83, 0x04, 0x83, 0xd6, + })) + }) + + It("computes the client key and IV", func() { + clientSecret, _ := computeSecrets(connID) + key, iv := computeNullAEADKeyAndIV(clientSecret) + Expect(key).To(Equal([]byte{ + 0x3a, 0xd0, 0x54, 0x2c, 0x4a, 0x85, 0x84, 0x74, + 0x00, 0x63, 0x04, 0x9e, 0x3b, 0x3c, 0xaa, 0xb2, + })) + Expect(iv).To(Equal([]byte{ + 0xd1, 0xfd, 0x26, 0x05, 0x42, 0x75, 0x3a, 0xba, + 0x38, 0x58, 0x9b, 0xad, + })) + }) + + It("computes the server key and IV", func() { + _, serverSecret := computeSecrets(connID) + key, iv := computeNullAEADKeyAndIV(serverSecret) + Expect(key).To(Equal([]byte{ + 0xbe, 0xe4, 0xc2, 0x4d, 0x2a, 0xf1, 0x33, 0x80, + 0xa9, 0xfa, 0x24, 0xa5, 0xe2, 0xba, 0x2c, 0xff, + })) + Expect(iv).To(Equal([]byte{ + 0x25, 0xb5, 0x8e, 0x24, 0x6d, 0x9e, 0x7d, 0x5f, + 0xfe, 0x43, 0x23, 0xfe, + })) + }) + }) + + It("seals and opens", func() { + connectionID := protocol.ConnectionID([]byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}) + clientAEAD, err := newNullAEADAESGCM(connectionID, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + serverAEAD, err := newNullAEADAESGCM(connectionID, protocol.PerspectiveServer) + Expect(err).ToNot(HaveOccurred()) + + clientMessage := clientAEAD.Seal(nil, []byte("foobar"), 42, []byte("aad")) + m, err := serverAEAD.Open(nil, clientMessage, 42, []byte("aad")) + Expect(err).ToNot(HaveOccurred()) + Expect(m).To(Equal([]byte("foobar"))) + serverMessage := serverAEAD.Seal(nil, []byte("raboof"), 99, []byte("daa")) + m, err = clientAEAD.Open(nil, serverMessage, 99, []byte("daa")) + Expect(err).ToNot(HaveOccurred()) + Expect(m).To(Equal([]byte("raboof"))) + }) + + It("doesn't work if initialized with different connection IDs", func() { + c1 := protocol.ConnectionID([]byte{0, 0, 0, 0, 0, 0, 0, 1}) + c2 := protocol.ConnectionID([]byte{0, 0, 0, 0, 0, 0, 0, 2}) + clientAEAD, err := newNullAEADAESGCM(c1, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + serverAEAD, err := newNullAEADAESGCM(c2, protocol.PerspectiveServer) + Expect(err).ToNot(HaveOccurred()) + + clientMessage := clientAEAD.Seal(nil, []byte("foobar"), 42, []byte("aad")) + _, err = serverAEAD.Open(nil, clientMessage, 42, []byte("aad")) + Expect(err).To(MatchError("cipher: message authentication failed")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a.go b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a.go new file mode 100644 index 00000000..6c50ab90 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a.go @@ -0,0 +1,79 @@ +package crypto + +import ( + "bytes" + "errors" + "fmt" + "hash/fnv" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// nullAEAD handles not-yet encrypted packets +type nullAEADFNV128a struct { + perspective protocol.Perspective +} + +var _ AEAD = &nullAEADFNV128a{} + +// Open and verify the ciphertext +func (n *nullAEADFNV128a) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { + if len(src) < 12 { + return nil, errors.New("NullAEAD: ciphertext cannot be less than 12 bytes long") + } + + hash := fnv.New128a() + hash.Write(associatedData) + hash.Write(src[12:]) + if n.perspective == protocol.PerspectiveServer { + hash.Write([]byte("Client")) + } else { + hash.Write([]byte("Server")) + } + sum := make([]byte, 0, 16) + sum = hash.Sum(sum) + // The tag is written in little endian, so we need to reverse the slice. + reverse(sum) + + if !bytes.Equal(sum[:12], src[:12]) { + return nil, fmt.Errorf("NullAEAD: failed to authenticate received data (%#v vs %#v)", sum[:12], src[:12]) + } + return src[12:], nil +} + +// Seal writes hash and ciphertext to the buffer +func (n *nullAEADFNV128a) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte { + if cap(dst) < 12+len(src) { + dst = make([]byte, 12+len(src)) + } else { + dst = dst[:12+len(src)] + } + + hash := fnv.New128a() + hash.Write(associatedData) + hash.Write(src) + + if n.perspective == protocol.PerspectiveServer { + hash.Write([]byte("Server")) + } else { + hash.Write([]byte("Client")) + } + sum := make([]byte, 0, 16) + sum = hash.Sum(sum) + // The tag is written in little endian, so we need to reverse the slice. + reverse(sum) + + copy(dst[12:], src) + copy(dst, sum[:12]) + return dst +} + +func (n *nullAEADFNV128a) Overhead() int { + return 12 +} + +func reverse(a []byte) { + for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 { + a[left], a[right] = a[right], a[left] + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a_test.go new file mode 100644 index 00000000..1a8fcc6a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_fnv128a_test.go @@ -0,0 +1,55 @@ +package crypto + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("NullAEAD using FNV128a", func() { + aad := []byte("All human beings are born free and equal in dignity and rights.") + plainText := []byte("They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood.") + hash36 := []byte{0x98, 0x9b, 0x33, 0x3f, 0xe8, 0xde, 0x32, 0x5c, 0xa6, 0x7f, 0x9c, 0xf7} + + var aeadServer AEAD + var aeadClient AEAD + + BeforeEach(func() { + aeadServer = &nullAEADFNV128a{protocol.PerspectiveServer} + aeadClient = &nullAEADFNV128a{protocol.PerspectiveClient} + }) + + It("seals and opens, client => server", func() { + cipherText := aeadClient.Seal(nil, plainText, 0, aad) + res, err := aeadServer.Open(nil, cipherText, 0, aad) + Expect(err).ToNot(HaveOccurred()) + Expect(res).To(Equal([]byte("They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood."))) + }) + + It("seals and opens, server => client", func() { + cipherText := aeadServer.Seal(nil, plainText, 0, aad) + res, err := aeadClient.Open(nil, cipherText, 0, aad) + Expect(err).ToNot(HaveOccurred()) + Expect(res).To(Equal([]byte("They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood."))) + }) + + It("rejects short ciphertexts", func() { + _, err := aeadServer.Open(nil, nil, 0, nil) + Expect(err).To(MatchError("NullAEAD: ciphertext cannot be less than 12 bytes long")) + }) + + It("seals in-place", func() { + buf := make([]byte, 6, 12+6) + copy(buf, []byte("foobar")) + res := aeadServer.Seal(buf[0:0], buf, 0, nil) + buf = buf[:12+6] + Expect(buf[12:]).To(Equal([]byte("foobar"))) + Expect(res[12:]).To(Equal([]byte("foobar"))) + }) + + It("fails", func() { + cipherText := append(append(hash36, plainText...), byte(0x42)) + _, err := aeadClient.Open(nil, cipherText, 0, aad) + Expect(err).To(HaveOccurred()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_test.go new file mode 100644 index 00000000..ce3a12a0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/null_aead_test.go @@ -0,0 +1,17 @@ +package crypto + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("NullAEAD", func() { + It("selects the right FVN variant", func() { + connID := protocol.ConnectionID([]byte{0x42, 0, 0, 0, 0, 0, 0, 0}) + Expect(NewNullAEAD(protocol.PerspectiveClient, connID, protocol.Version39)).To(Equal(&nullAEADFNV128a{ + perspective: protocol.PerspectiveClient, + })) + Expect(NewNullAEAD(protocol.PerspectiveClient, connID, protocol.VersionTLS)).To(BeAssignableToTypeOf(&aeadAESGCM{})) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/server_proof.go b/vendor/lucas-clemente/quic-go/internal/crypto/server_proof.go new file mode 100644 index 00000000..456ad32d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/server_proof.go @@ -0,0 +1,66 @@ +package crypto + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "encoding/asn1" + "errors" + "math/big" +) + +type ecdsaSignature struct { + R, S *big.Int +} + +// signServerProof signs CHLO and server config for use in the server proof +func signServerProof(cert *tls.Certificate, chlo []byte, serverConfigData []byte) ([]byte, error) { + hash := sha256.New() + hash.Write([]byte("QUIC CHLO and server config signature\x00")) + chloHash := sha256.Sum256(chlo) + hash.Write([]byte{32, 0, 0, 0}) + hash.Write(chloHash[:]) + hash.Write(serverConfigData) + + key, ok := cert.PrivateKey.(crypto.Signer) + if !ok { + return nil, errors.New("expected PrivateKey to implement crypto.Signer") + } + + opts := crypto.SignerOpts(crypto.SHA256) + + if _, ok = key.(*rsa.PrivateKey); ok { + opts = &rsa.PSSOptions{SaltLength: 32, Hash: crypto.SHA256} + } + + return key.Sign(rand.Reader, hash.Sum(nil), opts) +} + +// verifyServerProof verifies the server proof signature +func verifyServerProof(proof []byte, cert *x509.Certificate, chlo []byte, serverConfigData []byte) bool { + hash := sha256.New() + hash.Write([]byte("QUIC CHLO and server config signature\x00")) + chloHash := sha256.Sum256(chlo) + hash.Write([]byte{32, 0, 0, 0}) + hash.Write(chloHash[:]) + hash.Write(serverConfigData) + + // RSA + if cert.PublicKeyAlgorithm == x509.RSA { + opts := &rsa.PSSOptions{SaltLength: 32, Hash: crypto.SHA256} + err := rsa.VerifyPSS(cert.PublicKey.(*rsa.PublicKey), crypto.SHA256, hash.Sum(nil), proof, opts) + return err == nil + } + + // ECDSA + signature := &ecdsaSignature{} + rest, err := asn1.Unmarshal(proof, signature) + if err != nil || len(rest) != 0 { + return false + } + return ecdsa.Verify(cert.PublicKey.(*ecdsa.PublicKey), hash.Sum(nil), signature.R, signature.S) +} diff --git a/vendor/lucas-clemente/quic-go/internal/crypto/server_proof_test.go b/vendor/lucas-clemente/quic-go/internal/crypto/server_proof_test.go new file mode 100644 index 00000000..aecd63e3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/crypto/server_proof_test.go @@ -0,0 +1,127 @@ +package crypto + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/asn1" + "math/big" + + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Proof", func() { + It("gives valid signatures with the key in internal/testdata", func() { + key := &testdata.GetTLSConfig().Certificates[0] + signature, err := signServerProof(key, []byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'}) + Expect(err).ToNot(HaveOccurred()) + // Generated with: + // ruby -e 'require "digest"; p Digest::SHA256.digest("QUIC CHLO and server config signature\x00" + "\x20\x00\x00\x00" + Digest::SHA256.digest("CHLO") + "SCFG")' + data := []byte("W\xA6\xFC\xDE\xC7\xD2>c\xE6\xB5\xF6\tq\x9E|<~1\xA33\x01\xCA=\x19\xBD\xC1\xE4\xB0\xBA\x9B\x16%") + err = rsa.VerifyPSS(key.PrivateKey.(*rsa.PrivateKey).Public().(*rsa.PublicKey), crypto.SHA256, data, signature, &rsa.PSSOptions{SaltLength: 32}) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("when using RSA", func() { + generateCert := func() (*rsa.PrivateKey, *x509.Certificate) { + key, err := rsa.GenerateKey(rand.Reader, 1024) + Expect(err).NotTo(HaveOccurred()) + + certTemplate := x509.Certificate{SerialNumber: big.NewInt(1)} + certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &key.PublicKey, key) + Expect(err).ToNot(HaveOccurred()) + cert, err := x509.ParseCertificate(certDER) + Expect(err).ToNot(HaveOccurred()) + + return key, cert + } + + It("verifies a signature", func() { + key, cert := generateCert() + chlo := []byte("chlo") + scfg := []byte("scfg") + signature, err := signServerProof(&tls.Certificate{PrivateKey: key}, chlo, scfg) + Expect(err).ToNot(HaveOccurred()) + Expect(verifyServerProof(signature, cert, chlo, scfg)).To(BeTrue()) + }) + + It("rejects invalid signatures", func() { + key, cert := generateCert() + chlo := []byte("client hello") + scfg := []byte("sever config") + signature, err := signServerProof(&tls.Certificate{PrivateKey: key}, chlo, scfg) + Expect(err).ToNot(HaveOccurred()) + Expect(verifyServerProof(append(signature, byte(0x99)), cert, chlo, scfg)).To(BeFalse()) + Expect(verifyServerProof(signature, cert, chlo[:len(chlo)-2], scfg)).To(BeFalse()) + Expect(verifyServerProof(signature, cert, chlo, scfg[:len(scfg)-2])).To(BeFalse()) + }) + }) + + Context("when using ECDSA", func() { + generateCert := func() (*ecdsa.PrivateKey, *x509.Certificate) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + Expect(err).NotTo(HaveOccurred()) + + certTemplate := x509.Certificate{SerialNumber: big.NewInt(1)} + certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &key.PublicKey, key) + Expect(err).ToNot(HaveOccurred()) + cert, err := x509.ParseCertificate(certDER) + Expect(err).ToNot(HaveOccurred()) + + return key, cert + } + + It("gives valid signatures", func() { + key, _ := generateCert() + signature, err := signServerProof(&tls.Certificate{PrivateKey: key}, []byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'}) + Expect(err).ToNot(HaveOccurred()) + // Generated with: + // ruby -e 'require "digest"; p Digest::SHA256.digest("QUIC CHLO and server config signature\x00" + "\x20\x00\x00\x00" + Digest::SHA256.digest("CHLO") + "SCFG")' + data := []byte("W\xA6\xFC\xDE\xC7\xD2>c\xE6\xB5\xF6\tq\x9E|<~1\xA33\x01\xCA=\x19\xBD\xC1\xE4\xB0\xBA\x9B\x16%") + s := &ecdsaSignature{} + _, err = asn1.Unmarshal(signature, s) + Expect(err).NotTo(HaveOccurred()) + b := ecdsa.Verify(key.Public().(*ecdsa.PublicKey), data, s.R, s.S) + Expect(b).To(BeTrue()) + }) + + It("verifies a signature", func() { + key, cert := generateCert() + chlo := []byte("chlo") + scfg := []byte("server config") + signature, err := signServerProof(&tls.Certificate{PrivateKey: key}, chlo, scfg) + Expect(err).ToNot(HaveOccurred()) + Expect(verifyServerProof(signature, cert, chlo, scfg)).To(BeTrue()) + }) + + It("rejects invalid signatures", func() { + key, cert := generateCert() + chlo := []byte("client hello") + scfg := []byte("server config") + signature, err := signServerProof(&tls.Certificate{PrivateKey: key}, chlo, scfg) + Expect(err).ToNot(HaveOccurred()) + Expect(verifyServerProof(append(signature, byte(0x99)), cert, chlo, scfg)).To(BeFalse()) + Expect(verifyServerProof(signature, cert, chlo[:len(chlo)-2], scfg)).To(BeFalse()) + Expect(verifyServerProof(signature, cert, chlo, scfg[:len(scfg)-2])).To(BeFalse()) + }) + + It("rejects signatures generated with a different certificate", func() { + key1, cert1 := generateCert() + key2, cert2 := generateCert() + Expect(key1.PublicKey).ToNot(Equal(key2)) + Expect(cert1.Equal(cert2)).To(BeFalse()) + chlo := []byte("chlo") + scfg := []byte("sfcg") + signature, err := signServerProof(&tls.Certificate{PrivateKey: key1}, chlo, scfg) + Expect(err).ToNot(HaveOccurred()) + Expect(verifyServerProof(signature, cert2, chlo, scfg)).To(BeFalse()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go new file mode 100644 index 00000000..6a0aa3c5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go @@ -0,0 +1,122 @@ +package flowcontrol + +import ( + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type baseFlowController struct { + // for sending data + bytesSent protocol.ByteCount + sendWindow protocol.ByteCount + lastBlockedAt protocol.ByteCount + + // for receiving data + mutex sync.RWMutex + bytesRead protocol.ByteCount + highestReceived protocol.ByteCount + receiveWindow protocol.ByteCount + receiveWindowSize protocol.ByteCount + maxReceiveWindowSize protocol.ByteCount + + epochStartTime time.Time + epochStartOffset protocol.ByteCount + rttStats *congestion.RTTStats + + logger utils.Logger +} + +// IsNewlyBlocked says if it is newly blocked by flow control. +// For every offset, it only returns true once. +// If it is blocked, the offset is returned. +func (c *baseFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) { + if c.sendWindowSize() != 0 || c.sendWindow == c.lastBlockedAt { + return false, 0 + } + c.lastBlockedAt = c.sendWindow + return true, c.sendWindow +} + +func (c *baseFlowController) AddBytesSent(n protocol.ByteCount) { + c.bytesSent += n +} + +// UpdateSendWindow should be called after receiving a WindowUpdateFrame +// it returns true if the window was actually updated +func (c *baseFlowController) UpdateSendWindow(offset protocol.ByteCount) { + if offset > c.sendWindow { + c.sendWindow = offset + } +} + +func (c *baseFlowController) sendWindowSize() protocol.ByteCount { + // this only happens during connection establishment, when data is sent before we receive the peer's transport parameters + if c.bytesSent > c.sendWindow { + return 0 + } + return c.sendWindow - c.bytesSent +} + +func (c *baseFlowController) AddBytesRead(n protocol.ByteCount) { + c.mutex.Lock() + defer c.mutex.Unlock() + + // pretend we sent a WindowUpdate when reading the first byte + // this way auto-tuning of the window size already works for the first WindowUpdate + if c.bytesRead == 0 { + c.startNewAutoTuningEpoch() + } + c.bytesRead += n +} + +func (c *baseFlowController) hasWindowUpdate() bool { + bytesRemaining := c.receiveWindow - c.bytesRead + // update the window when more than the threshold was consumed + return bytesRemaining <= protocol.ByteCount((float64(c.receiveWindowSize) * float64((1 - protocol.WindowUpdateThreshold)))) +} + +// getWindowUpdate updates the receive window, if necessary +// it returns the new offset +func (c *baseFlowController) getWindowUpdate() protocol.ByteCount { + if !c.hasWindowUpdate() { + return 0 + } + + c.maybeAdjustWindowSize() + c.receiveWindow = c.bytesRead + c.receiveWindowSize + return c.receiveWindow +} + +// maybeAdjustWindowSize increases the receiveWindowSize if we're sending updates too often. +// For details about auto-tuning, see https://docs.google.com/document/d/1SExkMmGiz8VYzV3s9E35JQlJ73vhzCekKkDi85F1qCE/edit?usp=sharing. +func (c *baseFlowController) maybeAdjustWindowSize() { + bytesReadInEpoch := c.bytesRead - c.epochStartOffset + // don't do anything if less than half the window has been consumed + if bytesReadInEpoch <= c.receiveWindowSize/2 { + return + } + rtt := c.rttStats.SmoothedRTT() + if rtt == 0 { + return + } + + fraction := float64(bytesReadInEpoch) / float64(c.receiveWindowSize) + if time.Since(c.epochStartTime) < time.Duration(4*fraction*float64(rtt)) { + // window is consumed too fast, try to increase the window size + c.receiveWindowSize = utils.MinByteCount(2*c.receiveWindowSize, c.maxReceiveWindowSize) + } + c.startNewAutoTuningEpoch() +} + +func (c *baseFlowController) startNewAutoTuningEpoch() { + c.epochStartTime = time.Now() + c.epochStartOffset = c.bytesRead +} + +func (c *baseFlowController) checkFlowControlViolation() bool { + return c.highestReceived > c.receiveWindow +} diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller_test.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller_test.go new file mode 100644 index 00000000..8e1da5a4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller_test.go @@ -0,0 +1,235 @@ +package flowcontrol + +import ( + "os" + "strconv" + "time" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +// on the CIs, the timing is a lot less precise, so scale every duration by this factor +func scaleDuration(t time.Duration) time.Duration { + scaleFactor := 1 + if f, err := strconv.Atoi(os.Getenv("TIMESCALE_FACTOR")); err == nil { // parsing "" errors, so this works fine if the env is not set + scaleFactor = f + } + Expect(scaleFactor).ToNot(BeZero()) + return time.Duration(scaleFactor) * t +} + +var _ = Describe("Base Flow controller", func() { + var controller *baseFlowController + + BeforeEach(func() { + controller = &baseFlowController{} + controller.rttStats = &congestion.RTTStats{} + }) + + Context("send flow control", func() { + It("adds bytes sent", func() { + controller.bytesSent = 5 + controller.AddBytesSent(6) + Expect(controller.bytesSent).To(Equal(protocol.ByteCount(5 + 6))) + }) + + It("gets the size of the remaining flow control window", func() { + controller.bytesSent = 5 + controller.sendWindow = 12 + Expect(controller.sendWindowSize()).To(Equal(protocol.ByteCount(12 - 5))) + }) + + It("updates the size of the flow control window", func() { + controller.AddBytesSent(5) + controller.UpdateSendWindow(15) + Expect(controller.sendWindow).To(Equal(protocol.ByteCount(15))) + Expect(controller.sendWindowSize()).To(Equal(protocol.ByteCount(15 - 5))) + }) + + It("says that the window size is 0 if we sent more than we were allowed to", func() { + controller.AddBytesSent(15) + controller.UpdateSendWindow(10) + Expect(controller.sendWindowSize()).To(BeZero()) + }) + + It("does not decrease the flow control window", func() { + controller.UpdateSendWindow(20) + Expect(controller.sendWindowSize()).To(Equal(protocol.ByteCount(20))) + controller.UpdateSendWindow(10) + Expect(controller.sendWindowSize()).To(Equal(protocol.ByteCount(20))) + }) + + It("says when it's blocked", func() { + controller.UpdateSendWindow(100) + Expect(controller.IsNewlyBlocked()).To(BeFalse()) + controller.AddBytesSent(100) + blocked, offset := controller.IsNewlyBlocked() + Expect(blocked).To(BeTrue()) + Expect(offset).To(Equal(protocol.ByteCount(100))) + }) + + It("doesn't say that it's newly blocked multiple times for the same offset", func() { + controller.UpdateSendWindow(100) + controller.AddBytesSent(100) + newlyBlocked, offset := controller.IsNewlyBlocked() + Expect(newlyBlocked).To(BeTrue()) + Expect(offset).To(Equal(protocol.ByteCount(100))) + newlyBlocked, _ = controller.IsNewlyBlocked() + Expect(newlyBlocked).To(BeFalse()) + controller.UpdateSendWindow(150) + controller.AddBytesSent(150) + newlyBlocked, _ = controller.IsNewlyBlocked() + Expect(newlyBlocked).To(BeTrue()) + }) + }) + + Context("receive flow control", func() { + var ( + receiveWindow protocol.ByteCount = 10000 + receiveWindowSize protocol.ByteCount = 1000 + ) + + BeforeEach(func() { + controller.bytesRead = receiveWindow - receiveWindowSize + controller.receiveWindow = receiveWindow + controller.receiveWindowSize = receiveWindowSize + }) + + It("adds bytes read", func() { + controller.bytesRead = 5 + controller.AddBytesRead(6) + Expect(controller.bytesRead).To(Equal(protocol.ByteCount(5 + 6))) + }) + + It("triggers a window update when necessary", func() { + bytesConsumed := float64(receiveWindowSize)*protocol.WindowUpdateThreshold + 1 // consumed 1 byte more than the threshold + bytesRemaining := receiveWindowSize - protocol.ByteCount(bytesConsumed) + readPosition := receiveWindow - bytesRemaining + controller.bytesRead = readPosition + offset := controller.getWindowUpdate() + Expect(offset).To(Equal(readPosition + receiveWindowSize)) + Expect(controller.receiveWindow).To(Equal(readPosition + receiveWindowSize)) + }) + + It("doesn't trigger a window update when not necessary", func() { + bytesConsumed := float64(receiveWindowSize)*protocol.WindowUpdateThreshold - 1 // consumed 1 byte less than the threshold + bytesRemaining := receiveWindowSize - protocol.ByteCount(bytesConsumed) + readPosition := receiveWindow - bytesRemaining + controller.bytesRead = readPosition + offset := controller.getWindowUpdate() + Expect(offset).To(BeZero()) + }) + + Context("receive window size auto-tuning", func() { + var oldWindowSize protocol.ByteCount + + BeforeEach(func() { + oldWindowSize = controller.receiveWindowSize + controller.maxReceiveWindowSize = 5000 + }) + + // update the congestion such that it returns a given value for the smoothed RTT + setRtt := func(t time.Duration) { + controller.rttStats.UpdateRTT(t, 0, time.Now()) + Expect(controller.rttStats.SmoothedRTT()).To(Equal(t)) // make sure it worked + } + + It("doesn't increase the window size for a new stream", func() { + controller.maybeAdjustWindowSize() + Expect(controller.receiveWindowSize).To(Equal(oldWindowSize)) + }) + + It("doesn't increase the window size when no RTT estimate is available", func() { + setRtt(0) + controller.startNewAutoTuningEpoch() + controller.AddBytesRead(400) + offset := controller.getWindowUpdate() + Expect(offset).ToNot(BeZero()) // make sure a window update is sent + Expect(controller.receiveWindowSize).To(Equal(oldWindowSize)) + }) + + It("increases the window size if read so fast that the window would be consumed in less than 4 RTTs", func() { + bytesRead := controller.bytesRead + rtt := scaleDuration(20 * time.Millisecond) + setRtt(rtt) + // consume more than 2/3 of the window... + dataRead := receiveWindowSize*2/3 + 1 + // ... in 4*2/3 of the RTT + controller.epochStartOffset = controller.bytesRead + controller.epochStartTime = time.Now().Add(-rtt * 4 * 2 / 3) + controller.AddBytesRead(dataRead) + offset := controller.getWindowUpdate() + Expect(offset).ToNot(BeZero()) + // check that the window size was increased + newWindowSize := controller.receiveWindowSize + Expect(newWindowSize).To(Equal(2 * oldWindowSize)) + // check that the new window size was used to increase the offset + Expect(offset).To(Equal(protocol.ByteCount(bytesRead + dataRead + newWindowSize))) + }) + + It("doesn't increase the window size if data is read so fast that the window would be consumed in less than 4 RTTs, but less than half the window has been read", func() { + // this test only makes sense if a window update is triggered before half of the window has been consumed + Expect(protocol.WindowUpdateThreshold).To(BeNumerically(">", 1/3)) + bytesRead := controller.bytesRead + rtt := scaleDuration(20 * time.Millisecond) + setRtt(rtt) + // consume more than 2/3 of the window... + dataRead := receiveWindowSize*1/3 + 1 + // ... in 4*2/3 of the RTT + controller.epochStartOffset = controller.bytesRead + controller.epochStartTime = time.Now().Add(-rtt * 4 * 1 / 3) + controller.AddBytesRead(dataRead) + offset := controller.getWindowUpdate() + Expect(offset).ToNot(BeZero()) + // check that the window size was not increased + newWindowSize := controller.receiveWindowSize + Expect(newWindowSize).To(Equal(oldWindowSize)) + // check that the new window size was used to increase the offset + Expect(offset).To(Equal(protocol.ByteCount(bytesRead + dataRead + newWindowSize))) + }) + + It("doesn't increase the window size if read too slowly", func() { + bytesRead := controller.bytesRead + rtt := scaleDuration(20 * time.Millisecond) + setRtt(rtt) + // consume less than 2/3 of the window... + dataRead := receiveWindowSize*2/3 - 1 + // ... in 4*2/3 of the RTT + controller.epochStartOffset = controller.bytesRead + controller.epochStartTime = time.Now().Add(-rtt * 4 * 2 / 3) + controller.AddBytesRead(dataRead) + offset := controller.getWindowUpdate() + Expect(offset).ToNot(BeZero()) + // check that the window size was not increased + Expect(controller.receiveWindowSize).To(Equal(oldWindowSize)) + // check that the new window size was used to increase the offset + Expect(offset).To(Equal(protocol.ByteCount(bytesRead + dataRead + oldWindowSize))) + }) + + It("doesn't increase the window size to a value higher than the maxReceiveWindowSize", func() { + resetEpoch := func() { + // make sure the next call to maybeAdjustWindowSize will increase the window + controller.epochStartTime = time.Now().Add(-time.Millisecond) + controller.epochStartOffset = controller.bytesRead + controller.AddBytesRead(controller.receiveWindowSize/2 + 1) + } + setRtt(scaleDuration(20 * time.Millisecond)) + resetEpoch() + controller.maybeAdjustWindowSize() + Expect(controller.receiveWindowSize).To(Equal(2 * oldWindowSize)) // 2000 + // because the lastWindowUpdateTime is updated by MaybeTriggerWindowUpdate(), we can just call maybeAdjustWindowSize() multiple times and get an increase of the window size every time + resetEpoch() + controller.maybeAdjustWindowSize() + Expect(controller.receiveWindowSize).To(Equal(2 * 2 * oldWindowSize)) // 4000 + resetEpoch() + controller.maybeAdjustWindowSize() + Expect(controller.receiveWindowSize).To(Equal(controller.maxReceiveWindowSize)) // 5000 + controller.maybeAdjustWindowSize() + Expect(controller.receiveWindowSize).To(Equal(controller.maxReceiveWindowSize)) // 5000 + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller.go new file mode 100644 index 00000000..d18eaf55 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller.go @@ -0,0 +1,87 @@ +package flowcontrol + +import ( + "fmt" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +type connectionFlowController struct { + baseFlowController + + queueWindowUpdate func() +} + +var _ ConnectionFlowController = &connectionFlowController{} + +// NewConnectionFlowController gets a new flow controller for the connection +// It is created before we receive the peer's transport paramenters, thus it starts with a sendWindow of 0. +func NewConnectionFlowController( + receiveWindow protocol.ByteCount, + maxReceiveWindow protocol.ByteCount, + queueWindowUpdate func(), + rttStats *congestion.RTTStats, + logger utils.Logger, +) ConnectionFlowController { + return &connectionFlowController{ + baseFlowController: baseFlowController{ + rttStats: rttStats, + receiveWindow: receiveWindow, + receiveWindowSize: receiveWindow, + maxReceiveWindowSize: maxReceiveWindow, + logger: logger, + }, + queueWindowUpdate: queueWindowUpdate, + } +} + +func (c *connectionFlowController) SendWindowSize() protocol.ByteCount { + return c.baseFlowController.sendWindowSize() +} + +// IncrementHighestReceived adds an increment to the highestReceived value +func (c *connectionFlowController) IncrementHighestReceived(increment protocol.ByteCount) error { + c.mutex.Lock() + defer c.mutex.Unlock() + + c.highestReceived += increment + if c.checkFlowControlViolation() { + return qerr.Error(qerr.FlowControlReceivedTooMuchData, fmt.Sprintf("Received %d bytes for the connection, allowed %d bytes", c.highestReceived, c.receiveWindow)) + } + return nil +} + +func (c *connectionFlowController) MaybeQueueWindowUpdate() { + c.mutex.Lock() + hasWindowUpdate := c.hasWindowUpdate() + c.mutex.Unlock() + if hasWindowUpdate { + c.queueWindowUpdate() + } +} + +func (c *connectionFlowController) GetWindowUpdate() protocol.ByteCount { + c.mutex.Lock() + oldWindowSize := c.receiveWindowSize + offset := c.baseFlowController.getWindowUpdate() + if oldWindowSize < c.receiveWindowSize { + c.logger.Debugf("Increasing receive flow control window for the connection to %d kB", c.receiveWindowSize/(1<<10)) + } + c.mutex.Unlock() + return offset +} + +// EnsureMinimumWindowSize sets a minimum window size +// it should make sure that the connection-level window is increased when a stream-level window grows +func (c *connectionFlowController) EnsureMinimumWindowSize(inc protocol.ByteCount) { + c.mutex.Lock() + if inc > c.receiveWindowSize { + c.logger.Debugf("Increasing receive flow control window for the connection to %d kB, in response to stream flow control window increase", c.receiveWindowSize/(1<<10)) + c.receiveWindowSize = utils.MinByteCount(inc, c.maxReceiveWindowSize) + c.startNewAutoTuningEpoch() + } + c.mutex.Unlock() +} diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller_test.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller_test.go new file mode 100644 index 00000000..91edab42 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller_test.go @@ -0,0 +1,133 @@ +package flowcontrol + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Connection Flow controller", func() { + var ( + controller *connectionFlowController + queuedWindowUpdate bool + ) + + // update the congestion such that it returns a given value for the smoothed RTT + setRtt := func(t time.Duration) { + controller.rttStats.UpdateRTT(t, 0, time.Now()) + Expect(controller.rttStats.SmoothedRTT()).To(Equal(t)) // make sure it worked + } + + BeforeEach(func() { + controller = &connectionFlowController{} + controller.rttStats = &congestion.RTTStats{} + controller.logger = utils.DefaultLogger + controller.queueWindowUpdate = func() { queuedWindowUpdate = true } + }) + + Context("Constructor", func() { + rttStats := &congestion.RTTStats{} + + It("sets the send and receive windows", func() { + receiveWindow := protocol.ByteCount(2000) + maxReceiveWindow := protocol.ByteCount(3000) + + fc := NewConnectionFlowController(receiveWindow, maxReceiveWindow, nil, rttStats, utils.DefaultLogger).(*connectionFlowController) + Expect(fc.receiveWindow).To(Equal(receiveWindow)) + Expect(fc.maxReceiveWindowSize).To(Equal(maxReceiveWindow)) + }) + }) + + Context("receive flow control", func() { + It("increases the highestReceived by a given window size", func() { + controller.highestReceived = 1337 + controller.IncrementHighestReceived(123) + Expect(controller.highestReceived).To(Equal(protocol.ByteCount(1337 + 123))) + }) + + Context("getting window updates", func() { + BeforeEach(func() { + controller.receiveWindow = 100 + controller.receiveWindowSize = 60 + controller.maxReceiveWindowSize = 1000 + controller.bytesRead = 100 - 60 + }) + + It("queues window updates", func() { + controller.MaybeQueueWindowUpdate() + Expect(queuedWindowUpdate).To(BeFalse()) + controller.AddBytesRead(30) + controller.MaybeQueueWindowUpdate() + Expect(queuedWindowUpdate).To(BeTrue()) + Expect(controller.GetWindowUpdate()).ToNot(BeZero()) + queuedWindowUpdate = false + controller.MaybeQueueWindowUpdate() + Expect(queuedWindowUpdate).To(BeFalse()) + }) + + It("gets a window update", func() { + windowSize := controller.receiveWindowSize + oldOffset := controller.bytesRead + dataRead := windowSize/2 - 1 // make sure not to trigger auto-tuning + controller.AddBytesRead(dataRead) + offset := controller.GetWindowUpdate() + Expect(offset).To(Equal(protocol.ByteCount(oldOffset + dataRead + 60))) + }) + + It("autotunes the window", func() { + oldOffset := controller.bytesRead + oldWindowSize := controller.receiveWindowSize + rtt := scaleDuration(20 * time.Millisecond) + setRtt(rtt) + controller.epochStartTime = time.Now().Add(-time.Millisecond) + controller.epochStartOffset = oldOffset + dataRead := oldWindowSize/2 + 1 + controller.AddBytesRead(dataRead) + offset := controller.GetWindowUpdate() + newWindowSize := controller.receiveWindowSize + Expect(newWindowSize).To(Equal(2 * oldWindowSize)) + Expect(offset).To(Equal(protocol.ByteCount(oldOffset + dataRead + newWindowSize))) + }) + }) + }) + + Context("setting the minimum window size", func() { + var ( + oldWindowSize protocol.ByteCount + receiveWindow protocol.ByteCount = 10000 + receiveWindowSize protocol.ByteCount = 1000 + ) + + BeforeEach(func() { + controller.receiveWindow = receiveWindow + controller.receiveWindowSize = receiveWindowSize + oldWindowSize = controller.receiveWindowSize + controller.maxReceiveWindowSize = 3000 + }) + + It("sets the minimum window window size", func() { + controller.EnsureMinimumWindowSize(1800) + Expect(controller.receiveWindowSize).To(Equal(protocol.ByteCount(1800))) + }) + + It("doesn't reduce the window window size", func() { + controller.EnsureMinimumWindowSize(1) + Expect(controller.receiveWindowSize).To(Equal(oldWindowSize)) + }) + + It("doens't increase the window size beyond the maxReceiveWindowSize", func() { + max := controller.maxReceiveWindowSize + controller.EnsureMinimumWindowSize(2 * max) + Expect(controller.receiveWindowSize).To(Equal(max)) + }) + + It("starts a new epoch after the window size was increased", func() { + controller.EnsureMinimumWindowSize(1912) + Expect(controller.epochStartTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/flowcontrol_suite_test.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/flowcontrol_suite_test.go new file mode 100644 index 00000000..16da9ed2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/flowcontrol_suite_test.go @@ -0,0 +1,24 @@ +package flowcontrol + +import ( + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCrypto(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "FlowControl Suite") +} + +var mockCtrl *gomock.Controller + +var _ = BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) +}) + +var _ = AfterEach(func() { + mockCtrl.Finish() +}) diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/interface.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/interface.go new file mode 100644 index 00000000..5ee53e52 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/interface.go @@ -0,0 +1,38 @@ +package flowcontrol + +import "github.com/lucas-clemente/quic-go/internal/protocol" + +type flowController interface { + // for sending + SendWindowSize() protocol.ByteCount + UpdateSendWindow(protocol.ByteCount) + AddBytesSent(protocol.ByteCount) + // for receiving + AddBytesRead(protocol.ByteCount) + GetWindowUpdate() protocol.ByteCount // returns 0 if no update is necessary + MaybeQueueWindowUpdate() // queues a window update, if necessary + IsNewlyBlocked() (bool, protocol.ByteCount) +} + +// A StreamFlowController is a flow controller for a QUIC stream. +type StreamFlowController interface { + flowController + // for receiving + // UpdateHighestReceived should be called when a new highest offset is received + // final has to be to true if this is the final offset of the stream, as contained in a STREAM frame with FIN bit, and the RST_STREAM frame + UpdateHighestReceived(offset protocol.ByteCount, final bool) error +} + +// The ConnectionFlowController is the flow controller for the connection. +type ConnectionFlowController interface { + flowController +} + +type connectionFlowControllerI interface { + ConnectionFlowController + // The following two methods are not supposed to be called from outside this packet, but are needed internally + // for sending + EnsureMinimumWindowSize(protocol.ByteCount) + // for receiving + IncrementHighestReceived(protocol.ByteCount) error +} diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller.go new file mode 100644 index 00000000..d9878606 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller.go @@ -0,0 +1,149 @@ +package flowcontrol + +import ( + "fmt" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +type streamFlowController struct { + baseFlowController + + streamID protocol.StreamID + + queueWindowUpdate func() + + connection connectionFlowControllerI + contributesToConnection bool // does the stream contribute to connection level flow control + + receivedFinalOffset bool +} + +var _ StreamFlowController = &streamFlowController{} + +// NewStreamFlowController gets a new flow controller for a stream +func NewStreamFlowController( + streamID protocol.StreamID, + contributesToConnection bool, + cfc ConnectionFlowController, + receiveWindow protocol.ByteCount, + maxReceiveWindow protocol.ByteCount, + initialSendWindow protocol.ByteCount, + queueWindowUpdate func(protocol.StreamID), + rttStats *congestion.RTTStats, + logger utils.Logger, +) StreamFlowController { + return &streamFlowController{ + streamID: streamID, + contributesToConnection: contributesToConnection, + connection: cfc.(connectionFlowControllerI), + queueWindowUpdate: func() { queueWindowUpdate(streamID) }, + baseFlowController: baseFlowController{ + rttStats: rttStats, + receiveWindow: receiveWindow, + receiveWindowSize: receiveWindow, + maxReceiveWindowSize: maxReceiveWindow, + sendWindow: initialSendWindow, + logger: logger, + }, + } +} + +// UpdateHighestReceived updates the highestReceived value, if the byteOffset is higher +// it returns an ErrReceivedSmallerByteOffset if the received byteOffset is smaller than any byteOffset received before +func (c *streamFlowController) UpdateHighestReceived(byteOffset protocol.ByteCount, final bool) error { + c.mutex.Lock() + defer c.mutex.Unlock() + + // when receiving a final offset, check that this final offset is consistent with a final offset we might have received earlier + if final && c.receivedFinalOffset && byteOffset != c.highestReceived { + return qerr.Error(qerr.StreamDataAfterTermination, fmt.Sprintf("Received inconsistent final offset for stream %d (old: %d, new: %d bytes)", c.streamID, c.highestReceived, byteOffset)) + } + // if we already received a final offset, check that the offset in the STREAM frames is below the final offset + if c.receivedFinalOffset && byteOffset > c.highestReceived { + return qerr.StreamDataAfterTermination + } + if final { + c.receivedFinalOffset = true + } + if byteOffset == c.highestReceived { + return nil + } + if byteOffset <= c.highestReceived { + // a STREAM_FRAME with a higher offset was received before. + if final { + // If the current byteOffset is smaller than the offset in that STREAM_FRAME, this STREAM_FRAME contained data after the end of the stream + return qerr.StreamDataAfterTermination + } + // this is a reordered STREAM_FRAME + return nil + } + + increment := byteOffset - c.highestReceived + c.highestReceived = byteOffset + if c.checkFlowControlViolation() { + return qerr.Error(qerr.FlowControlReceivedTooMuchData, fmt.Sprintf("Received %d bytes on stream %d, allowed %d bytes", byteOffset, c.streamID, c.receiveWindow)) + } + if c.contributesToConnection { + return c.connection.IncrementHighestReceived(increment) + } + return nil +} + +func (c *streamFlowController) AddBytesRead(n protocol.ByteCount) { + c.baseFlowController.AddBytesRead(n) + if c.contributesToConnection { + c.connection.AddBytesRead(n) + } +} + +func (c *streamFlowController) AddBytesSent(n protocol.ByteCount) { + c.baseFlowController.AddBytesSent(n) + if c.contributesToConnection { + c.connection.AddBytesSent(n) + } +} + +func (c *streamFlowController) SendWindowSize() protocol.ByteCount { + window := c.baseFlowController.sendWindowSize() + if c.contributesToConnection { + window = utils.MinByteCount(window, c.connection.SendWindowSize()) + } + return window +} + +func (c *streamFlowController) MaybeQueueWindowUpdate() { + c.mutex.Lock() + hasWindowUpdate := !c.receivedFinalOffset && c.hasWindowUpdate() + c.mutex.Unlock() + if hasWindowUpdate { + c.queueWindowUpdate() + } + if c.contributesToConnection { + c.connection.MaybeQueueWindowUpdate() + } +} + +func (c *streamFlowController) GetWindowUpdate() protocol.ByteCount { + // don't use defer for unlocking the mutex here, GetWindowUpdate() is called frequently and defer shows up in the profiler + c.mutex.Lock() + // if we already received the final offset for this stream, the peer won't need any additional flow control credit + if c.receivedFinalOffset { + c.mutex.Unlock() + return 0 + } + + oldWindowSize := c.receiveWindowSize + offset := c.baseFlowController.getWindowUpdate() + if c.receiveWindowSize > oldWindowSize { // auto-tuning enlarged the window size + c.logger.Debugf("Increasing receive flow control window for stream %d to %d kB", c.streamID, c.receiveWindowSize/(1<<10)) + if c.contributesToConnection { + c.connection.EnsureMinimumWindowSize(protocol.ByteCount(float64(c.receiveWindowSize) * protocol.ConnectionFlowControlMultiplier)) + } + } + c.mutex.Unlock() + return offset +} diff --git a/vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller_test.go b/vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller_test.go new file mode 100644 index 00000000..83dcbb0e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller_test.go @@ -0,0 +1,290 @@ +package flowcontrol + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Stream Flow controller", func() { + var ( + controller *streamFlowController + queuedWindowUpdate bool + queuedConnWindowUpdate bool + ) + + BeforeEach(func() { + queuedWindowUpdate = false + queuedConnWindowUpdate = false + rttStats := &congestion.RTTStats{} + controller = &streamFlowController{ + streamID: 10, + connection: NewConnectionFlowController(1000, 1000, func() { queuedConnWindowUpdate = true }, rttStats, utils.DefaultLogger).(*connectionFlowController), + } + controller.maxReceiveWindowSize = 10000 + controller.rttStats = rttStats + controller.logger = utils.DefaultLogger + controller.queueWindowUpdate = func() { queuedWindowUpdate = true } + }) + + Context("Constructor", func() { + rttStats := &congestion.RTTStats{} + receiveWindow := protocol.ByteCount(2000) + maxReceiveWindow := protocol.ByteCount(3000) + sendWindow := protocol.ByteCount(4000) + + It("sets the send and receive windows", func() { + cc := NewConnectionFlowController(0, 0, nil, nil, utils.DefaultLogger) + fc := NewStreamFlowController(5, true, cc, receiveWindow, maxReceiveWindow, sendWindow, nil, rttStats, utils.DefaultLogger).(*streamFlowController) + Expect(fc.streamID).To(Equal(protocol.StreamID(5))) + Expect(fc.receiveWindow).To(Equal(receiveWindow)) + Expect(fc.maxReceiveWindowSize).To(Equal(maxReceiveWindow)) + Expect(fc.sendWindow).To(Equal(sendWindow)) + Expect(fc.contributesToConnection).To(BeTrue()) + }) + + It("queues window updates with the correction stream ID", func() { + var queued bool + queueWindowUpdate := func(id protocol.StreamID) { + Expect(id).To(Equal(protocol.StreamID(5))) + queued = true + } + + cc := NewConnectionFlowController(0, 0, nil, nil, utils.DefaultLogger) + fc := NewStreamFlowController(5, true, cc, receiveWindow, maxReceiveWindow, sendWindow, queueWindowUpdate, rttStats, utils.DefaultLogger).(*streamFlowController) + fc.AddBytesRead(receiveWindow) + fc.MaybeQueueWindowUpdate() + Expect(queued).To(BeTrue()) + }) + }) + + Context("receiving data", func() { + Context("registering received offsets", func() { + var receiveWindow protocol.ByteCount = 10000 + var receiveWindowSize protocol.ByteCount = 600 + + BeforeEach(func() { + controller.receiveWindow = receiveWindow + controller.receiveWindowSize = receiveWindowSize + }) + + It("updates the highestReceived", func() { + controller.highestReceived = 1337 + err := controller.UpdateHighestReceived(1338, false) + Expect(err).ToNot(HaveOccurred()) + Expect(controller.highestReceived).To(Equal(protocol.ByteCount(1338))) + }) + + It("informs the connection flow controller about received data", func() { + controller.highestReceived = 10 + controller.contributesToConnection = true + controller.connection.(*connectionFlowController).highestReceived = 100 + err := controller.UpdateHighestReceived(20, false) + Expect(err).ToNot(HaveOccurred()) + Expect(controller.connection.(*connectionFlowController).highestReceived).To(Equal(protocol.ByteCount(100 + 10))) + }) + + It("doesn't informs the connection flow controller about received data if it doesn't contribute", func() { + controller.highestReceived = 10 + controller.connection.(*connectionFlowController).highestReceived = 100 + err := controller.UpdateHighestReceived(20, false) + Expect(err).ToNot(HaveOccurred()) + Expect(controller.connection.(*connectionFlowController).highestReceived).To(Equal(protocol.ByteCount(100))) + }) + + It("does not decrease the highestReceived", func() { + controller.highestReceived = 1337 + err := controller.UpdateHighestReceived(1000, false) + Expect(err).ToNot(HaveOccurred()) + Expect(controller.highestReceived).To(Equal(protocol.ByteCount(1337))) + }) + + It("does nothing when setting the same byte offset", func() { + controller.highestReceived = 1337 + err := controller.UpdateHighestReceived(1337, false) + Expect(err).ToNot(HaveOccurred()) + }) + + It("does not give a flow control violation when using the window completely", func() { + err := controller.UpdateHighestReceived(receiveWindow, false) + Expect(err).ToNot(HaveOccurred()) + }) + + It("detects a flow control violation", func() { + err := controller.UpdateHighestReceived(receiveWindow+1, false) + Expect(err).To(MatchError("FlowControlReceivedTooMuchData: Received 10001 bytes on stream 10, allowed 10000 bytes")) + }) + + It("accepts a final offset higher than the highest received", func() { + controller.highestReceived = 100 + err := controller.UpdateHighestReceived(101, true) + Expect(err).ToNot(HaveOccurred()) + Expect(controller.highestReceived).To(Equal(protocol.ByteCount(101))) + }) + + It("errors when receiving a final offset smaller than the highest offset received so far", func() { + controller.highestReceived = 100 + err := controller.UpdateHighestReceived(99, true) + Expect(err).To(MatchError(qerr.StreamDataAfterTermination)) + }) + + It("accepts delayed data after receiving a final offset", func() { + err := controller.UpdateHighestReceived(300, true) + Expect(err).ToNot(HaveOccurred()) + err = controller.UpdateHighestReceived(250, false) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors when receiving a higher offset after receiving a final offset", func() { + err := controller.UpdateHighestReceived(200, true) + Expect(err).ToNot(HaveOccurred()) + err = controller.UpdateHighestReceived(250, false) + Expect(err).To(MatchError(qerr.StreamDataAfterTermination)) + }) + + It("accepts duplicate final offsets", func() { + err := controller.UpdateHighestReceived(200, true) + Expect(err).ToNot(HaveOccurred()) + err = controller.UpdateHighestReceived(200, true) + Expect(err).ToNot(HaveOccurred()) + Expect(controller.highestReceived).To(Equal(protocol.ByteCount(200))) + }) + + It("errors when receiving inconsistent final offsets", func() { + err := controller.UpdateHighestReceived(200, true) + Expect(err).ToNot(HaveOccurred()) + err = controller.UpdateHighestReceived(201, true) + Expect(err).To(MatchError("StreamDataAfterTermination: Received inconsistent final offset for stream 10 (old: 200, new: 201 bytes)")) + }) + }) + + Context("registering data read", func() { + It("saves when data is read, on a stream not contributing to the connection", func() { + controller.AddBytesRead(100) + Expect(controller.bytesRead).To(Equal(protocol.ByteCount(100))) + Expect(controller.connection.(*connectionFlowController).bytesRead).To(BeZero()) + }) + + It("saves when data is read, on a stream not contributing to the connection", func() { + controller.contributesToConnection = true + controller.AddBytesRead(200) + Expect(controller.bytesRead).To(Equal(protocol.ByteCount(200))) + Expect(controller.connection.(*connectionFlowController).bytesRead).To(Equal(protocol.ByteCount(200))) + }) + }) + + Context("generating window updates", func() { + var oldWindowSize protocol.ByteCount + + // update the congestion such that it returns a given value for the smoothed RTT + setRtt := func(t time.Duration) { + controller.rttStats.UpdateRTT(t, 0, time.Now()) + Expect(controller.rttStats.SmoothedRTT()).To(Equal(t)) // make sure it worked + } + + BeforeEach(func() { + controller.receiveWindow = 100 + controller.receiveWindowSize = 60 + controller.bytesRead = 100 - 60 + controller.connection.(*connectionFlowController).receiveWindow = 100 + controller.connection.(*connectionFlowController).receiveWindowSize = 120 + oldWindowSize = controller.receiveWindowSize + }) + + It("queues window updates", func() { + controller.MaybeQueueWindowUpdate() + Expect(queuedWindowUpdate).To(BeFalse()) + controller.AddBytesRead(30) + controller.MaybeQueueWindowUpdate() + Expect(queuedWindowUpdate).To(BeTrue()) + Expect(controller.GetWindowUpdate()).ToNot(BeZero()) + queuedWindowUpdate = false + controller.MaybeQueueWindowUpdate() + Expect(queuedWindowUpdate).To(BeFalse()) + }) + + It("queues connection-level window updates", func() { + controller.contributesToConnection = true + controller.MaybeQueueWindowUpdate() + Expect(queuedConnWindowUpdate).To(BeFalse()) + controller.AddBytesRead(60) + controller.MaybeQueueWindowUpdate() + Expect(queuedConnWindowUpdate).To(BeTrue()) + }) + + It("tells the connection flow controller when the window was autotuned", func() { + oldOffset := controller.bytesRead + controller.contributesToConnection = true + setRtt(scaleDuration(20 * time.Millisecond)) + controller.epochStartOffset = oldOffset + controller.epochStartTime = time.Now().Add(-time.Millisecond) + controller.AddBytesRead(55) + offset := controller.GetWindowUpdate() + Expect(offset).To(Equal(protocol.ByteCount(oldOffset + 55 + 2*oldWindowSize))) + Expect(controller.receiveWindowSize).To(Equal(2 * oldWindowSize)) + Expect(controller.connection.(*connectionFlowController).receiveWindowSize).To(Equal(protocol.ByteCount(float64(controller.receiveWindowSize) * protocol.ConnectionFlowControlMultiplier))) + }) + + It("doesn't tell the connection flow controller if it doesn't contribute", func() { + oldOffset := controller.bytesRead + controller.contributesToConnection = false + setRtt(scaleDuration(20 * time.Millisecond)) + controller.epochStartOffset = oldOffset + controller.epochStartTime = time.Now().Add(-time.Millisecond) + controller.AddBytesRead(55) + offset := controller.GetWindowUpdate() + Expect(offset).ToNot(BeZero()) + Expect(controller.receiveWindowSize).To(Equal(2 * oldWindowSize)) + Expect(controller.connection.(*connectionFlowController).receiveWindowSize).To(Equal(protocol.ByteCount(2 * oldWindowSize))) // unchanged + }) + + It("doesn't increase the window after a final offset was already received", func() { + controller.AddBytesRead(30) + err := controller.UpdateHighestReceived(90, true) + Expect(err).ToNot(HaveOccurred()) + controller.MaybeQueueWindowUpdate() + Expect(queuedWindowUpdate).To(BeFalse()) + offset := controller.GetWindowUpdate() + Expect(offset).To(BeZero()) + }) + }) + }) + + Context("sending data", func() { + It("gets the size of the send window", func() { + controller.UpdateSendWindow(15) + controller.AddBytesSent(5) + Expect(controller.SendWindowSize()).To(Equal(protocol.ByteCount(10))) + }) + + It("doesn't care about the connection-level window, if it doesn't contribute", func() { + controller.UpdateSendWindow(15) + controller.connection.UpdateSendWindow(1) + controller.AddBytesSent(5) + Expect(controller.SendWindowSize()).To(Equal(protocol.ByteCount(10))) + }) + + It("makes sure that it doesn't overflow the connection-level window", func() { + controller.contributesToConnection = true + controller.connection.UpdateSendWindow(12) + controller.UpdateSendWindow(20) + controller.AddBytesSent(10) + Expect(controller.SendWindowSize()).To(Equal(protocol.ByteCount(2))) + }) + + It("doesn't say that it's blocked, if only the connection is blocked", func() { + controller.contributesToConnection = true + controller.connection.UpdateSendWindow(50) + controller.UpdateSendWindow(100) + controller.AddBytesSent(50) + blocked, _ := controller.connection.IsNewlyBlocked() + Expect(blocked).To(BeTrue()) + Expect(controller.IsNewlyBlocked()).To(BeFalse()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator.go b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator.go new file mode 100644 index 00000000..00f6e7ef --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator.go @@ -0,0 +1,99 @@ +package handshake + +import ( + "encoding/asn1" + "fmt" + "net" + "time" +) + +const ( + cookiePrefixIP byte = iota + cookiePrefixString +) + +// A Cookie is derived from the client address and can be used to verify the ownership of this address. +type Cookie struct { + RemoteAddr string + // The time that the STK was issued (resolution 1 second) + SentTime time.Time +} + +// token is the struct that is used for ASN1 serialization and deserialization +type token struct { + Data []byte + Timestamp int64 +} + +// A CookieGenerator generates Cookies +type CookieGenerator struct { + cookieProtector cookieProtector +} + +// NewCookieGenerator initializes a new CookieGenerator +func NewCookieGenerator() (*CookieGenerator, error) { + cookieProtector, err := newCookieProtector() + if err != nil { + return nil, err + } + return &CookieGenerator{ + cookieProtector: cookieProtector, + }, nil +} + +// NewToken generates a new Cookie for a given source address +func (g *CookieGenerator) NewToken(raddr net.Addr) ([]byte, error) { + data, err := asn1.Marshal(token{ + Data: encodeRemoteAddr(raddr), + Timestamp: time.Now().Unix(), + }) + if err != nil { + return nil, err + } + return g.cookieProtector.NewToken(data) +} + +// DecodeToken decodes a Cookie +func (g *CookieGenerator) DecodeToken(encrypted []byte) (*Cookie, error) { + // if the client didn't send any Cookie, DecodeToken will be called with a nil-slice + if len(encrypted) == 0 { + return nil, nil + } + + data, err := g.cookieProtector.DecodeToken(encrypted) + if err != nil { + return nil, err + } + t := &token{} + rest, err := asn1.Unmarshal(data, t) + if err != nil { + return nil, err + } + if len(rest) != 0 { + return nil, fmt.Errorf("rest when unpacking token: %d", len(rest)) + } + return &Cookie{ + RemoteAddr: decodeRemoteAddr(t.Data), + SentTime: time.Unix(t.Timestamp, 0), + }, nil +} + +// encodeRemoteAddr encodes a remote address such that it can be saved in the Cookie +func encodeRemoteAddr(remoteAddr net.Addr) []byte { + if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok { + return append([]byte{cookiePrefixIP}, udpAddr.IP...) + } + return append([]byte{cookiePrefixString}, []byte(remoteAddr.String())...) +} + +// decodeRemoteAddr decodes the remote address saved in the Cookie +func decodeRemoteAddr(data []byte) string { + // data will never be empty for a Cookie that we generated. Check it to be on the safe side + if len(data) == 0 { + return "" + } + if data[0] == cookiePrefixIP { + return net.IP(data[1:]).String() + } + return string(data[1:]) +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator_test.go new file mode 100644 index 00000000..f0480701 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_generator_test.go @@ -0,0 +1,111 @@ +package handshake + +import ( + "encoding/asn1" + "net" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Cookie Generator", func() { + var cookieGen *CookieGenerator + + BeforeEach(func() { + var err error + cookieGen, err = NewCookieGenerator() + Expect(err).ToNot(HaveOccurred()) + }) + + It("generates a Cookie", func() { + ip := net.IPv4(127, 0, 0, 1) + token, err := cookieGen.NewToken(&net.UDPAddr{IP: ip, Port: 1337}) + Expect(err).ToNot(HaveOccurred()) + Expect(token).ToNot(BeEmpty()) + }) + + It("works with nil tokens", func() { + cookie, err := cookieGen.DecodeToken(nil) + Expect(err).ToNot(HaveOccurred()) + Expect(cookie).To(BeNil()) + }) + + It("accepts a valid cookie", func() { + ip := net.IPv4(192, 168, 0, 1) + token, err := cookieGen.NewToken(&net.UDPAddr{IP: ip, Port: 1337}) + Expect(err).ToNot(HaveOccurred()) + cookie, err := cookieGen.DecodeToken(token) + Expect(err).ToNot(HaveOccurred()) + Expect(cookie.RemoteAddr).To(Equal("192.168.0.1")) + // the time resolution of the Cookie is just 1 second + // if Cookie generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds + Expect(cookie.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second)) + }) + + It("rejects invalid tokens", func() { + _, err := cookieGen.DecodeToken([]byte("invalid token")) + Expect(err).To(HaveOccurred()) + }) + + It("rejects tokens that cannot be decoded", func() { + token, err := cookieGen.cookieProtector.NewToken([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + _, err = cookieGen.DecodeToken(token) + Expect(err).To(HaveOccurred()) + }) + + It("rejects tokens that can be decoded, but have additional payload", func() { + t, err := asn1.Marshal(token{Data: []byte("foobar")}) + Expect(err).ToNot(HaveOccurred()) + t = append(t, []byte("rest")...) + enc, err := cookieGen.cookieProtector.NewToken(t) + Expect(err).ToNot(HaveOccurred()) + _, err = cookieGen.DecodeToken(enc) + Expect(err).To(MatchError("rest when unpacking token: 4")) + }) + + // we don't generate tokens that have no data, but we should be able to handle them if we receive one for whatever reason + It("doesn't panic if a tokens has no data", func() { + t, err := asn1.Marshal(token{Data: []byte("")}) + Expect(err).ToNot(HaveOccurred()) + enc, err := cookieGen.cookieProtector.NewToken(t) + Expect(err).ToNot(HaveOccurred()) + _, err = cookieGen.DecodeToken(enc) + Expect(err).ToNot(HaveOccurred()) + }) + + It("works with an IPv6 addresses ", func() { + addresses := []string{ + "2001:db8::68", + "2001:0000:4136:e378:8000:63bf:3fff:fdd2", + "2001::1", + "ff01:0:0:0:0:0:0:2", + } + for _, addr := range addresses { + ip := net.ParseIP(addr) + Expect(ip).ToNot(BeNil()) + raddr := &net.UDPAddr{IP: ip, Port: 1337} + token, err := cookieGen.NewToken(raddr) + Expect(err).ToNot(HaveOccurred()) + cookie, err := cookieGen.DecodeToken(token) + Expect(err).ToNot(HaveOccurred()) + Expect(cookie.RemoteAddr).To(Equal(ip.String())) + // the time resolution of the Cookie is just 1 second + // if Cookie generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds + Expect(cookie.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second)) + } + }) + + It("uses the string representation an address that is not a UDP address", func() { + raddr := &net.TCPAddr{IP: net.IPv4(192, 168, 13, 37), Port: 1337} + token, err := cookieGen.NewToken(raddr) + Expect(err).ToNot(HaveOccurred()) + cookie, err := cookieGen.DecodeToken(token) + Expect(err).ToNot(HaveOccurred()) + Expect(cookie.RemoteAddr).To(Equal("192.168.13.37:1337")) + // the time resolution of the Cookie is just 1 second + // if Cookie generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds + Expect(cookie.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector.go b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector.go new file mode 100644 index 00000000..7ebdfa18 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector.go @@ -0,0 +1,86 @@ +package handshake + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "fmt" + "io" + + "golang.org/x/crypto/hkdf" +) + +// CookieProtector is used to create and verify a cookie +type cookieProtector interface { + // NewToken creates a new token + NewToken([]byte) ([]byte, error) + // DecodeToken decodes a token + DecodeToken([]byte) ([]byte, error) +} + +const ( + cookieSecretSize = 32 + cookieNonceSize = 32 +) + +// cookieProtector is used to create and verify a cookie +type cookieProtectorImpl struct { + secret []byte +} + +// newCookieProtector creates a source for source address tokens +func newCookieProtector() (cookieProtector, error) { + secret := make([]byte, cookieSecretSize) + if _, err := rand.Read(secret); err != nil { + return nil, err + } + return &cookieProtectorImpl{secret: secret}, nil +} + +// NewToken encodes data into a new token. +func (s *cookieProtectorImpl) NewToken(data []byte) ([]byte, error) { + nonce := make([]byte, cookieNonceSize) + if _, err := rand.Read(nonce); err != nil { + return nil, err + } + aead, aeadNonce, err := s.createAEAD(nonce) + if err != nil { + return nil, err + } + return append(nonce, aead.Seal(nil, aeadNonce, data, nil)...), nil +} + +// DecodeToken decodes a token. +func (s *cookieProtectorImpl) DecodeToken(p []byte) ([]byte, error) { + if len(p) < cookieNonceSize { + return nil, fmt.Errorf("Token too short: %d", len(p)) + } + nonce := p[:cookieNonceSize] + aead, aeadNonce, err := s.createAEAD(nonce) + if err != nil { + return nil, err + } + return aead.Open(nil, aeadNonce, p[cookieNonceSize:], nil) +} + +func (s *cookieProtectorImpl) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) { + h := hkdf.New(sha256.New, s.secret, nonce, []byte("quic-go cookie source")) + key := make([]byte, 32) // use a 32 byte key, in order to select AES-256 + if _, err := io.ReadFull(h, key); err != nil { + return nil, nil, err + } + aeadNonce := make([]byte, 12) + if _, err := io.ReadFull(h, aeadNonce); err != nil { + return nil, nil, err + } + c, err := aes.NewCipher(key) + if err != nil { + return nil, nil, err + } + aead, err := cipher.NewGCM(c) + if err != nil { + return nil, nil, err + } + return aead, aeadNonce, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector_test.go new file mode 100644 index 00000000..fbc7c27c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/cookie_protector_test.go @@ -0,0 +1,39 @@ +package handshake + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Cookie Protector", func() { + var cp cookieProtector + + BeforeEach(func() { + var err error + cp, err = newCookieProtector() + Expect(err).ToNot(HaveOccurred()) + }) + + It("encodes and decodes tokens", func() { + token, err := cp.NewToken([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + Expect(token).ToNot(ContainSubstring("foobar")) + decoded, err := cp.DecodeToken(token) + Expect(err).ToNot(HaveOccurred()) + Expect(decoded).To(Equal([]byte("foobar"))) + }) + + It("fails deconding invalid tokens", func() { + token, err := cp.NewToken([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + token = token[1:] // remove the first byte + _, err = cp.DecodeToken(token) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("message authentication failed")) + }) + + It("errors when decoding too short tokens", func() { + _, err := cp.DecodeToken([]byte("foobar")) + Expect(err).To(MatchError("Token too short: 6")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go new file mode 100644 index 00000000..6687b834 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go @@ -0,0 +1,543 @@ +package handshake + +import ( + "bytes" + "crypto/rand" + "crypto/tls" + "encoding/binary" + "errors" + "fmt" + "io" + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +type cryptoSetupClient struct { + mutex sync.RWMutex + + hostname string + connID protocol.ConnectionID + version protocol.VersionNumber + initialVersion protocol.VersionNumber + negotiatedVersions []protocol.VersionNumber + + cryptoStream io.ReadWriter + + serverConfig *serverConfigClient + + stk []byte + sno []byte + nonc []byte + proof []byte + chloForSignature []byte + lastSentCHLO []byte + certManager crypto.CertManager + + divNonceChan chan struct{} + diversificationNonce []byte + + clientHelloCounter int + serverVerified bool // has the certificate chain and the proof already been verified + keyDerivation QuicCryptoKeyDerivationFunction + + receivedSecurePacket bool + nullAEAD crypto.AEAD + secureAEAD crypto.AEAD + forwardSecureAEAD crypto.AEAD + + paramsChan chan<- TransportParameters + handshakeEvent chan<- struct{} + + params *TransportParameters + + logger utils.Logger +} + +var _ CryptoSetup = &cryptoSetupClient{} + +var ( + errNoObitForClientNonce = errors.New("CryptoSetup BUG: No OBIT for client nonce available") + errClientNonceAlreadyExists = errors.New("CryptoSetup BUG: A client nonce was already generated") + errConflictingDiversificationNonces = errors.New("Received two different diversification nonces") +) + +// NewCryptoSetupClient creates a new CryptoSetup instance for a client +func NewCryptoSetupClient( + cryptoStream io.ReadWriter, + hostname string, + connID protocol.ConnectionID, + version protocol.VersionNumber, + tlsConfig *tls.Config, + params *TransportParameters, + paramsChan chan<- TransportParameters, + handshakeEvent chan<- struct{}, + initialVersion protocol.VersionNumber, + negotiatedVersions []protocol.VersionNumber, + logger utils.Logger, +) (CryptoSetup, error) { + nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveClient, connID, version) + if err != nil { + return nil, err + } + divNonceChan := make(chan struct{}) + cs := &cryptoSetupClient{ + cryptoStream: cryptoStream, + hostname: hostname, + connID: connID, + version: version, + certManager: crypto.NewCertManager(tlsConfig), + params: params, + keyDerivation: crypto.DeriveQuicCryptoAESKeys, + nullAEAD: nullAEAD, + paramsChan: paramsChan, + handshakeEvent: handshakeEvent, + initialVersion: initialVersion, + // The server might have sent greased versions in the Version Negotiation packet. + // We need strip those from the list, since they won't be included in the handshake tag. + negotiatedVersions: protocol.StripGreasedVersions(negotiatedVersions), + divNonceChan: divNonceChan, + logger: logger, + } + return cs, nil +} + +func (h *cryptoSetupClient) HandleCryptoStream() error { + messageChan := make(chan HandshakeMessage) + errorChan := make(chan error, 1) + + go func() { + for { + message, err := ParseHandshakeMessage(h.cryptoStream) + if err != nil { + errorChan <- qerr.Error(qerr.HandshakeFailed, err.Error()) + return + } + messageChan <- message + } + }() + + for { + if err := h.maybeUpgradeCrypto(); err != nil { + return err + } + + h.mutex.RLock() + sendCHLO := h.secureAEAD == nil + h.mutex.RUnlock() + if sendCHLO { + if err := h.sendCHLO(); err != nil { + return err + } + } + + var message HandshakeMessage + select { + case <-h.divNonceChan: + // there's no message to process, but we should try upgrading the crypto again + continue + case message = <-messageChan: + case err := <-errorChan: + return err + } + + h.logger.Debugf("Got %s", message) + switch message.Tag { + case TagREJ: + if err := h.handleREJMessage(message.Data); err != nil { + return err + } + case TagSHLO: + params, err := h.handleSHLOMessage(message.Data) + if err != nil { + return err + } + // blocks until the session has received the parameters + h.paramsChan <- *params + h.handshakeEvent <- struct{}{} + close(h.handshakeEvent) + default: + return qerr.InvalidCryptoMessageType + } + } +} + +func (h *cryptoSetupClient) handleREJMessage(cryptoData map[Tag][]byte) error { + var err error + + if stk, ok := cryptoData[TagSTK]; ok { + h.stk = stk + } + + if sno, ok := cryptoData[TagSNO]; ok { + h.sno = sno + } + + // TODO: what happens if the server sends a different server config in two packets? + if scfg, ok := cryptoData[TagSCFG]; ok { + h.serverConfig, err = parseServerConfig(scfg) + if err != nil { + return err + } + + if h.serverConfig.IsExpired() { + return qerr.CryptoServerConfigExpired + } + + // now that we have a server config, we can use its OBIT value to generate a client nonce + if len(h.nonc) == 0 { + err = h.generateClientNonce() + if err != nil { + return err + } + } + } + + if proof, ok := cryptoData[TagPROF]; ok { + h.proof = proof + h.chloForSignature = h.lastSentCHLO + } + + if crt, ok := cryptoData[TagCERT]; ok { + err := h.certManager.SetData(crt) + if err != nil { + return qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid") + } + + err = h.certManager.Verify(h.hostname) + if err != nil { + h.logger.Infof("Certificate validation failed: %s", err.Error()) + return qerr.ProofInvalid + } + } + + if h.serverConfig != nil && len(h.proof) != 0 && h.certManager.GetLeafCert() != nil { + validProof := h.certManager.VerifyServerProof(h.proof, h.chloForSignature, h.serverConfig.Get()) + if !validProof { + h.logger.Infof("Server proof verification failed") + return qerr.ProofInvalid + } + + h.serverVerified = true + } + + return nil +} + +func (h *cryptoSetupClient) handleSHLOMessage(cryptoData map[Tag][]byte) (*TransportParameters, error) { + h.mutex.Lock() + defer h.mutex.Unlock() + + if !h.receivedSecurePacket { + return nil, qerr.Error(qerr.CryptoEncryptionLevelIncorrect, "unencrypted SHLO message") + } + + if sno, ok := cryptoData[TagSNO]; ok { + h.sno = sno + } + + serverPubs, ok := cryptoData[TagPUBS] + if !ok { + return nil, qerr.Error(qerr.CryptoMessageParameterNotFound, "PUBS") + } + + verTag, ok := cryptoData[TagVER] + if !ok { + return nil, qerr.Error(qerr.InvalidCryptoMessageParameter, "server hello missing version list") + } + if !h.validateVersionList(verTag) { + return nil, qerr.Error(qerr.VersionNegotiationMismatch, "Downgrade attack detected") + } + + nonce := append(h.nonc, h.sno...) + + ephermalSharedSecret, err := h.serverConfig.kex.CalculateSharedKey(serverPubs) + if err != nil { + return nil, err + } + + leafCert := h.certManager.GetLeafCert() + + h.forwardSecureAEAD, err = h.keyDerivation( + true, + ephermalSharedSecret, + nonce, + h.connID, + h.lastSentCHLO, + h.serverConfig.Get(), + leafCert, + nil, + protocol.PerspectiveClient, + ) + if err != nil { + return nil, err + } + h.logger.Debugf("Creating AEAD for forward-secure encryption. Stopping to accept all lower encryption levels.") + + params, err := readHelloMap(cryptoData) + if err != nil { + return nil, qerr.InvalidCryptoMessageParameter + } + return params, nil +} + +func (h *cryptoSetupClient) validateVersionList(verTags []byte) bool { + numNegotiatedVersions := len(h.negotiatedVersions) + if numNegotiatedVersions == 0 { + return true + } + if len(verTags)%4 != 0 || len(verTags)/4 != numNegotiatedVersions { + return false + } + + b := bytes.NewReader(verTags) + for i := 0; i < numNegotiatedVersions; i++ { + v, err := utils.BigEndian.ReadUint32(b) + if err != nil { // should never occur, since the length was already checked + return false + } + if protocol.VersionNumber(v) != h.negotiatedVersions[i] { + return false + } + } + return true +} + +func (h *cryptoSetupClient) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) { + h.mutex.RLock() + defer h.mutex.RUnlock() + + if h.forwardSecureAEAD != nil { + data, err := h.forwardSecureAEAD.Open(dst, src, packetNumber, associatedData) + if err == nil { + return data, protocol.EncryptionForwardSecure, nil + } + return nil, protocol.EncryptionUnspecified, err + } + + if h.secureAEAD != nil { + data, err := h.secureAEAD.Open(dst, src, packetNumber, associatedData) + if err == nil { + h.logger.Debugf("Received first secure packet. Stopping to accept unencrypted packets.") + h.receivedSecurePacket = true + return data, protocol.EncryptionSecure, nil + } + if h.receivedSecurePacket { + return nil, protocol.EncryptionUnspecified, err + } + } + res, err := h.nullAEAD.Open(dst, src, packetNumber, associatedData) + if err != nil { + return nil, protocol.EncryptionUnspecified, err + } + return res, protocol.EncryptionUnencrypted, nil +} + +func (h *cryptoSetupClient) GetSealer() (protocol.EncryptionLevel, Sealer) { + h.mutex.RLock() + defer h.mutex.RUnlock() + if h.forwardSecureAEAD != nil { + return protocol.EncryptionForwardSecure, h.forwardSecureAEAD + } else if h.secureAEAD != nil { + return protocol.EncryptionSecure, h.secureAEAD + } else { + return protocol.EncryptionUnencrypted, h.nullAEAD + } +} + +func (h *cryptoSetupClient) GetSealerForCryptoStream() (protocol.EncryptionLevel, Sealer) { + return protocol.EncryptionUnencrypted, h.nullAEAD +} + +func (h *cryptoSetupClient) GetSealerWithEncryptionLevel(encLevel protocol.EncryptionLevel) (Sealer, error) { + h.mutex.RLock() + defer h.mutex.RUnlock() + + switch encLevel { + case protocol.EncryptionUnencrypted: + return h.nullAEAD, nil + case protocol.EncryptionSecure: + if h.secureAEAD == nil { + return nil, errors.New("CryptoSetupClient: no secureAEAD") + } + return h.secureAEAD, nil + case protocol.EncryptionForwardSecure: + if h.forwardSecureAEAD == nil { + return nil, errors.New("CryptoSetupClient: no forwardSecureAEAD") + } + return h.forwardSecureAEAD, nil + } + return nil, errors.New("CryptoSetupClient: no encryption level specified") +} + +func (h *cryptoSetupClient) ConnectionState() ConnectionState { + h.mutex.Lock() + defer h.mutex.Unlock() + return ConnectionState{ + HandshakeComplete: h.forwardSecureAEAD != nil, + PeerCertificates: h.certManager.GetChain(), + } +} + +func (h *cryptoSetupClient) SetDiversificationNonce(divNonce []byte) error { + h.mutex.Lock() + if len(h.diversificationNonce) > 0 { + defer h.mutex.Unlock() + if !bytes.Equal(h.diversificationNonce, divNonce) { + return errConflictingDiversificationNonces + } + return nil + } + h.diversificationNonce = divNonce + h.mutex.Unlock() + h.divNonceChan <- struct{}{} + return nil +} + +func (h *cryptoSetupClient) sendCHLO() error { + h.clientHelloCounter++ + if h.clientHelloCounter > protocol.MaxClientHellos { + return qerr.Error(qerr.CryptoTooManyRejects, fmt.Sprintf("More than %d rejects", protocol.MaxClientHellos)) + } + + b := &bytes.Buffer{} + + tags, err := h.getTags() + if err != nil { + return err + } + h.addPadding(tags) + message := HandshakeMessage{ + Tag: TagCHLO, + Data: tags, + } + + h.logger.Debugf("Sending %s", message) + message.Write(b) + + _, err = h.cryptoStream.Write(b.Bytes()) + if err != nil { + return err + } + + h.lastSentCHLO = b.Bytes() + return nil +} + +func (h *cryptoSetupClient) getTags() (map[Tag][]byte, error) { + tags := h.params.getHelloMap() + tags[TagSNI] = []byte(h.hostname) + tags[TagPDMD] = []byte("X509") + + ccs := h.certManager.GetCommonCertificateHashes() + if len(ccs) > 0 { + tags[TagCCS] = ccs + } + + versionTag := make([]byte, 4) + binary.BigEndian.PutUint32(versionTag, uint32(h.initialVersion)) + tags[TagVER] = versionTag + + if len(h.stk) > 0 { + tags[TagSTK] = h.stk + } + if len(h.sno) > 0 { + tags[TagSNO] = h.sno + } + + if h.serverConfig != nil { + tags[TagSCID] = h.serverConfig.ID + + leafCert := h.certManager.GetLeafCert() + if leafCert != nil { + certHash, _ := h.certManager.GetLeafCertHash() + xlct := make([]byte, 8) + binary.LittleEndian.PutUint64(xlct, certHash) + + tags[TagNONC] = h.nonc + tags[TagXLCT] = xlct + tags[TagKEXS] = []byte("C255") + tags[TagAEAD] = []byte("AESG") + tags[TagPUBS] = h.serverConfig.kex.PublicKey() // TODO: check if 3 bytes need to be prepended + } + } + + return tags, nil +} + +// add a TagPAD to a tagMap, such that the total size will be bigger than the ClientHelloMinimumSize +func (h *cryptoSetupClient) addPadding(tags map[Tag][]byte) { + var size int + for _, tag := range tags { + size += 8 + len(tag) // 4 bytes for the tag + 4 bytes for the offset + the length of the data + } + paddingSize := protocol.MinClientHelloSize - size + if paddingSize > 0 { + tags[TagPAD] = bytes.Repeat([]byte{0}, paddingSize) + } +} + +func (h *cryptoSetupClient) maybeUpgradeCrypto() error { + if !h.serverVerified { + return nil + } + + h.mutex.Lock() + defer h.mutex.Unlock() + + leafCert := h.certManager.GetLeafCert() + if h.secureAEAD == nil && (h.serverConfig != nil && len(h.serverConfig.sharedSecret) > 0 && len(h.nonc) > 0 && len(leafCert) > 0 && len(h.diversificationNonce) > 0 && len(h.lastSentCHLO) > 0) { + var err error + var nonce []byte + if h.sno == nil { + nonce = h.nonc + } else { + nonce = append(h.nonc, h.sno...) + } + + h.secureAEAD, err = h.keyDerivation( + false, + h.serverConfig.sharedSecret, + nonce, + h.connID, + h.lastSentCHLO, + h.serverConfig.Get(), + leafCert, + h.diversificationNonce, + protocol.PerspectiveClient, + ) + if err != nil { + return err + } + h.logger.Debugf("Creating AEAD for secure encryption.") + h.handshakeEvent <- struct{}{} + } + return nil +} + +func (h *cryptoSetupClient) generateClientNonce() error { + if len(h.nonc) > 0 { + return errClientNonceAlreadyExists + } + + nonc := make([]byte, 32) + binary.BigEndian.PutUint32(nonc, uint32(time.Now().Unix())) + + if len(h.serverConfig.obit) != 8 { + return errNoObitForClientNonce + } + + copy(nonc[4:12], h.serverConfig.obit) + + _, err := rand.Read(nonc[12:]) + if err != nil { + return err + } + + h.nonc = nonc + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client_test.go new file mode 100644 index 00000000..92633fe5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_client_test.go @@ -0,0 +1,1011 @@ +package handshake + +import ( + "bytes" + "crypto/x509" + "encoding/binary" + "errors" + "fmt" + "time" + + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/mocks/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type keyDerivationValues struct { + forwardSecure bool + sharedSecret []byte + nonces []byte + connID protocol.ConnectionID + chlo []byte + scfg []byte + cert []byte + divNonce []byte + pers protocol.Perspective +} + +type mockCertManager struct { + setDataCalledWith []byte + setDataError error + + commonCertificateHashes []byte + + chain []*x509.Certificate + + leafCert []byte + leafCertHash uint64 + leafCertHashError error + + verifyServerProofResult bool + verifyServerProofCalled bool + + verifyError error + verifyCalled bool +} + +var _ crypto.CertManager = &mockCertManager{} + +func (m *mockCertManager) SetData(data []byte) error { + m.setDataCalledWith = data + return m.setDataError +} + +func (m *mockCertManager) GetCommonCertificateHashes() []byte { + return m.commonCertificateHashes +} + +func (m *mockCertManager) GetLeafCert() []byte { + return m.leafCert +} + +func (m *mockCertManager) GetLeafCertHash() (uint64, error) { + return m.leafCertHash, m.leafCertHashError +} + +func (m *mockCertManager) VerifyServerProof(proof, chlo, serverConfigData []byte) bool { + m.verifyServerProofCalled = true + return m.verifyServerProofResult +} + +func (m *mockCertManager) Verify(hostname string) error { + m.verifyCalled = true + return m.verifyError +} + +func (m *mockCertManager) GetChain() []*x509.Certificate { + return m.chain +} + +var _ = Describe("Client Crypto Setup", func() { + var ( + cs *cryptoSetupClient + certManager *mockCertManager + stream *mockStream + keyDerivationCalledWith *keyDerivationValues + shloMap map[Tag][]byte + handshakeEvent chan struct{} + paramsChan chan TransportParameters + ) + + BeforeEach(func() { + shloMap = map[Tag][]byte{ + TagPUBS: {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}, + TagVER: {}, + } + keyDerivation := func(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (crypto.AEAD, error) { + keyDerivationCalledWith = &keyDerivationValues{ + forwardSecure: forwardSecure, + sharedSecret: sharedSecret, + nonces: nonces, + connID: connID, + chlo: chlo, + scfg: scfg, + cert: cert, + divNonce: divNonce, + pers: pers, + } + return mockcrypto.NewMockAEAD(mockCtrl), nil + } + + stream = newMockStream() + certManager = &mockCertManager{} + version := protocol.Version39 + // use a buffered channel here, so that we can parse a SHLO without having to receive the TransportParameters to avoid blocking + paramsChan = make(chan TransportParameters, 1) + handshakeEvent = make(chan struct{}, 2) + csInt, err := NewCryptoSetupClient( + stream, + "hostname", + protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + version, + nil, + &TransportParameters{IdleTimeout: protocol.DefaultIdleTimeout}, + paramsChan, + handshakeEvent, + protocol.Version39, + nil, + utils.DefaultLogger, + ) + Expect(err).ToNot(HaveOccurred()) + cs = csInt.(*cryptoSetupClient) + cs.certManager = certManager + cs.keyDerivation = keyDerivation + cs.nullAEAD = mockcrypto.NewMockAEAD(mockCtrl) + cs.cryptoStream = stream + }) + + Context("Reading REJ", func() { + var tagMap map[Tag][]byte + + BeforeEach(func() { + tagMap = make(map[Tag][]byte) + }) + + It("rejects handshake messages with the wrong message tag", func() { + HandshakeMessage{Tag: TagCHLO, Data: tagMap}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.InvalidCryptoMessageType)) + }) + + It("errors on invalid handshake messages", func() { + stream.dataToRead.Write([]byte("invalid message")) + err := cs.HandleCryptoStream() + Expect(err).To(HaveOccurred()) + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.HandshakeFailed)) + }) + + It("passes the message on for parsing, and reads the source address token", func() { + stk := []byte("foobar") + tagMap[TagSTK] = stk + HandshakeMessage{Tag: TagREJ, Data: tagMap}.Write(&stream.dataToRead) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + Eventually(func() []byte { return cs.stk }).Should(Equal(stk)) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + + It("saves the proof", func() { + proof := []byte("signature for the server config") + tagMap[TagPROF] = proof + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.proof).To(Equal(proof)) + }) + + It("saves the last sent CHLO for signature validation, when receiving the proof", func() { + chlo := []byte("last sent CHLO") + cs.lastSentCHLO = chlo + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.chloForSignature).To(BeEmpty()) + tagMap[TagPROF] = []byte("signature") + err = cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.chloForSignature).To(Equal(chlo)) + }) + + It("saves the server nonce", func() { + nonc := []byte("servernonce") + tagMap[TagSNO] = nonc + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.sno).To(Equal(nonc)) + }) + + Context("validating the Version list", func() { + It("doesn't care about the version list if there was no version negotiation", func() { + Expect(cs.validateVersionList([]byte{0})).To(BeTrue()) + }) + + It("detects a downgrade attack if the number of versions is not equal", func() { + cs.negotiatedVersions = []protocol.VersionNumber{protocol.VersionWhatever} + Expect(cs.validateVersionList(bytes.Repeat([]byte{'f'}, 2*4))).To(BeFalse()) + }) + + It("detects a downgrade attack", func() { + cs.negotiatedVersions = []protocol.VersionNumber{12} + b := &bytes.Buffer{} + utils.BigEndian.WriteUint32(b, 11) + Expect(cs.validateVersionList(b.Bytes())).To(BeFalse()) + }) + + It("errors if the version tags are invalid", func() { + cs.negotiatedVersions = []protocol.VersionNumber{protocol.VersionWhatever} + Expect(cs.validateVersionList([]byte{0, 1, 2})).To(BeFalse()) // 1 byte too short + }) + + It("returns the right error when detecting a downgrade attack", func() { + cs.negotiatedVersions = []protocol.VersionNumber{protocol.VersionWhatever} + cs.receivedSecurePacket = true + _, err := cs.handleSHLOMessage(map[Tag][]byte{ + TagPUBS: {0}, + TagVER: {0, 1}, + }) + Expect(err).To(MatchError(qerr.Error(qerr.VersionNegotiationMismatch, "Downgrade attack detected"))) + }) + }) + + Context("Certificates", func() { + BeforeEach(func() { + cs.serverConfig = &serverConfigClient{} + }) + + It("passes the certificates to the CertManager", func() { + tagMap[TagCERT] = []byte("cert") + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(certManager.setDataCalledWith).To(Equal(tagMap[TagCERT])) + }) + + It("returns an InvalidCryptoMessageParameter error if it can't parse the cert chain", func() { + tagMap[TagCERT] = []byte("cert") + certManager.setDataError = errors.New("can't parse") + err := cs.handleREJMessage(tagMap) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid"))) + }) + + Context("verifying the certificate chain", func() { + It("returns a ProofInvalid error if the certificate chain is not valid", func() { + tagMap[TagCERT] = []byte("cert") + certManager.verifyError = errors.New("invalid") + err := cs.handleREJMessage(tagMap) + Expect(err).To(MatchError(qerr.ProofInvalid)) + }) + + It("verifies the certificate", func() { + certManager.verifyServerProofResult = true + tagMap[TagCERT] = []byte("cert") + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(certManager.verifyCalled).To(BeTrue()) + }) + }) + + Context("verifying the signature", func() { + BeforeEach(func() { + tagMap[TagCERT] = []byte("cert") + tagMap[TagPROF] = []byte("proof") + certManager.leafCert = []byte("leafcert") + }) + + It("rejects wrong signature", func() { + certManager.verifyServerProofResult = false + err := cs.handleREJMessage(tagMap) + Expect(err).To(MatchError(qerr.ProofInvalid)) + Expect(certManager.verifyServerProofCalled).To(BeTrue()) + }) + + It("accepts correct signatures", func() { + certManager.verifyServerProofResult = true + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(certManager.verifyServerProofCalled).To(BeTrue()) + }) + + It("doesn't try to verify the signature if the certificate is missing", func() { + delete(tagMap, TagCERT) + certManager.leafCert = nil + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(certManager.verifyServerProofCalled).To(BeFalse()) + }) + + It("doesn't try to verify the signature if the server config is missing", func() { + cs.serverConfig = nil + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(certManager.verifyServerProofCalled).To(BeFalse()) + }) + + It("doesn't try to verify the signature if the signature is missing", func() { + delete(tagMap, TagPROF) + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(certManager.verifyServerProofCalled).To(BeFalse()) + }) + }) + }) + + Context("Reading server configs", func() { + It("reads a server config", func() { + b := &bytes.Buffer{} + scfg := getDefaultServerConfigClient() + HandshakeMessage{Tag: TagSCFG, Data: scfg}.Write(b) + tagMap[TagSCFG] = b.Bytes() + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.serverConfig).ToNot(BeNil()) + Expect(cs.serverConfig.ID).To(Equal(scfg[TagSCID])) + }) + + It("rejects expired server configs", func() { + b := &bytes.Buffer{} + scfg := getDefaultServerConfigClient() + scfg[TagEXPY] = []byte{0x80, 0x54, 0x72, 0x4F, 0, 0, 0, 0} // 2012-03-28 + HandshakeMessage{Tag: TagSCFG, Data: scfg}.Write(b) + tagMap[TagSCFG] = b.Bytes() + // make sure we actually set TagEXPY correct + serverConfig, err := parseServerConfig(b.Bytes()) + Expect(err).ToNot(HaveOccurred()) + Expect(serverConfig.expiry.Year()).To(Equal(2012)) + // now try to read this server config in the crypto setup + err = cs.handleREJMessage(tagMap) + Expect(err).To(MatchError(qerr.CryptoServerConfigExpired)) + }) + + It("generates a client nonce after reading a server config", func() { + b := &bytes.Buffer{} + HandshakeMessage{Tag: TagSCFG, Data: getDefaultServerConfigClient()}.Write(b) + tagMap[TagSCFG] = b.Bytes() + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.nonc).To(HaveLen(32)) + }) + + It("only generates a client nonce once, when reading multiple server configs", func() { + b := &bytes.Buffer{} + HandshakeMessage{Tag: TagSCFG, Data: getDefaultServerConfigClient()}.Write(b) + tagMap[TagSCFG] = b.Bytes() + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + nonc := cs.nonc + Expect(nonc).ToNot(BeEmpty()) + err = cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.nonc).To(Equal(nonc)) + }) + + It("passes on errors from reading the server config", func() { + b := &bytes.Buffer{} + HandshakeMessage{Tag: TagSHLO, Data: make(map[Tag][]byte)}.Write(b) + tagMap[TagSCFG] = b.Bytes() + _, origErr := parseServerConfig(b.Bytes()) + err := cs.handleREJMessage(tagMap) + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(origErr)) + }) + }) + }) + + Context("Reading SHLO", func() { + BeforeEach(func() { + kex, err := crypto.NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + serverConfig := &serverConfigClient{ + kex: kex, + } + cs.serverConfig = serverConfig + cs.receivedSecurePacket = true + }) + + It("rejects unencrypted SHLOs", func() { + cs.receivedSecurePacket = false + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).To(MatchError(qerr.Error(qerr.CryptoEncryptionLevelIncorrect, "unencrypted SHLO message"))) + Expect(handshakeEvent).ToNot(Receive()) + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("rejects SHLOs without a PUBS", func() { + delete(shloMap, TagPUBS) + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).To(MatchError(qerr.Error(qerr.CryptoMessageParameterNotFound, "PUBS"))) + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("rejects SHLOs without a version list", func() { + delete(shloMap, TagVER) + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "server hello missing version list"))) + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("accepts a SHLO after a version negotiation", func() { + ver := protocol.SupportedVersions[0] + cs.negotiatedVersions = []protocol.VersionNumber{ver} + cs.receivedSecurePacket = true + b := &bytes.Buffer{} + utils.BigEndian.WriteUint32(b, uint32(ver)) + shloMap[TagVER] = b.Bytes() + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).ToNot(HaveOccurred()) + }) + + It("reads the server nonce, if set", func() { + shloMap[TagSNO] = []byte("server nonce") + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.sno).To(Equal(shloMap[TagSNO])) + }) + + It("creates a forwardSecureAEAD", func() { + shloMap[TagSNO] = []byte("server nonce") + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.forwardSecureAEAD).ToNot(BeNil()) + }) + + It("reads the connection parameters", func() { + shloMap[TagICSL] = []byte{13, 0, 0, 0} // 13 seconds + params, err := cs.handleSHLOMessage(shloMap) + Expect(err).ToNot(HaveOccurred()) + Expect(params.IdleTimeout).To(Equal(13 * time.Second)) + }) + + It("closes the handshakeEvent chan when receiving an SHLO", func() { + HandshakeMessage{Tag: TagSHLO, Data: shloMap}.Write(&stream.dataToRead) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + Eventually(handshakeEvent).Should(Receive()) + Eventually(handshakeEvent).Should(BeClosed()) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + + It("passes the transport parameters on the channel", func() { + shloMap[TagSFCW] = []byte{0x0d, 0x00, 0xdf, 0xba} + HandshakeMessage{Tag: TagSHLO, Data: shloMap}.Write(&stream.dataToRead) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + var params TransportParameters + Eventually(paramsChan).Should(Receive(¶ms)) + Expect(params.StreamFlowControlWindow).To(Equal(protocol.ByteCount(0xbadf000d))) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + + It("errors if it can't read a connection parameter", func() { + shloMap[TagICSL] = []byte{3, 0, 0} // 1 byte too short + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).To(MatchError(qerr.InvalidCryptoMessageParameter)) + }) + }) + + Context("CHLO generation", func() { + It("is longer than the miminum client hello size", func() { + err := cs.sendCHLO() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.cryptoStream.(*mockStream).dataWritten.Len()).To(BeNumerically(">", protocol.MinClientHelloSize)) + }) + + It("doesn't overflow the packet with padding", func() { + tagMap := make(map[Tag][]byte) + tagMap[TagSCID] = bytes.Repeat([]byte{0}, protocol.MinClientHelloSize*6/10) + cs.addPadding(tagMap) + Expect(len(tagMap[TagPAD])).To(BeNumerically("<", protocol.MinClientHelloSize/2)) + }) + + It("saves the last sent CHLO", func() { + // send first CHLO + err := cs.sendCHLO() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.cryptoStream.(*mockStream).dataWritten.Bytes()).To(Equal(cs.lastSentCHLO)) + cs.cryptoStream.(*mockStream).dataWritten.Reset() + firstCHLO := cs.lastSentCHLO + // send second CHLO + cs.sno = []byte("foobar") + err = cs.sendCHLO() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.cryptoStream.(*mockStream).dataWritten.Bytes()).To(Equal(cs.lastSentCHLO)) + Expect(cs.lastSentCHLO).ToNot(Equal(firstCHLO)) + }) + + It("has the right values for an inchoate CHLO", func() { + cs.version = cs.initialVersion - 1 + cs.hostname = "sni-hostname" + certManager.commonCertificateHashes = []byte("common certs") + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(string(tags[TagSNI])).To(Equal(cs.hostname)) + Expect(tags[TagPDMD]).To(Equal([]byte("X509"))) + Expect(tags[TagVER]).To(Equal([]byte("Q039"))) + Expect(tags[TagCCS]).To(Equal(certManager.commonCertificateHashes)) + Expect(tags).ToNot(HaveKey(TagTCID)) + }) + + It("requests to omit the connection ID", func() { + cs.params.OmitConnectionID = true + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags).To(HaveKeyWithValue(TagTCID, []byte{0, 0, 0, 0})) + }) + + It("adds the tags returned from the connectionParametersManager to the CHLO", func() { + pnTags := cs.params.getHelloMap() + Expect(pnTags).ToNot(BeEmpty()) + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + for t := range pnTags { + Expect(tags).To(HaveKey(t)) + } + }) + + It("doesn't send a CCS if there are no common certificate sets available", func() { + certManager.commonCertificateHashes = nil + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags).ToNot(HaveKey(TagCCS)) + }) + + It("includes the server config id, if available", func() { + id := []byte("foobar") + cs.serverConfig = &serverConfigClient{ID: id} + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags[TagSCID]).To(Equal(id)) + }) + + It("includes the source address token, if available", func() { + cs.stk = []byte("sourceaddresstoken") + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags[TagSTK]).To(Equal(cs.stk)) + }) + + It("includes the server nonce, if available", func() { + cs.sno = []byte("foobar") + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags[TagSNO]).To(Equal(cs.sno)) + }) + + It("doesn't include optional values, if not available", func() { + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags).ToNot(HaveKey(TagSCID)) + Expect(tags).ToNot(HaveKey(TagSNO)) + Expect(tags).ToNot(HaveKey(TagSTK)) + }) + + It("doesn't change any values after reading the certificate, if the server config is missing", func() { + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + certManager.leafCert = []byte("leafcert") + Expect(cs.getTags()).To(Equal(tags)) + }) + + It("sends a the values needed for a full CHLO after reading the certificate and the server config", func() { + certManager.leafCert = []byte("leafcert") + cs.nonc = []byte("client-nonce") + kex, err := crypto.NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + cs.serverConfig = &serverConfigClient{kex: kex} + xlct := []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8} + certManager.leafCertHash = binary.LittleEndian.Uint64(xlct) + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags[TagNONC]).To(Equal(cs.nonc)) + Expect(tags[TagPUBS]).To(Equal(kex.PublicKey())) + Expect(tags[TagXLCT]).To(Equal(xlct)) + Expect(tags[TagKEXS]).To(Equal([]byte("C255"))) + Expect(tags[TagAEAD]).To(Equal([]byte("AESG"))) + }) + + It("doesn't send more than MaxClientHellos CHLOs", func() { + Expect(cs.clientHelloCounter).To(BeZero()) + for i := 1; i <= protocol.MaxClientHellos; i++ { + err := cs.sendCHLO() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.clientHelloCounter).To(Equal(i)) + } + err := cs.sendCHLO() + Expect(err).To(MatchError(qerr.Error(qerr.CryptoTooManyRejects, fmt.Sprintf("More than %d rejects", protocol.MaxClientHellos)))) + }) + }) + + Context("escalating crypto", func() { + doCompleteREJ := func() { + cs.serverVerified = true + err := cs.maybeUpgradeCrypto() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.secureAEAD).ToNot(BeNil()) + } + + doSHLO := func() { + cs.receivedSecurePacket = true + _, err := cs.handleSHLOMessage(shloMap) + Expect(err).ToNot(HaveOccurred()) + } + + // sets all values necessary for escalating to secureAEAD + BeforeEach(func() { + kex, err := crypto.NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + cs.serverConfig = &serverConfigClient{ + kex: kex, + obit: []byte("obit"), + sharedSecret: []byte("sharedSecret"), + raw: []byte("rawserverconfig"), + } + cs.lastSentCHLO = []byte("lastSentCHLO") + cs.nonc = []byte("nonc") + cs.diversificationNonce = []byte("divnonce") + certManager.leafCert = []byte("leafCert") + }) + + It("creates a secureAEAD once it has all necessary values", func() { + cs.serverVerified = true + err := cs.maybeUpgradeCrypto() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.secureAEAD).ToNot(BeNil()) + Expect(keyDerivationCalledWith.forwardSecure).To(BeFalse()) + Expect(keyDerivationCalledWith.sharedSecret).To(Equal(cs.serverConfig.sharedSecret)) + Expect(keyDerivationCalledWith.nonces).To(Equal(cs.nonc)) + Expect(keyDerivationCalledWith.connID).To(Equal(cs.connID)) + Expect(keyDerivationCalledWith.chlo).To(Equal(cs.lastSentCHLO)) + Expect(keyDerivationCalledWith.scfg).To(Equal(cs.serverConfig.Get())) + Expect(keyDerivationCalledWith.cert).To(Equal(certManager.leafCert)) + Expect(keyDerivationCalledWith.divNonce).To(Equal(cs.diversificationNonce)) + Expect(keyDerivationCalledWith.pers).To(Equal(protocol.PerspectiveClient)) + Expect(handshakeEvent).To(Receive()) + Expect(handshakeEvent).ToNot(Receive()) + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("uses the server nonce, if the server sent one", func() { + cs.serverVerified = true + cs.sno = []byte("server nonce") + err := cs.maybeUpgradeCrypto() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.secureAEAD).ToNot(BeNil()) + Expect(keyDerivationCalledWith.nonces).To(Equal(append(cs.nonc, cs.sno...))) + Expect(handshakeEvent).To(Receive()) + Expect(handshakeEvent).ToNot(Receive()) + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("doesn't create a secureAEAD if the certificate is not yet verified, even if it has all necessary values", func() { + err := cs.maybeUpgradeCrypto() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.secureAEAD).To(BeNil()) + Expect(handshakeEvent).ToNot(Receive()) + cs.serverVerified = true + // make sure we really had all necessary values before, and only serverVerified was missing + err = cs.maybeUpgradeCrypto() + Expect(err).ToNot(HaveOccurred()) + Expect(cs.secureAEAD).ToNot(BeNil()) + Expect(handshakeEvent).To(Receive()) + Expect(handshakeEvent).ToNot(Receive()) + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("tries to escalate before reading a handshake message", func() { + Expect(cs.secureAEAD).To(BeNil()) + cs.serverVerified = true + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + Eventually(handshakeEvent).Should(Receive()) + Expect(cs.secureAEAD).ToNot(BeNil()) + Expect(handshakeEvent).ToNot(Receive()) + Expect(handshakeEvent).ToNot(BeClosed()) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + + It("tries to escalate the crypto after receiving a diversification nonce", func() { + done := make(chan struct{}) + cs.diversificationNonce = nil + cs.serverVerified = true + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + Expect(cs.secureAEAD).To(BeNil()) + Expect(cs.SetDiversificationNonce([]byte("div"))).To(Succeed()) + Eventually(handshakeEvent).Should(Receive()) + Expect(cs.secureAEAD).ToNot(BeNil()) + Expect(handshakeEvent).ToNot(Receive()) + Expect(handshakeEvent).ToNot(BeClosed()) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + + Context("null encryption", func() { + It("is used initially", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(10), []byte{}).Return([]byte("foobar unencrypted")) + enc, sealer := cs.GetSealer() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + d := sealer.Seal(nil, []byte("foobar"), 10, []byte{}) + Expect(d).To(Equal([]byte("foobar unencrypted"))) + }) + + It("is used for the crypto stream", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(1), []byte{}).Return([]byte("foobar unencrypted")) + enc, sealer := cs.GetSealerForCryptoStream() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + d := sealer.Seal(nil, []byte("foobar"), 1, []byte{}) + Expect(d).To(Equal([]byte("foobar unencrypted"))) + }) + + It("is accepted initially", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(1), []byte{}).Return([]byte("decrypted"), nil) + d, enc, err := cs.Open(nil, []byte("unencrypted"), 1, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("decrypted"))) + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("is accepted before the server sent an encrypted packet", func() { + doCompleteREJ() + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(1), []byte{}).Return(nil, errors.New("authentication failed")) + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(1), []byte{}).Return([]byte("decrypted"), nil) + cs.receivedSecurePacket = false + Expect(cs.secureAEAD).ToNot(BeNil()) + d, enc, err := cs.Open(nil, []byte("unencrypted"), 1, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("decrypted"))) + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("is not accepted after the server sent an encrypted packet", func() { + doCompleteREJ() + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(3), []byte{}).Return(nil, errors.New("authentication failed")) + cs.receivedSecurePacket = true + _, enc, err := cs.Open(nil, []byte("unencrypted"), 3, []byte{}) + Expect(err).To(MatchError("authentication failed")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("errors if the has the wrong hash", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("not unencrypted"), protocol.PacketNumber(3), []byte{}).Return(nil, errors.New("authentication failed")) + _, enc, err := cs.Open(nil, []byte("not unencrypted"), 3, []byte{}) + Expect(err).To(MatchError("authentication failed")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + }) + + Context("initial encryption", func() { + It("is used immediately when available", func() { + doCompleteREJ() + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(1), []byte{}).Return([]byte("foobar secure")) + cs.receivedSecurePacket = false + enc, sealer := cs.GetSealer() + Expect(enc).To(Equal(protocol.EncryptionSecure)) + d := sealer.Seal(nil, []byte("foobar"), 1, []byte{}) + Expect(d).To(Equal([]byte("foobar secure"))) + }) + + It("is accepted", func() { + doCompleteREJ() + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(3), []byte{}).Return([]byte("decrypted"), nil) + d, enc, err := cs.Open(nil, []byte("encrypted"), 3, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("decrypted"))) + Expect(enc).To(Equal(protocol.EncryptionSecure)) + Expect(cs.receivedSecurePacket).To(BeTrue()) + }) + + It("is not used after receiving the SHLO", func() { + doSHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(30), []byte{}).Return(nil, errors.New("authentication failed")) + _, enc, err := cs.Open(nil, []byte("encrypted"), 30, []byte{}) + Expect(err).To(MatchError("authentication failed")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("is not used for the crypto stream", func() { + doCompleteREJ() + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(3), []byte{}).Return([]byte("foobar unencrypted")) + enc, sealer := cs.GetSealerForCryptoStream() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + d := sealer.Seal(nil, []byte("foobar"), 3, []byte{}) + Expect(d).To(Equal([]byte("foobar unencrypted"))) + }) + }) + + Context("forward-secure encryption", func() { + It("is used after receiving the SHLO", func() { + doSHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("shlo"), protocol.PacketNumber(4), []byte{}) + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(10), []byte{}).Return([]byte("foobar forward sec")) + _, enc, err := cs.Open(nil, []byte("shlo"), 4, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) + enc, sealer := cs.GetSealer() + Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) + d := sealer.Seal(nil, []byte("foobar"), 10, []byte{}) + Expect(d).To(Equal([]byte("foobar forward sec"))) + }) + + It("is not used for the crypto stream", func() { + doSHLO() + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(3), []byte{}).Return([]byte("foobar unencrypted")) + enc, sealer := cs.GetSealerForCryptoStream() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + d := sealer.Seal(nil, []byte("foobar"), 3, []byte{}) + Expect(d).To(Equal([]byte("foobar unencrypted"))) + }) + }) + + Context("reporting the connection state", func() { + It("reports the connection state before the handshake completes", func() { + chain := []*x509.Certificate{testdata.GetCertificate().Leaf} + certManager.chain = chain + state := cs.ConnectionState() + Expect(state.HandshakeComplete).To(BeFalse()) + Expect(state.PeerCertificates).To(Equal(chain)) + }) + + It("reports the connection state after the handshake completes", func() { + doSHLO() + state := cs.ConnectionState() + Expect(state.HandshakeComplete).To(BeTrue()) + }) + }) + + Context("forcing encryption levels", func() { + It("forces null encryption", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(4), []byte{}).Return([]byte("foobar unencrypted")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionUnencrypted) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 4, []byte{}) + Expect(d).To(Equal([]byte("foobar unencrypted"))) + }) + + It("forces initial encryption", func() { + doCompleteREJ() + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(3), []byte{}).Return([]byte("foobar secure")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionSecure) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 3, []byte{}) + Expect(d).To(Equal([]byte("foobar secure"))) + }) + + It("errors of no AEAD for initial encryption is available", func() { + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionSecure) + Expect(err).To(MatchError("CryptoSetupClient: no secureAEAD")) + Expect(sealer).To(BeNil()) + }) + + It("forces forward-secure encryption", func() { + doSHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(4), []byte{}).Return([]byte("foobar forward sec")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionForwardSecure) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 4, []byte{}) + Expect(d).To(Equal([]byte("foobar forward sec"))) + }) + + It("errors of no AEAD for forward-secure encryption is available", func() { + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionForwardSecure) + Expect(err).To(MatchError("CryptoSetupClient: no forwardSecureAEAD")) + Expect(sealer).To(BeNil()) + }) + + It("errors if no encryption level is specified", func() { + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionUnspecified) + Expect(err).To(MatchError("CryptoSetupClient: no encryption level specified")) + Expect(sealer).To(BeNil()) + }) + }) + }) + + Context("Diversification Nonces", func() { + It("sets a diversification nonce", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + nonce := []byte("foobar") + Expect(cs.SetDiversificationNonce(nonce)).To(Succeed()) + Eventually(func() []byte { return cs.diversificationNonce }).Should(Equal(nonce)) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + + It("doesn't do anything when called multiple times with the same nonce", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + nonce := []byte("foobar") + Expect(cs.SetDiversificationNonce(nonce)).To(Succeed()) + Expect(cs.SetDiversificationNonce(nonce)).To(Succeed()) + Eventually(func() []byte { return cs.diversificationNonce }).Should(Equal(nonce)) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + + It("rejects a different diversification nonce", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.HandshakeFailed, errMockStreamClosing.Error()))) + close(done) + }() + nonce1 := []byte("foobar") + nonce2 := []byte("raboof") + err := cs.SetDiversificationNonce(nonce1) + Expect(err).ToNot(HaveOccurred()) + err = cs.SetDiversificationNonce(nonce2) + Expect(err).To(MatchError(errConflictingDiversificationNonces)) + // make the go routine return + stream.close() + Eventually(done).Should(BeClosed()) + }) + }) + + Context("Client Nonce generation", func() { + BeforeEach(func() { + cs.serverConfig = &serverConfigClient{} + cs.serverConfig.obit = []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8} + }) + + It("generates a client nonce", func() { + now := time.Now() + err := cs.generateClientNonce() + Expect(cs.nonc).To(HaveLen(32)) + Expect(err).ToNot(HaveOccurred()) + Expect(time.Unix(int64(binary.BigEndian.Uint32(cs.nonc[0:4])), 0)).To(BeTemporally("~", now, 1*time.Second)) + Expect(cs.nonc[4:12]).To(Equal(cs.serverConfig.obit)) + }) + + It("uses random values for the last 20 bytes", func() { + err := cs.generateClientNonce() + Expect(err).ToNot(HaveOccurred()) + nonce1 := cs.nonc + cs.nonc = []byte{} + err = cs.generateClientNonce() + Expect(err).ToNot(HaveOccurred()) + nonce2 := cs.nonc + Expect(nonce1[4:12]).To(Equal(nonce2[4:12])) + Expect(nonce1[12:]).ToNot(Equal(nonce2[12:])) + }) + + It("errors if a client nonce has already been generated", func() { + err := cs.generateClientNonce() + Expect(err).ToNot(HaveOccurred()) + err = cs.generateClientNonce() + Expect(err).To(MatchError(errClientNonceAlreadyExists)) + }) + + It("errors if no OBIT value is available", func() { + cs.serverConfig.obit = []byte{} + err := cs.generateClientNonce() + Expect(err).To(MatchError(errNoObitForClientNonce)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server.go new file mode 100644 index 00000000..552e8297 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server.go @@ -0,0 +1,467 @@ +package handshake + +import ( + "bytes" + "crypto/rand" + "encoding/binary" + "errors" + "io" + "net" + "sync" + + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +// QuicCryptoKeyDerivationFunction is used for key derivation +type QuicCryptoKeyDerivationFunction func(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (crypto.AEAD, error) + +// KeyExchangeFunction is used to make a new KEX +type KeyExchangeFunction func() (crypto.KeyExchange, error) + +// The CryptoSetupServer handles all things crypto for the Session +type cryptoSetupServer struct { + mutex sync.RWMutex + + connID protocol.ConnectionID + remoteAddr net.Addr + scfg *ServerConfig + diversificationNonce []byte + + version protocol.VersionNumber + supportedVersions []protocol.VersionNumber + + acceptSTKCallback func(net.Addr, *Cookie) bool + + nullAEAD crypto.AEAD + secureAEAD crypto.AEAD + forwardSecureAEAD crypto.AEAD + receivedForwardSecurePacket bool + receivedSecurePacket bool + sentSHLO chan struct{} // this channel is closed as soon as the SHLO has been written + + receivedParams bool + paramsChan chan<- TransportParameters + handshakeEvent chan<- struct{} + + keyDerivation QuicCryptoKeyDerivationFunction + keyExchange KeyExchangeFunction + + cryptoStream io.ReadWriter + + params *TransportParameters + + sni string // need to fill out the ConnectionState + + logger utils.Logger +} + +var _ CryptoSetup = &cryptoSetupServer{} + +// ErrNSTPExperiment is returned when the client sends the NSTP tag in the CHLO. +// This is an experiment implemented by Chrome in QUIC 38, which we don't support at this point. +var ErrNSTPExperiment = qerr.Error(qerr.InvalidCryptoMessageParameter, "NSTP experiment. Unsupported") + +// NewCryptoSetup creates a new CryptoSetup instance for a server +func NewCryptoSetup( + cryptoStream io.ReadWriter, + connID protocol.ConnectionID, + remoteAddr net.Addr, + version protocol.VersionNumber, + divNonce []byte, + scfg *ServerConfig, + params *TransportParameters, + supportedVersions []protocol.VersionNumber, + acceptSTK func(net.Addr, *Cookie) bool, + paramsChan chan<- TransportParameters, + handshakeEvent chan<- struct{}, + logger utils.Logger, +) (CryptoSetup, error) { + nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, connID, version) + if err != nil { + return nil, err + } + return &cryptoSetupServer{ + cryptoStream: cryptoStream, + connID: connID, + remoteAddr: remoteAddr, + version: version, + supportedVersions: supportedVersions, + diversificationNonce: divNonce, + scfg: scfg, + keyDerivation: crypto.DeriveQuicCryptoAESKeys, + keyExchange: getEphermalKEX, + nullAEAD: nullAEAD, + params: params, + acceptSTKCallback: acceptSTK, + sentSHLO: make(chan struct{}), + paramsChan: paramsChan, + handshakeEvent: handshakeEvent, + logger: logger, + }, nil +} + +// HandleCryptoStream reads and writes messages on the crypto stream +func (h *cryptoSetupServer) HandleCryptoStream() error { + for { + var chloData bytes.Buffer + message, err := ParseHandshakeMessage(io.TeeReader(h.cryptoStream, &chloData)) + if err != nil { + return qerr.HandshakeFailed + } + if message.Tag != TagCHLO { + return qerr.InvalidCryptoMessageType + } + + h.logger.Debugf("Got %s", message) + done, err := h.handleMessage(chloData.Bytes(), message.Data) + if err != nil { + return err + } + if done { + return nil + } + } +} + +func (h *cryptoSetupServer) handleMessage(chloData []byte, cryptoData map[Tag][]byte) (bool, error) { + if _, isNSTPExperiment := cryptoData[TagNSTP]; isNSTPExperiment { + return false, ErrNSTPExperiment + } + + sniSlice, ok := cryptoData[TagSNI] + if !ok { + return false, qerr.Error(qerr.CryptoMessageParameterNotFound, "SNI required") + } + sni := string(sniSlice) + if sni == "" { + return false, qerr.Error(qerr.CryptoMessageParameterNotFound, "SNI required") + } + h.sni = sni + + // prevent version downgrade attacks + // see https://groups.google.com/a/chromium.org/forum/#!topic/proto-quic/N-de9j63tCk for a discussion and examples + verSlice, ok := cryptoData[TagVER] + if !ok { + return false, qerr.Error(qerr.InvalidCryptoMessageParameter, "client hello missing version tag") + } + if len(verSlice) != 4 { + return false, qerr.Error(qerr.InvalidCryptoMessageParameter, "incorrect version tag") + } + ver := protocol.VersionNumber(binary.BigEndian.Uint32(verSlice)) + // If the client's preferred version is not the version we are currently speaking, then the client went through a version negotiation. In this case, we need to make sure that we actually do not support this version and that it wasn't a downgrade attack. + if ver != h.version && protocol.IsSupportedVersion(h.supportedVersions, ver) { + return false, qerr.Error(qerr.VersionNegotiationMismatch, "Downgrade attack detected") + } + + var reply []byte + var err error + + certUncompressed, err := h.scfg.certChain.GetLeafCert(sni) + if err != nil { + return false, err + } + + params, err := readHelloMap(cryptoData) + if err != nil { + return false, err + } + // blocks until the session has received the parameters + if !h.receivedParams { + h.receivedParams = true + h.paramsChan <- *params + } + + if !h.isInchoateCHLO(cryptoData, certUncompressed) { + // We have a CHLO with a proper server config ID, do a 0-RTT handshake + reply, err = h.handleCHLO(sni, chloData, cryptoData) + if err != nil { + return false, err + } + if _, err := h.cryptoStream.Write(reply); err != nil { + return false, err + } + h.handshakeEvent <- struct{}{} + close(h.sentSHLO) + return true, nil + } + + // We have an inchoate or non-matching CHLO, we now send a rejection + reply, err = h.handleInchoateCHLO(sni, chloData, cryptoData) + if err != nil { + return false, err + } + _, err = h.cryptoStream.Write(reply) + return false, err +} + +// Open a message +func (h *cryptoSetupServer) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) { + h.mutex.RLock() + defer h.mutex.RUnlock() + + if h.forwardSecureAEAD != nil { + res, err := h.forwardSecureAEAD.Open(dst, src, packetNumber, associatedData) + if err == nil { + if !h.receivedForwardSecurePacket { // this is the first forward secure packet we receive from the client + h.logger.Debugf("Received first forward-secure packet. Stopping to accept all lower encryption levels.") + h.receivedForwardSecurePacket = true + // wait for the send on the handshakeEvent chan + <-h.sentSHLO + close(h.handshakeEvent) + } + return res, protocol.EncryptionForwardSecure, nil + } + if h.receivedForwardSecurePacket { + return nil, protocol.EncryptionUnspecified, err + } + } + if h.secureAEAD != nil { + res, err := h.secureAEAD.Open(dst, src, packetNumber, associatedData) + if err == nil { + h.logger.Debugf("Received first secure packet. Stopping to accept unencrypted packets.") + h.receivedSecurePacket = true + return res, protocol.EncryptionSecure, nil + } + if h.receivedSecurePacket { + return nil, protocol.EncryptionUnspecified, err + } + } + res, err := h.nullAEAD.Open(dst, src, packetNumber, associatedData) + if err != nil { + return res, protocol.EncryptionUnspecified, err + } + return res, protocol.EncryptionUnencrypted, err +} + +func (h *cryptoSetupServer) GetSealer() (protocol.EncryptionLevel, Sealer) { + h.mutex.RLock() + defer h.mutex.RUnlock() + if h.forwardSecureAEAD != nil { + return protocol.EncryptionForwardSecure, h.forwardSecureAEAD + } + return protocol.EncryptionUnencrypted, h.nullAEAD +} + +func (h *cryptoSetupServer) GetSealerForCryptoStream() (protocol.EncryptionLevel, Sealer) { + h.mutex.RLock() + defer h.mutex.RUnlock() + if h.secureAEAD != nil { + return protocol.EncryptionSecure, h.secureAEAD + } + return protocol.EncryptionUnencrypted, h.nullAEAD +} + +func (h *cryptoSetupServer) GetSealerWithEncryptionLevel(encLevel protocol.EncryptionLevel) (Sealer, error) { + h.mutex.RLock() + defer h.mutex.RUnlock() + + switch encLevel { + case protocol.EncryptionUnencrypted: + return h.nullAEAD, nil + case protocol.EncryptionSecure: + if h.secureAEAD == nil { + return nil, errors.New("CryptoSetupServer: no secureAEAD") + } + return h.secureAEAD, nil + case protocol.EncryptionForwardSecure: + if h.forwardSecureAEAD == nil { + return nil, errors.New("CryptoSetupServer: no forwardSecureAEAD") + } + return h.forwardSecureAEAD, nil + } + return nil, errors.New("CryptoSetupServer: no encryption level specified") +} + +func (h *cryptoSetupServer) isInchoateCHLO(cryptoData map[Tag][]byte, cert []byte) bool { + if _, ok := cryptoData[TagPUBS]; !ok { + return true + } + scid, ok := cryptoData[TagSCID] + if !ok || !bytes.Equal(h.scfg.ID, scid) { + return true + } + xlctTag, ok := cryptoData[TagXLCT] + if !ok || len(xlctTag) != 8 { + return true + } + xlct := binary.LittleEndian.Uint64(xlctTag) + if crypto.HashCert(cert) != xlct { + return true + } + return !h.acceptSTK(cryptoData[TagSTK]) +} + +func (h *cryptoSetupServer) acceptSTK(token []byte) bool { + stk, err := h.scfg.cookieGenerator.DecodeToken(token) + if err != nil { + h.logger.Debugf("STK invalid: %s", err.Error()) + return false + } + return h.acceptSTKCallback(h.remoteAddr, stk) +} + +func (h *cryptoSetupServer) handleInchoateCHLO(sni string, chlo []byte, cryptoData map[Tag][]byte) ([]byte, error) { + token, err := h.scfg.cookieGenerator.NewToken(h.remoteAddr) + if err != nil { + return nil, err + } + + replyMap := map[Tag][]byte{ + TagSCFG: h.scfg.Get(), + TagSTK: token, + TagSVID: []byte("quic-go"), + } + + if h.acceptSTK(cryptoData[TagSTK]) { + proof, err := h.scfg.Sign(sni, chlo) + if err != nil { + return nil, err + } + + commonSetHashes := cryptoData[TagCCS] + cachedCertsHashes := cryptoData[TagCCRT] + + certCompressed, err := h.scfg.GetCertsCompressed(sni, commonSetHashes, cachedCertsHashes) + if err != nil { + return nil, err + } + // Token was valid, send more details + replyMap[TagPROF] = proof + replyMap[TagCERT] = certCompressed + } + + message := HandshakeMessage{ + Tag: TagREJ, + Data: replyMap, + } + + var serverReply bytes.Buffer + message.Write(&serverReply) + h.logger.Debugf("Sending %s", message) + return serverReply.Bytes(), nil +} + +func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[Tag][]byte) ([]byte, error) { + // We have a CHLO matching our server config, we can continue with the 0-RTT handshake + sharedSecret, err := h.scfg.kex.CalculateSharedKey(cryptoData[TagPUBS]) + if err != nil { + return nil, err + } + + h.mutex.Lock() + defer h.mutex.Unlock() + + certUncompressed, err := h.scfg.certChain.GetLeafCert(sni) + if err != nil { + return nil, err + } + + serverNonce := make([]byte, 32) + if _, err = rand.Read(serverNonce); err != nil { + return nil, err + } + + clientNonce := cryptoData[TagNONC] + err = h.validateClientNonce(clientNonce) + if err != nil { + return nil, err + } + + aead := cryptoData[TagAEAD] + if !bytes.Equal(aead, []byte("AESG")) { + return nil, qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS") + } + + kexs := cryptoData[TagKEXS] + if !bytes.Equal(kexs, []byte("C255")) { + return nil, qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS") + } + + h.secureAEAD, err = h.keyDerivation( + false, + sharedSecret, + clientNonce, + h.connID, + data, + h.scfg.Get(), + certUncompressed, + h.diversificationNonce, + protocol.PerspectiveServer, + ) + if err != nil { + return nil, err + } + h.logger.Debugf("Creating AEAD for secure encryption.") + h.handshakeEvent <- struct{}{} + + // Generate a new curve instance to derive the forward secure key + var fsNonce bytes.Buffer + fsNonce.Write(clientNonce) + fsNonce.Write(serverNonce) + ephermalKex, err := h.keyExchange() + if err != nil { + return nil, err + } + ephermalSharedSecret, err := ephermalKex.CalculateSharedKey(cryptoData[TagPUBS]) + if err != nil { + return nil, err + } + + h.forwardSecureAEAD, err = h.keyDerivation( + true, + ephermalSharedSecret, + fsNonce.Bytes(), + h.connID, + data, + h.scfg.Get(), + certUncompressed, + nil, + protocol.PerspectiveServer, + ) + if err != nil { + return nil, err + } + h.logger.Debugf("Creating AEAD for forward-secure encryption.") + + replyMap := h.params.getHelloMap() + // add crypto parameters + verTag := &bytes.Buffer{} + for _, v := range h.supportedVersions { + utils.BigEndian.WriteUint32(verTag, uint32(v)) + } + replyMap[TagPUBS] = ephermalKex.PublicKey() + replyMap[TagSNO] = serverNonce + replyMap[TagVER] = verTag.Bytes() + + // note that the SHLO *has* to fit into one packet + message := HandshakeMessage{ + Tag: TagSHLO, + Data: replyMap, + } + var reply bytes.Buffer + message.Write(&reply) + h.logger.Debugf("Sending %s", message) + return reply.Bytes(), nil +} + +func (h *cryptoSetupServer) ConnectionState() ConnectionState { + h.mutex.Lock() + defer h.mutex.Unlock() + return ConnectionState{ + ServerName: h.sni, + HandshakeComplete: h.receivedForwardSecurePacket, + } +} + +func (h *cryptoSetupServer) validateClientNonce(nonce []byte) error { + if len(nonce) != 32 { + return qerr.Error(qerr.InvalidCryptoMessageParameter, "invalid client nonce length") + } + if !bytes.Equal(nonce[4:12], h.scfg.obit) { + return qerr.Error(qerr.InvalidCryptoMessageParameter, "OBIT not matching") + } + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server_test.go new file mode 100644 index 00000000..7b4a0e94 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_server_test.go @@ -0,0 +1,731 @@ +package handshake + +import ( + "bytes" + "encoding/binary" + "errors" + "io" + "net" + "time" + + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/mocks/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockKEX struct { + ephermal bool + sharedKeyError error +} + +func (m *mockKEX) PublicKey() []byte { + if m.ephermal { + return []byte("ephermal pub") + } + return []byte("initial public") +} + +func (m *mockKEX) CalculateSharedKey(otherPublic []byte) ([]byte, error) { + if m.sharedKeyError != nil { + return nil, m.sharedKeyError + } + if m.ephermal { + return []byte("shared ephermal"), nil + } + return []byte("shared key"), nil +} + +type mockSigner struct { + gotCHLO bool +} + +func (s *mockSigner) SignServerProof(sni string, chlo []byte, serverConfigData []byte) ([]byte, error) { + if len(chlo) > 0 { + s.gotCHLO = true + } + return []byte("proof"), nil +} +func (*mockSigner) GetCertsCompressed(sni string, common, cached []byte) ([]byte, error) { + return []byte("certcompressed"), nil +} +func (*mockSigner) GetLeafCert(sni string) ([]byte, error) { + return []byte("certuncompressed"), nil +} + +func mockQuicCryptoKeyDerivation(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (crypto.AEAD, error) { + return mockcrypto.NewMockAEAD(mockCtrl), nil +} + +type mockStream struct { + unblockRead chan struct{} + dataToRead bytes.Buffer + dataWritten bytes.Buffer +} + +var _ io.ReadWriter = &mockStream{} + +var errMockStreamClosing = errors.New("mock stream closing") + +func newMockStream() *mockStream { + return &mockStream{unblockRead: make(chan struct{})} +} + +// call Close to make Read return +func (s *mockStream) Read(p []byte) (int, error) { + n, _ := s.dataToRead.Read(p) + if n == 0 { // block if there's no data + <-s.unblockRead + return 0, errMockStreamClosing + } + return n, nil // never return an EOF +} + +func (s *mockStream) Write(p []byte) (int, error) { + return s.dataWritten.Write(p) +} + +func (s *mockStream) close() { + close(s.unblockRead) +} + +type mockCookieProtector struct { + decodeErr error +} + +var _ cookieProtector = &mockCookieProtector{} + +func (mockCookieProtector) NewToken(sourceAddr []byte) ([]byte, error) { + return append([]byte("token "), sourceAddr...), nil +} + +func (s mockCookieProtector) DecodeToken(data []byte) ([]byte, error) { + if s.decodeErr != nil { + return nil, s.decodeErr + } + if len(data) < 6 { + return nil, errors.New("token too short") + } + return data[6:], nil +} + +var _ = Describe("Server Crypto Setup", func() { + var ( + kex *mockKEX + signer *mockSigner + scfg *ServerConfig + cs *cryptoSetupServer + stream *mockStream + paramsChan chan TransportParameters + handshakeEvent chan struct{} + nonce32 []byte + versionTag []byte + validSTK []byte + aead []byte + kexs []byte + version protocol.VersionNumber + supportedVersions []protocol.VersionNumber + sourceAddrValid bool + ) + + const ( + expectedInitialNonceLen = 32 + expectedFSNonceLen = 64 + ) + + BeforeEach(func() { + var err error + remoteAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 1234} + + // use a buffered channel here, so that we can parse a CHLO without having to receive the TransportParameters to avoid blocking + paramsChan = make(chan TransportParameters, 1) + handshakeEvent = make(chan struct{}, 2) + stream = newMockStream() + kex = &mockKEX{} + signer = &mockSigner{} + scfg, err = NewServerConfig(kex, signer) + nonce32 = make([]byte, 32) + aead = []byte("AESG") + kexs = []byte("C255") + copy(nonce32[4:12], scfg.obit) // set the OBIT value at the right position + versionTag = make([]byte, 4) + binary.BigEndian.PutUint32(versionTag, uint32(protocol.VersionWhatever)) + Expect(err).NotTo(HaveOccurred()) + version = protocol.SupportedVersions[len(protocol.SupportedVersions)-1] + supportedVersions = []protocol.VersionNumber{version, 98, 99} + csInt, err := NewCryptoSetup( + stream, + protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + remoteAddr, + version, + make([]byte, 32), // div nonce + scfg, + &TransportParameters{IdleTimeout: protocol.DefaultIdleTimeout}, + supportedVersions, + nil, + paramsChan, + handshakeEvent, + utils.DefaultLogger, + ) + Expect(err).NotTo(HaveOccurred()) + cs = csInt.(*cryptoSetupServer) + cs.scfg.cookieGenerator.cookieProtector = &mockCookieProtector{} + validSTK, err = cs.scfg.cookieGenerator.NewToken(remoteAddr) + Expect(err).NotTo(HaveOccurred()) + sourceAddrValid = true + cs.acceptSTKCallback = func(_ net.Addr, _ *Cookie) bool { return sourceAddrValid } + cs.keyDerivation = mockQuicCryptoKeyDerivation + cs.keyExchange = func() (crypto.KeyExchange, error) { return &mockKEX{ephermal: true}, nil } + cs.nullAEAD = mockcrypto.NewMockAEAD(mockCtrl) + cs.cryptoStream = stream + }) + + Context("when responding to client messages", func() { + var cert []byte + var xlct []byte + var fullCHLO map[Tag][]byte + + BeforeEach(func() { + xlct = make([]byte, 8) + var err error + cert, err = cs.scfg.certChain.GetLeafCert("") + Expect(err).ToNot(HaveOccurred()) + binary.LittleEndian.PutUint64(xlct, crypto.HashCert(cert)) + fullCHLO = map[Tag][]byte{ + TagSCID: scfg.ID, + TagSNI: []byte("quic.clemente.io"), + TagNONC: nonce32, + TagSTK: validSTK, + TagXLCT: xlct, + TagAEAD: aead, + TagKEXS: kexs, + TagPUBS: bytes.Repeat([]byte{'e'}, 31), + TagVER: versionTag, + } + }) + + It("doesn't support Chrome's no STOP_WAITING experiment", func() { + HandshakeMessage{ + Tag: TagCHLO, + Data: map[Tag][]byte{ + TagNSTP: []byte("foobar"), + }, + }.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(ErrNSTPExperiment)) + }) + + It("reads the transport parameters sent by the client", func() { + sourceAddrValid = true + fullCHLO[TagICSL] = []byte{0x37, 0x13, 0, 0} + _, err := cs.handleMessage(bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), fullCHLO) + Expect(err).ToNot(HaveOccurred()) + var params TransportParameters + Expect(paramsChan).To(Receive(¶ms)) + Expect(params.IdleTimeout).To(Equal(0x1337 * time.Second)) + }) + + It("generates REJ messages", func() { + sourceAddrValid = false + response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), nil) + Expect(err).ToNot(HaveOccurred()) + Expect(response).To(HavePrefix("REJ")) + Expect(response).To(ContainSubstring("initial public")) + Expect(response).ToNot(ContainSubstring("certcompressed")) + Expect(response).ToNot(ContainSubstring("proof")) + Expect(signer.gotCHLO).To(BeFalse()) + }) + + It("REJ messages don't include cert or proof without STK", func() { + sourceAddrValid = false + response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), nil) + Expect(err).ToNot(HaveOccurred()) + Expect(response).To(HavePrefix("REJ")) + Expect(response).ToNot(ContainSubstring("certcompressed")) + Expect(response).ToNot(ContainSubstring("proof")) + Expect(signer.gotCHLO).To(BeFalse()) + }) + + It("REJ messages include cert and proof with valid STK", func() { + sourceAddrValid = true + response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), map[Tag][]byte{ + TagSTK: validSTK, + TagSNI: []byte("foo"), + }) + Expect(err).ToNot(HaveOccurred()) + Expect(response).To(HavePrefix("REJ")) + Expect(response).To(ContainSubstring("certcompressed")) + Expect(response).To(ContainSubstring("proof")) + Expect(signer.gotCHLO).To(BeTrue()) + }) + + It("generates SHLO messages", func() { + var checkedSecure, checkedForwardSecure bool + cs.keyDerivation = func(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (crypto.AEAD, error) { + if forwardSecure { + Expect(nonces).To(HaveLen(expectedFSNonceLen)) + checkedForwardSecure = true + Expect(sharedSecret).To(Equal([]byte("shared ephermal"))) + } else { + Expect(nonces).To(HaveLen(expectedInitialNonceLen)) + Expect(sharedSecret).To(Equal([]byte("shared key"))) + checkedSecure = true + } + return mockcrypto.NewMockAEAD(mockCtrl), nil + } + + response, err := cs.handleCHLO("", []byte("chlo-data"), map[Tag][]byte{ + TagPUBS: []byte("pubs-c"), + TagNONC: nonce32, + TagAEAD: aead, + TagKEXS: kexs, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(response).To(HavePrefix("SHLO")) + message, err := ParseHandshakeMessage(bytes.NewReader(response)) + Expect(err).ToNot(HaveOccurred()) + Expect(message.Data).To(HaveKeyWithValue(TagPUBS, []byte("ephermal pub"))) + Expect(message.Data).To(HaveKey(TagSNO)) + Expect(message.Data).To(HaveKey(TagVER)) + Expect(message.Data[TagVER]).To(HaveLen(4 * len(supportedVersions))) + for _, v := range supportedVersions { + b := &bytes.Buffer{} + utils.BigEndian.WriteUint32(b, uint32(v)) + Expect(message.Data[TagVER]).To(ContainSubstring(b.String())) + } + Expect(checkedSecure).To(BeTrue()) + Expect(checkedForwardSecure).To(BeTrue()) + }) + + It("handles long handshake", func() { + HandshakeMessage{ + Tag: TagCHLO, + Data: map[Tag][]byte{ + TagSNI: []byte("quic.clemente.io"), + TagSTK: validSTK, + TagPAD: bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), + TagVER: versionTag, + }, + }.Write(&stream.dataToRead) + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).NotTo(HaveOccurred()) + Expect(stream.dataWritten.Bytes()).To(HavePrefix("REJ")) + Expect(handshakeEvent).To(Receive()) // for the switch to secure + Expect(stream.dataWritten.Bytes()).To(ContainSubstring("SHLO")) + Expect(handshakeEvent).To(Receive()) // for the switch to forward secure + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("rejects client nonces that have the wrong length", func() { + fullCHLO[TagNONC] = []byte("too short client nonce") + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "invalid client nonce length"))) + }) + + It("rejects client nonces that have the wrong OBIT value", func() { + fullCHLO[TagNONC] = make([]byte, 32) // the OBIT value is nonce[4:12] and here just initialized to 0 + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "OBIT not matching"))) + }) + + It("errors if it can't calculate a shared key", func() { + testErr := errors.New("test error") + kex.sharedKeyError = testErr + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(testErr)) + }) + + It("handles 0-RTT handshake", func() { + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).NotTo(HaveOccurred()) + Expect(stream.dataWritten.Bytes()).To(HavePrefix("SHLO")) + Expect(stream.dataWritten.Bytes()).ToNot(ContainSubstring("REJ")) + Expect(handshakeEvent).To(Receive()) // for the switch to secure + Expect(handshakeEvent).To(Receive()) // for the switch to forward secure + Expect(handshakeEvent).ToNot(BeClosed()) + }) + + It("recognizes inchoate CHLOs missing SCID", func() { + delete(fullCHLO, TagSCID) + Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeTrue()) + }) + + It("recognizes inchoate CHLOs missing PUBS", func() { + delete(fullCHLO, TagPUBS) + Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeTrue()) + }) + + It("recognizes inchoate CHLOs with missing XLCT", func() { + delete(fullCHLO, TagXLCT) + Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeTrue()) + }) + + It("recognizes inchoate CHLOs with wrong length XLCT", func() { + fullCHLO[TagXLCT] = bytes.Repeat([]byte{'f'}, 7) // should be 8 bytes + Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeTrue()) + }) + + It("recognizes inchoate CHLOs with wrong XLCT", func() { + fullCHLO[TagXLCT] = bytes.Repeat([]byte{'f'}, 8) + Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeTrue()) + }) + + It("recognizes inchoate CHLOs with an invalid STK", func() { + testErr := errors.New("STK invalid") + cs.scfg.cookieGenerator.cookieProtector.(*mockCookieProtector).decodeErr = testErr + Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeTrue()) + }) + + It("recognizes proper CHLOs", func() { + Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeFalse()) + }) + + It("rejects CHLOs without the version tag", func() { + HandshakeMessage{ + Tag: TagCHLO, + Data: map[Tag][]byte{ + TagSCID: scfg.ID, + TagSNI: []byte("quic.clemente.io"), + }, + }.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "client hello missing version tag"))) + }) + + It("rejects CHLOs with a version tag that has the wrong length", func() { + fullCHLO[TagVER] = []byte{0x13, 0x37} // should be 4 bytes + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "incorrect version tag"))) + }) + + It("detects version downgrade attacks", func() { + highestSupportedVersion := supportedVersions[len(supportedVersions)-1] + lowestSupportedVersion := supportedVersions[0] + Expect(highestSupportedVersion).ToNot(Equal(lowestSupportedVersion)) + cs.version = highestSupportedVersion + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, uint32(lowestSupportedVersion)) + fullCHLO[TagVER] = b + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.VersionNegotiationMismatch, "Downgrade attack detected"))) + }) + + It("accepts a non-matching version tag in the CHLO, if it is an unsupported version", func() { + supportedVersion := protocol.SupportedVersions[0] + unsupportedVersion := supportedVersion + 1000 + Expect(protocol.IsSupportedVersion(supportedVersions, unsupportedVersion)).To(BeFalse()) + cs.version = supportedVersion + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, uint32(unsupportedVersion)) + fullCHLO[TagVER] = b + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors if the AEAD tag is missing", func() { + delete(fullCHLO, TagAEAD) + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS"))) + }) + + It("errors if the AEAD tag has the wrong value", func() { + fullCHLO[TagAEAD] = []byte("wrong") + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS"))) + }) + + It("errors if the KEXS tag is missing", func() { + delete(fullCHLO, TagKEXS) + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS"))) + }) + + It("errors if the KEXS tag has the wrong value", func() { + fullCHLO[TagKEXS] = []byte("wrong") + HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS"))) + }) + }) + + It("errors without SNI", func() { + HandshakeMessage{ + Tag: TagCHLO, + Data: map[Tag][]byte{ + TagSTK: validSTK, + }, + }.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError("CryptoMessageParameterNotFound: SNI required")) + }) + + It("errors with empty SNI", func() { + HandshakeMessage{ + Tag: TagCHLO, + Data: map[Tag][]byte{ + TagSTK: validSTK, + TagSNI: nil, + }, + }.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError("CryptoMessageParameterNotFound: SNI required")) + }) + + It("errors with invalid message", func() { + stream.dataToRead.Write([]byte("invalid message")) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.HandshakeFailed)) + }) + + It("errors with non-CHLO message", func() { + HandshakeMessage{Tag: TagPAD, Data: nil}.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(qerr.InvalidCryptoMessageType)) + }) + + Context("escalating crypto", func() { + doCHLO := func() { + _, err := cs.handleCHLO("", []byte("chlo-data"), map[Tag][]byte{ + TagPUBS: []byte("pubs-c"), + TagNONC: nonce32, + TagAEAD: aead, + TagKEXS: kexs, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(handshakeEvent).To(Receive()) // for the switch to secure + close(cs.sentSHLO) + } + + Context("null encryption", func() { + It("is used initially", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(10), []byte{}).Return([]byte("foobar signed")) + enc, sealer := cs.GetSealer() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + d := sealer.Seal(nil, []byte("foobar"), 10, []byte{}) + Expect(d).To(Equal([]byte("foobar signed"))) + }) + + It("is used for the crypto stream", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(0), []byte{}) + enc, sealer := cs.GetSealerForCryptoStream() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + sealer.Seal(nil, []byte("foobar"), 0, []byte{}) + }) + + It("is accepted initially", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(5), []byte{}).Return([]byte("decrypted"), nil) + d, enc, err := cs.Open(nil, []byte("unencrypted"), 5, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("decrypted"))) + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("errors if the has the wrong hash", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("not unencrypted"), protocol.PacketNumber(5), []byte{}).Return(nil, errors.New("authentication failed")) + _, enc, err := cs.Open(nil, []byte("not unencrypted"), 5, []byte{}) + Expect(err).To(MatchError("authentication failed")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("is still accepted after CHLO", func() { + doCHLO() + // it tries forward secure and secure decryption first + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(99), []byte{}).Return(nil, errors.New("authentication failed")) + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(99), []byte{}).Return(nil, errors.New("authentication failed")) + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(99), []byte{}) + Expect(cs.secureAEAD).ToNot(BeNil()) + _, enc, err := cs.Open(nil, []byte("unencrypted"), 99, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("is not accepted after receiving secure packet", func() { + doCHLO() + // first receive a secure packet + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(98), []byte{}).Return(nil, errors.New("authentication failed")) + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(98), []byte{}).Return([]byte("decrypted"), nil) + d, enc, err := cs.Open(nil, []byte("encrypted"), 98, []byte{}) + Expect(enc).To(Equal(protocol.EncryptionSecure)) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("decrypted"))) + // now receive an unencrypted packet + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(99), []byte{}).Return(nil, errors.New("authentication failed")) + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("unencrypted"), protocol.PacketNumber(99), []byte{}).Return(nil, errors.New("authentication failed")) + _, enc, err = cs.Open(nil, []byte("unencrypted"), 99, []byte{}) + Expect(err).To(MatchError("authentication failed")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("is not used after CHLO", func() { + doCHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(0), []byte{}) + enc, sealer := cs.GetSealer() + Expect(enc).ToNot(Equal(protocol.EncryptionUnencrypted)) + sealer.Seal(nil, []byte("foobar"), 0, []byte{}) + }) + }) + + Context("initial encryption", func() { + It("is accepted after CHLO", func() { + doCHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(98), []byte{}).Return(nil, errors.New("authentication failed")) + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(98), []byte{}).Return([]byte("decrypted"), nil) + d, enc, err := cs.Open(nil, []byte("encrypted"), 98, []byte{}) + Expect(enc).To(Equal(protocol.EncryptionSecure)) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("decrypted"))) + }) + + It("is not accepted after receiving forward secure packet", func() { + doCHLO() + // receive a forward secure packet + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("forward secure encrypted"), protocol.PacketNumber(11), []byte{}) + _, _, err := cs.Open(nil, []byte("forward secure encrypted"), 11, []byte{}) + Expect(err).ToNot(HaveOccurred()) + // receive a secure packet + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(12), []byte{}).Return(nil, errors.New("authentication failed")) + _, enc, err := cs.Open(nil, []byte("encrypted"), 12, []byte{}) + Expect(err).To(MatchError("authentication failed")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("is used for the crypto stream", func() { + doCHLO() + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(1), []byte{}).Return([]byte("foobar crypto stream")) + enc, sealer := cs.GetSealerForCryptoStream() + Expect(enc).To(Equal(protocol.EncryptionSecure)) + d := sealer.Seal(nil, []byte("foobar"), 1, []byte{}) + Expect(d).To(Equal([]byte("foobar crypto stream"))) + }) + }) + + Context("forward secure encryption", func() { + It("is used after the CHLO", func() { + doCHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(20), []byte{}).Return([]byte("foobar forward sec")) + enc, sealer := cs.GetSealer() + Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) + d := sealer.Seal(nil, []byte("foobar"), 20, []byte{}) + Expect(d).To(Equal([]byte("foobar forward sec"))) + }) + + It("regards the handshake as complete once it receives a forward encrypted packet", func() { + doCHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("forward secure encrypted"), protocol.PacketNumber(200), []byte{}) + _, _, err := cs.Open(nil, []byte("forward secure encrypted"), 200, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(handshakeEvent).To(BeClosed()) + }) + }) + + Context("reporting the connection state", func() { + It("reports before the handshake completes", func() { + cs.sni = "server name" + state := cs.ConnectionState() + Expect(state.HandshakeComplete).To(BeFalse()) + Expect(state.ServerName).To(Equal("server name")) + }) + + It("reports after the handshake completes", func() { + doCHLO() + // receive a forward secure packet + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("forward secure encrypted"), protocol.PacketNumber(11), []byte{}) + _, _, err := cs.Open(nil, []byte("forward secure encrypted"), 11, []byte{}) + Expect(err).ToNot(HaveOccurred()) + state := cs.ConnectionState() + Expect(state.HandshakeComplete).To(BeTrue()) + }) + }) + + Context("forcing encryption levels", func() { + It("forces null encryption", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(11), []byte{}).Return([]byte("foobar unencrypted")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionUnencrypted) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 11, []byte{}) + Expect(d).To(Equal([]byte("foobar unencrypted"))) + }) + + It("forces initial encryption", func() { + doCHLO() + cs.secureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(12), []byte{}).Return([]byte("foobar secure")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionSecure) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 12, []byte{}) + Expect(d).To(Equal([]byte("foobar secure"))) + }) + + It("errors if no AEAD for initial encryption is available", func() { + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionSecure) + Expect(err).To(MatchError("CryptoSetupServer: no secureAEAD")) + Expect(sealer).To(BeNil()) + }) + + It("forces forward-secure encryption", func() { + doCHLO() + cs.forwardSecureAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(13), []byte{}).Return([]byte("foobar forward sec")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionForwardSecure) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 13, []byte{}) + Expect(d).To(Equal([]byte("foobar forward sec"))) + }) + + It("errors of no AEAD for forward-secure encryption is available", func() { + seal, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionForwardSecure) + Expect(err).To(MatchError("CryptoSetupServer: no forwardSecureAEAD")) + Expect(seal).To(BeNil()) + }) + + It("errors if no encryption level is specified", func() { + seal, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionUnspecified) + Expect(err).To(MatchError("CryptoSetupServer: no encryption level specified")) + Expect(seal).To(BeNil()) + }) + }) + }) + + Context("STK verification and creation", func() { + It("requires STK", func() { + sourceAddrValid = false + done, err := cs.handleMessage( + bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), + map[Tag][]byte{ + TagSNI: []byte("foo"), + TagVER: versionTag, + }, + ) + Expect(err).ToNot(HaveOccurred()) + Expect(done).To(BeFalse()) + Expect(stream.dataWritten.Bytes()).To(ContainSubstring(string(validSTK))) + Expect(cs.sni).To(Equal("foo")) + }) + + It("works with proper STK", func() { + sourceAddrValid = true + done, err := cs.handleMessage( + bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), + map[Tag][]byte{ + TagSNI: []byte("foo"), + TagVER: versionTag, + }, + ) + Expect(err).ToNot(HaveOccurred()) + Expect(done).To(BeFalse()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls.go new file mode 100644 index 00000000..2e5dd025 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls.go @@ -0,0 +1,163 @@ +package handshake + +import ( + "errors" + "fmt" + "io" + "sync" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// KeyDerivationFunction is used for key derivation +type KeyDerivationFunction func(crypto.TLSExporter, protocol.Perspective) (crypto.AEAD, error) + +type cryptoSetupTLS struct { + mutex sync.RWMutex + + perspective protocol.Perspective + + keyDerivation KeyDerivationFunction + nullAEAD crypto.AEAD + aead crypto.AEAD + + tls mintTLS + conn *cryptoStreamConn + handshakeEvent chan<- struct{} +} + +var _ CryptoSetupTLS = &cryptoSetupTLS{} + +// NewCryptoSetupTLSServer creates a new TLS CryptoSetup instance for a server +func NewCryptoSetupTLSServer( + cryptoStream io.ReadWriter, + connID protocol.ConnectionID, + config *mint.Config, + handshakeEvent chan<- struct{}, + version protocol.VersionNumber, +) (CryptoSetupTLS, error) { + nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, connID, version) + if err != nil { + return nil, err + } + conn := newCryptoStreamConn(cryptoStream) + tls := mint.Server(conn, config) + return &cryptoSetupTLS{ + tls: tls, + conn: conn, + nullAEAD: nullAEAD, + perspective: protocol.PerspectiveServer, + keyDerivation: crypto.DeriveAESKeys, + handshakeEvent: handshakeEvent, + }, nil +} + +// NewCryptoSetupTLSClient creates a new TLS CryptoSetup instance for a client +func NewCryptoSetupTLSClient( + cryptoStream io.ReadWriter, + connID protocol.ConnectionID, + config *mint.Config, + handshakeEvent chan<- struct{}, + version protocol.VersionNumber, +) (CryptoSetupTLS, error) { + nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveClient, connID, version) + if err != nil { + return nil, err + } + conn := newCryptoStreamConn(cryptoStream) + tls := mint.Client(conn, config) + return &cryptoSetupTLS{ + tls: tls, + conn: conn, + perspective: protocol.PerspectiveClient, + nullAEAD: nullAEAD, + keyDerivation: crypto.DeriveAESKeys, + handshakeEvent: handshakeEvent, + }, nil +} + +func (h *cryptoSetupTLS) HandleCryptoStream() error { + for { + if alert := h.tls.Handshake(); alert != mint.AlertNoAlert { + return fmt.Errorf("TLS handshake error: %s (Alert %d)", alert.String(), alert) + } + state := h.tls.ConnectionState().HandshakeState + if err := h.conn.Flush(); err != nil { + return err + } + if state == mint.StateClientConnected || state == mint.StateServerConnected { + break + } + } + + aead, err := h.keyDerivation(h.tls, h.perspective) + if err != nil { + return err + } + h.mutex.Lock() + h.aead = aead + h.mutex.Unlock() + + h.handshakeEvent <- struct{}{} + close(h.handshakeEvent) + return nil +} + +func (h *cryptoSetupTLS) OpenHandshake(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { + return h.nullAEAD.Open(dst, src, packetNumber, associatedData) +} + +func (h *cryptoSetupTLS) Open1RTT(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { + h.mutex.RLock() + defer h.mutex.RUnlock() + + if h.aead == nil { + return nil, errors.New("no 1-RTT sealer") + } + return h.aead.Open(dst, src, packetNumber, associatedData) +} + +func (h *cryptoSetupTLS) GetSealer() (protocol.EncryptionLevel, Sealer) { + h.mutex.RLock() + defer h.mutex.RUnlock() + + if h.aead != nil { + return protocol.EncryptionForwardSecure, h.aead + } + return protocol.EncryptionUnencrypted, h.nullAEAD +} + +func (h *cryptoSetupTLS) GetSealerWithEncryptionLevel(encLevel protocol.EncryptionLevel) (Sealer, error) { + errNoSealer := fmt.Errorf("CryptoSetup: no sealer with encryption level %s", encLevel.String()) + h.mutex.RLock() + defer h.mutex.RUnlock() + + switch encLevel { + case protocol.EncryptionUnencrypted: + return h.nullAEAD, nil + case protocol.EncryptionForwardSecure: + if h.aead == nil { + return nil, errNoSealer + } + return h.aead, nil + default: + return nil, errNoSealer + } +} + +func (h *cryptoSetupTLS) GetSealerForCryptoStream() (protocol.EncryptionLevel, Sealer) { + return protocol.EncryptionUnencrypted, h.nullAEAD +} + +func (h *cryptoSetupTLS) ConnectionState() ConnectionState { + h.mutex.Lock() + defer h.mutex.Unlock() + mintConnState := h.tls.ConnectionState() + return ConnectionState{ + // TODO: set the ServerName, once mint exports it + HandshakeComplete: h.aead != nil, + PeerCertificates: mintConnState.PeerCertificates, + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls_test.go new file mode 100644 index 00000000..85c087ea --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_setup_tls_test.go @@ -0,0 +1,192 @@ +package handshake + +import ( + "bytes" + "errors" + "fmt" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/mocks/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func mockKeyDerivation(crypto.TLSExporter, protocol.Perspective) (crypto.AEAD, error) { + return mockcrypto.NewMockAEAD(mockCtrl), nil +} + +var _ = Describe("TLS Crypto Setup", func() { + var ( + cs *cryptoSetupTLS + handshakeEvent chan struct{} + ) + + BeforeEach(func() { + handshakeEvent = make(chan struct{}, 2) + css, err := NewCryptoSetupTLSServer( + newCryptoStreamConn(bytes.NewBuffer([]byte{})), + protocol.ConnectionID{}, + &mint.Config{}, + handshakeEvent, + protocol.VersionTLS, + ) + Expect(err).ToNot(HaveOccurred()) + cs = css.(*cryptoSetupTLS) + cs.nullAEAD = mockcrypto.NewMockAEAD(mockCtrl) + }) + + It("errors when the handshake fails", func() { + alert := mint.AlertBadRecordMAC + cs.tls = NewMockMintTLS(mockCtrl) + cs.tls.(*MockMintTLS).EXPECT().Handshake().Return(alert) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(fmt.Errorf("TLS handshake error: %s (Alert %d)", alert.String(), alert))) + }) + + It("derives keys", func() { + cs.tls = NewMockMintTLS(mockCtrl) + cs.tls.(*MockMintTLS).EXPECT().Handshake().Return(mint.AlertNoAlert) + cs.tls.(*MockMintTLS).EXPECT().ConnectionState().Return(mint.ConnectionState{HandshakeState: mint.StateServerConnected}) + cs.keyDerivation = mockKeyDerivation + err := cs.HandleCryptoStream() + Expect(err).ToNot(HaveOccurred()) + Expect(handshakeEvent).To(Receive()) + Expect(handshakeEvent).To(BeClosed()) + }) + + It("handshakes until it is connected", func() { + cs.tls = NewMockMintTLS(mockCtrl) + cs.tls.(*MockMintTLS).EXPECT().Handshake().Return(mint.AlertNoAlert).Times(10) + cs.tls.(*MockMintTLS).EXPECT().ConnectionState().Return(mint.ConnectionState{HandshakeState: mint.StateServerNegotiated}).Times(9) + cs.tls.(*MockMintTLS).EXPECT().ConnectionState().Return(mint.ConnectionState{HandshakeState: mint.StateServerConnected}) + cs.keyDerivation = mockKeyDerivation + err := cs.HandleCryptoStream() + Expect(err).ToNot(HaveOccurred()) + Expect(handshakeEvent).To(Receive()) + }) + + Context("reporting the handshake state", func() { + It("reports before the handshake compeletes", func() { + cs.tls = NewMockMintTLS(mockCtrl) + cs.tls.(*MockMintTLS).EXPECT().ConnectionState().Return(mint.ConnectionState{}) + state := cs.ConnectionState() + Expect(state.HandshakeComplete).To(BeFalse()) + Expect(state.PeerCertificates).To(BeNil()) + }) + + It("reports after the handshake completes", func() { + cs.tls = NewMockMintTLS(mockCtrl) + cs.tls.(*MockMintTLS).EXPECT().Handshake().Return(mint.AlertNoAlert) + cs.tls.(*MockMintTLS).EXPECT().ConnectionState().Return(mint.ConnectionState{HandshakeState: mint.StateServerConnected}).Times(2) + cs.keyDerivation = mockKeyDerivation + err := cs.HandleCryptoStream() + Expect(err).ToNot(HaveOccurred()) + state := cs.ConnectionState() + Expect(state.HandshakeComplete).To(BeTrue()) + Expect(state.PeerCertificates).To(BeNil()) + }) + }) + + Context("escalating crypto", func() { + doHandshake := func() { + cs.tls = NewMockMintTLS(mockCtrl) + cs.tls.(*MockMintTLS).EXPECT().Handshake().Return(mint.AlertNoAlert) + cs.tls.(*MockMintTLS).EXPECT().ConnectionState().Return(mint.ConnectionState{HandshakeState: mint.StateServerConnected}) + cs.keyDerivation = mockKeyDerivation + err := cs.HandleCryptoStream() + Expect(err).ToNot(HaveOccurred()) + } + + Context("null encryption", func() { + It("is used initially", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(5), []byte{}).Return([]byte("foobar signed")) + enc, sealer := cs.GetSealer() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + d := sealer.Seal(nil, []byte("foobar"), 5, []byte{}) + Expect(d).To(Equal([]byte("foobar signed"))) + }) + + It("is used for opening", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("foobar enc"), protocol.PacketNumber(10), []byte{}).Return([]byte("foobar"), nil) + d, err := cs.OpenHandshake(nil, []byte("foobar enc"), 10, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("foobar"))) + }) + + It("is used for crypto stream", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(20), []byte{}).Return([]byte("foobar signed")) + enc, sealer := cs.GetSealerForCryptoStream() + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + d := sealer.Seal(nil, []byte("foobar"), 20, []byte{}) + Expect(d).To(Equal([]byte("foobar signed"))) + }) + + It("errors if the has the wrong hash", func() { + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("foobar enc"), protocol.PacketNumber(10), []byte{}).Return(nil, errors.New("authentication failed")) + _, err := cs.OpenHandshake(nil, []byte("foobar enc"), 10, []byte{}) + Expect(err).To(MatchError("authentication failed")) + }) + }) + + Context("forward-secure encryption", func() { + It("is used for sealing after the handshake completes", func() { + doHandshake() + cs.aead.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(5), []byte{}).Return([]byte("foobar forward sec")) + enc, sealer := cs.GetSealer() + Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) + d := sealer.Seal(nil, []byte("foobar"), 5, []byte{}) + Expect(d).To(Equal([]byte("foobar forward sec"))) + }) + + It("is used for opening", func() { + doHandshake() + cs.aead.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(6), []byte{}).Return([]byte("decrypted"), nil) + d, err := cs.Open1RTT(nil, []byte("encrypted"), 6, []byte{}) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("decrypted"))) + }) + }) + + Context("forcing encryption levels", func() { + It("forces null encryption", func() { + doHandshake() + cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(5), []byte{}).Return([]byte("foobar signed")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionUnencrypted) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 5, []byte{}) + Expect(d).To(Equal([]byte("foobar signed"))) + }) + + It("forces forward-secure encryption", func() { + doHandshake() + cs.aead.(*mockcrypto.MockAEAD).EXPECT().Seal(nil, []byte("foobar"), protocol.PacketNumber(5), []byte{}).Return([]byte("foobar forward sec")) + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionForwardSecure) + Expect(err).ToNot(HaveOccurred()) + d := sealer.Seal(nil, []byte("foobar"), 5, []byte{}) + Expect(d).To(Equal([]byte("foobar forward sec"))) + }) + + It("errors if the forward-secure AEAD is not available", func() { + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionForwardSecure) + Expect(err).To(MatchError("CryptoSetup: no sealer with encryption level forward-secure")) + Expect(sealer).To(BeNil()) + }) + + It("never returns a secure AEAD (they don't exist with TLS)", func() { + doHandshake() + sealer, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionSecure) + Expect(err).To(MatchError("CryptoSetup: no sealer with encryption level encrypted (not forward-secure)")) + Expect(sealer).To(BeNil()) + }) + + It("errors if no encryption level is specified", func() { + seal, err := cs.GetSealerWithEncryptionLevel(protocol.EncryptionUnspecified) + Expect(err).To(MatchError("CryptoSetup: no sealer with encryption level unknown")) + Expect(seal).To(BeNil()) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn.go new file mode 100644 index 00000000..a031f90c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn.go @@ -0,0 +1,69 @@ +package handshake + +import ( + "bytes" + "io" + "net" + "time" +) + +type cryptoStreamConn struct { + buffer *bytes.Buffer + stream io.ReadWriter +} + +var _ net.Conn = &cryptoStreamConn{} + +func newCryptoStreamConn(stream io.ReadWriter) *cryptoStreamConn { + return &cryptoStreamConn{ + stream: stream, + buffer: &bytes.Buffer{}, + } +} + +func (c *cryptoStreamConn) Read(b []byte) (int, error) { + return c.stream.Read(b) +} + +func (c *cryptoStreamConn) Write(p []byte) (int, error) { + return c.buffer.Write(p) +} + +func (c *cryptoStreamConn) Flush() error { + if c.buffer.Len() == 0 { + return nil + } + _, err := c.stream.Write(c.buffer.Bytes()) + c.buffer.Reset() + return err +} + +// Close is not implemented +func (c *cryptoStreamConn) Close() error { + return nil +} + +// LocalAddr is not implemented +func (c *cryptoStreamConn) LocalAddr() net.Addr { + return nil +} + +// RemoteAddr is not implemented +func (c *cryptoStreamConn) RemoteAddr() net.Addr { + return nil +} + +// SetReadDeadline is not implemented +func (c *cryptoStreamConn) SetReadDeadline(time.Time) error { + return nil +} + +// SetWriteDeadline is not implemented +func (c *cryptoStreamConn) SetWriteDeadline(time.Time) error { + return nil +} + +// SetDeadline is not implemented +func (c *cryptoStreamConn) SetDeadline(time.Time) error { + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn_test.go new file mode 100644 index 00000000..64bb6cbd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/crypto_stream_conn_test.go @@ -0,0 +1,41 @@ +package handshake + +import ( + "bytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Crypto Stream Conn", func() { + var ( + stream *bytes.Buffer + csc *cryptoStreamConn + ) + + BeforeEach(func() { + stream = &bytes.Buffer{} + csc = newCryptoStreamConn(stream) + }) + + It("buffers writes", func() { + _, err := csc.Write([]byte("foo")) + Expect(err).ToNot(HaveOccurred()) + Expect(stream.Len()).To(BeZero()) + _, err = csc.Write([]byte("bar")) + Expect(err).ToNot(HaveOccurred()) + Expect(stream.Len()).To(BeZero()) + + Expect(csc.Flush()).To(Succeed()) + Expect(stream.Bytes()).To(Equal([]byte("foobar"))) + }) + + It("reads from the stream", func() { + stream.Write([]byte("foobar")) + b := make([]byte, 6) + n, err := csc.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(6)) + Expect(b).To(Equal([]byte("foobar"))) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/data_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/data_test.go new file mode 100644 index 00000000..238f7033 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/data_test.go @@ -0,0 +1,24 @@ +package handshake + +import "strings" + +var sampleCHLO = []byte{0x43, 0x48, 0x4c, 0x4f, 0x10, 0x0, 0x0, 0x0, 0x50, 0x41, 0x44, 0x0, 0xf8, 0x3, 0x0, 0x0, 0x53, 0x4e, 0x49, 0x0, 0x7, 0x4, 0x0, 0x0, 0x56, 0x45, 0x52, 0x0, 0xb, 0x4, 0x0, 0x0, 0x43, 0x43, 0x53, 0x0, 0x1b, 0x4, 0x0, 0x0, 0x4d, 0x53, 0x50, 0x43, 0x1f, 0x4, 0x0, 0x0, 0x55, 0x41, 0x49, 0x44, 0x4c, 0x4, 0x0, 0x0, 0x54, 0x43, 0x49, 0x44, 0x50, 0x4, 0x0, 0x0, 0x50, 0x44, 0x4d, 0x44, 0x54, 0x4, 0x0, 0x0, 0x53, 0x52, 0x42, 0x46, 0x58, 0x4, 0x0, 0x0, 0x49, 0x43, 0x53, 0x4c, 0x5c, 0x4, 0x0, 0x0, 0x4e, 0x4f, 0x4e, 0x50, 0x7c, 0x4, 0x0, 0x0, 0x53, 0x43, 0x4c, 0x53, 0x80, 0x4, 0x0, 0x0, 0x43, 0x53, 0x43, 0x54, 0x80, 0x4, 0x0, 0x0, 0x43, 0x4f, 0x50, 0x54, 0x84, 0x4, 0x0, 0x0, 0x43, 0x46, 0x43, 0x57, 0x88, 0x4, 0x0, 0x0, 0x53, 0x46, 0x43, 0x57, 0x8c, 0x4, 0x0, 0x0, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x51, 0x30, 0x33, 0x30, 0x7b, 0x26, 0xe9, 0xe7, 0xe4, 0x5c, 0x71, 0xff, 0x1, 0xe8, 0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8, 0x64, 0x0, 0x0, 0x0, 0x64, 0x65, 0x76, 0x20, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x35, 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x37, 0x30, 0x30, 0x2e, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x6c, 0x20, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, 0x20, 0x31, 0x30, 0x5f, 0x31, 0x31, 0x5f, 0x34, 0x0, 0x0, 0x0, 0x0, 0x58, 0x35, 0x30, 0x39, 0x0, 0x0, 0x10, 0x0, 0x1e, 0x0, 0x0, 0x0, 0xe1, 0x84, 0x54, 0x1b, 0xe3, 0xd6, 0x7c, 0x1f, 0x69, 0xb2, 0x4e, 0x9e, 0x46, 0xf4, 0x46, 0xdd, 0xab, 0xe5, 0xde, 0x66, 0x94, 0xf6, 0xb2, 0xee, 0x1, 0xc4, 0xa5, 0x77, 0xfe, 0xc9, 0xb, 0xa3, 0x1, 0x0, 0x0, 0x0, 0x46, 0x49, 0x58, 0x44, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x60, 0x0} + +var sampleCHLOMap = map[Tag][]byte{ + TagPAD: []byte(strings.Repeat("-", 1016)), + TagSNI: []byte("www.example.org"), + TagVER: []byte("Q030"), + TagCCS: []byte("{&\xe9\xe7\xe4\\q\xff\x01\xe8\x81`\x92\x92\x1a\xe8"), + TagMSPC: []byte("d\x00\x00\x00"), + TagUAID: []byte("dev Chrome/51.0.2700.0 Intel Mac OS X 10_11_4"), + TagTCID: []byte("\x00\x00\x00\x00"), + TagSRBF: []byte("\x00\x00\x10\x00"), + TagICSL: []byte("\x1e\x00\x00\x00"), + TagNONP: []byte("\xe1\x84T\x1b\xe3\xd6|\x1fi\xb2N\x9eF\xf4Fݫ\xe5\xdef\x94\xf6\xb2\xee\x01ĥw\xfe\xc9\v\xa3"), + TagSCLS: []byte("\x01\x00\x00\x00"), + TagCSCT: {}, + TagCOPT: []byte("FIXD"), + TagSFCW: []byte("\x00\x00`\x00"), + TagCFCW: []byte("\x00\x00\xf0\x00"), + TagPDMD: []byte("X509"), +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache.go b/vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache.go new file mode 100644 index 00000000..eb1824d9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache.go @@ -0,0 +1,48 @@ +package handshake + +import ( + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +var ( + kexLifetime = protocol.EphermalKeyLifetime + kexCurrent crypto.KeyExchange + kexCurrentTime time.Time + kexMutex sync.RWMutex +) + +// getEphermalKEX returns the currently active KEX, which changes every protocol.EphermalKeyLifetime +// See the explanation from the QUIC crypto doc: +// +// A single connection is the usual scope for forward security, but the security +// difference between an ephemeral key used for a single connection, and one +// used for all connections for 60 seconds is negligible. Thus we can amortise +// the Diffie-Hellman key generation at the server over all the connections in a +// small time span. +func getEphermalKEX() (crypto.KeyExchange, error) { + kexMutex.RLock() + res := kexCurrent + t := kexCurrentTime + kexMutex.RUnlock() + if res != nil && time.Since(t) < kexLifetime { + return res, nil + } + + kexMutex.Lock() + defer kexMutex.Unlock() + // Check if still unfulfilled + if kexCurrent == nil || time.Since(kexCurrentTime) >= kexLifetime { + kex, err := crypto.NewCurve25519KEX() + if err != nil { + return nil, err + } + kexCurrent = kex + kexCurrentTime = time.Now() + return kexCurrent, nil + } + return kexCurrent, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache_test.go new file mode 100644 index 00000000..69eee338 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/ephermal_cache_test.go @@ -0,0 +1,35 @@ +package handshake + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Ephermal KEX", func() { + It("has a consistent KEX", func() { + kex1, err := getEphermalKEX() + Expect(err).ToNot(HaveOccurred()) + Expect(kex1).ToNot(BeNil()) + kex2, err := getEphermalKEX() + Expect(err).ToNot(HaveOccurred()) + Expect(kex2).ToNot(BeNil()) + Expect(kex1).To(Equal(kex2)) + }) + + It("changes KEX", func() { + kexLifetime = 10 * time.Millisecond + defer func() { + kexLifetime = protocol.EphermalKeyLifetime + }() + kex, err := getEphermalKEX() + Expect(err).ToNot(HaveOccurred()) + Expect(kex).ToNot(BeNil()) + time.Sleep(kexLifetime) + kex2, err := getEphermalKEX() + Expect(err).ToNot(HaveOccurred()) + Expect(kex2).ToNot(Equal(kex)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/handshake_message.go b/vendor/lucas-clemente/quic-go/internal/handshake/handshake_message.go new file mode 100644 index 00000000..cfbd2193 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/handshake_message.go @@ -0,0 +1,137 @@ +package handshake + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "sort" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +// A HandshakeMessage is a handshake message +type HandshakeMessage struct { + Tag Tag + Data map[Tag][]byte +} + +var _ fmt.Stringer = &HandshakeMessage{} + +// ParseHandshakeMessage reads a crypto message +func ParseHandshakeMessage(r io.Reader) (HandshakeMessage, error) { + slice4 := make([]byte, 4) + + if _, err := io.ReadFull(r, slice4); err != nil { + return HandshakeMessage{}, err + } + messageTag := Tag(binary.LittleEndian.Uint32(slice4)) + + if _, err := io.ReadFull(r, slice4); err != nil { + return HandshakeMessage{}, err + } + nPairs := binary.LittleEndian.Uint32(slice4) + + if nPairs > protocol.CryptoMaxParams { + return HandshakeMessage{}, qerr.CryptoTooManyEntries + } + + index := make([]byte, nPairs*8) + if _, err := io.ReadFull(r, index); err != nil { + return HandshakeMessage{}, err + } + + resultMap := map[Tag][]byte{} + + var dataStart uint32 + for indexPos := 0; indexPos < int(nPairs)*8; indexPos += 8 { + tag := Tag(binary.LittleEndian.Uint32(index[indexPos : indexPos+4])) + dataEnd := binary.LittleEndian.Uint32(index[indexPos+4 : indexPos+8]) + + dataLen := dataEnd - dataStart + if dataLen > protocol.CryptoParameterMaxLength { + return HandshakeMessage{}, qerr.Error(qerr.CryptoInvalidValueLength, "value too long") + } + + data := make([]byte, dataLen) + if _, err := io.ReadFull(r, data); err != nil { + return HandshakeMessage{}, err + } + + resultMap[tag] = data + dataStart = dataEnd + } + + return HandshakeMessage{ + Tag: messageTag, + Data: resultMap}, nil +} + +// Write writes a crypto message +func (h HandshakeMessage) Write(b *bytes.Buffer) { + data := h.Data + utils.LittleEndian.WriteUint32(b, uint32(h.Tag)) + utils.LittleEndian.WriteUint16(b, uint16(len(data))) + utils.LittleEndian.WriteUint16(b, 0) + + // Save current position in the buffer, so that we can update the index in-place later + indexStart := b.Len() + + indexData := make([]byte, 8*len(data)) + b.Write(indexData) // Will be updated later + + offset := uint32(0) + for i, t := range h.getTagsSorted() { + v := data[t] + b.Write(v) + offset += uint32(len(v)) + binary.LittleEndian.PutUint32(indexData[i*8:], uint32(t)) + binary.LittleEndian.PutUint32(indexData[i*8+4:], offset) + } + + // Now we write the index data for real + copy(b.Bytes()[indexStart:], indexData) +} + +func (h *HandshakeMessage) getTagsSorted() []Tag { + tags := make([]Tag, len(h.Data)) + i := 0 + for t := range h.Data { + tags[i] = t + i++ + } + sort.Slice(tags, func(i, j int) bool { + return tags[i] < tags[j] + }) + return tags +} + +func (h HandshakeMessage) String() string { + var pad string + res := tagToString(h.Tag) + ":\n" + for _, tag := range h.getTagsSorted() { + if tag == TagPAD { + pad = fmt.Sprintf("\t%s: (%d bytes)\n", tagToString(tag), len(h.Data[tag])) + } else { + res += fmt.Sprintf("\t%s: %#v\n", tagToString(tag), string(h.Data[tag])) + } + } + + if len(pad) > 0 { + res += pad + } + return res +} + +func tagToString(tag Tag) string { + b := make([]byte, 4) + binary.LittleEndian.PutUint32(b, uint32(tag)) + for i := range b { + if b[i] == 0 { + b[i] = ' ' + } + } + return string(b) +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/handshake_message_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/handshake_message_test.go new file mode 100644 index 00000000..fc96b120 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/handshake_message_test.go @@ -0,0 +1,71 @@ +package handshake + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Handshake Message", func() { + Context("when parsing", func() { + It("parses sample CHLO message", func() { + msg, err := ParseHandshakeMessage(bytes.NewReader(sampleCHLO)) + Expect(err).ToNot(HaveOccurred()) + Expect(msg.Tag).To(Equal(TagCHLO)) + Expect(msg.Data).To(Equal(sampleCHLOMap)) + }) + + It("rejects large numbers of pairs", func() { + r := bytes.NewReader([]byte("CHLO\xff\xff\xff\xff")) + _, err := ParseHandshakeMessage(r) + Expect(err).To(MatchError(qerr.CryptoTooManyEntries)) + }) + + It("rejects too long values", func() { + r := bytes.NewReader([]byte{ + 'C', 'H', 'L', 'O', + 1, 0, 0, 0, + 0, 0, 0, 0, + 0xff, 0xff, 0xff, 0xff, + }) + _, err := ParseHandshakeMessage(r) + Expect(err).To(MatchError(qerr.Error(qerr.CryptoInvalidValueLength, "value too long"))) + }) + }) + + Context("when writing", func() { + It("writes sample message", func() { + b := &bytes.Buffer{} + HandshakeMessage{Tag: TagCHLO, Data: sampleCHLOMap}.Write(b) + Expect(b.Bytes()).To(Equal(sampleCHLO)) + }) + }) + + Context("string representation", func() { + It("has a string representation", func() { + str := HandshakeMessage{ + Tag: TagSHLO, + Data: map[Tag][]byte{ + TagAEAD: []byte("foobar"), + TagEXPY: []byte("raboof"), + }, + }.String() + Expect(str[:4]).To(Equal("SHLO")) + Expect(str).To(ContainSubstring("AEAD: \"foobar\"")) + Expect(str).To(ContainSubstring("EXPY: \"raboof\"")) + }) + + It("lists padding separately", func() { + str := HandshakeMessage{ + Tag: TagSHLO, + Data: map[Tag][]byte{ + TagPAD: bytes.Repeat([]byte{0}, 1337), + }, + }.String() + Expect(str).To(ContainSubstring("PAD")) + Expect(str).To(ContainSubstring("1337 bytes")) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/handshake_suite_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/handshake_suite_test.go new file mode 100644 index 00000000..91f3d14b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/handshake_suite_test.go @@ -0,0 +1,24 @@ +package handshake + +import ( + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestQuicGo(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Handshake Suite") +} + +var mockCtrl *gomock.Controller + +var _ = BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) +}) + +var _ = AfterEach(func() { + mockCtrl.Finish() +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/interface.go b/vendor/lucas-clemente/quic-go/internal/handshake/interface.go new file mode 100644 index 00000000..5813fdd9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/interface.go @@ -0,0 +1,61 @@ +package handshake + +import ( + "crypto/x509" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// Sealer seals a packet +type Sealer interface { + Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte + Overhead() int +} + +// mintTLS combines some methods needed to interact with mint. +type mintTLS interface { + crypto.TLSExporter + Handshake() mint.Alert +} + +// A TLSExtensionHandler sends and received the QUIC TLS extension. +// It provides the parameters sent by the peer on a channel. +type TLSExtensionHandler interface { + Send(mint.HandshakeType, *mint.ExtensionList) error + Receive(mint.HandshakeType, *mint.ExtensionList) error + GetPeerParams() <-chan TransportParameters +} + +type baseCryptoSetup interface { + HandleCryptoStream() error + ConnectionState() ConnectionState + + GetSealer() (protocol.EncryptionLevel, Sealer) + GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (Sealer, error) + GetSealerForCryptoStream() (protocol.EncryptionLevel, Sealer) +} + +// CryptoSetup is the crypto setup used by gQUIC +type CryptoSetup interface { + baseCryptoSetup + + Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) +} + +// CryptoSetupTLS is the crypto setup used by IETF QUIC +type CryptoSetupTLS interface { + baseCryptoSetup + + OpenHandshake(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) + Open1RTT(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) +} + +// ConnectionState records basic details about the QUIC connection. +// Warning: This API should not be considered stable and might change soon. +type ConnectionState struct { + HandshakeComplete bool // handshake is complete + ServerName string // server name requested by client, if any (server side only) + PeerCertificates []*x509.Certificate // certificate chain presented by remote peer +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/mock_mint_tls_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/mock_mint_tls_test.go new file mode 100644 index 00000000..c6e7d50b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/mock_mint_tls_test.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/handshake (interfaces: MintTLS) + +// Package handshake is a generated GoMock package. +package handshake + +import ( + reflect "reflect" + + mint "github.com/bifurcation/mint" + gomock "github.com/golang/mock/gomock" +) + +// MockMintTLS is a mock of MintTLS interface +type MockMintTLS struct { + ctrl *gomock.Controller + recorder *MockMintTLSMockRecorder +} + +// MockMintTLSMockRecorder is the mock recorder for MockMintTLS +type MockMintTLSMockRecorder struct { + mock *MockMintTLS +} + +// NewMockMintTLS creates a new mock instance +func NewMockMintTLS(ctrl *gomock.Controller) *MockMintTLS { + mock := &MockMintTLS{ctrl: ctrl} + mock.recorder = &MockMintTLSMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockMintTLS) EXPECT() *MockMintTLSMockRecorder { + return m.recorder +} + +// ComputeExporter mocks base method +func (m *MockMintTLS) ComputeExporter(arg0 string, arg1 []byte, arg2 int) ([]byte, error) { + ret := m.ctrl.Call(m, "ComputeExporter", arg0, arg1, arg2) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ComputeExporter indicates an expected call of ComputeExporter +func (mr *MockMintTLSMockRecorder) ComputeExporter(arg0, arg1, arg2 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ComputeExporter", reflect.TypeOf((*MockMintTLS)(nil).ComputeExporter), arg0, arg1, arg2) +} + +// ConnectionState mocks base method +func (m *MockMintTLS) ConnectionState() mint.ConnectionState { + ret := m.ctrl.Call(m, "ConnectionState") + ret0, _ := ret[0].(mint.ConnectionState) + return ret0 +} + +// ConnectionState indicates an expected call of ConnectionState +func (mr *MockMintTLSMockRecorder) ConnectionState() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConnectionState", reflect.TypeOf((*MockMintTLS)(nil).ConnectionState)) +} + +// Handshake mocks base method +func (m *MockMintTLS) Handshake() mint.Alert { + ret := m.ctrl.Call(m, "Handshake") + ret0, _ := ret[0].(mint.Alert) + return ret0 +} + +// Handshake indicates an expected call of Handshake +func (mr *MockMintTLSMockRecorder) Handshake() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handshake", reflect.TypeOf((*MockMintTLS)(nil).Handshake)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/mockgen.go b/vendor/lucas-clemente/quic-go/internal/handshake/mockgen.go new file mode 100644 index 00000000..86232720 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/mockgen.go @@ -0,0 +1,3 @@ +package handshake + +//go:generate sh -c "../mockgen_internal.sh handshake mock_mint_tls_test.go github.com/lucas-clemente/quic-go/internal/handshake mintTLS" diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/server_config.go b/vendor/lucas-clemente/quic-go/internal/handshake/server_config.go new file mode 100644 index 00000000..b015750b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/server_config.go @@ -0,0 +1,73 @@ +package handshake + +import ( + "bytes" + "crypto/rand" + + "github.com/lucas-clemente/quic-go/internal/crypto" +) + +// ServerConfig is a server config +type ServerConfig struct { + kex crypto.KeyExchange + certChain crypto.CertChain + ID []byte + obit []byte + cookieGenerator *CookieGenerator +} + +// NewServerConfig creates a new server config +func NewServerConfig(kex crypto.KeyExchange, certChain crypto.CertChain) (*ServerConfig, error) { + id := make([]byte, 16) + _, err := rand.Read(id) + if err != nil { + return nil, err + } + + obit := make([]byte, 8) + if _, err = rand.Read(obit); err != nil { + return nil, err + } + + cookieGenerator, err := NewCookieGenerator() + + if err != nil { + return nil, err + } + + return &ServerConfig{ + kex: kex, + certChain: certChain, + ID: id, + obit: obit, + cookieGenerator: cookieGenerator, + }, nil +} + +// Get the server config binary representation +func (s *ServerConfig) Get() []byte { + var serverConfig bytes.Buffer + msg := HandshakeMessage{ + Tag: TagSCFG, + Data: map[Tag][]byte{ + TagSCID: s.ID, + TagKEXS: []byte("C255"), + TagAEAD: []byte("AESG"), + TagPUBS: append([]byte{0x20, 0x00, 0x00}, s.kex.PublicKey()...), + TagOBIT: s.obit, + TagEXPY: {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + } + msg.Write(&serverConfig) + return serverConfig.Bytes() +} + +// Sign the server config and CHLO with the server's keyData +func (s *ServerConfig) Sign(sni string, chlo []byte) ([]byte, error) { + return s.certChain.SignServerProof(sni, chlo, s.Get()) +} + +// GetCertsCompressed returns the certificate data +func (s *ServerConfig) GetCertsCompressed(sni string, commonSetHashes, compressedHashes []byte) ([]byte, error) { + return s.certChain.GetCertsCompressed(sni, commonSetHashes, compressedHashes) +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/server_config_client.go b/vendor/lucas-clemente/quic-go/internal/handshake/server_config_client.go new file mode 100644 index 00000000..0d6521a4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/server_config_client.go @@ -0,0 +1,184 @@ +package handshake + +import ( + "bytes" + "encoding/binary" + "errors" + "math" + "time" + + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +type serverConfigClient struct { + raw []byte + ID []byte + obit []byte + expiry time.Time + + kex crypto.KeyExchange + sharedSecret []byte +} + +var ( + errMessageNotServerConfig = errors.New("ServerConfig must have TagSCFG") +) + +// parseServerConfig parses a server config +func parseServerConfig(data []byte) (*serverConfigClient, error) { + message, err := ParseHandshakeMessage(bytes.NewReader(data)) + if err != nil { + return nil, err + } + if message.Tag != TagSCFG { + return nil, errMessageNotServerConfig + } + + scfg := &serverConfigClient{raw: data} + err = scfg.parseValues(message.Data) + if err != nil { + return nil, err + } + + return scfg, nil +} + +func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error { + // SCID + scfgID, ok := tagMap[TagSCID] + if !ok { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "SCID") + } + if len(scfgID) != 16 { + return qerr.Error(qerr.CryptoInvalidValueLength, "SCID") + } + s.ID = scfgID + + // KEXS + // TODO: setup Key Exchange + kexs, ok := tagMap[TagKEXS] + if !ok { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "KEXS") + } + if len(kexs)%4 != 0 { + return qerr.Error(qerr.CryptoInvalidValueLength, "KEXS") + } + c255Foundat := -1 + + for i := 0; i < len(kexs)/4; i++ { + if bytes.Equal(kexs[4*i:4*i+4], []byte("C255")) { + c255Foundat = i + break + } + } + if c255Foundat < 0 { + return qerr.Error(qerr.CryptoNoSupport, "KEXS: Could not find C255, other key exchanges are not supported") + } + + // AEAD + aead, ok := tagMap[TagAEAD] + if !ok { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "AEAD") + } + if len(aead)%4 != 0 { + return qerr.Error(qerr.CryptoInvalidValueLength, "AEAD") + } + var aesgFound bool + for i := 0; i < len(aead)/4; i++ { + if bytes.Equal(aead[4*i:4*i+4], []byte("AESG")) { + aesgFound = true + break + } + } + if !aesgFound { + return qerr.Error(qerr.CryptoNoSupport, "AEAD") + } + + // PUBS + pubs, ok := tagMap[TagPUBS] + if !ok { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "PUBS") + } + + var pubsKexs []struct { + Length uint32 + Value []byte + } + var lastLen uint32 + for i := 0; i < len(pubs)-3; i += int(lastLen) + 3 { + // the PUBS value is always prepended by 3 byte little endian length field + + err := binary.Read(bytes.NewReader([]byte{pubs[i], pubs[i+1], pubs[i+2], 0x00}), binary.LittleEndian, &lastLen) + if err != nil { + return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS not decodable") + } + if lastLen == 0 { + return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") + } + + if i+3+int(lastLen) > len(pubs) { + return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") + } + + pubsKexs = append(pubsKexs, struct { + Length uint32 + Value []byte + }{lastLen, pubs[i+3 : i+3+int(lastLen)]}) + } + + if c255Foundat >= len(pubsKexs) { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "KEXS not in PUBS") + } + + if pubsKexs[c255Foundat].Length != 32 { + return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") + } + + var err error + s.kex, err = crypto.NewCurve25519KEX() + if err != nil { + return err + } + + s.sharedSecret, err = s.kex.CalculateSharedKey(pubsKexs[c255Foundat].Value) + if err != nil { + return err + } + + // OBIT + obit, ok := tagMap[TagOBIT] + if !ok { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "OBIT") + } + if len(obit) != 8 { + return qerr.Error(qerr.CryptoInvalidValueLength, "OBIT") + } + s.obit = obit + + // EXPY + expy, ok := tagMap[TagEXPY] + if !ok { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "EXPY") + } + if len(expy) != 8 { + return qerr.Error(qerr.CryptoInvalidValueLength, "EXPY") + } + // make sure that the value doesn't overflow an int64 + // furthermore, values close to MaxInt64 are not a valid input to time.Unix, thus set MaxInt64/2 as the maximum value here + expyTimestamp := utils.MinUint64(binary.LittleEndian.Uint64(expy), math.MaxInt64/2) + s.expiry = time.Unix(int64(expyTimestamp), 0) + + // TODO: implement VER + + return nil +} + +func (s *serverConfigClient) IsExpired() bool { + return s.expiry.Before(time.Now()) +} + +func (s *serverConfigClient) Get() []byte { + return s.raw +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/server_config_client_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/server_config_client_test.go new file mode 100644 index 00000000..d298e2f4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/server_config_client_test.go @@ -0,0 +1,266 @@ +package handshake + +import ( + "bytes" + "time" + + "github.com/lucas-clemente/quic-go/internal/crypto" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +// This tagMap can be passed to parseValues and is garantueed to not cause any errors +func getDefaultServerConfigClient() map[Tag][]byte { + return map[Tag][]byte{ + TagSCID: bytes.Repeat([]byte{'F'}, 16), + TagKEXS: []byte("C255"), + TagAEAD: []byte("AESG"), + TagPUBS: append([]byte{0x20, 0x00, 0x00}, bytes.Repeat([]byte{0}, 32)...), + TagOBIT: bytes.Repeat([]byte{0}, 8), + TagEXPY: {0x0, 0x6c, 0x57, 0x78, 0, 0, 0, 0}, // 2033-12-24 + } +} + +var _ = Describe("Server Config", func() { + var tagMap map[Tag][]byte + + BeforeEach(func() { + tagMap = getDefaultServerConfigClient() + }) + + It("returns the parsed server config", func() { + tagMap[TagSCID] = []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf} + b := &bytes.Buffer{} + HandshakeMessage{Tag: TagSCFG, Data: tagMap}.Write(b) + scfg, err := parseServerConfig(b.Bytes()) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.ID).To(Equal(tagMap[TagSCID])) + }) + + It("saves the raw server config", func() { + b := &bytes.Buffer{} + HandshakeMessage{Tag: TagSCFG, Data: tagMap}.Write(b) + scfg, err := parseServerConfig(b.Bytes()) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.raw).To(Equal(b.Bytes())) + }) + + It("tells if a server config is expired", func() { + scfg := &serverConfigClient{} + scfg.expiry = time.Now().Add(-time.Second) + Expect(scfg.IsExpired()).To(BeTrue()) + scfg.expiry = time.Now().Add(time.Second) + Expect(scfg.IsExpired()).To(BeFalse()) + }) + + Context("parsing the server config", func() { + It("rejects a handshake message with the wrong message tag", func() { + var serverConfig bytes.Buffer + HandshakeMessage{Tag: TagCHLO, Data: make(map[Tag][]byte)}.Write(&serverConfig) + _, err := parseServerConfig(serverConfig.Bytes()) + Expect(err).To(MatchError(errMessageNotServerConfig)) + }) + + It("errors on invalid handshake messages", func() { + var serverConfig bytes.Buffer + HandshakeMessage{Tag: TagSCFG, Data: make(map[Tag][]byte)}.Write(&serverConfig) + _, err := parseServerConfig(serverConfig.Bytes()[:serverConfig.Len()-2]) + Expect(err).To(MatchError("unexpected EOF")) + }) + + It("passes on errors encountered when reading the TagMap", func() { + var serverConfig bytes.Buffer + HandshakeMessage{Tag: TagSCFG, Data: make(map[Tag][]byte)}.Write(&serverConfig) + _, err := parseServerConfig(serverConfig.Bytes()) + Expect(err).To(MatchError("CryptoMessageParameterNotFound: SCID")) + }) + + It("reads an example Handshake Message", func() { + var serverConfig bytes.Buffer + HandshakeMessage{Tag: TagSCFG, Data: tagMap}.Write(&serverConfig) + scfg, err := parseServerConfig(serverConfig.Bytes()) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.ID).To(Equal(tagMap[TagSCID])) + Expect(scfg.obit).To(Equal(tagMap[TagOBIT])) + }) + }) + + Context("Reading values from the TagMap", func() { + var scfg *serverConfigClient + + BeforeEach(func() { + scfg = &serverConfigClient{} + }) + + Context("ServerConfig ID", func() { + It("parses the ServerConfig ID", func() { + id := []byte{0xb2, 0xa4, 0xbb, 0x8f, 0xf6, 0x51, 0x28, 0xfd, 0x4d, 0xf7, 0xb3, 0x9a, 0x91, 0xe7, 0x91, 0xfb} + tagMap[TagSCID] = id + err := scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.ID).To(Equal(id)) + }) + + It("errors if the ServerConfig ID is missing", func() { + delete(tagMap, TagSCID) + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoMessageParameterNotFound: SCID")) + }) + + It("rejects ServerConfig IDs that have the wrong length", func() { + tagMap[TagSCID] = bytes.Repeat([]byte{'F'}, 17) // 1 byte too long + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: SCID")) + }) + }) + + Context("KEXS", func() { + It("rejects KEXS values that have the wrong length", func() { + tagMap[TagKEXS] = bytes.Repeat([]byte{'F'}, 5) // 1 byte too long + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: KEXS")) + }) + + It("rejects KEXS values other than C255", func() { + tagMap[TagKEXS] = []byte("P256") + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoNoSupport: KEXS: Could not find C255, other key exchanges are not supported")) + }) + + It("errors if the KEXS is missing", func() { + delete(tagMap, TagKEXS) + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoMessageParameterNotFound: KEXS")) + }) + }) + + Context("AEAD", func() { + It("rejects AEAD values that have the wrong length", func() { + tagMap[TagAEAD] = bytes.Repeat([]byte{'F'}, 5) // 1 byte too long + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: AEAD")) + }) + + It("rejects AEAD values other than AESG", func() { + tagMap[TagAEAD] = []byte("S20P") + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoNoSupport: AEAD")) + }) + + It("recognizes AESG in the list of AEADs, at the first position", func() { + tagMap[TagAEAD] = []byte("AESGS20P") + err := scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + }) + + It("recognizes AESG in the list of AEADs, not at the first position", func() { + tagMap[TagAEAD] = []byte("S20PAESG") + err := scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors if the AEAD is missing", func() { + delete(tagMap, TagAEAD) + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoMessageParameterNotFound: AEAD")) + }) + }) + + Context("PUBS", func() { + It("creates a Curve25519 key exchange", func() { + serverKex, err := crypto.NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + tagMap[TagPUBS] = append([]byte{0x20, 0x00, 0x00}, serverKex.PublicKey()...) + err = scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + sharedSecret, err := serverKex.CalculateSharedKey(scfg.kex.PublicKey()) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.sharedSecret).To(Equal(sharedSecret)) + }) + + It("rejects PUBS values that have the wrong length", func() { + tagMap[TagPUBS] = bytes.Repeat([]byte{'F'}, 100) // completely wrong length + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: PUBS")) + }) + + It("rejects PUBS values that have a zero length", func() { + tagMap[TagPUBS] = bytes.Repeat([]byte{0}, 100) // completely wrong length + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: PUBS")) + }) + + It("ensure that C255 Pubs must not be at the first index", func() { + serverKex, err := crypto.NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + tagMap[TagKEXS] = []byte("P256C255") // have another KEXS before C255 + // 3 byte len + 1 byte empty + C255 + tagMap[TagPUBS] = append([]byte{0x01, 0x00, 0x00, 0x00}, append([]byte{0x20, 0x00, 0x00}, serverKex.PublicKey()...)...) + err = scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + sharedSecret, err := serverKex.CalculateSharedKey(scfg.kex.PublicKey()) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.sharedSecret).To(Equal(sharedSecret)) + }) + + It("errors if the PUBS is missing", func() { + delete(tagMap, TagPUBS) + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoMessageParameterNotFound: PUBS")) + }) + }) + + Context("OBIT", func() { + It("parses the OBIT value", func() { + obit := []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8} + tagMap[TagOBIT] = obit + err := scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.obit).To(Equal(obit)) + }) + + It("errors if the OBIT is missing", func() { + delete(tagMap, TagOBIT) + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoMessageParameterNotFound: OBIT")) + }) + + It("rejets OBIT values that have the wrong length", func() { + tagMap[TagOBIT] = bytes.Repeat([]byte{'F'}, 7) // 1 byte too short + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: OBIT")) + }) + }) + + Context("EXPY", func() { + It("parses the expiry date", func() { + tagMap[TagEXPY] = []byte{0xdc, 0x89, 0x0e, 0x59, 0, 0, 0, 0} // UNIX Timestamp 0x590e89dc = 1494125020 + err := scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + year, month, day := scfg.expiry.UTC().Date() + Expect(year).To(Equal(2017)) + Expect(month).To(Equal(time.Month(5))) + Expect(day).To(Equal(7)) + }) + + It("errors if the EXPY is missing", func() { + delete(tagMap, TagEXPY) + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoMessageParameterNotFound: EXPY")) + }) + + It("rejects EXPY values that have the wrong length", func() { + tagMap[TagEXPY] = bytes.Repeat([]byte{'F'}, 9) // 1 byte too long + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: EXPY")) + }) + + It("deals with absurdly large timestamps", func() { + tagMap[TagEXPY] = bytes.Repeat([]byte{0xff}, 8) // this would overflow the int64 + err := scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.expiry.After(time.Now())).To(BeTrue()) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/server_config_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/server_config_test.go new file mode 100644 index 00000000..f942b487 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/server_config_test.go @@ -0,0 +1,45 @@ +package handshake + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/crypto" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ServerConfig", func() { + var ( + kex crypto.KeyExchange + ) + + BeforeEach(func() { + var err error + kex, err = crypto.NewCurve25519KEX() + Expect(err).NotTo(HaveOccurred()) + }) + + It("generates a random ID and OBIT", func() { + scfg1, err := NewServerConfig(kex, nil) + Expect(err).ToNot(HaveOccurred()) + scfg2, err := NewServerConfig(kex, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg1.ID).ToNot(Equal(scfg2.ID)) + Expect(scfg1.obit).ToNot(Equal(scfg2.obit)) + Expect(scfg1.cookieGenerator).ToNot(Equal(scfg2.cookieGenerator)) + }) + + It("gets the proper binary representation", func() { + scfg, err := NewServerConfig(kex, nil) + Expect(err).NotTo(HaveOccurred()) + expected := bytes.NewBuffer([]byte{0x53, 0x43, 0x46, 0x47, 0x6, 0x0, 0x0, 0x0, 0x41, 0x45, 0x41, 0x44, 0x4, 0x0, 0x0, 0x0, 0x53, 0x43, 0x49, 0x44, 0x14, 0x0, 0x0, 0x0, 0x50, 0x55, 0x42, 0x53, 0x37, 0x0, 0x0, 0x0, 0x4b, 0x45, 0x58, 0x53, 0x3b, 0x0, 0x0, 0x0, 0x4f, 0x42, 0x49, 0x54, 0x43, 0x0, 0x0, 0x0, 0x45, 0x58, 0x50, 0x59, 0x4b, 0x0, 0x0, 0x0, 0x41, 0x45, 0x53, 0x47}) + expected.Write(scfg.ID) + expected.Write([]byte{0x20, 0x0, 0x0}) + expected.Write(kex.PublicKey()) + expected.Write([]byte{0x43, 0x32, 0x35, 0x35}) + expected.Write(scfg.obit) + expected.Write([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) + Expect(scfg.Get()).To(Equal(expected.Bytes())) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/tags.go b/vendor/lucas-clemente/quic-go/internal/handshake/tags.go new file mode 100644 index 00000000..cf2a7562 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/tags.go @@ -0,0 +1,93 @@ +package handshake + +// A Tag in the QUIC crypto +type Tag uint32 + +const ( + // TagCHLO is a client hello + TagCHLO Tag = 'C' + 'H'<<8 + 'L'<<16 + 'O'<<24 + // TagREJ is a server hello rejection + TagREJ Tag = 'R' + 'E'<<8 + 'J'<<16 + // TagSCFG is a server config + TagSCFG Tag = 'S' + 'C'<<8 + 'F'<<16 + 'G'<<24 + + // TagPAD is padding + TagPAD Tag = 'P' + 'A'<<8 + 'D'<<16 + // TagSNI is the server name indication + TagSNI Tag = 'S' + 'N'<<8 + 'I'<<16 + // TagVER is the QUIC version + TagVER Tag = 'V' + 'E'<<8 + 'R'<<16 + // TagCCS are the hashes of the common certificate sets + TagCCS Tag = 'C' + 'C'<<8 + 'S'<<16 + // TagCCRT are the hashes of the cached certificates + TagCCRT Tag = 'C' + 'C'<<8 + 'R'<<16 + 'T'<<24 + // TagMSPC is max streams per connection + TagMSPC Tag = 'M' + 'S'<<8 + 'P'<<16 + 'C'<<24 + // TagMIDS is max incoming dyanamic streams + TagMIDS Tag = 'M' + 'I'<<8 + 'D'<<16 + 'S'<<24 + // TagUAID is the user agent ID + TagUAID Tag = 'U' + 'A'<<8 + 'I'<<16 + 'D'<<24 + // TagSVID is the server ID (unofficial tag by us :) + TagSVID Tag = 'S' + 'V'<<8 + 'I'<<16 + 'D'<<24 + // TagTCID is truncation of the connection ID + TagTCID Tag = 'T' + 'C'<<8 + 'I'<<16 + 'D'<<24 + // TagPDMD is the proof demand + TagPDMD Tag = 'P' + 'D'<<8 + 'M'<<16 + 'D'<<24 + // TagSRBF is the socket receive buffer + TagSRBF Tag = 'S' + 'R'<<8 + 'B'<<16 + 'F'<<24 + // TagICSL is the idle connection state lifetime + TagICSL Tag = 'I' + 'C'<<8 + 'S'<<16 + 'L'<<24 + // TagNONP is the client proof nonce + TagNONP Tag = 'N' + 'O'<<8 + 'N'<<16 + 'P'<<24 + // TagSCLS is the silently close timeout + TagSCLS Tag = 'S' + 'C'<<8 + 'L'<<16 + 'S'<<24 + // TagCSCT is the signed cert timestamp (RFC6962) of leaf cert + TagCSCT Tag = 'C' + 'S'<<8 + 'C'<<16 + 'T'<<24 + // TagCOPT are the connection options + TagCOPT Tag = 'C' + 'O'<<8 + 'P'<<16 + 'T'<<24 + // TagCFCW is the initial session/connection flow control receive window + TagCFCW Tag = 'C' + 'F'<<8 + 'C'<<16 + 'W'<<24 + // TagSFCW is the initial stream flow control receive window. + TagSFCW Tag = 'S' + 'F'<<8 + 'C'<<16 + 'W'<<24 + + // TagNSTP is the no STOP_WAITING experiment + // currently unsupported by quic-go + TagNSTP Tag = 'N' + 'S'<<8 + 'T'<<16 + 'P'<<24 + + // TagSTK is the source-address token + TagSTK Tag = 'S' + 'T'<<8 + 'K'<<16 + // TagSNO is the server nonce + TagSNO Tag = 'S' + 'N'<<8 + 'O'<<16 + // TagPROF is the server proof + TagPROF Tag = 'P' + 'R'<<8 + 'O'<<16 + 'F'<<24 + + // TagNONC is the client nonce + TagNONC Tag = 'N' + 'O'<<8 + 'N'<<16 + 'C'<<24 + // TagXLCT is the expected leaf certificate + TagXLCT Tag = 'X' + 'L'<<8 + 'C'<<16 + 'T'<<24 + + // TagSCID is the server config ID + TagSCID Tag = 'S' + 'C'<<8 + 'I'<<16 + 'D'<<24 + // TagKEXS is the list of key exchange algos + TagKEXS Tag = 'K' + 'E'<<8 + 'X'<<16 + 'S'<<24 + // TagAEAD is the list of AEAD algos + TagAEAD Tag = 'A' + 'E'<<8 + 'A'<<16 + 'D'<<24 + // TagPUBS is the public value for the KEX + TagPUBS Tag = 'P' + 'U'<<8 + 'B'<<16 + 'S'<<24 + // TagOBIT is the client orbit + TagOBIT Tag = 'O' + 'B'<<8 + 'I'<<16 + 'T'<<24 + // TagEXPY is the server config expiry + TagEXPY Tag = 'E' + 'X'<<8 + 'P'<<16 + 'Y'<<24 + // TagCERT is the CERT data + TagCERT Tag = 0xff545243 + + // TagSHLO is the server hello + TagSHLO Tag = 'S' + 'H'<<8 + 'L'<<16 + 'O'<<24 + + // TagPRST is the public reset tag + TagPRST Tag = 'P' + 'R'<<8 + 'S'<<16 + 'T'<<24 + // TagRSEQ is the public reset rejected packet number + TagRSEQ Tag = 'R' + 'S'<<8 + 'E'<<16 + 'Q'<<24 + // TagRNON is the public reset nonce + TagRNON Tag = 'R' + 'N'<<8 + 'O'<<16 + 'N'<<24 +) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension.go b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension.go new file mode 100644 index 00000000..b3665dfe --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension.go @@ -0,0 +1,123 @@ +package handshake + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type transportParameterID uint16 + +const quicTLSExtensionType = 0xff5 + +const ( + initialMaxStreamDataParameterID transportParameterID = 0x0 + initialMaxDataParameterID transportParameterID = 0x1 + initialMaxBidiStreamsParameterID transportParameterID = 0x2 + idleTimeoutParameterID transportParameterID = 0x3 + maxPacketSizeParameterID transportParameterID = 0x5 + statelessResetTokenParameterID transportParameterID = 0x6 + initialMaxUniStreamsParameterID transportParameterID = 0x8 + disableMigrationParameterID transportParameterID = 0x9 +) + +type clientHelloTransportParameters struct { + InitialVersion protocol.VersionNumber + Parameters TransportParameters +} + +func (p *clientHelloTransportParameters) Marshal() []byte { + const lenOffset = 4 + b := &bytes.Buffer{} + utils.BigEndian.WriteUint32(b, uint32(p.InitialVersion)) + b.Write([]byte{0, 0}) // length. Will be replaced later + p.Parameters.marshal(b) + data := b.Bytes() + binary.BigEndian.PutUint16(data[lenOffset:lenOffset+2], uint16(len(data)-lenOffset-2)) + return data +} + +func (p *clientHelloTransportParameters) Unmarshal(data []byte) error { + if len(data) < 6 { + return errors.New("transport parameter data too short") + } + p.InitialVersion = protocol.VersionNumber(binary.BigEndian.Uint32(data[:4])) + paramsLen := int(binary.BigEndian.Uint16(data[4:6])) + data = data[6:] + if len(data) != paramsLen { + return fmt.Errorf("expected transport parameters to be %d bytes long, have %d", paramsLen, len(data)) + } + return p.Parameters.unmarshal(data) +} + +type encryptedExtensionsTransportParameters struct { + NegotiatedVersion protocol.VersionNumber + SupportedVersions []protocol.VersionNumber + Parameters TransportParameters +} + +func (p *encryptedExtensionsTransportParameters) Marshal() []byte { + b := &bytes.Buffer{} + utils.BigEndian.WriteUint32(b, uint32(p.NegotiatedVersion)) + b.WriteByte(uint8(4 * len(p.SupportedVersions))) + for _, v := range p.SupportedVersions { + utils.BigEndian.WriteUint32(b, uint32(v)) + } + lenOffset := b.Len() + b.Write([]byte{0, 0}) // length. Will be replaced later + p.Parameters.marshal(b) + data := b.Bytes() + binary.BigEndian.PutUint16(data[lenOffset:lenOffset+2], uint16(len(data)-lenOffset-2)) + return data +} + +func (p *encryptedExtensionsTransportParameters) Unmarshal(data []byte) error { + if len(data) < 5 { + return errors.New("transport parameter data too short") + } + p.NegotiatedVersion = protocol.VersionNumber(binary.BigEndian.Uint32(data[:4])) + numVersions := int(data[4]) + if numVersions%4 != 0 { + return fmt.Errorf("invalid length for version list: %d", numVersions) + } + numVersions /= 4 + data = data[5:] + if len(data) < 4*numVersions+2 /*length field for the parameter list */ { + return errors.New("transport parameter data too short") + } + p.SupportedVersions = make([]protocol.VersionNumber, numVersions) + for i := 0; i < numVersions; i++ { + p.SupportedVersions[i] = protocol.VersionNumber(binary.BigEndian.Uint32(data[:4])) + data = data[4:] + } + paramsLen := int(binary.BigEndian.Uint16(data[:2])) + data = data[2:] + if len(data) != paramsLen { + return fmt.Errorf("expected transport parameters to be %d bytes long, have %d", paramsLen, len(data)) + } + return p.Parameters.unmarshal(data) +} + +type tlsExtensionBody struct { + data []byte +} + +var _ mint.ExtensionBody = &tlsExtensionBody{} + +func (e *tlsExtensionBody) Type() mint.ExtensionType { + return quicTLSExtensionType +} + +func (e *tlsExtensionBody) Marshal() ([]byte, error) { + return e.data, nil +} + +func (e *tlsExtensionBody) Unmarshal(data []byte) (int, error) { + e.data = data + return len(data), nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client.go b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client.go new file mode 100644 index 00000000..d03021ae --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client.go @@ -0,0 +1,112 @@ +package handshake + +import ( + "errors" + "fmt" + + "github.com/lucas-clemente/quic-go/qerr" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type extensionHandlerClient struct { + ourParams *TransportParameters + paramsChan chan TransportParameters + + initialVersion protocol.VersionNumber + supportedVersions []protocol.VersionNumber + version protocol.VersionNumber + + logger utils.Logger +} + +var _ mint.AppExtensionHandler = &extensionHandlerClient{} +var _ TLSExtensionHandler = &extensionHandlerClient{} + +// NewExtensionHandlerClient creates a new extension handler for the client. +func NewExtensionHandlerClient( + params *TransportParameters, + initialVersion protocol.VersionNumber, + supportedVersions []protocol.VersionNumber, + version protocol.VersionNumber, + logger utils.Logger, +) TLSExtensionHandler { + // The client reads the transport parameters from the Encrypted Extensions message. + // The paramsChan is used in the session's run loop's select statement. + // We have to use an unbuffered channel here to make sure that the session actually processes the transport parameters immediately. + paramsChan := make(chan TransportParameters) + return &extensionHandlerClient{ + ourParams: params, + paramsChan: paramsChan, + initialVersion: initialVersion, + supportedVersions: supportedVersions, + version: version, + logger: logger, + } +} + +func (h *extensionHandlerClient) Send(hType mint.HandshakeType, el *mint.ExtensionList) error { + if hType != mint.HandshakeTypeClientHello { + return nil + } + h.logger.Debugf("Sending Transport Parameters: %s", h.ourParams) + chtp := &clientHelloTransportParameters{ + InitialVersion: h.initialVersion, + Parameters: *h.ourParams, + } + return el.Add(&tlsExtensionBody{data: chtp.Marshal()}) +} + +func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.ExtensionList) error { + ext := &tlsExtensionBody{} + found, err := el.Find(ext) + if err != nil { + return err + } + + if hType != mint.HandshakeTypeEncryptedExtensions { + if found { + return fmt.Errorf("Unexpected QUIC extension in handshake message %d", hType) + } + return nil + } + + // hType == mint.HandshakeTypeEncryptedExtensions + if !found { + return errors.New("EncryptedExtensions message didn't contain a QUIC extension") + } + + eetp := &encryptedExtensionsTransportParameters{} + if err := eetp.Unmarshal(ext.data); err != nil { + return err + } + // check that the negotiated_version is the current version + if eetp.NegotiatedVersion != h.version { + return qerr.Error(qerr.VersionNegotiationMismatch, "current version doesn't match negotiated_version") + } + // check that the current version is included in the supported versions + if !protocol.IsSupportedVersion(eetp.SupportedVersions, h.version) { + return qerr.Error(qerr.VersionNegotiationMismatch, "current version not included in the supported versions") + } + // if version negotiation was performed, check that we would have selected the current version based on the supported versions sent by the server + if h.version != h.initialVersion { + negotiatedVersion, ok := protocol.ChooseSupportedVersion(h.supportedVersions, eetp.SupportedVersions) + if !ok || h.version != negotiatedVersion { + return qerr.Error(qerr.VersionNegotiationMismatch, "would have picked a different version") + } + } + + // check that the server sent a stateless reset token + if len(eetp.Parameters.StatelessResetToken) == 0 { + return errors.New("server didn't sent stateless_reset_token") + } + h.logger.Debugf("Received Transport Parameters: %s", &eetp.Parameters) + h.paramsChan <- eetp.Parameters + return nil +} + +func (h *extensionHandlerClient) GetPeerParams() <-chan TransportParameters { + return h.paramsChan +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client_test.go new file mode 100644 index 00000000..bbb72f7c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client_test.go @@ -0,0 +1,233 @@ +package handshake + +import ( + "bytes" + "fmt" + "time" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("TLS Extension Handler, for the client", func() { + var ( + handler *extensionHandlerClient + el mint.ExtensionList + ) + + BeforeEach(func() { + handler = NewExtensionHandlerClient(&TransportParameters{}, protocol.VersionWhatever, nil, protocol.VersionWhatever, utils.DefaultLogger).(*extensionHandlerClient) + el = make(mint.ExtensionList, 0) + }) + + Context("sending", func() { + It("only adds TransportParameters for the ClientHello", func() { + // test 2 other handshake types + err := handler.Send(mint.HandshakeTypeCertificateRequest, &el) + Expect(err).ToNot(HaveOccurred()) + Expect(el).To(BeEmpty()) + err = handler.Send(mint.HandshakeTypeEndOfEarlyData, &el) + Expect(err).ToNot(HaveOccurred()) + Expect(el).To(BeEmpty()) + }) + + It("adds TransportParameters to the ClientHello", func() { + handler.initialVersion = 13 + err := handler.Send(mint.HandshakeTypeClientHello, &el) + Expect(err).ToNot(HaveOccurred()) + Expect(el).To(HaveLen(1)) + ext := &tlsExtensionBody{} + found, err := el.Find(ext) + Expect(err).ToNot(HaveOccurred()) + Expect(found).To(BeTrue()) + chtp := &clientHelloTransportParameters{} + err = chtp.Unmarshal(ext.data) + Expect(err).ToNot(HaveOccurred()) + Expect(chtp.InitialVersion).To(BeEquivalentTo(13)) + }) + }) + + Context("receiving", func() { + var fakeBody *tlsExtensionBody + var parameters TransportParameters + + addEncryptedExtensionsWithParameters := func(params TransportParameters) { + body := (&encryptedExtensionsTransportParameters{ + Parameters: params, + SupportedVersions: []protocol.VersionNumber{handler.version}, + }).Marshal() + Expect(el.Add(&tlsExtensionBody{data: body})).To(Succeed()) + } + + BeforeEach(func() { + fakeBody = &tlsExtensionBody{data: []byte("foobar foobar")} + parameters = TransportParameters{ + IdleTimeout: 0x1337 * time.Second, + StatelessResetToken: bytes.Repeat([]byte{0}, 16), + } + }) + + It("blocks until the transport parameters are read", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + addEncryptedExtensionsWithParameters(parameters) + err := handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + Expect(handler.GetPeerParams()).To(Receive()) + Eventually(done).Should(BeClosed()) + }) + + It("accepts the TransportParameters on the EncryptedExtensions message", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + addEncryptedExtensionsWithParameters(parameters) + err := handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + var params TransportParameters + Eventually(handler.GetPeerParams()).Should(Receive(¶ms)) + Expect(params.IdleTimeout).To(Equal(0x1337 * time.Second)) + Eventually(done).Should(BeClosed()) + }) + + It("errors if the EncryptedExtensions message doesn't contain TransportParameters", func() { + err := handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).To(MatchError("EncryptedExtensions message didn't contain a QUIC extension")) + }) + + It("rejects the TransportParameters on a wrong handshake types", func() { + err := el.Add(fakeBody) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeCertificate, &el) + Expect(err).To(MatchError(fmt.Sprintf("Unexpected QUIC extension in handshake message %d", mint.HandshakeTypeCertificate))) + }) + + It("ignores messages without TransportParameters, if they are not required", func() { + err := handler.Receive(mint.HandshakeTypeCertificate, &el) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors when it can't parse the TransportParameters", func() { + err := el.Add(fakeBody) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).To(HaveOccurred()) // this will be some kind of decoding error + }) + + It("rejects TransportParameters if they don't contain the stateless reset token", func() { + parameters.StatelessResetToken = nil + addEncryptedExtensionsWithParameters(parameters) + err := handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).To(MatchError("server didn't sent stateless_reset_token")) + }) + + Context("Version Negotiation", func() { + It("accepts a valid version negotiation", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + Eventually(handler.GetPeerParams()).Should(Receive()) + close(done) + }() + + handler.initialVersion = 13 + handler.version = 37 + handler.supportedVersions = []protocol.VersionNumber{13, 37, 42} + body := (&encryptedExtensionsTransportParameters{ + Parameters: parameters, + NegotiatedVersion: 37, + SupportedVersions: []protocol.VersionNumber{36, 37, 38}, + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + }) + + It("errors if the current version doesn't match negotiated_version", func() { + handler.initialVersion = 13 + handler.version = 37 + handler.supportedVersions = []protocol.VersionNumber{13, 37, 42} + body := (&encryptedExtensionsTransportParameters{ + Parameters: parameters, + NegotiatedVersion: 38, + SupportedVersions: []protocol.VersionNumber{36, 37, 38}, + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).To(MatchError("VersionNegotiationMismatch: current version doesn't match negotiated_version")) + }) + + It("errors if the current version is not contained in the server's supported versions", func() { + handler.version = 42 + body := (&encryptedExtensionsTransportParameters{ + NegotiatedVersion: 42, + SupportedVersions: []protocol.VersionNumber{43, 44}, + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).To(MatchError("VersionNegotiationMismatch: current version not included in the supported versions")) + }) + + It("errors if version negotiation was performed, but would have picked a different version based on the supported version list", func() { + handler.version = 42 + handler.initialVersion = 41 + handler.supportedVersions = []protocol.VersionNumber{43, 42, 41} + serverSupportedVersions := []protocol.VersionNumber{42, 43} + // check that version negotiation would have led us to pick version 43 + ver, ok := protocol.ChooseSupportedVersion(handler.supportedVersions, serverSupportedVersions) + Expect(ok).To(BeTrue()) + Expect(ver).To(Equal(protocol.VersionNumber(43))) + body := (&encryptedExtensionsTransportParameters{ + NegotiatedVersion: 42, + SupportedVersions: serverSupportedVersions, + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).To(MatchError("VersionNegotiationMismatch: would have picked a different version")) + }) + + It("doesn't error if it would have picked a different version based on the supported version list, if no version negotiation was performed", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + Eventually(handler.GetPeerParams()).Should(Receive()) + close(done) + }() + + handler.version = 42 + handler.initialVersion = 42 // version == initialVersion means no version negotiation was performed + handler.supportedVersions = []protocol.VersionNumber{43, 42, 41} + serverSupportedVersions := []protocol.VersionNumber{42, 43} + // check that version negotiation would have led us to pick version 43 + ver, ok := protocol.ChooseSupportedVersion(handler.supportedVersions, serverSupportedVersions) + Expect(ok).To(BeTrue()) + Expect(ver).To(Equal(protocol.VersionNumber(43))) + body := (&encryptedExtensionsTransportParameters{ + Parameters: parameters, + NegotiatedVersion: 42, + SupportedVersions: serverSupportedVersions, + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server.go b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server.go new file mode 100644 index 00000000..2d75d693 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server.go @@ -0,0 +1,100 @@ +package handshake + +import ( + "errors" + "fmt" + + "github.com/lucas-clemente/quic-go/qerr" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type extensionHandlerServer struct { + ourParams *TransportParameters + paramsChan chan TransportParameters + + version protocol.VersionNumber + supportedVersions []protocol.VersionNumber + + logger utils.Logger +} + +var _ mint.AppExtensionHandler = &extensionHandlerServer{} +var _ TLSExtensionHandler = &extensionHandlerServer{} + +// NewExtensionHandlerServer creates a new extension handler for the server +func NewExtensionHandlerServer( + params *TransportParameters, + supportedVersions []protocol.VersionNumber, + version protocol.VersionNumber, + logger utils.Logger, +) TLSExtensionHandler { + // Processing the ClientHello is performed statelessly (and from a single go-routine). + // Therefore, we have to use a buffered chan to pass the transport parameters to that go routine. + paramsChan := make(chan TransportParameters, 1) + return &extensionHandlerServer{ + ourParams: params, + paramsChan: paramsChan, + supportedVersions: supportedVersions, + version: version, + logger: logger, + } +} + +func (h *extensionHandlerServer) Send(hType mint.HandshakeType, el *mint.ExtensionList) error { + if hType != mint.HandshakeTypeEncryptedExtensions { + return nil + } + h.logger.Debugf("Sending Transport Parameters: %s", h.ourParams) + eetp := &encryptedExtensionsTransportParameters{ + NegotiatedVersion: h.version, + SupportedVersions: protocol.GetGreasedVersions(h.supportedVersions), + Parameters: *h.ourParams, + } + return el.Add(&tlsExtensionBody{data: eetp.Marshal()}) +} + +func (h *extensionHandlerServer) Receive(hType mint.HandshakeType, el *mint.ExtensionList) error { + ext := &tlsExtensionBody{} + found, err := el.Find(ext) + if err != nil { + return err + } + + if hType != mint.HandshakeTypeClientHello { + if found { + return fmt.Errorf("Unexpected QUIC extension in handshake message %d", hType) + } + return nil + } + + if !found { + return errors.New("ClientHello didn't contain a QUIC extension") + } + chtp := &clientHelloTransportParameters{} + if err := chtp.Unmarshal(ext.data); err != nil { + return err + } + + // perform the stateless version negotiation validation: + // make sure that we would have sent a Version Negotiation Packet if the client offered the initial version + // this is the case if and only if the initial version is not contained in the supported versions + if chtp.InitialVersion != h.version && protocol.IsSupportedVersion(h.supportedVersions, chtp.InitialVersion) { + return qerr.Error(qerr.VersionNegotiationMismatch, "Client should have used the initial version") + } + + // check that the client didn't send a stateless reset token + if len(chtp.Parameters.StatelessResetToken) != 0 { + // TODO: return the correct error type + return errors.New("client sent a stateless reset token") + } + h.logger.Debugf("Received Transport Parameters: %s", &chtp.Parameters) + h.paramsChan <- chtp.Parameters + return nil +} + +func (h *extensionHandlerServer) GetPeerParams() <-chan TransportParameters { + return h.paramsChan +} diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server_test.go new file mode 100644 index 00000000..9563febe --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server_test.go @@ -0,0 +1,155 @@ +package handshake + +import ( + "bytes" + "fmt" + "time" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("TLS Extension Handler, for the server", func() { + var ( + handler *extensionHandlerServer + el mint.ExtensionList + ) + + BeforeEach(func() { + handler = NewExtensionHandlerServer(&TransportParameters{}, nil, protocol.VersionWhatever, utils.DefaultLogger).(*extensionHandlerServer) + el = make(mint.ExtensionList, 0) + }) + + Context("sending", func() { + It("only adds TransportParameters for the ClientHello", func() { + // test 2 other handshake types + err := handler.Send(mint.HandshakeTypeCertificateRequest, &el) + Expect(err).ToNot(HaveOccurred()) + Expect(el).To(BeEmpty()) + err = handler.Send(mint.HandshakeTypeEndOfEarlyData, &el) + Expect(err).ToNot(HaveOccurred()) + Expect(el).To(BeEmpty()) + }) + + It("adds TransportParameters to the EncryptedExtensions message", func() { + handler.version = 666 + versions := []protocol.VersionNumber{13, 37, 42} + handler.supportedVersions = versions + err := handler.Send(mint.HandshakeTypeEncryptedExtensions, &el) + Expect(err).ToNot(HaveOccurred()) + Expect(el).To(HaveLen(1)) + ext := &tlsExtensionBody{} + found, err := el.Find(ext) + Expect(err).ToNot(HaveOccurred()) + Expect(found).To(BeTrue()) + eetp := &encryptedExtensionsTransportParameters{} + err = eetp.Unmarshal(ext.data) + Expect(err).ToNot(HaveOccurred()) + Expect(eetp.NegotiatedVersion).To(BeEquivalentTo(666)) + // the SupportedVersions will contain one reserved version number + Expect(eetp.SupportedVersions).To(HaveLen(len(versions) + 1)) + for _, version := range versions { + Expect(eetp.SupportedVersions).To(ContainElement(version)) + } + }) + }) + + Context("receiving", func() { + var ( + fakeBody *tlsExtensionBody + parameters TransportParameters + ) + + addClientHelloWithParameters := func(params TransportParameters) { + body := (&clientHelloTransportParameters{Parameters: params}).Marshal() + Expect(el.Add(&tlsExtensionBody{data: body})).To(Succeed()) + } + + BeforeEach(func() { + fakeBody = &tlsExtensionBody{data: []byte("foobar foobar")} + parameters = TransportParameters{IdleTimeout: 0x1337 * time.Second} + }) + + It("accepts the TransportParameters on the EncryptedExtensions message", func() { + addClientHelloWithParameters(parameters) + err := handler.Receive(mint.HandshakeTypeClientHello, &el) + Expect(err).ToNot(HaveOccurred()) + var params TransportParameters + Expect(handler.GetPeerParams()).To(Receive(¶ms)) + Expect(params.IdleTimeout).To(Equal(0x1337 * time.Second)) + }) + + It("errors if the ClientHello doesn't contain TransportParameters", func() { + err := handler.Receive(mint.HandshakeTypeClientHello, &el) + Expect(err).To(MatchError("ClientHello didn't contain a QUIC extension")) + }) + + It("ignores messages without TransportParameters, if they are not required", func() { + err := handler.Receive(mint.HandshakeTypeCertificate, &el) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors if it can't unmarshal the TransportParameters", func() { + err := el.Add(fakeBody) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeClientHello, &el) + Expect(err).To(HaveOccurred()) // this will be some kind of decoding error + }) + + It("rejects messages other than the ClientHello that contain TransportParameters", func() { + addClientHelloWithParameters(parameters) + err := handler.Receive(mint.HandshakeTypeCertificateRequest, &el) + Expect(err).To(MatchError(fmt.Sprintf("Unexpected QUIC extension in handshake message %d", mint.HandshakeTypeCertificateRequest))) + }) + + It("rejects messages that contain a stateless reset token", func() { + parameters.StatelessResetToken = bytes.Repeat([]byte{0}, 16) + addClientHelloWithParameters(parameters) + err := handler.Receive(mint.HandshakeTypeClientHello, &el) + Expect(err).To(MatchError("client sent a stateless reset token")) + }) + + Context("Version Negotiation", func() { + It("accepts a ClientHello, when no version negotiation was performed", func() { + handler.version = 42 + body := (&clientHelloTransportParameters{ + InitialVersion: 42, + Parameters: parameters, + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeClientHello, &el) + Expect(err).ToNot(HaveOccurred()) + }) + + It("accepts a valid version negotiation", func() { + handler.version = 42 + handler.supportedVersions = []protocol.VersionNumber{13, 37, 42} + body := (&clientHelloTransportParameters{ + InitialVersion: 22, // this must be an unsupported version + Parameters: parameters, + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeClientHello, &el) + Expect(err).ToNot(HaveOccurred()) + }) + + It("erros when a version negotiation was performed, although we already support the initial version", func() { + handler.supportedVersions = []protocol.VersionNumber{11, 12, 13} + handler.version = 13 + body := (&clientHelloTransportParameters{ + InitialVersion: 11, // this is an supported version + }).Marshal() + err := el.Add(&tlsExtensionBody{data: body}) + Expect(err).ToNot(HaveOccurred()) + err = handler.Receive(mint.HandshakeTypeClientHello, &el) + Expect(err).To(MatchError("VersionNegotiationMismatch: Client should have used the initial version")) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_test.go new file mode 100644 index 00000000..ef0a6dc0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/tls_extension_test.go @@ -0,0 +1,95 @@ +package handshake + +import ( + "math/rand" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("TLS extension body", func() { + Context("Client Hello Transport Parameters", func() { + It("marshals and unmarshals", func() { + chtp := &clientHelloTransportParameters{ + InitialVersion: 0x123456, + Parameters: TransportParameters{ + StreamFlowControlWindow: 0x42, + IdleTimeout: 0x1337 * time.Second, + }, + } + chtp2 := &clientHelloTransportParameters{} + Expect(chtp2.Unmarshal(chtp.Marshal())).To(Succeed()) + Expect(chtp2.InitialVersion).To(Equal(chtp.InitialVersion)) + Expect(chtp2.Parameters.StreamFlowControlWindow).To(Equal(chtp.Parameters.StreamFlowControlWindow)) + Expect(chtp2.Parameters.IdleTimeout).To(Equal(chtp.Parameters.IdleTimeout)) + }) + + It("fuzzes", func() { + rand := rand.New(rand.NewSource(GinkgoRandomSeed())) + b := make([]byte, 100) + for i := 0; i < 1000; i++ { + rand.Read(b) + chtp := &clientHelloTransportParameters{} + chtp.Unmarshal(b[:int(rand.Int31n(100))]) + } + }) + }) + + Context("Encrypted Extensions Transport Parameters", func() { + It("marshals and unmarshals", func() { + eetp := &encryptedExtensionsTransportParameters{ + NegotiatedVersion: 0x123456, + SupportedVersions: []protocol.VersionNumber{0x42, 0x4242}, + Parameters: TransportParameters{ + StreamFlowControlWindow: 0x42, + IdleTimeout: 0x1337 * time.Second, + }, + } + eetp2 := &encryptedExtensionsTransportParameters{} + Expect(eetp2.Unmarshal(eetp.Marshal())).To(Succeed()) + Expect(eetp2.NegotiatedVersion).To(Equal(eetp.NegotiatedVersion)) + Expect(eetp2.SupportedVersions).To(Equal(eetp.SupportedVersions)) + Expect(eetp2.Parameters.StreamFlowControlWindow).To(Equal(eetp.Parameters.StreamFlowControlWindow)) + Expect(eetp2.Parameters.IdleTimeout).To(Equal(eetp.Parameters.IdleTimeout)) + }) + + It("fuzzes", func() { + rand := rand.New(rand.NewSource(GinkgoRandomSeed())) + b := make([]byte, 100) + for i := 0; i < 1000; i++ { + rand.Read(b) + chtp := &encryptedExtensionsTransportParameters{} + chtp.Unmarshal(b[:int(rand.Int31n(100))]) + } + }) + }) + + Context("TLS Extension Body", func() { + var extBody *tlsExtensionBody + + BeforeEach(func() { + extBody = &tlsExtensionBody{} + }) + + It("has the right TLS extension type", func() { + Expect(extBody.Type()).To(BeEquivalentTo(quicTLSExtensionType)) + }) + + It("saves the body when unmarshalling", func() { + n, err := extBody.Unmarshal([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(6)) + Expect(extBody.data).To(Equal([]byte("foobar"))) + }) + + It("returns the body when marshalling", func() { + extBody.data = []byte("foo") + data, err := extBody.Marshal() + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal([]byte("foo"))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/transport_parameter_test.go b/vendor/lucas-clemente/quic-go/internal/handshake/transport_parameter_test.go new file mode 100644 index 00000000..34637a20 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/transport_parameter_test.go @@ -0,0 +1,265 @@ +package handshake + +import ( + "bytes" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Transport Parameters", func() { + Context("for gQUIC", func() { + Context("parsing", func() { + It("sets all values", func() { + values := map[Tag][]byte{ + TagSFCW: {0xad, 0xfb, 0xca, 0xde}, + TagCFCW: {0xef, 0xbe, 0xad, 0xde}, + TagICSL: {0x0d, 0xf0, 0xad, 0xba}, + TagMIDS: {0xff, 0x10, 0x00, 0xc0}, + } + params, err := readHelloMap(values) + Expect(err).ToNot(HaveOccurred()) + Expect(params.StreamFlowControlWindow).To(Equal(protocol.ByteCount(0xdecafbad))) + Expect(params.ConnectionFlowControlWindow).To(Equal(protocol.ByteCount(0xdeadbeef))) + Expect(params.IdleTimeout).To(Equal(time.Duration(0xbaadf00d) * time.Second)) + Expect(params.MaxStreams).To(Equal(uint32(0xc00010ff))) + Expect(params.OmitConnectionID).To(BeFalse()) + }) + + It("reads if the connection ID should be omitted", func() { + values := map[Tag][]byte{TagTCID: {0, 0, 0, 0}} + params, err := readHelloMap(values) + Expect(err).ToNot(HaveOccurred()) + Expect(params.OmitConnectionID).To(BeTrue()) + }) + + It("doesn't allow idle timeouts below the minimum remote idle timeout", func() { + t := 2 * time.Second + Expect(t).To(BeNumerically("<", protocol.MinRemoteIdleTimeout)) + values := map[Tag][]byte{ + TagICSL: {uint8(t.Seconds()), 0, 0, 0}, + } + params, err := readHelloMap(values) + Expect(err).ToNot(HaveOccurred()) + Expect(params.IdleTimeout).To(Equal(protocol.MinRemoteIdleTimeout)) + }) + + It("errors when given an invalid SFCW value", func() { + values := map[Tag][]byte{TagSFCW: {2, 0, 0}} // 1 byte too short + _, err := readHelloMap(values) + Expect(err).To(MatchError(errMalformedTag)) + }) + + It("errors when given an invalid CFCW value", func() { + values := map[Tag][]byte{TagCFCW: {2, 0, 0}} // 1 byte too short + _, err := readHelloMap(values) + Expect(err).To(MatchError(errMalformedTag)) + }) + + It("errors when given an invalid TCID value", func() { + values := map[Tag][]byte{TagTCID: {2, 0, 0}} // 1 byte too short + _, err := readHelloMap(values) + Expect(err).To(MatchError(errMalformedTag)) + }) + + It("errors when given an invalid ICSL value", func() { + values := map[Tag][]byte{TagICSL: {2, 0, 0}} // 1 byte too short + _, err := readHelloMap(values) + Expect(err).To(MatchError(errMalformedTag)) + }) + + It("errors when given an invalid MIDS value", func() { + values := map[Tag][]byte{TagMIDS: {2, 0, 0}} // 1 byte too short + _, err := readHelloMap(values) + Expect(err).To(MatchError(errMalformedTag)) + }) + }) + + Context("writing", func() { + It("returns all necessary parameters ", func() { + params := &TransportParameters{ + StreamFlowControlWindow: 0xdeadbeef, + ConnectionFlowControlWindow: 0xdecafbad, + IdleTimeout: 0xbaaaaaad * time.Second, + MaxStreams: 0x1337, + } + entryMap := params.getHelloMap() + Expect(entryMap).To(HaveLen(4)) + Expect(entryMap).ToNot(HaveKey(TagTCID)) + Expect(entryMap).To(HaveKeyWithValue(TagSFCW, []byte{0xef, 0xbe, 0xad, 0xde})) + Expect(entryMap).To(HaveKeyWithValue(TagCFCW, []byte{0xad, 0xfb, 0xca, 0xde})) + Expect(entryMap).To(HaveKeyWithValue(TagICSL, []byte{0xad, 0xaa, 0xaa, 0xba})) + Expect(entryMap).To(HaveKeyWithValue(TagMIDS, []byte{0x37, 0x13, 0, 0})) + }) + + It("requests omission of the connection ID", func() { + params := &TransportParameters{OmitConnectionID: true} + entryMap := params.getHelloMap() + Expect(entryMap).To(HaveKeyWithValue(TagTCID, []byte{0, 0, 0, 0})) + }) + }) + }) + + Context("for TLS", func() { + It("has a string representation", func() { + p := &TransportParameters{ + StreamFlowControlWindow: 0x1234, + ConnectionFlowControlWindow: 0x4321, + MaxBidiStreams: 1337, + MaxUniStreams: 7331, + IdleTimeout: 42 * time.Second, + } + Expect(p.String()).To(Equal("&handshake.TransportParameters{StreamFlowControlWindow: 0x1234, ConnectionFlowControlWindow: 0x4321, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s}")) + }) + + Context("parsing", func() { + var ( + params *TransportParameters + parameters map[transportParameterID][]byte + statelessResetToken []byte + ) + + marshal := func(p map[transportParameterID][]byte) []byte { + b := &bytes.Buffer{} + for id, val := range p { + utils.BigEndian.WriteUint16(b, uint16(id)) + utils.BigEndian.WriteUint16(b, uint16(len(val))) + b.Write(val) + } + return b.Bytes() + } + + BeforeEach(func() { + params = &TransportParameters{} + statelessResetToken = bytes.Repeat([]byte{42}, 16) + parameters = map[transportParameterID][]byte{ + initialMaxStreamDataParameterID: {0x11, 0x22, 0x33, 0x44}, + initialMaxDataParameterID: {0x22, 0x33, 0x44, 0x55}, + initialMaxBidiStreamsParameterID: {0x33, 0x44}, + initialMaxUniStreamsParameterID: {0x44, 0x55}, + idleTimeoutParameterID: {0x13, 0x37}, + maxPacketSizeParameterID: {0x73, 0x31}, + disableMigrationParameterID: {}, + statelessResetTokenParameterID: statelessResetToken, + } + }) + It("reads parameters", func() { + err := params.unmarshal(marshal(parameters)) + Expect(err).ToNot(HaveOccurred()) + Expect(params.StreamFlowControlWindow).To(Equal(protocol.ByteCount(0x11223344))) + Expect(params.ConnectionFlowControlWindow).To(Equal(protocol.ByteCount(0x22334455))) + Expect(params.MaxBidiStreams).To(Equal(uint16(0x3344))) + Expect(params.MaxUniStreams).To(Equal(uint16(0x4455))) + Expect(params.IdleTimeout).To(Equal(0x1337 * time.Second)) + Expect(params.OmitConnectionID).To(BeFalse()) + Expect(params.MaxPacketSize).To(Equal(protocol.ByteCount(0x7331))) + Expect(params.DisableMigration).To(BeTrue()) + Expect(params.StatelessResetToken).To(Equal(statelessResetToken)) + }) + + It("rejects the parameters if the idle_timeout is missing", func() { + delete(parameters, idleTimeoutParameterID) + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("missing parameter")) + }) + + It("doesn't allow values below the minimum remote idle timeout", func() { + t := 2 * time.Second + Expect(t).To(BeNumerically("<", protocol.MinRemoteIdleTimeout)) + parameters[idleTimeoutParameterID] = []byte{0, uint8(t.Seconds())} + err := params.unmarshal(marshal(parameters)) + Expect(err).ToNot(HaveOccurred()) + Expect(params.IdleTimeout).To(Equal(protocol.MinRemoteIdleTimeout)) + }) + + It("rejects the parameters if the initial_max_stream_data has the wrong length", func() { + parameters[initialMaxStreamDataParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for initial_max_stream_data: 3 (expected 4)")) + }) + + It("rejects the parameters if the initial_max_data has the wrong length", func() { + parameters[initialMaxDataParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for initial_max_data: 3 (expected 4)")) + }) + + It("rejects the parameters if the initial_max_stream_id_bidi has the wrong length", func() { + parameters[initialMaxBidiStreamsParameterID] = []byte{0x11, 0x22, 0x33} // should be 2 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for initial_max_stream_id_bidi: 3 (expected 2)")) + }) + + It("rejects the parameters if the initial_max_stream_id_bidi has the wrong length", func() { + parameters[initialMaxUniStreamsParameterID] = []byte{0x11, 0x22, 0x33} // should be 2 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for initial_max_stream_id_uni: 3 (expected 2)")) + }) + + It("rejects the parameters if the initial_idle_timeout has the wrong length", func() { + parameters[idleTimeoutParameterID] = []byte{0x11, 0x22, 0x33} // should be 2 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for idle_timeout: 3 (expected 2)")) + }) + + It("rejects the parameters if max_packet_size has the wrong length", func() { + parameters[maxPacketSizeParameterID] = []byte{0x11} // should be 2 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for max_packet_size: 1 (expected 2)")) + }) + + It("rejects max_packet_sizes smaller than 1200 bytes", func() { + parameters[maxPacketSizeParameterID] = []byte{0x4, 0xaf} // 0x4af = 1199 + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("invalid value for max_packet_size: 1199 (minimum 1200)")) + }) + + It("rejects the parameters if disable_connection_migration has the wrong length", func() { + parameters[disableMigrationParameterID] = []byte{0x11} // should empty + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for disable_migration: 1 (expected empty)")) + }) + + It("rejects the parameters if the stateless_reset_token has the wrong length", func() { + parameters[statelessResetTokenParameterID] = statelessResetToken[1:] + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for stateless_reset_token: 15 (expected 16)")) + }) + + It("ignores unknown parameters", func() { + parameters[1337] = []byte{42} + err := params.unmarshal(marshal(parameters)) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("marshalling", func() { + It("marshals", func() { + params := &TransportParameters{ + StreamFlowControlWindow: 0xdeadbeef, + ConnectionFlowControlWindow: 0xdecafbad, + IdleTimeout: 0xcafe * time.Second, + MaxBidiStreams: 0x1234, + MaxUniStreams: 0x4321, + DisableMigration: true, + StatelessResetToken: bytes.Repeat([]byte{100}, 16), + } + b := &bytes.Buffer{} + params.marshal(b) + + p := &TransportParameters{} + Expect(p.unmarshal(b.Bytes())).To(Succeed()) + Expect(p.StreamFlowControlWindow).To(Equal(params.StreamFlowControlWindow)) + Expect(p.ConnectionFlowControlWindow).To(Equal(params.ConnectionFlowControlWindow)) + Expect(p.MaxUniStreams).To(Equal(params.MaxUniStreams)) + Expect(p.MaxBidiStreams).To(Equal(params.MaxBidiStreams)) + Expect(p.IdleTimeout).To(Equal(params.IdleTimeout)) + Expect(p.DisableMigration).To(Equal(params.DisableMigration)) + Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken)) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/handshake/transport_parameters.go b/vendor/lucas-clemente/quic-go/internal/handshake/transport_parameters.go new file mode 100644 index 00000000..9ed0aeb5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/handshake/transport_parameters.go @@ -0,0 +1,209 @@ +package handshake + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +// errMalformedTag is returned when the tag value cannot be read +var errMalformedTag = qerr.Error(qerr.InvalidCryptoMessageParameter, "malformed Tag value") + +// TransportParameters are parameters sent to the peer during the handshake +type TransportParameters struct { + StreamFlowControlWindow protocol.ByteCount + ConnectionFlowControlWindow protocol.ByteCount + + MaxPacketSize protocol.ByteCount + + MaxUniStreams uint16 // only used for IETF QUIC + MaxBidiStreams uint16 // only used for IETF QUIC + MaxStreams uint32 // only used for gQUIC + + OmitConnectionID bool // only used for gQUIC + IdleTimeout time.Duration + DisableMigration bool // only used for IETF QUIC + StatelessResetToken []byte // only used for IETF QUIC +} + +// readHelloMap reads the transport parameters from the tags sent in a gQUIC handshake message +func readHelloMap(tags map[Tag][]byte) (*TransportParameters, error) { + params := &TransportParameters{} + if value, ok := tags[TagTCID]; ok { + v, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value)) + if err != nil { + return nil, errMalformedTag + } + params.OmitConnectionID = (v == 0) + } + if value, ok := tags[TagMIDS]; ok { + v, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value)) + if err != nil { + return nil, errMalformedTag + } + params.MaxStreams = v + } + if value, ok := tags[TagICSL]; ok { + v, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value)) + if err != nil { + return nil, errMalformedTag + } + params.IdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, time.Duration(v)*time.Second) + } + if value, ok := tags[TagSFCW]; ok { + v, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value)) + if err != nil { + return nil, errMalformedTag + } + params.StreamFlowControlWindow = protocol.ByteCount(v) + } + if value, ok := tags[TagCFCW]; ok { + v, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value)) + if err != nil { + return nil, errMalformedTag + } + params.ConnectionFlowControlWindow = protocol.ByteCount(v) + } + return params, nil +} + +// GetHelloMap gets all parameters needed for the Hello message in the gQUIC handshake. +func (p *TransportParameters) getHelloMap() map[Tag][]byte { + sfcw := bytes.NewBuffer([]byte{}) + utils.LittleEndian.WriteUint32(sfcw, uint32(p.StreamFlowControlWindow)) + cfcw := bytes.NewBuffer([]byte{}) + utils.LittleEndian.WriteUint32(cfcw, uint32(p.ConnectionFlowControlWindow)) + mids := bytes.NewBuffer([]byte{}) + utils.LittleEndian.WriteUint32(mids, p.MaxStreams) + icsl := bytes.NewBuffer([]byte{}) + utils.LittleEndian.WriteUint32(icsl, uint32(p.IdleTimeout/time.Second)) + + tags := map[Tag][]byte{ + TagICSL: icsl.Bytes(), + TagMIDS: mids.Bytes(), + TagCFCW: cfcw.Bytes(), + TagSFCW: sfcw.Bytes(), + } + if p.OmitConnectionID { + tags[TagTCID] = []byte{0, 0, 0, 0} + } + return tags +} + +func (p *TransportParameters) unmarshal(data []byte) error { + var foundIdleTimeout bool + + for len(data) >= 4 { + paramID := binary.BigEndian.Uint16(data[:2]) + paramLen := int(binary.BigEndian.Uint16(data[2:4])) + data = data[4:] + if len(data) < paramLen { + return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", len(data), paramLen) + } + switch transportParameterID(paramID) { + case initialMaxStreamDataParameterID: + if paramLen != 4 { + return fmt.Errorf("wrong length for initial_max_stream_data: %d (expected 4)", paramLen) + } + p.StreamFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(data[:4])) + case initialMaxDataParameterID: + if paramLen != 4 { + return fmt.Errorf("wrong length for initial_max_data: %d (expected 4)", paramLen) + } + p.ConnectionFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(data[:4])) + case initialMaxBidiStreamsParameterID: + if paramLen != 2 { + return fmt.Errorf("wrong length for initial_max_stream_id_bidi: %d (expected 2)", paramLen) + } + p.MaxBidiStreams = binary.BigEndian.Uint16(data[:2]) + case initialMaxUniStreamsParameterID: + if paramLen != 2 { + return fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 2)", paramLen) + } + p.MaxUniStreams = binary.BigEndian.Uint16(data[:2]) + case idleTimeoutParameterID: + foundIdleTimeout = true + if paramLen != 2 { + return fmt.Errorf("wrong length for idle_timeout: %d (expected 2)", paramLen) + } + p.IdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, time.Duration(binary.BigEndian.Uint16(data[:2]))*time.Second) + case maxPacketSizeParameterID: + if paramLen != 2 { + return fmt.Errorf("wrong length for max_packet_size: %d (expected 2)", paramLen) + } + maxPacketSize := protocol.ByteCount(binary.BigEndian.Uint16(data[:2])) + if maxPacketSize < 1200 { + return fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", maxPacketSize) + } + p.MaxPacketSize = maxPacketSize + case disableMigrationParameterID: + if paramLen != 0 { + return fmt.Errorf("wrong length for disable_migration: %d (expected empty)", paramLen) + } + p.DisableMigration = true + case statelessResetTokenParameterID: + if paramLen != 16 { + return fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", paramLen) + } + p.StatelessResetToken = data[:16] + } + data = data[paramLen:] + } + + if len(data) != 0 { + return fmt.Errorf("should have read all data. Still have %d bytes", len(data)) + } + if !foundIdleTimeout { + return errors.New("missing parameter") + } + return nil +} + +func (p *TransportParameters) marshal(b *bytes.Buffer) { + // initial_max_stream_data + utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataParameterID)) + utils.BigEndian.WriteUint16(b, 4) + utils.BigEndian.WriteUint32(b, uint32(p.StreamFlowControlWindow)) + // initial_max_data + utils.BigEndian.WriteUint16(b, uint16(initialMaxDataParameterID)) + utils.BigEndian.WriteUint16(b, 4) + utils.BigEndian.WriteUint32(b, uint32(p.ConnectionFlowControlWindow)) + // initial_max_bidi_streams + utils.BigEndian.WriteUint16(b, uint16(initialMaxBidiStreamsParameterID)) + utils.BigEndian.WriteUint16(b, 2) + utils.BigEndian.WriteUint16(b, p.MaxBidiStreams) + // initial_max_uni_streams + utils.BigEndian.WriteUint16(b, uint16(initialMaxUniStreamsParameterID)) + utils.BigEndian.WriteUint16(b, 2) + utils.BigEndian.WriteUint16(b, p.MaxUniStreams) + // idle_timeout + utils.BigEndian.WriteUint16(b, uint16(idleTimeoutParameterID)) + utils.BigEndian.WriteUint16(b, 2) + utils.BigEndian.WriteUint16(b, uint16(p.IdleTimeout/time.Second)) + // max_packet_size + utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID)) + utils.BigEndian.WriteUint16(b, 2) + utils.BigEndian.WriteUint16(b, uint16(protocol.MaxReceivePacketSize)) + // disable_migration + if p.DisableMigration { + utils.BigEndian.WriteUint16(b, uint16(disableMigrationParameterID)) + utils.BigEndian.WriteUint16(b, 0) + } + if len(p.StatelessResetToken) > 0 { + utils.BigEndian.WriteUint16(b, uint16(statelessResetTokenParameterID)) + utils.BigEndian.WriteUint16(b, uint16(len(p.StatelessResetToken))) // should always be 16 bytes + b.Write(p.StatelessResetToken) + } +} + +// String returns a string representation, intended for logging. +// It should only used for IETF QUIC. +func (p *TransportParameters) String() string { + return fmt.Sprintf("&handshake.TransportParameters{StreamFlowControlWindow: %#x, ConnectionFlowControlWindow: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s}", p.StreamFlowControlWindow, p.ConnectionFlowControlWindow, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout) +} diff --git a/vendor/lucas-clemente/quic-go/internal/mockgen_internal.sh b/vendor/lucas-clemente/quic-go/internal/mockgen_internal.sh new file mode 100755 index 00000000..a0f9112b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mockgen_internal.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Mockgen refuses to generate mocks for internal packages. +# This script copies the internal directory and renames it to internalpackage. +# It also creages a public alias for private types. +# It then creates a mock for this public (alias) type. +# Afterwards, it corrects the import paths (replaces internalpackage back to internal). + +TEMP_DIR=$(mktemp -d) +mkdir -p $TEMP_DIR/src/github.com/lucas-clemente/quic-go/internalpackage + +# uppercase the name of the interface (only has an effect for private interfaces) +INTERFACE_NAME="$(tr '[:lower:]' '[:upper:]' <<< ${4:0:1})${4:1}" +PACKAGE_NAME=`echo $3 | sed 's/.*\///'` + +cp -r $GOPATH/src/github.com/lucas-clemente/quic-go/internal/* $TEMP_DIR/src/github.com/lucas-clemente/quic-go/internalpackage +find $TEMP_DIR -type f -name "*.go" -exec sed -i '' 's/internal/internalpackage/g' {} \; + +export GOPATH="$TEMP_DIR:$GOPATH" +PACKAGE_PATH=${3/internal/internalpackage} + +# if we're mocking a private interface, we need to add a public alias +if [ "$INTERFACE_NAME" != "$4" ]; then + # create a public alias for the interface, so that mockgen can process it + echo -e "package $PACKAGE_NAME\n" > $TEMP_DIR/src/$PACKAGE_PATH/mockgen_interface.go + echo "type $INTERFACE_NAME = $4" >> $TEMP_DIR/src/$PACKAGE_PATH/mockgen_interface.go +fi + +mockgen -package $1 -self_package $1 -destination $2 $PACKAGE_PATH $INTERFACE_NAME +sed -i '' 's/internalpackage/internal/g' $2 + +# mockgen imports the package we're generating a mock for +sed -i '' "s/$1\.//g" $2 +goimports -w $2 + +rm -r "$TEMP_DIR" diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/received_packet_handler.go b/vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/received_packet_handler.go new file mode 100644 index 00000000..d3e864f6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/received_packet_handler.go @@ -0,0 +1,83 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/ackhandler (interfaces: ReceivedPacketHandler) + +// Package mockackhandler is a generated GoMock package. +package mockackhandler + +import ( + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockReceivedPacketHandler is a mock of ReceivedPacketHandler interface +type MockReceivedPacketHandler struct { + ctrl *gomock.Controller + recorder *MockReceivedPacketHandlerMockRecorder +} + +// MockReceivedPacketHandlerMockRecorder is the mock recorder for MockReceivedPacketHandler +type MockReceivedPacketHandlerMockRecorder struct { + mock *MockReceivedPacketHandler +} + +// NewMockReceivedPacketHandler creates a new mock instance +func NewMockReceivedPacketHandler(ctrl *gomock.Controller) *MockReceivedPacketHandler { + mock := &MockReceivedPacketHandler{ctrl: ctrl} + mock.recorder = &MockReceivedPacketHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockReceivedPacketHandler) EXPECT() *MockReceivedPacketHandlerMockRecorder { + return m.recorder +} + +// GetAckFrame mocks base method +func (m *MockReceivedPacketHandler) GetAckFrame() *wire.AckFrame { + ret := m.ctrl.Call(m, "GetAckFrame") + ret0, _ := ret[0].(*wire.AckFrame) + return ret0 +} + +// GetAckFrame indicates an expected call of GetAckFrame +func (mr *MockReceivedPacketHandlerMockRecorder) GetAckFrame() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAckFrame", reflect.TypeOf((*MockReceivedPacketHandler)(nil).GetAckFrame)) +} + +// GetAlarmTimeout mocks base method +func (m *MockReceivedPacketHandler) GetAlarmTimeout() time.Time { + ret := m.ctrl.Call(m, "GetAlarmTimeout") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetAlarmTimeout indicates an expected call of GetAlarmTimeout +func (mr *MockReceivedPacketHandlerMockRecorder) GetAlarmTimeout() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAlarmTimeout", reflect.TypeOf((*MockReceivedPacketHandler)(nil).GetAlarmTimeout)) +} + +// IgnoreBelow mocks base method +func (m *MockReceivedPacketHandler) IgnoreBelow(arg0 protocol.PacketNumber) { + m.ctrl.Call(m, "IgnoreBelow", arg0) +} + +// IgnoreBelow indicates an expected call of IgnoreBelow +func (mr *MockReceivedPacketHandlerMockRecorder) IgnoreBelow(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IgnoreBelow", reflect.TypeOf((*MockReceivedPacketHandler)(nil).IgnoreBelow), arg0) +} + +// ReceivedPacket mocks base method +func (m *MockReceivedPacketHandler) ReceivedPacket(arg0 protocol.PacketNumber, arg1 time.Time, arg2 bool) error { + ret := m.ctrl.Call(m, "ReceivedPacket", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ReceivedPacket indicates an expected call of ReceivedPacket +func (mr *MockReceivedPacketHandlerMockRecorder) ReceivedPacket(arg0, arg1, arg2 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceivedPacket", reflect.TypeOf((*MockReceivedPacketHandler)(nil).ReceivedPacket), arg0, arg1, arg2) +} diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/sent_packet_handler.go b/vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/sent_packet_handler.go new file mode 100644 index 00000000..aff5a1e1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/ackhandler/sent_packet_handler.go @@ -0,0 +1,201 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/ackhandler (interfaces: SentPacketHandler) + +// Package mockackhandler is a generated GoMock package. +package mockackhandler + +import ( + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + ackhandler "github.com/lucas-clemente/quic-go/internal/ackhandler" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockSentPacketHandler is a mock of SentPacketHandler interface +type MockSentPacketHandler struct { + ctrl *gomock.Controller + recorder *MockSentPacketHandlerMockRecorder +} + +// MockSentPacketHandlerMockRecorder is the mock recorder for MockSentPacketHandler +type MockSentPacketHandlerMockRecorder struct { + mock *MockSentPacketHandler +} + +// NewMockSentPacketHandler creates a new mock instance +func NewMockSentPacketHandler(ctrl *gomock.Controller) *MockSentPacketHandler { + mock := &MockSentPacketHandler{ctrl: ctrl} + mock.recorder = &MockSentPacketHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSentPacketHandler) EXPECT() *MockSentPacketHandlerMockRecorder { + return m.recorder +} + +// DequeuePacketForRetransmission mocks base method +func (m *MockSentPacketHandler) DequeuePacketForRetransmission() *ackhandler.Packet { + ret := m.ctrl.Call(m, "DequeuePacketForRetransmission") + ret0, _ := ret[0].(*ackhandler.Packet) + return ret0 +} + +// DequeuePacketForRetransmission indicates an expected call of DequeuePacketForRetransmission +func (mr *MockSentPacketHandlerMockRecorder) DequeuePacketForRetransmission() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DequeuePacketForRetransmission", reflect.TypeOf((*MockSentPacketHandler)(nil).DequeuePacketForRetransmission)) +} + +// DequeueProbePacket mocks base method +func (m *MockSentPacketHandler) DequeueProbePacket() (*ackhandler.Packet, error) { + ret := m.ctrl.Call(m, "DequeueProbePacket") + ret0, _ := ret[0].(*ackhandler.Packet) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DequeueProbePacket indicates an expected call of DequeueProbePacket +func (mr *MockSentPacketHandlerMockRecorder) DequeueProbePacket() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DequeueProbePacket", reflect.TypeOf((*MockSentPacketHandler)(nil).DequeueProbePacket)) +} + +// GetAlarmTimeout mocks base method +func (m *MockSentPacketHandler) GetAlarmTimeout() time.Time { + ret := m.ctrl.Call(m, "GetAlarmTimeout") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetAlarmTimeout indicates an expected call of GetAlarmTimeout +func (mr *MockSentPacketHandlerMockRecorder) GetAlarmTimeout() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAlarmTimeout", reflect.TypeOf((*MockSentPacketHandler)(nil).GetAlarmTimeout)) +} + +// GetLowestPacketNotConfirmedAcked mocks base method +func (m *MockSentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNumber { + ret := m.ctrl.Call(m, "GetLowestPacketNotConfirmedAcked") + ret0, _ := ret[0].(protocol.PacketNumber) + return ret0 +} + +// GetLowestPacketNotConfirmedAcked indicates an expected call of GetLowestPacketNotConfirmedAcked +func (mr *MockSentPacketHandlerMockRecorder) GetLowestPacketNotConfirmedAcked() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLowestPacketNotConfirmedAcked", reflect.TypeOf((*MockSentPacketHandler)(nil).GetLowestPacketNotConfirmedAcked)) +} + +// GetPacketNumberLen mocks base method +func (m *MockSentPacketHandler) GetPacketNumberLen(arg0 protocol.PacketNumber) protocol.PacketNumberLen { + ret := m.ctrl.Call(m, "GetPacketNumberLen", arg0) + ret0, _ := ret[0].(protocol.PacketNumberLen) + return ret0 +} + +// GetPacketNumberLen indicates an expected call of GetPacketNumberLen +func (mr *MockSentPacketHandlerMockRecorder) GetPacketNumberLen(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPacketNumberLen", reflect.TypeOf((*MockSentPacketHandler)(nil).GetPacketNumberLen), arg0) +} + +// GetStopWaitingFrame mocks base method +func (m *MockSentPacketHandler) GetStopWaitingFrame(arg0 bool) *wire.StopWaitingFrame { + ret := m.ctrl.Call(m, "GetStopWaitingFrame", arg0) + ret0, _ := ret[0].(*wire.StopWaitingFrame) + return ret0 +} + +// GetStopWaitingFrame indicates an expected call of GetStopWaitingFrame +func (mr *MockSentPacketHandlerMockRecorder) GetStopWaitingFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStopWaitingFrame", reflect.TypeOf((*MockSentPacketHandler)(nil).GetStopWaitingFrame), arg0) +} + +// OnAlarm mocks base method +func (m *MockSentPacketHandler) OnAlarm() error { + ret := m.ctrl.Call(m, "OnAlarm") + ret0, _ := ret[0].(error) + return ret0 +} + +// OnAlarm indicates an expected call of OnAlarm +func (mr *MockSentPacketHandlerMockRecorder) OnAlarm() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAlarm", reflect.TypeOf((*MockSentPacketHandler)(nil).OnAlarm)) +} + +// ReceivedAck mocks base method +func (m *MockSentPacketHandler) ReceivedAck(arg0 *wire.AckFrame, arg1 protocol.PacketNumber, arg2 protocol.EncryptionLevel, arg3 time.Time) error { + ret := m.ctrl.Call(m, "ReceivedAck", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// ReceivedAck indicates an expected call of ReceivedAck +func (mr *MockSentPacketHandlerMockRecorder) ReceivedAck(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceivedAck", reflect.TypeOf((*MockSentPacketHandler)(nil).ReceivedAck), arg0, arg1, arg2, arg3) +} + +// SendMode mocks base method +func (m *MockSentPacketHandler) SendMode() ackhandler.SendMode { + ret := m.ctrl.Call(m, "SendMode") + ret0, _ := ret[0].(ackhandler.SendMode) + return ret0 +} + +// SendMode indicates an expected call of SendMode +func (mr *MockSentPacketHandlerMockRecorder) SendMode() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMode", reflect.TypeOf((*MockSentPacketHandler)(nil).SendMode)) +} + +// SentPacket mocks base method +func (m *MockSentPacketHandler) SentPacket(arg0 *ackhandler.Packet) { + m.ctrl.Call(m, "SentPacket", arg0) +} + +// SentPacket indicates an expected call of SentPacket +func (mr *MockSentPacketHandlerMockRecorder) SentPacket(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SentPacket", reflect.TypeOf((*MockSentPacketHandler)(nil).SentPacket), arg0) +} + +// SentPacketsAsRetransmission mocks base method +func (m *MockSentPacketHandler) SentPacketsAsRetransmission(arg0 []*ackhandler.Packet, arg1 protocol.PacketNumber) { + m.ctrl.Call(m, "SentPacketsAsRetransmission", arg0, arg1) +} + +// SentPacketsAsRetransmission indicates an expected call of SentPacketsAsRetransmission +func (mr *MockSentPacketHandlerMockRecorder) SentPacketsAsRetransmission(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SentPacketsAsRetransmission", reflect.TypeOf((*MockSentPacketHandler)(nil).SentPacketsAsRetransmission), arg0, arg1) +} + +// SetHandshakeComplete mocks base method +func (m *MockSentPacketHandler) SetHandshakeComplete() { + m.ctrl.Call(m, "SetHandshakeComplete") +} + +// SetHandshakeComplete indicates an expected call of SetHandshakeComplete +func (mr *MockSentPacketHandlerMockRecorder) SetHandshakeComplete() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHandshakeComplete", reflect.TypeOf((*MockSentPacketHandler)(nil).SetHandshakeComplete)) +} + +// ShouldSendNumPackets mocks base method +func (m *MockSentPacketHandler) ShouldSendNumPackets() int { + ret := m.ctrl.Call(m, "ShouldSendNumPackets") + ret0, _ := ret[0].(int) + return ret0 +} + +// ShouldSendNumPackets indicates an expected call of ShouldSendNumPackets +func (mr *MockSentPacketHandlerMockRecorder) ShouldSendNumPackets() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldSendNumPackets", reflect.TypeOf((*MockSentPacketHandler)(nil).ShouldSendNumPackets)) +} + +// TimeUntilSend mocks base method +func (m *MockSentPacketHandler) TimeUntilSend() time.Time { + ret := m.ctrl.Call(m, "TimeUntilSend") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// TimeUntilSend indicates an expected call of TimeUntilSend +func (mr *MockSentPacketHandlerMockRecorder) TimeUntilSend() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TimeUntilSend", reflect.TypeOf((*MockSentPacketHandler)(nil).TimeUntilSend)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/congestion.go b/vendor/lucas-clemente/quic-go/internal/mocks/congestion.go new file mode 100644 index 00000000..d0749252 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/congestion.go @@ -0,0 +1,140 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/congestion (interfaces: SendAlgorithm) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockSendAlgorithm is a mock of SendAlgorithm interface +type MockSendAlgorithm struct { + ctrl *gomock.Controller + recorder *MockSendAlgorithmMockRecorder +} + +// MockSendAlgorithmMockRecorder is the mock recorder for MockSendAlgorithm +type MockSendAlgorithmMockRecorder struct { + mock *MockSendAlgorithm +} + +// NewMockSendAlgorithm creates a new mock instance +func NewMockSendAlgorithm(ctrl *gomock.Controller) *MockSendAlgorithm { + mock := &MockSendAlgorithm{ctrl: ctrl} + mock.recorder = &MockSendAlgorithmMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSendAlgorithm) EXPECT() *MockSendAlgorithmMockRecorder { + return m.recorder +} + +// GetCongestionWindow mocks base method +func (m *MockSendAlgorithm) GetCongestionWindow() protocol.ByteCount { + ret := m.ctrl.Call(m, "GetCongestionWindow") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// GetCongestionWindow indicates an expected call of GetCongestionWindow +func (mr *MockSendAlgorithmMockRecorder) GetCongestionWindow() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCongestionWindow", reflect.TypeOf((*MockSendAlgorithm)(nil).GetCongestionWindow)) +} + +// MaybeExitSlowStart mocks base method +func (m *MockSendAlgorithm) MaybeExitSlowStart() { + m.ctrl.Call(m, "MaybeExitSlowStart") +} + +// MaybeExitSlowStart indicates an expected call of MaybeExitSlowStart +func (mr *MockSendAlgorithmMockRecorder) MaybeExitSlowStart() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaybeExitSlowStart", reflect.TypeOf((*MockSendAlgorithm)(nil).MaybeExitSlowStart)) +} + +// OnConnectionMigration mocks base method +func (m *MockSendAlgorithm) OnConnectionMigration() { + m.ctrl.Call(m, "OnConnectionMigration") +} + +// OnConnectionMigration indicates an expected call of OnConnectionMigration +func (mr *MockSendAlgorithmMockRecorder) OnConnectionMigration() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnConnectionMigration", reflect.TypeOf((*MockSendAlgorithm)(nil).OnConnectionMigration)) +} + +// OnPacketAcked mocks base method +func (m *MockSendAlgorithm) OnPacketAcked(arg0 protocol.PacketNumber, arg1, arg2 protocol.ByteCount, arg3 time.Time) { + m.ctrl.Call(m, "OnPacketAcked", arg0, arg1, arg2, arg3) +} + +// OnPacketAcked indicates an expected call of OnPacketAcked +func (mr *MockSendAlgorithmMockRecorder) OnPacketAcked(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketAcked", reflect.TypeOf((*MockSendAlgorithm)(nil).OnPacketAcked), arg0, arg1, arg2, arg3) +} + +// OnPacketLost mocks base method +func (m *MockSendAlgorithm) OnPacketLost(arg0 protocol.PacketNumber, arg1, arg2 protocol.ByteCount) { + m.ctrl.Call(m, "OnPacketLost", arg0, arg1, arg2) +} + +// OnPacketLost indicates an expected call of OnPacketLost +func (mr *MockSendAlgorithmMockRecorder) OnPacketLost(arg0, arg1, arg2 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketLost", reflect.TypeOf((*MockSendAlgorithm)(nil).OnPacketLost), arg0, arg1, arg2) +} + +// OnPacketSent mocks base method +func (m *MockSendAlgorithm) OnPacketSent(arg0 time.Time, arg1 protocol.ByteCount, arg2 protocol.PacketNumber, arg3 protocol.ByteCount, arg4 bool) { + m.ctrl.Call(m, "OnPacketSent", arg0, arg1, arg2, arg3, arg4) +} + +// OnPacketSent indicates an expected call of OnPacketSent +func (mr *MockSendAlgorithmMockRecorder) OnPacketSent(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketSent", reflect.TypeOf((*MockSendAlgorithm)(nil).OnPacketSent), arg0, arg1, arg2, arg3, arg4) +} + +// OnRetransmissionTimeout mocks base method +func (m *MockSendAlgorithm) OnRetransmissionTimeout(arg0 bool) { + m.ctrl.Call(m, "OnRetransmissionTimeout", arg0) +} + +// OnRetransmissionTimeout indicates an expected call of OnRetransmissionTimeout +func (mr *MockSendAlgorithmMockRecorder) OnRetransmissionTimeout(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRetransmissionTimeout", reflect.TypeOf((*MockSendAlgorithm)(nil).OnRetransmissionTimeout), arg0) +} + +// SetNumEmulatedConnections mocks base method +func (m *MockSendAlgorithm) SetNumEmulatedConnections(arg0 int) { + m.ctrl.Call(m, "SetNumEmulatedConnections", arg0) +} + +// SetNumEmulatedConnections indicates an expected call of SetNumEmulatedConnections +func (mr *MockSendAlgorithmMockRecorder) SetNumEmulatedConnections(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetNumEmulatedConnections", reflect.TypeOf((*MockSendAlgorithm)(nil).SetNumEmulatedConnections), arg0) +} + +// SetSlowStartLargeReduction mocks base method +func (m *MockSendAlgorithm) SetSlowStartLargeReduction(arg0 bool) { + m.ctrl.Call(m, "SetSlowStartLargeReduction", arg0) +} + +// SetSlowStartLargeReduction indicates an expected call of SetSlowStartLargeReduction +func (mr *MockSendAlgorithmMockRecorder) SetSlowStartLargeReduction(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSlowStartLargeReduction", reflect.TypeOf((*MockSendAlgorithm)(nil).SetSlowStartLargeReduction), arg0) +} + +// TimeUntilSend mocks base method +func (m *MockSendAlgorithm) TimeUntilSend(arg0 protocol.ByteCount) time.Duration { + ret := m.ctrl.Call(m, "TimeUntilSend", arg0) + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// TimeUntilSend indicates an expected call of TimeUntilSend +func (mr *MockSendAlgorithmMockRecorder) TimeUntilSend(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TimeUntilSend", reflect.TypeOf((*MockSendAlgorithm)(nil).TimeUntilSend), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/connection_flow_controller.go b/vendor/lucas-clemente/quic-go/internal/mocks/connection_flow_controller.go new file mode 100644 index 00000000..1a47362b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/connection_flow_controller.go @@ -0,0 +1,112 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/flowcontrol (interfaces: ConnectionFlowController) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockConnectionFlowController is a mock of ConnectionFlowController interface +type MockConnectionFlowController struct { + ctrl *gomock.Controller + recorder *MockConnectionFlowControllerMockRecorder +} + +// MockConnectionFlowControllerMockRecorder is the mock recorder for MockConnectionFlowController +type MockConnectionFlowControllerMockRecorder struct { + mock *MockConnectionFlowController +} + +// NewMockConnectionFlowController creates a new mock instance +func NewMockConnectionFlowController(ctrl *gomock.Controller) *MockConnectionFlowController { + mock := &MockConnectionFlowController{ctrl: ctrl} + mock.recorder = &MockConnectionFlowControllerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockConnectionFlowController) EXPECT() *MockConnectionFlowControllerMockRecorder { + return m.recorder +} + +// AddBytesRead mocks base method +func (m *MockConnectionFlowController) AddBytesRead(arg0 protocol.ByteCount) { + m.ctrl.Call(m, "AddBytesRead", arg0) +} + +// AddBytesRead indicates an expected call of AddBytesRead +func (mr *MockConnectionFlowControllerMockRecorder) AddBytesRead(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBytesRead", reflect.TypeOf((*MockConnectionFlowController)(nil).AddBytesRead), arg0) +} + +// AddBytesSent mocks base method +func (m *MockConnectionFlowController) AddBytesSent(arg0 protocol.ByteCount) { + m.ctrl.Call(m, "AddBytesSent", arg0) +} + +// AddBytesSent indicates an expected call of AddBytesSent +func (mr *MockConnectionFlowControllerMockRecorder) AddBytesSent(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBytesSent", reflect.TypeOf((*MockConnectionFlowController)(nil).AddBytesSent), arg0) +} + +// GetWindowUpdate mocks base method +func (m *MockConnectionFlowController) GetWindowUpdate() protocol.ByteCount { + ret := m.ctrl.Call(m, "GetWindowUpdate") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// GetWindowUpdate indicates an expected call of GetWindowUpdate +func (mr *MockConnectionFlowControllerMockRecorder) GetWindowUpdate() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWindowUpdate", reflect.TypeOf((*MockConnectionFlowController)(nil).GetWindowUpdate)) +} + +// IsNewlyBlocked mocks base method +func (m *MockConnectionFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) { + ret := m.ctrl.Call(m, "IsNewlyBlocked") + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(protocol.ByteCount) + return ret0, ret1 +} + +// IsNewlyBlocked indicates an expected call of IsNewlyBlocked +func (mr *MockConnectionFlowControllerMockRecorder) IsNewlyBlocked() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNewlyBlocked", reflect.TypeOf((*MockConnectionFlowController)(nil).IsNewlyBlocked)) +} + +// MaybeQueueWindowUpdate mocks base method +func (m *MockConnectionFlowController) MaybeQueueWindowUpdate() { + m.ctrl.Call(m, "MaybeQueueWindowUpdate") +} + +// MaybeQueueWindowUpdate indicates an expected call of MaybeQueueWindowUpdate +func (mr *MockConnectionFlowControllerMockRecorder) MaybeQueueWindowUpdate() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaybeQueueWindowUpdate", reflect.TypeOf((*MockConnectionFlowController)(nil).MaybeQueueWindowUpdate)) +} + +// SendWindowSize mocks base method +func (m *MockConnectionFlowController) SendWindowSize() protocol.ByteCount { + ret := m.ctrl.Call(m, "SendWindowSize") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// SendWindowSize indicates an expected call of SendWindowSize +func (mr *MockConnectionFlowControllerMockRecorder) SendWindowSize() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendWindowSize", reflect.TypeOf((*MockConnectionFlowController)(nil).SendWindowSize)) +} + +// UpdateSendWindow mocks base method +func (m *MockConnectionFlowController) UpdateSendWindow(arg0 protocol.ByteCount) { + m.ctrl.Call(m, "UpdateSendWindow", arg0) +} + +// UpdateSendWindow indicates an expected call of UpdateSendWindow +func (mr *MockConnectionFlowControllerMockRecorder) UpdateSendWindow(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSendWindow", reflect.TypeOf((*MockConnectionFlowController)(nil).UpdateSendWindow), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/crypto/aead.go b/vendor/lucas-clemente/quic-go/internal/mocks/crypto/aead.go new file mode 100644 index 00000000..324a00ce --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/crypto/aead.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/crypto (interfaces: AEAD) + +// Package mockcrypto is a generated GoMock package. +package mockcrypto + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockAEAD is a mock of AEAD interface +type MockAEAD struct { + ctrl *gomock.Controller + recorder *MockAEADMockRecorder +} + +// MockAEADMockRecorder is the mock recorder for MockAEAD +type MockAEADMockRecorder struct { + mock *MockAEAD +} + +// NewMockAEAD creates a new mock instance +func NewMockAEAD(ctrl *gomock.Controller) *MockAEAD { + mock := &MockAEAD{ctrl: ctrl} + mock.recorder = &MockAEADMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAEAD) EXPECT() *MockAEADMockRecorder { + return m.recorder +} + +// Open mocks base method +func (m *MockAEAD) Open(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) ([]byte, error) { + ret := m.ctrl.Call(m, "Open", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Open indicates an expected call of Open +func (mr *MockAEADMockRecorder) Open(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockAEAD)(nil).Open), arg0, arg1, arg2, arg3) +} + +// Overhead mocks base method +func (m *MockAEAD) Overhead() int { + ret := m.ctrl.Call(m, "Overhead") + ret0, _ := ret[0].(int) + return ret0 +} + +// Overhead indicates an expected call of Overhead +func (mr *MockAEADMockRecorder) Overhead() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Overhead", reflect.TypeOf((*MockAEAD)(nil).Overhead)) +} + +// Seal mocks base method +func (m *MockAEAD) Seal(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) []byte { + ret := m.ctrl.Call(m, "Seal", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]byte) + return ret0 +} + +// Seal indicates an expected call of Seal +func (mr *MockAEADMockRecorder) Seal(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Seal", reflect.TypeOf((*MockAEAD)(nil).Seal), arg0, arg1, arg2, arg3) +} diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/mockgen.go b/vendor/lucas-clemente/quic-go/internal/mocks/mockgen.go new file mode 100644 index 00000000..5bfcdc22 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/mockgen.go @@ -0,0 +1,9 @@ +package mocks + +//go:generate sh -c "../mockgen_internal.sh mocks tls_extension_handler.go github.com/lucas-clemente/quic-go/internal/handshake TLSExtensionHandler" +//go:generate sh -c "../mockgen_internal.sh mocks stream_flow_controller.go github.com/lucas-clemente/quic-go/internal/flowcontrol StreamFlowController" +//go:generate sh -c "../mockgen_internal.sh mockackhandler ackhandler/sent_packet_handler.go github.com/lucas-clemente/quic-go/internal/ackhandler SentPacketHandler" +//go:generate sh -c "../mockgen_internal.sh mockackhandler ackhandler/received_packet_handler.go github.com/lucas-clemente/quic-go/internal/ackhandler ReceivedPacketHandler" +//go:generate sh -c "../mockgen_internal.sh mocks congestion.go github.com/lucas-clemente/quic-go/internal/congestion SendAlgorithm" +//go:generate sh -c "../mockgen_internal.sh mocks connection_flow_controller.go github.com/lucas-clemente/quic-go/internal/flowcontrol ConnectionFlowController" +//go:generate sh -c "../mockgen_internal.sh mockcrypto crypto/aead.go github.com/lucas-clemente/quic-go/internal/crypto AEAD" diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/stream_flow_controller.go b/vendor/lucas-clemente/quic-go/internal/mocks/stream_flow_controller.go new file mode 100644 index 00000000..955f5509 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/stream_flow_controller.go @@ -0,0 +1,124 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/flowcontrol (interfaces: StreamFlowController) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockStreamFlowController is a mock of StreamFlowController interface +type MockStreamFlowController struct { + ctrl *gomock.Controller + recorder *MockStreamFlowControllerMockRecorder +} + +// MockStreamFlowControllerMockRecorder is the mock recorder for MockStreamFlowController +type MockStreamFlowControllerMockRecorder struct { + mock *MockStreamFlowController +} + +// NewMockStreamFlowController creates a new mock instance +func NewMockStreamFlowController(ctrl *gomock.Controller) *MockStreamFlowController { + mock := &MockStreamFlowController{ctrl: ctrl} + mock.recorder = &MockStreamFlowControllerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStreamFlowController) EXPECT() *MockStreamFlowControllerMockRecorder { + return m.recorder +} + +// AddBytesRead mocks base method +func (m *MockStreamFlowController) AddBytesRead(arg0 protocol.ByteCount) { + m.ctrl.Call(m, "AddBytesRead", arg0) +} + +// AddBytesRead indicates an expected call of AddBytesRead +func (mr *MockStreamFlowControllerMockRecorder) AddBytesRead(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBytesRead", reflect.TypeOf((*MockStreamFlowController)(nil).AddBytesRead), arg0) +} + +// AddBytesSent mocks base method +func (m *MockStreamFlowController) AddBytesSent(arg0 protocol.ByteCount) { + m.ctrl.Call(m, "AddBytesSent", arg0) +} + +// AddBytesSent indicates an expected call of AddBytesSent +func (mr *MockStreamFlowControllerMockRecorder) AddBytesSent(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBytesSent", reflect.TypeOf((*MockStreamFlowController)(nil).AddBytesSent), arg0) +} + +// GetWindowUpdate mocks base method +func (m *MockStreamFlowController) GetWindowUpdate() protocol.ByteCount { + ret := m.ctrl.Call(m, "GetWindowUpdate") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// GetWindowUpdate indicates an expected call of GetWindowUpdate +func (mr *MockStreamFlowControllerMockRecorder) GetWindowUpdate() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWindowUpdate", reflect.TypeOf((*MockStreamFlowController)(nil).GetWindowUpdate)) +} + +// IsNewlyBlocked mocks base method +func (m *MockStreamFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) { + ret := m.ctrl.Call(m, "IsNewlyBlocked") + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(protocol.ByteCount) + return ret0, ret1 +} + +// IsNewlyBlocked indicates an expected call of IsNewlyBlocked +func (mr *MockStreamFlowControllerMockRecorder) IsNewlyBlocked() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNewlyBlocked", reflect.TypeOf((*MockStreamFlowController)(nil).IsNewlyBlocked)) +} + +// MaybeQueueWindowUpdate mocks base method +func (m *MockStreamFlowController) MaybeQueueWindowUpdate() { + m.ctrl.Call(m, "MaybeQueueWindowUpdate") +} + +// MaybeQueueWindowUpdate indicates an expected call of MaybeQueueWindowUpdate +func (mr *MockStreamFlowControllerMockRecorder) MaybeQueueWindowUpdate() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaybeQueueWindowUpdate", reflect.TypeOf((*MockStreamFlowController)(nil).MaybeQueueWindowUpdate)) +} + +// SendWindowSize mocks base method +func (m *MockStreamFlowController) SendWindowSize() protocol.ByteCount { + ret := m.ctrl.Call(m, "SendWindowSize") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// SendWindowSize indicates an expected call of SendWindowSize +func (mr *MockStreamFlowControllerMockRecorder) SendWindowSize() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendWindowSize", reflect.TypeOf((*MockStreamFlowController)(nil).SendWindowSize)) +} + +// UpdateHighestReceived mocks base method +func (m *MockStreamFlowController) UpdateHighestReceived(arg0 protocol.ByteCount, arg1 bool) error { + ret := m.ctrl.Call(m, "UpdateHighestReceived", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateHighestReceived indicates an expected call of UpdateHighestReceived +func (mr *MockStreamFlowControllerMockRecorder) UpdateHighestReceived(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateHighestReceived", reflect.TypeOf((*MockStreamFlowController)(nil).UpdateHighestReceived), arg0, arg1) +} + +// UpdateSendWindow mocks base method +func (m *MockStreamFlowController) UpdateSendWindow(arg0 protocol.ByteCount) { + m.ctrl.Call(m, "UpdateSendWindow", arg0) +} + +// UpdateSendWindow indicates an expected call of UpdateSendWindow +func (mr *MockStreamFlowControllerMockRecorder) UpdateSendWindow(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSendWindow", reflect.TypeOf((*MockStreamFlowController)(nil).UpdateSendWindow), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/internal/mocks/tls_extension_handler.go b/vendor/lucas-clemente/quic-go/internal/mocks/tls_extension_handler.go new file mode 100644 index 00000000..fcceee2e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/mocks/tls_extension_handler.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/handshake (interfaces: TLSExtensionHandler) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + mint "github.com/bifurcation/mint" + gomock "github.com/golang/mock/gomock" + handshake "github.com/lucas-clemente/quic-go/internal/handshake" +) + +// MockTLSExtensionHandler is a mock of TLSExtensionHandler interface +type MockTLSExtensionHandler struct { + ctrl *gomock.Controller + recorder *MockTLSExtensionHandlerMockRecorder +} + +// MockTLSExtensionHandlerMockRecorder is the mock recorder for MockTLSExtensionHandler +type MockTLSExtensionHandlerMockRecorder struct { + mock *MockTLSExtensionHandler +} + +// NewMockTLSExtensionHandler creates a new mock instance +func NewMockTLSExtensionHandler(ctrl *gomock.Controller) *MockTLSExtensionHandler { + mock := &MockTLSExtensionHandler{ctrl: ctrl} + mock.recorder = &MockTLSExtensionHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockTLSExtensionHandler) EXPECT() *MockTLSExtensionHandlerMockRecorder { + return m.recorder +} + +// GetPeerParams mocks base method +func (m *MockTLSExtensionHandler) GetPeerParams() <-chan handshake.TransportParameters { + ret := m.ctrl.Call(m, "GetPeerParams") + ret0, _ := ret[0].(<-chan handshake.TransportParameters) + return ret0 +} + +// GetPeerParams indicates an expected call of GetPeerParams +func (mr *MockTLSExtensionHandlerMockRecorder) GetPeerParams() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPeerParams", reflect.TypeOf((*MockTLSExtensionHandler)(nil).GetPeerParams)) +} + +// Receive mocks base method +func (m *MockTLSExtensionHandler) Receive(arg0 mint.HandshakeType, arg1 *mint.ExtensionList) error { + ret := m.ctrl.Call(m, "Receive", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Receive indicates an expected call of Receive +func (mr *MockTLSExtensionHandlerMockRecorder) Receive(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Receive", reflect.TypeOf((*MockTLSExtensionHandler)(nil).Receive), arg0, arg1) +} + +// Send mocks base method +func (m *MockTLSExtensionHandler) Send(arg0 mint.HandshakeType, arg1 *mint.ExtensionList) error { + ret := m.ctrl.Call(m, "Send", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Send indicates an expected call of Send +func (mr *MockTLSExtensionHandlerMockRecorder) Send(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockTLSExtensionHandler)(nil).Send), arg0, arg1) +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/connection_id.go b/vendor/lucas-clemente/quic-go/internal/protocol/connection_id.go new file mode 100644 index 00000000..f99461b2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/connection_id.go @@ -0,0 +1,69 @@ +package protocol + +import ( + "bytes" + "crypto/rand" + "fmt" + "io" +) + +// A ConnectionID in QUIC +type ConnectionID []byte + +const maxConnectionIDLen = 18 + +// GenerateConnectionID generates a connection ID using cryptographic random +func GenerateConnectionID(len int) (ConnectionID, error) { + b := make([]byte, len) + if _, err := rand.Read(b); err != nil { + return nil, err + } + return ConnectionID(b), nil +} + +// GenerateConnectionIDForInitial generates a connection ID for the Initial packet. +// It uses a length randomly chosen between 8 and 18 bytes. +func GenerateConnectionIDForInitial() (ConnectionID, error) { + r := make([]byte, 1) + if _, err := rand.Read(r); err != nil { + return nil, err + } + len := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1) + return GenerateConnectionID(len) +} + +// ReadConnectionID reads a connection ID of length len from the given io.Reader. +// It returns io.EOF if there are not enough bytes to read. +func ReadConnectionID(r io.Reader, len int) (ConnectionID, error) { + if len == 0 { + return nil, nil + } + c := make(ConnectionID, len) + _, err := io.ReadFull(r, c) + if err == io.ErrUnexpectedEOF { + return nil, io.EOF + } + return c, err +} + +// Equal says if two connection IDs are equal +func (c ConnectionID) Equal(other ConnectionID) bool { + return bytes.Equal(c, other) +} + +// Len returns the length of the connection ID in bytes +func (c ConnectionID) Len() int { + return len(c) +} + +// Bytes returns the byte representation +func (c ConnectionID) Bytes() []byte { + return []byte(c) +} + +func (c ConnectionID) String() string { + if c.Len() == 0 { + return "(empty)" + } + return fmt.Sprintf("%#x", c.Bytes()) +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/connection_id_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/connection_id_test.go new file mode 100644 index 00000000..f0c7f7cc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/connection_id_test.go @@ -0,0 +1,108 @@ +package protocol + +import ( + "bytes" + "io" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Connection ID generation", func() { + It("generates random connection IDs", func() { + c1, err := GenerateConnectionID(8) + Expect(err).ToNot(HaveOccurred()) + Expect(c1).ToNot(BeZero()) + c2, err := GenerateConnectionID(8) + Expect(err).ToNot(HaveOccurred()) + Expect(c1).ToNot(Equal(c2)) + }) + + It("generates connection IDs with the requested length", func() { + c, err := GenerateConnectionID(5) + Expect(err).ToNot(HaveOccurred()) + Expect(c.Len()).To(Equal(5)) + }) + + It("generates random length destination connection IDs", func() { + var has8ByteConnID, has18ByteConnID bool + for i := 0; i < 1000; i++ { + c, err := GenerateConnectionIDForInitial() + Expect(err).ToNot(HaveOccurred()) + Expect(c.Len()).To(BeNumerically(">=", 8)) + Expect(c.Len()).To(BeNumerically("<=", 18)) + if c.Len() == 8 { + has8ByteConnID = true + } + if c.Len() == 18 { + has18ByteConnID = true + } + } + Expect(has8ByteConnID).To(BeTrue()) + Expect(has18ByteConnID).To(BeTrue()) + }) + + It("says if connection IDs are equal", func() { + c1 := ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + c2 := ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + Expect(c1.Equal(c1)).To(BeTrue()) + Expect(c2.Equal(c2)).To(BeTrue()) + Expect(c1.Equal(c2)).To(BeFalse()) + Expect(c2.Equal(c1)).To(BeFalse()) + }) + + It("reads the connection ID", func() { + buf := bytes.NewBuffer([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}) + c, err := ReadConnectionID(buf, 9) + Expect(err).ToNot(HaveOccurred()) + Expect(c.Bytes()).To(Equal([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9})) + }) + + It("returns io.EOF if there's not enough data to read", func() { + buf := bytes.NewBuffer([]byte{1, 2, 3, 4}) + _, err := ReadConnectionID(buf, 5) + Expect(err).To(MatchError(io.EOF)) + }) + + It("returns nil for a 0 length connection ID", func() { + buf := bytes.NewBuffer([]byte{1, 2, 3, 4}) + c, err := ReadConnectionID(buf, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(c).To(BeNil()) + }) + + It("returns the length", func() { + c := ConnectionID{1, 2, 3, 4, 5, 6, 7} + Expect(c.Len()).To(Equal(7)) + }) + + It("has 0 length for the default value", func() { + var c ConnectionID + Expect(c.Len()).To(BeZero()) + }) + + It("returns the bytes", func() { + c := ConnectionID([]byte{1, 2, 3, 4, 5, 6, 7}) + Expect(c.Bytes()).To(Equal([]byte{1, 2, 3, 4, 5, 6, 7})) + }) + + It("returns a nil byte slice for the default value", func() { + var c ConnectionID + Expect(c.Bytes()).To(BeNil()) + }) + + It("has a string representation", func() { + c := ConnectionID([]byte{0xde, 0xad, 0xbe, 0xef, 0x42}) + Expect(c.String()).To(Equal("0xdeadbeef42")) + }) + + It("has a long string representation", func() { + c := ConnectionID{0x13, 0x37, 0, 0, 0xde, 0xca, 0xfb, 0xad} + Expect(c.String()).To(Equal("0x13370000decafbad")) + }) + + It("has a string representation for the default value", func() { + var c ConnectionID + Expect(c.String()).To(Equal("(empty)")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/encryption_level.go b/vendor/lucas-clemente/quic-go/internal/protocol/encryption_level.go new file mode 100644 index 00000000..19480b12 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/encryption_level.go @@ -0,0 +1,28 @@ +package protocol + +// EncryptionLevel is the encryption level +// Default value is Unencrypted +type EncryptionLevel int + +const ( + // EncryptionUnspecified is a not specified encryption level + EncryptionUnspecified EncryptionLevel = iota + // EncryptionUnencrypted is not encrypted + EncryptionUnencrypted + // EncryptionSecure is encrypted, but not forward secure + EncryptionSecure + // EncryptionForwardSecure is forward secure + EncryptionForwardSecure +) + +func (e EncryptionLevel) String() string { + switch e { + case EncryptionUnencrypted: + return "unencrypted" + case EncryptionSecure: + return "encrypted (not forward-secure)" + case EncryptionForwardSecure: + return "forward-secure" + } + return "unknown" +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/encryption_level_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/encryption_level_test.go new file mode 100644 index 00000000..12a40d06 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/encryption_level_test.go @@ -0,0 +1,15 @@ +package protocol + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Encryption Level", func() { + It("has the correct string representation", func() { + Expect(EncryptionUnspecified.String()).To(Equal("unknown")) + Expect(EncryptionUnencrypted.String()).To(Equal("unencrypted")) + Expect(EncryptionSecure.String()).To(Equal("encrypted (not forward-secure)")) + Expect(EncryptionForwardSecure.String()).To(Equal("forward-secure")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/packet_number.go b/vendor/lucas-clemente/quic-go/internal/protocol/packet_number.go new file mode 100644 index 00000000..41f002f5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/packet_number.go @@ -0,0 +1,70 @@ +package protocol + +// InferPacketNumber calculates the packet number based on the received packet number, its length and the last seen packet number +func InferPacketNumber( + packetNumberLength PacketNumberLen, + lastPacketNumber PacketNumber, + wirePacketNumber PacketNumber, + version VersionNumber, +) PacketNumber { + var epochDelta PacketNumber + if version.UsesVarintPacketNumbers() { + switch packetNumberLength { + case PacketNumberLen1: + epochDelta = PacketNumber(1) << 7 + case PacketNumberLen2: + epochDelta = PacketNumber(1) << 14 + case PacketNumberLen4: + epochDelta = PacketNumber(1) << 30 + } + } else { + epochDelta = PacketNumber(1) << (uint8(packetNumberLength) * 8) + } + epoch := lastPacketNumber & ^(epochDelta - 1) + prevEpochBegin := epoch - epochDelta + nextEpochBegin := epoch + epochDelta + return closestTo( + lastPacketNumber+1, + epoch+wirePacketNumber, + closestTo(lastPacketNumber+1, prevEpochBegin+wirePacketNumber, nextEpochBegin+wirePacketNumber), + ) +} + +func closestTo(target, a, b PacketNumber) PacketNumber { + if delta(target, a) < delta(target, b) { + return a + } + return b +} + +func delta(a, b PacketNumber) PacketNumber { + if a < b { + return b - a + } + return a - b +} + +// GetPacketNumberLengthForHeader gets the length of the packet number for the public header +// it never chooses a PacketNumberLen of 1 byte, since this is too short under certain circumstances +func GetPacketNumberLengthForHeader(packetNumber, leastUnacked PacketNumber, version VersionNumber) PacketNumberLen { + diff := uint64(packetNumber - leastUnacked) + if version.UsesVarintPacketNumbers() && diff < (1<<(14-1)) || + !version.UsesVarintPacketNumbers() && diff < (1<<(16-1)) { + return PacketNumberLen2 + } + return PacketNumberLen4 +} + +// GetPacketNumberLength gets the minimum length needed to fully represent the packet number +func GetPacketNumberLength(packetNumber PacketNumber) PacketNumberLen { + if packetNumber < (1 << (uint8(PacketNumberLen1) * 8)) { + return PacketNumberLen1 + } + if packetNumber < (1 << (uint8(PacketNumberLen2) * 8)) { + return PacketNumberLen2 + } + if packetNumber < (1 << (uint8(PacketNumberLen4) * 8)) { + return PacketNumberLen4 + } + return PacketNumberLen6 +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/packet_number_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/packet_number_test.go new file mode 100644 index 00000000..ef5a5e9b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/packet_number_test.go @@ -0,0 +1,244 @@ +package protocol + +import ( + "fmt" + "math" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +// Tests taken and extended from chrome +var _ = Describe("packet number calculation", func() { + Context("infering a packet number", func() { + getEpoch := func(len PacketNumberLen, v VersionNumber) uint64 { + if v.UsesVarintPacketNumbers() { + switch len { + case PacketNumberLen1: + return uint64(1) << 7 + case PacketNumberLen2: + return uint64(1) << 14 + case PacketNumberLen4: + return uint64(1) << 30 + default: + Fail("invalid packet number len") + } + } + return uint64(1) << (len * 8) + } + check := func(length PacketNumberLen, expected, last uint64, v VersionNumber) { + epoch := getEpoch(length, v) + epochMask := epoch - 1 + wirePacketNumber := expected & epochMask + Expect(InferPacketNumber(length, PacketNumber(last), PacketNumber(wirePacketNumber), v)).To(Equal(PacketNumber(expected))) + } + + for _, v := range []VersionNumber{Version39, VersionTLS} { + version := v + + Context(fmt.Sprintf("using varint packet numbers: %t", version.UsesVarintPacketNumbers()), func() { + for _, l := range []PacketNumberLen{PacketNumberLen1, PacketNumberLen2, PacketNumberLen4} { + length := l + + Context(fmt.Sprintf("with %d bytes", length), func() { + epoch := getEpoch(length, version) + epochMask := epoch - 1 + + It("works near epoch start", func() { + // A few quick manual sanity check + check(length, 1, 0, version) + check(length, epoch+1, epochMask, version) + check(length, epoch, epochMask, version) + + // Cases where the last number was close to the start of the range. + for last := uint64(0); last < 10; last++ { + // Small numbers should not wrap (even if they're out of order). + for j := uint64(0); j < 10; j++ { + check(length, j, last, version) + } + + // Large numbers should not wrap either (because we're near 0 already). + for j := uint64(0); j < 10; j++ { + check(length, epoch-1-j, last, version) + } + } + }) + + It("works near epoch end", func() { + // Cases where the last number was close to the end of the range + for i := uint64(0); i < 10; i++ { + last := epoch - i + + // Small numbers should wrap. + for j := uint64(0); j < 10; j++ { + check(length, epoch+j, last, version) + } + + // Large numbers should not (even if they're out of order). + for j := uint64(0); j < 10; j++ { + check(length, epoch-1-j, last, version) + } + } + }) + + // Next check where we're in a non-zero epoch to verify we handle + // reverse wrapping, too. + It("works near previous epoch", func() { + prevEpoch := 1 * epoch + curEpoch := 2 * epoch + // Cases where the last number was close to the start of the range + for i := uint64(0); i < 10; i++ { + last := curEpoch + i + // Small number should not wrap (even if they're out of order). + for j := uint64(0); j < 10; j++ { + check(length, curEpoch+j, last, version) + } + + // But large numbers should reverse wrap. + for j := uint64(0); j < 10; j++ { + num := epoch - 1 - j + check(length, prevEpoch+num, last, version) + } + } + }) + + It("works near next epoch", func() { + curEpoch := 2 * epoch + nextEpoch := 3 * epoch + // Cases where the last number was close to the end of the range + for i := uint64(0); i < 10; i++ { + last := nextEpoch - 1 - i + + // Small numbers should wrap. + for j := uint64(0); j < 10; j++ { + check(length, nextEpoch+j, last, version) + } + + // but large numbers should not (even if they're out of order). + for j := uint64(0); j < 10; j++ { + num := epoch - 1 - j + check(length, curEpoch+num, last, version) + } + } + }) + + It("works near next max", func() { + maxNumber := uint64(math.MaxUint64) + maxEpoch := maxNumber & ^epochMask + + // Cases where the last number was close to the end of the range + for i := uint64(0); i < 10; i++ { + // Subtract 1, because the expected next packet number is 1 more than the + // last packet number. + last := maxNumber - i - 1 + + // Small numbers should not wrap, because they have nowhere to go. + for j := uint64(0); j < 10; j++ { + check(length, maxEpoch+j, last, version) + } + + // Large numbers should not wrap either. + for j := uint64(0); j < 10; j++ { + num := epoch - 1 - j + check(length, maxEpoch+num, last, version) + } + } + }) + }) + } + + Context("shortening a packet number for the header", func() { + Context("shortening", func() { + It("sends out low packet numbers as 2 byte", func() { + length := GetPacketNumberLengthForHeader(4, 2, version) + Expect(length).To(Equal(PacketNumberLen2)) + }) + + It("sends out high packet numbers as 2 byte, if all ACKs are received", func() { + length := GetPacketNumberLengthForHeader(0xdeadbeef, 0xdeadbeef-1, version) + Expect(length).To(Equal(PacketNumberLen2)) + }) + + It("sends out higher packet numbers as 4 bytes, if a lot of ACKs are missing", func() { + length := GetPacketNumberLengthForHeader(40000, 2, version) + Expect(length).To(Equal(PacketNumberLen4)) + }) + }) + + Context("self-consistency", func() { + It("works for small packet numbers", func() { + for i := uint64(1); i < 10000; i++ { + packetNumber := PacketNumber(i) + leastUnacked := PacketNumber(1) + length := GetPacketNumberLengthForHeader(packetNumber, leastUnacked, version) + wirePacketNumber := (uint64(packetNumber) << (64 - length*8)) >> (64 - length*8) + + inferedPacketNumber := InferPacketNumber(length, leastUnacked, PacketNumber(wirePacketNumber), version) + Expect(inferedPacketNumber).To(Equal(packetNumber)) + } + }) + + It("works for small packet numbers and increasing ACKed packets", func() { + for i := uint64(1); i < 10000; i++ { + packetNumber := PacketNumber(i) + leastUnacked := PacketNumber(i / 2) + length := GetPacketNumberLengthForHeader(packetNumber, leastUnacked, version) + epochMask := getEpoch(length, version) - 1 + wirePacketNumber := uint64(packetNumber) & epochMask + + inferedPacketNumber := InferPacketNumber(length, leastUnacked, PacketNumber(wirePacketNumber), version) + Expect(inferedPacketNumber).To(Equal(packetNumber)) + } + }) + + It("also works for larger packet numbers", func() { + var increment uint64 + for i := uint64(1); i < getEpoch(PacketNumberLen4, version); i += increment { + packetNumber := PacketNumber(i) + leastUnacked := PacketNumber(1) + length := GetPacketNumberLengthForHeader(packetNumber, leastUnacked, version) + epochMask := getEpoch(length, version) - 1 + wirePacketNumber := uint64(packetNumber) & epochMask + + inferedPacketNumber := InferPacketNumber(length, leastUnacked, PacketNumber(wirePacketNumber), version) + Expect(inferedPacketNumber).To(Equal(packetNumber)) + + increment = getEpoch(length, version) / 8 + } + }) + + It("works for packet numbers larger than 2^48", func() { + for i := (uint64(1) << 48); i < ((uint64(1) << 63) - 1); i += (uint64(1) << 48) { + packetNumber := PacketNumber(i) + leastUnacked := PacketNumber(i - 1000) + length := GetPacketNumberLengthForHeader(packetNumber, leastUnacked, version) + wirePacketNumber := (uint64(packetNumber) << (64 - length*8)) >> (64 - length*8) + + inferedPacketNumber := InferPacketNumber(length, leastUnacked, PacketNumber(wirePacketNumber), version) + Expect(inferedPacketNumber).To(Equal(packetNumber)) + } + }) + }) + }) + }) + } + }) + + Context("determining the minimum length of a packet number", func() { + It("1 byte", func() { + Expect(GetPacketNumberLength(0xFF)).To(Equal(PacketNumberLen1)) + }) + + It("2 byte", func() { + Expect(GetPacketNumberLength(0xFFFF)).To(Equal(PacketNumberLen2)) + }) + + It("4 byte", func() { + Expect(GetPacketNumberLength(0xFFFFFFFF)).To(Equal(PacketNumberLen4)) + }) + + It("6 byte", func() { + Expect(GetPacketNumberLength(0xFFFFFFFFFFFF)).To(Equal(PacketNumberLen6)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/perspective.go b/vendor/lucas-clemente/quic-go/internal/protocol/perspective.go new file mode 100644 index 00000000..43358fec --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/perspective.go @@ -0,0 +1,26 @@ +package protocol + +// Perspective determines if we're acting as a server or a client +type Perspective int + +// the perspectives +const ( + PerspectiveServer Perspective = 1 + PerspectiveClient Perspective = 2 +) + +// Opposite returns the perspective of the peer +func (p Perspective) Opposite() Perspective { + return 3 - p +} + +func (p Perspective) String() string { + switch p { + case PerspectiveServer: + return "Server" + case PerspectiveClient: + return "Client" + default: + return "invalid perspective" + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/perspective_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/perspective_test.go new file mode 100644 index 00000000..0ae23d7c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/perspective_test.go @@ -0,0 +1,19 @@ +package protocol + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Perspective", func() { + It("has a string representation", func() { + Expect(PerspectiveClient.String()).To(Equal("Client")) + Expect(PerspectiveServer.String()).To(Equal("Server")) + Expect(Perspective(0).String()).To(Equal("invalid perspective")) + }) + + It("returns the opposite", func() { + Expect(PerspectiveClient.Opposite()).To(Equal(PerspectiveServer)) + Expect(PerspectiveServer.Opposite()).To(Equal(PerspectiveClient)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/protocol.go b/vendor/lucas-clemente/quic-go/internal/protocol/protocol.go new file mode 100644 index 00000000..2a52f895 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/protocol.go @@ -0,0 +1,90 @@ +package protocol + +import ( + "fmt" +) + +// A PacketNumber in QUIC +type PacketNumber uint64 + +// PacketNumberLen is the length of the packet number in bytes +type PacketNumberLen uint8 + +const ( + // PacketNumberLenInvalid is the default value and not a valid length for a packet number + PacketNumberLenInvalid PacketNumberLen = 0 + // PacketNumberLen1 is a packet number length of 1 byte + PacketNumberLen1 PacketNumberLen = 1 + // PacketNumberLen2 is a packet number length of 2 bytes + PacketNumberLen2 PacketNumberLen = 2 + // PacketNumberLen4 is a packet number length of 4 bytes + PacketNumberLen4 PacketNumberLen = 4 + // PacketNumberLen6 is a packet number length of 6 bytes + PacketNumberLen6 PacketNumberLen = 6 +) + +// The PacketType is the Long Header Type (only used for the IETF draft header format) +type PacketType uint8 + +const ( + // PacketTypeInitial is the packet type of an Initial packet + PacketTypeInitial PacketType = 0x7f + // PacketTypeRetry is the packet type of a Retry packet + PacketTypeRetry PacketType = 0x7e + // PacketTypeHandshake is the packet type of a Handshake packet + PacketTypeHandshake PacketType = 0x7d + // PacketType0RTT is the packet type of a 0-RTT packet + PacketType0RTT PacketType = 0x7c +) + +func (t PacketType) String() string { + switch t { + case PacketTypeInitial: + return "Initial" + case PacketTypeRetry: + return "Retry" + case PacketTypeHandshake: + return "Handshake" + case PacketType0RTT: + return "0-RTT Protected" + default: + return fmt.Sprintf("unknown packet type: %d", t) + } +} + +// A ByteCount in QUIC +type ByteCount uint64 + +// MaxByteCount is the maximum value of a ByteCount +const MaxByteCount = ByteCount(1<<62 - 1) + +// An ApplicationErrorCode is an application-defined error code. +type ApplicationErrorCode uint16 + +// MaxReceivePacketSize maximum packet size of any QUIC packet, based on +// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header, +// UDP adds an additional 8 bytes. This is a total overhead of 48 bytes. +// Ethernet's max packet size is 1500 bytes, 1500 - 48 = 1452. +const MaxReceivePacketSize ByteCount = 1452 + +// DefaultTCPMSS is the default maximum packet size used in the Linux TCP implementation. +// Used in QUIC for congestion window computations in bytes. +const DefaultTCPMSS ByteCount = 1460 + +// MinClientHelloSize is the minimum size the server expects an inchoate CHLO to have (in gQUIC) +const MinClientHelloSize = 1024 + +// MinInitialPacketSize is the minimum size an Initial packet (in IETF QUIC) is required to have. +const MinInitialPacketSize = 1200 + +// MaxClientHellos is the maximum number of times we'll send a client hello +// The value 3 accounts for: +// * one failure due to an incorrect or missing source-address token +// * one failure due the server's certificate chain being unavailable and the server being unwilling to send it without a valid source-address token +const MaxClientHellos = 3 + +// ConnectionIDLenGQUIC is the length of the source Connection ID used on gQUIC QUIC packets. +const ConnectionIDLenGQUIC = 8 + +// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet. +const MinConnectionIDLenInitial = 8 diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/protocol_suite_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/protocol_suite_test.go new file mode 100644 index 00000000..204a3680 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/protocol_suite_test.go @@ -0,0 +1,13 @@ +package protocol + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestProtocol(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Protocol Suite") +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/protocol_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/protocol_test.go new file mode 100644 index 00000000..a89f732f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/protocol_test.go @@ -0,0 +1,18 @@ +package protocol + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Protocol", func() { + Context("Long Header Packet Types", func() { + It("has the correct string representation", func() { + Expect(PacketTypeInitial.String()).To(Equal("Initial")) + Expect(PacketTypeRetry.String()).To(Equal("Retry")) + Expect(PacketTypeHandshake.String()).To(Equal("Handshake")) + Expect(PacketType0RTT.String()).To(Equal("0-RTT Protected")) + Expect(PacketType(10).String()).To(Equal("unknown packet type: 10")) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/server_parameters.go b/vendor/lucas-clemente/quic-go/internal/protocol/server_parameters.go new file mode 100644 index 00000000..aa61b3d7 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/server_parameters.go @@ -0,0 +1,154 @@ +package protocol + +import "time" + +// MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets. +const MaxPacketSizeIPv4 = 1252 + +// MaxPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets. +const MaxPacketSizeIPv6 = 1232 + +// NonForwardSecurePacketSizeReduction is the number of bytes a non forward-secure packet has to be smaller than a forward-secure packet +// This makes sure that those packets can always be retransmitted without splitting the contained StreamFrames +const NonForwardSecurePacketSizeReduction = 50 + +const defaultMaxCongestionWindowPackets = 1000 + +// DefaultMaxCongestionWindow is the default for the max congestion window +const DefaultMaxCongestionWindow ByteCount = defaultMaxCongestionWindowPackets * DefaultTCPMSS + +// InitialCongestionWindow is the initial congestion window in QUIC packets +const InitialCongestionWindow ByteCount = 32 * DefaultTCPMSS + +// MaxUndecryptablePackets limits the number of undecryptable packets that a +// session queues for later until it sends a public reset. +const MaxUndecryptablePackets = 10 + +// PublicResetTimeout is the time to wait before sending a Public Reset when receiving too many undecryptable packets during the handshake +// This timeout allows the Go scheduler to switch to the Go rountine that reads the crypto stream and to escalate the crypto +const PublicResetTimeout = 500 * time.Millisecond + +// ReceiveStreamFlowControlWindow is the stream-level flow control window for receiving data +// This is the value that Google servers are using +const ReceiveStreamFlowControlWindow = (1 << 10) * 32 // 32 kB + +// ReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data +// This is the value that Google servers are using +const ReceiveConnectionFlowControlWindow = (1 << 10) * 48 // 48 kB + +// DefaultMaxReceiveStreamFlowControlWindowServer is the default maximum stream-level flow control window for receiving data, for the server +// This is the value that Google servers are using +const DefaultMaxReceiveStreamFlowControlWindowServer = 1 * (1 << 20) // 1 MB + +// DefaultMaxReceiveConnectionFlowControlWindowServer is the default connection-level flow control window for receiving data, for the server +// This is the value that Google servers are using +const DefaultMaxReceiveConnectionFlowControlWindowServer = 1.5 * (1 << 20) // 1.5 MB + +// DefaultMaxReceiveStreamFlowControlWindowClient is the default maximum stream-level flow control window for receiving data, for the client +// This is the value that Chromium is using +const DefaultMaxReceiveStreamFlowControlWindowClient = 6 * (1 << 20) // 6 MB + +// DefaultMaxReceiveConnectionFlowControlWindowClient is the default connection-level flow control window for receiving data, for the client +// This is the value that Google servers are using +const DefaultMaxReceiveConnectionFlowControlWindowClient = 15 * (1 << 20) // 15 MB + +// ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window +// This is the value that Chromium is using +const ConnectionFlowControlMultiplier = 1.5 + +// WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client +const WindowUpdateThreshold = 0.25 + +// DefaultMaxIncomingStreams is the maximum number of streams that a peer may open +const DefaultMaxIncomingStreams = 100 + +// DefaultMaxIncomingUniStreams is the maximum number of unidirectional streams that a peer may open +const DefaultMaxIncomingUniStreams = 100 + +// MaxStreamsMultiplier is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this procentual increase and the absolute increment specified by MaxStreamsMinimumIncrement is used. +const MaxStreamsMultiplier = 1.1 + +// MaxStreamsMinimumIncrement is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this absolute increment and the procentual increase specified by MaxStreamsMultiplier is used. +const MaxStreamsMinimumIncrement = 10 + +// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed. +const MaxSessionUnprocessedPackets = defaultMaxCongestionWindowPackets + +// SkipPacketAveragePeriodLength is the average period length in which one packet number is skipped to prevent an Optimistic ACK attack +const SkipPacketAveragePeriodLength PacketNumber = 500 + +// MaxTrackedSkippedPackets is the maximum number of skipped packet numbers the SentPacketHandler keep track of for Optimistic ACK attack mitigation +const MaxTrackedSkippedPackets = 10 + +// CookieExpiryTime is the valid time of a cookie +const CookieExpiryTime = 24 * time.Hour + +// MaxOutstandingSentPackets is maximum number of packets saved for retransmission. +// When reached, it imposes a soft limit on sending new packets: +// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent. +const MaxOutstandingSentPackets = 2 * defaultMaxCongestionWindowPackets + +// MaxTrackedSentPackets is maximum number of sent packets saved for retransmission. +// When reached, no more packets will be sent. +// This value *must* be larger than MaxOutstandingSentPackets. +const MaxTrackedSentPackets = MaxOutstandingSentPackets * 5 / 4 + +// MaxTrackedReceivedAckRanges is the maximum number of ACK ranges tracked +const MaxTrackedReceivedAckRanges = defaultMaxCongestionWindowPackets + +// MaxNonRetransmittableAcks is the maximum number of packets containing an ACK, but no retransmittable frames, that we send in a row +const MaxNonRetransmittableAcks = 19 + +// MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames +// prevents DoS attacks against the streamFrameSorter +const MaxStreamFrameSorterGaps = 1000 + +// CryptoMaxParams is the upper limit for the number of parameters in a crypto message. +// Value taken from Chrome. +const CryptoMaxParams = 128 + +// CryptoParameterMaxLength is the upper limit for the length of a parameter in a crypto message. +const CryptoParameterMaxLength = 4000 + +// EphermalKeyLifetime is the lifetime of the ephermal key during the handshake, see handshake.getEphermalKEX. +const EphermalKeyLifetime = time.Minute + +// MinRemoteIdleTimeout is the minimum value that we accept for the remote idle timeout +const MinRemoteIdleTimeout = 5 * time.Second + +// DefaultIdleTimeout is the default idle timeout +const DefaultIdleTimeout = 30 * time.Second + +// DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds. +const DefaultHandshakeTimeout = 10 * time.Second + +// ClosedSessionDeleteTimeout the server ignores packets arriving on a connection that is already closed +// after this time all information about the old connection will be deleted +const ClosedSessionDeleteTimeout = time.Minute + +// NumCachedCertificates is the number of cached compressed certificate chains, each taking ~1K space +const NumCachedCertificates = 128 + +// MinStreamFrameSize is the minimum size that has to be left in a packet, so that we add another STREAM frame. +// This avoids splitting up STREAM frames into small pieces, which has 2 advantages: +// 1. it reduces the framing overhead +// 2. it reduces the head-of-line blocking, when a packet is lost +const MinStreamFrameSize ByteCount = 128 + +// MaxAckFrameSize is the maximum size for an (IETF QUIC) ACK frame that we write +// Due to the varint encoding, ACK frames can grow (almost) indefinitely large. +// The MaxAckFrameSize should be large enough to encode many ACK range, +// but must ensure that a maximum size ACK frame fits into one packet. +const MaxAckFrameSize ByteCount = 1000 + +// MinPacingDelay is the minimum duration that is used for packet pacing +// If the packet packing frequency is higher, multiple packets might be sent at once. +// Example: For a packet pacing delay of 20 microseconds, we would send 5 packets at once, wait for 100 microseconds, and so forth. +const MinPacingDelay time.Duration = 100 * time.Microsecond + +// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections +// if no other value is configured. +const DefaultConnectionIDLength = 4 + +// MaxRetries is the maximum number of Retries a client will do before failing the connection. +const MaxRetries = 3 diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/stream_id.go b/vendor/lucas-clemente/quic-go/internal/protocol/stream_id.go new file mode 100644 index 00000000..a0dced0c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/stream_id.go @@ -0,0 +1,36 @@ +package protocol + +// A StreamID in QUIC +type StreamID uint64 + +// MaxBidiStreamID is the highest stream ID that the peer is allowed to open, +// when it is allowed to open numStreams bidirectional streams. +// It is only valid for IETF QUIC. +func MaxBidiStreamID(numStreams int, pers Perspective) StreamID { + if numStreams == 0 { + return 0 + } + var first StreamID + if pers == PerspectiveClient { + first = 1 + } else { + first = 4 + } + return first + 4*StreamID(numStreams-1) +} + +// MaxUniStreamID is the highest stream ID that the peer is allowed to open, +// when it is allowed to open numStreams unidirectional streams. +// It is only valid for IETF QUIC. +func MaxUniStreamID(numStreams int, pers Perspective) StreamID { + if numStreams == 0 { + return 0 + } + var first StreamID + if pers == PerspectiveClient { + first = 3 + } else { + first = 2 + } + return first + 4*StreamID(numStreams-1) +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/stream_id_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/stream_id_test.go new file mode 100644 index 00000000..cca4f928 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/stream_id_test.go @@ -0,0 +1,42 @@ +package protocol + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Stream ID", func() { + Context("bidirectional streams", func() { + It("doesn't allow any", func() { + Expect(MaxBidiStreamID(0, PerspectiveClient)).To(Equal(StreamID(0))) + Expect(MaxBidiStreamID(0, PerspectiveServer)).To(Equal(StreamID(0))) + }) + + It("allows one", func() { + Expect(MaxBidiStreamID(1, PerspectiveClient)).To(Equal(StreamID(1))) + Expect(MaxBidiStreamID(1, PerspectiveServer)).To(Equal(StreamID(4))) + }) + + It("allows many", func() { + Expect(MaxBidiStreamID(100, PerspectiveClient)).To(Equal(StreamID(397))) + Expect(MaxBidiStreamID(100, PerspectiveServer)).To(Equal(StreamID(400))) + }) + }) + + Context("unidirectional streams", func() { + It("doesn't allow any", func() { + Expect(MaxUniStreamID(0, PerspectiveClient)).To(Equal(StreamID(0))) + Expect(MaxUniStreamID(0, PerspectiveServer)).To(Equal(StreamID(0))) + }) + + It("allows one", func() { + Expect(MaxUniStreamID(1, PerspectiveClient)).To(Equal(StreamID(3))) + Expect(MaxUniStreamID(1, PerspectiveServer)).To(Equal(StreamID(2))) + }) + + It("allows many", func() { + Expect(MaxUniStreamID(100, PerspectiveClient)).To(Equal(StreamID(399))) + Expect(MaxUniStreamID(100, PerspectiveServer)).To(Equal(StreamID(398))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/version.go b/vendor/lucas-clemente/quic-go/internal/protocol/version.go new file mode 100644 index 00000000..9e1963dc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/version.go @@ -0,0 +1,185 @@ +package protocol + +import ( + "crypto/rand" + "encoding/binary" + "fmt" + "math" +) + +// VersionNumber is a version number as int +type VersionNumber uint32 + +// gQUIC version range as defined in the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions +const ( + gquicVersion0 = 0x51303030 + maxGquicVersion = 0x51303439 +) + +// The version numbers, making grepping easier +const ( + Version39 VersionNumber = gquicVersion0 + 3*0x100 + 0x9 + Version43 VersionNumber = gquicVersion0 + 4*0x100 + 0x3 + Version44 VersionNumber = gquicVersion0 + 4*0x100 + 0x4 + VersionTLS VersionNumber = 101 + VersionWhatever VersionNumber = 0 // for when the version doesn't matter + VersionUnknown VersionNumber = math.MaxUint32 + + VersionMilestone0_10_0 VersionNumber = 0x51474f02 +) + +// SupportedVersions lists the versions that the server supports +// must be in sorted descending order +var SupportedVersions = []VersionNumber{ + Version44, + Version43, + Version39, +} + +// IsValidVersion says if the version is known to quic-go +func IsValidVersion(v VersionNumber) bool { + return v == VersionTLS || v == VersionMilestone0_10_0 || IsSupportedVersion(SupportedVersions, v) +} + +// UsesTLS says if this QUIC version uses TLS 1.3 for the handshake +func (vn VersionNumber) UsesTLS() bool { + return !vn.isGQUIC() +} + +func (vn VersionNumber) String() string { + switch vn { + case VersionWhatever: + return "whatever" + case VersionUnknown: + return "unknown" + case VersionMilestone0_10_0: + return "quic-go Milestone 0.10.0" + case VersionTLS: + return "TLS dev version (WIP)" + default: + if vn.isGQUIC() { + return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion()) + } + return fmt.Sprintf("%#x", uint32(vn)) + } +} + +// ToAltSvc returns the representation of the version for the H2 Alt-Svc parameters +func (vn VersionNumber) ToAltSvc() string { + if vn.isGQUIC() { + return fmt.Sprintf("%d", vn.toGQUICVersion()) + } + return fmt.Sprintf("%d", vn) +} + +// CryptoStreamID gets the Stream ID of the crypto stream +func (vn VersionNumber) CryptoStreamID() StreamID { + if vn.isGQUIC() { + return 1 + } + return 0 +} + +// UsesIETFFrameFormat tells if this version uses the IETF frame format +func (vn VersionNumber) UsesIETFFrameFormat() bool { + return !vn.isGQUIC() +} + +// UsesIETFHeaderFormat tells if this version uses the IETF header format +func (vn VersionNumber) UsesIETFHeaderFormat() bool { + return !vn.isGQUIC() || vn >= Version44 +} + +// UsesLengthInHeader tells if this version uses the Length field in the IETF header +func (vn VersionNumber) UsesLengthInHeader() bool { + return !vn.isGQUIC() +} + +// UsesTokenInHeader tells if this version uses the Token field in the IETF header +func (vn VersionNumber) UsesTokenInHeader() bool { + return !vn.isGQUIC() +} + +// UsesStopWaitingFrames tells if this version uses STOP_WAITING frames +func (vn VersionNumber) UsesStopWaitingFrames() bool { + return vn.isGQUIC() && vn <= Version43 +} + +// UsesVarintPacketNumbers tells if this version uses 7/14/30 bit packet numbers +func (vn VersionNumber) UsesVarintPacketNumbers() bool { + return !vn.isGQUIC() +} + +// StreamContributesToConnectionFlowControl says if a stream contributes to connection-level flow control +func (vn VersionNumber) StreamContributesToConnectionFlowControl(id StreamID) bool { + if id == vn.CryptoStreamID() { + return false + } + if vn.isGQUIC() && id == 3 { + return false + } + return true +} + +func (vn VersionNumber) isGQUIC() bool { + return vn > gquicVersion0 && vn <= maxGquicVersion +} + +func (vn VersionNumber) toGQUICVersion() int { + return int(10*(vn-gquicVersion0)/0x100) + int(vn%0x10) +} + +// IsSupportedVersion returns true if the server supports this version +func IsSupportedVersion(supported []VersionNumber, v VersionNumber) bool { + for _, t := range supported { + if t == v { + return true + } + } + return false +} + +// ChooseSupportedVersion finds the best version in the overlap of ours and theirs +// ours is a slice of versions that we support, sorted by our preference (descending) +// theirs is a slice of versions offered by the peer. The order does not matter. +// The bool returned indicates if a matching version was found. +func ChooseSupportedVersion(ours, theirs []VersionNumber) (VersionNumber, bool) { + for _, ourVer := range ours { + for _, theirVer := range theirs { + if ourVer == theirVer { + return ourVer, true + } + } + } + return 0, false +} + +// generateReservedVersion generates a reserved version number (v & 0x0f0f0f0f == 0x0a0a0a0a) +func generateReservedVersion() VersionNumber { + b := make([]byte, 4) + _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything + return VersionNumber((binary.BigEndian.Uint32(b) | 0x0a0a0a0a) & 0xfafafafa) +} + +// GetGreasedVersions adds one reserved version number to a slice of version numbers, at a random position +func GetGreasedVersions(supported []VersionNumber) []VersionNumber { + b := make([]byte, 1) + _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything + randPos := int(b[0]) % (len(supported) + 1) + greased := make([]VersionNumber, len(supported)+1) + copy(greased, supported[:randPos]) + greased[randPos] = generateReservedVersion() + copy(greased[randPos+1:], supported[randPos:]) + return greased +} + +// StripGreasedVersions strips all greased versions from a slice of versions +func StripGreasedVersions(versions []VersionNumber) []VersionNumber { + realVersions := make([]VersionNumber, 0, len(versions)) + for _, v := range versions { + if v&0x0f0f0f0f != 0x0a0a0a0a { + realVersions = append(realVersions, v) + } + } + return realVersions +} diff --git a/vendor/lucas-clemente/quic-go/internal/protocol/version_test.go b/vendor/lucas-clemente/quic-go/internal/protocol/version_test.go new file mode 100644 index 00000000..6d118ad7 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/protocol/version_test.go @@ -0,0 +1,241 @@ +package protocol + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Version", func() { + isReservedVersion := func(v VersionNumber) bool { + return v&0x0f0f0f0f == 0x0a0a0a0a + } + + // version numbers taken from the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions + It("has the right gQUIC version number", func() { + Expect(Version39).To(BeEquivalentTo(0x51303339)) + Expect(Version43).To(BeEquivalentTo(0x51303433)) + Expect(Version44).To(BeEquivalentTo(0x51303434)) + }) + + It("says if a version is valid", func() { + Expect(IsValidVersion(Version39)).To(BeTrue()) + Expect(IsValidVersion(Version43)).To(BeTrue()) + Expect(IsValidVersion(Version44)).To(BeTrue()) + Expect(IsValidVersion(VersionTLS)).To(BeTrue()) + Expect(IsValidVersion(VersionMilestone0_10_0)).To(BeTrue()) + Expect(IsValidVersion(VersionWhatever)).To(BeFalse()) + Expect(IsValidVersion(VersionUnknown)).To(BeFalse()) + Expect(IsValidVersion(1234)).To(BeFalse()) + }) + + It("says if a version supports TLS", func() { + Expect(Version39.UsesTLS()).To(BeFalse()) + Expect(Version43.UsesTLS()).To(BeFalse()) + Expect(Version44.UsesTLS()).To(BeFalse()) + Expect(VersionMilestone0_10_0.UsesTLS()).To(BeTrue()) + Expect(VersionTLS.UsesTLS()).To(BeTrue()) + }) + + It("versions don't have reserved version numbers", func() { + Expect(isReservedVersion(Version39)).To(BeFalse()) + Expect(isReservedVersion(Version43)).To(BeFalse()) + Expect(isReservedVersion(Version44)).To(BeFalse()) + Expect(isReservedVersion(VersionTLS)).To(BeFalse()) + Expect(isReservedVersion(VersionMilestone0_10_0)).To(BeFalse()) + }) + + It("has the right string representation", func() { + Expect(Version39.String()).To(Equal("gQUIC 39")) + Expect(VersionTLS.String()).To(ContainSubstring("TLS")) + Expect(VersionMilestone0_10_0.String()).To(Equal("quic-go Milestone 0.10.0")) + Expect(VersionWhatever.String()).To(Equal("whatever")) + Expect(VersionUnknown.String()).To(Equal("unknown")) + // check with unsupported version numbers from the wiki + Expect(VersionNumber(0x51303039).String()).To(Equal("gQUIC 9")) + Expect(VersionNumber(0x51303133).String()).To(Equal("gQUIC 13")) + Expect(VersionNumber(0x51303235).String()).To(Equal("gQUIC 25")) + Expect(VersionNumber(0x51303438).String()).To(Equal("gQUIC 48")) + Expect(VersionNumber(0x01234567).String()).To(Equal("0x1234567")) + }) + + It("has the right representation for the H2 Alt-Svc tag", func() { + Expect(Version39.ToAltSvc()).To(Equal("39")) + Expect(Version43.ToAltSvc()).To(Equal("43")) + Expect(Version44.ToAltSvc()).To(Equal("44")) + Expect(VersionTLS.ToAltSvc()).To(Equal("101")) + // check with unsupported version numbers from the wiki + Expect(VersionNumber(0x51303133).ToAltSvc()).To(Equal("13")) + Expect(VersionNumber(0x51303235).ToAltSvc()).To(Equal("25")) + Expect(VersionNumber(0x51303438).ToAltSvc()).To(Equal("48")) + }) + + It("tells the Stream ID of the crypto stream", func() { + Expect(Version39.CryptoStreamID()).To(Equal(StreamID(1))) + Expect(Version43.CryptoStreamID()).To(Equal(StreamID(1))) + Expect(Version44.CryptoStreamID()).To(Equal(StreamID(1))) + Expect(VersionTLS.CryptoStreamID()).To(Equal(StreamID(0))) + Expect(VersionMilestone0_10_0.CryptoStreamID()).To(Equal(StreamID(0))) + }) + + It("tells if a version uses the IETF frame types", func() { + Expect(Version39.UsesIETFFrameFormat()).To(BeFalse()) + Expect(Version43.UsesIETFFrameFormat()).To(BeFalse()) + Expect(Version44.UsesIETFFrameFormat()).To(BeFalse()) + Expect(VersionTLS.UsesIETFFrameFormat()).To(BeTrue()) + Expect(VersionMilestone0_10_0.UsesIETFFrameFormat()).To(BeTrue()) + }) + + It("tells if a version uses the IETF header format", func() { + Expect(Version39.UsesIETFHeaderFormat()).To(BeFalse()) + Expect(Version43.UsesIETFHeaderFormat()).To(BeFalse()) + Expect(Version44.UsesIETFHeaderFormat()).To(BeTrue()) + Expect(VersionTLS.UsesIETFHeaderFormat()).To(BeTrue()) + Expect(VersionMilestone0_10_0.UsesIETFHeaderFormat()).To(BeTrue()) + }) + + It("tells if a version uses varint packet numbers", func() { + Expect(Version39.UsesVarintPacketNumbers()).To(BeFalse()) + Expect(Version43.UsesVarintPacketNumbers()).To(BeFalse()) + Expect(Version44.UsesVarintPacketNumbers()).To(BeFalse()) + Expect(VersionTLS.UsesVarintPacketNumbers()).To(BeTrue()) + Expect(VersionMilestone0_10_0.UsesVarintPacketNumbers()).To(BeTrue()) + }) + + It("tells if a version uses the Length field in the IETF header", func() { + Expect(Version44.UsesLengthInHeader()).To(BeFalse()) + Expect(VersionTLS.UsesLengthInHeader()).To(BeTrue()) + Expect(VersionMilestone0_10_0.UsesLengthInHeader()).To(BeTrue()) + }) + + It("tells if a version uses the Token field in the IETF header", func() { + Expect(Version44.UsesTokenInHeader()).To(BeFalse()) + Expect(VersionTLS.UsesTokenInHeader()).To(BeTrue()) + Expect(VersionMilestone0_10_0.UsesTokenInHeader()).To(BeTrue()) + }) + + It("tells if a version uses STOP_WAITING frames", func() { + Expect(Version39.UsesStopWaitingFrames()).To(BeTrue()) + Expect(Version43.UsesStopWaitingFrames()).To(BeTrue()) + Expect(Version44.UsesStopWaitingFrames()).To(BeFalse()) + Expect(VersionTLS.UsesStopWaitingFrames()).To(BeFalse()) + Expect(VersionMilestone0_10_0.UsesStopWaitingFrames()).To(BeFalse()) + }) + + It("says if a stream contributes to connection-level flowcontrol, for gQUIC", func() { + for _, v := range []VersionNumber{Version39, Version43, Version44} { + version := v + Expect(version.StreamContributesToConnectionFlowControl(1)).To(BeFalse()) + Expect(version.StreamContributesToConnectionFlowControl(2)).To(BeTrue()) + Expect(version.StreamContributesToConnectionFlowControl(3)).To(BeFalse()) + Expect(version.StreamContributesToConnectionFlowControl(4)).To(BeTrue()) + Expect(version.StreamContributesToConnectionFlowControl(5)).To(BeTrue()) + } + }) + + It("says if a stream contributes to connection-level flowcontrol, for TLS", func() { + Expect(VersionTLS.StreamContributesToConnectionFlowControl(0)).To(BeFalse()) + Expect(VersionTLS.StreamContributesToConnectionFlowControl(1)).To(BeTrue()) + Expect(VersionTLS.StreamContributesToConnectionFlowControl(2)).To(BeTrue()) + Expect(VersionTLS.StreamContributesToConnectionFlowControl(3)).To(BeTrue()) + Expect(VersionMilestone0_10_0.StreamContributesToConnectionFlowControl(0)).To(BeFalse()) + Expect(VersionMilestone0_10_0.StreamContributesToConnectionFlowControl(1)).To(BeTrue()) + Expect(VersionMilestone0_10_0.StreamContributesToConnectionFlowControl(2)).To(BeTrue()) + Expect(VersionMilestone0_10_0.StreamContributesToConnectionFlowControl(3)).To(BeTrue()) + }) + + It("recognizes supported versions", func() { + Expect(IsSupportedVersion(SupportedVersions, 0)).To(BeFalse()) + Expect(IsSupportedVersion(SupportedVersions, SupportedVersions[0])).To(BeTrue()) + Expect(IsSupportedVersion(SupportedVersions, SupportedVersions[len(SupportedVersions)-1])).To(BeTrue()) + }) + + It("has supported versions in sorted order", func() { + for i := 0; i < len(SupportedVersions)-1; i++ { + Expect(SupportedVersions[i]).To(BeNumerically(">", SupportedVersions[i+1])) + } + }) + + Context("highest supported version", func() { + It("finds the supported version", func() { + supportedVersions := []VersionNumber{1, 2, 3} + other := []VersionNumber{6, 5, 4, 3} + ver, ok := ChooseSupportedVersion(supportedVersions, other) + Expect(ok).To(BeTrue()) + Expect(ver).To(Equal(VersionNumber(3))) + }) + + It("picks the preferred version", func() { + supportedVersions := []VersionNumber{2, 1, 3} + other := []VersionNumber{3, 6, 1, 8, 2, 10} + ver, ok := ChooseSupportedVersion(supportedVersions, other) + Expect(ok).To(BeTrue()) + Expect(ver).To(Equal(VersionNumber(2))) + }) + + It("says when no matching version was found", func() { + _, ok := ChooseSupportedVersion([]VersionNumber{1}, []VersionNumber{2}) + Expect(ok).To(BeFalse()) + }) + + It("handles empty inputs", func() { + _, ok := ChooseSupportedVersion([]VersionNumber{102, 101}, []VersionNumber{}) + Expect(ok).To(BeFalse()) + _, ok = ChooseSupportedVersion([]VersionNumber{}, []VersionNumber{1, 2}) + Expect(ok).To(BeFalse()) + _, ok = ChooseSupportedVersion([]VersionNumber{}, []VersionNumber{}) + Expect(ok).To(BeFalse()) + }) + }) + + Context("reserved versions", func() { + It("adds a greased version if passed an empty slice", func() { + greased := GetGreasedVersions([]VersionNumber{}) + Expect(greased).To(HaveLen(1)) + Expect(isReservedVersion(greased[0])).To(BeTrue()) + }) + + It("strips greased versions", func() { + v := SupportedVersions[0] + greased := GetGreasedVersions([]VersionNumber{v}) + Expect(greased).To(HaveLen(2)) + stripped := StripGreasedVersions(greased) + Expect(stripped).To(HaveLen(1)) + Expect(stripped[0]).To(Equal(v)) + }) + + It("creates greased lists of version numbers", func() { + supported := []VersionNumber{10, 18, 29} + for _, v := range supported { + Expect(isReservedVersion(v)).To(BeFalse()) + } + var greasedVersionFirst, greasedVersionLast, greasedVersionMiddle int + // check that + // 1. the greased version sometimes appears first + // 2. the greased version sometimes appears in the middle + // 3. the greased version sometimes appears last + // 4. the supported versions are kept in order + for i := 0; i < 100; i++ { + greased := GetGreasedVersions(supported) + Expect(greased).To(HaveLen(4)) + var j int + for i, v := range greased { + if isReservedVersion(v) { + if i == 0 { + greasedVersionFirst++ + } + if i == len(greased)-1 { + greasedVersionLast++ + } + greasedVersionMiddle++ + continue + } + Expect(supported[j]).To(Equal(v)) + j++ + } + } + Expect(greasedVersionFirst).ToNot(BeZero()) + Expect(greasedVersionLast).ToNot(BeZero()) + Expect(greasedVersionMiddle).ToNot(BeZero()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/testdata/cert.go b/vendor/lucas-clemente/quic-go/internal/testdata/cert.go new file mode 100644 index 00000000..6acfbb5a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/testdata/cert.go @@ -0,0 +1,44 @@ +package testdata + +import ( + "crypto/tls" + "path" + "runtime" +) + +var certPath string + +func init() { + _, filename, _, ok := runtime.Caller(0) + if !ok { + panic("Failed to get current frame") + } + + certPath = path.Join(path.Dir(path.Dir(path.Dir(filename))), "example") +} + +// GetCertificatePaths returns the paths to 'fullchain.pem' and 'privkey.pem' for the +// quic.clemente.io cert. +func GetCertificatePaths() (string, string) { + return path.Join(certPath, "fullchain.pem"), path.Join(certPath, "privkey.pem") +} + +// GetTLSConfig returns a tls config for quic.clemente.io +func GetTLSConfig() *tls.Config { + cert, err := tls.LoadX509KeyPair(GetCertificatePaths()) + if err != nil { + panic(err) + } + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + } +} + +// GetCertificate returns a certificate for quic.clemente.io +func GetCertificate() tls.Certificate { + cert, err := tls.LoadX509KeyPair(GetCertificatePaths()) + if err != nil { + panic(err) + } + return cert +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/atomic_bool.go b/vendor/lucas-clemente/quic-go/internal/utils/atomic_bool.go new file mode 100644 index 00000000..cf464250 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/atomic_bool.go @@ -0,0 +1,22 @@ +package utils + +import "sync/atomic" + +// An AtomicBool is an atomic bool +type AtomicBool struct { + v int32 +} + +// Set sets the value +func (a *AtomicBool) Set(value bool) { + var n int32 + if value { + n = 1 + } + atomic.StoreInt32(&a.v, n) +} + +// Get gets the value +func (a *AtomicBool) Get() bool { + return atomic.LoadInt32(&a.v) != 0 +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/atomic_bool_test.go b/vendor/lucas-clemente/quic-go/internal/utils/atomic_bool_test.go new file mode 100644 index 00000000..83a200c2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/atomic_bool_test.go @@ -0,0 +1,29 @@ +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Atomic Bool", func() { + var a *AtomicBool + + BeforeEach(func() { + a = &AtomicBool{} + }) + + It("has the right default value", func() { + Expect(a.Get()).To(BeFalse()) + }) + + It("sets the value to true", func() { + a.Set(true) + Expect(a.Get()).To(BeTrue()) + }) + + It("sets the value to false", func() { + a.Set(true) + a.Set(false) + Expect(a.Get()).To(BeFalse()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/byteinterval_linkedlist.go b/vendor/lucas-clemente/quic-go/internal/utils/byteinterval_linkedlist.go new file mode 100644 index 00000000..096023ef --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/byteinterval_linkedlist.go @@ -0,0 +1,217 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package utils + +// Linked list implementation from the Go standard library. + +// ByteIntervalElement is an element of a linked list. +type ByteIntervalElement struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *ByteIntervalElement + + // The list to which this element belongs. + list *ByteIntervalList + + // The value stored with this element. + Value ByteInterval +} + +// Next returns the next list element or nil. +func (e *ByteIntervalElement) Next() *ByteIntervalElement { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// Prev returns the previous list element or nil. +func (e *ByteIntervalElement) Prev() *ByteIntervalElement { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// ByteIntervalList is a linked list of ByteIntervals. +type ByteIntervalList struct { + root ByteIntervalElement // sentinel list element, only &root, root.prev, and root.next are used + len int // current list length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *ByteIntervalList) Init() *ByteIntervalList { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// NewByteIntervalList returns an initialized list. +func NewByteIntervalList() *ByteIntervalList { return new(ByteIntervalList).Init() } + +// Len returns the number of elements of list l. +// The complexity is O(1). +func (l *ByteIntervalList) Len() int { return l.len } + +// Front returns the first element of list l or nil if the list is empty. +func (l *ByteIntervalList) Front() *ByteIntervalElement { + if l.len == 0 { + return nil + } + return l.root.next +} + +// Back returns the last element of list l or nil if the list is empty. +func (l *ByteIntervalList) Back() *ByteIntervalElement { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero List value. +func (l *ByteIntervalList) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *ByteIntervalList) insert(e, at *ByteIntervalElement) *ByteIntervalElement { + n := at.next + at.next = e + e.prev = at + e.next = n + n.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). +func (l *ByteIntervalList) insertValue(v ByteInterval, at *ByteIntervalElement) *ByteIntervalElement { + return l.insert(&ByteIntervalElement{Value: v}, at) +} + +// remove removes e from its list, decrements l.len, and returns e. +func (l *ByteIntervalList) remove(e *ByteIntervalElement) *ByteIntervalElement { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + return e +} + +// Remove removes e from l if e is an element of list l. +// It returns the element value e.Value. +// The element must not be nil. +func (l *ByteIntervalList) Remove(e *ByteIntervalElement) ByteInterval { + if e.list == l { + // if e.list == l, l must have been initialized when e was inserted + // in l or l == nil (e is a zero Element) and l.remove will crash + l.remove(e) + } + return e.Value +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *ByteIntervalList) PushFront(v ByteInterval) *ByteIntervalElement { + l.lazyInit() + return l.insertValue(v, &l.root) +} + +// PushBack inserts a new element e with value v at the back of list l and returns e. +func (l *ByteIntervalList) PushBack(v ByteInterval) *ByteIntervalElement { + l.lazyInit() + return l.insertValue(v, l.root.prev) +} + +// InsertBefore inserts a new element e with value v immediately before mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *ByteIntervalList) InsertBefore(v ByteInterval, mark *ByteIntervalElement) *ByteIntervalElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark.prev) +} + +// InsertAfter inserts a new element e with value v immediately after mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *ByteIntervalList) InsertAfter(v ByteInterval, mark *ByteIntervalElement) *ByteIntervalElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *ByteIntervalList) MoveToFront(e *ByteIntervalElement) { + if e.list != l || l.root.next == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), &l.root) +} + +// MoveToBack moves element e to the back of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *ByteIntervalList) MoveToBack(e *ByteIntervalElement) { + if e.list != l || l.root.prev == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), l.root.prev) +} + +// MoveBefore moves element e to its new position before mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *ByteIntervalList) MoveBefore(e, mark *ByteIntervalElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark.prev) +} + +// MoveAfter moves element e to its new position after mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *ByteIntervalList) MoveAfter(e, mark *ByteIntervalElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark) +} + +// PushBackList inserts a copy of an other list at the back of list l. +// The lists l and other may be the same. They must not be nil. +func (l *ByteIntervalList) PushBackList(other *ByteIntervalList) { + l.lazyInit() + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +// PushFrontList inserts a copy of an other list at the front of list l. +// The lists l and other may be the same. They must not be nil. +func (l *ByteIntervalList) PushFrontList(other *ByteIntervalList) { + l.lazyInit() + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, &l.root) + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/byteoder_big_endian_test.go b/vendor/lucas-clemente/quic-go/internal/utils/byteoder_big_endian_test.go new file mode 100644 index 00000000..dec2e841 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/byteoder_big_endian_test.go @@ -0,0 +1,220 @@ +package utils + +import ( + "bytes" + "io" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Big Endian encoding / decoding", func() { + Context("ReadUint16", func() { + It("reads a big endian", func() { + b := []byte{0x13, 0xEF} + val, err := BigEndian.ReadUint16(bytes.NewReader(b)) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint16(0x13EF))) + }) + + It("throws an error if less than 2 bytes are passed", func() { + b := []byte{0x13, 0xEF} + for i := 0; i < len(b); i++ { + _, err := BigEndian.ReadUint16(bytes.NewReader(b[:i])) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("ReadUint32", func() { + It("reads a big endian", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF} + val, err := BigEndian.ReadUint32(bytes.NewReader(b)) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint32(0x1235ABFF))) + }) + + It("throws an error if less than 4 bytes are passed", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF} + for i := 0; i < len(b); i++ { + _, err := BigEndian.ReadUint32(bytes.NewReader(b[:i])) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("ReadUint64", func() { + It("reads a big endian", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF, 0xEF, 0xBE, 0xAD, 0xDE} + val, err := BigEndian.ReadUint64(bytes.NewReader(b)) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint64(0x1235ABFFEFBEADDE))) + }) + + It("throws an error if less than 8 bytes are passed", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF, 0xEF, 0xBE, 0xAD, 0xDE} + for i := 0; i < len(b); i++ { + _, err := BigEndian.ReadUint64(bytes.NewReader(b[:i])) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("WriteUint16", func() { + It("outputs 2 bytes", func() { + b := &bytes.Buffer{} + BigEndian.WriteUint16(b, uint16(1)) + Expect(b.Len()).To(Equal(2)) + }) + + It("outputs a big endian", func() { + num := uint16(0xFF11) + b := &bytes.Buffer{} + BigEndian.WriteUint16(b, num) + Expect(b.Bytes()).To(Equal([]byte{0xFF, 0x11})) + }) + }) + + Context("WriteUint24", func() { + It("outputs 3 bytes", func() { + b := &bytes.Buffer{} + BigEndian.WriteUint24(b, uint32(1)) + Expect(b.Len()).To(Equal(3)) + }) + + It("outputs a big endian", func() { + num := uint32(0x010203) + b := &bytes.Buffer{} + BigEndian.WriteUint24(b, num) + Expect(b.Bytes()).To(Equal([]byte{0x01, 0x02, 0x03})) + }) + + It("panics if the value doesn't fit into 24 bits", func() { + num := uint32(0x01020304) + b := &bytes.Buffer{} + Expect(func() { BigEndian.WriteUint24(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint32", func() { + It("outputs 4 bytes", func() { + b := &bytes.Buffer{} + BigEndian.WriteUint32(b, uint32(1)) + Expect(b.Len()).To(Equal(4)) + }) + + It("outputs a big endian", func() { + num := uint32(0xEFAC3512) + b := &bytes.Buffer{} + BigEndian.WriteUint32(b, num) + Expect(b.Bytes()).To(Equal([]byte{0xEF, 0xAC, 0x35, 0x12})) + }) + }) + + Context("WriteUint40", func() { + It("outputs 5 bytes", func() { + b := &bytes.Buffer{} + BigEndian.WriteUint40(b, uint64(1)) + Expect(b.Len()).To(Equal(5)) + }) + + It("outputs a big endian", func() { + num := uint64(0xDECAFBAD42) + b := &bytes.Buffer{} + BigEndian.WriteUint40(b, num) + Expect(b.Bytes()).To(Equal([]byte{0xDE, 0xCA, 0xFB, 0xAD, 0x42})) + }) + + It("panics if the value doesn't fit into 40 bits", func() { + num := uint64(0x010203040506) + b := &bytes.Buffer{} + Expect(func() { BigEndian.WriteUint40(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint48", func() { + It("outputs 6 bytes", func() { + b := &bytes.Buffer{} + BigEndian.WriteUint48(b, uint64(1)) + Expect(b.Len()).To(Equal(6)) + }) + + It("outputs a big endian", func() { + num := uint64(0xDEADBEEFCAFE) + b := &bytes.Buffer{} + BigEndian.WriteUint48(b, num) + Expect(b.Bytes()).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE})) + }) + + It("panics if the value doesn't fit into 48 bits", func() { + num := uint64(0xDEADBEEFCAFE01) + b := &bytes.Buffer{} + Expect(func() { BigEndian.WriteUint48(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint56", func() { + It("outputs 7 bytes", func() { + b := &bytes.Buffer{} + BigEndian.WriteUint56(b, uint64(1)) + Expect(b.Len()).To(Equal(7)) + }) + + It("outputs a big endian", func() { + num := uint64(0xEEDDCCBBAA9988) + b := &bytes.Buffer{} + BigEndian.WriteUint56(b, num) + Expect(b.Bytes()).To(Equal([]byte{0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88})) + }) + + It("panics if the value doesn't fit into 56 bits", func() { + num := uint64(0xEEDDCCBBAA998801) + b := &bytes.Buffer{} + Expect(func() { BigEndian.WriteUint56(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint64", func() { + It("outputs 8 bytes", func() { + b := &bytes.Buffer{} + BigEndian.WriteUint64(b, uint64(1)) + Expect(b.Len()).To(Equal(8)) + }) + + It("outputs a big endian", func() { + num := uint64(0xFFEEDDCCBBAA9988) + b := &bytes.Buffer{} + BigEndian.WriteUint64(b, num) + Expect(b.Bytes()).To(Equal([]byte{0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88})) + }) + }) + + Context("ReadUintN", func() { + + It("reads n bytes", func() { + m := map[uint8]uint64{ + 0: 0x0, + 1: 0x01, + 2: 0x0102, + 3: 0x010203, + 4: 0x01020304, + 5: 0x0102030405, + 6: 0x010203040506, + 7: 0x01020304050607, + 8: 0x0102030405060708, + } + for n, expected := range m { + b := bytes.NewReader([]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}) + i, err := BigEndian.ReadUintN(b, n) + Expect(err).ToNot(HaveOccurred()) + Expect(i).To(Equal(expected)) + } + }) + + It("errors", func() { + b := bytes.NewReader([]byte{0x1, 0x2}) + _, err := BigEndian.ReadUintN(b, 3) + Expect(err).To(HaveOccurred()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/byteorder.go b/vendor/lucas-clemente/quic-go/internal/utils/byteorder.go new file mode 100644 index 00000000..b45800a3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/byteorder.go @@ -0,0 +1,25 @@ +package utils + +import ( + "bytes" + "io" +) + +// A ByteOrder specifies how to convert byte sequences into 16-, 32-, or 64-bit unsigned integers. +type ByteOrder interface { + ReadUintN(b io.ByteReader, length uint8) (uint64, error) + ReadUint64(io.ByteReader) (uint64, error) + ReadUint32(io.ByteReader) (uint32, error) + ReadUint16(io.ByteReader) (uint16, error) + + WriteUint64(*bytes.Buffer, uint64) + WriteUint56(*bytes.Buffer, uint64) + WriteUint48(*bytes.Buffer, uint64) + WriteUint40(*bytes.Buffer, uint64) + WriteUint32(*bytes.Buffer, uint32) + WriteUint24(*bytes.Buffer, uint32) + WriteUint16(*bytes.Buffer, uint16) + + ReadUfloat16(io.ByteReader) (uint64, error) + WriteUfloat16(*bytes.Buffer, uint64) +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go b/vendor/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go new file mode 100644 index 00000000..9f6c9a61 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go @@ -0,0 +1,157 @@ +package utils + +import ( + "bytes" + "fmt" + "io" +) + +// BigEndian is the big-endian implementation of ByteOrder. +var BigEndian ByteOrder = bigEndian{} + +type bigEndian struct{} + +var _ ByteOrder = &bigEndian{} + +// ReadUintN reads N bytes +func (bigEndian) ReadUintN(b io.ByteReader, length uint8) (uint64, error) { + var res uint64 + for i := uint8(0); i < length; i++ { + bt, err := b.ReadByte() + if err != nil { + return 0, err + } + res ^= uint64(bt) << ((length - 1 - i) * 8) + } + return res, nil +} + +// ReadUint64 reads a uint64 +func (bigEndian) ReadUint64(b io.ByteReader) (uint64, error) { + var b1, b2, b3, b4, b5, b6, b7, b8 uint8 + var err error + if b8, err = b.ReadByte(); err != nil { + return 0, err + } + if b7, err = b.ReadByte(); err != nil { + return 0, err + } + if b6, err = b.ReadByte(); err != nil { + return 0, err + } + if b5, err = b.ReadByte(); err != nil { + return 0, err + } + if b4, err = b.ReadByte(); err != nil { + return 0, err + } + if b3, err = b.ReadByte(); err != nil { + return 0, err + } + if b2, err = b.ReadByte(); err != nil { + return 0, err + } + if b1, err = b.ReadByte(); err != nil { + return 0, err + } + return uint64(b1) + uint64(b2)<<8 + uint64(b3)<<16 + uint64(b4)<<24 + uint64(b5)<<32 + uint64(b6)<<40 + uint64(b7)<<48 + uint64(b8)<<56, nil +} + +// ReadUint32 reads a uint32 +func (bigEndian) ReadUint32(b io.ByteReader) (uint32, error) { + var b1, b2, b3, b4 uint8 + var err error + if b4, err = b.ReadByte(); err != nil { + return 0, err + } + if b3, err = b.ReadByte(); err != nil { + return 0, err + } + if b2, err = b.ReadByte(); err != nil { + return 0, err + } + if b1, err = b.ReadByte(); err != nil { + return 0, err + } + return uint32(b1) + uint32(b2)<<8 + uint32(b3)<<16 + uint32(b4)<<24, nil +} + +// ReadUint16 reads a uint16 +func (bigEndian) ReadUint16(b io.ByteReader) (uint16, error) { + var b1, b2 uint8 + var err error + if b2, err = b.ReadByte(); err != nil { + return 0, err + } + if b1, err = b.ReadByte(); err != nil { + return 0, err + } + return uint16(b1) + uint16(b2)<<8, nil +} + +// WriteUint64 writes a uint64 +func (bigEndian) WriteUint64(b *bytes.Buffer, i uint64) { + b.Write([]byte{ + uint8(i >> 56), uint8(i >> 48), uint8(i >> 40), uint8(i >> 32), + uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), + }) +} + +// WriteUint56 writes 56 bit of a uint64 +func (bigEndian) WriteUint56(b *bytes.Buffer, i uint64) { + if i >= (1 << 56) { + panic(fmt.Sprintf("%#x doesn't fit into 56 bits", i)) + } + b.Write([]byte{ + uint8(i >> 48), uint8(i >> 40), uint8(i >> 32), + uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), + }) +} + +// WriteUint48 writes 48 bit of a uint64 +func (bigEndian) WriteUint48(b *bytes.Buffer, i uint64) { + if i >= (1 << 48) { + panic(fmt.Sprintf("%#x doesn't fit into 48 bits", i)) + } + b.Write([]byte{ + uint8(i >> 40), uint8(i >> 32), + uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), + }) +} + +// WriteUint40 writes 40 bit of a uint64 +func (bigEndian) WriteUint40(b *bytes.Buffer, i uint64) { + if i >= (1 << 40) { + panic(fmt.Sprintf("%#x doesn't fit into 40 bits", i)) + } + b.Write([]byte{ + uint8(i >> 32), + uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), + }) +} + +// WriteUint32 writes a uint32 +func (bigEndian) WriteUint32(b *bytes.Buffer, i uint32) { + b.Write([]byte{uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i)}) +} + +// WriteUint24 writes 24 bit of a uint32 +func (bigEndian) WriteUint24(b *bytes.Buffer, i uint32) { + if i >= (1 << 24) { + panic(fmt.Sprintf("%#x doesn't fit into 24 bits", i)) + } + b.Write([]byte{uint8(i >> 16), uint8(i >> 8), uint8(i)}) +} + +// WriteUint16 writes a uint16 +func (bigEndian) WriteUint16(b *bytes.Buffer, i uint16) { + b.Write([]byte{uint8(i >> 8), uint8(i)}) +} + +func (l bigEndian) ReadUfloat16(b io.ByteReader) (uint64, error) { + return readUfloat16(b, l) +} + +func (l bigEndian) WriteUfloat16(b *bytes.Buffer, val uint64) { + writeUfloat16(b, l, val) +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian.go b/vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian.go new file mode 100644 index 00000000..71ff95d5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian.go @@ -0,0 +1,157 @@ +package utils + +import ( + "bytes" + "fmt" + "io" +) + +// LittleEndian is the little-endian implementation of ByteOrder. +var LittleEndian ByteOrder = littleEndian{} + +type littleEndian struct{} + +var _ ByteOrder = &littleEndian{} + +// ReadUintN reads N bytes +func (littleEndian) ReadUintN(b io.ByteReader, length uint8) (uint64, error) { + var res uint64 + for i := uint8(0); i < length; i++ { + bt, err := b.ReadByte() + if err != nil { + return 0, err + } + res ^= uint64(bt) << (i * 8) + } + return res, nil +} + +// ReadUint64 reads a uint64 +func (littleEndian) ReadUint64(b io.ByteReader) (uint64, error) { + var b1, b2, b3, b4, b5, b6, b7, b8 uint8 + var err error + if b1, err = b.ReadByte(); err != nil { + return 0, err + } + if b2, err = b.ReadByte(); err != nil { + return 0, err + } + if b3, err = b.ReadByte(); err != nil { + return 0, err + } + if b4, err = b.ReadByte(); err != nil { + return 0, err + } + if b5, err = b.ReadByte(); err != nil { + return 0, err + } + if b6, err = b.ReadByte(); err != nil { + return 0, err + } + if b7, err = b.ReadByte(); err != nil { + return 0, err + } + if b8, err = b.ReadByte(); err != nil { + return 0, err + } + return uint64(b1) + uint64(b2)<<8 + uint64(b3)<<16 + uint64(b4)<<24 + uint64(b5)<<32 + uint64(b6)<<40 + uint64(b7)<<48 + uint64(b8)<<56, nil +} + +// ReadUint32 reads a uint32 +func (littleEndian) ReadUint32(b io.ByteReader) (uint32, error) { + var b1, b2, b3, b4 uint8 + var err error + if b1, err = b.ReadByte(); err != nil { + return 0, err + } + if b2, err = b.ReadByte(); err != nil { + return 0, err + } + if b3, err = b.ReadByte(); err != nil { + return 0, err + } + if b4, err = b.ReadByte(); err != nil { + return 0, err + } + return uint32(b1) + uint32(b2)<<8 + uint32(b3)<<16 + uint32(b4)<<24, nil +} + +// ReadUint16 reads a uint16 +func (littleEndian) ReadUint16(b io.ByteReader) (uint16, error) { + var b1, b2 uint8 + var err error + if b1, err = b.ReadByte(); err != nil { + return 0, err + } + if b2, err = b.ReadByte(); err != nil { + return 0, err + } + return uint16(b1) + uint16(b2)<<8, nil +} + +// WriteUint64 writes a uint64 +func (littleEndian) WriteUint64(b *bytes.Buffer, i uint64) { + b.Write([]byte{ + uint8(i), uint8(i >> 8), uint8(i >> 16), uint8(i >> 24), + uint8(i >> 32), uint8(i >> 40), uint8(i >> 48), uint8(i >> 56), + }) +} + +// WriteUint56 writes 56 bit of a uint64 +func (littleEndian) WriteUint56(b *bytes.Buffer, i uint64) { + if i >= (1 << 56) { + panic(fmt.Sprintf("%#x doesn't fit into 56 bits", i)) + } + b.Write([]byte{ + uint8(i), uint8(i >> 8), uint8(i >> 16), uint8(i >> 24), + uint8(i >> 32), uint8(i >> 40), uint8(i >> 48), + }) +} + +// WriteUint48 writes 48 bit of a uint64 +func (littleEndian) WriteUint48(b *bytes.Buffer, i uint64) { + if i >= (1 << 48) { + panic(fmt.Sprintf("%#x doesn't fit into 48 bits", i)) + } + b.Write([]byte{ + uint8(i), uint8(i >> 8), uint8(i >> 16), uint8(i >> 24), + uint8(i >> 32), uint8(i >> 40), + }) +} + +// WriteUint40 writes 40 bit of a uint64 +func (littleEndian) WriteUint40(b *bytes.Buffer, i uint64) { + if i >= (1 << 40) { + panic(fmt.Sprintf("%#x doesn't fit into 40 bits", i)) + } + b.Write([]byte{ + uint8(i), uint8(i >> 8), uint8(i >> 16), + uint8(i >> 24), uint8(i >> 32), + }) +} + +// WriteUint32 writes a uint32 +func (littleEndian) WriteUint32(b *bytes.Buffer, i uint32) { + b.Write([]byte{uint8(i), uint8(i >> 8), uint8(i >> 16), uint8(i >> 24)}) +} + +// WriteUint24 writes 24 bit of a uint32 +func (littleEndian) WriteUint24(b *bytes.Buffer, i uint32) { + if i >= (1 << 24) { + panic(fmt.Sprintf("%#x doesn't fit into 24 bits", i)) + } + b.Write([]byte{uint8(i), uint8(i >> 8), uint8(i >> 16)}) +} + +// WriteUint16 writes a uint16 +func (littleEndian) WriteUint16(b *bytes.Buffer, i uint16) { + b.Write([]byte{uint8(i), uint8(i >> 8)}) +} + +func (l littleEndian) ReadUfloat16(b io.ByteReader) (uint64, error) { + return readUfloat16(b, l) +} + +func (l littleEndian) WriteUfloat16(b *bytes.Buffer, val uint64) { + writeUfloat16(b, l, val) +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian_test.go b/vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian_test.go new file mode 100644 index 00000000..60508aaf --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/byteorder_little_endian_test.go @@ -0,0 +1,212 @@ +package utils + +import ( + "bytes" + "io" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Little Endian encoding / decoding", func() { + Context("ReadUint16", func() { + It("reads a little endian", func() { + b := []byte{0x13, 0xEF} + val, err := LittleEndian.ReadUint16(bytes.NewReader(b)) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint16(0xEF13))) + }) + + It("throws an error if less than 2 bytes are passed", func() { + b := []byte{0x13, 0xEF} + for i := 0; i < len(b); i++ { + _, err := LittleEndian.ReadUint16(bytes.NewReader(b[:i])) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("ReadUint32", func() { + It("reads a little endian", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF} + val, err := LittleEndian.ReadUint32(bytes.NewReader(b)) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint32(0xFFAB3512))) + }) + + It("throws an error if less than 4 bytes are passed", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF} + for i := 0; i < len(b); i++ { + _, err := LittleEndian.ReadUint32(bytes.NewReader(b[:i])) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("ReadUint64", func() { + It("reads a little endian", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF, 0xEF, 0xBE, 0xAD, 0xDE} + val, err := LittleEndian.ReadUint64(bytes.NewReader(b)) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint64(0xDEADBEEFFFAB3512))) + }) + + It("throws an error if less than 8 bytes are passed", func() { + b := []byte{0x12, 0x35, 0xAB, 0xFF, 0xEF, 0xBE, 0xAD, 0xDE} + for i := 0; i < len(b); i++ { + _, err := LittleEndian.ReadUint64(bytes.NewReader(b[:i])) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("WriteUint16", func() { + It("outputs 2 bytes", func() { + b := &bytes.Buffer{} + LittleEndian.WriteUint16(b, uint16(1)) + Expect(b.Len()).To(Equal(2)) + }) + + It("outputs a little endian", func() { + num := uint16(0xFF11) + b := &bytes.Buffer{} + LittleEndian.WriteUint16(b, num) + Expect(b.Bytes()).To(Equal([]byte{0x11, 0xFF})) + }) + }) + + Context("WriteUint24", func() { + It("outputs 3 bytes", func() { + b := &bytes.Buffer{} + LittleEndian.WriteUint24(b, uint32(1)) + Expect(b.Len()).To(Equal(3)) + }) + + It("outputs a little endian", func() { + num := uint32(0x010203) + b := &bytes.Buffer{} + LittleEndian.WriteUint24(b, num) + Expect(b.Bytes()).To(Equal([]byte{0x03, 0x02, 0x01})) + }) + + It("panics if the value doesn't fit into 24 bits", func() { + num := uint32(0x01020304) + b := &bytes.Buffer{} + Expect(func() { LittleEndian.WriteUint24(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint32", func() { + It("outputs 4 bytes", func() { + b := &bytes.Buffer{} + LittleEndian.WriteUint32(b, uint32(1)) + Expect(b.Len()).To(Equal(4)) + }) + + It("outputs a little endian", func() { + num := uint32(0xEFAC3512) + b := &bytes.Buffer{} + LittleEndian.WriteUint32(b, num) + Expect(b.Bytes()).To(Equal([]byte{0x12, 0x35, 0xAC, 0xEF})) + }) + }) + + Context("WriteUint40", func() { + It("outputs 5 bytes", func() { + b := &bytes.Buffer{} + LittleEndian.WriteUint40(b, uint64(1)) + Expect(b.Len()).To(Equal(5)) + }) + + It("outputs a little endian", func() { + num := uint64(0x0102030405) + b := &bytes.Buffer{} + LittleEndian.WriteUint40(b, num) + Expect(b.Bytes()).To(Equal([]byte{0x05, 0x04, 0x03, 0x02, 0x01})) + }) + + It("panics if the value doesn't fit into 40 bits", func() { + num := uint64(0x010203040506) + b := &bytes.Buffer{} + Expect(func() { LittleEndian.WriteUint40(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint48", func() { + It("outputs 6 bytes", func() { + b := &bytes.Buffer{} + LittleEndian.WriteUint48(b, uint64(1)) + Expect(b.Len()).To(Equal(6)) + }) + + It("outputs a little endian", func() { + num := uint64(0xDEADBEEFCAFE) + b := &bytes.Buffer{} + LittleEndian.WriteUint48(b, num) + Expect(b.Bytes()).To(Equal([]byte{0xFE, 0xCA, 0xEF, 0xBE, 0xAD, 0xDE})) + }) + + It("panics if the value doesn't fit into 48 bits", func() { + num := uint64(0xDEADBEEFCAFE01) + b := &bytes.Buffer{} + Expect(func() { LittleEndian.WriteUint48(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint56", func() { + It("outputs 7 bytes", func() { + b := &bytes.Buffer{} + LittleEndian.WriteUint56(b, uint64(1)) + Expect(b.Len()).To(Equal(7)) + }) + + It("outputs a little endian", func() { + num := uint64(0xEEDDCCBBAA9988) + b := &bytes.Buffer{} + LittleEndian.WriteUint56(b, num) + Expect(b.Bytes()).To(Equal([]byte{0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE})) + }) + + It("panics if the value doesn't fit into 56 bits", func() { + num := uint64(0xEEDDCCBBAA998801) + b := &bytes.Buffer{} + Expect(func() { LittleEndian.WriteUint56(b, num) }).Should(Panic()) + }) + }) + + Context("WriteUint64", func() { + It("outputs 8 bytes", func() { + b := &bytes.Buffer{} + LittleEndian.WriteUint64(b, uint64(1)) + Expect(b.Len()).To(Equal(8)) + }) + + It("outputs a little endian", func() { + num := uint64(0xFFEEDDCCBBAA9988) + b := &bytes.Buffer{} + LittleEndian.WriteUint64(b, num) + Expect(b.Bytes()).To(Equal([]byte{0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF})) + }) + }) + + Context("ReadUintN", func() { + It("reads n bytes", func() { + m := map[uint8]uint64{ + 0: 0x0, 1: 0x01, 2: 0x0201, 3: 0x030201, 4: 0x04030201, 5: 0x0504030201, + 6: 0x060504030201, 7: 0x07060504030201, 8: 0x0807060504030201, + } + for n, expected := range m { + b := bytes.NewReader([]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}) + i, err := LittleEndian.ReadUintN(b, n) + Expect(err).ToNot(HaveOccurred()) + Expect(i).To(Equal(expected)) + } + }) + + It("errors", func() { + b := bytes.NewReader([]byte{0x1, 0x2}) + _, err := LittleEndian.ReadUintN(b, 3) + Expect(err).To(HaveOccurred()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/float16.go b/vendor/lucas-clemente/quic-go/internal/utils/float16.go new file mode 100644 index 00000000..8e2ca1bc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/float16.go @@ -0,0 +1,86 @@ +package utils + +import ( + "bytes" + "io" + "math" +) + +// We define an unsigned 16-bit floating point value, inspired by IEEE floats +// (http://en.wikipedia.org/wiki/Half_precision_floating-point_format), +// with 5-bit exponent (bias 1), 11-bit mantissa (effective 12 with hidden +// bit) and denormals, but without signs, transfinites or fractions. Wire format +// 16 bits (little-endian byte order) are split into exponent (high 5) and +// mantissa (low 11) and decoded as: +// uint64_t value; +// if (exponent == 0) value = mantissa; +// else value = (mantissa | 1 << 11) << (exponent - 1) +const uFloat16ExponentBits = 5 +const uFloat16MaxExponent = (1 << uFloat16ExponentBits) - 2 // 30 +const uFloat16MantissaBits = 16 - uFloat16ExponentBits // 11 +const uFloat16MantissaEffectiveBits = uFloat16MantissaBits + 1 // 12 +const uFloat16MaxValue = ((uint64(1) << uFloat16MantissaEffectiveBits) - 1) << uFloat16MaxExponent // 0x3FFC0000000 + +// readUfloat16 reads a float in the QUIC-float16 format and returns its uint64 representation +func readUfloat16(b io.ByteReader, byteOrder ByteOrder) (uint64, error) { + val, err := byteOrder.ReadUint16(b) + if err != nil { + return 0, err + } + + res := uint64(val) + + if res < (1 << uFloat16MantissaEffectiveBits) { + // Fast path: either the value is denormalized (no hidden bit), or + // normalized (hidden bit set, exponent offset by one) with exponent zero. + // Zero exponent offset by one sets the bit exactly where the hidden bit is. + // So in both cases the value encodes itself. + return res, nil + } + + exponent := val >> uFloat16MantissaBits // No sign extend on uint! + // After the fast pass, the exponent is at least one (offset by one). + // Un-offset the exponent. + exponent-- + // Here we need to clear the exponent and set the hidden bit. We have already + // decremented the exponent, so when we subtract it, it leaves behind the + // hidden bit. + res -= uint64(exponent) << uFloat16MantissaBits + res <<= exponent + return res, nil +} + +// writeUfloat16 writes a float in the QUIC-float16 format from its uint64 representation +func writeUfloat16(b *bytes.Buffer, byteOrder ByteOrder, value uint64) { + var result uint16 + if value < (uint64(1) << uFloat16MantissaEffectiveBits) { + // Fast path: either the value is denormalized, or has exponent zero. + // Both cases are represented by the value itself. + result = uint16(value) + } else if value >= uFloat16MaxValue { + // Value is out of range; clamp it to the maximum representable. + result = math.MaxUint16 + } else { + // The highest bit is between position 13 and 42 (zero-based), which + // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10, + // hidden bit is 11 and exponent is 11 to 15. Shift the highest bit to 11 + // and count the shifts. + exponent := uint16(0) + for offset := uint16(16); offset > 0; offset /= 2 { + // Right-shift the value until the highest bit is in position 11. + // For offset of 16, 8, 4, 2 and 1 (binary search over 1-30), + // shift if the bit is at or above 11 + offset. + if value >= (uint64(1) << (uFloat16MantissaBits + offset)) { + exponent += offset + value >>= offset + } + } + + // Hidden bit (position 11) is set. We should remove it and increment the + // exponent. Equivalently, we just add it to the exponent. + // This hides the bit. + result = (uint16(value) + (exponent << uFloat16MantissaBits)) + } + + byteOrder.WriteUint16(b, result) +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/float16_test.go b/vendor/lucas-clemente/quic-go/internal/utils/float16_test.go new file mode 100644 index 00000000..319fad24 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/float16_test.go @@ -0,0 +1,161 @@ +package utils + +import ( + "bytes" + "fmt" + "io" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("float16", func() { + for _, v := range []ByteOrder{LittleEndian, BigEndian} { + bo := v + name := "little endian" + if bo == BigEndian { + name = "big endian" + } + + Context(fmt.Sprintf("in %s", name), func() { + It("reads", func() { + testcases := []struct { + expected uint64 + binary uint16 + }{ + // There are fewer decoding test cases because encoding truncates, and + // decoding returns the smallest expansion. + // Small numbers represent themselves. + {0, 0}, + {1, 1}, + {2, 2}, + {3, 3}, + {4, 4}, + {5, 5}, + {6, 6}, + {7, 7}, + {15, 15}, + {31, 31}, + {42, 42}, + {123, 123}, + {1234, 1234}, + // Check transition through 2^11. + {2046, 2046}, + {2047, 2047}, + {2048, 2048}, + {2049, 2049}, + // Running out of mantissa at 2^12. + {4094, 4094}, + {4095, 4095}, + {4096, 4096}, + {4098, 4097}, + {4100, 4098}, + // Check transition through 2^13. + {8190, 6143}, + {8192, 6144}, + {8196, 6145}, + // Half-way through the exponents. + {0x7FF8000, 0x87FF}, + {0x8000000, 0x8800}, + {0xFFF0000, 0x8FFF}, + {0x10000000, 0x9000}, + // Transition into the largest exponent. + {0x1FFE0000000, 0xF7FF}, + {0x20000000000, 0xF800}, + {0x20040000000, 0xF801}, + // Transition into the max value. + {0x3FF80000000, 0xFFFE}, + {0x3FFC0000000, 0xFFFF}, + } + for _, testcase := range testcases { + b := &bytes.Buffer{} + bo.WriteUint16(b, testcase.binary) + val, err := bo.ReadUfloat16(b) + Expect(err).NotTo(HaveOccurred()) + Expect(val).To(Equal(testcase.expected)) + } + }) + + It("errors on eof", func() { + _, err := bo.ReadUfloat16(&bytes.Buffer{}) + Expect(err).To(MatchError(io.EOF)) + }) + + It("writes", func() { + testcases := []struct { + decoded uint64 + encoded uint16 + }{ + // Small numbers represent themselves. + {0, 0}, + {1, 1}, + {2, 2}, + {3, 3}, + {4, 4}, + {5, 5}, + {6, 6}, + {7, 7}, + {15, 15}, + {31, 31}, + {42, 42}, + {123, 123}, + {1234, 1234}, + // Check transition through 2^11. + {2046, 2046}, + {2047, 2047}, + {2048, 2048}, + {2049, 2049}, + // Running out of mantissa at 2^12. + {4094, 4094}, + {4095, 4095}, + {4096, 4096}, + {4097, 4096}, + {4098, 4097}, + {4099, 4097}, + {4100, 4098}, + {4101, 4098}, + // Check transition through 2^13. + {8190, 6143}, + {8191, 6143}, + {8192, 6144}, + {8193, 6144}, + {8194, 6144}, + {8195, 6144}, + {8196, 6145}, + {8197, 6145}, + // Half-way through the exponents. + {0x7FF8000, 0x87FF}, + {0x7FFFFFF, 0x87FF}, + {0x8000000, 0x8800}, + {0xFFF0000, 0x8FFF}, + {0xFFFFFFF, 0x8FFF}, + {0x10000000, 0x9000}, + // Transition into the largest exponent. + {0x1FFFFFFFFFE, 0xF7FF}, + {0x1FFFFFFFFFF, 0xF7FF}, + {0x20000000000, 0xF800}, + {0x20000000001, 0xF800}, + {0x2003FFFFFFE, 0xF800}, + {0x2003FFFFFFF, 0xF800}, + {0x20040000000, 0xF801}, + {0x20040000001, 0xF801}, + // Transition into the max value and clamping. + {0x3FF80000000, 0xFFFE}, + {0x3FFBFFFFFFF, 0xFFFE}, + {0x3FFC0000000, 0xFFFF}, + {0x3FFC0000001, 0xFFFF}, + {0x3FFFFFFFFFF, 0xFFFF}, + {0x40000000000, 0xFFFF}, + {0xFFFFFFFFFFFFFFFF, 0xFFFF}, + } + for _, testcase := range testcases { + b := &bytes.Buffer{} + bo.WriteUfloat16(b, testcase.decoded) + val, err := bo.ReadUint16(b) + Expect(err).NotTo(HaveOccurred()) + Expect(val).To(Equal(testcase.encoded)) + } + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/gen.go b/vendor/lucas-clemente/quic-go/internal/utils/gen.go new file mode 100644 index 00000000..bb839be6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/gen.go @@ -0,0 +1,4 @@ +package utils + +//go:generate genny -pkg utils -in linkedlist/linkedlist.go -out byteinterval_linkedlist.go gen Item=ByteInterval +//go:generate genny -pkg utils -in linkedlist/linkedlist.go -out packetinterval_linkedlist.go gen Item=PacketInterval diff --git a/vendor/lucas-clemente/quic-go/internal/utils/host.go b/vendor/lucas-clemente/quic-go/internal/utils/host.go new file mode 100644 index 00000000..a1d6453b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/host.go @@ -0,0 +1,27 @@ +package utils + +import ( + "net/url" + "strings" +) + +// HostnameFromAddr determines the hostname in an address string +func HostnameFromAddr(addr string) (string, error) { + p, err := url.Parse(addr) + if err != nil { + return "", err + } + h := p.Host + + // copied from https://golang.org/src/net/http/transport.go + if hasPort(h) { + h = h[:strings.LastIndex(h, ":")] + } + + return h, nil +} + +// copied from https://golang.org/src/net/http/http.go +func hasPort(s string) bool { + return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/host_test.go b/vendor/lucas-clemente/quic-go/internal/utils/host_test.go new file mode 100644 index 00000000..d7667eb3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/host_test.go @@ -0,0 +1,49 @@ +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Hostname", func() { + It("gets the hostname from an URL", func() { + h, err := HostnameFromAddr("https://quic.clemente.io/file.dat?param=true¶m2=false") + Expect(err).ToNot(HaveOccurred()) + Expect(h).To(Equal("quic.clemente.io")) + }) + + It("gets the hostname from an URL with a port number", func() { + h, err := HostnameFromAddr("https://quic.clemente.io:6121/file.dat") + Expect(err).ToNot(HaveOccurred()) + Expect(h).To(Equal("quic.clemente.io")) + }) + + It("gets the hostname from an URL containing username and password", func() { + h, err := HostnameFromAddr("https://user:password@quic.clemente.io:6121/file.dat") + Expect(err).ToNot(HaveOccurred()) + Expect(h).To(Equal("quic.clemente.io")) + }) + + It("gets local hostnames", func() { + h, err := HostnameFromAddr("https://localhost/file.dat") + Expect(err).ToNot(HaveOccurred()) + Expect(h).To(Equal("localhost")) + }) + + It("gets the hostname for other protocols", func() { + h, err := HostnameFromAddr("ftp://quic.clemente.io:6121/file.dat") + Expect(err).ToNot(HaveOccurred()) + Expect(h).To(Equal("quic.clemente.io")) + }) + + It("gets an IP", func() { + h, err := HostnameFromAddr("https://1.3.3.7:6121/file.dat") + Expect(err).ToNot(HaveOccurred()) + Expect(h).To(Equal("1.3.3.7")) + }) + + It("errors on malformed URLs", func() { + _, err := HostnameFromAddr("://quic.clemente.io:6121/file.dat") + Expect(err).To(HaveOccurred()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/linkedlist/README.md b/vendor/lucas-clemente/quic-go/internal/utils/linkedlist/README.md new file mode 100644 index 00000000..15b46dce --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/linkedlist/README.md @@ -0,0 +1,11 @@ +# Usage + +This is the Go standard library implementation of a linked list +(https://golang.org/src/container/list/list.go), modified such that genny +(https://github.com/cheekybits/genny) can be used to generate a typed linked +list. + +To generate, run +``` +genny -pkg $PACKAGE -in linkedlist.go -out $OUTFILE gen Item=$TYPE +``` diff --git a/vendor/lucas-clemente/quic-go/internal/utils/linkedlist/linkedlist.go b/vendor/lucas-clemente/quic-go/internal/utils/linkedlist/linkedlist.go new file mode 100644 index 00000000..74b815a8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/linkedlist/linkedlist.go @@ -0,0 +1,218 @@ +package linkedlist + +import "github.com/cheekybits/genny/generic" + +// Linked list implementation from the Go standard library. + +// Item is a generic type. +type Item generic.Type + +// ItemElement is an element of a linked list. +type ItemElement struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *ItemElement + + // The list to which this element belongs. + list *ItemList + + // The value stored with this element. + Value Item +} + +// Next returns the next list element or nil. +func (e *ItemElement) Next() *ItemElement { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// Prev returns the previous list element or nil. +func (e *ItemElement) Prev() *ItemElement { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// ItemList is a linked list of Items. +type ItemList struct { + root ItemElement // sentinel list element, only &root, root.prev, and root.next are used + len int // current list length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *ItemList) Init() *ItemList { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// NewItemList returns an initialized list. +func NewItemList() *ItemList { return new(ItemList).Init() } + +// Len returns the number of elements of list l. +// The complexity is O(1). +func (l *ItemList) Len() int { return l.len } + +// Front returns the first element of list l or nil if the list is empty. +func (l *ItemList) Front() *ItemElement { + if l.len == 0 { + return nil + } + return l.root.next +} + +// Back returns the last element of list l or nil if the list is empty. +func (l *ItemList) Back() *ItemElement { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero List value. +func (l *ItemList) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *ItemList) insert(e, at *ItemElement) *ItemElement { + n := at.next + at.next = e + e.prev = at + e.next = n + n.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). +func (l *ItemList) insertValue(v Item, at *ItemElement) *ItemElement { + return l.insert(&ItemElement{Value: v}, at) +} + +// remove removes e from its list, decrements l.len, and returns e. +func (l *ItemList) remove(e *ItemElement) *ItemElement { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + return e +} + +// Remove removes e from l if e is an element of list l. +// It returns the element value e.Value. +// The element must not be nil. +func (l *ItemList) Remove(e *ItemElement) Item { + if e.list == l { + // if e.list == l, l must have been initialized when e was inserted + // in l or l == nil (e is a zero Element) and l.remove will crash + l.remove(e) + } + return e.Value +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *ItemList) PushFront(v Item) *ItemElement { + l.lazyInit() + return l.insertValue(v, &l.root) +} + +// PushBack inserts a new element e with value v at the back of list l and returns e. +func (l *ItemList) PushBack(v Item) *ItemElement { + l.lazyInit() + return l.insertValue(v, l.root.prev) +} + +// InsertBefore inserts a new element e with value v immediately before mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *ItemList) InsertBefore(v Item, mark *ItemElement) *ItemElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark.prev) +} + +// InsertAfter inserts a new element e with value v immediately after mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *ItemList) InsertAfter(v Item, mark *ItemElement) *ItemElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *ItemList) MoveToFront(e *ItemElement) { + if e.list != l || l.root.next == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), &l.root) +} + +// MoveToBack moves element e to the back of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *ItemList) MoveToBack(e *ItemElement) { + if e.list != l || l.root.prev == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), l.root.prev) +} + +// MoveBefore moves element e to its new position before mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *ItemList) MoveBefore(e, mark *ItemElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark.prev) +} + +// MoveAfter moves element e to its new position after mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *ItemList) MoveAfter(e, mark *ItemElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark) +} + +// PushBackList inserts a copy of an other list at the back of list l. +// The lists l and other may be the same. They must not be nil. +func (l *ItemList) PushBackList(other *ItemList) { + l.lazyInit() + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +// PushFrontList inserts a copy of an other list at the front of list l. +// The lists l and other may be the same. They must not be nil. +func (l *ItemList) PushFrontList(other *ItemList) { + l.lazyInit() + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, &l.root) + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/log.go b/vendor/lucas-clemente/quic-go/internal/utils/log.go new file mode 100644 index 00000000..e27f01b4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/log.go @@ -0,0 +1,131 @@ +package utils + +import ( + "fmt" + "log" + "os" + "strings" + "time" +) + +// LogLevel of quic-go +type LogLevel uint8 + +const ( + // LogLevelNothing disables + LogLevelNothing LogLevel = iota + // LogLevelError enables err logs + LogLevelError + // LogLevelInfo enables info logs (e.g. packets) + LogLevelInfo + // LogLevelDebug enables debug logs (e.g. packet contents) + LogLevelDebug +) + +const logEnv = "QUIC_GO_LOG_LEVEL" + +// A Logger logs. +type Logger interface { + SetLogLevel(LogLevel) + SetLogTimeFormat(format string) + WithPrefix(prefix string) Logger + Debug() bool + + Errorf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Debugf(format string, args ...interface{}) +} + +// DefaultLogger is used by quic-go for logging. +var DefaultLogger Logger + +type defaultLogger struct { + prefix string + + logLevel LogLevel + timeFormat string +} + +var _ Logger = &defaultLogger{} + +// SetLogLevel sets the log level +func (l *defaultLogger) SetLogLevel(level LogLevel) { + l.logLevel = level +} + +// SetLogTimeFormat sets the format of the timestamp +// an empty string disables the logging of timestamps +func (l *defaultLogger) SetLogTimeFormat(format string) { + log.SetFlags(0) // disable timestamp logging done by the log package + l.timeFormat = format +} + +// Debugf logs something +func (l *defaultLogger) Debugf(format string, args ...interface{}) { + if l.logLevel == LogLevelDebug { + l.logMessage(format, args...) + } +} + +// Infof logs something +func (l *defaultLogger) Infof(format string, args ...interface{}) { + if l.logLevel >= LogLevelInfo { + l.logMessage(format, args...) + } +} + +// Errorf logs something +func (l *defaultLogger) Errorf(format string, args ...interface{}) { + if l.logLevel >= LogLevelError { + l.logMessage(format, args...) + } +} + +func (l *defaultLogger) logMessage(format string, args ...interface{}) { + var pre string + + if len(l.timeFormat) > 0 { + pre = time.Now().Format(l.timeFormat) + " " + } + if len(l.prefix) > 0 { + pre += l.prefix + " " + } + log.Printf(pre+format, args...) +} + +func (l *defaultLogger) WithPrefix(prefix string) Logger { + if len(l.prefix) > 0 { + prefix = l.prefix + " " + prefix + } + return &defaultLogger{ + logLevel: l.logLevel, + timeFormat: l.timeFormat, + prefix: prefix, + } +} + +// Debug returns true if the log level is LogLevelDebug +func (l *defaultLogger) Debug() bool { + return l.logLevel == LogLevelDebug +} + +func init() { + DefaultLogger = &defaultLogger{} + DefaultLogger.SetLogLevel(readLoggingEnv()) +} + +func readLoggingEnv() LogLevel { + switch strings.ToLower(os.Getenv(logEnv)) { + case "": + return LogLevelNothing + case "debug": + return LogLevelDebug + case "info": + return LogLevelInfo + case "error": + return LogLevelError + default: + fmt.Fprintln(os.Stderr, "invalid quic-go log level, see https://github.com/lucas-clemente/quic-go/wiki/Logging") + return LogLevelNothing + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/log_test.go b/vendor/lucas-clemente/quic-go/internal/utils/log_test.go new file mode 100644 index 00000000..0cda4583 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/log_test.go @@ -0,0 +1,144 @@ +package utils + +import ( + "bytes" + "log" + "os" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Log", func() { + var b *bytes.Buffer + + BeforeEach(func() { + b = &bytes.Buffer{} + log.SetOutput(b) + }) + + AfterEach(func() { + log.SetOutput(os.Stdout) + DefaultLogger.SetLogLevel(LogLevelNothing) + }) + + It("the log level has the correct numeric value", func() { + Expect(LogLevelNothing).To(BeEquivalentTo(0)) + Expect(LogLevelError).To(BeEquivalentTo(1)) + Expect(LogLevelInfo).To(BeEquivalentTo(2)) + Expect(LogLevelDebug).To(BeEquivalentTo(3)) + }) + + It("log level nothing", func() { + DefaultLogger.SetLogLevel(LogLevelNothing) + DefaultLogger.Debugf("debug") + DefaultLogger.Infof("info") + DefaultLogger.Errorf("err") + Expect(b.String()).To(BeEmpty()) + }) + + It("log level err", func() { + DefaultLogger.SetLogLevel(LogLevelError) + DefaultLogger.Debugf("debug") + DefaultLogger.Infof("info") + DefaultLogger.Errorf("err") + Expect(b.String()).To(ContainSubstring("err\n")) + Expect(b.String()).ToNot(ContainSubstring("info")) + Expect(b.String()).ToNot(ContainSubstring("debug")) + }) + + It("log level info", func() { + DefaultLogger.SetLogLevel(LogLevelInfo) + DefaultLogger.Debugf("debug") + DefaultLogger.Infof("info") + DefaultLogger.Errorf("err") + Expect(b.String()).To(ContainSubstring("err\n")) + Expect(b.String()).To(ContainSubstring("info\n")) + Expect(b.String()).ToNot(ContainSubstring("debug")) + }) + + It("log level debug", func() { + DefaultLogger.SetLogLevel(LogLevelDebug) + DefaultLogger.Debugf("debug") + DefaultLogger.Infof("info") + DefaultLogger.Errorf("err") + Expect(b.String()).To(ContainSubstring("err\n")) + Expect(b.String()).To(ContainSubstring("info\n")) + Expect(b.String()).To(ContainSubstring("debug\n")) + }) + + It("doesn't add a timestamp if the time format is empty", func() { + DefaultLogger.SetLogLevel(LogLevelDebug) + DefaultLogger.SetLogTimeFormat("") + DefaultLogger.Debugf("debug") + Expect(b.String()).To(Equal("debug\n")) + }) + + It("adds a timestamp", func() { + format := "Jan 2, 2006" + DefaultLogger.SetLogTimeFormat(format) + DefaultLogger.SetLogLevel(LogLevelInfo) + DefaultLogger.Infof("info") + t, err := time.Parse(format, string(b.String()[:b.Len()-6])) + Expect(err).ToNot(HaveOccurred()) + Expect(t).To(BeTemporally("~", time.Now(), 25*time.Hour)) + }) + + It("says whether debug is enabled", func() { + Expect(DefaultLogger.Debug()).To(BeFalse()) + DefaultLogger.SetLogLevel(LogLevelDebug) + Expect(DefaultLogger.Debug()).To(BeTrue()) + }) + + It("adds a prefix", func() { + DefaultLogger.SetLogLevel(LogLevelDebug) + prefixLogger := DefaultLogger.WithPrefix("prefix") + prefixLogger.Debugf("debug") + Expect(b.String()).To(ContainSubstring("prefix")) + Expect(b.String()).To(ContainSubstring("debug")) + }) + + It("adds multiple prefixes", func() { + DefaultLogger.SetLogLevel(LogLevelDebug) + prefixLogger := DefaultLogger.WithPrefix("prefix1") + prefixPrefixLogger := prefixLogger.WithPrefix("prefix2") + prefixPrefixLogger.Debugf("debug") + Expect(b.String()).To(ContainSubstring("prefix")) + Expect(b.String()).To(ContainSubstring("debug")) + }) + + Context("reading from env", func() { + BeforeEach(func() { + Expect(DefaultLogger.(*defaultLogger).logLevel).To(Equal(LogLevelNothing)) + }) + + It("reads DEBUG", func() { + os.Setenv(logEnv, "DEBUG") + Expect(readLoggingEnv()).To(Equal(LogLevelDebug)) + }) + + It("reads debug", func() { + os.Setenv(logEnv, "debug") + Expect(readLoggingEnv()).To(Equal(LogLevelDebug)) + }) + + It("reads INFO", func() { + os.Setenv(logEnv, "INFO") + readLoggingEnv() + Expect(readLoggingEnv()).To(Equal(LogLevelInfo)) + }) + + It("reads ERROR", func() { + os.Setenv(logEnv, "ERROR") + Expect(readLoggingEnv()).To(Equal(LogLevelError)) + }) + + It("does not error reading invalid log levels from env", func() { + os.Setenv(logEnv, "") + Expect(readLoggingEnv()).To(Equal(LogLevelNothing)) + os.Setenv(logEnv, "asdf") + Expect(readLoggingEnv()).To(Equal(LogLevelNothing)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/minmax.go b/vendor/lucas-clemente/quic-go/internal/utils/minmax.go new file mode 100644 index 00000000..4394ab04 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/minmax.go @@ -0,0 +1,147 @@ +package utils + +import ( + "math" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// InfDuration is a duration of infinite length +const InfDuration = time.Duration(math.MaxInt64) + +// Max returns the maximum of two Ints +func Max(a, b int) int { + if a < b { + return b + } + return a +} + +// MaxUint32 returns the maximum of two uint32 +func MaxUint32(a, b uint32) uint32 { + if a < b { + return b + } + return a +} + +// MaxUint64 returns the maximum of two uint64 +func MaxUint64(a, b uint64) uint64 { + if a < b { + return b + } + return a +} + +// MinUint64 returns the maximum of two uint64 +func MinUint64(a, b uint64) uint64 { + if a < b { + return a + } + return b +} + +// Min returns the minimum of two Ints +func Min(a, b int) int { + if a < b { + return a + } + return b +} + +// MinUint32 returns the maximum of two uint32 +func MinUint32(a, b uint32) uint32 { + if a < b { + return a + } + return b +} + +// MinInt64 returns the minimum of two int64 +func MinInt64(a, b int64) int64 { + if a < b { + return a + } + return b +} + +// MaxInt64 returns the minimum of two int64 +func MaxInt64(a, b int64) int64 { + if a > b { + return a + } + return b +} + +// MinByteCount returns the minimum of two ByteCounts +func MinByteCount(a, b protocol.ByteCount) protocol.ByteCount { + if a < b { + return a + } + return b +} + +// MaxByteCount returns the maximum of two ByteCounts +func MaxByteCount(a, b protocol.ByteCount) protocol.ByteCount { + if a < b { + return b + } + return a +} + +// MaxDuration returns the max duration +func MaxDuration(a, b time.Duration) time.Duration { + if a > b { + return a + } + return b +} + +// MinDuration returns the minimum duration +func MinDuration(a, b time.Duration) time.Duration { + if a > b { + return b + } + return a +} + +// AbsDuration returns the absolute value of a time duration +func AbsDuration(d time.Duration) time.Duration { + if d >= 0 { + return d + } + return -d +} + +// MinTime returns the earlier time +func MinTime(a, b time.Time) time.Time { + if a.After(b) { + return b + } + return a +} + +// MaxTime returns the later time +func MaxTime(a, b time.Time) time.Time { + if a.After(b) { + return a + } + return b +} + +// MaxPacketNumber returns the max packet number +func MaxPacketNumber(a, b protocol.PacketNumber) protocol.PacketNumber { + if a > b { + return a + } + return b +} + +// MinPacketNumber returns the min packet number +func MinPacketNumber(a, b protocol.PacketNumber) protocol.PacketNumber { + if a < b { + return a + } + return b +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/minmax_test.go b/vendor/lucas-clemente/quic-go/internal/utils/minmax_test.go new file mode 100644 index 00000000..95816372 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/minmax_test.go @@ -0,0 +1,104 @@ +package utils + +import ( + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Min / Max", func() { + Context("Max", func() { + It("returns the maximum", func() { + Expect(Max(5, 7)).To(Equal(7)) + Expect(Max(7, 5)).To(Equal(7)) + }) + + It("returns the maximum uint32", func() { + Expect(MaxUint32(5, 7)).To(Equal(uint32(7))) + Expect(MaxUint32(7, 5)).To(Equal(uint32(7))) + }) + + It("returns the maximum uint64", func() { + Expect(MaxUint64(5, 7)).To(Equal(uint64(7))) + Expect(MaxUint64(7, 5)).To(Equal(uint64(7))) + }) + + It("returns the minimum uint64", func() { + Expect(MinUint64(5, 7)).To(Equal(uint64(5))) + Expect(MinUint64(7, 5)).To(Equal(uint64(5))) + }) + + It("returns the maximum int64", func() { + Expect(MaxInt64(5, 7)).To(Equal(int64(7))) + Expect(MaxInt64(7, 5)).To(Equal(int64(7))) + }) + + It("returns the maximum ByteCount", func() { + Expect(MaxByteCount(7, 5)).To(Equal(protocol.ByteCount(7))) + Expect(MaxByteCount(5, 7)).To(Equal(protocol.ByteCount(7))) + }) + + It("returns the maximum duration", func() { + Expect(MaxDuration(time.Microsecond, time.Nanosecond)).To(Equal(time.Microsecond)) + Expect(MaxDuration(time.Nanosecond, time.Microsecond)).To(Equal(time.Microsecond)) + }) + + It("returns the minimum duration", func() { + Expect(MinDuration(time.Microsecond, time.Nanosecond)).To(Equal(time.Nanosecond)) + Expect(MinDuration(time.Nanosecond, time.Microsecond)).To(Equal(time.Nanosecond)) + }) + + It("returns packet number max", func() { + Expect(MaxPacketNumber(1, 2)).To(Equal(protocol.PacketNumber(2))) + Expect(MaxPacketNumber(2, 1)).To(Equal(protocol.PacketNumber(2))) + }) + + It("returns the maximum time", func() { + a := time.Now() + b := a.Add(time.Second) + Expect(MaxTime(a, b)).To(Equal(b)) + Expect(MaxTime(b, a)).To(Equal(b)) + }) + }) + + Context("Min", func() { + It("returns the minimum", func() { + Expect(Min(5, 7)).To(Equal(5)) + Expect(Min(7, 5)).To(Equal(5)) + }) + + It("returns the minimum uint32", func() { + Expect(MinUint32(7, 5)).To(Equal(uint32(5))) + Expect(MinUint32(5, 7)).To(Equal(uint32(5))) + }) + + It("returns the minimum int64", func() { + Expect(MinInt64(7, 5)).To(Equal(int64(5))) + Expect(MinInt64(5, 7)).To(Equal(int64(5))) + }) + + It("returns the minimum ByteCount", func() { + Expect(MinByteCount(7, 5)).To(Equal(protocol.ByteCount(5))) + Expect(MinByteCount(5, 7)).To(Equal(protocol.ByteCount(5))) + }) + + It("returns packet number min", func() { + Expect(MinPacketNumber(1, 2)).To(Equal(protocol.PacketNumber(1))) + Expect(MinPacketNumber(2, 1)).To(Equal(protocol.PacketNumber(1))) + }) + + It("returns the minimum time", func() { + a := time.Now() + b := a.Add(time.Second) + Expect(MinTime(a, b)).To(Equal(a)) + Expect(MinTime(b, a)).To(Equal(a)) + }) + }) + + It("returns the abs time", func() { + Expect(AbsDuration(time.Microsecond)).To(Equal(time.Microsecond)) + Expect(AbsDuration(-time.Microsecond)).To(Equal(time.Microsecond)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/packet_interval.go b/vendor/lucas-clemente/quic-go/internal/utils/packet_interval.go new file mode 100644 index 00000000..62cc8b9c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/packet_interval.go @@ -0,0 +1,9 @@ +package utils + +import "github.com/lucas-clemente/quic-go/internal/protocol" + +// PacketInterval is an interval from one PacketNumber to the other +type PacketInterval struct { + Start protocol.PacketNumber + End protocol.PacketNumber +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/packetinterval_linkedlist.go b/vendor/lucas-clemente/quic-go/internal/utils/packetinterval_linkedlist.go new file mode 100644 index 00000000..b461e85a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/packetinterval_linkedlist.go @@ -0,0 +1,217 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package utils + +// Linked list implementation from the Go standard library. + +// PacketIntervalElement is an element of a linked list. +type PacketIntervalElement struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *PacketIntervalElement + + // The list to which this element belongs. + list *PacketIntervalList + + // The value stored with this element. + Value PacketInterval +} + +// Next returns the next list element or nil. +func (e *PacketIntervalElement) Next() *PacketIntervalElement { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// Prev returns the previous list element or nil. +func (e *PacketIntervalElement) Prev() *PacketIntervalElement { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// PacketIntervalList is a linked list of PacketIntervals. +type PacketIntervalList struct { + root PacketIntervalElement // sentinel list element, only &root, root.prev, and root.next are used + len int // current list length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *PacketIntervalList) Init() *PacketIntervalList { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// NewPacketIntervalList returns an initialized list. +func NewPacketIntervalList() *PacketIntervalList { return new(PacketIntervalList).Init() } + +// Len returns the number of elements of list l. +// The complexity is O(1). +func (l *PacketIntervalList) Len() int { return l.len } + +// Front returns the first element of list l or nil if the list is empty. +func (l *PacketIntervalList) Front() *PacketIntervalElement { + if l.len == 0 { + return nil + } + return l.root.next +} + +// Back returns the last element of list l or nil if the list is empty. +func (l *PacketIntervalList) Back() *PacketIntervalElement { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero List value. +func (l *PacketIntervalList) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *PacketIntervalList) insert(e, at *PacketIntervalElement) *PacketIntervalElement { + n := at.next + at.next = e + e.prev = at + e.next = n + n.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). +func (l *PacketIntervalList) insertValue(v PacketInterval, at *PacketIntervalElement) *PacketIntervalElement { + return l.insert(&PacketIntervalElement{Value: v}, at) +} + +// remove removes e from its list, decrements l.len, and returns e. +func (l *PacketIntervalList) remove(e *PacketIntervalElement) *PacketIntervalElement { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + return e +} + +// Remove removes e from l if e is an element of list l. +// It returns the element value e.Value. +// The element must not be nil. +func (l *PacketIntervalList) Remove(e *PacketIntervalElement) PacketInterval { + if e.list == l { + // if e.list == l, l must have been initialized when e was inserted + // in l or l == nil (e is a zero Element) and l.remove will crash + l.remove(e) + } + return e.Value +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *PacketIntervalList) PushFront(v PacketInterval) *PacketIntervalElement { + l.lazyInit() + return l.insertValue(v, &l.root) +} + +// PushBack inserts a new element e with value v at the back of list l and returns e. +func (l *PacketIntervalList) PushBack(v PacketInterval) *PacketIntervalElement { + l.lazyInit() + return l.insertValue(v, l.root.prev) +} + +// InsertBefore inserts a new element e with value v immediately before mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *PacketIntervalList) InsertBefore(v PacketInterval, mark *PacketIntervalElement) *PacketIntervalElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark.prev) +} + +// InsertAfter inserts a new element e with value v immediately after mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *PacketIntervalList) InsertAfter(v PacketInterval, mark *PacketIntervalElement) *PacketIntervalElement { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *PacketIntervalList) MoveToFront(e *PacketIntervalElement) { + if e.list != l || l.root.next == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), &l.root) +} + +// MoveToBack moves element e to the back of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *PacketIntervalList) MoveToBack(e *PacketIntervalElement) { + if e.list != l || l.root.prev == e { + return + } + // see comment in List.Remove about initialization of l + l.insert(l.remove(e), l.root.prev) +} + +// MoveBefore moves element e to its new position before mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *PacketIntervalList) MoveBefore(e, mark *PacketIntervalElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark.prev) +} + +// MoveAfter moves element e to its new position after mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *PacketIntervalList) MoveAfter(e, mark *PacketIntervalElement) { + if e.list != l || e == mark || mark.list != l { + return + } + l.insert(l.remove(e), mark) +} + +// PushBackList inserts a copy of an other list at the back of list l. +// The lists l and other may be the same. They must not be nil. +func (l *PacketIntervalList) PushBackList(other *PacketIntervalList) { + l.lazyInit() + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +// PushFrontList inserts a copy of an other list at the front of list l. +// The lists l and other may be the same. They must not be nil. +func (l *PacketIntervalList) PushFrontList(other *PacketIntervalList) { + l.lazyInit() + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, &l.root) + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/streamframe_interval.go b/vendor/lucas-clemente/quic-go/internal/utils/streamframe_interval.go new file mode 100644 index 00000000..ec16d251 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/streamframe_interval.go @@ -0,0 +1,9 @@ +package utils + +import "github.com/lucas-clemente/quic-go/internal/protocol" + +// ByteInterval is an interval from one ByteCount to the other +type ByteInterval struct { + Start protocol.ByteCount + End protocol.ByteCount +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/timer.go b/vendor/lucas-clemente/quic-go/internal/utils/timer.go new file mode 100644 index 00000000..20eaacd0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/timer.go @@ -0,0 +1,43 @@ +package utils + +import "time" + +// A Timer wrapper that behaves correctly when resetting +type Timer struct { + t *time.Timer + read bool + deadline time.Time +} + +// NewTimer creates a new timer that is not set +func NewTimer() *Timer { + return &Timer{t: time.NewTimer(0)} +} + +// Chan returns the channel of the wrapped timer +func (t *Timer) Chan() <-chan time.Time { + return t.t.C +} + +// Reset the timer, no matter whether the value was read or not +func (t *Timer) Reset(deadline time.Time) { + if deadline.Equal(t.deadline) && !t.read { + // No need to reset the timer + return + } + + // We need to drain the timer if the value from its channel was not read yet. + // See https://groups.google.com/forum/#!topic/golang-dev/c9UUfASVPoU + if !t.t.Stop() && !t.read { + <-t.t.C + } + t.t.Reset(time.Until(deadline)) + + t.read = false + t.deadline = deadline +} + +// SetRead should be called after the value from the chan was read +func (t *Timer) SetRead() { + t.read = true +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/timer_test.go b/vendor/lucas-clemente/quic-go/internal/utils/timer_test.go new file mode 100644 index 00000000..c1581919 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/timer_test.go @@ -0,0 +1,69 @@ +package utils + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Timer", func() { + const d = 10 * time.Millisecond + + It("works", func() { + t := NewTimer() + t.Reset(time.Now().Add(d)) + Eventually(t.Chan()).Should(Receive()) + }) + + It("works multiple times with reading", func() { + t := NewTimer() + for i := 0; i < 10; i++ { + t.Reset(time.Now().Add(d)) + Eventually(t.Chan()).Should(Receive()) + t.SetRead() + } + }) + + It("works multiple times without reading", func() { + t := NewTimer() + for i := 0; i < 10; i++ { + t.Reset(time.Now().Add(d)) + time.Sleep(d * 2) + } + Eventually(t.Chan()).Should(Receive()) + }) + + It("works when resetting without expiration", func() { + t := NewTimer() + for i := 0; i < 10; i++ { + t.Reset(time.Now().Add(time.Hour)) + } + t.Reset(time.Now().Add(d)) + Eventually(t.Chan()).Should(Receive()) + }) + + It("immediately fires the timer, if the deadlines has already passed", func() { + t := NewTimer() + t.Reset(time.Now().Add(-time.Second)) + Eventually(t.Chan()).Should(Receive()) + }) + + It("fires the timer twice, if reset to the same deadline", func() { + deadline := time.Now().Add(-time.Millisecond) + t := NewTimer() + t.Reset(deadline) + Eventually(t.Chan()).Should(Receive()) + t.SetRead() + t.Reset(deadline) + Eventually(t.Chan()).Should(Receive()) + }) + + It("only fires the timer once, if it is reset to the same deadline, but not read in between", func() { + deadline := time.Now().Add(-time.Millisecond) + t := NewTimer() + t.Reset(deadline) + Eventually(t.Chan()).Should(Receive()) + Consistently(t.Chan()).ShouldNot(Receive()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/utils_suite_test.go b/vendor/lucas-clemente/quic-go/internal/utils/utils_suite_test.go new file mode 100644 index 00000000..2874819b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/utils_suite_test.go @@ -0,0 +1,13 @@ +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCrypto(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Utils Suite") +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/varint.go b/vendor/lucas-clemente/quic-go/internal/utils/varint.go new file mode 100644 index 00000000..35e8674e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/varint.go @@ -0,0 +1,101 @@ +package utils + +import ( + "bytes" + "fmt" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// taken from the QUIC draft +const ( + maxVarInt1 = 63 + maxVarInt2 = 16383 + maxVarInt4 = 1073741823 + maxVarInt8 = 4611686018427387903 +) + +// ReadVarInt reads a number in the QUIC varint format +func ReadVarInt(b io.ByteReader) (uint64, error) { + firstByte, err := b.ReadByte() + if err != nil { + return 0, err + } + // the first two bits of the first byte encode the length + len := 1 << ((firstByte & 0xc0) >> 6) + b1 := firstByte & (0xff - 0xc0) + if len == 1 { + return uint64(b1), nil + } + b2, err := b.ReadByte() + if err != nil { + return 0, err + } + if len == 2 { + return uint64(b2) + uint64(b1)<<8, nil + } + b3, err := b.ReadByte() + if err != nil { + return 0, err + } + b4, err := b.ReadByte() + if err != nil { + return 0, err + } + if len == 4 { + return uint64(b4) + uint64(b3)<<8 + uint64(b2)<<16 + uint64(b1)<<24, nil + } + b5, err := b.ReadByte() + if err != nil { + return 0, err + } + b6, err := b.ReadByte() + if err != nil { + return 0, err + } + b7, err := b.ReadByte() + if err != nil { + return 0, err + } + b8, err := b.ReadByte() + if err != nil { + return 0, err + } + return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil +} + +// WriteVarInt writes a number in the QUIC varint format +func WriteVarInt(b *bytes.Buffer, i uint64) { + if i <= maxVarInt1 { + b.WriteByte(uint8(i)) + } else if i <= maxVarInt2 { + b.Write([]byte{uint8(i>>8) | 0x40, uint8(i)}) + } else if i <= maxVarInt4 { + b.Write([]byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}) + } else if i <= maxVarInt8 { + b.Write([]byte{ + uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32), + uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), + }) + } else { + panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i)) + } +} + +// VarIntLen determines the number of bytes that will be needed to write a number +func VarIntLen(i uint64) protocol.ByteCount { + if i <= maxVarInt1 { + return 1 + } + if i <= maxVarInt2 { + return 2 + } + if i <= maxVarInt4 { + return 4 + } + if i <= maxVarInt8 { + return 8 + } + panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber.go b/vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber.go new file mode 100644 index 00000000..b05afd4b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber.go @@ -0,0 +1,50 @@ +package utils + +import ( + "bytes" + "fmt" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// ReadVarIntPacketNumber reads a number in the QUIC varint packet number format +func ReadVarIntPacketNumber(b *bytes.Reader) (protocol.PacketNumber, protocol.PacketNumberLen, error) { + b1, err := b.ReadByte() + if err != nil { + return 0, 0, err + } + if b1&0x80 == 0 { + return protocol.PacketNumber(b1), protocol.PacketNumberLen1, nil + } + b2, err := b.ReadByte() + if err != nil { + return 0, 0, err + } + if b1&0x40 == 0 { + return protocol.PacketNumber(uint64(b1&0x3f)<<8 + uint64(b2)), protocol.PacketNumberLen2, nil + } + b3, err := b.ReadByte() + if err != nil { + return 0, 0, err + } + b4, err := b.ReadByte() + if err != nil { + return 0, 0, err + } + return protocol.PacketNumber(uint64(b1&0x3f)<<24 + uint64(b2)<<16 + uint64(b3)<<8 + uint64(b4)), protocol.PacketNumberLen4, nil +} + +// WriteVarIntPacketNumber writes a packet number in the QUIC varint packet number format +func WriteVarIntPacketNumber(b *bytes.Buffer, i protocol.PacketNumber, len protocol.PacketNumberLen) error { + switch len { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(i & 0x7f)) + case protocol.PacketNumberLen2: + b.Write([]byte{(uint8(i>>8) & 0x3f) | 0x80, uint8(i)}) + case protocol.PacketNumberLen4: + b.Write([]byte{(uint8(i>>24) & 0x3f) | 0xc0, uint8(i >> 16), uint8(i >> 8), uint8(i)}) + default: + return fmt.Errorf("invalid packet number length: %d", len) + } + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber_test.go b/vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber_test.go new file mode 100644 index 00000000..d743b1ae --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/varint_packetnumber_test.go @@ -0,0 +1,157 @@ +package utils + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Varint packet number encoding / decoding", func() { + Context("Decoding", func() { + It("reads a 1 byte number", func() { + b := bytes.NewReader([]byte{0x19}) // 00011001 + p, len, err := ReadVarIntPacketNumber(b) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen1)) + Expect(p).To(Equal(protocol.PacketNumber(0x19))) + }) + + It("errors when given an empty reader", func() { + _, _, err := ReadVarIntPacketNumber(bytes.NewReader(nil)) + Expect(err).To(MatchError(io.EOF)) + }) + + It("reads a 2 byte number", func() { + b := bytes.NewReader([]byte{0xb7, 0x19}) // first byte: 10110111 + p, len, err := ReadVarIntPacketNumber(b) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen2)) + Expect(p).To(Equal(protocol.PacketNumber(0x3719))) + }) + + It("errors on EOF when reading a 2 byte number", func() { + b := bytes.NewReader([]byte{0xb7}) // first byte: 10110111 + _, _, err := ReadVarIntPacketNumber(b) + Expect(err).To(MatchError(io.EOF)) + }) + + It("reads a 4 byte number", func() { + b := bytes.NewReader([]byte{0xe5, 0x89, 0xfa, 0x19}) // first byte: 11100101 + p, len, err := ReadVarIntPacketNumber(b) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen4)) + Expect(p).To(Equal(protocol.PacketNumber(0x2589fa19))) + }) + + It("errors on EOF after the 3rd byte when reading a 4 byte number", func() { + b := bytes.NewReader([]byte{0xe5, 0x89}) // first byte: 11100101 + _, _, err := ReadVarIntPacketNumber(b) + Expect(err).To(MatchError(io.EOF)) + }) + + It("errors on EOF after the 4th byte when reading a 4 byte number", func() { + b := bytes.NewReader([]byte{0xe5, 0x89, 0xfa}) // first byte: 11100101 + _, _, err := ReadVarIntPacketNumber(b) + Expect(err).To(MatchError(io.EOF)) + }) + }) + + Context("Encoding", func() { + It("writes a 1 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x42, protocol.PacketNumberLen1) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(1)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen1)) + Expect(p).To(Equal(protocol.PacketNumber(0x42))) + }) + + It("only uses the least significant 7 bits when writing a 1 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x1234ea, protocol.PacketNumberLen1) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(1)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen1)) + Expect(p).To(Equal(protocol.PacketNumber(0x6a))) + }) + + It("writes a small 2 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x42, protocol.PacketNumberLen2) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(2)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen2)) + Expect(p).To(Equal(protocol.PacketNumber(0x42))) + }) + + It("writes a 2 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x1337, protocol.PacketNumberLen2) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(2)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen2)) + Expect(p).To(Equal(protocol.PacketNumber(0x1337))) + }) + + It("only uses the least significant 14 bits when writing a 2 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x1234ff37, protocol.PacketNumberLen2) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(2)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen2)) + Expect(p).To(Equal(protocol.PacketNumber(0x3f37))) + }) + + It("writes a small 4 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0xbeef, protocol.PacketNumberLen4) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(4)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen4)) + Expect(p).To(Equal(protocol.PacketNumber(0xbeef))) + }) + + It("writes a 4 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x12beef42, protocol.PacketNumberLen4) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(4)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen4)) + Expect(p).To(Equal(protocol.PacketNumber(0x12beef42))) + }) + + It("only uses the least significant 30 bits when writing a 4 byte packet number", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x1234deadbeef, protocol.PacketNumberLen4) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(4)) + p, len, err := ReadVarIntPacketNumber(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(len).To(Equal(protocol.PacketNumberLen4)) + Expect(p).To(Equal(protocol.PacketNumber(0x1eadbeef))) + }) + + It("errors when encountering invalid packet number lengths", func() { + b := &bytes.Buffer{} + err := WriteVarIntPacketNumber(b, 0x1234deadbeef, 13) + Expect(err).To(MatchError("invalid packet number length: 13")) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/utils/varint_test.go b/vendor/lucas-clemente/quic-go/internal/utils/varint_test.go new file mode 100644 index 00000000..b49774f0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/utils/varint_test.go @@ -0,0 +1,157 @@ +package utils + +import ( + "bytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Varint encoding / decoding", func() { + Context("decoding", func() { + It("reads a 1 byte number", func() { + b := bytes.NewReader([]byte{25}) // 00011001 + val, err := ReadVarInt(b) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint64(25))) + Expect(b.Len()).To(BeZero()) + }) + + It("reads a number that is encoded too long", func() { + b := bytes.NewReader([]byte{0x40, 0x25}) // first byte: 01000000 + val, err := ReadVarInt(b) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint64(37))) + Expect(b.Len()).To(BeZero()) + }) + + It("reads a 2 byte number", func() { + b := bytes.NewReader([]byte{0x7b, 0xbd}) // first byte: 01111011 + val, err := ReadVarInt(b) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint64(15293))) + Expect(b.Len()).To(BeZero()) + }) + + It("reads a 4 byte number", func() { + b := bytes.NewReader([]byte{0x9d, 0x7f, 0x3e, 0x7d}) // first byte: 10011011 + val, err := ReadVarInt(b) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint64(494878333))) + Expect(b.Len()).To(BeZero()) + }) + + It("reads an 8 byte number", func() { + b := bytes.NewReader([]byte{0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c}) // first byte: 10000010 + val, err := ReadVarInt(b) + Expect(err).ToNot(HaveOccurred()) + Expect(val).To(Equal(uint64(151288809941952652))) + Expect(b.Len()).To(BeZero()) + }) + }) + + Context("encoding", func() { + It("writes a 1 byte number", func() { + b := &bytes.Buffer{} + WriteVarInt(b, 37) + Expect(b.Bytes()).To(Equal([]byte{0x25})) + }) + + It("writes the maximum 1 byte number in 1 byte", func() { + b := &bytes.Buffer{} + WriteVarInt(b, maxVarInt1) + Expect(b.Bytes()).To(Equal([]byte{0x3f /* 00111111 */})) + }) + + It("writes the minimum 2 byte number in 2 bytes", func() { + b := &bytes.Buffer{} + WriteVarInt(b, maxVarInt1+1) + Expect(b.Bytes()).To(Equal([]byte{0x40, maxVarInt1 + 1})) + }) + + It("writes a 2 byte number", func() { + b := &bytes.Buffer{} + WriteVarInt(b, 15293) + Expect(b.Bytes()).To(Equal([]byte{0x7b, 0xbd})) + }) + + It("writes the maximum 2 byte number in 2 bytes", func() { + b := &bytes.Buffer{} + WriteVarInt(b, maxVarInt2) + Expect(b.Bytes()).To(Equal([]byte{0x7f /* 01111111 */, 0xff})) + }) + + It("writes the minimum 4 byte number in 4 bytes", func() { + b := &bytes.Buffer{} + WriteVarInt(b, maxVarInt2+1) + Expect(b.Len()).To(Equal(4)) + num, err := ReadVarInt(b) + Expect(err).ToNot(HaveOccurred()) + Expect(num).To(Equal(uint64(maxVarInt2 + 1))) + }) + + It("writes a 4 byte number", func() { + b := &bytes.Buffer{} + WriteVarInt(b, 494878333) + Expect(b.Bytes()).To(Equal([]byte{0x9d, 0x7f, 0x3e, 0x7d})) + }) + + It("writes the maximum 4 byte number in 4 bytes", func() { + b := &bytes.Buffer{} + WriteVarInt(b, maxVarInt4) + Expect(b.Bytes()).To(Equal([]byte{0xbf /* 10111111 */, 0xff, 0xff, 0xff})) + }) + + It("writes the minimum 8 byte number in 8 bytes", func() { + b := &bytes.Buffer{} + WriteVarInt(b, maxVarInt4+1) + Expect(b.Len()).To(Equal(8)) + num, err := ReadVarInt(b) + Expect(err).ToNot(HaveOccurred()) + Expect(num).To(Equal(uint64(maxVarInt4 + 1))) + }) + + It("writes an 8 byte number", func() { + b := &bytes.Buffer{} + WriteVarInt(b, 151288809941952652) + Expect(b.Bytes()).To(Equal([]byte{0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c})) + }) + + It("writes the maximum 8 byte number in 8 bytes", func() { + b := &bytes.Buffer{} + WriteVarInt(b, maxVarInt8) + Expect(b.Bytes()).To(Equal([]byte{0xff /* 11111111 */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})) + }) + + It("panics when given a too large number (> 62 bit)", func() { + b := &bytes.Buffer{} + Expect(func() { WriteVarInt(b, maxVarInt8+1) }).Should(Panic()) + }) + }) + + Context("determining the length needed for encoding", func() { + It("for numbers that need 1 byte", func() { + Expect(VarIntLen(0)).To(BeEquivalentTo(1)) + Expect(VarIntLen(maxVarInt1)).To(BeEquivalentTo(1)) + }) + + It("for numbers that need 2 bytes", func() { + Expect(VarIntLen(maxVarInt1 + 1)).To(BeEquivalentTo(2)) + Expect(VarIntLen(maxVarInt2)).To(BeEquivalentTo(2)) + }) + + It("for numbers that need 4 bytes", func() { + Expect(VarIntLen(maxVarInt2 + 1)).To(BeEquivalentTo(4)) + Expect(VarIntLen(maxVarInt4)).To(BeEquivalentTo(4)) + }) + + It("for numbers that need 8 bytes", func() { + Expect(VarIntLen(maxVarInt4 + 1)).To(BeEquivalentTo(8)) + Expect(VarIntLen(maxVarInt8)).To(BeEquivalentTo(8)) + }) + + It("panics when given a too large number (> 62 bit)", func() { + Expect(func() { VarIntLen(maxVarInt8 + 1) }).Should(Panic()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ack_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame.go new file mode 100644 index 00000000..00759db4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame.go @@ -0,0 +1,243 @@ +package wire + +import ( + "bytes" + "errors" + "sort" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// TODO: use the value sent in the transport parameters +const ackDelayExponent = 3 + +// An AckFrame is an ACK frame +type AckFrame struct { + AckRanges []AckRange // has to be ordered. The highest ACK range goes first, the lowest ACK range goes last + DelayTime time.Duration +} + +func parseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { + return parseAckOrAckEcnFrame(r, false, version) +} + +func parseAckEcnFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { + return parseAckOrAckEcnFrame(r, true, version) +} + +// parseAckFrame reads an ACK frame +func parseAckOrAckEcnFrame(r *bytes.Reader, ecn bool, version protocol.VersionNumber) (*AckFrame, error) { + if !version.UsesIETFFrameFormat() { + return parseAckFrameLegacy(r, version) + } + + if _, err := r.ReadByte(); err != nil { + return nil, err + } + + frame := &AckFrame{} + + la, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + largestAcked := protocol.PacketNumber(la) + delay, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + frame.DelayTime = time.Duration(delay*1< largestAcked { + return nil, errors.New("invalid first ACK range") + } + smallest := largestAcked - ackBlock + + // read all the other ACK ranges + frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largestAcked}) + for i := uint64(0); i < numBlocks; i++ { + g, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + gap := protocol.PacketNumber(g) + if smallest < gap+2 { + return nil, errInvalidAckRanges + } + largest := smallest - gap - 2 + + ab, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + ackBlock := protocol.PacketNumber(ab) + + if ackBlock > largest { + return nil, errInvalidAckRanges + } + smallest = largest - ackBlock + frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largest}) + } + + if !frame.validateAckRanges() { + return nil, errInvalidAckRanges + } + return frame, nil +} + +// Write writes an ACK frame. +func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + if !version.UsesIETFFrameFormat() { + return f.writeLegacy(b, version) + } + + b.WriteByte(0x0d) + utils.WriteVarInt(b, uint64(f.LargestAcked())) + utils.WriteVarInt(b, encodeAckDelay(f.DelayTime)) + + numRanges := f.numEncodableAckRanges() + utils.WriteVarInt(b, uint64(numRanges-1)) + + // write the first range + _, firstRange := f.encodeAckRange(0) + utils.WriteVarInt(b, firstRange) + + // write all the other range + for i := 1; i < numRanges; i++ { + gap, len := f.encodeAckRange(i) + utils.WriteVarInt(b, gap) + utils.WriteVarInt(b, len) + } + return nil +} + +// Length of a written frame +func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + if !version.UsesIETFFrameFormat() { + return f.lengthLegacy(version) + } + + largestAcked := f.AckRanges[0].Largest + numRanges := f.numEncodableAckRanges() + + length := 1 + utils.VarIntLen(uint64(largestAcked)) + utils.VarIntLen(encodeAckDelay(f.DelayTime)) + + length += utils.VarIntLen(uint64(numRanges - 1)) + lowestInFirstRange := f.AckRanges[0].Smallest + length += utils.VarIntLen(uint64(largestAcked - lowestInFirstRange)) + + for i := 1; i < numRanges; i++ { + gap, len := f.encodeAckRange(i) + length += utils.VarIntLen(gap) + length += utils.VarIntLen(len) + } + return length +} + +// gets the number of ACK ranges that can be encoded +// such that the resulting frame is smaller than the maximum ACK frame size +func (f *AckFrame) numEncodableAckRanges() int { + length := 1 + utils.VarIntLen(uint64(f.LargestAcked())) + utils.VarIntLen(encodeAckDelay(f.DelayTime)) + length += 2 // assume that the number of ranges will consume 2 bytes + for i := 1; i < len(f.AckRanges); i++ { + gap, len := f.encodeAckRange(i) + rangeLen := utils.VarIntLen(gap) + utils.VarIntLen(len) + if length+rangeLen > protocol.MaxAckFrameSize { + // Writing range i would exceed the MaxAckFrameSize. + // So encode one range less than that. + return i - 1 + } + length += rangeLen + } + return len(f.AckRanges) +} + +func (f *AckFrame) encodeAckRange(i int) (uint64 /* gap */, uint64 /* length */) { + if i == 0 { + return 0, uint64(f.AckRanges[0].Largest - f.AckRanges[0].Smallest) + } + return uint64(f.AckRanges[i-1].Smallest - f.AckRanges[i].Largest - 2), + uint64(f.AckRanges[i].Largest - f.AckRanges[i].Smallest) +} + +// HasMissingRanges returns if this frame reports any missing packets +func (f *AckFrame) HasMissingRanges() bool { + return len(f.AckRanges) > 1 +} + +func (f *AckFrame) validateAckRanges() bool { + if len(f.AckRanges) == 0 { + return false + } + + // check the validity of every single ACK range + for _, ackRange := range f.AckRanges { + if ackRange.Smallest > ackRange.Largest { + return false + } + } + + // check the consistency for ACK with multiple NACK ranges + for i, ackRange := range f.AckRanges { + if i == 0 { + continue + } + lastAckRange := f.AckRanges[i-1] + if lastAckRange.Smallest <= ackRange.Smallest { + return false + } + if lastAckRange.Smallest <= ackRange.Largest+1 { + return false + } + } + + return true +} + +// LargestAcked is the largest acked packet number +func (f *AckFrame) LargestAcked() protocol.PacketNumber { + return f.AckRanges[0].Largest +} + +// LowestAcked is the lowest acked packet number +func (f *AckFrame) LowestAcked() protocol.PacketNumber { + return f.AckRanges[len(f.AckRanges)-1].Smallest +} + +// AcksPacket determines if this ACK frame acks a certain packet number +func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool { + if p < f.LowestAcked() || p > f.LargestAcked() { + return false + } + + i := sort.Search(len(f.AckRanges), func(i int) bool { + return p >= f.AckRanges[i].Smallest + }) + // i will always be < len(f.AckRanges), since we checked above that p is not bigger than the largest acked + return p <= f.AckRanges[i].Largest +} + +func encodeAckDelay(delay time.Duration) uint64 { + return uint64(delay.Nanoseconds() / (1000 * (1 << ackDelayExponent))) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy.go b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy.go new file mode 100644 index 00000000..c2a71e0b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy.go @@ -0,0 +1,364 @@ +package wire + +import ( + "bytes" + "errors" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +var errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges") + +func parseAckFrameLegacy(r *bytes.Reader, _ protocol.VersionNumber) (*AckFrame, error) { + frame := &AckFrame{} + + typeByte, err := r.ReadByte() + if err != nil { + return nil, err + } + + hasMissingRanges := typeByte&0x20 == 0x20 + largestAckedLen := 2 * ((typeByte & 0x0C) >> 2) + if largestAckedLen == 0 { + largestAckedLen = 1 + } + + missingSequenceNumberDeltaLen := 2 * (typeByte & 0x03) + if missingSequenceNumberDeltaLen == 0 { + missingSequenceNumberDeltaLen = 1 + } + + la, err := utils.BigEndian.ReadUintN(r, largestAckedLen) + if err != nil { + return nil, err + } + largestAcked := protocol.PacketNumber(la) + + delay, err := utils.BigEndian.ReadUfloat16(r) + if err != nil { + return nil, err + } + frame.DelayTime = time.Duration(delay) * time.Microsecond + + var numAckBlocks uint8 + if hasMissingRanges { + numAckBlocks, err = r.ReadByte() + if err != nil { + return nil, err + } + } + + if hasMissingRanges && numAckBlocks == 0 { + return nil, errInvalidAckRanges + } + + abl, err := utils.BigEndian.ReadUintN(r, missingSequenceNumberDeltaLen) + if err != nil { + return nil, err + } + ackBlockLength := protocol.PacketNumber(abl) + if largestAcked > 0 && ackBlockLength < 1 { + return nil, errors.New("invalid first ACK range") + } + + if ackBlockLength > largestAcked+1 { + return nil, errInvalidAckRanges + } + + if hasMissingRanges { + ackRange := AckRange{ + Smallest: largestAcked - ackBlockLength + 1, + Largest: largestAcked, + } + frame.AckRanges = append(frame.AckRanges, ackRange) + + var inLongBlock bool + var lastRangeComplete bool + for i := uint8(0); i < numAckBlocks; i++ { + var gap uint8 + gap, err = r.ReadByte() + if err != nil { + return nil, err + } + + abl, err := utils.BigEndian.ReadUintN(r, missingSequenceNumberDeltaLen) + if err != nil { + return nil, err + } + ackBlockLength := protocol.PacketNumber(abl) + + if inLongBlock { + frame.AckRanges[len(frame.AckRanges)-1].Smallest -= protocol.PacketNumber(gap) + ackBlockLength + frame.AckRanges[len(frame.AckRanges)-1].Largest -= protocol.PacketNumber(gap) + } else { + lastRangeComplete = false + ackRange := AckRange{ + Largest: frame.AckRanges[len(frame.AckRanges)-1].Smallest - protocol.PacketNumber(gap) - 1, + } + ackRange.Smallest = ackRange.Largest - ackBlockLength + 1 + frame.AckRanges = append(frame.AckRanges, ackRange) + } + + if ackBlockLength > 0 { + lastRangeComplete = true + } + inLongBlock = (ackBlockLength == 0) + } + + // if the last range was not complete, First and Last make no sense + // remove the range from frame.AckRanges + if !lastRangeComplete { + frame.AckRanges = frame.AckRanges[:len(frame.AckRanges)-1] + } + } else { + frame.AckRanges = make([]AckRange, 1) + if largestAcked != 0 { + frame.AckRanges[0].Largest = largestAcked + frame.AckRanges[0].Smallest = largestAcked + 1 - ackBlockLength + } + } + + if !frame.validateAckRanges() { + return nil, errInvalidAckRanges + } + + var numTimestamp byte + numTimestamp, err = r.ReadByte() + if err != nil { + return nil, err + } + + if numTimestamp > 0 { + // Delta Largest acked + _, err = r.ReadByte() + if err != nil { + return nil, err + } + // First Timestamp + _, err = utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + + for i := 0; i < int(numTimestamp)-1; i++ { + // Delta Largest acked + _, err = r.ReadByte() + if err != nil { + return nil, err + } + + // Time Since Previous Timestamp + _, err = utils.BigEndian.ReadUint16(r) + if err != nil { + return nil, err + } + } + } + return frame, nil +} + +func (f *AckFrame) writeLegacy(b *bytes.Buffer, _ protocol.VersionNumber) error { + largestAcked := f.LargestAcked() + largestAckedLen := protocol.GetPacketNumberLength(largestAcked) + + typeByte := uint8(0x40) + + if largestAckedLen != protocol.PacketNumberLen1 { + typeByte ^= (uint8(largestAckedLen / 2)) << 2 + } + + missingSequenceNumberDeltaLen := f.getMissingSequenceNumberDeltaLen() + if missingSequenceNumberDeltaLen != protocol.PacketNumberLen1 { + typeByte ^= (uint8(missingSequenceNumberDeltaLen / 2)) + } + + if f.HasMissingRanges() { + typeByte |= 0x20 + } + + b.WriteByte(typeByte) + + switch largestAckedLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(largestAcked)) + case protocol.PacketNumberLen2: + utils.BigEndian.WriteUint16(b, uint16(largestAcked)) + case protocol.PacketNumberLen4: + utils.BigEndian.WriteUint32(b, uint32(largestAcked)) + case protocol.PacketNumberLen6: + utils.BigEndian.WriteUint48(b, uint64(largestAcked)&(1<<48-1)) + } + + utils.BigEndian.WriteUfloat16(b, uint64(f.DelayTime/time.Microsecond)) + + var numRanges uint64 + var numRangesWritten uint64 + if f.HasMissingRanges() { + numRanges = f.numWritableNackRanges() + if numRanges > 0xFF { + panic("AckFrame: Too many ACK ranges") + } + b.WriteByte(uint8(numRanges - 1)) + } + + var firstAckBlockLength protocol.PacketNumber + if !f.HasMissingRanges() { + firstAckBlockLength = largestAcked - f.LowestAcked() + 1 + } else { + firstAckBlockLength = largestAcked - f.AckRanges[0].Smallest + 1 + numRangesWritten++ + } + + switch missingSequenceNumberDeltaLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(firstAckBlockLength)) + case protocol.PacketNumberLen2: + utils.BigEndian.WriteUint16(b, uint16(firstAckBlockLength)) + case protocol.PacketNumberLen4: + utils.BigEndian.WriteUint32(b, uint32(firstAckBlockLength)) + case protocol.PacketNumberLen6: + utils.BigEndian.WriteUint48(b, uint64(firstAckBlockLength)&(1<<48-1)) + } + + for i, ackRange := range f.AckRanges { + if i == 0 { + continue + } + + length := ackRange.Largest - ackRange.Smallest + 1 + gap := f.AckRanges[i-1].Smallest - ackRange.Largest - 1 + + num := gap/0xFF + 1 + if gap%0xFF == 0 { + num-- + } + + if num == 1 { + b.WriteByte(uint8(gap)) + switch missingSequenceNumberDeltaLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(length)) + case protocol.PacketNumberLen2: + utils.BigEndian.WriteUint16(b, uint16(length)) + case protocol.PacketNumberLen4: + utils.BigEndian.WriteUint32(b, uint32(length)) + case protocol.PacketNumberLen6: + utils.BigEndian.WriteUint48(b, uint64(length)&(1<<48-1)) + } + numRangesWritten++ + } else { + for i := 0; i < int(num); i++ { + var lengthWritten uint64 + var gapWritten uint8 + + if i == int(num)-1 { // last block + lengthWritten = uint64(length) + gapWritten = uint8(1 + ((gap - 1) % 255)) + } else { + lengthWritten = 0 + gapWritten = 0xFF + } + + b.WriteByte(gapWritten) + switch missingSequenceNumberDeltaLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(lengthWritten)) + case protocol.PacketNumberLen2: + utils.BigEndian.WriteUint16(b, uint16(lengthWritten)) + case protocol.PacketNumberLen4: + utils.BigEndian.WriteUint32(b, uint32(lengthWritten)) + case protocol.PacketNumberLen6: + utils.BigEndian.WriteUint48(b, lengthWritten&(1<<48-1)) + } + + numRangesWritten++ + } + } + + // this is needed if not all AckRanges can be written to the ACK frame (if there are more than 0xFF) + if numRangesWritten >= numRanges { + break + } + } + + if numRanges != numRangesWritten { + return errors.New("BUG: Inconsistent number of ACK ranges written") + } + + b.WriteByte(0) // no timestamps + return nil +} + +func (f *AckFrame) lengthLegacy(_ protocol.VersionNumber) protocol.ByteCount { + length := protocol.ByteCount(1 + 2 + 1) // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp + length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestAcked())) + + missingSequenceNumberDeltaLen := protocol.ByteCount(f.getMissingSequenceNumberDeltaLen()) + + if f.HasMissingRanges() { + length += (1 + missingSequenceNumberDeltaLen) * protocol.ByteCount(f.numWritableNackRanges()) + } else { + length += missingSequenceNumberDeltaLen + } + // we don't write + return length +} + +// numWritableNackRanges calculates the number of ACK blocks that are about to be written +// this number is different from len(f.AckRanges) for the case of long gaps (> 255 packets) +func (f *AckFrame) numWritableNackRanges() uint64 { + if len(f.AckRanges) == 0 { + return 0 + } + + var numRanges uint64 + for i, ackRange := range f.AckRanges { + if i == 0 { + continue + } + + lastAckRange := f.AckRanges[i-1] + gap := lastAckRange.Smallest - ackRange.Largest - 1 + rangeLength := 1 + uint64(gap)/0xFF + if uint64(gap)%0xFF == 0 { + rangeLength-- + } + + if numRanges+rangeLength < 0xFF { + numRanges += rangeLength + } else { + break + } + } + + return numRanges + 1 +} + +func (f *AckFrame) getMissingSequenceNumberDeltaLen() protocol.PacketNumberLen { + var maxRangeLength protocol.PacketNumber + + if f.HasMissingRanges() { + for _, ackRange := range f.AckRanges { + rangeLength := ackRange.Largest - ackRange.Smallest + 1 + if rangeLength > maxRangeLength { + maxRangeLength = rangeLength + } + } + } else { + maxRangeLength = f.LargestAcked() - f.LowestAcked() + 1 + } + + if maxRangeLength <= 0xFF { + return protocol.PacketNumberLen1 + } + if maxRangeLength <= 0xFFFF { + return protocol.PacketNumberLen2 + } + if maxRangeLength <= 0xFFFFFFFF { + return protocol.PacketNumberLen4 + } + + return protocol.PacketNumberLen6 +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy_test.go b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy_test.go new file mode 100644 index 00000000..3be341a2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_legacy_test.go @@ -0,0 +1,1045 @@ +package wire + +import ( + "bytes" + "io" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ACK Frame (for gQUIC)", func() { + Context("when parsing", func() { + It("accepts a sample frame", func() { + b := bytes.NewReader([]byte{0x40, + 0x1c, // largest acked + 0x0, 0x0, // delay time + 0x1c, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x1c))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame that acks packet number 0", func() { + b := bytes.NewReader([]byte{0x40, + 0x0, // largest acked + 0x0, 0x0, // delay time + 0x1, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with 1 ACKed packet", func() { + b := bytes.NewReader([]byte{0x40, + 0x10, // largest acked + 0x0, 0x0, // delay time + 0x1, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x10))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0x10))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame that acks multiple packets, starting with 0", func() { + b := bytes.NewReader([]byte{0x40, + 0x10, // largest acked + 0x0, 0x0, // delay time + 0x11, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x10))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with multiple timestamps", func() { + b := bytes.NewReader([]byte{0x40, + 0x10, // largest acked + 0x0, 0x0, // timestamp + 0x10, // block length + 0x4, // num timestamps + 0x1, 0x6b, 0x26, 0x4, 0x0, // 1st timestamp + 0x3, 0, 0, // 2nd timestamp + 0x2, 0, 0, // 3rd timestamp + 0x1, 0, 0, // 4th timestamp + }) + _, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + }) + + It("errors when the ACK range is too large", func() { + // LargestAcked: 0x1c + // Length: 0x1d => LowestAcked would be -1 + b := bytes.NewReader([]byte{0x40, + 0x1c, // largest acked + 0x0, 0x0, // delay time + 0x1e, // block length + 0, + }) + _, err := parseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError(errInvalidAckRanges)) + }) + + It("errors when the first ACK range is empty", func() { + b := bytes.NewReader([]byte{0x40, + 0x9, // largest acked + 0x0, 0x0, // delay time + 0x0, // block length + 0, + }) + _, err := parseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError("invalid first ACK range")) + }) + + It("parses the delay time", func() { + b := bytes.NewReader([]byte{0x40, + 0x3, // largest acked + 0x0, 0x8e, // delay time + 0x3, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(3))) + Expect(frame.DelayTime).To(Equal(142 * time.Microsecond)) + }) + + It("errors on EOFs", func() { + data := []byte{0x60 ^ 0x4 ^ 0x1, + 0x9, 0x66, // largest acked + 0x23, 0x1, // delay time + 0x7, // num ACk blocks + 0x0, 0x7, // 1st block + 0xff, 0x0, 0x0, // 2nd block + 0xf5, 0x2, 0x8a, // 3rd block + 0xc8, 0x0, 0xe6, // 4th block + 0xff, 0x0, 0x0, // 5th block + 0xff, 0x0, 0x0, // 6th block + 0xff, 0x0, 0x0, // 7th block + 0x23, 0x0, 0x13, // 8th blocks + 0x2, // num timestamps + 0x1, 0x13, 0xae, 0xb, 0x0, // 1st timestamp + 0x0, 0x80, 0x5, // 2nd timestamp + } + _, err := parseAckFrame(bytes.NewReader(data), versionBigEndian) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseAckFrame(bytes.NewReader(data[0:i]), versionBigEndian) + Expect(err).To(MatchError(io.EOF)) + } + }) + + Context("largest acked length", func() { + It("parses a frame with a 2 byte packet number", func() { + b := bytes.NewReader([]byte{0x40 | 0x4, + 0x13, 0x37, // largest acked + 0x0, 0x0, // delay time + 0x9, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x1337))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0x1337 - 0x9 + 1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with a 4 byte packet number", func() { + b := bytes.NewReader([]byte{0x40 | 0x8, + 0xde, 0xca, 0xfb, 0xad, // largest acked + 0x0, 0x0, // timesatmp + 0x5, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0xdecafbad))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0xdecafbad - 5 + 1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with a 6 byte packet number", func() { + b := bytes.NewReader([]byte{0x4 | 0xc, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked + 0x0, 0x0, // delay time + 0x5, // block length + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0xdeadbeefcafe - 5 + 1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + }) + + Context("ACK blocks", func() { + It("parses a frame with two ACK blocks", func() { + b := bytes.NewReader([]byte{0x60, + 0x18, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0x3, // 1st block + 0x2, 0x10, // 2nd block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x18))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 0x18 - 0x3 + 1, Largest: 0x18})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: (0x18 - 0x3 + 1) - (0x2 + 1) - (0x10 - 1), Largest: (0x18 - 0x3 + 1) - (0x2 + 1)})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(4))) + Expect(b.Len()).To(BeZero()) + }) + + It("rejects a frame with invalid ACK ranges", func() { + // like the test before, but increased the last ACK range, such that the First would be negative + b := bytes.NewReader([]byte{0x60, + 0x18, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0x3, // 1st block + 0x2, 0x15, // 2nd block + 0, + }) + _, err := parseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError(errInvalidAckRanges)) + }) + + It("rejects a frame that says it has ACK blocks in the typeByte, but doesn't have any", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x3, + 0x4, // largest acked + 0x0, 0x0, // delay time + 0, // num ACK blocks + 0, + }) + _, err := parseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError(errInvalidAckRanges)) + }) + + It("parses a frame with multiple single packets missing", func() { + b := bytes.NewReader([]byte{0x60, + 0x27, // largest acked + 0x0, 0x0, // delay time + 0x6, // num ACK blocks + 0x9, // 1st block + 0x1, 0x1, // 2nd block + 0x1, 0x1, // 3rd block + 0x1, 0x1, // 4th block + 0x1, 0x1, // 5th block + 0x1, 0x1, // 6th block + 0x1, 0x13, // 7th block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x27))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(7)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 31, Largest: 0x27})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 29, Largest: 29})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{Smallest: 27, Largest: 27})) + Expect(frame.AckRanges[3]).To(Equal(AckRange{Smallest: 25, Largest: 25})) + Expect(frame.AckRanges[4]).To(Equal(AckRange{Smallest: 23, Largest: 23})) + Expect(frame.AckRanges[5]).To(Equal(AckRange{Smallest: 21, Largest: 21})) + Expect(frame.AckRanges[6]).To(Equal(AckRange{Smallest: 1, Largest: 19})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with multiple longer ACK blocks", func() { + b := bytes.NewReader([]byte{0x60, + 0x52, // largest acked + 0xd1, 0x0, //delay time + 0x3, // num ACK blocks + 0x17, // 1st block + 0xa, 0x10, // 2nd block + 0x4, 0x8, // 3rd block + 0x2, 0x12, // 4th block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x52))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(4)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 60, Largest: 0x52})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 34, Largest: 49})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{Smallest: 22, Largest: 29})) + Expect(frame.AckRanges[3]).To(Equal(AckRange{Smallest: 2, Largest: 19})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(2))) + Expect(b.Len()).To(BeZero()) + }) + + Context("more than 256 lost packets in a row", func() { + // 255 missing packets fit into a single ACK block + It("parses a frame with a range of 255 missing packets", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x1, 0x15, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0x3, // 1st block + 0xff, 0x13, // 2nd block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x115))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 20 + 255, Largest: 0x115})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 1, Largest: 19})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + // 256 missing packets fit into two ACK blocks + It("parses a frame with a range of 256 missing packets", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x1, 0x14, // largest acked + 0x0, 0x0, // delay time + 0x2, // num ACK blocks + 0x1, // 1st block + 0xff, 0x0, // 2nd block + 0x1, 0x13, // 3rd block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x114))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 20 + 256, Largest: 0x114})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 1, Largest: 19})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with an incomplete range at the end", func() { + // this is a modified ACK frame that has 5 instead of originally 6 written ranges + // each gap is 300 packets and thus takes 2 ranges + // the last range is incomplete, and should be completely ignored + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x3, 0x9b, // largest acked + 0x0, 0x0, // delay time + 0x5, // num ACK blocks, instead of 0x6 + 0x1, // 1st block + 0xff, 0x0, // 2nd block + 0x2d, 0x1, // 3rd block + 0xff, 0x0, // 4th block + 0x2d, 0x1, // 5th block + 0xff, 0x0, /*0x2d, 0x14,*/ // 6th block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x39b))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(3)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 20 + 3*301, Largest: 20 + 3*301})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 20 + 2*301, Largest: 20 + 2*301})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{Smallest: 20 + 1*301, Largest: 20 + 1*301})) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with one long range, spanning 2 blocks, of missing packets", func() { + // 280 missing packets + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x1, 0x44, // largest acked + 0x0, 0x0, // delay time + 0x2, // num ACK blocks + 0x19, // 1st block + 0xff, 0x0, // 2nd block + 0x19, 0x13, // 3rd block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x144))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 300, Largest: 0x144})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 1, Largest: 19})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with one long range, spanning multiple blocks, of missing packets", func() { + // 2345 missing packets + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x9, 0x5b, // largest acked + 0x0, 0x0, // delay time + 0xa, // num ACK blocks + 0x1f, // 1st block + 0xff, 0x0, // 2nd block + 0xff, 0x0, // 3rd block + 0xff, 0x0, // 4th block + 0xff, 0x0, // 5th block + 0xff, 0x0, // 6th block + 0xff, 0x0, // 7th block + 0xff, 0x0, // 8th block + 0xff, 0x0, // 9th block + 0xff, 0x0, // 10th block + 0x32, 0x13, // 11th block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x95b))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 2365, Largest: 0x95b})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 1, Largest: 19})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with multiple 2 byte long ranges of missing packets", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x4 ^ 0x1, + 0x9, 0x66, // largest acked + 0x0, 0x0, // delay time + 0x7, // num ACK blocks + 0x0, 0x7, // 1st block + 0xff, 0x0, 0x0, // 2nd block + 0xf5, 0x2, 0x8a, // 3rd block + 0xc8, 0x0, 0xe6, // 4th block + 0xff, 0x0, 0x0, // 5th block + 0xff, 0x0, 0x0, // 6th block + 0xff, 0x0, 0x0, // 7th block + 0x23, 0x0, 0x13, // 8th block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0x966))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(4)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 2400, Largest: 0x966})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: 1250, Largest: 1899})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{Smallest: 820, Largest: 1049})) + Expect(frame.AckRanges[3]).To(Equal(AckRange{Smallest: 1, Largest: 19})) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with with a 4 byte ack block length", func() { + b := bytes.NewReader([]byte{0x60 ^ 0xc ^ 0x2, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0, 0, 0x13, 0x37, // 1st block + 0x20, 0x12, 0x34, 0x56, 0x78, // 2nd block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 0xdeadbeefcafe - 0x1337 + 1, Largest: 0xdeadbeefcafe})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1) - (0x12345678 - 1), Largest: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1)})) + }) + + It("parses a frame with with a 6 byte ack block length", func() { + b := bytes.NewReader([]byte{0x60 ^ 0xc ^ 0x3, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACk blocks + 0, 0, 0, 0, 0x13, 0x37, // 1st block + 0x20, 0x0, 0xab, 0x12, 0x34, 0x56, 0x78, // 2nd block + 0, + }) + frame, err := parseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{Smallest: 0xdeadbeefcafe - 0x1337 + 1, Largest: 0xdeadbeefcafe})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{Smallest: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1) - (0xab12345678 - 1), Largest: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1)})) + }) + }) + }) + }) + + Context("when writing", func() { + var b *bytes.Buffer + + BeforeEach(func() { + b = &bytes.Buffer{} + }) + + Context("self-consistency", func() { + It("writes a simple ACK frame", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 1}}, + DelayTime: 876 * time.Microsecond, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(frame.DelayTime).To(Equal(frameOrig.DelayTime)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK that also acks packet 0", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 0, Largest: 1}}, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes the correct block length in a simple ACK frame", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 10, Largest: 20}}, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a simple ACK frame with a high packet number", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 0xdeadbeefcafe, Largest: 0xdeadbeefcafe}}, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK frame with one packet missing", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 25, Largest: 40}, + {Smallest: 0, Largest: 23}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK frame with multiple missing packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 22, Largest: 25}, + {Smallest: 15, Largest: 18}, + {Smallest: 13, Largest: 13}, + {Smallest: 1, Largest: 10}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + Context("longer gaps between ACK blocks", func() { + It("only writes one block for 254 lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 20 + 254, Largest: 300}, + {Smallest: 1, Largest: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(2))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("only writes one block for 255 lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 20 + 255, Largest: 300}, + {Smallest: 1, Largest: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(2))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes two blocks for 256 lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 20 + 256, Largest: 300}, + {Smallest: 1, Largest: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(3))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes two blocks for 510 lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 20 + 510, Largest: 600}, + {Smallest: 1, Largest: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(3))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes three blocks for 511 lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 20 + 511, Largest: 600}, + {Smallest: 1, Largest: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(4))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes three blocks for 512 lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 20 + 512, Largest: 600}, + {Smallest: 1, Largest: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(4))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes multiple blocks for a lot of lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 2900, Largest: 3000}, + {Smallest: 1, Largest: 19}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes multiple longer blocks for 256 lost packets", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 2900, Largest: 3600}, + {Smallest: 1000, Largest: 2500}, + {Smallest: 1, Largest: 19}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + }) + + Context("largest acked length", func() { + It("writes a 1 largest acked", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 200}}, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x0))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 2 byte largest acked", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 0x100}}, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 4 byte largest acked", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 0x10000}}, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 6 byte largest acked", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 0x100000000}}, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(r.Len()).To(BeZero()) + }) + }) + + Context("ack block length", func() { + It("writes a 1 byte ack block length, if all ACK blocks are short", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 5000, Largest: 5001}, + {Smallest: 250, Largest: 300}, + {Smallest: 1, Largest: 200}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x0))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 2 byte ack block length, for a frame with one ACK block", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 9990, Largest: 10000}, + {Smallest: 1, Largest: 9988}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 2 byte ack block length, for a frame with multiple ACK blocks", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 9990, Largest: 10000}, + {Smallest: 1, Largest: 256}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 4 byte ack block length, for a frame with single ACK blocks", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 9990, Largest: 0xdeadbeef}, + {Smallest: 1, Largest: 9988}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 4 byte ack block length, for a frame with multiple ACK blocks", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 9990, Largest: 0xdeadbeef}, + {Smallest: 1, Largest: 256}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 6 byte ack block length, for a frame with a single ACK blocks", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 9990, Largest: 0xdeadbeefcafe}, + {Smallest: 1, Largest: 9988}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 6 byte ack block length, for a frame with multiple ACK blocks", func() { + frameOrig := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 9990, Largest: 0xdeadbeefcafe}, + {Smallest: 1, Largest: 256}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(frameOrig.LowestAcked())) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + }) + + Context("too many ACK blocks", func() { + It("skips the lowest ACK ranges, if there are more than 255 AckRanges", func() { + ackRanges := make([]AckRange, 300) + for i := 1; i <= 300; i++ { + ackRanges[300-i] = AckRange{Smallest: protocol.PacketNumber(3 * i), Largest: protocol.PacketNumber(3*i + 1)} + } + frameOrig := &AckFrame{AckRanges: ackRanges} + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(ackRanges[254].Smallest)) + Expect(frame.AckRanges).To(HaveLen(0xFF)) + Expect(frame.validateAckRanges()).To(BeTrue()) + }) + + It("skips the lowest ACK ranges, if the gaps are large", func() { + ackRanges := make([]AckRange, 100) + // every AckRange will take 4 written ACK ranges + for i := 1; i <= 100; i++ { + ackRanges[100-i] = AckRange{Smallest: protocol.PacketNumber(1000 * i), Largest: protocol.PacketNumber(1000*i + 1)} + } + frameOrig := &AckFrame{AckRanges: ackRanges} + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.LowestAcked()).To(Equal(ackRanges[255/4].Smallest)) + Expect(frame.validateAckRanges()).To(BeTrue()) + }) + + It("works with huge gaps", func() { + ackRanges := []AckRange{ + {Smallest: 2 * 255 * 200, Largest: 2*255*200 + 1}, + {Smallest: 1 * 255 * 200, Largest: 1*255*200 + 1}, + {Smallest: 1, Largest: 2}, + } + frameOrig := &AckFrame{AckRanges: ackRanges} + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := parseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(frameOrig.LargestAcked())) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.LowestAcked()).To(Equal(ackRanges[1].Smallest)) + Expect(frame.validateAckRanges()).To(BeTrue()) + }) + }) + }) + + Context("min length", func() { + It("has proper min length", func() { + f := &AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 1}}, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has proper min length with a large LargestObserved", func() { + f := &AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 0xdeadbeefcafe}}, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has the proper min length for an ACK with missing packets", func() { + f := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 1000, Largest: 2000}, + {Smallest: 50, Largest: 900}, + {Smallest: 10, Largest: 23}, + }, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has the proper min length for an ACK with long gaps of missing packets", func() { + f := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 1500, Largest: 2000}, + {Smallest: 290, Largest: 295}, + {Smallest: 1, Largest: 19}, + }, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has the proper min length for an ACK with a long ACK range", func() { + largestAcked := protocol.PacketNumber(2 + 0xFFFFFF) + f := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 1500, Largest: largestAcked}, + {Smallest: 290, Largest: 295}, + {Smallest: 1, Largest: 19}, + }, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_test.go new file mode 100644 index 00000000..65c9e4ab --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ack_frame_test.go @@ -0,0 +1,410 @@ +package wire + +import ( + "bytes" + "io" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ACK Frame (for IETF QUIC)", func() { + Context("parsing", func() { + It("parses an ACK frame without any ranges", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(100)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(10)...) // first ack block + b := bytes.NewReader(data) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(100))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(90))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses an ACK frame that only acks a single packet", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(55)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(0)...) // first ack block + b := bytes.NewReader(data) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(55))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(55))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("accepts an ACK frame that acks all packets from 0 to largest", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(20)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(20)...) // first ack block + b := bytes.NewReader(data) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(20))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("rejects an ACK frame that has a first ACK block which is larger than LargestAcked", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(20)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(21)...) // first ack block + b := bytes.NewReader(data) + _, err := parseAckFrame(b, versionIETFFrames) + Expect(err).To(MatchError("invalid first ACK range")) + }) + + It("parses an ACK frame that has a single block", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(1000)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(1)...) // num blocks + data = append(data, encodeVarInt(100)...) // first ack block + data = append(data, encodeVarInt(98)...) // gap + data = append(data, encodeVarInt(50)...) // ack block + b := bytes.NewReader(data) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(1000))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(750))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(Equal([]AckRange{ + {Largest: 1000, Smallest: 900}, + {Largest: 800, Smallest: 750}, + })) + Expect(b.Len()).To(BeZero()) + }) + + It("parses an ACK frame that has a multiple blocks", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(100)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(2)...) // num blocks + data = append(data, encodeVarInt(0)...) // first ack block + data = append(data, encodeVarInt(0)...) // gap + data = append(data, encodeVarInt(0)...) // ack block + data = append(data, encodeVarInt(1)...) // gap + data = append(data, encodeVarInt(1)...) // ack block + b := bytes.NewReader(data) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(100))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(94))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(Equal([]AckRange{ + {Largest: 100, Smallest: 100}, + {Largest: 98, Smallest: 98}, + {Largest: 95, Smallest: 94}, + })) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOF", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(1000)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(1)...) // num blocks + data = append(data, encodeVarInt(100)...) // first ack block + data = append(data, encodeVarInt(98)...) // gap + data = append(data, encodeVarInt(50)...) // ack block + _, err := parseAckFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseAckFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("when writing", func() { + It("writes a simple frame", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + AckRanges: []AckRange{{Smallest: 100, Largest: 1337}}, + } + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0xd} + expected = append(expected, encodeVarInt(1337)...) // largest acked + expected = append(expected, 0) // delay + expected = append(expected, encodeVarInt(0)...) // num ranges + expected = append(expected, encodeVarInt(1337-100)...) + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("writes a frame that acks a single packet", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + AckRanges: []AckRange{{Smallest: 0xdeadbeef, Largest: 0xdeadbeef}}, + DelayTime: 18 * time.Millisecond, + } + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(frame.DelayTime).To(Equal(f.DelayTime)) + Expect(b.Len()).To(BeZero()) + }) + + It("writes a frame that acks many packets", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + AckRanges: []AckRange{{Smallest: 0x1337, Largest: 0xdeadbeef}}, + } + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("writes a frame with a a single gap", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 400, Largest: 1000}, + {Smallest: 100, Largest: 200}, + }, + } + Expect(f.validateAckRanges()).To(BeTrue()) + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(b.Len()).To(BeZero()) + }) + + It("writes a frame with multiple ranges", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 10, Largest: 10}, + {Smallest: 8, Largest: 8}, + {Smallest: 5, Largest: 6}, + {Smallest: 1, Largest: 3}, + }, + } + Expect(f.validateAckRanges()).To(BeTrue()) + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(b.Len()).To(BeZero()) + }) + + It("limits the maximum size of the ACK frame", func() { + buf := &bytes.Buffer{} + const numRanges = 1000 + ackRanges := make([]AckRange, numRanges) + for i := protocol.PacketNumber(1); i <= numRanges; i++ { + ackRanges[numRanges-i] = AckRange{Smallest: 2 * i, Largest: 2 * i} + } + f := &AckFrame{AckRanges: ackRanges} + Expect(f.validateAckRanges()).To(BeTrue()) + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + // make sure the ACK frame is *a little bit* smaller than the MaxAckFrameSize + Expect(buf.Len()).To(BeNumerically(">", protocol.MaxAckFrameSize-5)) + Expect(buf.Len()).To(BeNumerically("<=", protocol.MaxAckFrameSize)) + b := bytes.NewReader(buf.Bytes()) + frame, err := parseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(b.Len()).To(BeZero()) + Expect(len(frame.AckRanges)).To(BeNumerically("<", numRanges)) // make sure we dropped some ranges + }) + }) + + Context("ACK range validator", func() { + It("rejects ACKs without ranges", func() { + Expect((&AckFrame{}).validateAckRanges()).To(BeFalse()) + }) + + It("accepts an ACK without NACK Ranges", func() { + ack := AckFrame{ + AckRanges: []AckRange{{Smallest: 1, Largest: 7}}, + } + Expect(ack.validateAckRanges()).To(BeTrue()) + }) + + It("rejects ACK ranges with Smallest greater than Largest", func() { + ack := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 8, Largest: 10}, + {Smallest: 4, Largest: 3}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects ACK ranges in the wrong order", func() { + ack := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 2, Largest: 2}, + {Smallest: 6, Largest: 7}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects with overlapping ACK ranges", func() { + ack := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 5, Largest: 7}, + {Smallest: 2, Largest: 5}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects ACK ranges that are part of a larger ACK range", func() { + ack := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 4, Largest: 7}, + {Smallest: 5, Largest: 6}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects with directly adjacent ACK ranges", func() { + ack := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 5, Largest: 7}, + {Smallest: 2, Largest: 4}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("accepts an ACK with one lost packet", func() { + ack := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 5, Largest: 10}, + {Smallest: 1, Largest: 3}, + }, + } + Expect(ack.validateAckRanges()).To(BeTrue()) + }) + + It("accepts an ACK with multiple lost packets", func() { + ack := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 15, Largest: 20}, + {Smallest: 10, Largest: 12}, + {Smallest: 1, Largest: 3}, + }, + } + Expect(ack.validateAckRanges()).To(BeTrue()) + }) + }) + + Context("check if ACK frame acks a certain packet", func() { + It("works with an ACK without any ranges", func() { + f := AckFrame{ + AckRanges: []AckRange{{Smallest: 5, Largest: 10}}, + } + Expect(f.AcksPacket(1)).To(BeFalse()) + Expect(f.AcksPacket(4)).To(BeFalse()) + Expect(f.AcksPacket(5)).To(BeTrue()) + Expect(f.AcksPacket(8)).To(BeTrue()) + Expect(f.AcksPacket(10)).To(BeTrue()) + Expect(f.AcksPacket(11)).To(BeFalse()) + Expect(f.AcksPacket(20)).To(BeFalse()) + }) + + It("works with an ACK with multiple ACK ranges", func() { + f := AckFrame{ + AckRanges: []AckRange{ + {Smallest: 15, Largest: 20}, + {Smallest: 5, Largest: 8}, + }, + } + Expect(f.AcksPacket(4)).To(BeFalse()) + Expect(f.AcksPacket(5)).To(BeTrue()) + Expect(f.AcksPacket(6)).To(BeTrue()) + Expect(f.AcksPacket(7)).To(BeTrue()) + Expect(f.AcksPacket(8)).To(BeTrue()) + Expect(f.AcksPacket(9)).To(BeFalse()) + Expect(f.AcksPacket(14)).To(BeFalse()) + Expect(f.AcksPacket(15)).To(BeTrue()) + Expect(f.AcksPacket(18)).To(BeTrue()) + Expect(f.AcksPacket(19)).To(BeTrue()) + Expect(f.AcksPacket(20)).To(BeTrue()) + Expect(f.AcksPacket(21)).To(BeFalse()) + }) + }) +}) + +var _ = Describe("ACK_ECN frame", func() { + Context("parsing", func() { + It("parses an ACK_ECN frame", func() { + data := []byte{0xd} + data = append(data, encodeVarInt(100)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0x42)...) // ECT(0) + data = append(data, encodeVarInt(0x12345)...) // ECT(1) + data = append(data, encodeVarInt(0x12345678)...) // ECN-CE + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(10)...) // first ack block + b := bytes.NewReader(data) + frame, err := parseAckEcnFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(100))) + Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(90))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOF", func() { + data := []byte{0x1a} + data = append(data, encodeVarInt(1000)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0x42)...) // ECT(0) + data = append(data, encodeVarInt(0x12345)...) // ECT(1) + data = append(data, encodeVarInt(0x12345678)...) // ECN-CE + data = append(data, encodeVarInt(1)...) // num blocks + data = append(data, encodeVarInt(100)...) // first ack block + data = append(data, encodeVarInt(98)...) // gap + data = append(data, encodeVarInt(50)...) // ack block + _, err := parseAckEcnFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseAckEcnFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } + }) + + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ack_range.go b/vendor/lucas-clemente/quic-go/internal/wire/ack_range.go new file mode 100644 index 00000000..0f418580 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ack_range.go @@ -0,0 +1,14 @@ +package wire + +import "github.com/lucas-clemente/quic-go/internal/protocol" + +// AckRange is an ACK range +type AckRange struct { + Smallest protocol.PacketNumber + Largest protocol.PacketNumber +} + +// Len returns the number of packets contained in this ACK range +func (r AckRange) Len() protocol.PacketNumber { + return r.Largest - r.Smallest + 1 +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ack_range_test.go b/vendor/lucas-clemente/quic-go/internal/wire/ack_range_test.go new file mode 100644 index 00000000..84ef71b5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ack_range_test.go @@ -0,0 +1,13 @@ +package wire + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ACK range", func() { + It("returns the length", func() { + Expect(AckRange{Smallest: 10, Largest: 10}.Len()).To(BeEquivalentTo(1)) + Expect(AckRange{Smallest: 10, Largest: 13}.Len()).To(BeEquivalentTo(4)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame.go new file mode 100644 index 00000000..1d3e56e5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame.go @@ -0,0 +1,45 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A BlockedFrame is a BLOCKED frame +type BlockedFrame struct { + Offset protocol.ByteCount +} + +// parseBlockedFrame parses a BLOCKED frame +func parseBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*BlockedFrame, error) { + if _, err := r.ReadByte(); err != nil { + return nil, err + } + offset, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + return &BlockedFrame{ + Offset: protocol.ByteCount(offset), + }, nil +} + +func (f *BlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + if !version.UsesIETFFrameFormat() { + return (&blockedFrameLegacy{}).Write(b, version) + } + typeByte := uint8(0x08) + b.WriteByte(typeByte) + utils.WriteVarInt(b, uint64(f.Offset)) + return nil +} + +// Length of a written frame +func (f *BlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + if !version.UsesIETFFrameFormat() { + return 1 + 4 + } + return 1 + utils.VarIntLen(uint64(f.Offset)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy.go b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy.go new file mode 100644 index 00000000..9943e166 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy.go @@ -0,0 +1,37 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type blockedFrameLegacy struct { + StreamID protocol.StreamID +} + +// parseBlockedFrameLegacy parses a BLOCKED frame (in gQUIC format) +// The frame returned is +// * a STREAM_BLOCKED frame, if the BLOCKED applies to a stream +// * a BLOCKED frame, if the BLOCKED applies to the connection +func parseBlockedFrameLegacy(r *bytes.Reader, _ protocol.VersionNumber) (Frame, error) { + if _, err := r.ReadByte(); err != nil { // read the TypeByte + return nil, err + } + streamID, err := utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + if streamID == 0 { + return &BlockedFrame{}, nil + } + return &StreamBlockedFrame{StreamID: protocol.StreamID(streamID)}, nil +} + +//Write writes a BLOCKED frame +func (f *blockedFrameLegacy) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + b.WriteByte(0x05) + utils.BigEndian.WriteUint32(b, uint32(f.StreamID)) + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy_test.go b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy_test.go new file mode 100644 index 00000000..6bd5abcf --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_legacy_test.go @@ -0,0 +1,65 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("legacy BLOCKED Frame", func() { + Context("when parsing", func() { + It("accepts sample frame for a stream", func() { + b := bytes.NewReader([]byte{0x5, 0xde, 0xad, 0xbe, 0xef}) + f, err := parseBlockedFrameLegacy(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f).To(BeAssignableToTypeOf(&StreamBlockedFrame{})) + frame := f.(*StreamBlockedFrame) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdeadbeef))) + }) + + It("accepts sample frame for the connection", func() { + b := bytes.NewReader([]byte{0x5, 0x0, 0x0, 0x0, 0x0}) + f, err := parseBlockedFrameLegacy(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f).To(BeAssignableToTypeOf(&BlockedFrame{})) + }) + }) + + It("errors on EOFs", func() { + data := []byte{0x5, 0xef, 0xbe, 0xad, 0xde} + _, err := parseBlockedFrameLegacy(bytes.NewReader(data), protocol.VersionWhatever) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseBlockedFrameLegacy(bytes.NewReader(data[0:i]), protocol.VersionWhatever) + Expect(err).To(HaveOccurred()) + } + }) + + Context("when writing", func() { + It("writes a BLOCKED frame for a stream", func() { + b := &bytes.Buffer{} + frame := StreamBlockedFrame{StreamID: 0x1337} + frame.Write(b, versionBigEndian) + Expect(b.Bytes()).To(Equal([]byte{0x5, 0x0, 0x0, 0x13, 0x37})) + }) + + It("has the correct min length for a BLOCKED frame for a stream", func() { + frame := StreamBlockedFrame{StreamID: 3} + Expect(frame.Length(versionBigEndian)).To(Equal(protocol.ByteCount(5))) + }) + + It("writes a BLOCKED frame for the connection", func() { + b := &bytes.Buffer{} + frame := BlockedFrame{} + frame.Write(b, versionBigEndian) + Expect(b.Bytes()).To(Equal([]byte{0x5, 0x0, 0x0, 0x0, 0x0})) + }) + + It("has the correct min length for a BLOCKED frame for the connection", func() { + frame := BlockedFrame{} + Expect(frame.Length(versionBigEndian)).To(Equal(protocol.ByteCount(5))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_test.go new file mode 100644 index 00000000..ef67f4c3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/blocked_frame_test.go @@ -0,0 +1,54 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("BLOCKED frame", func() { + Context("when parsing", func() { + It("accepts sample frame", func() { + data := []byte{0x08} + data = append(data, encodeVarInt(0x12345678)...) + b := bytes.NewReader(data) + frame, err := parseBlockedFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.Offset).To(Equal(protocol.ByteCount(0x12345678))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x08} + data = append(data, encodeVarInt(0x12345678)...) + _, err := parseBlockedFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + for i := range data { + _, err := parseBlockedFrame(bytes.NewReader(data[:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("when writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := BlockedFrame{Offset: 0xdeadbeef} + err := frame.Write(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x08} + expected = append(expected, encodeVarInt(0xdeadbeef)...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("has the correct min length", func() { + frame := BlockedFrame{Offset: 0x12345} + Expect(frame.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x12345))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame.go new file mode 100644 index 00000000..667ded74 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame.go @@ -0,0 +1,96 @@ +package wire + +import ( + "bytes" + "errors" + "io" + "math" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +// A ConnectionCloseFrame in QUIC +type ConnectionCloseFrame struct { + ErrorCode qerr.ErrorCode + ReasonPhrase string +} + +// parseConnectionCloseFrame reads a CONNECTION_CLOSE frame +func parseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) (*ConnectionCloseFrame, error) { + if _, err := r.ReadByte(); err != nil { // read the TypeByte + return nil, err + } + + var errorCode qerr.ErrorCode + var reasonPhraseLen uint64 + if version.UsesIETFFrameFormat() { + ec, err := utils.BigEndian.ReadUint16(r) + if err != nil { + return nil, err + } + errorCode = qerr.ErrorCode(ec) + reasonPhraseLen, err = utils.ReadVarInt(r) + if err != nil { + return nil, err + } + } else { + ec, err := utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + errorCode = qerr.ErrorCode(ec) + length, err := utils.BigEndian.ReadUint16(r) + if err != nil { + return nil, err + } + reasonPhraseLen = uint64(length) + } + + // shortcut to prevent the unnecessary allocation of dataLen bytes + // if the dataLen is larger than the remaining length of the packet + // reading the whole reason phrase would result in EOF when attempting to READ + if int(reasonPhraseLen) > r.Len() { + return nil, io.EOF + } + + reasonPhrase := make([]byte, reasonPhraseLen) + if _, err := io.ReadFull(r, reasonPhrase); err != nil { + // this should never happen, since we already checked the reasonPhraseLen earlier + return nil, err + } + + return &ConnectionCloseFrame{ + ErrorCode: errorCode, + ReasonPhrase: string(reasonPhrase), + }, nil +} + +// Length of a written frame +func (f *ConnectionCloseFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + if version.UsesIETFFrameFormat() { + return 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase)) + } + return 1 + 4 + 2 + protocol.ByteCount(len(f.ReasonPhrase)) +} + +// Write writes an CONNECTION_CLOSE frame. +func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + b.WriteByte(0x02) + + if len(f.ReasonPhrase) > math.MaxUint16 { + return errors.New("ConnectionFrame: ReasonPhrase too long") + } + + if version.UsesIETFFrameFormat() { + utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode)) + utils.WriteVarInt(b, uint64(len(f.ReasonPhrase))) + } else { + utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode)) + utils.BigEndian.WriteUint16(b, uint16(len(f.ReasonPhrase))) + } + b.WriteString(f.ReasonPhrase) + + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame_test.go new file mode 100644 index 00000000..c43095da --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/connection_close_frame_test.go @@ -0,0 +1,196 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("CONNECTION_CLOSE Frame", func() { + Context("when parsing", func() { + Context("in varint encoding", func() { + It("accepts sample frame", func() { + data := []byte{0x2, 0x0, 0x19} + data = append(data, encodeVarInt(0x1b)...) // reason phrase length + data = append(data, []byte{ + 'N', 'o', ' ', 'r', 'e', 'c', 'e', 'n', 't', ' ', 'n', 'e', 't', 'w', 'o', 'r', 'k', ' ', 'a', 'c', 't', 'i', 'v', 'i', 't', 'y', '.', + }...) + b := bytes.NewReader(data) + frame, err := parseConnectionCloseFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.ErrorCode).To(Equal(qerr.ErrorCode(0x19))) + Expect(frame.ReasonPhrase).To(Equal("No recent network activity.")) + Expect(b.Len()).To(BeZero()) + }) + + It("rejects long reason phrases", func() { + data := []byte{0x2, 0xca, 0xfe} + data = append(data, encodeVarInt(0xffff)...) // reason phrase length + b := bytes.NewReader(data) + _, err := parseConnectionCloseFrame(b, versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + }) + + It("errors on EOFs", func() { + data := []byte{0x2, 0x0, 0x19} + data = append(data, encodeVarInt(0x1b)...) // reason phrase length + data = append(data, []byte{ + 'N', 'o', ' ', 'r', 'e', 'c', 'e', 'n', 't', ' ', 'n', 'e', 't', 'w', 'o', 'r', 'k', ' ', 'a', 'c', 't', 'i', 'v', 'i', 't', 'y', '.', + }...) + _, err := parseConnectionCloseFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseConnectionCloseFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + }) + + It("parses a frame without a reason phrase", func() { + data := []byte{0x2, 0xca, 0xfe} + data = append(data, encodeVarInt(0)...) + b := bytes.NewReader(data) + frame, err := parseConnectionCloseFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.ReasonPhrase).To(BeEmpty()) + Expect(b.Len()).To(BeZero()) + }) + }) + + Context("in big endian", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x2, + 0x0, 0x0, 0x0, 0x19, // error code + 0x0, 0x1b, // reason phrase length + 'N', 'o', ' ', 'r', 'e', 'c', 'e', 'n', 't', ' ', 'n', 'e', 't', 'w', 'o', 'r', 'k', ' ', 'a', 'c', 't', 'i', 'v', 'i', 't', 'y', '.', + }) + frame, err := parseConnectionCloseFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.ErrorCode).To(Equal(qerr.ErrorCode(0x19))) + Expect(frame.ReasonPhrase).To(Equal("No recent network activity.")) + Expect(b.Len()).To(BeZero()) + }) + + It("rejects long reason phrases", func() { + b := bytes.NewReader([]byte{0x2, + 0xad, 0xfb, 0xca, 0xde, // error code + 0xff, 0x0, // reason phrase length + }) + _, err := parseConnectionCloseFrame(b, versionBigEndian) + Expect(err).To(MatchError(io.EOF)) + }) + + It("errors on EOFs", func() { + data := []byte{0x40, + 0x19, 0x0, 0x0, 0x0, // error code + 0x0, 0x1b, // reason phrase length + 'N', 'o', ' ', 'r', 'e', 'c', 'e', 'n', 't', ' ', 'n', 'e', 't', 'w', 'o', 'r', 'k', ' ', 'a', 'c', 't', 'i', 'v', 'i', 't', 'y', '.', + } + _, err := parseConnectionCloseFrame(bytes.NewReader(data), versionBigEndian) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseConnectionCloseFrame(bytes.NewReader(data[0:i]), versionBigEndian) + Expect(err).To(HaveOccurred()) + } + }) + + It("parses a frame without a reason phrase", func() { + b := bytes.NewReader([]byte{0x2, + 0xad, 0xfb, 0xca, 0xde, // error code + 0x0, 0x0, // reason phrase length + }) + frame, err := parseConnectionCloseFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.ReasonPhrase).To(BeEmpty()) + Expect(b.Len()).To(BeZero()) + }) + }) + }) + + Context("when writing", func() { + Context("in varint encoding", func() { + It("writes a frame without a ReasonPhrase", func() { + b := &bytes.Buffer{} + frame := &ConnectionCloseFrame{ + ErrorCode: 0xbeef, + } + err := frame.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x2, 0xbe, 0xef} + expected = append(expected, encodeVarInt(0)...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("writes a frame with a ReasonPhrase", func() { + b := &bytes.Buffer{} + frame := &ConnectionCloseFrame{ + ErrorCode: 0xdead, + ReasonPhrase: "foobar", + } + err := frame.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x2, 0xde, 0xad} + expected = append(expected, encodeVarInt(6)...) + expected = append(expected, []byte{'f', 'o', 'o', 'b', 'a', 'r'}...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("has proper min length", func() { + b := &bytes.Buffer{} + f := &ConnectionCloseFrame{ + ErrorCode: 0xcafe, + ReasonPhrase: "foobar", + } + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionIETFFrames)).To(Equal(protocol.ByteCount(b.Len()))) + }) + }) + + Context("in big endian", func() { + It("writes a frame without a ReasonPhrase", func() { + b := &bytes.Buffer{} + frame := &ConnectionCloseFrame{ + ErrorCode: 0xdeadbeef, + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(1 + 2 + 4)) + Expect(b.Bytes()).To(Equal([]byte{0x2, + 0xde, 0xad, 0xbe, 0xef, // error code + 0x0, 0x0, // reason phrase length + })) + }) + + It("writes a frame with a ReasonPhrase", func() { + b := &bytes.Buffer{} + frame := &ConnectionCloseFrame{ + ErrorCode: 0xdeadbeef, + ReasonPhrase: "foobar", + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(1 + 2 + 4 + len(frame.ReasonPhrase))) + Expect(b.Bytes()).To(Equal([]byte{0x2, + 0xde, 0xad, 0xbe, 0xef, // error code + 0x0, 0x6, // reason phrase length + 'f', 'o', 'o', 'b', 'a', 'r', + })) + }) + + It("has proper min length", func() { + b := &bytes.Buffer{} + f := &ConnectionCloseFrame{ + ErrorCode: 0xcafe, + ReasonPhrase: "foobar", + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/frame.go b/vendor/lucas-clemente/quic-go/internal/wire/frame.go new file mode 100644 index 00000000..835905a4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/frame.go @@ -0,0 +1,13 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// A Frame in QUIC +type Frame interface { + Write(b *bytes.Buffer, version protocol.VersionNumber) error + Length(version protocol.VersionNumber) protocol.ByteCount +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/frame_parser.go b/vendor/lucas-clemente/quic-go/internal/wire/frame_parser.go new file mode 100644 index 00000000..ce558e36 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/frame_parser.go @@ -0,0 +1,172 @@ +package wire + +import ( + "bytes" + "errors" + "fmt" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/qerr" +) + +// ParseNextFrame parses the next frame +// It skips PADDING frames. +func ParseNextFrame(r *bytes.Reader, hdr *Header, v protocol.VersionNumber) (Frame, error) { + for r.Len() != 0 { + typeByte, _ := r.ReadByte() + if typeByte == 0x0 { // PADDING frame + continue + } + r.UnreadByte() + + if !v.UsesIETFFrameFormat() { + return parseGQUICFrame(r, typeByte, hdr, v) + } + return parseIETFFrame(r, typeByte, v) + } + return nil, nil +} + +func parseIETFFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (Frame, error) { + var frame Frame + var err error + if typeByte&0xf8 == 0x10 { + frame, err = parseStreamFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidStreamData, err.Error()) + } + return frame, err + } + // TODO: implement all IETF QUIC frame types + switch typeByte { + case 0x1: + frame, err = parseRstStreamFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidRstStreamData, err.Error()) + } + case 0x2: + frame, err = parseConnectionCloseFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidConnectionCloseData, err.Error()) + } + case 0x4: + frame, err = parseMaxDataFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error()) + } + case 0x5: + frame, err = parseMaxStreamDataFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error()) + } + case 0x6: + frame, err = parseMaxStreamIDFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidFrameData, err.Error()) + } + case 0x7: + frame, err = parsePingFrame(r, v) + case 0x8: + frame, err = parseBlockedFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidBlockedData, err.Error()) + } + case 0x9: + frame, err = parseStreamBlockedFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidBlockedData, err.Error()) + } + case 0xa: + frame, err = parseStreamIDBlockedFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidFrameData, err.Error()) + } + case 0xc: + frame, err = parseStopSendingFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidFrameData, err.Error()) + } + case 0xd: + frame, err = parseAckFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidAckData, err.Error()) + } + case 0xe: + frame, err = parsePathChallengeFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidFrameData, err.Error()) + } + case 0xf: + frame, err = parsePathResponseFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidFrameData, err.Error()) + } + case 0x1a: + frame, err = parseAckEcnFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidAckData, err.Error()) + } + default: + err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte)) + } + return frame, err +} + +func parseGQUICFrame(r *bytes.Reader, typeByte byte, hdr *Header, v protocol.VersionNumber) (Frame, error) { + var frame Frame + var err error + if typeByte&0x80 == 0x80 { + frame, err = parseStreamFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidStreamData, err.Error()) + } + return frame, err + } else if typeByte&0xc0 == 0x40 { + frame, err = parseAckFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidAckData, err.Error()) + } + return frame, err + } + switch typeByte { + case 0x1: + frame, err = parseRstStreamFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidRstStreamData, err.Error()) + } + case 0x2: + frame, err = parseConnectionCloseFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidConnectionCloseData, err.Error()) + } + case 0x3: + frame, err = parseGoawayFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidGoawayData, err.Error()) + } + case 0x4: + frame, err = parseWindowUpdateFrame(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error()) + } + case 0x5: + frame, err = parseBlockedFrameLegacy(r, v) + if err != nil { + err = qerr.Error(qerr.InvalidBlockedData, err.Error()) + } + case 0x6: + if !v.UsesStopWaitingFrames() { + err = errors.New("STOP_WAITING frames not supported by this QUIC version") + break + } + frame, err = parseStopWaitingFrame(r, hdr.PacketNumber, hdr.PacketNumberLen, v) + if err != nil { + err = qerr.Error(qerr.InvalidStopWaitingData, err.Error()) + } + case 0x7: + frame, err = parsePingFrame(r, v) + default: + err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte)) + } + return frame, err +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/frame_parser_test.go b/vendor/lucas-clemente/quic-go/internal/wire/frame_parser_test.go new file mode 100644 index 00000000..ca89d575 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/frame_parser_test.go @@ -0,0 +1,359 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Frame parsing", func() { + var buf *bytes.Buffer + + BeforeEach(func() { + buf = &bytes.Buffer{} + }) + + It("returns nil if there's nothing more to read", func() { + f, err := ParseNextFrame(bytes.NewReader(nil), nil, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(f).To(BeNil()) + }) + + It("skips PADDING frames", func() { + buf.Write([]byte{0}) // PADDING frame + (&PingFrame{}).Write(buf, versionIETFFrames) + f, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f).To(Equal(&PingFrame{})) + }) + + It("handles PADDING at the end", func() { + r := bytes.NewReader([]byte{0, 0, 0}) + f, err := ParseNextFrame(r, nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f).To(BeNil()) + Expect(r.Len()).To(BeZero()) + }) + + Context("for gQUIC frames", func() { + It("unpacks RST_STREAM frames", func() { + f := &RstStreamFrame{ + StreamID: 0xdeadbeef, + ByteOffset: 0xdecafbad11223344, + ErrorCode: 0x1337, + } + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks CONNECTION_CLOSE frames", func() { + f := &ConnectionCloseFrame{ReasonPhrase: "foo"} + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks GOAWAY frames", func() { + f := &GoawayFrame{ + ErrorCode: 1, + LastGoodStream: 2, + ReasonPhrase: "foo", + } + err := f.Write(buf, 0) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks a stream-level WINDOW_UPDATE frame", func() { + f := &MaxStreamDataFrame{ + StreamID: 0xdeadbeef, + ByteOffset: 0xcafe000000001337, + } + buf := &bytes.Buffer{} + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks a connection-level WINDOW_UPDATE frame", func() { + f := &MaxDataFrame{ + ByteOffset: 0xcafe000000001337, + } + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks connection-level BLOCKED frames", func() { + f := &BlockedFrame{} + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks stream-level BLOCKED frames", func() { + f := &StreamBlockedFrame{StreamID: 0xdeadbeef} + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks STOP_WAITING frames", func() { + hdr := &Header{ + PacketNumber: 0x1338, + PacketNumberLen: protocol.PacketNumberLen4, + } + f := &StopWaitingFrame{ + LeastUnacked: 0x1337, + PacketNumber: hdr.PacketNumber, + PacketNumberLen: hdr.PacketNumberLen, + } + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), hdr, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(BeAssignableToTypeOf(f)) + Expect(frame.(*StopWaitingFrame).LeastUnacked).To(Equal(protocol.PacketNumber(0x1337))) + }) + + It("errors on STOP_WAITING frames in QUIC 44", func() { + Expect(protocol.Version44.UsesStopWaitingFrames()).To(BeFalse()) + hdr := &Header{ + PacketNumber: 0x1338, + PacketNumberLen: protocol.PacketNumberLen4, + } + f := &StopWaitingFrame{ + LeastUnacked: 0x1337, + PacketNumber: hdr.PacketNumber, + PacketNumberLen: hdr.PacketNumberLen, + } + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + _, err = ParseNextFrame(bytes.NewReader(buf.Bytes()), hdr, protocol.Version44) + Expect(err).To(MatchError("STOP_WAITING frames not supported by this QUIC version")) + }) + + It("unpacks PING frames", func() { + f := &PingFrame{} + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks ACK frames", func() { + f := &AckFrame{AckRanges: []AckRange{{Smallest: 1, Largest: 0x13}}} + err := f.Write(buf, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).ToNot(BeNil()) + Expect(frame).To(BeAssignableToTypeOf(f)) + Expect(frame.(*AckFrame).LargestAcked()).To(Equal(protocol.PacketNumber(0x13))) + }) + + It("errors on invalid type", func() { + _, err := ParseNextFrame(bytes.NewReader([]byte{0xf}), nil, versionBigEndian) + Expect(err).To(MatchError("InvalidFrameData: unknown type byte 0xf")) + }) + + It("errors on invalid frames", func() { + for b, e := range map[byte]qerr.ErrorCode{ + 0x80: qerr.InvalidStreamData, + 0x40: qerr.InvalidAckData, + 0x01: qerr.InvalidRstStreamData, + 0x02: qerr.InvalidConnectionCloseData, + 0x03: qerr.InvalidGoawayData, + 0x04: qerr.InvalidWindowUpdateData, + 0x05: qerr.InvalidBlockedData, + 0x06: qerr.InvalidStopWaitingData, + } { + _, err := ParseNextFrame(bytes.NewReader([]byte{b}), &Header{PacketNumberLen: 2}, versionBigEndian) + Expect(err).To(HaveOccurred()) + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(e)) + } + }) + }) + + Context("for IETF draft frames", func() { + It("unpacks RST_STREAM frames", func() { + f := &RstStreamFrame{ + StreamID: 0xdeadbeef, + ByteOffset: 0xdecafbad1234, + ErrorCode: 0x1337, + } + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks CONNECTION_CLOSE frames", func() { + f := &ConnectionCloseFrame{ReasonPhrase: "foo"} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks MAX_DATA frames", func() { + f := &MaxDataFrame{ + ByteOffset: 0xcafe, + } + buf := &bytes.Buffer{} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks MAX_STREAM_DATA frames", func() { + f := &MaxStreamDataFrame{ + StreamID: 0xdeadbeef, + ByteOffset: 0xdecafbad, + } + buf := &bytes.Buffer{} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks MAX_STREAM_ID frames", func() { + f := &MaxStreamIDFrame{StreamID: 0x1337} + buf := &bytes.Buffer{} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks connection-level BLOCKED frames", func() { + f := &BlockedFrame{Offset: 0x1234} + buf := &bytes.Buffer{} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks stream-level BLOCKED frames", func() { + f := &StreamBlockedFrame{ + StreamID: 0xdeadbeef, + Offset: 0xdead, + } + buf := &bytes.Buffer{} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks STREAM_ID_BLOCKED frames", func() { + f := &StreamIDBlockedFrame{StreamID: 0x1234567} + buf := &bytes.Buffer{} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks STOP_SENDING frames", func() { + f := &StopSendingFrame{StreamID: 0x42} + buf := &bytes.Buffer{} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + }) + + It("unpacks ACK frames", func() { + f := &AckFrame{AckRanges: []AckRange{{Smallest: 1, Largest: 0x13}}} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).ToNot(BeNil()) + Expect(frame).To(BeAssignableToTypeOf(f)) + Expect(frame.(*AckFrame).LargestAcked()).To(Equal(protocol.PacketNumber(0x13))) + }) + + It("unpacks PATH_CHALLENGE frames", func() { + f := &PathChallengeFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).ToNot(BeNil()) + Expect(frame).To(BeAssignableToTypeOf(f)) + Expect(frame.(*PathChallengeFrame).Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) + }) + + It("unpacks PATH_RESPONSE frames", func() { + f := &PathResponseFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}} + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), nil, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).ToNot(BeNil()) + Expect(frame).To(BeAssignableToTypeOf(f)) + Expect(frame.(*PathResponseFrame).Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) + }) + + It("errors on invalid type", func() { + _, err := ParseNextFrame(bytes.NewReader([]byte{0x42}), nil, versionIETFFrames) + Expect(err).To(MatchError("InvalidFrameData: unknown type byte 0x42")) + }) + + It("errors on invalid frames", func() { + for b, e := range map[byte]qerr.ErrorCode{ + 0x01: qerr.InvalidRstStreamData, + 0x02: qerr.InvalidConnectionCloseData, + 0x04: qerr.InvalidWindowUpdateData, + 0x05: qerr.InvalidWindowUpdateData, + 0x06: qerr.InvalidFrameData, + 0x08: qerr.InvalidBlockedData, + 0x09: qerr.InvalidBlockedData, + 0x0a: qerr.InvalidFrameData, + 0x0c: qerr.InvalidFrameData, + 0x0d: qerr.InvalidAckData, + 0x0e: qerr.InvalidFrameData, + 0x0f: qerr.InvalidFrameData, + 0x10: qerr.InvalidStreamData, + 0x1a: qerr.InvalidAckData, + } { + _, err := ParseNextFrame(bytes.NewReader([]byte{b}), nil, versionIETFFrames) + Expect(err).To(HaveOccurred()) + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(e)) + } + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/goaway_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/goaway_frame.go new file mode 100644 index 00000000..86bf2b43 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/goaway_frame.go @@ -0,0 +1,68 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +// A GoawayFrame is a GOAWAY frame +type GoawayFrame struct { + ErrorCode qerr.ErrorCode + LastGoodStream protocol.StreamID + ReasonPhrase string +} + +// parseGoawayFrame parses a GOAWAY frame +func parseGoawayFrame(r *bytes.Reader, _ protocol.VersionNumber) (*GoawayFrame, error) { + frame := &GoawayFrame{} + + if _, err := r.ReadByte(); err != nil { + return nil, err + } + + errorCode, err := utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + frame.ErrorCode = qerr.ErrorCode(errorCode) + + lastGoodStream, err := utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + frame.LastGoodStream = protocol.StreamID(lastGoodStream) + + reasonPhraseLen, err := utils.BigEndian.ReadUint16(r) + if err != nil { + return nil, err + } + + if reasonPhraseLen > uint16(protocol.MaxReceivePacketSize) { + return nil, qerr.Error(qerr.InvalidGoawayData, "reason phrase too long") + } + + reasonPhrase := make([]byte, reasonPhraseLen) + if _, err := io.ReadFull(r, reasonPhrase); err != nil { + return nil, err + } + frame.ReasonPhrase = string(reasonPhrase) + return frame, nil +} + +func (f *GoawayFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + b.WriteByte(0x03) + utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode)) + utils.BigEndian.WriteUint32(b, uint32(f.LastGoodStream)) + utils.BigEndian.WriteUint16(b, uint16(len(f.ReasonPhrase))) + b.WriteString(f.ReasonPhrase) + return nil +} + +// Length of a written frame +func (f *GoawayFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + return protocol.ByteCount(1 + 4 + 4 + 2 + len(f.ReasonPhrase)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/goaway_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/goaway_frame_test.go new file mode 100644 index 00000000..61127649 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/goaway_frame_test.go @@ -0,0 +1,87 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("GoawayFrame", func() { + Context("when parsing", func() { + Context("in big endian", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x3, + 0x0, 0x0, 0x13, 0x37, // error code + 0x0, 0x0, 0x12, 0x34, // last good stream id + 0x0, 0x3, // reason phrase length + 'f', 'o', 'o', + }) + frame, err := parseGoawayFrame(b, versionBigEndian) + Expect(frame).To(Equal(&GoawayFrame{ + ErrorCode: 0x1337, + LastGoodStream: 0x1234, + ReasonPhrase: "foo", + })) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x3, + 0x0, 0x0, 0x0, 0x1, // error code + 0x0, 0x0, 0x0, 0x2, // last good stream id + 0x0, 0x3, // reason phrase length + 'f', 'o', 'o', + } + _, err := parseGoawayFrame(bytes.NewReader(data), versionBigEndian) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseGoawayFrame(bytes.NewReader(data[0:i]), versionBigEndian) + Expect(err).To(HaveOccurred()) + } + }) + }) + + It("rejects long reason phrases", func() { + b := bytes.NewReader([]byte{0x3, + 0x1, 0x0, 0x0, 0x0, // error code + 0x2, 0x0, 0x0, 0x0, // last good stream id + 0xff, 0xff, // reason phrase length + }) + _, err := parseGoawayFrame(b, protocol.VersionWhatever) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidGoawayData, "reason phrase too long"))) + }) + }) + + Context("when writing", func() { + Context("in big endian", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := GoawayFrame{ + ErrorCode: 0x1337, + LastGoodStream: 2, + ReasonPhrase: "foo", + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x3, + 0x0, 0x0, 0x13, 0x37, // reason code + 0x0, 0x0, 0x0, 0x2, // last good stream id + 0x0, 0x3, // reason phrase length + 'f', 'o', 'o', + })) + }) + }) + + It("has the correct min length", func() { + frame := GoawayFrame{ + ReasonPhrase: "foo", + } + Expect(frame.Length(0)).To(Equal(protocol.ByteCount(14))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/header.go b/vendor/lucas-clemente/quic-go/internal/wire/header.go new file mode 100644 index 00000000..41a322b8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/header.go @@ -0,0 +1,333 @@ +package wire + +import ( + "bytes" + "crypto/rand" + "errors" + "fmt" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// Header is the header of a QUIC packet. +// It contains fields that are only needed for the gQUIC Public Header and the IETF draft Header. +type Header struct { + IsPublicHeader bool + + Raw []byte + + Version protocol.VersionNumber + + DestConnectionID protocol.ConnectionID + SrcConnectionID protocol.ConnectionID + OrigDestConnectionID protocol.ConnectionID // only needed in the Retry packet + + PacketNumberLen protocol.PacketNumberLen + PacketNumber protocol.PacketNumber + + IsVersionNegotiation bool + SupportedVersions []protocol.VersionNumber // Version Number sent in a Version Negotiation Packet by the server + + // only needed for the gQUIC Public Header + VersionFlag bool + ResetFlag bool + DiversificationNonce []byte + + // only needed for the IETF Header + Type protocol.PacketType + IsLongHeader bool + KeyPhase int + PayloadLen protocol.ByteCount + Token []byte +} + +var errInvalidPacketNumberLen = errors.New("invalid packet number length") + +// Write writes the Header. +func (h *Header) Write(b *bytes.Buffer, pers protocol.Perspective, ver protocol.VersionNumber) error { + if !ver.UsesIETFHeaderFormat() { + h.IsPublicHeader = true // save that this is a Public Header, so we can log it correctly later + return h.writePublicHeader(b, pers, ver) + } + // write an IETF QUIC header + if h.IsLongHeader { + return h.writeLongHeader(b, ver) + } + return h.writeShortHeader(b, ver) +} + +// TODO: add support for the key phase +func (h *Header) writeLongHeader(b *bytes.Buffer, v protocol.VersionNumber) error { + b.WriteByte(byte(0x80 | h.Type)) + utils.BigEndian.WriteUint32(b, uint32(h.Version)) + connIDLen, err := encodeConnIDLen(h.DestConnectionID, h.SrcConnectionID) + if err != nil { + return err + } + b.WriteByte(connIDLen) + b.Write(h.DestConnectionID.Bytes()) + b.Write(h.SrcConnectionID.Bytes()) + + if h.Type == protocol.PacketTypeInitial && v.UsesTokenInHeader() { + utils.WriteVarInt(b, uint64(len(h.Token))) + b.Write(h.Token) + } + + if h.Type == protocol.PacketTypeRetry { + odcil, err := encodeSingleConnIDLen(h.OrigDestConnectionID) + if err != nil { + return err + } + // randomize the first 4 bits + odcilByte := make([]byte, 1) + _, _ = rand.Read(odcilByte) // it's safe to ignore the error here + odcilByte[0] = (odcilByte[0] & 0xf0) | odcil + b.Write(odcilByte) + b.Write(h.OrigDestConnectionID.Bytes()) + b.Write(h.Token) + return nil + } + + if v.UsesLengthInHeader() { + utils.WriteVarInt(b, uint64(h.PayloadLen)) + } + if v.UsesVarintPacketNumbers() { + return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen) + } + utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber)) + if h.Type == protocol.PacketType0RTT && v == protocol.Version44 { + if len(h.DiversificationNonce) != 32 { + return errors.New("invalid diversification nonce length") + } + b.Write(h.DiversificationNonce) + } + return nil +} + +func (h *Header) writeShortHeader(b *bytes.Buffer, v protocol.VersionNumber) error { + typeByte := byte(0x30) + typeByte |= byte(h.KeyPhase << 6) + if !v.UsesVarintPacketNumbers() { + switch h.PacketNumberLen { + case protocol.PacketNumberLen1: + case protocol.PacketNumberLen2: + typeByte |= 0x1 + case protocol.PacketNumberLen4: + typeByte |= 0x2 + default: + return errInvalidPacketNumberLen + } + } + + b.WriteByte(typeByte) + b.Write(h.DestConnectionID.Bytes()) + + if !v.UsesVarintPacketNumbers() { + switch h.PacketNumberLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(h.PacketNumber)) + case protocol.PacketNumberLen2: + utils.BigEndian.WriteUint16(b, uint16(h.PacketNumber)) + case protocol.PacketNumberLen4: + utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber)) + } + return nil + } + return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen) +} + +// writePublicHeader writes a Public Header. +func (h *Header) writePublicHeader(b *bytes.Buffer, pers protocol.Perspective, _ protocol.VersionNumber) error { + if h.ResetFlag || (h.VersionFlag && pers == protocol.PerspectiveServer) { + return errors.New("PublicHeader: Can only write regular packets") + } + if h.SrcConnectionID.Len() != 0 { + return errors.New("PublicHeader: SrcConnectionID must not be set") + } + if len(h.DestConnectionID) != 0 && len(h.DestConnectionID) != 8 { + return fmt.Errorf("PublicHeader: wrong length for Connection ID: %d (expected 8)", len(h.DestConnectionID)) + } + + publicFlagByte := uint8(0x00) + if h.VersionFlag { + publicFlagByte |= 0x01 + } + if h.DestConnectionID.Len() > 0 { + publicFlagByte |= 0x08 + } + if len(h.DiversificationNonce) > 0 { + if len(h.DiversificationNonce) != 32 { + return errors.New("invalid diversification nonce length") + } + publicFlagByte |= 0x04 + } + switch h.PacketNumberLen { + case protocol.PacketNumberLen1: + publicFlagByte |= 0x00 + case protocol.PacketNumberLen2: + publicFlagByte |= 0x10 + case protocol.PacketNumberLen4: + publicFlagByte |= 0x20 + } + b.WriteByte(publicFlagByte) + + if h.DestConnectionID.Len() > 0 { + b.Write(h.DestConnectionID) + } + if h.VersionFlag && pers == protocol.PerspectiveClient { + utils.BigEndian.WriteUint32(b, uint32(h.Version)) + } + if len(h.DiversificationNonce) > 0 { + b.Write(h.DiversificationNonce) + } + + switch h.PacketNumberLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(h.PacketNumber)) + case protocol.PacketNumberLen2: + utils.BigEndian.WriteUint16(b, uint16(h.PacketNumber)) + case protocol.PacketNumberLen4: + utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber)) + case protocol.PacketNumberLen6: + return errInvalidPacketNumberLen + default: + return errors.New("PublicHeader: PacketNumberLen not set") + } + + return nil +} + +// GetLength determines the length of the Header. +func (h *Header) GetLength(v protocol.VersionNumber) (protocol.ByteCount, error) { + if !v.UsesIETFHeaderFormat() { + return h.getPublicHeaderLength() + } + return h.getHeaderLength(v) +} + +func (h *Header) getHeaderLength(v protocol.VersionNumber) (protocol.ByteCount, error) { + if h.IsLongHeader { + length := 1 /* type byte */ + 4 /* version */ + 1 /* conn id len byte */ + protocol.ByteCount(h.DestConnectionID.Len()+h.SrcConnectionID.Len()) + protocol.ByteCount(h.PacketNumberLen) + if v.UsesLengthInHeader() { + length += utils.VarIntLen(uint64(h.PayloadLen)) + } + if h.Type == protocol.PacketTypeInitial && v.UsesTokenInHeader() { + length += utils.VarIntLen(uint64(len(h.Token))) + protocol.ByteCount(len(h.Token)) + } + if h.Type == protocol.PacketType0RTT && v == protocol.Version44 { + length += protocol.ByteCount(len(h.DiversificationNonce)) + } + return length, nil + } + + length := protocol.ByteCount(1 /* type byte */ + h.DestConnectionID.Len()) + if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 { + return 0, fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen) + } + length += protocol.ByteCount(h.PacketNumberLen) + return length, nil +} + +// getPublicHeaderLength gets the length of the publicHeader in bytes. +// It can only be called for regular packets. +func (h *Header) getPublicHeaderLength() (protocol.ByteCount, error) { + length := protocol.ByteCount(1) // 1 byte for public flags + if h.PacketNumberLen == protocol.PacketNumberLen6 { + return 0, errInvalidPacketNumberLen + } + if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 { + return 0, errPacketNumberLenNotSet + } + length += protocol.ByteCount(h.PacketNumberLen) + length += protocol.ByteCount(h.DestConnectionID.Len()) + // Version Number in packets sent by the client + if h.VersionFlag { + length += 4 + } + length += protocol.ByteCount(len(h.DiversificationNonce)) + return length, nil +} + +// Log logs the Header +func (h *Header) Log(logger utils.Logger) { + if h.IsPublicHeader { + h.logPublicHeader(logger) + } else { + h.logHeader(logger) + } +} + +func (h *Header) logHeader(logger utils.Logger) { + if h.IsLongHeader { + if h.Version == 0 { + logger.Debugf("\tVersionNegotiationPacket{DestConnectionID: %s, SrcConnectionID: %s, SupportedVersions: %s}", h.DestConnectionID, h.SrcConnectionID, h.SupportedVersions) + } else { + var token string + if h.Type == protocol.PacketTypeInitial || h.Type == protocol.PacketTypeRetry { + if len(h.Token) == 0 { + token = "Token: (empty), " + } else { + token = fmt.Sprintf("Token: %#x, ", h.Token) + } + } + if h.Type == protocol.PacketTypeRetry { + logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sOrigDestConnectionID: %s, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.OrigDestConnectionID, h.Version) + return + } + if h.Version == protocol.Version44 { + var divNonce string + if h.Type == protocol.PacketType0RTT { + divNonce = fmt.Sprintf("Diversification Nonce: %#x, ", h.DiversificationNonce) + } + logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, %sVersion: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, h.PacketNumber, h.PacketNumberLen, divNonce, h.Version) + return + } + logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %#x, PacketNumberLen: %d, PayloadLen: %d, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.PacketNumber, h.PacketNumberLen, h.PayloadLen, h.Version) + } + } else { + logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, KeyPhase: %d}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, h.KeyPhase) + } +} + +func (h *Header) logPublicHeader(logger utils.Logger) { + ver := "(unset)" + if h.Version != 0 { + ver = h.Version.String() + } + logger.Debugf("\tPublic Header{ConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, Version: %s, DiversificationNonce: %#v}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, ver, h.DiversificationNonce) +} + +func encodeConnIDLen(dest, src protocol.ConnectionID) (byte, error) { + dcil, err := encodeSingleConnIDLen(dest) + if err != nil { + return 0, err + } + scil, err := encodeSingleConnIDLen(src) + if err != nil { + return 0, err + } + return scil | dcil<<4, nil +} + +func encodeSingleConnIDLen(id protocol.ConnectionID) (byte, error) { + len := id.Len() + if len == 0 { + return 0, nil + } + if len < 4 || len > 18 { + return 0, fmt.Errorf("invalid connection ID length: %d bytes", len) + } + return byte(len - 3), nil +} + +func decodeConnIDLen(enc byte) (int /*dest conn id len*/, int /*src conn id len*/) { + return decodeSingleConnIDLen(enc >> 4), decodeSingleConnIDLen(enc & 0xf) +} + +func decodeSingleConnIDLen(enc uint8) int { + if enc == 0 { + return 0 + } + return int(enc) + 3 +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/header_parser.go b/vendor/lucas-clemente/quic-go/internal/wire/header_parser.go new file mode 100644 index 00000000..08f5b406 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/header_parser.go @@ -0,0 +1,273 @@ +package wire + +import ( + "bytes" + "fmt" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +// The InvariantHeader is the version independent part of the header +type InvariantHeader struct { + IsLongHeader bool + Version protocol.VersionNumber + SrcConnectionID protocol.ConnectionID + DestConnectionID protocol.ConnectionID + + typeByte byte +} + +// ParseInvariantHeader parses the version independent part of the header +func ParseInvariantHeader(b *bytes.Reader, shortHeaderConnIDLen int) (*InvariantHeader, error) { + typeByte, err := b.ReadByte() + if err != nil { + return nil, err + } + + h := &InvariantHeader{typeByte: typeByte} + h.IsLongHeader = typeByte&0x80 > 0 + + // If this is not a Long Header, it could either be a Public Header or a Short Header. + if !h.IsLongHeader { + // In the Public Header 0x8 is the Connection ID Flag. + // In the IETF Short Header: + // * 0x8 it is the gQUIC Demultiplexing bit, and always 0. + // * 0x20 and 0x10 are always 1. + var connIDLen int + if typeByte&0x8 > 0 { // Public Header containing a connection ID + connIDLen = 8 + } + if typeByte&0x38 == 0x30 { // Short Header + connIDLen = shortHeaderConnIDLen + } + if connIDLen > 0 { + h.DestConnectionID, err = protocol.ReadConnectionID(b, connIDLen) + if err != nil { + return nil, err + } + } + return h, nil + } + // Long Header + v, err := utils.BigEndian.ReadUint32(b) + if err != nil { + return nil, err + } + h.Version = protocol.VersionNumber(v) + connIDLenByte, err := b.ReadByte() + if err != nil { + return nil, err + } + dcil, scil := decodeConnIDLen(connIDLenByte) + h.DestConnectionID, err = protocol.ReadConnectionID(b, dcil) + if err != nil { + return nil, err + } + h.SrcConnectionID, err = protocol.ReadConnectionID(b, scil) + if err != nil { + return nil, err + } + return h, nil +} + +// Parse parses the version dependent part of the header +func (iv *InvariantHeader) Parse(b *bytes.Reader, sentBy protocol.Perspective, ver protocol.VersionNumber) (*Header, error) { + if iv.IsLongHeader { + if iv.Version == 0 { // Version Negotiation Packet + return iv.parseVersionNegotiationPacket(b) + } + return iv.parseLongHeader(b, sentBy, ver) + } + // The Public Header never uses 6 byte packet numbers. + // Therefore, the third and fourth bit will never be 11. + // For the Short Header, the third and fourth bit are always 11. + if iv.typeByte&0x30 != 0x30 { + if sentBy == protocol.PerspectiveServer && iv.typeByte&0x1 > 0 { + return iv.parseVersionNegotiationPacket(b) + } + return iv.parsePublicHeader(b, sentBy, ver) + } + return iv.parseShortHeader(b, ver) +} + +func (iv *InvariantHeader) toHeader() *Header { + return &Header{ + IsLongHeader: iv.IsLongHeader, + DestConnectionID: iv.DestConnectionID, + SrcConnectionID: iv.SrcConnectionID, + Version: iv.Version, + } +} + +func (iv *InvariantHeader) parseVersionNegotiationPacket(b *bytes.Reader) (*Header, error) { + h := iv.toHeader() + h.VersionFlag = true + if b.Len() == 0 { + return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list") + } + h.IsVersionNegotiation = true + h.SupportedVersions = make([]protocol.VersionNumber, b.Len()/4) + for i := 0; b.Len() > 0; i++ { + v, err := utils.BigEndian.ReadUint32(b) + if err != nil { + return nil, qerr.InvalidVersionNegotiationPacket + } + h.SupportedVersions[i] = protocol.VersionNumber(v) + } + return h, nil +} + +func (iv *InvariantHeader) parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, v protocol.VersionNumber) (*Header, error) { + h := iv.toHeader() + h.Type = protocol.PacketType(iv.typeByte & 0x7f) + + if h.Type != protocol.PacketTypeInitial && h.Type != protocol.PacketTypeRetry && h.Type != protocol.PacketType0RTT && h.Type != protocol.PacketTypeHandshake { + return nil, qerr.Error(qerr.InvalidPacketHeader, fmt.Sprintf("Received packet with invalid packet type: %d", h.Type)) + } + + if h.Type == protocol.PacketTypeRetry { + odcilByte, err := b.ReadByte() + if err != nil { + return nil, err + } + odcil := decodeSingleConnIDLen(odcilByte & 0xf) + h.OrigDestConnectionID, err = protocol.ReadConnectionID(b, odcil) + if err != nil { + return nil, err + } + h.Token = make([]byte, b.Len()) + if _, err := io.ReadFull(b, h.Token); err != nil { + return nil, err + } + return h, nil + } + + if h.Type == protocol.PacketTypeInitial && v.UsesTokenInHeader() { + tokenLen, err := utils.ReadVarInt(b) + if err != nil { + return nil, err + } + if tokenLen > uint64(b.Len()) { + return nil, io.EOF + } + h.Token = make([]byte, tokenLen) + if _, err := io.ReadFull(b, h.Token); err != nil { + return nil, err + } + } + + if v.UsesLengthInHeader() { + pl, err := utils.ReadVarInt(b) + if err != nil { + return nil, err + } + h.PayloadLen = protocol.ByteCount(pl) + } + if v.UsesVarintPacketNumbers() { + pn, pnLen, err := utils.ReadVarIntPacketNumber(b) + if err != nil { + return nil, err + } + h.PacketNumber = pn + h.PacketNumberLen = pnLen + } else { + pn, err := utils.BigEndian.ReadUint32(b) + if err != nil { + return nil, err + } + h.PacketNumber = protocol.PacketNumber(pn) + h.PacketNumberLen = protocol.PacketNumberLen4 + } + if h.Type == protocol.PacketType0RTT && v == protocol.Version44 && sentBy == protocol.PerspectiveServer { + h.DiversificationNonce = make([]byte, 32) + if _, err := io.ReadFull(b, h.DiversificationNonce); err != nil { + if err == io.ErrUnexpectedEOF { + return nil, io.EOF + } + return nil, err + } + } + + return h, nil +} + +func (iv *InvariantHeader) parseShortHeader(b *bytes.Reader, v protocol.VersionNumber) (*Header, error) { + h := iv.toHeader() + h.KeyPhase = int(iv.typeByte&0x40) >> 6 + + if v.UsesVarintPacketNumbers() { + pn, pnLen, err := utils.ReadVarIntPacketNumber(b) + if err != nil { + return nil, err + } + h.PacketNumber = pn + h.PacketNumberLen = pnLen + } else { + switch iv.typeByte & 0x3 { + case 0x0: + h.PacketNumberLen = protocol.PacketNumberLen1 + case 0x1: + h.PacketNumberLen = protocol.PacketNumberLen2 + case 0x2: + h.PacketNumberLen = protocol.PacketNumberLen4 + default: + return nil, errInvalidPacketNumberLen + } + p, err := utils.BigEndian.ReadUintN(b, uint8(h.PacketNumberLen)) + if err != nil { + return nil, err + } + h.PacketNumber = protocol.PacketNumber(p) + } + return h, nil +} + +func (iv *InvariantHeader) parsePublicHeader(b *bytes.Reader, sentBy protocol.Perspective, ver protocol.VersionNumber) (*Header, error) { + h := iv.toHeader() + h.IsPublicHeader = true + h.ResetFlag = iv.typeByte&0x2 > 0 + if h.ResetFlag { + return h, nil + } + + h.VersionFlag = iv.typeByte&0x1 > 0 + if h.VersionFlag && sentBy == protocol.PerspectiveClient { + v, err := utils.BigEndian.ReadUint32(b) + if err != nil { + return nil, err + } + h.Version = protocol.VersionNumber(v) + } + + // Contrary to what the gQUIC wire spec says, the 0x4 bit only indicates the presence of the diversification nonce for packets sent by the server. + // It doesn't have any meaning when sent by the client. + if sentBy == protocol.PerspectiveServer && iv.typeByte&0x4 > 0 { + h.DiversificationNonce = make([]byte, 32) + if _, err := io.ReadFull(b, h.DiversificationNonce); err != nil { + if err == io.ErrUnexpectedEOF { + return nil, io.EOF + } + return nil, err + } + } + + switch iv.typeByte & 0x30 { + case 0x00: + h.PacketNumberLen = protocol.PacketNumberLen1 + case 0x10: + h.PacketNumberLen = protocol.PacketNumberLen2 + case 0x20: + h.PacketNumberLen = protocol.PacketNumberLen4 + } + + pn, err := utils.BigEndian.ReadUintN(b, uint8(h.PacketNumberLen)) + if err != nil { + return nil, err + } + h.PacketNumber = protocol.PacketNumber(pn) + + return h, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/header_parser_test.go b/vendor/lucas-clemente/quic-go/internal/wire/header_parser_test.go new file mode 100644 index 00000000..cf126674 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/header_parser_test.go @@ -0,0 +1,716 @@ +package wire + +import ( + "bytes" + "encoding/binary" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Header Parsing", func() { + Context("IETF QUIC Header", func() { + appendPacketNumber := func(data []byte, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen) []byte { + buf := &bytes.Buffer{} + utils.WriteVarIntPacketNumber(buf, pn, pnLen) + return append(data, buf.Bytes()...) + } + + Context("Version Negotiation Packets", func() { + It("parses", func() { + srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} + destConnID := protocol.ConnectionID{9, 8, 7, 6, 5, 4, 3, 2, 1} + versions := []protocol.VersionNumber{0x22334455, 0x33445566} + data, err := ComposeVersionNegotiation(destConnID, srcConnID, versions) + Expect(err).ToNot(HaveOccurred()) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.DestConnectionID).To(Equal(destConnID)) + Expect(iHdr.SrcConnectionID).To(Equal(srcConnID)) + Expect(iHdr.IsLongHeader).To(BeTrue()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsVersionNegotiation).To(BeTrue()) + Expect(hdr.Version).To(BeZero()) + Expect(hdr.DestConnectionID).To(Equal(destConnID)) + Expect(hdr.SrcConnectionID).To(Equal(srcConnID)) + for _, v := range versions { + Expect(hdr.SupportedVersions).To(ContainElement(v)) + } + }) + + It("errors if it contains versions of the wrong length", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + versions := []protocol.VersionNumber{0x22334455, 0x33445566} + data, err := ComposeVersionNegotiation(connID, connID, versions) + Expect(err).ToNot(HaveOccurred()) + b := bytes.NewReader(data[:len(data)-2]) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFFrames) + Expect(err).To(MatchError(qerr.InvalidVersionNegotiationPacket)) + }) + + It("errors if the version list is empty", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + versions := []protocol.VersionNumber{0x22334455} + data, err := ComposeVersionNegotiation(connID, connID, versions) + Expect(err).ToNot(HaveOccurred()) + // remove 8 bytes (two versions), since ComposeVersionNegotiation also added a reserved version number + b := bytes.NewReader(data[:len(data)-8]) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFFrames) + Expect(err).To(MatchError("InvalidVersionNegotiationPacket: empty version list")) + }) + }) + + Context("Long Headers", func() { + It("parses a Long Header", func() { + destConnID := protocol.ConnectionID{9, 8, 7, 6, 5, 4, 3, 2, 1} + srcConnID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef} + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version number + 0x61, // connection ID lengths + } + data = append(data, destConnID...) + data = append(data, srcConnID...) + data = append(data, encodeVarInt(6)...) // token length + data = append(data, []byte("foobar")...) // token + data = append(data, encodeVarInt(0x1337)...) // payload length + // packet number + data = appendPacketNumber(data, 0xbeef, protocol.PacketNumberLen4) + + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeTrue()) + Expect(iHdr.DestConnectionID).To(Equal(destConnID)) + Expect(iHdr.SrcConnectionID).To(Equal(srcConnID)) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.Type).To(Equal(protocol.PacketTypeInitial)) + Expect(hdr.IsLongHeader).To(BeTrue()) + Expect(hdr.DestConnectionID).To(Equal(destConnID)) + Expect(hdr.SrcConnectionID).To(Equal(srcConnID)) + Expect(hdr.Token).To(Equal([]byte("foobar"))) + Expect(hdr.PayloadLen).To(Equal(protocol.ByteCount(0x1337))) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xbeef))) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + Expect(hdr.Version).To(Equal(protocol.VersionNumber(0x1020304))) + Expect(hdr.IsVersionNegotiation).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a Long Header without a destination connection ID", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version number + 0x01, // connection ID lengths + 0xde, 0xad, 0xbe, 0xef, // source connection ID + } + data = append(data, encodeVarInt(0x42)...) // payload length + data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.SrcConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef})) + Expect(iHdr.DestConnectionID).To(BeEmpty()) + }) + + It("parses a Long Header without a source connection ID", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version number + 0x70, // connection ID lengths + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // source connection ID + } + data = append(data, encodeVarInt(0x42)...) // payload length + data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.SrcConnectionID).To(BeEmpty()) + Expect(iHdr.DestConnectionID).To(Equal(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) + }) + + It("parses a Long Header with a 2 byte packet number", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version number + 0x0, // connection ID lengths + } + data = append(data, encodeVarInt(0)...) // token length + data = append(data, encodeVarInt(0x42)...) // payload length + data = appendPacketNumber(data, 0x123, protocol.PacketNumberLen2) + + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x123))) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2)) + }) + + It("parses a Retry packet", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeRetry), + 0x1, 0x2, 0x3, 0x4, // version number + 0x0, // connection ID lengths + 0x97, // Orig Destination Connection ID length + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // source connection ID + 'f', 'o', 'o', 'b', 'a', 'r', // token + } + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.Type).To(Equal(protocol.PacketTypeRetry)) + Expect(hdr.OrigDestConnectionID).To(Equal(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) + Expect(hdr.Token).To(Equal([]byte("foobar"))) + }) + + It("rejects packets sent with an unknown packet type", func() { + srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + buf := &bytes.Buffer{} + err := (&Header{ + IsLongHeader: true, + Type: 42, + SrcConnectionID: srcConnID, + Version: 0x10203040, + PacketNumber: 1, + PacketNumberLen: protocol.PacketNumberLen1, + }).Write(buf, protocol.PerspectiveClient, protocol.VersionTLS) + Expect(err).ToNot(HaveOccurred()) + b := bytes.NewReader(buf.Bytes()) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).To(MatchError("InvalidPacketHeader: Received packet with invalid packet type: 42")) + }) + + It("errors if the token length is too large", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version number + 0x0, // connection ID lengths + } + data = append(data, encodeVarInt(4)...) // token length: 4 bytes (1 byte too long) + data = append(data, encodeVarInt(0x42)...) // payload length, 1 byte + data = appendPacketNumber(data, 0x123, protocol.PacketNumberLen2) // 2 bytes + + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).To(MatchError(io.EOF)) + }) + + It("errors on EOF, when parsing the invariant header", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version number + 0x55, // connection ID lengths + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // destination connection ID + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // source connection ID + } + for i := 0; i < len(data); i++ { + _, err := ParseInvariantHeader(bytes.NewReader(data[:i]), 0) + Expect(err).To(Equal(io.EOF)) + } + }) + + It("errors on EOF, when parsing the header", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version number + 0x0, // connection ID lengths + } + iHdrLen := len(data) + data = append(data, encodeVarInt(0x1337)...) + data = appendPacketNumber(data, 0xdeadbeef, protocol.PacketNumberLen4) + for i := iHdrLen; i < len(data); i++ { + b := bytes.NewReader(data[:i]) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).To(Equal(io.EOF)) + } + }) + + It("errors on EOF, for a Retry packet", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeRetry), + 0x1, 0x2, 0x3, 0x4, // version number + 0x0, // connection ID lengths + } + iHdrLen := len(data) + data = append(data, []byte{ + 0x97, // Orig Destination Connection ID length + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // source connection ID + }...) + for i := iHdrLen; i < len(data); i++ { + b := bytes.NewReader(data[:i]) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).To(Equal(io.EOF)) + } + }) + }) + + Context("Short Headers", func() { + It("reads a Short Header with a 8 byte connection ID", func() { + connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37} + data := append([]byte{0x30}, connID...) + data = appendPacketNumber(data, 0x42, protocol.PacketNumberLen1) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 8) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + Expect(iHdr.DestConnectionID).To(Equal(connID)) + hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.KeyPhase).To(Equal(0)) + Expect(hdr.DestConnectionID).To(Equal(connID)) + Expect(hdr.SrcConnectionID).To(BeEmpty()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x42))) + Expect(hdr.IsVersionNegotiation).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("reads a Short Header with a 5 byte connection ID", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5} + data := append([]byte{0x30}, connID...) + data = appendPacketNumber(data, 0x42, protocol.PacketNumberLen1) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 5) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + Expect(iHdr.DestConnectionID).To(Equal(connID)) + hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.KeyPhase).To(Equal(0)) + Expect(hdr.DestConnectionID).To(Equal(connID)) + Expect(hdr.SrcConnectionID).To(BeEmpty()) + Expect(b.Len()).To(BeZero()) + }) + + It("reads the Key Phase Bit", func() { + data := []byte{ + 0x30 ^ 0x40, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // connection ID + } + data = appendPacketNumber(data, 11, protocol.PacketNumberLen1) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 6) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsLongHeader).To(BeFalse()) + Expect(hdr.KeyPhase).To(Equal(1)) + Expect(b.Len()).To(BeZero()) + }) + + It("reads a header with a 2 byte packet number", func() { + data := []byte{ + 0x30 ^ 0x40 ^ 0x1, + 0xde, 0xad, 0xbe, 0xef, // connection ID + } + data = appendPacketNumber(data, 0x1337, protocol.PacketNumberLen2) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 4) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsLongHeader).To(BeFalse()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x1337))) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2)) + Expect(b.Len()).To(BeZero()) + }) + + It("reads a header with a 4 byte packet number", func() { + data := []byte{ + 0x30 ^ 0x40 ^ 0x2, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x1, 0x2, 0x3, 0x4, // connection ID + } + data = appendPacketNumber(data, 0x99beef, protocol.PacketNumberLen4) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 10) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsLongHeader).To(BeFalse()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x99beef))) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOF, when parsing the invariant header", func() { + data := []byte{ + 0x30 ^ 0x2, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID + } + for i := 0; i < len(data); i++ { + _, err := ParseInvariantHeader(bytes.NewReader(data[:i]), 8) + Expect(err).To(Equal(io.EOF)) + } + }) + + It("errors on EOF, when parsing the invariant header", func() { + data := []byte{ + 0x30 ^ 0x2, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // connection ID + } + iHdrLen := len(data) + data = appendPacketNumber(data, 0xdeadbeef, protocol.PacketNumberLen4) + for i := iHdrLen; i < len(data); i++ { + b := bytes.NewReader(data[:i]) + iHdr, err := ParseInvariantHeader(b, 6) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).To(Equal(io.EOF)) + } + }) + }) + }) + + Context("gQUIC 44", func() { + Context("Long Headers", func() { + It("parses a Long Header", func() { + destConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + srcConnID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + data := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0x1, 0x2, 0x3, 0x4, // version + 0x55, // connection ID lengths + } + data = append(data, destConnID...) + data = append(data, srcConnID...) + data = append(data, []byte{0xde, 0xad, 0xbe, 0xef}...) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeTrue()) + Expect(iHdr.Version).To(Equal(protocol.VersionNumber(0x1020304))) + Expect(iHdr.DestConnectionID).To(Equal(destConnID)) + Expect(iHdr.SrcConnectionID).To(Equal(srcConnID)) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsPublicHeader).To(BeFalse()) + Expect(hdr.Type).To(Equal(protocol.PacketTypeInitial)) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xdeadbeef))) + }) + + It("parses a Long Header containing a Diversification Nonce", func() { + srcConnID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + divNonce := bytes.Repeat([]byte{'f'}, 32) + data := []byte{ + 0x80 ^ uint8(protocol.PacketType0RTT), + 0x1, 0x2, 0x3, 0x4, // version + 0x5, // connection ID lengths + } + data = append(data, srcConnID...) + data = append(data, []byte{0xde, 0xad, 0xbe, 0xef}...) + data = append(data, divNonce...) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeTrue()) + Expect(iHdr.Version).To(Equal(protocol.VersionNumber(0x1020304))) + Expect(iHdr.SrcConnectionID).To(Equal(srcConnID)) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsPublicHeader).To(BeFalse()) + Expect(hdr.Type).To(Equal(protocol.PacketType0RTT)) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xdeadbeef))) + Expect(hdr.DiversificationNonce).To(Equal(divNonce)) + }) + + It("errors on EOF, for Long Headers containing a Diversification Nonce", func() { + data := []byte{ + 0x80 ^ uint8(protocol.PacketType0RTT), + 0x1, 0x2, 0x3, 0x4, // version + 0x5, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID + } + iHdrLen := len(data) + data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...) // packet number + data = append(data, bytes.Repeat([]byte{'d'}, 32)...) + for i := iHdrLen; i < len(data); i++ { + b := bytes.NewReader(data[:i]) + iHdr, err := ParseInvariantHeader(b, 8) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeTrue()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).To(Equal(io.EOF)) + } + }) + }) + + Context("Short Headers", func() { + It("parses a Short Header with a 1 byte packet number", func() { + destConnID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + data := []byte{0x30} + data = append(data, destConnID...) + data = append(data, 0x42) // packet number + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 8) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + Expect(iHdr.DestConnectionID).To(Equal(destConnID)) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsPublicHeader).To(BeFalse()) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen1)) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x42))) + }) + + It("parses a Short Header with a 2 byte packet number", func() { + data := []byte{0x30 ^ 0x1, 0xca, 0xfe} + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + Expect(iHdr.DestConnectionID.Len()).To(BeZero()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsPublicHeader).To(BeFalse()) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2)) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xcafe))) + }) + + It("parses a Short Header with a 4 byte packet number", func() { + data := []byte{0x30 ^ 0x2, 0xde, 0xad, 0xbe, 0xef} + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + Expect(iHdr.DestConnectionID.Len()).To(BeZero()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsPublicHeader).To(BeFalse()) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xdeadbeef))) + }) + + It("errors on an invalid packet number length flag", func() { + data := []byte{0x30 ^ 0x3, 0xde, 0xad, 0xbe, 0xef} + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + Expect(iHdr.DestConnectionID.Len()).To(BeZero()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).To(MatchError(errInvalidPacketNumberLen)) + }) + + It("errors on EOF", func() { + data := []byte{0x30 ^ 0x2, 0xde, 0xad, 0xbe, 0xef} + iHdrLen := 1 + for i := iHdrLen; i < len(data); i++ { + b := bytes.NewReader(data[:i]) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, protocol.Version44) + Expect(err).To(Equal(io.EOF)) + } + }) + }) + }) + + Context("Public Header", func() { + It("accepts a sample client header", func() { + data := []byte{ + 0x9, + 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, + } + data = append(data, []byte{0xde, 0xad, 0xbe, 0xef}...) + data = append(data, 0x1) // packet number + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.VersionFlag).To(BeTrue()) + Expect(hdr.IsVersionNegotiation).To(BeFalse()) + Expect(hdr.ResetFlag).To(BeFalse()) + connID := protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6} + Expect(hdr.DestConnectionID).To(Equal(connID)) + Expect(hdr.SrcConnectionID).To(BeEmpty()) + Expect(hdr.Version).To(Equal(protocol.VersionNumber(0xdeadbeef))) + Expect(hdr.SupportedVersions).To(BeEmpty()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("accepts an omitted connection ID", func() { + b := bytes.NewReader([]byte{0x0, 0x1}) + iHdr, err := ParseInvariantHeader(b, 8) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + Expect(iHdr.DestConnectionID).To(BeEmpty()) + Expect(iHdr.SrcConnectionID).To(BeEmpty()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a PUBLIC_RESET packet", func() { + b := bytes.NewReader([]byte{0xa, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}) + iHdr, err := ParseInvariantHeader(b, 4) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.ResetFlag).To(BeTrue()) + Expect(hdr.VersionFlag).To(BeFalse()) + Expect(hdr.IsVersionNegotiation).To(BeFalse()) + connID := protocol.ConnectionID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8} + Expect(hdr.SrcConnectionID).To(BeEmpty()) + Expect(hdr.DestConnectionID).To(Equal(connID)) + }) + + It("reads a diversification nonce sent by the server", func() { + divNonce := []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f} + Expect(divNonce).To(HaveLen(32)) + b := bytes.NewReader(append(append([]byte{0x0c, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c}, divNonce...), 0x37)) + iHdr, err := ParseInvariantHeader(b, 7) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.DestConnectionID).ToNot(BeEmpty()) + Expect(hdr.SrcConnectionID).To(BeEmpty()) + Expect(hdr.DiversificationNonce).To(Equal(divNonce)) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOF", func() { + data := []byte{ + 0x10 ^ 0x8 ^ 0x4, + 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c, + } + iHdrLen := len(data) + data = append(data, bytes.Repeat([]byte{0}, 32)...) // add a diversification nonce + data = append(data, []byte{0x13, 37}...) // packet number + for i := iHdrLen; i < len(data); i++ { + b := bytes.NewReader(data[:i]) + iHdr, err := ParseInvariantHeader(b, 5) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).To(Equal(io.EOF)) + } + }) + + Context("version negotiation packets", func() { + appendVersion := func(data []byte, v protocol.VersionNumber) []byte { + data = append(data, []byte{0, 0, 0, 0}...) + binary.BigEndian.PutUint32(data[len(data)-4:], uint32(v)) + return data + } + + It("parses", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + versions := []protocol.VersionNumber{0x13, 0x37} + b := bytes.NewReader(ComposeGQUICVersionNegotiation(connID, versions)) + iHdr, err := ParseInvariantHeader(b, 6) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.DestConnectionID).To(Equal(connID)) + Expect(hdr.SrcConnectionID).To(BeEmpty()) + Expect(hdr.VersionFlag).To(BeTrue()) + Expect(hdr.Version).To(BeZero()) // unitialized + Expect(hdr.IsVersionNegotiation).To(BeTrue()) + // in addition to the versions, the supported versions might contain a reserved version number + for _, version := range versions { + Expect(hdr.SupportedVersions).To(ContainElement(version)) + } + Expect(b.Len()).To(BeZero()) + }) + + It("errors if it doesn't contain any versions", func() { + b := bytes.NewReader([]byte{0x9, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c}) + iHdr, err := ParseInvariantHeader(b, 4) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).To(MatchError("InvalidVersionNegotiationPacket: empty version list")) + }) + + It("reads version negotiation packets containing unsupported versions", func() { + data := []byte{0x9, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c} + data = appendVersion(data, 1) // unsupported version + data = appendVersion(data, protocol.SupportedVersions[0]) + data = appendVersion(data, 99) // unsupported version + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.VersionFlag).To(BeTrue()) + Expect(hdr.IsVersionNegotiation).To(BeTrue()) + Expect(hdr.SupportedVersions).To(Equal([]protocol.VersionNumber{1, protocol.SupportedVersions[0], 99})) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on invalid version tags", func() { + data := ComposeGQUICVersionNegotiation(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, protocol.SupportedVersions) + data = append(data, []byte{0x13, 0x37}...) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + _, err = iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).To(MatchError(qerr.InvalidVersionNegotiationPacket)) + }) + }) + + Context("Packet Number lengths", func() { + It("accepts 1-byte packet numbers", func() { + b := bytes.NewReader([]byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xde}) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xde))) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen1)) + Expect(b.Len()).To(BeZero()) + }) + + It("accepts 2-byte packet numbers", func() { + b := bytes.NewReader([]byte{0x18, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xde, 0xca}) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xdeca))) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2)) + Expect(b.Len()).To(BeZero()) + }) + + It("accepts 4-byte packet numbers", func() { + b := bytes.NewReader([]byte{0x28, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xad, 0xfb, 0xca, 0xde}) + iHdr, err := ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xadfbcade))) + Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + Expect(b.Len()).To(BeZero()) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/header_test.go b/vendor/lucas-clemente/quic-go/internal/wire/header_test.go new file mode 100644 index 00000000..9e796443 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/header_test.go @@ -0,0 +1,902 @@ +package wire + +import ( + "bytes" + "log" + "os" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Header", func() { + const ( + versionPublicHeader = protocol.Version39 // a QUIC version that uses the Public Header format + versionIETFHeader = protocol.VersionTLS // a QUIC version that uses the IETF Header format + ) + + Context("Writing", func() { + var buf *bytes.Buffer + + BeforeEach(func() { + buf = &bytes.Buffer{} + }) + + Context("IETF Header", func() { + appendPacketNumber := func(data []byte, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen) []byte { + buf := &bytes.Buffer{} + utils.WriteVarIntPacketNumber(buf, pn, pnLen) + return append(data, buf.Bytes()...) + } + + Context("Long Header", func() { + srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + + It("writes", func() { + err := (&Header{ + IsLongHeader: true, + Type: 0x5, + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe}, + SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x0, 0x0, 0x13, 0x37}, + PayloadLen: 0xcafe, + PacketNumber: 0xdecaf, + PacketNumberLen: protocol.PacketNumberLen4, + Version: 0x1020304, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{ + 0x80 ^ 0x5, + 0x1, 0x2, 0x3, 0x4, // version number + 0x35, // connection ID lengths + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // dest connection ID + 0xde, 0xca, 0xfb, 0xad, 0x0, 0x0, 0x13, 0x37, // source connection ID + } + expected = append(expected, encodeVarInt(0xcafe)...) // payload length + expected = appendPacketNumber(expected, 0xdecaf, protocol.PacketNumberLen4) + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("refuses to write a header with a too short connection ID", func() { + err := (&Header{ + IsLongHeader: true, + Type: 0x5, + SrcConnectionID: srcConnID, + DestConnectionID: protocol.ConnectionID{1, 2, 3}, // connection IDs must be at least 4 bytes long + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen4, + Version: 0x1020304, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).To(MatchError("invalid connection ID length: 3 bytes")) + }) + + It("refuses to write a header with a too long connection ID", func() { + err := (&Header{ + IsLongHeader: true, + Type: 0x5, + SrcConnectionID: srcConnID, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, // connection IDs must be at most 18 bytes long + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen4, + Version: 0x1020304, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).To(MatchError("invalid connection ID length: 19 bytes")) + }) + + It("writes a header with an 18 byte connection ID", func() { + err := (&Header{ + IsLongHeader: true, + Type: 0x5, + SrcConnectionID: srcConnID, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}, // connection IDs must be at most 18 bytes long + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen4, + Version: 0x1020304, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(ContainSubstring(string([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}))) + }) + + It("writes an Initial containing a token", func() { + token := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") + err := (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeInitial, + Token: token, + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen4, + Version: 0x1020304, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + expectedSubstring := append(encodeVarInt(uint64(len(token))), token...) + Expect(buf.Bytes()).To(ContainSubstring(string(expectedSubstring))) + }) + + It("writes a Retry packet", func() { + token := []byte("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.") + err := (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeRetry, + Token: token, + OrigDestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Version: 0x1020304, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()[:6]).To(Equal([]byte{ + 0x80 ^ uint8(protocol.PacketTypeRetry), + 0x1, 0x2, 0x3, 0x4, // version number + 0x0, // connection ID lengths)) + })) + Expect(buf.Bytes()[6] & 0xf).To(Equal(uint8(6))) + Expect(buf.Bytes()[7 : 7+9]).To(Equal([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9})) // Orig Dest Connection ID + Expect(buf.Bytes()[7+9:]).To(Equal(token)) + }) + + It("refuses to write a Retry packet with an invalid Orig Destination Connection ID length", func() { + err := (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeRetry, + Token: []byte("foobar"), + OrigDestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, // connection IDs must be at most 18 bytes long + Version: 0x1020304, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).To(MatchError("invalid connection ID length: 19 bytes")) + }) + }) + + Context("short header", func() { + It("writes a header with connection ID", func() { + err := (&Header{ + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + PacketNumberLen: protocol.PacketNumberLen1, + PacketNumber: 0x42, + }).Write(buf, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x30, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID + 0x42, // packet number + })) + }) + + It("writes a header without connection ID", func() { + err := (&Header{ + PacketNumberLen: protocol.PacketNumberLen1, + PacketNumber: 0x42, + }).Write(buf, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x30, + 0x42, // packet number + })) + }) + + It("writes a header with a 2 byte packet number", func() { + err := (&Header{ + PacketNumberLen: protocol.PacketNumberLen2, + PacketNumber: 0x765, + }).Write(buf, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x30} + expected = appendPacketNumber(expected, 0x765, protocol.PacketNumberLen2) + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("writes a header with a 4 byte packet number", func() { + err := (&Header{ + PacketNumberLen: protocol.PacketNumberLen4, + PacketNumber: 0x123456, + }).Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x30} + expected = appendPacketNumber(expected, 0x123456, protocol.PacketNumberLen4) + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("errors when given an invalid packet number length", func() { + err := (&Header{ + PacketNumberLen: 3, + PacketNumber: 0xdecafbad, + }).Write(buf, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).To(MatchError("invalid packet number length: 3")) + }) + + It("writes the Key Phase Bit", func() { + err := (&Header{ + KeyPhase: 1, + PacketNumberLen: protocol.PacketNumberLen1, + PacketNumber: 0x42, + }).Write(buf, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x30 | 0x40, + 0x42, // packet number + })) + }) + }) + }) + + Context("gQUIC 44", func() { + Context("Long Header", func() { + It("writes", func() { + err := (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeInitial, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + Version: 0xdeadbeef, + PacketNumberLen: protocol.PacketNumberLen4, + PacketNumber: 0xdecafbad, + }).Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{ + 0x80 ^ uint8(protocol.PacketTypeInitial), + 0xde, 0xad, 0xbe, 0xef, // version + 0x50, // connection ID lengths + 1, 2, 3, 4, 5, 6, 7, 8, // connection ID + 0xde, 0xca, 0xfb, 0xad, // packet number + } + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("writes a 0-RTT packet with a Diversification Nonce", func() { + divNonce := bytes.Repeat([]byte{'c'}, 32) + err := (&Header{ + IsLongHeader: true, + Type: protocol.PacketType0RTT, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + Version: 0xdeadbeef, + PacketNumberLen: protocol.PacketNumberLen4, + PacketNumber: 0xdecafbad, + DiversificationNonce: divNonce, + }).Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{ + 0x80 ^ uint8(protocol.PacketType0RTT), + 0xde, 0xad, 0xbe, 0xef, // version + 0x50, // connection ID lengths + 1, 2, 3, 4, 5, 6, 7, 8, // connection ID + 0xde, 0xca, 0xfb, 0xad, // packet number + } + expected = append(expected, divNonce...) + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("refuses to write a 0-RTT packet with a wrong length Diversification Nonce", func() { + divNonce := bytes.Repeat([]byte{'c'}, 31) + err := (&Header{ + IsLongHeader: true, + Type: protocol.PacketType0RTT, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + Version: 0xdeadbeef, + PacketNumberLen: protocol.PacketNumberLen4, + PacketNumber: 0xdecafbad, + DiversificationNonce: divNonce, + }).Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).To(MatchError("invalid diversification nonce length")) + }) + }) + + Context("Short Header", func() { + It("writes a Short Header with a 1 byte packet number", func() { + err := (&Header{ + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen1, + PacketNumber: 0x42, + }).Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{ + 0x30, + 1, 2, 3, 4, 5, 6, 7, 8, // connection ID + 0x42, // packet number + } + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("writes a Short Header with a 2 byte packet number", func() { + err := (&Header{ + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen2, + PacketNumber: 0xcafe, + }).Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{ + 0x30 ^ 0x1, + 1, 2, 3, 4, 5, 6, 7, 8, // connection ID + 0xca, 0xfe, // packet number + } + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("writes a Short Header with a 4 byte packet number", func() { + err := (&Header{ + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen4, + PacketNumber: 0xdeadbeef, + }).Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{ + 0x30 ^ 0x2, + 1, 2, 3, 4, 5, 6, 7, 8, // connection ID + 0xde, 0xad, 0xbe, 0xef, // packet number + } + Expect(buf.Bytes()).To(Equal(expected)) + }) + }) + }) + + Context("Public Header", func() { + connID := protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6} + + It("writes a sample header as a server", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 2, + PacketNumberLen: protocol.PacketNumberLen4, + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x28, + 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, + 0, 0, 0, 2, + })) + }) + + It("writes a sample header as a client", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0x1337, + PacketNumberLen: protocol.PacketNumberLen2, + } + err := hdr.Write(buf, protocol.PerspectiveClient, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x18, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, + 0x13, 0x37, + })) + }) + + It("refuses to write a Public Header with a source connection ID", func() { + hdr := Header{ + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + SrcConnectionID: protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + PacketNumber: 0x1337, + PacketNumberLen: protocol.PacketNumberLen4, + } + err := hdr.Write(buf, protocol.PerspectiveClient, versionPublicHeader) + Expect(err).To(MatchError("PublicHeader: SrcConnectionID must not be set")) + }) + + It("refuses to write a Public Header if the connection ID has the wrong length", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7} + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 2, + PacketNumberLen: protocol.PacketNumberLen2, + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).To(MatchError("PublicHeader: wrong length for Connection ID: 7 (expected 8)")) + }) + + It("refuses to write a Public Header if the PacketNumberLen is not set", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 2, + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).To(MatchError("PublicHeader: PacketNumberLen not set")) + }) + + It("omits the connection ID", func() { + hdr := Header{ + PacketNumberLen: protocol.PacketNumberLen1, + PacketNumber: 1, + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{0x0, 0x1})) + }) + + It("writes diversification nonces", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0x42, + PacketNumberLen: protocol.PacketNumberLen1, + DiversificationNonce: bytes.Repeat([]byte{1}, 32), + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0xc, + 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0x42, + })) + }) + + It("writes packets with Version Flag, as a client", func() { + hdr := Header{ + VersionFlag: true, + Version: 0x11223344, + DestConnectionID: connID, + PacketNumber: 0x42, + PacketNumberLen: protocol.PacketNumberLen1, + } + err := hdr.Write(buf, protocol.PerspectiveClient, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + // must be the first assertion + Expect(buf.Len()).To(Equal(1 + 8 + 4 + 1)) // 1 FlagByte + 8 ConnectionID + 4 version number + 1 PacketNumber + firstByte, _ := buf.ReadByte() + Expect(firstByte & 0x01).To(Equal(uint8(1))) + Expect(firstByte & 0x30).To(Equal(uint8(0x0))) + Expect(buf.Bytes()[8:12]).To(Equal([]byte{0x11, 0x22, 0x33, 0x44})) + Expect(buf.Bytes()[12:13]).To(Equal([]byte{0x42})) + }) + + Context("packet number length", func() { + It("doesn't write a header if the packet number length is not set", func() { + b := &bytes.Buffer{} + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0xDECAFBAD, + } + err := hdr.Write(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).To(MatchError("PublicHeader: PacketNumberLen not set")) + }) + + It("writes a header with a 1-byte packet number", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen1, + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x8, + 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, + 0xad, + })) + }) + + It("writes a header with a 2-byte packet number", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen2, + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x18, + 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, + 0xfb, 0xad, + })) + }) + + It("writes a header with a 4-byte packet number", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0x13decafbad, + PacketNumberLen: protocol.PacketNumberLen4, + } + err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Bytes()).To(Equal([]byte{ + 0x28, + 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, + 0xde, 0xca, 0xfb, 0xad, + })) + }) + + It("refuses to write a header with a 6-byte packet number", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0xbe1337decafbad, + PacketNumberLen: protocol.PacketNumberLen6, + } + err := hdr.writePublicHeader(buf, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).To(MatchError(errInvalidPacketNumberLen)) + }) + }) + }) + }) + + Context("getting the length", func() { + var buf *bytes.Buffer + + BeforeEach(func() { + buf = &bytes.Buffer{} + }) + + Context("IETF QUIC", func() { + It("has the right length for the Long Header, for a short payload length", func() { + h := &Header{ + IsLongHeader: true, + PayloadLen: 1, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen1, + } + expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 8 /* src conn id */ + 1 /* short payload len */ + 1 /* packet number */ + Expect(h.GetLength(versionIETFHeader)).To(BeEquivalentTo(expectedLen)) + err := h.Write(buf, protocol.PerspectiveClient, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(expectedLen)) + }) + + It("has the right length for the Long Header, for a long payload length", func() { + h := &Header{ + IsLongHeader: true, + PayloadLen: 1500, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen2, + } + expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 8 /* src conn id */ + 2 /* long payload len */ + 2 /* packet number */ + Expect(h.GetLength(versionIETFHeader)).To(BeEquivalentTo(expectedLen)) + err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(expectedLen)) + }) + + It("has the right length for an Initial not containing a Token", func() { + h := &Header{ + Type: protocol.PacketTypeInitial, + IsLongHeader: true, + PayloadLen: 1500, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4}, + PacketNumberLen: protocol.PacketNumberLen2, + } + expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 4 /* src conn id */ + 1 /* token length */ + 2 /* long payload len */ + 2 /* packet number */ + Expect(h.GetLength(versionIETFHeader)).To(BeEquivalentTo(expectedLen)) + err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(expectedLen)) + }) + + It("has the right length for an Initial containing a Token", func() { + h := &Header{ + Type: protocol.PacketTypeInitial, + IsLongHeader: true, + PayloadLen: 1500, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4}, + PacketNumberLen: protocol.PacketNumberLen2, + Token: []byte("foo"), + } + expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 4 /* src conn id */ + 1 /* token length */ + 3 /* token */ + 2 /* long payload len */ + 2 /* packet number */ + Expect(h.GetLength(versionIETFHeader)).To(BeEquivalentTo(expectedLen)) + err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(expectedLen)) + }) + + It("has the right length for a Short Header containing a connection ID", func() { + h := &Header{ + PacketNumberLen: protocol.PacketNumberLen1, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + } + Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 8 + 1))) + err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(10)) + }) + + It("has the right length for a short header without a connection ID", func() { + h := &Header{PacketNumberLen: protocol.PacketNumberLen1} + Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 1))) + err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(2)) + }) + + It("has the right length for a short header with a 2 byte packet number", func() { + h := &Header{PacketNumberLen: protocol.PacketNumberLen2} + Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 2))) + err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(3)) + }) + + It("has the right length for a short header with a 5 byte packet number", func() { + h := &Header{PacketNumberLen: protocol.PacketNumberLen4} + Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 4))) + err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(5)) + }) + + It("errors when given an invalid packet number length", func() { + h := &Header{PacketNumberLen: 5} + _, err := h.GetLength(versionIETFHeader) + Expect(err).To(MatchError("invalid packet number length: 5")) + }) + }) + + Context("gQUIC 44", func() { + It("has the right length for the Long Header", func() { + h := &Header{ + IsLongHeader: true, + Type: protocol.PacketTypeInitial, + PayloadLen: 1, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen4, + } + expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 4 /* packet number */ + Expect(h.GetLength(protocol.Version44)).To(BeEquivalentTo(expectedLen)) + err := h.Write(buf, protocol.PerspectiveClient, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(expectedLen)) + }) + + It("has the right length for the Long Header containing a Diversification Nonce", func() { + h := &Header{ + IsLongHeader: true, + Type: protocol.PacketType0RTT, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen4, + DiversificationNonce: bytes.Repeat([]byte{'d'}, 32), + } + expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 4 /* packet number */ + 32 /* div nonce */ + Expect(h.GetLength(protocol.Version44)).To(BeEquivalentTo(expectedLen)) + err := h.Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(expectedLen)) + }) + + It("has the right length for a Short Header", func() { + h := &Header{ + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + PacketNumberLen: protocol.PacketNumberLen2, + } + expectedLen := 1 /*type byte*/ + 8 /* conn ID */ + 2 /* packet number */ + Expect(h.GetLength(protocol.Version44)).To(BeEquivalentTo(expectedLen)) + err := h.Write(buf, protocol.PerspectiveServer, protocol.Version44) + Expect(err).ToNot(HaveOccurred()) + Expect(buf.Len()).To(Equal(expectedLen)) + }) + }) + + Context("Public Header", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + + It("errors when PacketNumberLen is not set", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0xdecafbad, + } + _, err := hdr.GetLength(versionPublicHeader) + Expect(err).To(MatchError(errPacketNumberLenNotSet)) + }) + + It("gets the length of a packet with longest packet number length and connectionID", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen4, + } + length, err := hdr.GetLength(versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(length).To(Equal(protocol.ByteCount(1 + 8 + 4))) // 1 byte public flag, 8 bytes connectionID, and packet number + }) + + It("gets the lengths of a packet sent by the client with the VersionFlag set", func() { + hdr := Header{ + PacketNumber: 0xdecafbad, + PacketNumberLen: protocol.PacketNumberLen4, + VersionFlag: true, + Version: versionPublicHeader, + } + length, err := hdr.GetLength(versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(length).To(Equal(protocol.ByteCount(1 + 4 + 4))) // 1 byte public flag, 4 version number, and packet number + }) + + It("gets the length of a packet with longest packet number length and omitted connectionID", func() { + hdr := Header{ + PacketNumber: 0xDECAFBAD, + PacketNumberLen: protocol.PacketNumberLen4, + } + length, err := hdr.GetLength(versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(length).To(Equal(protocol.ByteCount(1 + 4))) // 1 byte public flag, and packet number + }) + + It("gets the length of a packet 2 byte packet number length ", func() { + hdr := Header{ + DestConnectionID: connID, + PacketNumber: 0xDECAFBAD, + PacketNumberLen: protocol.PacketNumberLen2, + } + length, err := hdr.GetLength(versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(length).To(Equal(protocol.ByteCount(1 + 8 + 2))) // 1 byte public flag, 8 byte connectionID, and packet number + }) + + It("works with diversification nonce", func() { + hdr := Header{ + DiversificationNonce: []byte("foo"), + PacketNumberLen: protocol.PacketNumberLen1, + } + length, err := hdr.GetLength(versionPublicHeader) + Expect(err).NotTo(HaveOccurred()) + Expect(length).To(Equal(protocol.ByteCount(1 + 3 + 1))) // 1 byte public flag, 3 byte DiversificationNonce, 1 byte PacketNumber + }) + }) + }) + + Context("Logging", func() { + var ( + buf *bytes.Buffer + logger utils.Logger + ) + + BeforeEach(func() { + buf = &bytes.Buffer{} + logger = utils.DefaultLogger + logger.SetLogLevel(utils.LogLevelDebug) + log.SetOutput(buf) + }) + + AfterEach(func() { + log.SetOutput(os.Stdout) + }) + + Context("IETF QUIC Header", func() { + It("logs version negotiation packets", func() { + destConnID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37} + srcConnID := protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37} + data, err := ComposeVersionNegotiation(destConnID, srcConnID, []protocol.VersionNumber{0x12345678, 0x87654321}) + Expect(err).ToNot(HaveOccurred()) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 4) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + hdr.Log(logger) + Expect(buf.String()).To(ContainSubstring("VersionNegotiationPacket{DestConnectionID: 0xdeadbeefcafe1337, SrcConnectionID: 0xdecafbad13371337")) + Expect(buf.String()).To(ContainSubstring("0x12345678")) + Expect(buf.String()).To(ContainSubstring("0x87654321")) + }) + + It("logs Long Headers", func() { + (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeHandshake, + PacketNumber: 0x1337, + PacketNumberLen: protocol.PacketNumberLen2, + PayloadLen: 54321, + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37}, + Version: 0xfeed, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Long Header{Type: Handshake, DestConnectionID: 0xdeadbeefcafe1337, SrcConnectionID: 0xdecafbad13371337, PacketNumber: 0x1337, PacketNumberLen: 2, PayloadLen: 54321, Version: 0xfeed}")) + }) + + It("logs Initial Packets with a Token", func() { + (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeInitial, + Token: []byte{0xde, 0xad, 0xbe, 0xef}, + PacketNumber: 0x42, + PacketNumberLen: protocol.PacketNumberLen2, + PayloadLen: 100, + DestConnectionID: protocol.ConnectionID{0xca, 0xfe, 0x13, 0x37}, + SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad}, + Version: 0xfeed, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Long Header{Type: Initial, DestConnectionID: 0xcafe1337, SrcConnectionID: 0xdecafbad, Token: 0xdeadbeef, PacketNumber: 0x42, PacketNumberLen: 2, PayloadLen: 100, Version: 0xfeed}")) + }) + + It("logs Initial Packets without a Token", func() { + (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeInitial, + PacketNumber: 0x42, + PacketNumberLen: protocol.PacketNumberLen2, + PayloadLen: 100, + DestConnectionID: protocol.ConnectionID{0xca, 0xfe, 0x13, 0x37}, + SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad}, + Version: 0xfeed, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Long Header{Type: Initial, DestConnectionID: 0xcafe1337, SrcConnectionID: 0xdecafbad, Token: (empty), PacketNumber: 0x42, PacketNumberLen: 2, PayloadLen: 100, Version: 0xfeed}")) + }) + + It("logs Initial Packets without a Token", func() { + (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeRetry, + DestConnectionID: protocol.ConnectionID{0xca, 0xfe, 0x13, 0x37}, + SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad}, + OrigDestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + Token: []byte{0x12, 0x34, 0x56}, + Version: 0xfeed, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Long Header{Type: Retry, DestConnectionID: 0xcafe1337, SrcConnectionID: 0xdecafbad, Token: 0x123456, OrigDestConnectionID: 0xdeadbeef, Version: 0xfeed}")) + }) + + It("logs Short Headers containing a connection ID", func() { + (&Header{ + KeyPhase: 1, + PacketNumber: 0x1337, + PacketNumberLen: 4, + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Short Header{DestConnectionID: 0xdeadbeefcafe1337, PacketNumber: 0x1337, PacketNumberLen: 4, KeyPhase: 1}")) + }) + }) + + Context("gQUIC 44", func() { + It("logs Long Headers", func() { + (&Header{ + IsLongHeader: true, + Type: protocol.PacketTypeHandshake, + PacketNumber: 0x1337, + PacketNumberLen: protocol.PacketNumberLen4, + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37}, + Version: protocol.Version44, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Long Header{Type: Handshake, DestConnectionID: 0xdeadbeefcafe1337, SrcConnectionID: 0xdecafbad13371337, PacketNumber: 0x1337, PacketNumberLen: 4, Version: gQUIC 44}")) + }) + + It("logs a Long Header with a Diversification Nonce", func() { + (&Header{ + IsLongHeader: true, + Type: protocol.PacketType0RTT, + PacketNumber: 0x1337, + PacketNumberLen: protocol.PacketNumberLen4, + SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37}, + DiversificationNonce: []byte{0xde, 0xad, 0xbe, 0xef}, + Version: protocol.Version44, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Long Header{Type: 0-RTT Protected, DestConnectionID: (empty), SrcConnectionID: 0xdecafbad13371337, PacketNumber: 0x1337, PacketNumberLen: 4, Diversification Nonce: 0xdeadbeef, Version: gQUIC 44}")) + }) + }) + + Context("Public Header", func() { + It("logs a Public Header containing a connection ID", func() { + (&Header{ + IsPublicHeader: true, + DestConnectionID: protocol.ConnectionID{0x13, 0x37, 0, 0, 0xde, 0xca, 0xfb, 0xad}, + PacketNumber: 0x1337, + PacketNumberLen: 6, + Version: protocol.Version39, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Public Header{ConnectionID: 0x13370000decafbad, PacketNumber: 0x1337, PacketNumberLen: 6, Version: gQUIC 39")) + }) + + It("logs a Public Header with omitted connection ID", func() { + (&Header{ + IsPublicHeader: true, + PacketNumber: 0x1337, + PacketNumberLen: 6, + Version: protocol.Version39, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Public Header{ConnectionID: (empty)")) + }) + + It("logs a Public Header without a version", func() { + (&Header{ + IsPublicHeader: true, + PacketNumber: 0x1337, + PacketNumberLen: 6, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("Version: (unset)")) + }) + + It("logs diversification nonces", func() { + (&Header{ + IsPublicHeader: true, + DestConnectionID: []byte{0x13, 0x13, 0, 0, 0xde, 0xca, 0xfb, 0xad}, + DiversificationNonce: []byte{0xba, 0xdf, 0x00, 0x0d}, + }).Log(logger) + Expect(buf.String()).To(ContainSubstring("DiversificationNonce: []byte{0xba, 0xdf, 0x0, 0xd}")) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/log.go b/vendor/lucas-clemente/quic-go/internal/wire/log.go new file mode 100644 index 00000000..465e82ab --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/log.go @@ -0,0 +1,41 @@ +package wire + +import ( + "fmt" + "strings" + + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// LogFrame logs a frame, either sent or received +func LogFrame(logger utils.Logger, frame Frame, sent bool) { + if !logger.Debug() { + return + } + dir := "<-" + if sent { + dir = "->" + } + switch f := frame.(type) { + case *StreamFrame: + logger.Debugf("\t%s &wire.StreamFrame{StreamID: %d, FinBit: %t, Offset: 0x%x, Data length: 0x%x, Offset + Data length: 0x%x}", dir, f.StreamID, f.FinBit, f.Offset, f.DataLen(), f.Offset+f.DataLen()) + case *StopWaitingFrame: + if sent { + logger.Debugf("\t%s &wire.StopWaitingFrame{LeastUnacked: 0x%x, PacketNumberLen: 0x%x}", dir, f.LeastUnacked, f.PacketNumberLen) + } else { + logger.Debugf("\t%s &wire.StopWaitingFrame{LeastUnacked: 0x%x}", dir, f.LeastUnacked) + } + case *AckFrame: + if len(f.AckRanges) > 1 { + ackRanges := make([]string, len(f.AckRanges)) + for i, r := range f.AckRanges { + ackRanges[i] = fmt.Sprintf("{Largest: %#x, Smallest: %#x}", r.Largest, r.Smallest) + } + logger.Debugf("\t%s &wire.AckFrame{LargestAcked: %#x, LowestAcked: %#x, AckRanges: {%s}, DelayTime: %s}", dir, f.LargestAcked(), f.LowestAcked(), strings.Join(ackRanges, ", "), f.DelayTime.String()) + } else { + logger.Debugf("\t%s &wire.AckFrame{LargestAcked: %#x, LowestAcked: %#x, DelayTime: %s}", dir, f.LargestAcked(), f.LowestAcked(), f.DelayTime.String()) + } + default: + logger.Debugf("\t%s %#v", dir, frame) + } +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/log_test.go b/vendor/lucas-clemente/quic-go/internal/wire/log_test.go new file mode 100644 index 00000000..4b1078f8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/log_test.go @@ -0,0 +1,96 @@ +package wire + +import ( + "bytes" + "log" + "os" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Frame logging", func() { + var ( + buf *bytes.Buffer + logger utils.Logger + ) + + BeforeEach(func() { + buf = &bytes.Buffer{} + logger = utils.DefaultLogger + logger.SetLogLevel(utils.LogLevelDebug) + log.SetOutput(buf) + }) + + AfterEach(func() { + log.SetOutput(os.Stdout) + }) + + It("doesn't log when debug is disabled", func() { + logger.SetLogLevel(utils.LogLevelInfo) + LogFrame(logger, &RstStreamFrame{}, true) + Expect(buf.Len()).To(BeZero()) + }) + + It("logs sent frames", func() { + LogFrame(logger, &RstStreamFrame{}, true) + Expect(buf.Bytes()).To(ContainSubstring("\t-> &wire.RstStreamFrame{StreamID:0x0, ErrorCode:0x0, ByteOffset:0x0}\n")) + }) + + It("logs received frames", func() { + LogFrame(logger, &RstStreamFrame{}, false) + Expect(buf.Bytes()).To(ContainSubstring("\t<- &wire.RstStreamFrame{StreamID:0x0, ErrorCode:0x0, ByteOffset:0x0}\n")) + }) + + It("logs stream frames", func() { + frame := &StreamFrame{ + StreamID: 42, + Offset: 0x1337, + Data: bytes.Repeat([]byte{'f'}, 0x100), + } + LogFrame(logger, frame, false) + Expect(buf.Bytes()).To(ContainSubstring("\t<- &wire.StreamFrame{StreamID: 42, FinBit: false, Offset: 0x1337, Data length: 0x100, Offset + Data length: 0x1437}\n")) + }) + + It("logs ACK frames without missing packets", func() { + frame := &AckFrame{ + AckRanges: []AckRange{{Smallest: 0x42, Largest: 0x1337}}, + DelayTime: 1 * time.Millisecond, + } + LogFrame(logger, frame, false) + Expect(buf.String()).To(ContainSubstring("\t<- &wire.AckFrame{LargestAcked: 0x1337, LowestAcked: 0x42, DelayTime: 1ms}\n")) + }) + + It("logs ACK frames with missing packets", func() { + frame := &AckFrame{ + AckRanges: []AckRange{ + {Smallest: 0x5, Largest: 0x8}, + {Smallest: 0x2, Largest: 0x3}, + }, + DelayTime: 12 * time.Millisecond, + } + LogFrame(logger, frame, false) + Expect(buf.String()).To(ContainSubstring("\t<- &wire.AckFrame{LargestAcked: 0x8, LowestAcked: 0x2, AckRanges: {{Largest: 0x8, Smallest: 0x5}, {Largest: 0x3, Smallest: 0x2}}, DelayTime: 12ms}\n")) + }) + + It("logs incoming StopWaiting frames", func() { + frame := &StopWaitingFrame{ + LeastUnacked: 0x1337, + } + LogFrame(logger, frame, false) + Expect(buf.Bytes()).To(ContainSubstring("\t<- &wire.StopWaitingFrame{LeastUnacked: 0x1337}\n")) + }) + + It("logs outgoing StopWaiting frames", func() { + frame := &StopWaitingFrame{ + LeastUnacked: 0x1337, + PacketNumberLen: protocol.PacketNumberLen4, + } + LogFrame(logger, frame, true) + Expect(buf.Bytes()).To(ContainSubstring("\t-> &wire.StopWaitingFrame{LeastUnacked: 0x1337, PacketNumberLen: 0x4}\n")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/max_data_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/max_data_frame.go new file mode 100644 index 00000000..0bca27da --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/max_data_frame.go @@ -0,0 +1,51 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A MaxDataFrame carries flow control information for the connection +type MaxDataFrame struct { + ByteOffset protocol.ByteCount +} + +// parseMaxDataFrame parses a MAX_DATA frame +func parseMaxDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*MaxDataFrame, error) { + // read the TypeByte + if _, err := r.ReadByte(); err != nil { + return nil, err + } + + frame := &MaxDataFrame{} + byteOffset, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + frame.ByteOffset = protocol.ByteCount(byteOffset) + return frame, nil +} + +//Write writes a MAX_STREAM_DATA frame +func (f *MaxDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + if !version.UsesIETFFrameFormat() { + // write a gQUIC WINDOW_UPDATE frame (with stream ID 0, which means connection-level there) + return (&windowUpdateFrame{ + StreamID: 0, + ByteOffset: f.ByteOffset, + }).Write(b, version) + } + b.WriteByte(0x4) + utils.WriteVarInt(b, uint64(f.ByteOffset)) + return nil +} + +// Length of a written frame +func (f *MaxDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + if !version.UsesIETFFrameFormat() { // writing this frame would result in a gQUIC WINDOW_UPDATE being written, which is longer + return 1 + 4 + 8 + } + return 1 + utils.VarIntLen(uint64(f.ByteOffset)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/max_data_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/max_data_frame_test.go new file mode 100644 index 00000000..a56d2616 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/max_data_frame_test.go @@ -0,0 +1,56 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("MAX_DATA frame", func() { + Context("when parsing", func() { + It("accepts sample frame", func() { + data := []byte{0x4} + data = append(data, encodeVarInt(0xdecafbad123456)...) // byte offset + b := bytes.NewReader(data) + frame, err := parseMaxDataFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.ByteOffset).To(Equal(protocol.ByteCount(0xdecafbad123456))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x4} + data = append(data, encodeVarInt(0xdecafbad1234567)...) // byte offset + _, err := parseMaxDataFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseMaxDataFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("writing", func() { + It("has proper min length", func() { + f := &MaxDataFrame{ + ByteOffset: 0xdeadbeef, + } + Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0xdeadbeef))) + }) + + It("writes a MAX_DATA frame", func() { + b := &bytes.Buffer{} + f := &MaxDataFrame{ + ByteOffset: 0xdeadbeefcafe, + } + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x4} + expected = append(expected, encodeVarInt(0xdeadbeefcafe)...) + Expect(b.Bytes()).To(Equal(expected)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go new file mode 100644 index 00000000..6d8be236 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go @@ -0,0 +1,60 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A MaxStreamDataFrame carries flow control information for a stream +type MaxStreamDataFrame struct { + StreamID protocol.StreamID + ByteOffset protocol.ByteCount +} + +// parseMaxStreamDataFrame parses a MAX_STREAM_DATA frame +func parseMaxStreamDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*MaxStreamDataFrame, error) { + frame := &MaxStreamDataFrame{} + + // read the TypeByte + if _, err := r.ReadByte(); err != nil { + return nil, err + } + + sid, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + frame.StreamID = protocol.StreamID(sid) + + byteOffset, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + frame.ByteOffset = protocol.ByteCount(byteOffset) + return frame, nil +} + +// Write writes a MAX_STREAM_DATA frame +func (f *MaxStreamDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + if !version.UsesIETFFrameFormat() { + return (&windowUpdateFrame{ + StreamID: f.StreamID, + ByteOffset: f.ByteOffset, + }).Write(b, version) + } + b.WriteByte(0x5) + utils.WriteVarInt(b, uint64(f.StreamID)) + utils.WriteVarInt(b, uint64(f.ByteOffset)) + return nil +} + +// Length of a written frame +func (f *MaxStreamDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + // writing this frame would result in a gQUIC WINDOW_UPDATE being written, which has a different length + if !version.UsesIETFFrameFormat() { + return 1 + 4 + 8 + } + return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.ByteOffset)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame_test.go new file mode 100644 index 00000000..06f7c245 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_data_frame_test.go @@ -0,0 +1,62 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("MAX_STREAM_DATA frame", func() { + Context("parsing", func() { + It("accepts sample frame", func() { + data := []byte{0x5} + data = append(data, encodeVarInt(0xdeadbeef)...) // Stream ID + data = append(data, encodeVarInt(0x12345678)...) // Offset + b := bytes.NewReader(data) + frame, err := parseMaxStreamDataFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdeadbeef))) + Expect(frame.ByteOffset).To(Equal(protocol.ByteCount(0x12345678))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x5} + data = append(data, encodeVarInt(0xdeadbeef)...) // Stream ID + data = append(data, encodeVarInt(0x12345678)...) // Offset + _, err := parseMaxStreamDataFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseMaxStreamDataFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("writing", func() { + It("has proper min length", func() { + f := &MaxStreamDataFrame{ + StreamID: 0x1337, + ByteOffset: 0xdeadbeef, + } + Expect(f.Length(protocol.VersionWhatever)).To(Equal(1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.ByteOffset)))) + }) + + It("writes a sample frame", func() { + b := &bytes.Buffer{} + f := &MaxStreamDataFrame{ + StreamID: 0xdecafbad, + ByteOffset: 0xdeadbeefcafe42, + } + expected := []byte{0x5} + expected = append(expected, encodeVarInt(0xdecafbad)...) + expected = append(expected, encodeVarInt(0xdeadbeefcafe42)...) + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal(expected)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame.go new file mode 100644 index 00000000..9f5424da --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame.go @@ -0,0 +1,37 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A MaxStreamIDFrame is a MAX_STREAM_ID frame +type MaxStreamIDFrame struct { + StreamID protocol.StreamID +} + +// parseMaxStreamIDFrame parses a MAX_STREAM_ID frame +func parseMaxStreamIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStreamIDFrame, error) { + // read the Type byte + if _, err := r.ReadByte(); err != nil { + return nil, err + } + streamID, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + return &MaxStreamIDFrame{StreamID: protocol.StreamID(streamID)}, nil +} + +func (f *MaxStreamIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + b.WriteByte(0x6) + utils.WriteVarInt(b, uint64(f.StreamID)) + return nil +} + +// Length of a written frame +func (f *MaxStreamIDFrame) Length(protocol.VersionNumber) protocol.ByteCount { + return 1 + utils.VarIntLen(uint64(f.StreamID)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame_test.go new file mode 100644 index 00000000..66a27e7b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/max_stream_id_frame_test.go @@ -0,0 +1,51 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("MAX_STREAM_ID frame", func() { + Context("parsing", func() { + It("accepts sample frame", func() { + data := []byte{0x6} + data = append(data, encodeVarInt(0xdecafbad)...) + b := bytes.NewReader(data) + f, err := parseMaxStreamIDFrame(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(f.StreamID).To(Equal(protocol.StreamID(0xdecafbad))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x06} + data = append(data, encodeVarInt(0xdeadbeefcafe13)...) + _, err := parseMaxStreamIDFrame(bytes.NewReader(data), protocol.VersionWhatever) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseMaxStreamIDFrame(bytes.NewReader(data[0:i]), protocol.VersionWhatever) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := MaxStreamIDFrame{StreamID: 0x12345678} + frame.Write(b, protocol.VersionWhatever) + expected := []byte{0x6} + expected = append(expected, encodeVarInt(0x12345678)...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("has the correct min length", func() { + frame := MaxStreamIDFrame{StreamID: 0x1337} + Expect(frame.Length(protocol.VersionWhatever)).To(Equal(1 + utils.VarIntLen(0x1337))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go new file mode 100644 index 00000000..f2a27d84 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go @@ -0,0 +1,39 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// A PathChallengeFrame is a PATH_CHALLENGE frame +type PathChallengeFrame struct { + Data [8]byte +} + +func parsePathChallengeFrame(r *bytes.Reader, version protocol.VersionNumber) (*PathChallengeFrame, error) { + if _, err := r.ReadByte(); err != nil { + return nil, err + } + frame := &PathChallengeFrame{} + if _, err := io.ReadFull(r, frame.Data[:]); err != nil { + if err == io.ErrUnexpectedEOF { + return nil, io.EOF + } + return nil, err + } + return frame, nil +} + +func (f *PathChallengeFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + typeByte := uint8(0x0e) + b.WriteByte(typeByte) + b.Write(f.Data[:]) + return nil +} + +// Length of a written frame +func (f *PathChallengeFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { + return 1 + 8 +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame_test.go new file mode 100644 index 00000000..bbfc7109 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/path_challenge_frame_test.go @@ -0,0 +1,47 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("PATH_CHALLENGE frame", func() { + Context("when parsing", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x0e, 1, 2, 3, 4, 5, 6, 7, 8}) + f, err := parsePathChallengeFrame(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + Expect(f.Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) + }) + + It("errors on EOFs", func() { + data := []byte{0x0e, 1, 2, 3, 4, 5, 6, 7, 8} + _, err := parsePathChallengeFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parsePathChallengeFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("when writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := PathChallengeFrame{Data: [8]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}} + err := frame.Write(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x0e, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37})) + }) + + It("has the correct min length", func() { + frame := PathChallengeFrame{} + Expect(frame.Length(protocol.VersionWhatever)).To(Equal(protocol.ByteCount(9))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/path_response_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/path_response_frame.go new file mode 100644 index 00000000..2ab2fcda --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/path_response_frame.go @@ -0,0 +1,39 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// A PathResponseFrame is a PATH_RESPONSE frame +type PathResponseFrame struct { + Data [8]byte +} + +func parsePathResponseFrame(r *bytes.Reader, version protocol.VersionNumber) (*PathResponseFrame, error) { + if _, err := r.ReadByte(); err != nil { + return nil, err + } + frame := &PathResponseFrame{} + if _, err := io.ReadFull(r, frame.Data[:]); err != nil { + if err == io.ErrUnexpectedEOF { + return nil, io.EOF + } + return nil, err + } + return frame, nil +} + +func (f *PathResponseFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + typeByte := uint8(0x0f) + b.WriteByte(typeByte) + b.Write(f.Data[:]) + return nil +} + +// Length of a written frame +func (f *PathResponseFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { + return 1 + 8 +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/path_response_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/path_response_frame_test.go new file mode 100644 index 00000000..14e45bed --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/path_response_frame_test.go @@ -0,0 +1,47 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("PATH_RESPONSE frame", func() { + Context("when parsing", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x0f, 1, 2, 3, 4, 5, 6, 7, 8}) + f, err := parsePathResponseFrame(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + Expect(f.Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) + }) + + It("errors on EOFs", func() { + data := []byte{0x0f, 1, 2, 3, 4, 5, 6, 7, 8} + _, err := parsePathResponseFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parsePathResponseFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("when writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := PathResponseFrame{Data: [8]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}} + err := frame.Write(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x0f, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37})) + }) + + It("has the correct min length", func() { + frame := PathResponseFrame{} + Expect(frame.Length(protocol.VersionWhatever)).To(Equal(protocol.ByteCount(9))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ping_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/ping_frame.go new file mode 100644 index 00000000..bc1dedac --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ping_frame.go @@ -0,0 +1,33 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// A PingFrame is a ping frame +type PingFrame struct{} + +// parsePingFrame parses a Ping frame +func parsePingFrame(r *bytes.Reader, version protocol.VersionNumber) (*PingFrame, error) { + frame := &PingFrame{} + + _, err := r.ReadByte() + if err != nil { + return nil, err + } + + return frame, nil +} + +func (f *PingFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + typeByte := uint8(0x07) + b.WriteByte(typeByte) + return nil +} + +// Length of a written frame +func (f *PingFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + return 1 +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/ping_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/ping_frame_test.go new file mode 100644 index 00000000..54c7c6c1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/ping_frame_test.go @@ -0,0 +1,39 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("PingFrame", func() { + Context("when parsing", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x07}) + _, err := parsePingFrame(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + _, err := parsePingFrame(bytes.NewReader(nil), protocol.VersionWhatever) + Expect(err).To(HaveOccurred()) + }) + }) + + Context("when writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := PingFrame{} + frame.Write(b, protocol.VersionWhatever) + Expect(b.Bytes()).To(Equal([]byte{0x07})) + }) + + It("has the correct min length", func() { + frame := PingFrame{} + Expect(frame.Length(0)).To(Equal(protocol.ByteCount(1))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/public_reset.go b/vendor/lucas-clemente/quic-go/internal/wire/public_reset.go new file mode 100644 index 00000000..b57ea7ad --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/public_reset.go @@ -0,0 +1,65 @@ +package wire + +import ( + "bytes" + "encoding/binary" + "errors" + + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A PublicReset is a PUBLIC_RESET +type PublicReset struct { + RejectedPacketNumber protocol.PacketNumber + Nonce uint64 +} + +// WritePublicReset writes a PUBLIC_RESET +func WritePublicReset(connectionID protocol.ConnectionID, rejectedPacketNumber protocol.PacketNumber, nonceProof uint64) []byte { + b := &bytes.Buffer{} + b.WriteByte(0x0a) + b.Write(connectionID) + utils.LittleEndian.WriteUint32(b, uint32(handshake.TagPRST)) + utils.LittleEndian.WriteUint32(b, 2) + utils.LittleEndian.WriteUint32(b, uint32(handshake.TagRNON)) + utils.LittleEndian.WriteUint32(b, 8) + utils.LittleEndian.WriteUint32(b, uint32(handshake.TagRSEQ)) + utils.LittleEndian.WriteUint32(b, 16) + utils.LittleEndian.WriteUint64(b, nonceProof) + utils.LittleEndian.WriteUint64(b, uint64(rejectedPacketNumber)) + return b.Bytes() +} + +// ParsePublicReset parses a PUBLIC_RESET +func ParsePublicReset(r *bytes.Reader) (*PublicReset, error) { + pr := PublicReset{} + msg, err := handshake.ParseHandshakeMessage(r) + if err != nil { + return nil, err + } + if msg.Tag != handshake.TagPRST { + return nil, errors.New("wrong public reset tag") + } + + // The RSEQ tag is mandatory according to the gQUIC wire spec. + // However, Google doesn't send RSEQ in their PUBLIC_RESETs. + // Therefore, we'll treat RSEQ as an optional field. + if rseq, ok := msg.Data[handshake.TagRSEQ]; ok { + if len(rseq) != 8 { + return nil, errors.New("invalid RSEQ tag") + } + pr.RejectedPacketNumber = protocol.PacketNumber(binary.LittleEndian.Uint64(rseq)) + } + + rnon, ok := msg.Data[handshake.TagRNON] + if !ok { + return nil, errors.New("RNON missing") + } + if len(rnon) != 8 { + return nil, errors.New("invalid RNON tag") + } + pr.Nonce = binary.LittleEndian.Uint64(rnon) + return &pr, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/public_reset_test.go b/vendor/lucas-clemente/quic-go/internal/wire/public_reset_test.go new file mode 100644 index 00000000..45347df6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/public_reset_test.go @@ -0,0 +1,96 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("public reset", func() { + Context("writing", func() { + It("writes public reset packets", func() { + Expect(WritePublicReset(protocol.ConnectionID{0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef}, 0x8badf00d, 0xdecafbad)).To(Equal([]byte{ + 0x0a, + 0x0, 0x0, 0x0, 0x0, 0xde, 0xad, 0xbe, 0xef, + 'P', 'R', 'S', 'T', + 0x02, 0x00, 0x00, 0x00, + 'R', 'N', 'O', 'N', + 0x08, 0x00, 0x00, 0x00, + 'R', 'S', 'E', 'Q', + 0x10, 0x00, 0x00, 0x00, + 0xad, 0xfb, 0xca, 0xde, 0x0, 0x0, 0x0, 0x0, + 0x0d, 0xf0, 0xad, 0x8b, 0x0, 0x0, 0x0, 0x0, + })) + }) + }) + + Context("parsing", func() { + var b *bytes.Buffer + + BeforeEach(func() { + b = &bytes.Buffer{} + }) + + It("parses a public reset", func() { + packet := WritePublicReset(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, 0x8badf00d, 0xdecafbad) + pr, err := ParsePublicReset(bytes.NewReader(packet[9:])) // 1 byte Public Flag, 8 bytes connection ID + Expect(err).ToNot(HaveOccurred()) + Expect(pr.Nonce).To(Equal(uint64(0xdecafbad))) + Expect(pr.RejectedPacketNumber).To(Equal(protocol.PacketNumber(0x8badf00d))) + }) + + It("rejects packets that it can't parse", func() { + _, err := ParsePublicReset(bytes.NewReader([]byte{})) + Expect(err).To(MatchError(io.EOF)) + }) + + It("rejects packets with the wrong tag", func() { + handshake.HandshakeMessage{Tag: handshake.TagREJ, Data: nil}.Write(b) + _, err := ParsePublicReset(bytes.NewReader(b.Bytes())) + Expect(err).To(MatchError("wrong public reset tag")) + }) + + It("rejects packets missing the nonce", func() { + data := map[handshake.Tag][]byte{ + handshake.TagRSEQ: {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + } + handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b) + _, err := ParsePublicReset(bytes.NewReader(b.Bytes())) + Expect(err).To(MatchError("RNON missing")) + }) + + It("rejects packets with a wrong length nonce", func() { + data := map[handshake.Tag][]byte{ + handshake.TagRSEQ: {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + handshake.TagRNON: {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13}, + } + handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b) + _, err := ParsePublicReset(bytes.NewReader(b.Bytes())) + Expect(err).To(MatchError("invalid RNON tag")) + }) + + It("accepts packets missing the rejected packet number", func() { + data := map[handshake.Tag][]byte{ + handshake.TagRNON: {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + } + handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b) + pr, err := ParsePublicReset(bytes.NewReader(b.Bytes())) + Expect(err).ToNot(HaveOccurred()) + Expect(pr.Nonce).To(Equal(uint64(0x3713fecaefbeadde))) + }) + + It("rejects packets with a wrong length rejected packet number", func() { + data := map[handshake.Tag][]byte{ + handshake.TagRSEQ: {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13}, + handshake.TagRNON: {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}, + } + handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b) + _, err := ParsePublicReset(bytes.NewReader(b.Bytes())) + Expect(err).To(MatchError("invalid RSEQ tag")) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame.go new file mode 100644 index 00000000..209422c2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame.go @@ -0,0 +1,89 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A RstStreamFrame is a RST_STREAM frame in QUIC +type RstStreamFrame struct { + StreamID protocol.StreamID + // The error code is a uint32 in gQUIC, but a uint16 in IETF QUIC. + // protocol.ApplicaitonErrorCode is a uint16, so larger values in gQUIC frames will be truncated. + ErrorCode protocol.ApplicationErrorCode + ByteOffset protocol.ByteCount +} + +// parseRstStreamFrame parses a RST_STREAM frame +func parseRstStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*RstStreamFrame, error) { + if _, err := r.ReadByte(); err != nil { // read the TypeByte + return nil, err + } + + var streamID protocol.StreamID + var errorCode uint16 + var byteOffset protocol.ByteCount + if version.UsesIETFFrameFormat() { + sid, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + streamID = protocol.StreamID(sid) + errorCode, err = utils.BigEndian.ReadUint16(r) + if err != nil { + return nil, err + } + bo, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + byteOffset = protocol.ByteCount(bo) + } else { + sid, err := utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + streamID = protocol.StreamID(sid) + bo, err := utils.BigEndian.ReadUint64(r) + if err != nil { + return nil, err + } + byteOffset = protocol.ByteCount(bo) + ec, err := utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + errorCode = uint16(ec) + } + + return &RstStreamFrame{ + StreamID: streamID, + ErrorCode: protocol.ApplicationErrorCode(errorCode), + ByteOffset: byteOffset, + }, nil +} + +//Write writes a RST_STREAM frame +func (f *RstStreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + b.WriteByte(0x01) + if version.UsesIETFFrameFormat() { + utils.WriteVarInt(b, uint64(f.StreamID)) + utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode)) + utils.WriteVarInt(b, uint64(f.ByteOffset)) + } else { + utils.BigEndian.WriteUint32(b, uint32(f.StreamID)) + utils.BigEndian.WriteUint64(b, uint64(f.ByteOffset)) + utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode)) + } + return nil +} + +// Length of a written frame +func (f *RstStreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + if version.UsesIETFFrameFormat() { + return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2 + utils.VarIntLen(uint64(f.ByteOffset)) + } + return 1 + 4 + 8 + 4 +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame_test.go new file mode 100644 index 00000000..f39be0f7 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/rst_stream_frame_test.go @@ -0,0 +1,128 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("RST_STREAM frame", func() { + Context("when parsing", func() { + Context("in varint encoding", func() { + It("accepts sample frame", func() { + data := []byte{0x1} + data = append(data, encodeVarInt(0xdeadbeef)...) // stream ID + data = append(data, []byte{0x13, 0x37}...) // error code + data = append(data, encodeVarInt(0x987654321)...) // byte offset + b := bytes.NewReader(data) + frame, err := parseRstStreamFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdeadbeef))) + Expect(frame.ByteOffset).To(Equal(protocol.ByteCount(0x987654321))) + Expect(frame.ErrorCode).To(Equal(protocol.ApplicationErrorCode(0x1337))) + }) + + It("errors on EOFs", func() { + data := []byte{0x1} + data = append(data, encodeVarInt(0xdeadbeef)...) // stream ID + data = append(data, []byte{0x13, 0x37}...) // error code + data = append(data, encodeVarInt(0x987654321)...) // byte offset + _, err := parseRstStreamFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseRstStreamFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("in big endian", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x1, + 0xde, 0xad, 0xbe, 0xef, // stream id + 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // byte offset + 0x0, 0x0, 0xca, 0xfe, // error code + }) + frame, err := parseRstStreamFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdeadbeef))) + Expect(frame.ByteOffset).To(Equal(protocol.ByteCount(0x8877665544332211))) + Expect(frame.ErrorCode).To(Equal(protocol.ApplicationErrorCode(0xcafe))) + }) + + It("errors on EOFs", func() { + data := []byte{0x1, + 0xef, 0xbe, 0xad, 0xde, 0x44, // stream id + 0x33, 0x22, 0x11, 0xad, 0xfb, 0xca, 0xde, 0x34, // byte offset + 0x12, 0x37, 0x13, // error code + } + _, err := parseRstStreamFrame(bytes.NewReader(data), versionBigEndian) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseRstStreamFrame(bytes.NewReader(data[0:i]), versionBigEndian) + Expect(err).To(HaveOccurred()) + } + }) + }) + }) + + Context("when writing", func() { + Context("in varint encoding", func() { + It("writes a sample frame", func() { + frame := RstStreamFrame{ + StreamID: 0x1337, + ByteOffset: 0x11223344decafbad, + ErrorCode: 0xcafe, + } + b := &bytes.Buffer{} + err := frame.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x1} + expected = append(expected, encodeVarInt(0x1337)...) + expected = append(expected, []byte{0xca, 0xfe}...) + expected = append(expected, encodeVarInt(0x11223344decafbad)...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("has the correct min length", func() { + rst := RstStreamFrame{ + StreamID: 0x1337, + ByteOffset: 0x1234567, + ErrorCode: 0xde, + } + expectedLen := 1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x1234567) + 2 + Expect(rst.Length(versionIETFFrames)).To(Equal(expectedLen)) + }) + }) + + Context("in big endian", func() { + It("writes a sample frame", func() { + frame := RstStreamFrame{ + StreamID: 0x1337, + ByteOffset: 0x11223344decafbad, + ErrorCode: 0xcafe, + } + b := &bytes.Buffer{} + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x01, + 0x0, 0x0, 0x13, 0x37, // stream id + 0x11, 0x22, 0x33, 0x44, 0xde, 0xca, 0xfb, 0xad, // byte offset + 0x0, 0x0, 0xca, 0xfe, // error code + })) + }) + + It("has the correct min length", func() { + rst := RstStreamFrame{ + StreamID: 0x1337, + ByteOffset: 0x1000, + ErrorCode: 0xde, + } + Expect(rst.Length(versionBigEndian)).To(Equal(protocol.ByteCount(17))) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go new file mode 100644 index 00000000..b5e69804 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go @@ -0,0 +1,47 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A StopSendingFrame is a STOP_SENDING frame +type StopSendingFrame struct { + StreamID protocol.StreamID + ErrorCode protocol.ApplicationErrorCode +} + +// parseStopSendingFrame parses a STOP_SENDING frame +func parseStopSendingFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StopSendingFrame, error) { + if _, err := r.ReadByte(); err != nil { // read the TypeByte + return nil, err + } + + streamID, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + errorCode, err := utils.BigEndian.ReadUint16(r) + if err != nil { + return nil, err + } + + return &StopSendingFrame{ + StreamID: protocol.StreamID(streamID), + ErrorCode: protocol.ApplicationErrorCode(errorCode), + }, nil +} + +// Length of a written frame +func (f *StopSendingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { + return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2 +} + +func (f *StopSendingFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + b.WriteByte(0x0c) + utils.WriteVarInt(b, uint64(f.StreamID)) + utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode)) + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame_test.go new file mode 100644 index 00000000..2f93487a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stop_sending_frame_test.go @@ -0,0 +1,63 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("STOP_SENDING frame", func() { + Context("when parsing", func() { + It("parses a sample frame", func() { + data := []byte{0x0c} + data = append(data, encodeVarInt(0xdecafbad)...) // stream ID + data = append(data, []byte{0x13, 0x37}...) // error code + b := bytes.NewReader(data) + frame, err := parseStopSendingFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdecafbad))) + Expect(frame.ErrorCode).To(Equal(protocol.ApplicationErrorCode(0x1337))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x0c} + data = append(data, encodeVarInt(0xdecafbad)...) // stream ID + data = append(data, []byte{0x13, 0x37}...) // error code + _, err := parseStopSendingFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseStopSendingFrame(bytes.NewReader(data[:i]), versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("when writing", func() { + It("writes", func() { + frame := &StopSendingFrame{ + StreamID: 0xdeadbeefcafe, + ErrorCode: 0x10, + } + buf := &bytes.Buffer{} + err := frame.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x0c} + expected = append(expected, encodeVarInt(0xdeadbeefcafe)...) + expected = append(expected, []byte{0x0, 0x10}...) + Expect(buf.Bytes()).To(Equal(expected)) + }) + + It("has the correct min length", func() { + frame := &StopSendingFrame{ + StreamID: 0xdeadbeef, + ErrorCode: 0x10, + } + Expect(frame.Length(versionIETFFrames)).To(Equal(1 + 2 + utils.VarIntLen(0xdeadbeef))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame.go new file mode 100644 index 00000000..b87606ad --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame.go @@ -0,0 +1,77 @@ +package wire + +import ( + "bytes" + "errors" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A StopWaitingFrame in QUIC +type StopWaitingFrame struct { + LeastUnacked protocol.PacketNumber + PacketNumberLen protocol.PacketNumberLen + // PacketNumber is the packet number of the packet that this StopWaitingFrame will be sent with + PacketNumber protocol.PacketNumber +} + +var ( + errLeastUnackedHigherThanPacketNumber = errors.New("StopWaitingFrame: LeastUnacked can't be greater than the packet number") + errPacketNumberNotSet = errors.New("StopWaitingFrame: PacketNumber not set") + errPacketNumberLenNotSet = errors.New("StopWaitingFrame: PacketNumberLen not set") +) + +func (f *StopWaitingFrame) Write(b *bytes.Buffer, v protocol.VersionNumber) error { + if v.UsesIETFFrameFormat() { + return errors.New("STOP_WAITING not defined in IETF QUIC") + } + // make sure the PacketNumber was set + if f.PacketNumber == protocol.PacketNumber(0) { + return errPacketNumberNotSet + } + if f.LeastUnacked > f.PacketNumber { + return errLeastUnackedHigherThanPacketNumber + } + + b.WriteByte(0x06) + leastUnackedDelta := uint64(f.PacketNumber - f.LeastUnacked) + switch f.PacketNumberLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(leastUnackedDelta)) + case protocol.PacketNumberLen2: + utils.BigEndian.WriteUint16(b, uint16(leastUnackedDelta)) + case protocol.PacketNumberLen4: + utils.BigEndian.WriteUint32(b, uint32(leastUnackedDelta)) + case protocol.PacketNumberLen6: + utils.BigEndian.WriteUint48(b, leastUnackedDelta&(1<<48-1)) + default: + return errPacketNumberLenNotSet + } + return nil +} + +// Length of a written frame +func (f *StopWaitingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { + return 1 + protocol.ByteCount(f.PacketNumberLen) +} + +// parseStopWaitingFrame parses a StopWaiting frame +func parseStopWaitingFrame(r *bytes.Reader, packetNumber protocol.PacketNumber, packetNumberLen protocol.PacketNumberLen, _ protocol.VersionNumber) (*StopWaitingFrame, error) { + frame := &StopWaitingFrame{} + + // read the TypeByte + if _, err := r.ReadByte(); err != nil { + return nil, err + } + + leastUnackedDelta, err := utils.BigEndian.ReadUintN(r, uint8(packetNumberLen)) + if err != nil { + return nil, err + } + if leastUnackedDelta > uint64(packetNumber) { + return nil, errors.New("invalid LeastUnackedDelta") + } + frame.LeastUnacked = protocol.PacketNumber(uint64(packetNumber) - leastUnackedDelta) + return frame, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame_test.go new file mode 100644 index 00000000..7452f06d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stop_waiting_frame_test.go @@ -0,0 +1,208 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("StopWaitingFrame", func() { + Context("when parsing", func() { + Context("in big endian", func() { + It("accepts sample frame", func() { + b := bytes.NewReader([]byte{0x06, 0x12, 0x34}) + frame, err := parseStopWaitingFrame(b, 0x1337, 2, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LeastUnacked).To(Equal(protocol.PacketNumber(0x1337 - 0x1234))) + Expect(b.Len()).To(BeZero()) + }) + }) + + It("rejects frames that would have a negative LeastUnacked value", func() { + b := bytes.NewReader([]byte{0x06, 0xD}) + _, err := parseStopWaitingFrame(b, 10, 1, protocol.VersionWhatever) + Expect(err).To(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with 0 as LeastUnacked", func() { + b := bytes.NewReader([]byte{0x6, 0x8}) + frame, err := parseStopWaitingFrame(b, 8, 1, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LeastUnacked).To(Equal(protocol.PacketNumber(0))) + Expect(b.Len()).To(BeZero()) + }) + + It("rejects frames that underflow LeastUnacked", func() { + b := bytes.NewReader([]byte{0x6, 0x9}) + _, err := parseStopWaitingFrame(b, 8, 1, protocol.VersionWhatever) + Expect(err).To(MatchError("invalid LeastUnackedDelta")) + }) + + It("errors on EOFs", func() { + data := []byte{0x06, 0x03} + _, err := parseStopWaitingFrame(bytes.NewReader(data), 5, 1, protocol.VersionWhatever) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseStopWaitingFrame(bytes.NewReader(data[0:i]), 5, 1, protocol.VersionWhatever) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("when writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumber: 13, + PacketNumberLen: protocol.PacketNumberLen6, + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0]).To(Equal(uint8(0x06))) + Expect(b.Bytes()[1:7]).To(Equal([]byte{0, 0, 0, 0, 0, 3})) + }) + + It("writes a frame for LeastUnacked = 0", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 0, + PacketNumber: 8, + PacketNumberLen: protocol.PacketNumberLen1, + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x6, 0x8})) + }) + + It("errors when PacketNumber was not set", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumberLen: protocol.PacketNumberLen1, + } + err := frame.Write(b, versionBigEndian) + Expect(err).To(MatchError(errPacketNumberNotSet)) + }) + + It("errors when PacketNumberLen was not set", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumber: 13, + } + err := frame.Write(b, versionBigEndian) + Expect(err).To(MatchError(errPacketNumberLenNotSet)) + }) + + It("errors when the LeastUnackedDelta would be negative", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumber: 5, + PacketNumberLen: protocol.PacketNumberLen1, + } + err := frame.Write(b, versionBigEndian) + Expect(err).To(MatchError(errLeastUnackedHigherThanPacketNumber)) + }) + + It("refuses to write for IETF QUIC", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumber: 13, + PacketNumberLen: protocol.PacketNumberLen6, + } + err := frame.Write(b, versionIETFFrames) + Expect(err).To(MatchError("STOP_WAITING not defined in IETF QUIC")) + }) + + Context("LeastUnackedDelta length", func() { + Context("in big endian", func() { + It("writes a 1-byte LeastUnackedDelta", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumber: 13, + PacketNumberLen: protocol.PacketNumberLen1, + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(2)) + Expect(b.Bytes()[1]).To(Equal(uint8(3))) + }) + + It("writes a 2-byte LeastUnackedDelta", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 0x10, + PacketNumber: 0x1300, + PacketNumberLen: protocol.PacketNumberLen2, + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(3)) + Expect(b.Bytes()[1:3]).To(Equal([]byte{0x12, 0xf0})) + }) + + It("writes a 4-byte LeastUnackedDelta", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 0x1000, + PacketNumber: 0x12345678, + PacketNumberLen: protocol.PacketNumberLen4, + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(5)) + Expect(b.Bytes()[1:5]).To(Equal([]byte{0x12, 0x34, 0x46, 0x78})) + }) + + It("writes a 6-byte LeastUnackedDelta, for a delta that fits into 6 bytes", func() { + b := &bytes.Buffer{} + frame := &StopWaitingFrame{ + LeastUnacked: 0x10, + PacketNumber: 0x123456789abc, + PacketNumberLen: protocol.PacketNumberLen6, + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(7)) + Expect(b.Bytes()[1:7]).To(Equal([]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc - 0x10})) + }) + }) + }) + }) + + Context("Length", func() { + It("calculates the right length", func() { + for _, length := range []protocol.PacketNumberLen{protocol.PacketNumberLen1, protocol.PacketNumberLen2, protocol.PacketNumberLen4, protocol.PacketNumberLen6} { + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumberLen: length, + } + Expect(frame.Length(protocol.VersionWhatever)).To(Equal(protocol.ByteCount(length + 1))) + } + }) + }) + + Context("self consistency", func() { + It("reads a STOP_WAITING frame that it wrote", func() { + packetNumber := protocol.PacketNumber(13) + frame := &StopWaitingFrame{ + LeastUnacked: 10, + PacketNumber: packetNumber, + PacketNumberLen: protocol.PacketNumberLen4, + } + b := &bytes.Buffer{} + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + readframe, err := parseStopWaitingFrame(bytes.NewReader(b.Bytes()), packetNumber, protocol.PacketNumberLen4, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(readframe.LeastUnacked).To(Equal(frame.LeastUnacked)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame.go new file mode 100644 index 00000000..a083a9f5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame.go @@ -0,0 +1,52 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A StreamBlockedFrame in QUIC +type StreamBlockedFrame struct { + StreamID protocol.StreamID + Offset protocol.ByteCount +} + +// parseStreamBlockedFrame parses a STREAM_BLOCKED frame +func parseStreamBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamBlockedFrame, error) { + if _, err := r.ReadByte(); err != nil { // read the TypeByte + return nil, err + } + sid, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + offset, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + return &StreamBlockedFrame{ + StreamID: protocol.StreamID(sid), + Offset: protocol.ByteCount(offset), + }, nil +} + +// Write writes a STREAM_BLOCKED frame +func (f *StreamBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + if !version.UsesIETFFrameFormat() { + return (&blockedFrameLegacy{StreamID: f.StreamID}).Write(b, version) + } + b.WriteByte(0x09) + utils.WriteVarInt(b, uint64(f.StreamID)) + utils.WriteVarInt(b, uint64(f.Offset)) + return nil +} + +// Length of a written frame +func (f *StreamBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + if !version.UsesIETFFrameFormat() { + return 1 + 4 + } + return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.Offset)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame_test.go new file mode 100644 index 00000000..d72f4bda --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_blocked_frame_test.go @@ -0,0 +1,63 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("STREAM_BLOCKED frame", func() { + Context("parsing", func() { + It("accepts sample frame", func() { + data := []byte{0x9} + data = append(data, encodeVarInt(0xdeadbeef)...) // stream ID + data = append(data, encodeVarInt(0xdecafbad)...) // offset + b := bytes.NewReader(data) + frame, err := parseStreamBlockedFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdeadbeef))) + Expect(frame.Offset).To(Equal(protocol.ByteCount(0xdecafbad))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x9} + data = append(data, encodeVarInt(0xdeadbeef)...) + data = append(data, encodeVarInt(0xc0010ff)...) + _, err := parseStreamBlockedFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseStreamBlockedFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("writing", func() { + It("has proper min length", func() { + f := &StreamBlockedFrame{ + StreamID: 0x1337, + Offset: 0xdeadbeef, + } + Expect(f.Length(0)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0xdeadbeef))) + }) + + It("writes a sample frame", func() { + b := &bytes.Buffer{} + f := &StreamBlockedFrame{ + StreamID: 0xdecafbad, + Offset: 0x1337, + } + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x9} + expected = append(expected, encodeVarInt(uint64(f.StreamID))...) + expected = append(expected, encodeVarInt(uint64(f.Offset))...) + Expect(b.Bytes()).To(Equal(expected)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame.go new file mode 100644 index 00000000..192319e6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame.go @@ -0,0 +1,179 @@ +package wire + +import ( + "bytes" + "errors" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +// A StreamFrame of QUIC +type StreamFrame struct { + StreamID protocol.StreamID + FinBit bool + DataLenPresent bool + Offset protocol.ByteCount + Data []byte +} + +// parseStreamFrame reads a STREAM frame +func parseStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*StreamFrame, error) { + if !version.UsesIETFFrameFormat() { + return parseLegacyStreamFrame(r, version) + } + + frame := &StreamFrame{} + + typeByte, err := r.ReadByte() + if err != nil { + return nil, err + } + + frame.FinBit = typeByte&0x1 > 0 + frame.DataLenPresent = typeByte&0x2 > 0 + hasOffset := typeByte&0x4 > 0 + + streamID, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + frame.StreamID = protocol.StreamID(streamID) + if hasOffset { + offset, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + frame.Offset = protocol.ByteCount(offset) + } + + var dataLen uint64 + if frame.DataLenPresent { + var err error + dataLen, err = utils.ReadVarInt(r) + if err != nil { + return nil, err + } + // shortcut to prevent the unnecessary allocation of dataLen bytes + // if the dataLen is larger than the remaining length of the packet + // reading the packet contents would result in EOF when attempting to READ + if dataLen > uint64(r.Len()) { + return nil, io.EOF + } + } else { + // The rest of the packet is data + dataLen = uint64(r.Len()) + } + if dataLen != 0 { + frame.Data = make([]byte, dataLen) + if _, err := io.ReadFull(r, frame.Data); err != nil { + // this should never happen, since we already checked the dataLen earlier + return nil, err + } + } + if frame.Offset+frame.DataLen() > protocol.MaxByteCount { + return nil, qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset") + } + return frame, nil +} + +// Write writes a STREAM frame +func (f *StreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + if !version.UsesIETFFrameFormat() { + return f.writeLegacy(b, version) + } + + if len(f.Data) == 0 && !f.FinBit { + return errors.New("StreamFrame: attempting to write empty frame without FIN") + } + + typeByte := byte(0x10) + if f.FinBit { + typeByte ^= 0x1 + } + hasOffset := f.Offset != 0 + if f.DataLenPresent { + typeByte ^= 0x2 + } + if hasOffset { + typeByte ^= 0x4 + } + b.WriteByte(typeByte) + utils.WriteVarInt(b, uint64(f.StreamID)) + if hasOffset { + utils.WriteVarInt(b, uint64(f.Offset)) + } + if f.DataLenPresent { + utils.WriteVarInt(b, uint64(f.DataLen())) + } + b.Write(f.Data) + return nil +} + +// Length returns the total length of the STREAM frame +func (f *StreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount { + if !version.UsesIETFFrameFormat() { + return f.lengthLegacy(version) + } + length := 1 + utils.VarIntLen(uint64(f.StreamID)) + if f.Offset != 0 { + length += utils.VarIntLen(uint64(f.Offset)) + } + if f.DataLenPresent { + length += utils.VarIntLen(uint64(f.DataLen())) + } + return length + f.DataLen() +} + +// MaxDataLen returns the maximum data length +// If 0 is returned, writing will fail (a STREAM frame must contain at least 1 byte of data). +func (f *StreamFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount { + if !version.UsesIETFFrameFormat() { + return f.maxDataLenLegacy(maxSize, version) + } + + headerLen := 1 + utils.VarIntLen(uint64(f.StreamID)) + if f.Offset != 0 { + headerLen += utils.VarIntLen(uint64(f.Offset)) + } + if f.DataLenPresent { + // pretend that the data size will be 1 bytes + // if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards + headerLen++ + } + if headerLen > maxSize { + return 0 + } + maxDataLen := maxSize - headerLen + if f.DataLenPresent && utils.VarIntLen(uint64(maxDataLen)) != 1 { + maxDataLen-- + } + return maxDataLen +} + +// MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes. +// If n >= len(frame), nil is returned and nothing is modified. +func (f *StreamFrame) MaybeSplitOffFrame(maxSize protocol.ByteCount, version protocol.VersionNumber) (*StreamFrame, error) { + if maxSize >= f.Length(version) { + return nil, nil + } + + n := f.MaxDataLen(maxSize, version) + if n == 0 { + return nil, errors.New("too small") + } + newFrame := &StreamFrame{ + FinBit: false, + StreamID: f.StreamID, + Offset: f.Offset, + Data: f.Data[:n], + DataLenPresent: f.DataLenPresent, + } + + f.Data = f.Data[n:] + f.Offset += n + + return newFrame, nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy.go new file mode 100644 index 00000000..a2b159dc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy.go @@ -0,0 +1,209 @@ +package wire + +import ( + "bytes" + "errors" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" +) + +var ( + errInvalidStreamIDLen = errors.New("StreamFrame: Invalid StreamID length") + errInvalidOffsetLen = errors.New("StreamFrame: Invalid offset length") +) + +// parseLegacyStreamFrame reads a stream frame. The type byte must not have been read yet. +func parseLegacyStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamFrame, error) { + frame := &StreamFrame{} + + typeByte, err := r.ReadByte() + if err != nil { + return nil, err + } + + frame.FinBit = typeByte&0x40 > 0 + frame.DataLenPresent = typeByte&0x20 > 0 + offsetLen := typeByte & 0x1c >> 2 + if offsetLen != 0 { + offsetLen++ + } + streamIDLen := typeByte&0x3 + 1 + + sid, err := utils.BigEndian.ReadUintN(r, streamIDLen) + if err != nil { + return nil, err + } + frame.StreamID = protocol.StreamID(sid) + + offset, err := utils.BigEndian.ReadUintN(r, offsetLen) + if err != nil { + return nil, err + } + frame.Offset = protocol.ByteCount(offset) + + var dataLen uint16 + if frame.DataLenPresent { + dataLen, err = utils.BigEndian.ReadUint16(r) + if err != nil { + return nil, err + } + } + + // shortcut to prevent the unnecessary allocation of dataLen bytes + // if the dataLen is larger than the remaining length of the packet + // reading the packet contents would result in EOF when attempting to READ + if int(dataLen) > r.Len() { + return nil, io.EOF + } + + if !frame.DataLenPresent { + // The rest of the packet is data + dataLen = uint16(r.Len()) + } + if dataLen != 0 { + frame.Data = make([]byte, dataLen) + if _, err := io.ReadFull(r, frame.Data); err != nil { + // this should never happen, since we already checked the dataLen earlier + return nil, err + } + } + + // MaxByteCount is the highest value that can be encoded with the IETF QUIC variable integer encoding (2^62-1). + // Note that this value is smaller than the maximum value that could be encoded in the gQUIC STREAM frame (2^64-1). + if frame.Offset+frame.DataLen() > protocol.MaxByteCount { + return nil, qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset") + } + if !frame.FinBit && frame.DataLen() == 0 { + return nil, qerr.EmptyStreamFrameNoFin + } + return frame, nil +} + +// writeLegacy writes a stream frame. +func (f *StreamFrame) writeLegacy(b *bytes.Buffer, _ protocol.VersionNumber) error { + if len(f.Data) == 0 && !f.FinBit { + return errors.New("StreamFrame: attempting to write empty frame without FIN") + } + + typeByte := uint8(0x80) // sets the leftmost bit to 1 + if f.FinBit { + typeByte ^= 0x40 + } + if f.DataLenPresent { + typeByte ^= 0x20 + } + + offsetLength := f.getOffsetLength() + if offsetLength > 0 { + typeByte ^= (uint8(offsetLength) - 1) << 2 + } + + streamIDLen := f.calculateStreamIDLength() + typeByte ^= streamIDLen - 1 + + b.WriteByte(typeByte) + + switch streamIDLen { + case 1: + b.WriteByte(uint8(f.StreamID)) + case 2: + utils.BigEndian.WriteUint16(b, uint16(f.StreamID)) + case 3: + utils.BigEndian.WriteUint24(b, uint32(f.StreamID)) + case 4: + utils.BigEndian.WriteUint32(b, uint32(f.StreamID)) + default: + return errInvalidStreamIDLen + } + + switch offsetLength { + case 0: + case 2: + utils.BigEndian.WriteUint16(b, uint16(f.Offset)) + case 3: + utils.BigEndian.WriteUint24(b, uint32(f.Offset)) + case 4: + utils.BigEndian.WriteUint32(b, uint32(f.Offset)) + case 5: + utils.BigEndian.WriteUint40(b, uint64(f.Offset)) + case 6: + utils.BigEndian.WriteUint48(b, uint64(f.Offset)) + case 7: + utils.BigEndian.WriteUint56(b, uint64(f.Offset)) + case 8: + utils.BigEndian.WriteUint64(b, uint64(f.Offset)) + default: + return errInvalidOffsetLen + } + + if f.DataLenPresent { + utils.BigEndian.WriteUint16(b, uint16(len(f.Data))) + } + + b.Write(f.Data) + return nil +} + +func (f *StreamFrame) calculateStreamIDLength() uint8 { + if f.StreamID < (1 << 8) { + return 1 + } else if f.StreamID < (1 << 16) { + return 2 + } else if f.StreamID < (1 << 24) { + return 3 + } + return 4 +} + +func (f *StreamFrame) getOffsetLength() protocol.ByteCount { + if f.Offset == 0 { + return 0 + } + if f.Offset < (1 << 16) { + return 2 + } + if f.Offset < (1 << 24) { + return 3 + } + if f.Offset < (1 << 32) { + return 4 + } + if f.Offset < (1 << 40) { + return 5 + } + if f.Offset < (1 << 48) { + return 6 + } + if f.Offset < (1 << 56) { + return 7 + } + return 8 +} + +func (f *StreamFrame) headerLengthLegacy(_ protocol.VersionNumber) protocol.ByteCount { + length := protocol.ByteCount(1) + protocol.ByteCount(f.calculateStreamIDLength()) + f.getOffsetLength() + if f.DataLenPresent { + length += 2 + } + return length +} + +func (f *StreamFrame) lengthLegacy(version protocol.VersionNumber) protocol.ByteCount { + return f.headerLengthLegacy(version) + f.DataLen() +} + +func (f *StreamFrame) maxDataLenLegacy(maxFrameSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount { + headerLen := f.headerLengthLegacy(version) + if headerLen > maxFrameSize { + return 0 + } + return maxFrameSize - headerLen +} + +// DataLen gives the length of data in bytes +func (f *StreamFrame) DataLen() protocol.ByteCount { + return protocol.ByteCount(len(f.Data)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy_test.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy_test.go new file mode 100644 index 00000000..7927e92a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_legacy_test.go @@ -0,0 +1,515 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("STREAM frame (for gQUIC)", func() { + Context("when parsing", func() { + It("accepts a sample frame", func() { + // a STREAM frame, plus 3 additional bytes, not belonging to this frame + b := bytes.NewReader([]byte{0x80 ^ 0x20, + 0x1, // stream id + 0x0, 0x6, // data length + 'f', 'o', 'o', 'b', 'a', 'r', + 'f', 'o', 'o', // additional bytes + }) + frame, err := parseStreamFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.FinBit).To(BeFalse()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(1))) + Expect(frame.Offset).To(BeZero()) + Expect(frame.DataLenPresent).To(BeTrue()) + Expect(frame.Data).To(Equal([]byte("foobar"))) + Expect(b.Len()).To(Equal(3)) + }) + + It("accepts frames with offsets", func() { + b := bytes.NewReader([]byte{0x80 ^ 0x20 /* 2 byte offset */ ^ 0x4, + 0x1, // stream id + 0x0, 0x42, // offset + 0x0, 0x6, // data length + 'f', 'o', 'o', 'b', 'a', 'r', + }) + frame, err := parseStreamFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.FinBit).To(BeFalse()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(1))) + Expect(frame.Offset).To(Equal(protocol.ByteCount(0x42))) + Expect(frame.DataLenPresent).To(BeTrue()) + Expect(frame.Data).To(Equal([]byte("foobar"))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0x80 ^ 0x20 ^ 0x4, + 0x1, // stream id + 0x0, 0x2a, // offset + 0x0, 0x6, // data length, + 'f', 'o', 'o', 'b', 'a', 'r', + } + _, err := parseStreamFrame(bytes.NewReader(data), versionBigEndian) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseStreamFrame(bytes.NewReader(data[0:i]), versionBigEndian) + Expect(err).To(HaveOccurred()) + } + }) + + It("accepts frame without data length", func() { + b := bytes.NewReader([]byte{0x80, + 0x1, // stream id + 'f', 'o', 'o', 'b', 'a', 'r', + }) + frame, err := parseStreamFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.FinBit).To(BeFalse()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(1))) + Expect(frame.Offset).To(BeZero()) + Expect(frame.DataLenPresent).To(BeFalse()) + Expect(frame.Data).To(Equal([]byte("foobar"))) + Expect(b.Len()).To(BeZero()) + }) + + It("accepts an empty frame with FinBit set, with data length set", func() { + // the STREAM frame, plus 3 additional bytes, not belonging to this frame + b := bytes.NewReader([]byte{0x80 ^ 0x40 ^ 0x20, + 0x1, // stream id + 0, 0, // data length + 'f', 'o', 'o', // additional bytes + }) + frame, err := parseStreamFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.FinBit).To(BeTrue()) + Expect(frame.DataLenPresent).To(BeTrue()) + Expect(frame.Data).To(BeEmpty()) + Expect(b.Len()).To(Equal(3)) + }) + + It("accepts an empty frame with the FinBit set", func() { + b := bytes.NewReader([]byte{0x80 ^ 0x40, + 0x1, // stream id + 'f', 'o', 'o', 'b', 'a', 'r', + }) + frame, err := parseStreamFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.FinBit).To(BeTrue()) + Expect(frame.DataLenPresent).To(BeFalse()) + Expect(frame.Data).To(Equal([]byte("foobar"))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on empty stream frames that don't have the FinBit set", func() { + b := bytes.NewReader([]byte{0x80 ^ 0x20, + 0x1, // stream id + 0, 0, // data length + }) + _, err := parseStreamFrame(b, versionBigEndian) + Expect(err).To(MatchError(qerr.EmptyStreamFrameNoFin)) + }) + + It("rejects frames to too large dataLen", func() { + b := bytes.NewReader([]byte{0xa0, 0x1, 0xff, 0xff}) + _, err := parseStreamFrame(b, versionBigEndian) + Expect(err).To(MatchError(io.EOF)) + }) + + It("rejects frames that overflow the offset", func() { + // Offset + len(Data) overflows MaxByteCount + f := &StreamFrame{ + StreamID: 1, + Offset: protocol.MaxByteCount, + Data: []byte{'f'}, + } + b := &bytes.Buffer{} + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + _, err = parseStreamFrame(bytes.NewReader(b.Bytes()), versionBigEndian) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset"))) + }) + }) + + Context("when writing", func() { + Context("in big endian", func() { + It("writes sample frame", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + DataLenPresent: true, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x80 ^ 0x20, + 0x1, // stream id + 0x0, 0x6, // data length + 'f', 'o', 'o', 'b', 'a', 'r', + })) + }) + }) + + It("sets the FinBit", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + FinBit: true, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x40).To(Equal(byte(0x40))) + }) + + It("errors when length is zero and FIN is not set", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + }).Write(b, versionBigEndian) + Expect(err).To(MatchError("StreamFrame: attempting to write empty frame without FIN")) + }) + + It("has proper min length for a short StreamID and a short offset", func() { + b := &bytes.Buffer{} + f := &StreamFrame{ + StreamID: 1, + Data: []byte{}, + Offset: 0, + FinBit: true, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(0)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has proper min length for a long StreamID and a big offset", func() { + b := &bytes.Buffer{} + f := &StreamFrame{ + StreamID: 0xdecafbad, + Data: []byte{}, + Offset: 0xdeadbeefcafe, + FinBit: true, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + Context("data length field", func() { + It("writes the data length", func() { + dataLen := 0x1337 + b := &bytes.Buffer{} + f := &StreamFrame{ + StreamID: 1, + Data: bytes.Repeat([]byte{'f'}, dataLen), + DataLenPresent: true, + Offset: 0, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x20).To(Equal(uint8(0x20))) + frame, err := parseStreamFrame(bytes.NewReader(b.Bytes()), versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.DataLenPresent).To(BeTrue()) + Expect(frame.DataLen()).To(Equal(protocol.ByteCount(dataLen))) + }) + }) + + It("omits the data length field", func() { + dataLen := 0x1337 + b := &bytes.Buffer{} + f := &StreamFrame{ + StreamID: 1, + Data: bytes.Repeat([]byte{'f'}, dataLen), + DataLenPresent: false, + Offset: 0, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x20).To(Equal(uint8(0))) + Expect(b.Bytes()[1 : b.Len()-dataLen]).ToNot(ContainSubstring(string([]byte{0x37, 0x13}))) + length := f.Length(versionBigEndian) + f.DataLenPresent = true + lengthWithoutDataLen := f.Length(versionBigEndian) + Expect(length).To(Equal(lengthWithoutDataLen - 2)) + }) + + It("calculates the correct min-length", func() { + f := &StreamFrame{ + StreamID: 0xcafe, + Data: []byte("foobar"), + DataLenPresent: false, + Offset: 0xdeadbeef, + } + lengthWithoutDataLen := f.Length(versionBigEndian) + f.DataLenPresent = true + Expect(f.Length(versionBigEndian)).To(Equal(lengthWithoutDataLen + 2)) + }) + + Context("offset lengths", func() { + It("does not write an offset if the offset is 0", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x0))) + }) + + It("writes a 2-byte offset if the offset is larger than 0", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0x1337, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x1 << 2))) + Expect(b.Bytes()[2:4]).To(Equal([]byte{0x13, 0x37})) + }) + + It("writes a 3-byte offset if the offset", func() { + b := &bytes.Buffer{} + (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0x13cafe, + }).Write(b, versionBigEndian) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x2 << 2))) + Expect(b.Bytes()[2:5]).To(Equal([]byte{0x13, 0xca, 0xfe})) + }) + + It("writes a 4-byte offset if the offset", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0xdeadbeef, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x3 << 2))) + Expect(b.Bytes()[2:6]).To(Equal([]byte{0xde, 0xad, 0xbe, 0xef})) + }) + + It("writes a 5-byte offset if the offset", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0x13deadbeef, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x4 << 2))) + Expect(b.Bytes()[2:7]).To(Equal([]byte{0x13, 0xde, 0xad, 0xbe, 0xef})) + }) + + It("writes a 6-byte offset if the offset", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0xdeadbeefcafe, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x5 << 2))) + Expect(b.Bytes()[2:8]).To(Equal([]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe})) + }) + + It("writes a 7-byte offset if the offset", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0x13deadbeefcafe, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x6 << 2))) + Expect(b.Bytes()[2:9]).To(Equal([]byte{0x13, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe})) + }) + + It("writes a 8-byte offset if the offset", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + Offset: 0x1337deadbeefcafe, + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x1c).To(Equal(uint8(0x7 << 2))) + Expect(b.Bytes()[2:10]).To(Equal([]byte{0x13, 0x37, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe})) + }) + }) + + Context("lengths of StreamIDs", func() { + It("writes a 1 byte StreamID", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 13, + Data: []byte("foobar"), + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x0))) + Expect(b.Bytes()[1]).To(Equal(uint8(13))) + }) + + It("writes a 2 byte StreamID", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 0xcafe, + Data: []byte("foobar"), + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x1))) + Expect(b.Bytes()[1:3]).To(Equal([]byte{0xca, 0xfe})) + }) + + It("writes a 3 byte StreamID", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 0x13beef, + Data: []byte("foobar"), + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x2))) + Expect(b.Bytes()[1:4]).To(Equal([]byte{0x13, 0xbe, 0xef})) + }) + + It("writes a 4 byte StreamID", func() { + b := &bytes.Buffer{} + err := (&StreamFrame{ + StreamID: 0xdecafbad, + Data: []byte("foobar"), + }).Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x3))) + Expect(b.Bytes()[1:5]).To(Equal([]byte{0xde, 0xca, 0xfb, 0xad})) + }) + + It("writes a multiple byte StreamID, after the Stream length was already determined by MinLenght()", func() { + b := &bytes.Buffer{} + frame := &StreamFrame{ + StreamID: 0xdecafbad, + Data: []byte("foobar"), + } + err := frame.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x3))) + Expect(b.Bytes()[1:5]).To(Equal([]byte{0xde, 0xca, 0xfb, 0xad})) + }) + }) + }) + + Context("shortening of StreamIDs", func() { + It("determines the length of a 1 byte StreamID", func() { + f := &StreamFrame{StreamID: 0xFF} + Expect(f.calculateStreamIDLength()).To(Equal(uint8(1))) + }) + + It("determines the length of a 2 byte StreamID", func() { + f := &StreamFrame{StreamID: 0xFFFF} + Expect(f.calculateStreamIDLength()).To(Equal(uint8(2))) + }) + + It("determines the length of a 3 byte StreamID", func() { + f := &StreamFrame{StreamID: 0xFFFFFF} + Expect(f.calculateStreamIDLength()).To(Equal(uint8(3))) + }) + + It("determines the length of a 4 byte StreamID", func() { + f := &StreamFrame{StreamID: 0xFFFFFFFF} + Expect(f.calculateStreamIDLength()).To(Equal(uint8(4))) + }) + }) + + Context("shortening of Offsets", func() { + It("determines length 0 of offset 0", func() { + f := &StreamFrame{Offset: 0} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(0))) + }) + + It("determines the length of a 2 byte offset", func() { + f := &StreamFrame{Offset: 0xFFFF} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(2))) + }) + + It("determines the length of a 2 byte offset, even if it would fit into 1 byte", func() { + f := &StreamFrame{Offset: 0x1} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(2))) + }) + + It("determines the length of a 3 byte offset", func() { + f := &StreamFrame{Offset: 0xFFFFFF} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(3))) + }) + + It("determines the length of a 4 byte offset", func() { + f := &StreamFrame{Offset: 0xFFFFFFFF} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(4))) + }) + + It("determines the length of a 5 byte offset", func() { + f := &StreamFrame{Offset: 0xFFFFFFFFFF} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(5))) + }) + + It("determines the length of a 6 byte offset", func() { + f := &StreamFrame{Offset: 0xFFFFFFFFFFFF} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(6))) + }) + + It("determines the length of a 7 byte offset", func() { + f := &StreamFrame{Offset: 0xFFFFFFFFFFFFFF} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(7))) + }) + + It("determines the length of an 8 byte offset", func() { + f := &StreamFrame{Offset: 0xFFFFFFFFFFFFFFFF} + Expect(f.getOffsetLength()).To(Equal(protocol.ByteCount(8))) + }) + }) + + Context("DataLen", func() { + It("determines the length of the data", func() { + frame := StreamFrame{ + Data: []byte("foobar"), + } + Expect(frame.DataLen()).To(Equal(protocol.ByteCount(6))) + }) + }) + + Context("max data length", func() { + It("always returns a data length such that the resulting frame has the right size", func() { + const maxSize = 3000 + + data := make([]byte, maxSize) + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0xdeadbeef, + DataLenPresent: true, + } + b := &bytes.Buffer{} + for i := 1; i < 3000; i++ { + b.Reset() + f.Data = nil + maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionBigEndian) + if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written + // check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size + f.Data = []byte{0} + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeNumerically(">", i)) + continue + } + f.Data = data[:int(maxDataLen)] + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(i)) + } + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_test.go new file mode 100644 index 00000000..e8d4c3ed --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_frame_test.go @@ -0,0 +1,396 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("STREAM frame (for IETF QUIC)", func() { + Context("when parsing", func() { + It("parses a frame with OFF bit", func() { + data := []byte{0x10 ^ 0x4} + data = append(data, encodeVarInt(0x12345)...) // stream ID + data = append(data, encodeVarInt(0xdecafbad)...) // offset + data = append(data, []byte("foobar")...) + r := bytes.NewReader(data) + frame, err := parseStreamFrame(r, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) + Expect(frame.Data).To(Equal([]byte("foobar"))) + Expect(frame.FinBit).To(BeFalse()) + Expect(frame.Offset).To(Equal(protocol.ByteCount(0xdecafbad))) + Expect(r.Len()).To(BeZero()) + }) + + It("respects the LEN when parsing the frame", func() { + data := []byte{0x10 ^ 0x2} + data = append(data, encodeVarInt(0x12345)...) // stream ID + data = append(data, encodeVarInt(4)...) // data length + data = append(data, []byte("foobar")...) + r := bytes.NewReader(data) + frame, err := parseStreamFrame(r, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) + Expect(frame.Data).To(Equal([]byte("foob"))) + Expect(frame.FinBit).To(BeFalse()) + Expect(frame.Offset).To(BeZero()) + Expect(r.Len()).To(Equal(2)) + }) + + It("parses a frame with FIN bit", func() { + data := []byte{0x10 ^ 0x1} + data = append(data, encodeVarInt(9)...) // stream ID + data = append(data, []byte("foobar")...) + r := bytes.NewReader(data) + frame, err := parseStreamFrame(r, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(9))) + Expect(frame.Data).To(Equal([]byte("foobar"))) + Expect(frame.FinBit).To(BeTrue()) + Expect(frame.Offset).To(BeZero()) + Expect(r.Len()).To(BeZero()) + }) + + It("allows empty frames", func() { + data := []byte{0x10 ^ 0x4} + data = append(data, encodeVarInt(0x1337)...) // stream ID + data = append(data, encodeVarInt(0x12345)...) // offset + r := bytes.NewReader(data) + f, err := parseStreamFrame(r, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.StreamID).To(Equal(protocol.StreamID(0x1337))) + Expect(f.Offset).To(Equal(protocol.ByteCount(0x12345))) + Expect(f.Data).To(BeEmpty()) + Expect(f.FinBit).To(BeFalse()) + }) + + It("rejects frames that overflow the maximum offset", func() { + data := []byte{0x10 ^ 0x4} + data = append(data, encodeVarInt(0x12345)...) // stream ID + data = append(data, encodeVarInt(uint64(protocol.MaxByteCount-5))...) // offset + data = append(data, []byte("foobar")...) + r := bytes.NewReader(data) + _, err := parseStreamFrame(r, versionIETFFrames) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset"))) + }) + + It("errors on EOFs", func() { + data := []byte{0x10 ^ 0x4 ^ 0x2} + data = append(data, encodeVarInt(0x12345)...) // stream ID + data = append(data, encodeVarInt(0xdecafbad)...) // offset + data = append(data, encodeVarInt(6)...) // data length + data = append(data, []byte("foobar")...) + _, err := parseStreamFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseStreamFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("when writing", func() { + It("writes a frame without offset", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Data: []byte("foobar"), + } + b := &bytes.Buffer{} + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x10} + expected = append(expected, encodeVarInt(0x1337)...) // stream ID + expected = append(expected, []byte("foobar")...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("writes a frame with offset", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0x123456, + Data: []byte("foobar"), + } + b := &bytes.Buffer{} + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x10 ^ 0x4} + expected = append(expected, encodeVarInt(0x1337)...) // stream ID + expected = append(expected, encodeVarInt(0x123456)...) // offset + expected = append(expected, []byte("foobar")...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("writes a frame with FIN bit", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0x123456, + FinBit: true, + } + b := &bytes.Buffer{} + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x10 ^ 0x4 ^ 0x1} + expected = append(expected, encodeVarInt(0x1337)...) // stream ID + expected = append(expected, encodeVarInt(0x123456)...) // offset + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("writes a frame with data length", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Data: []byte("foobar"), + DataLenPresent: true, + } + b := &bytes.Buffer{} + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x10 ^ 0x2} + expected = append(expected, encodeVarInt(0x1337)...) // stream ID + expected = append(expected, encodeVarInt(6)...) // data length + expected = append(expected, []byte("foobar")...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("writes a frame with data length and offset", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Data: []byte("foobar"), + DataLenPresent: true, + Offset: 0x123456, + } + b := &bytes.Buffer{} + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0x10 ^ 0x4 ^ 0x2} + expected = append(expected, encodeVarInt(0x1337)...) // stream ID + expected = append(expected, encodeVarInt(0x123456)...) // offset + expected = append(expected, encodeVarInt(6)...) // data length + expected = append(expected, []byte("foobar")...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("refuses to write an empty frame without FIN", func() { + f := &StreamFrame{ + StreamID: 0x42, + Offset: 0x1337, + } + b := &bytes.Buffer{} + err := f.Write(b, versionIETFFrames) + Expect(err).To(MatchError("StreamFrame: attempting to write empty frame without FIN")) + }) + }) + + Context("length", func() { + It("has the right length for a frame without offset and data length", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Data: []byte("foobar"), + } + Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + 6)) + }) + + It("has the right length for a frame with offset", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0x42, + Data: []byte("foobar"), + } + Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x42) + 6)) + }) + + It("has the right length for a frame with data length", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0x1234567, + DataLenPresent: true, + Data: []byte("foobar"), + } + Expect(f.Length(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x1234567) + utils.VarIntLen(6) + 6)) + }) + }) + + Context("max data length", func() { + const maxSize = 3000 + + It("always returns a data length such that the resulting frame has the right size, if data length is not present", func() { + data := make([]byte, maxSize) + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0xdeadbeef, + } + b := &bytes.Buffer{} + for i := 1; i < 3000; i++ { + b.Reset() + f.Data = nil + maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionIETFFrames) + if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written + // check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size + f.Data = []byte{0} + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeNumerically(">", i)) + continue + } + f.Data = data[:int(maxDataLen)] + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(Equal(i)) + } + }) + + It("always returns a data length such that the resulting frame has the right size, if data length is present", func() { + data := make([]byte, maxSize) + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0xdeadbeef, + DataLenPresent: true, + } + b := &bytes.Buffer{} + var frameOneByteTooSmallCounter int + for i := 1; i < 3000; i++ { + b.Reset() + f.Data = nil + maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionIETFFrames) + if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written + // check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size + f.Data = []byte{0} + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeNumerically(">", i)) + continue + } + f.Data = data[:int(maxDataLen)] + err := f.Write(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + // There's *one* pathological case, where a data length of x can be encoded into 1 byte + // but a data lengths of x+1 needs 2 bytes + // In that case, it's impossible to create a STREAM frame of the desired size + if b.Len() == i-1 { + frameOneByteTooSmallCounter++ + continue + } + Expect(b.Len()).To(Equal(i)) + } + Expect(frameOneByteTooSmallCounter).To(Equal(1)) + }) + }) + + Context("splitting", func() { + for _, v := range []protocol.VersionNumber{versionBigEndian, versionIETFFrames} { + version := v + + It("doesn't split if the frame is short enough", func() { + f := &StreamFrame{ + StreamID: 0x1337, + DataLenPresent: true, + Offset: 0xdeadbeef, + Data: make([]byte, 100), + } + newFrame, err := f.MaybeSplitOffFrame(f.Length(version), version) + Expect(err).ToNot(HaveOccurred()) + Expect(newFrame).To(BeNil()) + newFrame, err = f.MaybeSplitOffFrame(f.Length(version)-1, version) + Expect(err).ToNot(HaveOccurred()) + Expect(newFrame).ToNot(BeNil()) + }) + + It("keeps the data len", func() { + f := &StreamFrame{ + StreamID: 0x1337, + DataLenPresent: true, + Data: make([]byte, 100), + } + newFrame, err := f.MaybeSplitOffFrame(66, version) + Expect(err).ToNot(HaveOccurred()) + Expect(newFrame).ToNot(BeNil()) + Expect(f.DataLenPresent).To(BeTrue()) + Expect(newFrame.DataLenPresent).To(BeTrue()) + }) + + It("adjusts the offset", func() { + f := &StreamFrame{ + StreamID: 0x1337, + Offset: 0x100, + Data: []byte("foobar"), + } + newFrame, err := f.MaybeSplitOffFrame(f.Length(version)-3, version) + Expect(err).ToNot(HaveOccurred()) + Expect(newFrame).ToNot(BeNil()) + Expect(newFrame.Offset).To(Equal(protocol.ByteCount(0x100))) + Expect(newFrame.Data).To(Equal([]byte("foo"))) + Expect(f.Offset).To(Equal(protocol.ByteCount(0x100 + 3))) + Expect(f.Data).To(Equal([]byte("bar"))) + }) + + It("preserves the FIN bit", func() { + f := &StreamFrame{ + StreamID: 0x1337, + FinBit: true, + Offset: 0xdeadbeef, + Data: make([]byte, 100), + } + newFrame, err := f.MaybeSplitOffFrame(50, version) + Expect(err).ToNot(HaveOccurred()) + Expect(newFrame).ToNot(BeNil()) + Expect(newFrame.Offset).To(BeNumerically("<", f.Offset)) + Expect(f.FinBit).To(BeTrue()) + Expect(newFrame.FinBit).To(BeFalse()) + }) + + It("produces frames of the correct length, without data len", func() { + const size = 1000 + f := &StreamFrame{ + StreamID: 0xdecafbad, + Offset: 0x1234, + Data: []byte{0}, + } + minFrameSize := f.Length(version) + for i := protocol.ByteCount(0); i < minFrameSize; i++ { + _, err := f.MaybeSplitOffFrame(i, version) + Expect(err).To(HaveOccurred()) + } + for i := minFrameSize; i < size; i++ { + f.Data = make([]byte, size) + newFrame, err := f.MaybeSplitOffFrame(i, version) + Expect(err).ToNot(HaveOccurred()) + Expect(newFrame.Length(version)).To(Equal(i)) + } + }) + } + + It("produces frames of the correct length, with data len", func() { + const size = 1000 + f := &StreamFrame{ + StreamID: 0xdecafbad, + Offset: 0x1234, + DataLenPresent: true, + Data: []byte{0}, + } + minFrameSize := f.Length(versionIETFFrames) + for i := protocol.ByteCount(0); i < minFrameSize; i++ { + _, err := f.MaybeSplitOffFrame(i, versionIETFFrames) + Expect(err).To(HaveOccurred()) + } + var frameOneByteTooSmallCounter int + for i := minFrameSize; i < size; i++ { + f.Data = make([]byte, size) + newFrame, err := f.MaybeSplitOffFrame(i, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + // There's *one* pathological case, where a data length of x can be encoded into 1 byte + // but a data lengths of x+1 needs 2 bytes + // In that case, it's impossible to create a STREAM frame of the desired size + if newFrame.Length(versionIETFFrames) == i-1 { + frameOneByteTooSmallCounter++ + continue + } + Expect(newFrame.Length(versionIETFFrames)).To(Equal(i)) + } + Expect(frameOneByteTooSmallCounter).To(Equal(1)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame.go new file mode 100644 index 00000000..6476eb9d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame.go @@ -0,0 +1,37 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// A StreamIDBlockedFrame is a STREAM_ID_BLOCKED frame +type StreamIDBlockedFrame struct { + StreamID protocol.StreamID +} + +// parseStreamIDBlockedFrame parses a STREAM_ID_BLOCKED frame +func parseStreamIDBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamIDBlockedFrame, error) { + if _, err := r.ReadByte(); err != nil { + return nil, err + } + streamID, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + return &StreamIDBlockedFrame{StreamID: protocol.StreamID(streamID)}, nil +} + +func (f *StreamIDBlockedFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + typeByte := uint8(0x0a) + b.WriteByte(typeByte) + utils.WriteVarInt(b, uint64(f.StreamID)) + return nil +} + +// Length of a written frame +func (f *StreamIDBlockedFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { + return 1 + utils.VarIntLen(uint64(f.StreamID)) +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame_test.go new file mode 100644 index 00000000..7fb1cfb1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/stream_id_blocked_frame_test.go @@ -0,0 +1,53 @@ +package wire + +import ( + "bytes" + "io" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("STREAM_ID_BLOCKED frame", func() { + Context("parsing", func() { + It("accepts sample frame", func() { + expected := []byte{0xa} + expected = append(expected, encodeVarInt(0xdecafbad)...) + b := bytes.NewReader(expected) + frame, err := parseStreamIDBlockedFrame(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdecafbad))) + Expect(b.Len()).To(BeZero()) + }) + + It("errors on EOFs", func() { + data := []byte{0xa} + data = append(data, encodeVarInt(0x12345678)...) + _, err := parseStreamIDBlockedFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + for i := range data { + _, err := parseStreamIDBlockedFrame(bytes.NewReader(data[:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) + + Context("writing", func() { + It("writes a sample frame", func() { + b := &bytes.Buffer{} + frame := StreamIDBlockedFrame{StreamID: 0xdeadbeefcafe} + err := frame.Write(b, protocol.VersionWhatever) + Expect(err).ToNot(HaveOccurred()) + expected := []byte{0xa} + expected = append(expected, encodeVarInt(0xdeadbeefcafe)...) + Expect(b.Bytes()).To(Equal(expected)) + }) + + It("has the correct min length", func() { + frame := StreamIDBlockedFrame{StreamID: 0x123456} + Expect(frame.Length(0)).To(Equal(protocol.ByteCount(1) + utils.VarIntLen(0x123456))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/version_negotiation.go b/vendor/lucas-clemente/quic-go/internal/wire/version_negotiation.go new file mode 100644 index 00000000..df8b1f2c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/version_negotiation.go @@ -0,0 +1,42 @@ +package wire + +import ( + "bytes" + "crypto/rand" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +// ComposeGQUICVersionNegotiation composes a Version Negotiation Packet for gQUIC +func ComposeGQUICVersionNegotiation(connID protocol.ConnectionID, versions []protocol.VersionNumber) []byte { + buf := bytes.NewBuffer(make([]byte, 0, 1+8+len(versions)*4)) + buf.Write([]byte{0x1 | 0x8}) // type byte + buf.Write(connID) + for _, v := range versions { + utils.BigEndian.WriteUint32(buf, uint32(v)) + } + return buf.Bytes() +} + +// ComposeVersionNegotiation composes a Version Negotiation according to the IETF draft +func ComposeVersionNegotiation(destConnID, srcConnID protocol.ConnectionID, versions []protocol.VersionNumber) ([]byte, error) { + greasedVersions := protocol.GetGreasedVersions(versions) + expectedLen := 1 /* type byte */ + 4 /* version field */ + 1 /* connection ID length field */ + destConnID.Len() + srcConnID.Len() + len(greasedVersions)*4 + buf := bytes.NewBuffer(make([]byte, 0, expectedLen)) + r := make([]byte, 1) + _, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here. + buf.WriteByte(r[0] | 0x80) + utils.BigEndian.WriteUint32(buf, 0) // version 0 + connIDLen, err := encodeConnIDLen(destConnID, srcConnID) + if err != nil { + return nil, err + } + buf.WriteByte(connIDLen) + buf.Write(destConnID) + buf.Write(srcConnID) + for _, v := range greasedVersions { + utils.BigEndian.WriteUint32(buf, uint32(v)) + } + return buf.Bytes(), nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/version_negotiation_test.go b/vendor/lucas-clemente/quic-go/internal/wire/version_negotiation_test.go new file mode 100644 index 00000000..0d53142a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/version_negotiation_test.go @@ -0,0 +1,49 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Version Negotiation Packets", func() { + It("writes for gQUIC", func() { + connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37} + versions := []protocol.VersionNumber{1001, 1003} + data := ComposeGQUICVersionNegotiation(connID, versions) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 4) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.VersionFlag).To(BeTrue()) + Expect(hdr.DestConnectionID).To(Equal(connID)) + Expect(hdr.SrcConnectionID).To(BeEmpty()) + Expect(hdr.SupportedVersions).To(Equal(versions)) + }) + + It("writes in IETF draft style", func() { + srcConnID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37} + destConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + versions := []protocol.VersionNumber{1001, 1003} + data, err := ComposeVersionNegotiation(destConnID, srcConnID, versions) + Expect(err).ToNot(HaveOccurred()) + Expect(data[0] & 0x80).ToNot(BeZero()) + b := bytes.NewReader(data) + iHdr, err := ParseInvariantHeader(b, 4) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.IsVersionNegotiation).To(BeTrue()) + Expect(hdr.DestConnectionID).To(Equal(destConnID)) + Expect(hdr.SrcConnectionID).To(Equal(srcConnID)) + Expect(hdr.Version).To(BeZero()) + // the supported versions should include one reserved version number + Expect(hdr.SupportedVersions).To(HaveLen(len(versions) + 1)) + for _, version := range versions { + Expect(hdr.SupportedVersions).To(ContainElement(version)) + } + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/window_update_frame.go b/vendor/lucas-clemente/quic-go/internal/wire/window_update_frame.go new file mode 100644 index 00000000..606e25cf --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/window_update_frame.go @@ -0,0 +1,45 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type windowUpdateFrame struct { + StreamID protocol.StreamID + ByteOffset protocol.ByteCount +} + +// parseWindowUpdateFrame parses a WINDOW_UPDATE frame +// The frame returned is +// * a MAX_STREAM_DATA frame, if the WINDOW_UPDATE applies to a stream +// * a MAX_DATA frame, if the WINDOW_UPDATE applies to the connection +func parseWindowUpdateFrame(r *bytes.Reader, _ protocol.VersionNumber) (Frame, error) { + if _, err := r.ReadByte(); err != nil { // read the TypeByte + return nil, err + } + streamID, err := utils.BigEndian.ReadUint32(r) + if err != nil { + return nil, err + } + offset, err := utils.BigEndian.ReadUint64(r) + if err != nil { + return nil, err + } + if streamID == 0 { + return &MaxDataFrame{ByteOffset: protocol.ByteCount(offset)}, nil + } + return &MaxStreamDataFrame{ + StreamID: protocol.StreamID(streamID), + ByteOffset: protocol.ByteCount(offset), + }, nil +} + +func (f *windowUpdateFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { + b.WriteByte(0x4) + utils.BigEndian.WriteUint32(b, uint32(f.StreamID)) + utils.BigEndian.WriteUint64(b, uint64(f.ByteOffset)) + return nil +} diff --git a/vendor/lucas-clemente/quic-go/internal/wire/window_update_frame_test.go b/vendor/lucas-clemente/quic-go/internal/wire/window_update_frame_test.go new file mode 100644 index 00000000..cc1c0819 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/window_update_frame_test.go @@ -0,0 +1,98 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("WINDOW_UPDATE frame", func() { + Context("parsing", func() { + Context("in big endian", func() { + It("parses a stream-level WINDOW_UPDATE", func() { + b := bytes.NewReader([]byte{0x4, + 0xde, 0xad, 0xbe, 0xef, // stream id + 0xde, 0xca, 0xfb, 0xad, 0x11, 0x22, 0x33, 0x44, // byte offset + }) + f, err := parseWindowUpdateFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f).To(BeAssignableToTypeOf(&MaxStreamDataFrame{})) + frame := f.(*MaxStreamDataFrame) + Expect(frame.ByteOffset).To(Equal(protocol.ByteCount(0xdecafbad11223344))) + Expect(frame.StreamID).To(Equal(protocol.StreamID(0xdeadbeef))) + }) + + It("parses a connection-level WINDOW_UPDATE", func() { + b := bytes.NewReader([]byte{0x4, + 0x0, 0x0, 0x0, 0x0, // stream id + 0xde, 0xca, 0xfb, 0xad, 0x11, 0x22, 0x33, 0x44, // byte offset + }) + f, err := parseWindowUpdateFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f).To(BeAssignableToTypeOf(&MaxDataFrame{})) + frame := f.(*MaxDataFrame) + Expect(frame.ByteOffset).To(Equal(protocol.ByteCount(0xdecafbad11223344))) + }) + + It("errors on EOFs", func() { + data := []byte{0x4, + 0xef, 0xbe, 0xad, 0xde, // stream id + 0x44, 0x33, 0x22, 0x11, 0xad, 0xfb, 0xca, 0xde, // byte offset + } + _, err := parseWindowUpdateFrame(bytes.NewReader(data), versionBigEndian) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := parseWindowUpdateFrame(bytes.NewReader(data[0:i]), versionBigEndian) + Expect(err).To(HaveOccurred()) + } + }) + }) + }) + + Context("writing", func() { + It("has the proper min length for the stream-level WINDOW_UPDATE frame", func() { + f := &MaxDataFrame{ + ByteOffset: 0xdeadbeef, + } + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(1 + 4 + 8))) + }) + + It("has the proper min length for the connection-level WINDOW_UPDATE frame", func() { + f := &MaxDataFrame{ + ByteOffset: 0xdeadbeef, + } + Expect(f.Length(versionBigEndian)).To(Equal(protocol.ByteCount(1 + 4 + 8))) + }) + + Context("in big endian", func() { + It("writes a stream-level WINDOW_UPDATE frame", func() { + b := &bytes.Buffer{} + f := &MaxStreamDataFrame{ + StreamID: 0xdecafbad, + ByteOffset: 0xdeadbeefcafe1337, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x4, + 0xde, 0xca, 0xfb, 0xad, // stream ID 0 + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // byte offset + })) + }) + + It("writes a connection-level WINDOW_UPDATE frame", func() { + b := &bytes.Buffer{} + f := &MaxDataFrame{ + ByteOffset: 0xdeadbeefcafe1337, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()).To(Equal([]byte{0x4, + 0x0, 0x0, 0x0, 0x0, // stream ID 0 + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // byte offset + })) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/internal/wire/wire_suite_test.go b/vendor/lucas-clemente/quic-go/internal/wire/wire_suite_test.go new file mode 100644 index 00000000..7eda7918 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/internal/wire/wire_suite_test.go @@ -0,0 +1,39 @@ +package wire + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestWire(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Wire Suite") +} + +const ( + // a QUIC version that uses big endian encoding + versionBigEndian = protocol.Version39 + // a QUIC version that uses the IETF frame types + versionIETFFrames = protocol.VersionTLS + // a QUIC version that uses the gQUIC Public Header + versionPublicHeader = protocol.Version43 + // a QUIC version that the IETF QUIC Header + versionIETFHeader = protocol.VersionTLS +) + +func encodeVarInt(i uint64) []byte { + b := &bytes.Buffer{} + utils.WriteVarInt(b, i) + return b.Bytes() +} + +var _ = BeforeSuite(func() { + Expect(versionBigEndian.UsesIETFFrameFormat()).To(BeFalse()) + Expect(versionIETFFrames.UsesIETFFrameFormat()).To(BeTrue()) +}) diff --git a/vendor/lucas-clemente/quic-go/mint_utils.go b/vendor/lucas-clemente/quic-go/mint_utils.go new file mode 100644 index 00000000..657adb56 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mint_utils.go @@ -0,0 +1,52 @@ +package quic + +import ( + gocrypto "crypto" + "crypto/tls" + "crypto/x509" + "errors" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +func tlsToMintConfig(tlsConf *tls.Config, pers protocol.Perspective) (*mint.Config, error) { + mconf := &mint.Config{ + NonBlocking: true, + CipherSuites: []mint.CipherSuite{ + mint.TLS_AES_128_GCM_SHA256, + mint.TLS_AES_256_GCM_SHA384, + }, + } + if tlsConf != nil { + mconf.ServerName = tlsConf.ServerName + mconf.InsecureSkipVerify = tlsConf.InsecureSkipVerify + mconf.Certificates = make([]*mint.Certificate, len(tlsConf.Certificates)) + mconf.RootCAs = tlsConf.RootCAs + mconf.VerifyPeerCertificate = tlsConf.VerifyPeerCertificate + for i, certChain := range tlsConf.Certificates { + mconf.Certificates[i] = &mint.Certificate{ + Chain: make([]*x509.Certificate, len(certChain.Certificate)), + PrivateKey: certChain.PrivateKey.(gocrypto.Signer), + } + for j, cert := range certChain.Certificate { + c, err := x509.ParseCertificate(cert) + if err != nil { + return nil, err + } + mconf.Certificates[i].Chain[j] = c + } + } + switch tlsConf.ClientAuth { + case tls.NoClientCert: + case tls.RequireAnyClientCert: + mconf.RequireClientAuth = true + default: + return nil, errors.New("mint currently only support ClientAuthType RequireAnyClientCert") + } + } + if err := mconf.Init(pers == protocol.PerspectiveClient); err != nil { + return nil, err + } + return mconf, nil +} diff --git a/vendor/lucas-clemente/quic-go/mint_utils_test.go b/vendor/lucas-clemente/quic-go/mint_utils_test.go new file mode 100644 index 00000000..39b17c5e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mint_utils_test.go @@ -0,0 +1,65 @@ +package quic + +import ( + "crypto/tls" + "crypto/x509" + "errors" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Mint Utils", func() { + Context("generating a mint.Config", func() { + It("sets non-blocking mode", func() { + mintConf, err := tlsToMintConfig(nil, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + Expect(mintConf.NonBlocking).To(BeTrue()) + }) + + It("sets the certificate chain", func() { + tlsConf := testdata.GetTLSConfig() + mintConf, err := tlsToMintConfig(tlsConf, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + Expect(mintConf.Certificates).ToNot(BeEmpty()) + Expect(mintConf.Certificates).To(HaveLen(len(tlsConf.Certificates))) + }) + + It("copies values from the tls.Config", func() { + verifyErr := errors.New("test err") + certPool := &x509.CertPool{} + tlsConf := &tls.Config{ + RootCAs: certPool, + ServerName: "www.example.com", + InsecureSkipVerify: true, + VerifyPeerCertificate: func(_ [][]byte, _ [][]*x509.Certificate) error { + return verifyErr + }, + } + mintConf, err := tlsToMintConfig(tlsConf, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + Expect(mintConf.RootCAs).To(Equal(certPool)) + Expect(mintConf.ServerName).To(Equal("www.example.com")) + Expect(mintConf.InsecureSkipVerify).To(BeTrue()) + Expect(mintConf.VerifyPeerCertificate(nil, nil)).To(MatchError(verifyErr)) + }) + + It("requires client authentication", func() { + mintConf, err := tlsToMintConfig(nil, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + Expect(mintConf.RequireClientAuth).To(BeFalse()) + conf := &tls.Config{ClientAuth: tls.RequireAnyClientCert} + mintConf, err = tlsToMintConfig(conf, protocol.PerspectiveClient) + Expect(err).ToNot(HaveOccurred()) + Expect(mintConf.RequireClientAuth).To(BeTrue()) + }) + + It("rejects unsupported client auth types", func() { + conf := &tls.Config{ClientAuth: tls.RequireAndVerifyClientCert} + _, err := tlsToMintConfig(conf, protocol.PerspectiveClient) + Expect(err).To(MatchError("mint currently only support ClientAuthType RequireAnyClientCert")) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/mock_crypto_stream_test.go b/vendor/lucas-clemente/quic-go/mock_crypto_stream_test.go new file mode 100644 index 00000000..68e47c1d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_crypto_stream_test.go @@ -0,0 +1,141 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: CryptoStream) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockCryptoStream is a mock of CryptoStream interface +type MockCryptoStream struct { + ctrl *gomock.Controller + recorder *MockCryptoStreamMockRecorder +} + +// MockCryptoStreamMockRecorder is the mock recorder for MockCryptoStream +type MockCryptoStreamMockRecorder struct { + mock *MockCryptoStream +} + +// NewMockCryptoStream creates a new mock instance +func NewMockCryptoStream(ctrl *gomock.Controller) *MockCryptoStream { + mock := &MockCryptoStream{ctrl: ctrl} + mock.recorder = &MockCryptoStreamMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockCryptoStream) EXPECT() *MockCryptoStreamMockRecorder { + return m.recorder +} + +// Read mocks base method +func (m *MockCryptoStream) Read(arg0 []byte) (int, error) { + ret := m.ctrl.Call(m, "Read", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Read indicates an expected call of Read +func (mr *MockCryptoStreamMockRecorder) Read(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockCryptoStream)(nil).Read), arg0) +} + +// StreamID mocks base method +func (m *MockCryptoStream) StreamID() protocol.StreamID { + ret := m.ctrl.Call(m, "StreamID") + ret0, _ := ret[0].(protocol.StreamID) + return ret0 +} + +// StreamID indicates an expected call of StreamID +func (mr *MockCryptoStreamMockRecorder) StreamID() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StreamID", reflect.TypeOf((*MockCryptoStream)(nil).StreamID)) +} + +// Write mocks base method +func (m *MockCryptoStream) Write(arg0 []byte) (int, error) { + ret := m.ctrl.Call(m, "Write", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Write indicates an expected call of Write +func (mr *MockCryptoStreamMockRecorder) Write(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockCryptoStream)(nil).Write), arg0) +} + +// closeForShutdown mocks base method +func (m *MockCryptoStream) closeForShutdown(arg0 error) { + m.ctrl.Call(m, "closeForShutdown", arg0) +} + +// closeForShutdown indicates an expected call of closeForShutdown +func (mr *MockCryptoStreamMockRecorder) closeForShutdown(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "closeForShutdown", reflect.TypeOf((*MockCryptoStream)(nil).closeForShutdown), arg0) +} + +// getWindowUpdate mocks base method +func (m *MockCryptoStream) getWindowUpdate() protocol.ByteCount { + ret := m.ctrl.Call(m, "getWindowUpdate") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// getWindowUpdate indicates an expected call of getWindowUpdate +func (mr *MockCryptoStreamMockRecorder) getWindowUpdate() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getWindowUpdate", reflect.TypeOf((*MockCryptoStream)(nil).getWindowUpdate)) +} + +// handleMaxStreamDataFrame mocks base method +func (m *MockCryptoStream) handleMaxStreamDataFrame(arg0 *wire.MaxStreamDataFrame) { + m.ctrl.Call(m, "handleMaxStreamDataFrame", arg0) +} + +// handleMaxStreamDataFrame indicates an expected call of handleMaxStreamDataFrame +func (mr *MockCryptoStreamMockRecorder) handleMaxStreamDataFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleMaxStreamDataFrame", reflect.TypeOf((*MockCryptoStream)(nil).handleMaxStreamDataFrame), arg0) +} + +// handleStreamFrame mocks base method +func (m *MockCryptoStream) handleStreamFrame(arg0 *wire.StreamFrame) error { + ret := m.ctrl.Call(m, "handleStreamFrame", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// handleStreamFrame indicates an expected call of handleStreamFrame +func (mr *MockCryptoStreamMockRecorder) handleStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleStreamFrame", reflect.TypeOf((*MockCryptoStream)(nil).handleStreamFrame), arg0) +} + +// popStreamFrame mocks base method +func (m *MockCryptoStream) popStreamFrame(arg0 protocol.ByteCount) (*wire.StreamFrame, bool) { + ret := m.ctrl.Call(m, "popStreamFrame", arg0) + ret0, _ := ret[0].(*wire.StreamFrame) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// popStreamFrame indicates an expected call of popStreamFrame +func (mr *MockCryptoStreamMockRecorder) popStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "popStreamFrame", reflect.TypeOf((*MockCryptoStream)(nil).popStreamFrame), arg0) +} + +// setReadOffset mocks base method +func (m *MockCryptoStream) setReadOffset(arg0 protocol.ByteCount) { + m.ctrl.Call(m, "setReadOffset", arg0) +} + +// setReadOffset indicates an expected call of setReadOffset +func (mr *MockCryptoStreamMockRecorder) setReadOffset(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "setReadOffset", reflect.TypeOf((*MockCryptoStream)(nil).setReadOffset), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_gquic_aead_test.go b/vendor/lucas-clemente/quic-go/mock_gquic_aead_test.go new file mode 100644 index 00000000..c8ac324b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_gquic_aead_test.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: GQUICAEAD) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockGQUICAEAD is a mock of GQUICAEAD interface +type MockGQUICAEAD struct { + ctrl *gomock.Controller + recorder *MockGQUICAEADMockRecorder +} + +// MockGQUICAEADMockRecorder is the mock recorder for MockGQUICAEAD +type MockGQUICAEADMockRecorder struct { + mock *MockGQUICAEAD +} + +// NewMockGQUICAEAD creates a new mock instance +func NewMockGQUICAEAD(ctrl *gomock.Controller) *MockGQUICAEAD { + mock := &MockGQUICAEAD{ctrl: ctrl} + mock.recorder = &MockGQUICAEADMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockGQUICAEAD) EXPECT() *MockGQUICAEADMockRecorder { + return m.recorder +} + +// Open mocks base method +func (m *MockGQUICAEAD) Open(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) ([]byte, protocol.EncryptionLevel, error) { + ret := m.ctrl.Call(m, "Open", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(protocol.EncryptionLevel) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// Open indicates an expected call of Open +func (mr *MockGQUICAEADMockRecorder) Open(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockGQUICAEAD)(nil).Open), arg0, arg1, arg2, arg3) +} diff --git a/vendor/lucas-clemente/quic-go/mock_multiplexer_test.go b/vendor/lucas-clemente/quic-go/mock_multiplexer_test.go new file mode 100644 index 00000000..2c1ac30d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_multiplexer_test.go @@ -0,0 +1,48 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: Multiplexer) + +// Package quic is a generated GoMock package. +package quic + +import ( + net "net" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockMultiplexer is a mock of Multiplexer interface +type MockMultiplexer struct { + ctrl *gomock.Controller + recorder *MockMultiplexerMockRecorder +} + +// MockMultiplexerMockRecorder is the mock recorder for MockMultiplexer +type MockMultiplexerMockRecorder struct { + mock *MockMultiplexer +} + +// NewMockMultiplexer creates a new mock instance +func NewMockMultiplexer(ctrl *gomock.Controller) *MockMultiplexer { + mock := &MockMultiplexer{ctrl: ctrl} + mock.recorder = &MockMultiplexerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockMultiplexer) EXPECT() *MockMultiplexerMockRecorder { + return m.recorder +} + +// AddConn mocks base method +func (m *MockMultiplexer) AddConn(arg0 net.PacketConn, arg1 int) (packetHandlerManager, error) { + ret := m.ctrl.Call(m, "AddConn", arg0, arg1) + ret0, _ := ret[0].(packetHandlerManager) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AddConn indicates an expected call of AddConn +func (mr *MockMultiplexerMockRecorder) AddConn(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddConn", reflect.TypeOf((*MockMultiplexer)(nil).AddConn), arg0, arg1) +} diff --git a/vendor/lucas-clemente/quic-go/mock_packet_handler_manager_test.go b/vendor/lucas-clemente/quic-go/mock_packet_handler_manager_test.go new file mode 100644 index 00000000..fef4eb84 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_packet_handler_manager_test.go @@ -0,0 +1,75 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: PacketHandlerManager) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockPacketHandlerManager is a mock of PacketHandlerManager interface +type MockPacketHandlerManager struct { + ctrl *gomock.Controller + recorder *MockPacketHandlerManagerMockRecorder +} + +// MockPacketHandlerManagerMockRecorder is the mock recorder for MockPacketHandlerManager +type MockPacketHandlerManagerMockRecorder struct { + mock *MockPacketHandlerManager +} + +// NewMockPacketHandlerManager creates a new mock instance +func NewMockPacketHandlerManager(ctrl *gomock.Controller) *MockPacketHandlerManager { + mock := &MockPacketHandlerManager{ctrl: ctrl} + mock.recorder = &MockPacketHandlerManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockPacketHandlerManager) EXPECT() *MockPacketHandlerManagerMockRecorder { + return m.recorder +} + +// Add mocks base method +func (m *MockPacketHandlerManager) Add(arg0 protocol.ConnectionID, arg1 packetHandler) { + m.ctrl.Call(m, "Add", arg0, arg1) +} + +// Add indicates an expected call of Add +func (mr *MockPacketHandlerManagerMockRecorder) Add(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockPacketHandlerManager)(nil).Add), arg0, arg1) +} + +// CloseServer mocks base method +func (m *MockPacketHandlerManager) CloseServer() { + m.ctrl.Call(m, "CloseServer") +} + +// CloseServer indicates an expected call of CloseServer +func (mr *MockPacketHandlerManagerMockRecorder) CloseServer() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseServer", reflect.TypeOf((*MockPacketHandlerManager)(nil).CloseServer)) +} + +// Remove mocks base method +func (m *MockPacketHandlerManager) Remove(arg0 protocol.ConnectionID) { + m.ctrl.Call(m, "Remove", arg0) +} + +// Remove indicates an expected call of Remove +func (mr *MockPacketHandlerManagerMockRecorder) Remove(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockPacketHandlerManager)(nil).Remove), arg0) +} + +// SetServer mocks base method +func (m *MockPacketHandlerManager) SetServer(arg0 unknownPacketHandler) { + m.ctrl.Call(m, "SetServer", arg0) +} + +// SetServer indicates an expected call of SetServer +func (mr *MockPacketHandlerManagerMockRecorder) SetServer(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetServer", reflect.TypeOf((*MockPacketHandlerManager)(nil).SetServer), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_packet_handler_test.go b/vendor/lucas-clemente/quic-go/mock_packet_handler_test.go new file mode 100644 index 00000000..dfa884a9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_packet_handler_test.go @@ -0,0 +1,91 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: PacketHandler) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockPacketHandler is a mock of PacketHandler interface +type MockPacketHandler struct { + ctrl *gomock.Controller + recorder *MockPacketHandlerMockRecorder +} + +// MockPacketHandlerMockRecorder is the mock recorder for MockPacketHandler +type MockPacketHandlerMockRecorder struct { + mock *MockPacketHandler +} + +// NewMockPacketHandler creates a new mock instance +func NewMockPacketHandler(ctrl *gomock.Controller) *MockPacketHandler { + mock := &MockPacketHandler{ctrl: ctrl} + mock.recorder = &MockPacketHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockPacketHandler) EXPECT() *MockPacketHandlerMockRecorder { + return m.recorder +} + +// Close mocks base method +func (m *MockPacketHandler) Close() error { + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockPacketHandlerMockRecorder) Close() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPacketHandler)(nil).Close)) +} + +// GetPerspective mocks base method +func (m *MockPacketHandler) GetPerspective() protocol.Perspective { + ret := m.ctrl.Call(m, "GetPerspective") + ret0, _ := ret[0].(protocol.Perspective) + return ret0 +} + +// GetPerspective indicates an expected call of GetPerspective +func (mr *MockPacketHandlerMockRecorder) GetPerspective() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPerspective", reflect.TypeOf((*MockPacketHandler)(nil).GetPerspective)) +} + +// GetVersion mocks base method +func (m *MockPacketHandler) GetVersion() protocol.VersionNumber { + ret := m.ctrl.Call(m, "GetVersion") + ret0, _ := ret[0].(protocol.VersionNumber) + return ret0 +} + +// GetVersion indicates an expected call of GetVersion +func (mr *MockPacketHandlerMockRecorder) GetVersion() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVersion", reflect.TypeOf((*MockPacketHandler)(nil).GetVersion)) +} + +// destroy mocks base method +func (m *MockPacketHandler) destroy(arg0 error) { + m.ctrl.Call(m, "destroy", arg0) +} + +// destroy indicates an expected call of destroy +func (mr *MockPacketHandlerMockRecorder) destroy(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "destroy", reflect.TypeOf((*MockPacketHandler)(nil).destroy), arg0) +} + +// handlePacket mocks base method +func (m *MockPacketHandler) handlePacket(arg0 *receivedPacket) { + m.ctrl.Call(m, "handlePacket", arg0) +} + +// handlePacket indicates an expected call of handlePacket +func (mr *MockPacketHandlerMockRecorder) handlePacket(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handlePacket", reflect.TypeOf((*MockPacketHandler)(nil).handlePacket), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_quic_aead_test.go b/vendor/lucas-clemente/quic-go/mock_quic_aead_test.go new file mode 100644 index 00000000..63a2a5a7 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_quic_aead_test.go @@ -0,0 +1,61 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: QuicAEAD) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockQuicAEAD is a mock of QuicAEAD interface +type MockQuicAEAD struct { + ctrl *gomock.Controller + recorder *MockQuicAEADMockRecorder +} + +// MockQuicAEADMockRecorder is the mock recorder for MockQuicAEAD +type MockQuicAEADMockRecorder struct { + mock *MockQuicAEAD +} + +// NewMockQuicAEAD creates a new mock instance +func NewMockQuicAEAD(ctrl *gomock.Controller) *MockQuicAEAD { + mock := &MockQuicAEAD{ctrl: ctrl} + mock.recorder = &MockQuicAEADMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockQuicAEAD) EXPECT() *MockQuicAEADMockRecorder { + return m.recorder +} + +// Open1RTT mocks base method +func (m *MockQuicAEAD) Open1RTT(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) ([]byte, error) { + ret := m.ctrl.Call(m, "Open1RTT", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Open1RTT indicates an expected call of Open1RTT +func (mr *MockQuicAEADMockRecorder) Open1RTT(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open1RTT", reflect.TypeOf((*MockQuicAEAD)(nil).Open1RTT), arg0, arg1, arg2, arg3) +} + +// OpenHandshake mocks base method +func (m *MockQuicAEAD) OpenHandshake(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) ([]byte, error) { + ret := m.ctrl.Call(m, "OpenHandshake", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenHandshake indicates an expected call of OpenHandshake +func (mr *MockQuicAEADMockRecorder) OpenHandshake(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenHandshake", reflect.TypeOf((*MockQuicAEAD)(nil).OpenHandshake), arg0, arg1, arg2, arg3) +} diff --git a/vendor/lucas-clemente/quic-go/mock_quic_session_test.go b/vendor/lucas-clemente/quic-go/mock_quic_session_test.go new file mode 100644 index 00000000..d67d1fa3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_quic_session_test.go @@ -0,0 +1,242 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: QuicSession) + +// Package quic is a generated GoMock package. +package quic + +import ( + context "context" + net "net" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + handshake "github.com/lucas-clemente/quic-go/internal/handshake" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockQuicSession is a mock of QuicSession interface +type MockQuicSession struct { + ctrl *gomock.Controller + recorder *MockQuicSessionMockRecorder +} + +// MockQuicSessionMockRecorder is the mock recorder for MockQuicSession +type MockQuicSessionMockRecorder struct { + mock *MockQuicSession +} + +// NewMockQuicSession creates a new mock instance +func NewMockQuicSession(ctrl *gomock.Controller) *MockQuicSession { + mock := &MockQuicSession{ctrl: ctrl} + mock.recorder = &MockQuicSessionMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockQuicSession) EXPECT() *MockQuicSessionMockRecorder { + return m.recorder +} + +// AcceptStream mocks base method +func (m *MockQuicSession) AcceptStream() (Stream, error) { + ret := m.ctrl.Call(m, "AcceptStream") + ret0, _ := ret[0].(Stream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcceptStream indicates an expected call of AcceptStream +func (mr *MockQuicSessionMockRecorder) AcceptStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptStream", reflect.TypeOf((*MockQuicSession)(nil).AcceptStream)) +} + +// AcceptUniStream mocks base method +func (m *MockQuicSession) AcceptUniStream() (ReceiveStream, error) { + ret := m.ctrl.Call(m, "AcceptUniStream") + ret0, _ := ret[0].(ReceiveStream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcceptUniStream indicates an expected call of AcceptUniStream +func (mr *MockQuicSessionMockRecorder) AcceptUniStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptUniStream", reflect.TypeOf((*MockQuicSession)(nil).AcceptUniStream)) +} + +// Close mocks base method +func (m *MockQuicSession) Close() error { + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockQuicSessionMockRecorder) Close() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockQuicSession)(nil).Close)) +} + +// CloseWithError mocks base method +func (m *MockQuicSession) CloseWithError(arg0 protocol.ApplicationErrorCode, arg1 error) error { + ret := m.ctrl.Call(m, "CloseWithError", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// CloseWithError indicates an expected call of CloseWithError +func (mr *MockQuicSessionMockRecorder) CloseWithError(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseWithError", reflect.TypeOf((*MockQuicSession)(nil).CloseWithError), arg0, arg1) +} + +// ConnectionState mocks base method +func (m *MockQuicSession) ConnectionState() handshake.ConnectionState { + ret := m.ctrl.Call(m, "ConnectionState") + ret0, _ := ret[0].(handshake.ConnectionState) + return ret0 +} + +// ConnectionState indicates an expected call of ConnectionState +func (mr *MockQuicSessionMockRecorder) ConnectionState() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConnectionState", reflect.TypeOf((*MockQuicSession)(nil).ConnectionState)) +} + +// Context mocks base method +func (m *MockQuicSession) Context() context.Context { + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context +func (mr *MockQuicSessionMockRecorder) Context() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockQuicSession)(nil).Context)) +} + +// GetVersion mocks base method +func (m *MockQuicSession) GetVersion() protocol.VersionNumber { + ret := m.ctrl.Call(m, "GetVersion") + ret0, _ := ret[0].(protocol.VersionNumber) + return ret0 +} + +// GetVersion indicates an expected call of GetVersion +func (mr *MockQuicSessionMockRecorder) GetVersion() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVersion", reflect.TypeOf((*MockQuicSession)(nil).GetVersion)) +} + +// LocalAddr mocks base method +func (m *MockQuicSession) LocalAddr() net.Addr { + ret := m.ctrl.Call(m, "LocalAddr") + ret0, _ := ret[0].(net.Addr) + return ret0 +} + +// LocalAddr indicates an expected call of LocalAddr +func (mr *MockQuicSessionMockRecorder) LocalAddr() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LocalAddr", reflect.TypeOf((*MockQuicSession)(nil).LocalAddr)) +} + +// OpenStream mocks base method +func (m *MockQuicSession) OpenStream() (Stream, error) { + ret := m.ctrl.Call(m, "OpenStream") + ret0, _ := ret[0].(Stream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenStream indicates an expected call of OpenStream +func (mr *MockQuicSessionMockRecorder) OpenStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenStream", reflect.TypeOf((*MockQuicSession)(nil).OpenStream)) +} + +// OpenStreamSync mocks base method +func (m *MockQuicSession) OpenStreamSync() (Stream, error) { + ret := m.ctrl.Call(m, "OpenStreamSync") + ret0, _ := ret[0].(Stream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenStreamSync indicates an expected call of OpenStreamSync +func (mr *MockQuicSessionMockRecorder) OpenStreamSync() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenStreamSync", reflect.TypeOf((*MockQuicSession)(nil).OpenStreamSync)) +} + +// OpenUniStream mocks base method +func (m *MockQuicSession) OpenUniStream() (SendStream, error) { + ret := m.ctrl.Call(m, "OpenUniStream") + ret0, _ := ret[0].(SendStream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenUniStream indicates an expected call of OpenUniStream +func (mr *MockQuicSessionMockRecorder) OpenUniStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenUniStream", reflect.TypeOf((*MockQuicSession)(nil).OpenUniStream)) +} + +// OpenUniStreamSync mocks base method +func (m *MockQuicSession) OpenUniStreamSync() (SendStream, error) { + ret := m.ctrl.Call(m, "OpenUniStreamSync") + ret0, _ := ret[0].(SendStream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenUniStreamSync indicates an expected call of OpenUniStreamSync +func (mr *MockQuicSessionMockRecorder) OpenUniStreamSync() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenUniStreamSync", reflect.TypeOf((*MockQuicSession)(nil).OpenUniStreamSync)) +} + +// RemoteAddr mocks base method +func (m *MockQuicSession) RemoteAddr() net.Addr { + ret := m.ctrl.Call(m, "RemoteAddr") + ret0, _ := ret[0].(net.Addr) + return ret0 +} + +// RemoteAddr indicates an expected call of RemoteAddr +func (mr *MockQuicSessionMockRecorder) RemoteAddr() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoteAddr", reflect.TypeOf((*MockQuicSession)(nil).RemoteAddr)) +} + +// closeRemote mocks base method +func (m *MockQuicSession) closeRemote(arg0 error) { + m.ctrl.Call(m, "closeRemote", arg0) +} + +// closeRemote indicates an expected call of closeRemote +func (mr *MockQuicSessionMockRecorder) closeRemote(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "closeRemote", reflect.TypeOf((*MockQuicSession)(nil).closeRemote), arg0) +} + +// destroy mocks base method +func (m *MockQuicSession) destroy(arg0 error) { + m.ctrl.Call(m, "destroy", arg0) +} + +// destroy indicates an expected call of destroy +func (mr *MockQuicSessionMockRecorder) destroy(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "destroy", reflect.TypeOf((*MockQuicSession)(nil).destroy), arg0) +} + +// handlePacket mocks base method +func (m *MockQuicSession) handlePacket(arg0 *receivedPacket) { + m.ctrl.Call(m, "handlePacket", arg0) +} + +// handlePacket indicates an expected call of handlePacket +func (mr *MockQuicSessionMockRecorder) handlePacket(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handlePacket", reflect.TypeOf((*MockQuicSession)(nil).handlePacket), arg0) +} + +// run mocks base method +func (m *MockQuicSession) run() error { + ret := m.ctrl.Call(m, "run") + ret0, _ := ret[0].(error) + return ret0 +} + +// run indicates an expected call of run +func (mr *MockQuicSessionMockRecorder) run() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "run", reflect.TypeOf((*MockQuicSession)(nil).run)) +} diff --git a/vendor/lucas-clemente/quic-go/mock_receive_stream_internal_test.go b/vendor/lucas-clemente/quic-go/mock_receive_stream_internal_test.go new file mode 100644 index 00000000..c41bfa7e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_receive_stream_internal_test.go @@ -0,0 +1,132 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: ReceiveStreamI) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockReceiveStreamI is a mock of ReceiveStreamI interface +type MockReceiveStreamI struct { + ctrl *gomock.Controller + recorder *MockReceiveStreamIMockRecorder +} + +// MockReceiveStreamIMockRecorder is the mock recorder for MockReceiveStreamI +type MockReceiveStreamIMockRecorder struct { + mock *MockReceiveStreamI +} + +// NewMockReceiveStreamI creates a new mock instance +func NewMockReceiveStreamI(ctrl *gomock.Controller) *MockReceiveStreamI { + mock := &MockReceiveStreamI{ctrl: ctrl} + mock.recorder = &MockReceiveStreamIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockReceiveStreamI) EXPECT() *MockReceiveStreamIMockRecorder { + return m.recorder +} + +// CancelRead mocks base method +func (m *MockReceiveStreamI) CancelRead(arg0 protocol.ApplicationErrorCode) error { + ret := m.ctrl.Call(m, "CancelRead", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// CancelRead indicates an expected call of CancelRead +func (mr *MockReceiveStreamIMockRecorder) CancelRead(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelRead", reflect.TypeOf((*MockReceiveStreamI)(nil).CancelRead), arg0) +} + +// Read mocks base method +func (m *MockReceiveStreamI) Read(arg0 []byte) (int, error) { + ret := m.ctrl.Call(m, "Read", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Read indicates an expected call of Read +func (mr *MockReceiveStreamIMockRecorder) Read(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockReceiveStreamI)(nil).Read), arg0) +} + +// SetReadDeadline mocks base method +func (m *MockReceiveStreamI) SetReadDeadline(arg0 time.Time) error { + ret := m.ctrl.Call(m, "SetReadDeadline", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetReadDeadline indicates an expected call of SetReadDeadline +func (mr *MockReceiveStreamIMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReadDeadline", reflect.TypeOf((*MockReceiveStreamI)(nil).SetReadDeadline), arg0) +} + +// StreamID mocks base method +func (m *MockReceiveStreamI) StreamID() protocol.StreamID { + ret := m.ctrl.Call(m, "StreamID") + ret0, _ := ret[0].(protocol.StreamID) + return ret0 +} + +// StreamID indicates an expected call of StreamID +func (mr *MockReceiveStreamIMockRecorder) StreamID() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StreamID", reflect.TypeOf((*MockReceiveStreamI)(nil).StreamID)) +} + +// closeForShutdown mocks base method +func (m *MockReceiveStreamI) closeForShutdown(arg0 error) { + m.ctrl.Call(m, "closeForShutdown", arg0) +} + +// closeForShutdown indicates an expected call of closeForShutdown +func (mr *MockReceiveStreamIMockRecorder) closeForShutdown(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "closeForShutdown", reflect.TypeOf((*MockReceiveStreamI)(nil).closeForShutdown), arg0) +} + +// getWindowUpdate mocks base method +func (m *MockReceiveStreamI) getWindowUpdate() protocol.ByteCount { + ret := m.ctrl.Call(m, "getWindowUpdate") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// getWindowUpdate indicates an expected call of getWindowUpdate +func (mr *MockReceiveStreamIMockRecorder) getWindowUpdate() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getWindowUpdate", reflect.TypeOf((*MockReceiveStreamI)(nil).getWindowUpdate)) +} + +// handleRstStreamFrame mocks base method +func (m *MockReceiveStreamI) handleRstStreamFrame(arg0 *wire.RstStreamFrame) error { + ret := m.ctrl.Call(m, "handleRstStreamFrame", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// handleRstStreamFrame indicates an expected call of handleRstStreamFrame +func (mr *MockReceiveStreamIMockRecorder) handleRstStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleRstStreamFrame", reflect.TypeOf((*MockReceiveStreamI)(nil).handleRstStreamFrame), arg0) +} + +// handleStreamFrame mocks base method +func (m *MockReceiveStreamI) handleStreamFrame(arg0 *wire.StreamFrame) error { + ret := m.ctrl.Call(m, "handleStreamFrame", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// handleStreamFrame indicates an expected call of handleStreamFrame +func (mr *MockReceiveStreamIMockRecorder) handleStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleStreamFrame", reflect.TypeOf((*MockReceiveStreamI)(nil).handleStreamFrame), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_send_stream_internal_test.go b/vendor/lucas-clemente/quic-go/mock_send_stream_internal_test.go new file mode 100644 index 00000000..f1e68a0f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_send_stream_internal_test.go @@ -0,0 +1,154 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: SendStreamI) + +// Package quic is a generated GoMock package. +package quic + +import ( + context "context" + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockSendStreamI is a mock of SendStreamI interface +type MockSendStreamI struct { + ctrl *gomock.Controller + recorder *MockSendStreamIMockRecorder +} + +// MockSendStreamIMockRecorder is the mock recorder for MockSendStreamI +type MockSendStreamIMockRecorder struct { + mock *MockSendStreamI +} + +// NewMockSendStreamI creates a new mock instance +func NewMockSendStreamI(ctrl *gomock.Controller) *MockSendStreamI { + mock := &MockSendStreamI{ctrl: ctrl} + mock.recorder = &MockSendStreamIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSendStreamI) EXPECT() *MockSendStreamIMockRecorder { + return m.recorder +} + +// CancelWrite mocks base method +func (m *MockSendStreamI) CancelWrite(arg0 protocol.ApplicationErrorCode) error { + ret := m.ctrl.Call(m, "CancelWrite", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// CancelWrite indicates an expected call of CancelWrite +func (mr *MockSendStreamIMockRecorder) CancelWrite(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelWrite", reflect.TypeOf((*MockSendStreamI)(nil).CancelWrite), arg0) +} + +// Close mocks base method +func (m *MockSendStreamI) Close() error { + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockSendStreamIMockRecorder) Close() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSendStreamI)(nil).Close)) +} + +// Context mocks base method +func (m *MockSendStreamI) Context() context.Context { + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context +func (mr *MockSendStreamIMockRecorder) Context() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockSendStreamI)(nil).Context)) +} + +// SetWriteDeadline mocks base method +func (m *MockSendStreamI) SetWriteDeadline(arg0 time.Time) error { + ret := m.ctrl.Call(m, "SetWriteDeadline", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetWriteDeadline indicates an expected call of SetWriteDeadline +func (mr *MockSendStreamIMockRecorder) SetWriteDeadline(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetWriteDeadline", reflect.TypeOf((*MockSendStreamI)(nil).SetWriteDeadline), arg0) +} + +// StreamID mocks base method +func (m *MockSendStreamI) StreamID() protocol.StreamID { + ret := m.ctrl.Call(m, "StreamID") + ret0, _ := ret[0].(protocol.StreamID) + return ret0 +} + +// StreamID indicates an expected call of StreamID +func (mr *MockSendStreamIMockRecorder) StreamID() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StreamID", reflect.TypeOf((*MockSendStreamI)(nil).StreamID)) +} + +// Write mocks base method +func (m *MockSendStreamI) Write(arg0 []byte) (int, error) { + ret := m.ctrl.Call(m, "Write", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Write indicates an expected call of Write +func (mr *MockSendStreamIMockRecorder) Write(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockSendStreamI)(nil).Write), arg0) +} + +// closeForShutdown mocks base method +func (m *MockSendStreamI) closeForShutdown(arg0 error) { + m.ctrl.Call(m, "closeForShutdown", arg0) +} + +// closeForShutdown indicates an expected call of closeForShutdown +func (mr *MockSendStreamIMockRecorder) closeForShutdown(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "closeForShutdown", reflect.TypeOf((*MockSendStreamI)(nil).closeForShutdown), arg0) +} + +// handleMaxStreamDataFrame mocks base method +func (m *MockSendStreamI) handleMaxStreamDataFrame(arg0 *wire.MaxStreamDataFrame) { + m.ctrl.Call(m, "handleMaxStreamDataFrame", arg0) +} + +// handleMaxStreamDataFrame indicates an expected call of handleMaxStreamDataFrame +func (mr *MockSendStreamIMockRecorder) handleMaxStreamDataFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleMaxStreamDataFrame", reflect.TypeOf((*MockSendStreamI)(nil).handleMaxStreamDataFrame), arg0) +} + +// handleStopSendingFrame mocks base method +func (m *MockSendStreamI) handleStopSendingFrame(arg0 *wire.StopSendingFrame) { + m.ctrl.Call(m, "handleStopSendingFrame", arg0) +} + +// handleStopSendingFrame indicates an expected call of handleStopSendingFrame +func (mr *MockSendStreamIMockRecorder) handleStopSendingFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleStopSendingFrame", reflect.TypeOf((*MockSendStreamI)(nil).handleStopSendingFrame), arg0) +} + +// popStreamFrame mocks base method +func (m *MockSendStreamI) popStreamFrame(arg0 protocol.ByteCount) (*wire.StreamFrame, bool) { + ret := m.ctrl.Call(m, "popStreamFrame", arg0) + ret0, _ := ret[0].(*wire.StreamFrame) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// popStreamFrame indicates an expected call of popStreamFrame +func (mr *MockSendStreamIMockRecorder) popStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "popStreamFrame", reflect.TypeOf((*MockSendStreamI)(nil).popStreamFrame), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_session_runner_test.go b/vendor/lucas-clemente/quic-go/mock_session_runner_test.go new file mode 100644 index 00000000..4ef433ce --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_session_runner_test.go @@ -0,0 +1,55 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: SessionRunner) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockSessionRunner is a mock of SessionRunner interface +type MockSessionRunner struct { + ctrl *gomock.Controller + recorder *MockSessionRunnerMockRecorder +} + +// MockSessionRunnerMockRecorder is the mock recorder for MockSessionRunner +type MockSessionRunnerMockRecorder struct { + mock *MockSessionRunner +} + +// NewMockSessionRunner creates a new mock instance +func NewMockSessionRunner(ctrl *gomock.Controller) *MockSessionRunner { + mock := &MockSessionRunner{ctrl: ctrl} + mock.recorder = &MockSessionRunnerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSessionRunner) EXPECT() *MockSessionRunnerMockRecorder { + return m.recorder +} + +// onHandshakeComplete mocks base method +func (m *MockSessionRunner) onHandshakeComplete(arg0 Session) { + m.ctrl.Call(m, "onHandshakeComplete", arg0) +} + +// onHandshakeComplete indicates an expected call of onHandshakeComplete +func (mr *MockSessionRunnerMockRecorder) onHandshakeComplete(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "onHandshakeComplete", reflect.TypeOf((*MockSessionRunner)(nil).onHandshakeComplete), arg0) +} + +// removeConnectionID mocks base method +func (m *MockSessionRunner) removeConnectionID(arg0 protocol.ConnectionID) { + m.ctrl.Call(m, "removeConnectionID", arg0) +} + +// removeConnectionID indicates an expected call of removeConnectionID +func (mr *MockSessionRunnerMockRecorder) removeConnectionID(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "removeConnectionID", reflect.TypeOf((*MockSessionRunner)(nil).removeConnectionID), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_stream_frame_source_test.go b/vendor/lucas-clemente/quic-go/mock_stream_frame_source_test.go new file mode 100644 index 00000000..9b365805 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_stream_frame_source_test.go @@ -0,0 +1,72 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: StreamFrameSource) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockStreamFrameSource is a mock of StreamFrameSource interface +type MockStreamFrameSource struct { + ctrl *gomock.Controller + recorder *MockStreamFrameSourceMockRecorder +} + +// MockStreamFrameSourceMockRecorder is the mock recorder for MockStreamFrameSource +type MockStreamFrameSourceMockRecorder struct { + mock *MockStreamFrameSource +} + +// NewMockStreamFrameSource creates a new mock instance +func NewMockStreamFrameSource(ctrl *gomock.Controller) *MockStreamFrameSource { + mock := &MockStreamFrameSource{ctrl: ctrl} + mock.recorder = &MockStreamFrameSourceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStreamFrameSource) EXPECT() *MockStreamFrameSourceMockRecorder { + return m.recorder +} + +// HasCryptoStreamData mocks base method +func (m *MockStreamFrameSource) HasCryptoStreamData() bool { + ret := m.ctrl.Call(m, "HasCryptoStreamData") + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasCryptoStreamData indicates an expected call of HasCryptoStreamData +func (mr *MockStreamFrameSourceMockRecorder) HasCryptoStreamData() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasCryptoStreamData", reflect.TypeOf((*MockStreamFrameSource)(nil).HasCryptoStreamData)) +} + +// PopCryptoStreamFrame mocks base method +func (m *MockStreamFrameSource) PopCryptoStreamFrame(arg0 protocol.ByteCount) *wire.StreamFrame { + ret := m.ctrl.Call(m, "PopCryptoStreamFrame", arg0) + ret0, _ := ret[0].(*wire.StreamFrame) + return ret0 +} + +// PopCryptoStreamFrame indicates an expected call of PopCryptoStreamFrame +func (mr *MockStreamFrameSourceMockRecorder) PopCryptoStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PopCryptoStreamFrame", reflect.TypeOf((*MockStreamFrameSource)(nil).PopCryptoStreamFrame), arg0) +} + +// PopStreamFrames mocks base method +func (m *MockStreamFrameSource) PopStreamFrames(arg0 protocol.ByteCount) []*wire.StreamFrame { + ret := m.ctrl.Call(m, "PopStreamFrames", arg0) + ret0, _ := ret[0].([]*wire.StreamFrame) + return ret0 +} + +// PopStreamFrames indicates an expected call of PopStreamFrames +func (mr *MockStreamFrameSourceMockRecorder) PopStreamFrames(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PopStreamFrames", reflect.TypeOf((*MockStreamFrameSource)(nil).PopStreamFrames), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_stream_getter_test.go b/vendor/lucas-clemente/quic-go/mock_stream_getter_test.go new file mode 100644 index 00000000..8dfa2d86 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_stream_getter_test.go @@ -0,0 +1,61 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: StreamGetter) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockStreamGetter is a mock of StreamGetter interface +type MockStreamGetter struct { + ctrl *gomock.Controller + recorder *MockStreamGetterMockRecorder +} + +// MockStreamGetterMockRecorder is the mock recorder for MockStreamGetter +type MockStreamGetterMockRecorder struct { + mock *MockStreamGetter +} + +// NewMockStreamGetter creates a new mock instance +func NewMockStreamGetter(ctrl *gomock.Controller) *MockStreamGetter { + mock := &MockStreamGetter{ctrl: ctrl} + mock.recorder = &MockStreamGetterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStreamGetter) EXPECT() *MockStreamGetterMockRecorder { + return m.recorder +} + +// GetOrOpenReceiveStream mocks base method +func (m *MockStreamGetter) GetOrOpenReceiveStream(arg0 protocol.StreamID) (receiveStreamI, error) { + ret := m.ctrl.Call(m, "GetOrOpenReceiveStream", arg0) + ret0, _ := ret[0].(receiveStreamI) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrOpenReceiveStream indicates an expected call of GetOrOpenReceiveStream +func (mr *MockStreamGetterMockRecorder) GetOrOpenReceiveStream(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrOpenReceiveStream", reflect.TypeOf((*MockStreamGetter)(nil).GetOrOpenReceiveStream), arg0) +} + +// GetOrOpenSendStream mocks base method +func (m *MockStreamGetter) GetOrOpenSendStream(arg0 protocol.StreamID) (sendStreamI, error) { + ret := m.ctrl.Call(m, "GetOrOpenSendStream", arg0) + ret0, _ := ret[0].(sendStreamI) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrOpenSendStream indicates an expected call of GetOrOpenSendStream +func (mr *MockStreamGetterMockRecorder) GetOrOpenSendStream(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrOpenSendStream", reflect.TypeOf((*MockStreamGetter)(nil).GetOrOpenSendStream), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_stream_internal_test.go b/vendor/lucas-clemente/quic-go/mock_stream_internal_test.go new file mode 100644 index 00000000..6cbc8a97 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_stream_internal_test.go @@ -0,0 +1,239 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: StreamI) + +// Package quic is a generated GoMock package. +package quic + +import ( + context "context" + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockStreamI is a mock of StreamI interface +type MockStreamI struct { + ctrl *gomock.Controller + recorder *MockStreamIMockRecorder +} + +// MockStreamIMockRecorder is the mock recorder for MockStreamI +type MockStreamIMockRecorder struct { + mock *MockStreamI +} + +// NewMockStreamI creates a new mock instance +func NewMockStreamI(ctrl *gomock.Controller) *MockStreamI { + mock := &MockStreamI{ctrl: ctrl} + mock.recorder = &MockStreamIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStreamI) EXPECT() *MockStreamIMockRecorder { + return m.recorder +} + +// CancelRead mocks base method +func (m *MockStreamI) CancelRead(arg0 protocol.ApplicationErrorCode) error { + ret := m.ctrl.Call(m, "CancelRead", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// CancelRead indicates an expected call of CancelRead +func (mr *MockStreamIMockRecorder) CancelRead(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelRead", reflect.TypeOf((*MockStreamI)(nil).CancelRead), arg0) +} + +// CancelWrite mocks base method +func (m *MockStreamI) CancelWrite(arg0 protocol.ApplicationErrorCode) error { + ret := m.ctrl.Call(m, "CancelWrite", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// CancelWrite indicates an expected call of CancelWrite +func (mr *MockStreamIMockRecorder) CancelWrite(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelWrite", reflect.TypeOf((*MockStreamI)(nil).CancelWrite), arg0) +} + +// Close mocks base method +func (m *MockStreamI) Close() error { + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockStreamIMockRecorder) Close() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockStreamI)(nil).Close)) +} + +// Context mocks base method +func (m *MockStreamI) Context() context.Context { + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context +func (mr *MockStreamIMockRecorder) Context() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockStreamI)(nil).Context)) +} + +// Read mocks base method +func (m *MockStreamI) Read(arg0 []byte) (int, error) { + ret := m.ctrl.Call(m, "Read", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Read indicates an expected call of Read +func (mr *MockStreamIMockRecorder) Read(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockStreamI)(nil).Read), arg0) +} + +// SetDeadline mocks base method +func (m *MockStreamI) SetDeadline(arg0 time.Time) error { + ret := m.ctrl.Call(m, "SetDeadline", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetDeadline indicates an expected call of SetDeadline +func (mr *MockStreamIMockRecorder) SetDeadline(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDeadline", reflect.TypeOf((*MockStreamI)(nil).SetDeadline), arg0) +} + +// SetReadDeadline mocks base method +func (m *MockStreamI) SetReadDeadline(arg0 time.Time) error { + ret := m.ctrl.Call(m, "SetReadDeadline", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetReadDeadline indicates an expected call of SetReadDeadline +func (mr *MockStreamIMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReadDeadline", reflect.TypeOf((*MockStreamI)(nil).SetReadDeadline), arg0) +} + +// SetWriteDeadline mocks base method +func (m *MockStreamI) SetWriteDeadline(arg0 time.Time) error { + ret := m.ctrl.Call(m, "SetWriteDeadline", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetWriteDeadline indicates an expected call of SetWriteDeadline +func (mr *MockStreamIMockRecorder) SetWriteDeadline(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetWriteDeadline", reflect.TypeOf((*MockStreamI)(nil).SetWriteDeadline), arg0) +} + +// StreamID mocks base method +func (m *MockStreamI) StreamID() protocol.StreamID { + ret := m.ctrl.Call(m, "StreamID") + ret0, _ := ret[0].(protocol.StreamID) + return ret0 +} + +// StreamID indicates an expected call of StreamID +func (mr *MockStreamIMockRecorder) StreamID() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StreamID", reflect.TypeOf((*MockStreamI)(nil).StreamID)) +} + +// Write mocks base method +func (m *MockStreamI) Write(arg0 []byte) (int, error) { + ret := m.ctrl.Call(m, "Write", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Write indicates an expected call of Write +func (mr *MockStreamIMockRecorder) Write(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockStreamI)(nil).Write), arg0) +} + +// closeForShutdown mocks base method +func (m *MockStreamI) closeForShutdown(arg0 error) { + m.ctrl.Call(m, "closeForShutdown", arg0) +} + +// closeForShutdown indicates an expected call of closeForShutdown +func (mr *MockStreamIMockRecorder) closeForShutdown(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "closeForShutdown", reflect.TypeOf((*MockStreamI)(nil).closeForShutdown), arg0) +} + +// getWindowUpdate mocks base method +func (m *MockStreamI) getWindowUpdate() protocol.ByteCount { + ret := m.ctrl.Call(m, "getWindowUpdate") + ret0, _ := ret[0].(protocol.ByteCount) + return ret0 +} + +// getWindowUpdate indicates an expected call of getWindowUpdate +func (mr *MockStreamIMockRecorder) getWindowUpdate() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getWindowUpdate", reflect.TypeOf((*MockStreamI)(nil).getWindowUpdate)) +} + +// handleMaxStreamDataFrame mocks base method +func (m *MockStreamI) handleMaxStreamDataFrame(arg0 *wire.MaxStreamDataFrame) { + m.ctrl.Call(m, "handleMaxStreamDataFrame", arg0) +} + +// handleMaxStreamDataFrame indicates an expected call of handleMaxStreamDataFrame +func (mr *MockStreamIMockRecorder) handleMaxStreamDataFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleMaxStreamDataFrame", reflect.TypeOf((*MockStreamI)(nil).handleMaxStreamDataFrame), arg0) +} + +// handleRstStreamFrame mocks base method +func (m *MockStreamI) handleRstStreamFrame(arg0 *wire.RstStreamFrame) error { + ret := m.ctrl.Call(m, "handleRstStreamFrame", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// handleRstStreamFrame indicates an expected call of handleRstStreamFrame +func (mr *MockStreamIMockRecorder) handleRstStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleRstStreamFrame", reflect.TypeOf((*MockStreamI)(nil).handleRstStreamFrame), arg0) +} + +// handleStopSendingFrame mocks base method +func (m *MockStreamI) handleStopSendingFrame(arg0 *wire.StopSendingFrame) { + m.ctrl.Call(m, "handleStopSendingFrame", arg0) +} + +// handleStopSendingFrame indicates an expected call of handleStopSendingFrame +func (mr *MockStreamIMockRecorder) handleStopSendingFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleStopSendingFrame", reflect.TypeOf((*MockStreamI)(nil).handleStopSendingFrame), arg0) +} + +// handleStreamFrame mocks base method +func (m *MockStreamI) handleStreamFrame(arg0 *wire.StreamFrame) error { + ret := m.ctrl.Call(m, "handleStreamFrame", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// handleStreamFrame indicates an expected call of handleStreamFrame +func (mr *MockStreamIMockRecorder) handleStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handleStreamFrame", reflect.TypeOf((*MockStreamI)(nil).handleStreamFrame), arg0) +} + +// popStreamFrame mocks base method +func (m *MockStreamI) popStreamFrame(arg0 protocol.ByteCount) (*wire.StreamFrame, bool) { + ret := m.ctrl.Call(m, "popStreamFrame", arg0) + ret0, _ := ret[0].(*wire.StreamFrame) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// popStreamFrame indicates an expected call of popStreamFrame +func (mr *MockStreamIMockRecorder) popStreamFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "popStreamFrame", reflect.TypeOf((*MockStreamI)(nil).popStreamFrame), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_stream_manager_test.go b/vendor/lucas-clemente/quic-go/mock_stream_manager_test.go new file mode 100644 index 00000000..0fdd7262 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_stream_manager_test.go @@ -0,0 +1,185 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: StreamManager) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + handshake "github.com/lucas-clemente/quic-go/internal/handshake" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockStreamManager is a mock of StreamManager interface +type MockStreamManager struct { + ctrl *gomock.Controller + recorder *MockStreamManagerMockRecorder +} + +// MockStreamManagerMockRecorder is the mock recorder for MockStreamManager +type MockStreamManagerMockRecorder struct { + mock *MockStreamManager +} + +// NewMockStreamManager creates a new mock instance +func NewMockStreamManager(ctrl *gomock.Controller) *MockStreamManager { + mock := &MockStreamManager{ctrl: ctrl} + mock.recorder = &MockStreamManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStreamManager) EXPECT() *MockStreamManagerMockRecorder { + return m.recorder +} + +// AcceptStream mocks base method +func (m *MockStreamManager) AcceptStream() (Stream, error) { + ret := m.ctrl.Call(m, "AcceptStream") + ret0, _ := ret[0].(Stream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcceptStream indicates an expected call of AcceptStream +func (mr *MockStreamManagerMockRecorder) AcceptStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptStream", reflect.TypeOf((*MockStreamManager)(nil).AcceptStream)) +} + +// AcceptUniStream mocks base method +func (m *MockStreamManager) AcceptUniStream() (ReceiveStream, error) { + ret := m.ctrl.Call(m, "AcceptUniStream") + ret0, _ := ret[0].(ReceiveStream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcceptUniStream indicates an expected call of AcceptUniStream +func (mr *MockStreamManagerMockRecorder) AcceptUniStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptUniStream", reflect.TypeOf((*MockStreamManager)(nil).AcceptUniStream)) +} + +// CloseWithError mocks base method +func (m *MockStreamManager) CloseWithError(arg0 error) { + m.ctrl.Call(m, "CloseWithError", arg0) +} + +// CloseWithError indicates an expected call of CloseWithError +func (mr *MockStreamManagerMockRecorder) CloseWithError(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseWithError", reflect.TypeOf((*MockStreamManager)(nil).CloseWithError), arg0) +} + +// DeleteStream mocks base method +func (m *MockStreamManager) DeleteStream(arg0 protocol.StreamID) error { + ret := m.ctrl.Call(m, "DeleteStream", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteStream indicates an expected call of DeleteStream +func (mr *MockStreamManagerMockRecorder) DeleteStream(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStream", reflect.TypeOf((*MockStreamManager)(nil).DeleteStream), arg0) +} + +// GetOrOpenReceiveStream mocks base method +func (m *MockStreamManager) GetOrOpenReceiveStream(arg0 protocol.StreamID) (receiveStreamI, error) { + ret := m.ctrl.Call(m, "GetOrOpenReceiveStream", arg0) + ret0, _ := ret[0].(receiveStreamI) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrOpenReceiveStream indicates an expected call of GetOrOpenReceiveStream +func (mr *MockStreamManagerMockRecorder) GetOrOpenReceiveStream(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrOpenReceiveStream", reflect.TypeOf((*MockStreamManager)(nil).GetOrOpenReceiveStream), arg0) +} + +// GetOrOpenSendStream mocks base method +func (m *MockStreamManager) GetOrOpenSendStream(arg0 protocol.StreamID) (sendStreamI, error) { + ret := m.ctrl.Call(m, "GetOrOpenSendStream", arg0) + ret0, _ := ret[0].(sendStreamI) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrOpenSendStream indicates an expected call of GetOrOpenSendStream +func (mr *MockStreamManagerMockRecorder) GetOrOpenSendStream(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrOpenSendStream", reflect.TypeOf((*MockStreamManager)(nil).GetOrOpenSendStream), arg0) +} + +// HandleMaxStreamIDFrame mocks base method +func (m *MockStreamManager) HandleMaxStreamIDFrame(arg0 *wire.MaxStreamIDFrame) error { + ret := m.ctrl.Call(m, "HandleMaxStreamIDFrame", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// HandleMaxStreamIDFrame indicates an expected call of HandleMaxStreamIDFrame +func (mr *MockStreamManagerMockRecorder) HandleMaxStreamIDFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMaxStreamIDFrame", reflect.TypeOf((*MockStreamManager)(nil).HandleMaxStreamIDFrame), arg0) +} + +// OpenStream mocks base method +func (m *MockStreamManager) OpenStream() (Stream, error) { + ret := m.ctrl.Call(m, "OpenStream") + ret0, _ := ret[0].(Stream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenStream indicates an expected call of OpenStream +func (mr *MockStreamManagerMockRecorder) OpenStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenStream", reflect.TypeOf((*MockStreamManager)(nil).OpenStream)) +} + +// OpenStreamSync mocks base method +func (m *MockStreamManager) OpenStreamSync() (Stream, error) { + ret := m.ctrl.Call(m, "OpenStreamSync") + ret0, _ := ret[0].(Stream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenStreamSync indicates an expected call of OpenStreamSync +func (mr *MockStreamManagerMockRecorder) OpenStreamSync() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenStreamSync", reflect.TypeOf((*MockStreamManager)(nil).OpenStreamSync)) +} + +// OpenUniStream mocks base method +func (m *MockStreamManager) OpenUniStream() (SendStream, error) { + ret := m.ctrl.Call(m, "OpenUniStream") + ret0, _ := ret[0].(SendStream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenUniStream indicates an expected call of OpenUniStream +func (mr *MockStreamManagerMockRecorder) OpenUniStream() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenUniStream", reflect.TypeOf((*MockStreamManager)(nil).OpenUniStream)) +} + +// OpenUniStreamSync mocks base method +func (m *MockStreamManager) OpenUniStreamSync() (SendStream, error) { + ret := m.ctrl.Call(m, "OpenUniStreamSync") + ret0, _ := ret[0].(SendStream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenUniStreamSync indicates an expected call of OpenUniStreamSync +func (mr *MockStreamManagerMockRecorder) OpenUniStreamSync() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenUniStreamSync", reflect.TypeOf((*MockStreamManager)(nil).OpenUniStreamSync)) +} + +// UpdateLimits mocks base method +func (m *MockStreamManager) UpdateLimits(arg0 *handshake.TransportParameters) { + m.ctrl.Call(m, "UpdateLimits", arg0) +} + +// UpdateLimits indicates an expected call of UpdateLimits +func (mr *MockStreamManagerMockRecorder) UpdateLimits(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateLimits", reflect.TypeOf((*MockStreamManager)(nil).UpdateLimits), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_stream_sender_test.go b/vendor/lucas-clemente/quic-go/mock_stream_sender_test.go new file mode 100644 index 00000000..d6f090a1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_stream_sender_test.go @@ -0,0 +1,66 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: StreamSender) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockStreamSender is a mock of StreamSender interface +type MockStreamSender struct { + ctrl *gomock.Controller + recorder *MockStreamSenderMockRecorder +} + +// MockStreamSenderMockRecorder is the mock recorder for MockStreamSender +type MockStreamSenderMockRecorder struct { + mock *MockStreamSender +} + +// NewMockStreamSender creates a new mock instance +func NewMockStreamSender(ctrl *gomock.Controller) *MockStreamSender { + mock := &MockStreamSender{ctrl: ctrl} + mock.recorder = &MockStreamSenderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStreamSender) EXPECT() *MockStreamSenderMockRecorder { + return m.recorder +} + +// onHasStreamData mocks base method +func (m *MockStreamSender) onHasStreamData(arg0 protocol.StreamID) { + m.ctrl.Call(m, "onHasStreamData", arg0) +} + +// onHasStreamData indicates an expected call of onHasStreamData +func (mr *MockStreamSenderMockRecorder) onHasStreamData(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "onHasStreamData", reflect.TypeOf((*MockStreamSender)(nil).onHasStreamData), arg0) +} + +// onStreamCompleted mocks base method +func (m *MockStreamSender) onStreamCompleted(arg0 protocol.StreamID) { + m.ctrl.Call(m, "onStreamCompleted", arg0) +} + +// onStreamCompleted indicates an expected call of onStreamCompleted +func (mr *MockStreamSenderMockRecorder) onStreamCompleted(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "onStreamCompleted", reflect.TypeOf((*MockStreamSender)(nil).onStreamCompleted), arg0) +} + +// queueControlFrame mocks base method +func (m *MockStreamSender) queueControlFrame(arg0 wire.Frame) { + m.ctrl.Call(m, "queueControlFrame", arg0) +} + +// queueControlFrame indicates an expected call of queueControlFrame +func (mr *MockStreamSenderMockRecorder) queueControlFrame(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "queueControlFrame", reflect.TypeOf((*MockStreamSender)(nil).queueControlFrame), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_unknown_packet_handler_test.go b/vendor/lucas-clemente/quic-go/mock_unknown_packet_handler_test.go new file mode 100644 index 00000000..65f2978a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_unknown_packet_handler_test.go @@ -0,0 +1,56 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: UnknownPacketHandler) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockUnknownPacketHandler is a mock of UnknownPacketHandler interface +type MockUnknownPacketHandler struct { + ctrl *gomock.Controller + recorder *MockUnknownPacketHandlerMockRecorder +} + +// MockUnknownPacketHandlerMockRecorder is the mock recorder for MockUnknownPacketHandler +type MockUnknownPacketHandlerMockRecorder struct { + mock *MockUnknownPacketHandler +} + +// NewMockUnknownPacketHandler creates a new mock instance +func NewMockUnknownPacketHandler(ctrl *gomock.Controller) *MockUnknownPacketHandler { + mock := &MockUnknownPacketHandler{ctrl: ctrl} + mock.recorder = &MockUnknownPacketHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockUnknownPacketHandler) EXPECT() *MockUnknownPacketHandlerMockRecorder { + return m.recorder +} + +// closeWithError mocks base method +func (m *MockUnknownPacketHandler) closeWithError(arg0 error) error { + ret := m.ctrl.Call(m, "closeWithError", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// closeWithError indicates an expected call of closeWithError +func (mr *MockUnknownPacketHandlerMockRecorder) closeWithError(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "closeWithError", reflect.TypeOf((*MockUnknownPacketHandler)(nil).closeWithError), arg0) +} + +// handlePacket mocks base method +func (m *MockUnknownPacketHandler) handlePacket(arg0 *receivedPacket) { + m.ctrl.Call(m, "handlePacket", arg0) +} + +// handlePacket indicates an expected call of handlePacket +func (mr *MockUnknownPacketHandlerMockRecorder) handlePacket(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "handlePacket", reflect.TypeOf((*MockUnknownPacketHandler)(nil).handlePacket), arg0) +} diff --git a/vendor/lucas-clemente/quic-go/mock_unpacker_test.go b/vendor/lucas-clemente/quic-go/mock_unpacker_test.go new file mode 100644 index 00000000..6bf3cc69 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mock_unpacker_test.go @@ -0,0 +1,48 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go (interfaces: Unpacker) + +// Package quic is a generated GoMock package. +package quic + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + wire "github.com/lucas-clemente/quic-go/internal/wire" +) + +// MockUnpacker is a mock of Unpacker interface +type MockUnpacker struct { + ctrl *gomock.Controller + recorder *MockUnpackerMockRecorder +} + +// MockUnpackerMockRecorder is the mock recorder for MockUnpacker +type MockUnpackerMockRecorder struct { + mock *MockUnpacker +} + +// NewMockUnpacker creates a new mock instance +func NewMockUnpacker(ctrl *gomock.Controller) *MockUnpacker { + mock := &MockUnpacker{ctrl: ctrl} + mock.recorder = &MockUnpackerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockUnpacker) EXPECT() *MockUnpackerMockRecorder { + return m.recorder +} + +// Unpack mocks base method +func (m *MockUnpacker) Unpack(arg0 []byte, arg1 *wire.Header, arg2 []byte) (*unpackedPacket, error) { + ret := m.ctrl.Call(m, "Unpack", arg0, arg1, arg2) + ret0, _ := ret[0].(*unpackedPacket) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Unpack indicates an expected call of Unpack +func (mr *MockUnpackerMockRecorder) Unpack(arg0, arg1, arg2 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unpack", reflect.TypeOf((*MockUnpacker)(nil).Unpack), arg0, arg1, arg2) +} diff --git a/vendor/lucas-clemente/quic-go/mockgen.go b/vendor/lucas-clemente/quic-go/mockgen.go new file mode 100644 index 00000000..5b7cd4f0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mockgen.go @@ -0,0 +1,19 @@ +package quic + +//go:generate sh -c "./mockgen_private.sh quic mock_stream_internal_test.go github.com/lucas-clemente/quic-go streamI" +//go:generate sh -c "./mockgen_private.sh quic mock_receive_stream_internal_test.go github.com/lucas-clemente/quic-go receiveStreamI" +//go:generate sh -c "./mockgen_private.sh quic mock_send_stream_internal_test.go github.com/lucas-clemente/quic-go sendStreamI" +//go:generate sh -c "./mockgen_private.sh quic mock_stream_sender_test.go github.com/lucas-clemente/quic-go streamSender" +//go:generate sh -c "./mockgen_private.sh quic mock_stream_getter_test.go github.com/lucas-clemente/quic-go streamGetter" +//go:generate sh -c "./mockgen_private.sh quic mock_stream_frame_source_test.go github.com/lucas-clemente/quic-go streamFrameSource" +//go:generate sh -c "./mockgen_private.sh quic mock_crypto_stream_test.go github.com/lucas-clemente/quic-go cryptoStream" +//go:generate sh -c "./mockgen_private.sh quic mock_stream_manager_test.go github.com/lucas-clemente/quic-go streamManager" +//go:generate sh -c "./mockgen_private.sh quic mock_unpacker_test.go github.com/lucas-clemente/quic-go unpacker" +//go:generate sh -c "./mockgen_private.sh quic mock_quic_aead_test.go github.com/lucas-clemente/quic-go quicAEAD" +//go:generate sh -c "./mockgen_private.sh quic mock_gquic_aead_test.go github.com/lucas-clemente/quic-go gQUICAEAD" +//go:generate sh -c "./mockgen_private.sh quic mock_session_runner_test.go github.com/lucas-clemente/quic-go sessionRunner" +//go:generate sh -c "./mockgen_private.sh quic mock_quic_session_test.go github.com/lucas-clemente/quic-go quicSession" +//go:generate sh -c "./mockgen_private.sh quic mock_packet_handler_test.go github.com/lucas-clemente/quic-go packetHandler" +//go:generate sh -c "./mockgen_private.sh quic mock_unknown_packet_handler_test.go github.com/lucas-clemente/quic-go unknownPacketHandler" +//go:generate sh -c "./mockgen_private.sh quic mock_packet_handler_manager_test.go github.com/lucas-clemente/quic-go packetHandlerManager" +//go:generate sh -c "./mockgen_private.sh quic mock_multiplexer_test.go github.com/lucas-clemente/quic-go multiplexer" diff --git a/vendor/lucas-clemente/quic-go/mockgen_private.sh b/vendor/lucas-clemente/quic-go/mockgen_private.sh new file mode 100755 index 00000000..0ba5f64e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/mockgen_private.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Mockgen refuses to generate mocks private types. +# This script copies the quic package to a temporary directory, and adds an public alias for the private type. +# It then creates a mock for this public (alias) type. + +TEMP_DIR=$(mktemp -d) +mkdir -p $TEMP_DIR/src/github.com/lucas-clemente/quic-go/ + +# uppercase the name of the interface +INTERFACE_NAME="$(tr '[:lower:]' '[:upper:]' <<< ${4:0:1})${4:1}" + +# copy all .go files to a temporary directory +rsync -r --exclude 'vendor' --include='*.go' --include '*/' --exclude '*' $GOPATH/src/github.com/lucas-clemente/quic-go/ $TEMP_DIR/src/github.com/lucas-clemente/quic-go/ + +# create a public alias for the interface, so that mockgen can process it +echo -e "package $1\n" > $TEMP_DIR/src/github.com/lucas-clemente/quic-go/mockgen_interface.go +echo "type $INTERFACE_NAME = $4" >> $TEMP_DIR/src/github.com/lucas-clemente/quic-go/mockgen_interface.go + +export GOPATH="$TEMP_DIR:$GOPATH" + +mockgen -package $1 -self_package $1 -destination $2 $3 $INTERFACE_NAME + +# mockgen imports quic-go as 'import quic_go github.com/lucas_clemente/quic-go' +sed -i '' 's/quic_go.//g' $2 +goimports -w $2 + +rm -r "$TEMP_DIR" diff --git a/vendor/lucas-clemente/quic-go/multiplexer.go b/vendor/lucas-clemente/quic-go/multiplexer.go new file mode 100644 index 00000000..c4482ac2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/multiplexer.go @@ -0,0 +1,63 @@ +package quic + +import ( + "fmt" + "net" + "sync" + + "github.com/lucas-clemente/quic-go/internal/utils" +) + +var ( + connMuxerOnce sync.Once + connMuxer multiplexer +) + +type multiplexer interface { + AddConn(net.PacketConn, int) (packetHandlerManager, error) +} + +type connManager struct { + connIDLen int + manager packetHandlerManager +} + +// The connMultiplexer listens on multiple net.PacketConns and dispatches +// incoming packets to the session handler. +type connMultiplexer struct { + mutex sync.Mutex + + conns map[net.PacketConn]connManager + newPacketHandlerManager func(net.PacketConn, int, utils.Logger) packetHandlerManager // so it can be replaced in the tests + + logger utils.Logger +} + +var _ multiplexer = &connMultiplexer{} + +func getMultiplexer() multiplexer { + connMuxerOnce.Do(func() { + connMuxer = &connMultiplexer{ + conns: make(map[net.PacketConn]connManager), + logger: utils.DefaultLogger.WithPrefix("muxer"), + newPacketHandlerManager: newPacketHandlerMap, + } + }) + return connMuxer +} + +func (m *connMultiplexer) AddConn(c net.PacketConn, connIDLen int) (packetHandlerManager, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + p, ok := m.conns[c] + if !ok { + manager := m.newPacketHandlerManager(c, connIDLen, m.logger) + p = connManager{connIDLen: connIDLen, manager: manager} + m.conns[c] = p + } + if p.connIDLen != connIDLen { + return nil, fmt.Errorf("cannot use %d byte connection IDs on a connection that is already using %d byte connction IDs", connIDLen, p.connIDLen) + } + return p.manager, nil +} diff --git a/vendor/lucas-clemente/quic-go/multiplexer_test.go b/vendor/lucas-clemente/quic-go/multiplexer_test.go new file mode 100644 index 00000000..f50f227f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/multiplexer_test.go @@ -0,0 +1,23 @@ +package quic + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Client Multiplexer", func() { + It("adds a new packet conn ", func() { + conn := newMockPacketConn() + _, err := getMultiplexer().AddConn(conn, 8) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors when adding an existing conn with a different connection ID length", func() { + conn := newMockPacketConn() + _, err := getMultiplexer().AddConn(conn, 5) + Expect(err).ToNot(HaveOccurred()) + _, err = getMultiplexer().AddConn(conn, 6) + Expect(err).To(MatchError("cannot use 6 byte connection IDs on a connection that is already using 5 byte connction IDs")) + }) + +}) diff --git a/vendor/lucas-clemente/quic-go/packet_handler_map.go b/vendor/lucas-clemente/quic-go/packet_handler_map.go new file mode 100644 index 00000000..35f9bdfa --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_handler_map.go @@ -0,0 +1,198 @@ +package quic + +import ( + "bytes" + "fmt" + "net" + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +// The packetHandlerMap stores packetHandlers, identified by connection ID. +// It is used: +// * by the server to store sessions +// * when multiplexing outgoing connections to store clients +type packetHandlerMap struct { + mutex sync.RWMutex + + conn net.PacketConn + connIDLen int + + handlers map[string] /* string(ConnectionID)*/ packetHandler + server unknownPacketHandler + closed bool + + deleteClosedSessionsAfter time.Duration + + logger utils.Logger +} + +var _ packetHandlerManager = &packetHandlerMap{} + +func newPacketHandlerMap(conn net.PacketConn, connIDLen int, logger utils.Logger) packetHandlerManager { + m := &packetHandlerMap{ + conn: conn, + connIDLen: connIDLen, + handlers: make(map[string]packetHandler), + deleteClosedSessionsAfter: protocol.ClosedSessionDeleteTimeout, + logger: logger, + } + go m.listen() + return m +} + +func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) { + h.mutex.Lock() + h.handlers[string(id)] = handler + h.mutex.Unlock() +} + +func (h *packetHandlerMap) Remove(id protocol.ConnectionID) { + h.removeByConnectionIDAsString(string(id)) +} + +func (h *packetHandlerMap) removeByConnectionIDAsString(id string) { + h.mutex.Lock() + h.handlers[id] = nil + h.mutex.Unlock() + + time.AfterFunc(h.deleteClosedSessionsAfter, func() { + h.mutex.Lock() + delete(h.handlers, id) + h.mutex.Unlock() + }) +} + +func (h *packetHandlerMap) SetServer(s unknownPacketHandler) { + h.mutex.Lock() + h.server = s + h.mutex.Unlock() +} + +func (h *packetHandlerMap) CloseServer() { + h.mutex.Lock() + h.server = nil + var wg sync.WaitGroup + for id, handler := range h.handlers { + if handler != nil && handler.GetPerspective() == protocol.PerspectiveServer { + wg.Add(1) + go func(id string, handler packetHandler) { + // session.Close() blocks until the CONNECTION_CLOSE has been sent and the run-loop has stopped + _ = handler.Close() + h.removeByConnectionIDAsString(id) + wg.Done() + }(id, handler) + } + } + h.mutex.Unlock() + wg.Wait() +} + +func (h *packetHandlerMap) close(e error) error { + h.mutex.Lock() + if h.closed { + h.mutex.Unlock() + return nil + } + h.closed = true + + var wg sync.WaitGroup + for _, handler := range h.handlers { + if handler != nil { + wg.Add(1) + go func(handler packetHandler) { + handler.destroy(e) + wg.Done() + }(handler) + } + } + + if h.server != nil { + h.server.closeWithError(e) + } + h.mutex.Unlock() + wg.Wait() + return nil +} + +func (h *packetHandlerMap) listen() { + for { + data := *getPacketBuffer() + data = data[:protocol.MaxReceivePacketSize] + // The packet size should not exceed protocol.MaxReceivePacketSize bytes + // If it does, we only read a truncated packet, which will then end up undecryptable + n, addr, err := h.conn.ReadFrom(data) + if err != nil { + h.close(err) + return + } + data = data[:n] + + if err := h.handlePacket(addr, data); err != nil { + h.logger.Debugf("error handling packet from %s: %s", addr, err) + } + } +} + +func (h *packetHandlerMap) handlePacket(addr net.Addr, data []byte) error { + rcvTime := time.Now() + + r := bytes.NewReader(data) + iHdr, err := wire.ParseInvariantHeader(r, h.connIDLen) + // drop the packet if we can't parse the header + if err != nil { + return fmt.Errorf("error parsing invariant header: %s", err) + } + + h.mutex.RLock() + handler, ok := h.handlers[string(iHdr.DestConnectionID)] + server := h.server + h.mutex.RUnlock() + + var sentBy protocol.Perspective + var version protocol.VersionNumber + var handlePacket func(*receivedPacket) + if ok && handler == nil { + // Late packet for closed session + return nil + } + if !ok { + if server == nil { // no server set + return fmt.Errorf("received a packet with an unexpected connection ID %s", iHdr.DestConnectionID) + } + handlePacket = server.handlePacket + sentBy = protocol.PerspectiveClient + version = iHdr.Version + } else { + sentBy = handler.GetPerspective().Opposite() + version = handler.GetVersion() + handlePacket = handler.handlePacket + } + + hdr, err := iHdr.Parse(r, sentBy, version) + if err != nil { + return fmt.Errorf("error parsing header: %s", err) + } + hdr.Raw = data[:len(data)-r.Len()] + packetData := data[len(data)-r.Len():] + + if hdr.IsLongHeader && hdr.Version.UsesLengthInHeader() { + if protocol.ByteCount(len(packetData)) < hdr.PayloadLen { + return fmt.Errorf("packet payload (%d bytes) is smaller than the expected payload length (%d bytes)", len(packetData), hdr.PayloadLen) + } + packetData = packetData[:int(hdr.PayloadLen)] + // TODO(#1312): implement parsing of compound packets + } + + handlePacket(&receivedPacket{ + remoteAddr: addr, + header: hdr, + data: packetData, + rcvTime: rcvTime, + }) + return nil +} diff --git a/vendor/lucas-clemente/quic-go/packet_handler_map_test.go b/vendor/lucas-clemente/quic-go/packet_handler_map_test.go new file mode 100644 index 00000000..4986081f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_handler_map_test.go @@ -0,0 +1,206 @@ +package quic + +import ( + "bytes" + "errors" + "time" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Packet Handler Map", func() { + var ( + handler *packetHandlerMap + conn *mockPacketConn + ) + + getPacket := func(connID protocol.ConnectionID) []byte { + buf := &bytes.Buffer{} + err := (&wire.Header{ + DestConnectionID: connID, + PacketNumberLen: protocol.PacketNumberLen1, + }).Write(buf, protocol.PerspectiveServer, versionGQUICFrames) + Expect(err).ToNot(HaveOccurred()) + return buf.Bytes() + } + + BeforeEach(func() { + conn = newMockPacketConn() + handler = newPacketHandlerMap(conn, 5, utils.DefaultLogger).(*packetHandlerMap) + }) + + It("closes", func() { + testErr := errors.New("test error ") + sess1 := NewMockPacketHandler(mockCtrl) + sess1.EXPECT().destroy(testErr) + sess2 := NewMockPacketHandler(mockCtrl) + sess2.EXPECT().destroy(testErr) + handler.Add(protocol.ConnectionID{1, 1, 1, 1}, sess1) + handler.Add(protocol.ConnectionID{2, 2, 2, 2}, sess2) + handler.close(testErr) + }) + + Context("handling packets", func() { + It("handles packets for different packet handlers on the same packet conn", func() { + connID1 := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + connID2 := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + packetHandler1 := NewMockPacketHandler(mockCtrl) + packetHandler2 := NewMockPacketHandler(mockCtrl) + handledPacket1 := make(chan struct{}) + handledPacket2 := make(chan struct{}) + packetHandler1.EXPECT().handlePacket(gomock.Any()).Do(func(p *receivedPacket) { + Expect(p.header.DestConnectionID).To(Equal(connID1)) + close(handledPacket1) + }) + packetHandler1.EXPECT().GetVersion() + packetHandler1.EXPECT().GetPerspective().Return(protocol.PerspectiveClient) + packetHandler2.EXPECT().handlePacket(gomock.Any()).Do(func(p *receivedPacket) { + Expect(p.header.DestConnectionID).To(Equal(connID2)) + close(handledPacket2) + }) + packetHandler2.EXPECT().GetVersion() + packetHandler2.EXPECT().GetPerspective().Return(protocol.PerspectiveClient) + handler.Add(connID1, packetHandler1) + handler.Add(connID2, packetHandler2) + + conn.dataToRead <- getPacket(connID1) + conn.dataToRead <- getPacket(connID2) + Eventually(handledPacket1).Should(BeClosed()) + Eventually(handledPacket2).Should(BeClosed()) + + // makes the listen go routine return + packetHandler1.EXPECT().destroy(gomock.Any()).AnyTimes() + packetHandler2.EXPECT().destroy(gomock.Any()).AnyTimes() + close(conn.dataToRead) + }) + + It("drops unparseable packets", func() { + err := handler.handlePacket(nil, []byte("invalid")) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("error parsing invariant header:")) + }) + + It("deletes nil session entries after a wait time", func() { + handler.deleteClosedSessionsAfter = 10 * time.Millisecond + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + handler.Add(connID, NewMockPacketHandler(mockCtrl)) + handler.Remove(connID) + Eventually(func() error { + return handler.handlePacket(nil, getPacket(connID)) + }).Should(MatchError("received a packet with an unexpected connection ID 0x0102030405060708")) + }) + + It("ignores packets arriving late for closed sessions", func() { + handler.deleteClosedSessionsAfter = time.Hour + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + handler.Add(connID, NewMockPacketHandler(mockCtrl)) + handler.Remove(connID) + err := handler.handlePacket(nil, getPacket(connID)) + Expect(err).ToNot(HaveOccurred()) + }) + + It("drops packets for unknown receivers", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + err := handler.handlePacket(nil, getPacket(connID)) + Expect(err).To(MatchError("received a packet with an unexpected connection ID 0x0102030405060708")) + }) + + It("errors on packets that are smaller than the Payload Length in the packet header", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + packetHandler := NewMockPacketHandler(mockCtrl) + packetHandler.EXPECT().GetVersion().Return(versionIETFFrames) + packetHandler.EXPECT().GetPerspective().Return(protocol.PerspectiveClient) + handler.Add(connID, packetHandler) + hdr := &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeHandshake, + PayloadLen: 1000, + DestConnectionID: connID, + PacketNumberLen: protocol.PacketNumberLen1, + Version: versionIETFFrames, + } + buf := &bytes.Buffer{} + Expect(hdr.Write(buf, protocol.PerspectiveServer, versionIETFFrames)).To(Succeed()) + buf.Write(bytes.Repeat([]byte{0}, 500)) + + err := handler.handlePacket(nil, buf.Bytes()) + Expect(err).To(MatchError("packet payload (500 bytes) is smaller than the expected payload length (1000 bytes)")) + }) + + It("cuts packets at the Payload Length", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + packetHandler := NewMockPacketHandler(mockCtrl) + packetHandler.EXPECT().GetVersion().Return(versionIETFFrames) + packetHandler.EXPECT().GetPerspective().Return(protocol.PerspectiveClient) + handler.Add(connID, packetHandler) + packetHandler.EXPECT().handlePacket(gomock.Any()).Do(func(p *receivedPacket) { + Expect(p.data).To(HaveLen(456)) + }) + + hdr := &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeHandshake, + PayloadLen: 456, + DestConnectionID: connID, + PacketNumberLen: protocol.PacketNumberLen1, + Version: versionIETFFrames, + } + buf := &bytes.Buffer{} + Expect(hdr.Write(buf, protocol.PerspectiveServer, versionIETFFrames)).To(Succeed()) + buf.Write(bytes.Repeat([]byte{0}, 500)) + err := handler.handlePacket(nil, buf.Bytes()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("closes the packet handlers when reading from the conn fails", func() { + done := make(chan struct{}) + packetHandler := NewMockPacketHandler(mockCtrl) + packetHandler.EXPECT().destroy(gomock.Any()).Do(func(e error) { + Expect(e).To(HaveOccurred()) + close(done) + }) + handler.Add(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, packetHandler) + conn.Close() + Eventually(done).Should(BeClosed()) + }) + }) + + Context("running a server", func() { + It("adds a server", func() { + connID := protocol.ConnectionID{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} + p := getPacket(connID) + server := NewMockUnknownPacketHandler(mockCtrl) + server.EXPECT().handlePacket(gomock.Any()).Do(func(p *receivedPacket) { + Expect(p.header.DestConnectionID).To(Equal(connID)) + }) + handler.SetServer(server) + Expect(handler.handlePacket(nil, p)).To(Succeed()) + }) + + It("closes all server sessions", func() { + clientSess := NewMockPacketHandler(mockCtrl) + clientSess.EXPECT().GetPerspective().Return(protocol.PerspectiveClient) + serverSess := NewMockPacketHandler(mockCtrl) + serverSess.EXPECT().GetPerspective().Return(protocol.PerspectiveServer) + serverSess.EXPECT().Close() + + handler.Add(protocol.ConnectionID{1, 1, 1, 1}, clientSess) + handler.Add(protocol.ConnectionID{2, 2, 2, 2}, serverSess) + handler.CloseServer() + }) + + It("stops handling packets with unknown connection IDs after the server is closed", func() { + connID := protocol.ConnectionID{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} + p := getPacket(connID) + server := NewMockUnknownPacketHandler(mockCtrl) + handler.SetServer(server) + handler.CloseServer() + Expect(handler.handlePacket(nil, p)).To(MatchError("received a packet with an unexpected connection ID 0x1122334455667788")) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/packet_number_generator.go b/vendor/lucas-clemente/quic-go/packet_number_generator.go new file mode 100644 index 00000000..ac635776 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_number_generator.go @@ -0,0 +1,69 @@ +package quic + +import ( + "crypto/rand" + "math" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// The packetNumberGenerator generates the packet number for the next packet +// it randomly skips a packet number every averagePeriod packets (on average) +// it is guarantued to never skip two consecutive packet numbers +type packetNumberGenerator struct { + averagePeriod protocol.PacketNumber + + next protocol.PacketNumber + nextToSkip protocol.PacketNumber +} + +func newPacketNumberGenerator(initial, averagePeriod protocol.PacketNumber) *packetNumberGenerator { + return &packetNumberGenerator{ + next: initial, + averagePeriod: averagePeriod, + } +} + +func (p *packetNumberGenerator) Peek() protocol.PacketNumber { + return p.next +} + +func (p *packetNumberGenerator) Pop() protocol.PacketNumber { + next := p.next + + // generate a new packet number for the next packet + p.next++ + + if p.next == p.nextToSkip { + p.next++ + p.generateNewSkip() + } + + return next +} + +func (p *packetNumberGenerator) generateNewSkip() error { + num, err := p.getRandomNumber() + if err != nil { + return err + } + + skip := protocol.PacketNumber(num) * (p.averagePeriod - 1) / (math.MaxUint16 / 2) + // make sure that there are never two consecutive packet numbers that are skipped + p.nextToSkip = p.next + 2 + skip + + return nil +} + +// getRandomNumber() generates a cryptographically secure random number between 0 and MaxUint16 (= 65535) +// The expectation value is 65535/2 +func (p *packetNumberGenerator) getRandomNumber() (uint16, error) { + b := make([]byte, 2) + _, err := rand.Read(b) + if err != nil { + return 0, err + } + + num := uint16(b[0])<<8 + uint16(b[1]) + return num, nil +} diff --git a/vendor/lucas-clemente/quic-go/packet_number_generator_test.go b/vendor/lucas-clemente/quic-go/packet_number_generator_test.go new file mode 100644 index 00000000..ece74a96 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_number_generator_test.go @@ -0,0 +1,87 @@ +package quic + +import ( + "math" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Packet Number Generator", func() { + var png packetNumberGenerator + + BeforeEach(func() { + png = *newPacketNumberGenerator(1, 100) + }) + + It("can be initialized to return any first packet number", func() { + png = *newPacketNumberGenerator(12345, 100) + Expect(png.Pop()).To(Equal(protocol.PacketNumber(12345))) + }) + + It("gets 1 as the first packet number", func() { + num := png.Pop() + Expect(num).To(Equal(protocol.PacketNumber(1))) + }) + + It("allows peeking", func() { + png.nextToSkip = 1000 + Expect(png.Peek()).To(Equal(protocol.PacketNumber(1))) + Expect(png.Peek()).To(Equal(protocol.PacketNumber(1))) + num := png.Pop() + Expect(num).To(Equal(protocol.PacketNumber(1))) + Expect(png.Peek()).To(Equal(protocol.PacketNumber(2))) + Expect(png.Peek()).To(Equal(protocol.PacketNumber(2))) + }) + + It("skips a packet number", func() { + png.nextToSkip = 2 + num := png.Pop() + Expect(num).To(Equal(protocol.PacketNumber(1))) + Expect(png.Peek()).To(Equal(protocol.PacketNumber(3))) + num = png.Pop() + Expect(num).To(Equal(protocol.PacketNumber(3))) + }) + + It("generates a new packet number to skip", func() { + png.next = 100 + png.averagePeriod = 100 + + rep := 5000 + var sum protocol.PacketNumber + + for i := 0; i < rep; i++ { + png.generateNewSkip() + Expect(png.nextToSkip).ToNot(Equal(protocol.PacketNumber(101))) + sum += png.nextToSkip + } + + average := sum / protocol.PacketNumber(rep) + Expect(average).To(BeNumerically("==", protocol.PacketNumber(200), 4)) + }) + + It("uses random numbers", func() { + var smallest uint16 = math.MaxUint16 + var largest uint16 + var sum uint64 + + rep := 10000 + + for i := 0; i < rep; i++ { + num, err := png.getRandomNumber() + Expect(err).ToNot(HaveOccurred()) + sum += uint64(num) + if num > largest { + largest = num + } + if num < smallest { + smallest = num + } + } + + Expect(smallest).To(BeNumerically("<", 300)) + Expect(largest).To(BeNumerically(">", math.MaxUint16-300)) + Expect(sum / uint64(rep)).To(BeNumerically("==", uint64(math.MaxUint16/2), 1000)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/packet_packer.go b/vendor/lucas-clemente/quic-go/packet_packer.go new file mode 100644 index 00000000..9b2cccd5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_packer.go @@ -0,0 +1,576 @@ +package quic + +import ( + "bytes" + "errors" + "fmt" + "net" + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/ackhandler" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type packedPacket struct { + header *wire.Header + raw []byte + frames []wire.Frame + encryptionLevel protocol.EncryptionLevel +} + +func (p *packedPacket) ToAckHandlerPacket() *ackhandler.Packet { + return &ackhandler.Packet{ + PacketNumber: p.header.PacketNumber, + PacketType: p.header.Type, + Frames: p.frames, + Length: protocol.ByteCount(len(p.raw)), + EncryptionLevel: p.encryptionLevel, + SendTime: time.Now(), + } +} + +type sealingManager interface { + GetSealer() (protocol.EncryptionLevel, handshake.Sealer) + GetSealerForCryptoStream() (protocol.EncryptionLevel, handshake.Sealer) + GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (handshake.Sealer, error) +} + +type streamFrameSource interface { + HasCryptoStreamData() bool + PopCryptoStreamFrame(protocol.ByteCount) *wire.StreamFrame + PopStreamFrames(protocol.ByteCount) []*wire.StreamFrame +} + +type packetPacker struct { + destConnID protocol.ConnectionID + srcConnID protocol.ConnectionID + + perspective protocol.Perspective + version protocol.VersionNumber + cryptoSetup sealingManager + + token []byte + divNonce []byte + + packetNumberGenerator *packetNumberGenerator + getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen + streams streamFrameSource + + controlFrameMutex sync.Mutex + controlFrames []wire.Frame + + stopWaiting *wire.StopWaitingFrame + ackFrame *wire.AckFrame + omitConnectionID bool + maxPacketSize protocol.ByteCount + hasSentPacket bool // has the packetPacker already sent a packet + numNonRetransmittableAcks int +} + +func newPacketPacker( + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, + initialPacketNumber protocol.PacketNumber, + getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen, + remoteAddr net.Addr, // only used for determining the max packet size + token []byte, + divNonce []byte, + cryptoSetup sealingManager, + streamFramer streamFrameSource, + perspective protocol.Perspective, + version protocol.VersionNumber, +) *packetPacker { + maxPacketSize := protocol.ByteCount(protocol.MinInitialPacketSize) + // If this is not a UDP address, we don't know anything about the MTU. + // Use the minimum size of an Initial packet as the max packet size. + if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok { + // If ip is not an IPv4 address, To4 returns nil. + // Note that there might be some corner cases, where this is not correct. + // See https://stackoverflow.com/questions/22751035/golang-distinguish-ipv4-ipv6. + if udpAddr.IP.To4() == nil { + maxPacketSize = protocol.MaxPacketSizeIPv6 + } else { + maxPacketSize = protocol.MaxPacketSizeIPv4 + } + } + return &packetPacker{ + cryptoSetup: cryptoSetup, + divNonce: divNonce, + token: token, + destConnID: destConnID, + srcConnID: srcConnID, + perspective: perspective, + version: version, + streams: streamFramer, + getPacketNumberLen: getPacketNumberLen, + packetNumberGenerator: newPacketNumberGenerator(initialPacketNumber, protocol.SkipPacketAveragePeriodLength), + maxPacketSize: maxPacketSize, + } +} + +// PackConnectionClose packs a packet that ONLY contains a ConnectionCloseFrame +func (p *packetPacker) PackConnectionClose(ccf *wire.ConnectionCloseFrame) (*packedPacket, error) { + frames := []wire.Frame{ccf} + encLevel, sealer := p.cryptoSetup.GetSealer() + header := p.getHeader(encLevel) + raw, err := p.writeAndSealPacket(header, frames, sealer) + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }, err +} + +func (p *packetPacker) PackAckPacket() (*packedPacket, error) { + if p.ackFrame == nil { + return nil, errors.New("packet packer BUG: no ack frame queued") + } + encLevel, sealer := p.cryptoSetup.GetSealer() + header := p.getHeader(encLevel) + frames := []wire.Frame{p.ackFrame} + if p.stopWaiting != nil { // a STOP_WAITING will only be queued when using gQUIC + p.stopWaiting.PacketNumber = header.PacketNumber + p.stopWaiting.PacketNumberLen = header.PacketNumberLen + frames = append(frames, p.stopWaiting) + p.stopWaiting = nil + } + p.ackFrame = nil + raw, err := p.writeAndSealPacket(header, frames, sealer) + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }, err +} + +// PackRetransmission packs a retransmission +// For packets sent after completion of the handshake, it might happen that 2 packets have to be sent. +// This can happen e.g. when a longer packet number is used in the header. +func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedPacket, error) { + if packet.EncryptionLevel != protocol.EncryptionForwardSecure { + p, err := p.packHandshakeRetransmission(packet) + return []*packedPacket{p}, err + } + + var controlFrames []wire.Frame + var streamFrames []*wire.StreamFrame + for _, f := range packet.Frames { + if sf, ok := f.(*wire.StreamFrame); ok { + sf.DataLenPresent = true + streamFrames = append(streamFrames, sf) + } else { + controlFrames = append(controlFrames, f) + } + } + + var packets []*packedPacket + encLevel, sealer := p.cryptoSetup.GetSealer() + for len(controlFrames) > 0 || len(streamFrames) > 0 { + var frames []wire.Frame + var payloadLength protocol.ByteCount + + header := p.getHeader(encLevel) + headerLength, err := header.GetLength(p.version) + if err != nil { + return nil, err + } + maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength + + // for gQUIC: add a STOP_WAITING for *every* retransmission + if p.version.UsesStopWaitingFrames() { + if p.stopWaiting == nil { + return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame") + } + // create a new StopWaitingFrame, since we might need to send more than one packet as a retransmission + swf := &wire.StopWaitingFrame{ + LeastUnacked: p.stopWaiting.LeastUnacked, + PacketNumber: header.PacketNumber, + PacketNumberLen: header.PacketNumberLen, + } + payloadLength += swf.Length(p.version) + frames = append(frames, swf) + } + + for len(controlFrames) > 0 { + frame := controlFrames[0] + length := frame.Length(p.version) + if payloadLength+length > maxSize { + break + } + payloadLength += length + frames = append(frames, frame) + controlFrames = controlFrames[1:] + } + + // temporarily increase the maxFrameSize by the (minimum) length of the DataLen field + // this leads to a properly sized packet in all cases, since we do all the packet length calculations with StreamFrames that have the DataLen set + // however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size + // for gQUIC STREAM frames, DataLen is always 2 bytes + // for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes + if p.version.UsesIETFFrameFormat() { + maxSize++ + } else { + maxSize += 2 + } + for len(streamFrames) > 0 && payloadLength+protocol.MinStreamFrameSize < maxSize { + // TODO: optimize by setting DataLenPresent = false on all but the last STREAM frame + frame := streamFrames[0] + frameToAdd := frame + + sf, err := frame.MaybeSplitOffFrame(maxSize-payloadLength, p.version) + if err != nil { + return nil, err + } + if sf != nil { + frameToAdd = sf + } else { + streamFrames = streamFrames[1:] + } + payloadLength += frameToAdd.Length(p.version) + frames = append(frames, frameToAdd) + } + if sf, ok := frames[len(frames)-1].(*wire.StreamFrame); ok { + sf.DataLenPresent = false + } + raw, err := p.writeAndSealPacket(header, frames, sealer) + if err != nil { + return nil, err + } + packets = append(packets, &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }) + } + p.stopWaiting = nil + return packets, nil +} + +// packHandshakeRetransmission retransmits a handshake packet, that was sent with less than forward-secure encryption +func (p *packetPacker) packHandshakeRetransmission(packet *ackhandler.Packet) (*packedPacket, error) { + sealer, err := p.cryptoSetup.GetSealerWithEncryptionLevel(packet.EncryptionLevel) + if err != nil { + return nil, err + } + // make sure that the retransmission for an Initial packet is sent as an Initial packet + if packet.PacketType == protocol.PacketTypeInitial { + p.hasSentPacket = false + } + header := p.getHeader(packet.EncryptionLevel) + header.Type = packet.PacketType + var frames []wire.Frame + if p.version.UsesStopWaitingFrames() { // for gQUIC: pack a STOP_WAITING first + if p.stopWaiting == nil { + return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame") + } + swf := p.stopWaiting + swf.PacketNumber = header.PacketNumber + swf.PacketNumberLen = header.PacketNumberLen + p.stopWaiting = nil + frames = append([]wire.Frame{swf}, packet.Frames...) + } else { + frames = packet.Frames + } + raw, err := p.writeAndSealPacket(header, frames, sealer) + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: packet.EncryptionLevel, + }, err +} + +// PackPacket packs a new packet +// the other controlFrames are sent in the next packet, but might be queued and sent in the next packet if the packet would overflow MaxPacketSize otherwise +func (p *packetPacker) PackPacket() (*packedPacket, error) { + hasCryptoStreamFrame := p.streams.HasCryptoStreamData() + // if this is the first packet to be send, make sure it contains stream data + if !p.hasSentPacket && !hasCryptoStreamFrame { + return nil, nil + } + if hasCryptoStreamFrame { + return p.packCryptoPacket() + } + + encLevel, sealer := p.cryptoSetup.GetSealer() + + header := p.getHeader(encLevel) + headerLength, err := header.GetLength(p.version) + if err != nil { + return nil, err + } + if p.stopWaiting != nil { + p.stopWaiting.PacketNumber = header.PacketNumber + p.stopWaiting.PacketNumberLen = header.PacketNumberLen + } + + maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength + payloadFrames, err := p.composeNextPacket(maxSize, p.canSendData(encLevel)) + if err != nil { + return nil, err + } + + // Check if we have enough frames to send + if len(payloadFrames) == 0 { + return nil, nil + } + // Don't send out packets that only contain a StopWaitingFrame + if len(payloadFrames) == 1 && p.stopWaiting != nil { + return nil, nil + } + if p.ackFrame != nil { + // check if this packet only contains an ACK (and maybe a STOP_WAITING) + if len(payloadFrames) == 1 || (p.stopWaiting != nil && len(payloadFrames) == 2) { + if p.numNonRetransmittableAcks >= protocol.MaxNonRetransmittableAcks { + payloadFrames = append(payloadFrames, &wire.PingFrame{}) + p.numNonRetransmittableAcks = 0 + } else { + p.numNonRetransmittableAcks++ + } + } else { + p.numNonRetransmittableAcks = 0 + } + } + p.stopWaiting = nil + p.ackFrame = nil + + raw, err := p.writeAndSealPacket(header, payloadFrames, sealer) + if err != nil { + return nil, err + } + return &packedPacket{ + header: header, + raw: raw, + frames: payloadFrames, + encryptionLevel: encLevel, + }, nil +} + +func (p *packetPacker) packCryptoPacket() (*packedPacket, error) { + encLevel, sealer := p.cryptoSetup.GetSealerForCryptoStream() + header := p.getHeader(encLevel) + headerLength, err := header.GetLength(p.version) + if err != nil { + return nil, err + } + maxLen := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - protocol.NonForwardSecurePacketSizeReduction - headerLength + sf := p.streams.PopCryptoStreamFrame(maxLen) + sf.DataLenPresent = false + frames := []wire.Frame{sf} + raw, err := p.writeAndSealPacket(header, frames, sealer) + if err != nil { + return nil, err + } + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }, nil +} + +func (p *packetPacker) composeNextPacket( + maxFrameSize protocol.ByteCount, + canSendStreamFrames bool, +) ([]wire.Frame, error) { + var payloadLength protocol.ByteCount + var payloadFrames []wire.Frame + + // STOP_WAITING and ACK will always fit + if p.ackFrame != nil { // ACKs need to go first, so that the sentPacketHandler will recognize them + payloadFrames = append(payloadFrames, p.ackFrame) + l := p.ackFrame.Length(p.version) + payloadLength += l + } + if p.stopWaiting != nil { // a STOP_WAITING will only be queued when using gQUIC + payloadFrames = append(payloadFrames, p.stopWaiting) + payloadLength += p.stopWaiting.Length(p.version) + } + + p.controlFrameMutex.Lock() + for len(p.controlFrames) > 0 { + frame := p.controlFrames[len(p.controlFrames)-1] + length := frame.Length(p.version) + if payloadLength+length > maxFrameSize { + break + } + payloadFrames = append(payloadFrames, frame) + payloadLength += length + p.controlFrames = p.controlFrames[:len(p.controlFrames)-1] + } + p.controlFrameMutex.Unlock() + + if payloadLength > maxFrameSize { + return nil, fmt.Errorf("Packet Packer BUG: packet payload (%d) too large (%d)", payloadLength, maxFrameSize) + } + + if !canSendStreamFrames { + return payloadFrames, nil + } + + // temporarily increase the maxFrameSize by the (minimum) length of the DataLen field + // this leads to a properly sized packet in all cases, since we do all the packet length calculations with StreamFrames that have the DataLen set + // however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size + // for gQUIC STREAM frames, DataLen is always 2 bytes + // for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes + if p.version.UsesIETFFrameFormat() { + maxFrameSize++ + } else { + maxFrameSize += 2 + } + + fs := p.streams.PopStreamFrames(maxFrameSize - payloadLength) + if len(fs) != 0 { + fs[len(fs)-1].DataLenPresent = false + } + + for _, f := range fs { + payloadFrames = append(payloadFrames, f) + } + return payloadFrames, nil +} + +func (p *packetPacker) QueueControlFrame(frame wire.Frame) { + switch f := frame.(type) { + case *wire.StopWaitingFrame: + p.stopWaiting = f + case *wire.AckFrame: + p.ackFrame = f + default: + p.controlFrameMutex.Lock() + p.controlFrames = append(p.controlFrames, f) + p.controlFrameMutex.Unlock() + } +} + +func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Header { + pnum := p.packetNumberGenerator.Peek() + packetNumberLen := p.getPacketNumberLen(pnum) + + header := &wire.Header{ + PacketNumber: pnum, + PacketNumberLen: packetNumberLen, + Version: p.version, + } + + if p.version.UsesIETFHeaderFormat() && encLevel != protocol.EncryptionForwardSecure { + header.IsLongHeader = true + header.SrcConnectionID = p.srcConnID + if !p.version.UsesVarintPacketNumbers() { + header.PacketNumberLen = protocol.PacketNumberLen4 + } + // Set the payload len to maximum size. + // Since it is encoded as a varint, this guarantees us that the header will end up at most as big as GetLength() returns. + header.PayloadLen = p.maxPacketSize + if !p.hasSentPacket && p.perspective == protocol.PerspectiveClient { + header.Type = protocol.PacketTypeInitial + header.Token = p.token + } else { + header.Type = protocol.PacketTypeHandshake + } + } + + if !p.omitConnectionID || encLevel != protocol.EncryptionForwardSecure { + header.DestConnectionID = p.destConnID + } + if !p.version.UsesTLS() { + if p.perspective == protocol.PerspectiveServer && encLevel == protocol.EncryptionSecure { + header.Type = protocol.PacketType0RTT + header.DiversificationNonce = p.divNonce + } + if p.perspective == protocol.PerspectiveClient && encLevel != protocol.EncryptionForwardSecure { + header.VersionFlag = true + } + } + return header +} + +func (p *packetPacker) writeAndSealPacket( + header *wire.Header, + payloadFrames []wire.Frame, + sealer handshake.Sealer, +) ([]byte, error) { + raw := *getPacketBuffer() + buffer := bytes.NewBuffer(raw[:0]) + + // the payload length is only needed for Long Headers + if header.IsLongHeader { + if header.Type == protocol.PacketTypeInitial { + headerLen, _ := header.GetLength(p.version) + header.PayloadLen = protocol.ByteCount(protocol.MinInitialPacketSize) - headerLen + } else { + payloadLen := protocol.ByteCount(sealer.Overhead()) + for _, frame := range payloadFrames { + payloadLen += frame.Length(p.version) + } + header.PayloadLen = payloadLen + } + } + + if err := header.Write(buffer, p.perspective, p.version); err != nil { + return nil, err + } + payloadStartIndex := buffer.Len() + + // the Initial packet needs to be padded, so the last STREAM frame must have the data length present + if header.Type == protocol.PacketTypeInitial { + lastFrame := payloadFrames[len(payloadFrames)-1] + if sf, ok := lastFrame.(*wire.StreamFrame); ok { + sf.DataLenPresent = true + } + } + for _, frame := range payloadFrames { + if err := frame.Write(buffer, p.version); err != nil { + return nil, err + } + } + // if this is an IETF QUIC Initial packet, we need to pad it to fulfill the minimum size requirement + // in gQUIC, padding is handled in the CHLO + if header.Type == protocol.PacketTypeInitial { + paddingLen := protocol.MinInitialPacketSize - sealer.Overhead() - buffer.Len() + if paddingLen > 0 { + buffer.Write(bytes.Repeat([]byte{0}, paddingLen)) + } + } + + if size := protocol.ByteCount(buffer.Len() + sealer.Overhead()); size > p.maxPacketSize { + return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, p.maxPacketSize) + } + + raw = raw[0:buffer.Len()] + _ = sealer.Seal(raw[payloadStartIndex:payloadStartIndex], raw[payloadStartIndex:], header.PacketNumber, raw[:payloadStartIndex]) + raw = raw[0 : buffer.Len()+sealer.Overhead()] + + num := p.packetNumberGenerator.Pop() + if num != header.PacketNumber { + return nil, errors.New("packetPacker BUG: Peeked and Popped packet numbers do not match") + } + p.hasSentPacket = true + return raw, nil +} + +func (p *packetPacker) canSendData(encLevel protocol.EncryptionLevel) bool { + if p.perspective == protocol.PerspectiveClient { + return encLevel >= protocol.EncryptionSecure + } + return encLevel == protocol.EncryptionForwardSecure +} + +func (p *packetPacker) SetOmitConnectionID() { + p.omitConnectionID = true +} + +func (p *packetPacker) ChangeDestConnectionID(connID protocol.ConnectionID) { + p.destConnID = connID +} + +func (p *packetPacker) SetMaxPacketSize(size protocol.ByteCount) { + p.maxPacketSize = utils.MinByteCount(p.maxPacketSize, size) +} diff --git a/vendor/lucas-clemente/quic-go/packet_packer_test.go b/vendor/lucas-clemente/quic-go/packet_packer_test.go new file mode 100644 index 00000000..ae40aa2e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_packer_test.go @@ -0,0 +1,1079 @@ +package quic + +import ( + "bytes" + "net" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/ackhandler" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockSealer struct{} + +func (s *mockSealer) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte { + return append(src, bytes.Repeat([]byte{0}, 12)...) +} + +func (s *mockSealer) Overhead() int { return 12 } + +var _ handshake.Sealer = &mockSealer{} + +type mockCryptoSetup struct { + handleErr error + encLevelSeal protocol.EncryptionLevel + encLevelSealCrypto protocol.EncryptionLevel + divNonce []byte +} + +var _ handshake.CryptoSetup = &mockCryptoSetup{} + +func (m *mockCryptoSetup) HandleCryptoStream() error { + return m.handleErr +} +func (m *mockCryptoSetup) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) { + return nil, protocol.EncryptionUnspecified, nil +} +func (m *mockCryptoSetup) GetSealer() (protocol.EncryptionLevel, handshake.Sealer) { + return m.encLevelSeal, &mockSealer{} +} +func (m *mockCryptoSetup) GetSealerForCryptoStream() (protocol.EncryptionLevel, handshake.Sealer) { + return m.encLevelSealCrypto, &mockSealer{} +} +func (m *mockCryptoSetup) GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (handshake.Sealer, error) { + return &mockSealer{}, nil +} +func (m *mockCryptoSetup) SetDiversificationNonce(divNonce []byte) error { + m.divNonce = divNonce + return nil +} +func (m *mockCryptoSetup) ConnectionState() ConnectionState { panic("not implemented") } + +var _ = Describe("Packet packer", func() { + const maxPacketSize protocol.ByteCount = 1357 + var ( + packer *packetPacker + publicHeaderLen protocol.ByteCount + maxFrameSize protocol.ByteCount + mockStreamFramer *MockStreamFrameSource + divNonce []byte + token []byte + ) + + checkPayloadLen := func(data []byte) { + r := bytes.NewReader(data) + iHdr, err := wire.ParseInvariantHeader(r, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(r, protocol.PerspectiveServer, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + ExpectWithOffset(0, hdr.PayloadLen).To(BeEquivalentTo(r.Len())) + } + + BeforeEach(func() { + version := versionGQUICFrames + mockSender := NewMockStreamSender(mockCtrl) + mockSender.EXPECT().onHasStreamData(gomock.Any()).AnyTimes() + mockStreamFramer = NewMockStreamFrameSource(mockCtrl) + divNonce = bytes.Repeat([]byte{'e'}, 32) + token = []byte("initial token") + + packer = newPacketPacker( + protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + 1, + func(protocol.PacketNumber) protocol.PacketNumberLen { return protocol.PacketNumberLen2 }, + &net.TCPAddr{}, + token, // token + divNonce, + &mockCryptoSetup{encLevelSeal: protocol.EncryptionForwardSecure}, + mockStreamFramer, + protocol.PerspectiveServer, + version, + ) + publicHeaderLen = 1 + 8 + 2 // 1 flag byte, 8 connection ID, 2 packet number + maxFrameSize = maxPacketSize - protocol.ByteCount((&mockSealer{}).Overhead()) - publicHeaderLen + packer.hasSentPacket = true + packer.version = version + packer.maxPacketSize = maxPacketSize + }) + + Context("determining the maximum packet size", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + + It("uses the minimum initial size, if it can't determine if the remote address is IPv4 or IPv6", func() { + remoteAddr := &net.TCPAddr{} + packer = newPacketPacker(connID, connID, 1, nil, remoteAddr, nil, nil, nil, nil, protocol.PerspectiveServer, protocol.VersionWhatever) + Expect(packer.maxPacketSize).To(BeEquivalentTo(protocol.MinInitialPacketSize)) + }) + + It("uses the maximum IPv4 packet size, if the remote address is IPv4", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(11, 12, 13, 14), Port: 1337} + packer = newPacketPacker(connID, connID, 1, nil, remoteAddr, nil, nil, nil, nil, protocol.PerspectiveServer, protocol.VersionWhatever) + Expect(packer.maxPacketSize).To(BeEquivalentTo(protocol.MaxPacketSizeIPv4)) + }) + + It("uses the maximum IPv6 packet size, if the remote address is IPv6", func() { + ip := net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334") + remoteAddr := &net.UDPAddr{IP: ip, Port: 1337} + packer = newPacketPacker(connID, connID, 1, nil, remoteAddr, nil, nil, nil, nil, protocol.PerspectiveServer, protocol.VersionWhatever) + Expect(packer.maxPacketSize).To(BeEquivalentTo(protocol.MaxPacketSizeIPv6)) + }) + }) + + It("returns nil when no packet is queued", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + p, err := packer.PackPacket() + Expect(p).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("packs single packets", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + f := &wire.StreamFrame{ + StreamID: 5, + Data: []byte{0xDE, 0xCA, 0xFB, 0xAD}, + } + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Return([]*wire.StreamFrame{f}) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).ToNot(BeNil()) + b := &bytes.Buffer{} + f.Write(b, packer.version) + Expect(p.frames).To(Equal([]wire.Frame{f})) + Expect(p.raw).To(ContainSubstring(b.String())) + }) + + It("stores the encryption level a packet was sealed with", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Return([]*wire.StreamFrame{{ + StreamID: 5, + Data: []byte("foobar"), + }}) + packer.cryptoSetup.(*mockCryptoSetup).encLevelSeal = protocol.EncryptionForwardSecure + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.encryptionLevel).To(Equal(protocol.EncryptionForwardSecure)) + }) + + Context("generating a packet header", func() { + const ( + versionPublicHeader = protocol.Version39 // a QUIC version that uses the Public Header format + versionIETFHeader = protocol.VersionTLS // a QUIC version that uses the IETF Header format + ) + + Context("Public Header (for gQUIC)", func() { + BeforeEach(func() { + packer.version = versionPublicHeader + }) + + It("doesn't set the source connection ID", func() { + ph := packer.getHeader(protocol.EncryptionForwardSecure) + Expect(ph.SrcConnectionID).To(BeEmpty()) + }) + + It("it omits the connection ID for forward-secure packets", func() { + packer.version = protocol.Version43 + ph := packer.getHeader(protocol.EncryptionForwardSecure) + Expect(ph.DestConnectionID.Len()).ToNot(BeZero()) + packer.SetOmitConnectionID() + ph = packer.getHeader(protocol.EncryptionForwardSecure) + Expect(ph.DestConnectionID.Len()).To(BeZero()) + }) + + It("doesn't omit the connection ID for non-forward-secure packets", func() { + packer.SetOmitConnectionID() + ph := packer.getHeader(protocol.EncryptionSecure) + Expect(ph.DestConnectionID.Len()).ToNot(BeZero()) + }) + + It("adds the Version Flag to the Public Header before the crypto handshake is finished", func() { + packer.perspective = protocol.PerspectiveClient + ph := packer.getHeader(protocol.EncryptionSecure) + Expect(ph.VersionFlag).To(BeTrue()) + }) + + It("doesn't add the Version Flag to the Public Header for forward-secure packets", func() { + packer.perspective = protocol.PerspectiveClient + ph := packer.getHeader(protocol.EncryptionForwardSecure) + Expect(ph.VersionFlag).To(BeFalse()) + }) + + Context("diversificaton nonces", func() { + It("doesn't include a div nonce, when sending a packet with initial encryption", func() { + ph := packer.getHeader(protocol.EncryptionUnencrypted) + Expect(ph.DiversificationNonce).To(BeEmpty()) + }) + + It("includes a div nonce, when sending a packet with secure encryption", func() { + ph := packer.getHeader(protocol.EncryptionSecure) + Expect(ph.DiversificationNonce).To(Equal(divNonce)) + }) + + It("doesn't include a div nonce, when sending a packet with forward-secure encryption", func() { + ph := packer.getHeader(protocol.EncryptionForwardSecure) + Expect(ph.DiversificationNonce).To(BeEmpty()) + }) + + It("doesn't send a div nonce as a client", func() { + packer.perspective = protocol.PerspectiveClient + ph := packer.getHeader(protocol.EncryptionSecure) + Expect(ph.DiversificationNonce).To(BeEmpty()) + }) + }) + }) + + Context("Header (for gQUIC 44)", func() { + BeforeEach(func() { + packer.version = protocol.Version44 + }) + + It("sends an Initial packet as the first packets, for the client", func() { + packer.perspective = protocol.PerspectiveClient + packer.hasSentPacket = false + h := packer.getHeader(protocol.EncryptionUnencrypted) + Expect(h.IsLongHeader).To(BeTrue()) + Expect(h.Type).To(Equal(protocol.PacketTypeInitial)) + Expect(h.Version).To(Equal(protocol.Version44)) + Expect(h.DestConnectionID).To(Equal(packer.destConnID)) + Expect(h.SrcConnectionID).To(Equal(packer.srcConnID)) + Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + }) + + It("sends a Handshake for non-forward-secure packets, for the server", func() { + packer.perspective = protocol.PerspectiveServer + h := packer.getHeader(protocol.EncryptionUnencrypted) + Expect(h.IsLongHeader).To(BeTrue()) + Expect(h.Type).To(Equal(protocol.PacketTypeHandshake)) + Expect(h.Version).To(Equal(protocol.Version44)) + Expect(h.DestConnectionID).To(Equal(packer.destConnID)) + Expect(h.SrcConnectionID).To(Equal(packer.srcConnID)) + Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen4)) + }) + + It("sets the Diversification Nonce for secure packets", func() { + packer.perspective = protocol.PerspectiveServer + Expect(divNonce).ToNot(BeEmpty()) + h := packer.getHeader(protocol.EncryptionSecure) + Expect(h.IsLongHeader).To(BeTrue()) + Expect(h.Version).To(Equal(protocol.Version44)) + Expect(h.Type).To(Equal(protocol.PacketType0RTT)) + Expect(h.DiversificationNonce).To(Equal(divNonce)) + }) + + It("uses the Short Header for forward-secure packets", func() { + h := packer.getHeader(protocol.EncryptionForwardSecure) + Expect(h.IsLongHeader).To(BeFalse()) + Expect(h.IsPublicHeader).To(BeFalse()) + Expect(h.DestConnectionID).To(Equal(packer.destConnID)) + }) + }) + + Context("Header (for IETF draft QUIC)", func() { + BeforeEach(func() { + packer.version = versionIETFHeader + }) + + It("uses the Long Header format for non-forward-secure packets", func() { + h := packer.getHeader(protocol.EncryptionSecure) + Expect(h.IsLongHeader).To(BeTrue()) + Expect(h.Version).To(Equal(versionIETFHeader)) + }) + + It("sets source and destination connection ID", func() { + srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + destConnID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + packer.srcConnID = srcConnID + packer.destConnID = destConnID + h := packer.getHeader(protocol.EncryptionSecure) + Expect(h.SrcConnectionID).To(Equal(srcConnID)) + Expect(h.DestConnectionID).To(Equal(destConnID)) + }) + + It("changes the destination connection ID", func() { + srcConnID := protocol.ConnectionID{1, 1, 1, 1, 1, 1, 1, 1} + packer.srcConnID = srcConnID + dest1 := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + dest2 := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + packer.ChangeDestConnectionID(dest1) + h := packer.getHeader(protocol.EncryptionUnencrypted) + Expect(h.SrcConnectionID).To(Equal(srcConnID)) + Expect(h.DestConnectionID).To(Equal(dest1)) + packer.ChangeDestConnectionID(dest2) + h = packer.getHeader(protocol.EncryptionUnencrypted) + Expect(h.SrcConnectionID).To(Equal(srcConnID)) + Expect(h.DestConnectionID).To(Equal(dest2)) + }) + + It("uses the Short Header format for forward-secure packets", func() { + h := packer.getHeader(protocol.EncryptionForwardSecure) + Expect(h.IsLongHeader).To(BeFalse()) + Expect(h.PacketNumberLen).To(BeNumerically(">", 0)) + }) + }) + }) + + It("sets the payload length for packets containing crypto data", func() { + packer.version = versionIETFFrames + f := &wire.StreamFrame{ + StreamID: packer.version.CryptoStreamID(), + Offset: 0x1337, + Data: []byte("foobar"), + } + mockStreamFramer.EXPECT().HasCryptoStreamData().Return(true) + mockStreamFramer.EXPECT().PopCryptoStreamFrame(gomock.Any()).Return(f) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + checkPayloadLen(p.raw) + }) + + It("packs a CONNECTION_CLOSE", func() { + ccf := wire.ConnectionCloseFrame{ + ErrorCode: 0x1337, + ReasonPhrase: "foobar", + } + p, err := packer.PackConnectionClose(&ccf) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(1)) + Expect(p.frames[0]).To(Equal(&ccf)) + }) + + It("doesn't send any other frames when sending a CONNECTION_CLOSE", func() { + // expect no mockStreamFramer.PopStreamFrames + ccf := &wire.ConnectionCloseFrame{ + ErrorCode: 0x1337, + ReasonPhrase: "foobar", + } + packer.controlFrames = []wire.Frame{&wire.MaxStreamDataFrame{StreamID: 37}} + p, err := packer.PackConnectionClose(ccf) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(Equal([]wire.Frame{ccf})) + }) + + It("packs only control frames", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + packer.QueueControlFrame(&wire.RstStreamFrame{}) + packer.QueueControlFrame(&wire.MaxDataFrame{}) + p, err := packer.PackPacket() + Expect(p).ToNot(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(2)) + Expect(p.raw).NotTo(BeEmpty()) + }) + + It("increases the packet number", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData().Times(2) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Times(2) + packer.QueueControlFrame(&wire.RstStreamFrame{}) + p1, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p1).ToNot(BeNil()) + packer.QueueControlFrame(&wire.RstStreamFrame{}) + p2, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p2).ToNot(BeNil()) + Expect(p2.header.PacketNumber).To(BeNumerically(">", p1.header.PacketNumber)) + }) + + It("packs a STOP_WAITING frame first", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + packer.packetNumberGenerator.next = 15 + swf := &wire.StopWaitingFrame{LeastUnacked: 10} + packer.QueueControlFrame(&wire.RstStreamFrame{}) + packer.QueueControlFrame(swf) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).ToNot(BeNil()) + Expect(p.frames).To(HaveLen(2)) + Expect(p.frames[0]).To(Equal(swf)) + }) + + It("sets the LeastUnackedDelta length of a STOP_WAITING frame", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + packer.packetNumberGenerator.next = 0x1337 + swf := &wire.StopWaitingFrame{LeastUnacked: 0x1337 - 0x100} + packer.QueueControlFrame(&wire.RstStreamFrame{}) + packer.QueueControlFrame(swf) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames[0].(*wire.StopWaitingFrame).PacketNumberLen).To(Equal(protocol.PacketNumberLen2)) + }) + + It("does not pack a packet containing only a STOP_WAITING frame", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + swf := &wire.StopWaitingFrame{LeastUnacked: 10} + packer.QueueControlFrame(swf) + p, err := packer.PackPacket() + Expect(p).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("packs a packet if it has queued control frames, but no new control frames", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + packer.controlFrames = []wire.Frame{&wire.BlockedFrame{}} + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).ToNot(BeNil()) + }) + + It("refuses to send a packet that doesn't contain crypto stream data, if it has never sent a packet before", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + packer.hasSentPacket = false + packer.controlFrames = []wire.Frame{&wire.BlockedFrame{}} + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(BeNil()) + }) + + It("packs many control frames into 1 packets", func() { + f := &wire.AckFrame{AckRanges: []wire.AckRange{{Largest: 1, Smallest: 1}}} + b := &bytes.Buffer{} + err := f.Write(b, packer.version) + Expect(err).ToNot(HaveOccurred()) + maxFramesPerPacket := int(maxFrameSize) / b.Len() + var controlFrames []wire.Frame + for i := 0; i < maxFramesPerPacket; i++ { + controlFrames = append(controlFrames, f) + } + packer.controlFrames = controlFrames + payloadFrames, err := packer.composeNextPacket(maxFrameSize, false) + Expect(err).ToNot(HaveOccurred()) + Expect(payloadFrames).To(HaveLen(maxFramesPerPacket)) + payloadFrames, err = packer.composeNextPacket(maxFrameSize, false) + Expect(err).ToNot(HaveOccurred()) + Expect(payloadFrames).To(BeEmpty()) + }) + + It("packs a lot of control frames into 2 packets if they don't fit into one", func() { + blockedFrame := &wire.BlockedFrame{} + maxFramesPerPacket := int(maxFrameSize) / int(blockedFrame.Length(packer.version)) + var controlFrames []wire.Frame + for i := 0; i < maxFramesPerPacket+10; i++ { + controlFrames = append(controlFrames, blockedFrame) + } + packer.controlFrames = controlFrames + payloadFrames, err := packer.composeNextPacket(maxFrameSize, false) + Expect(err).ToNot(HaveOccurred()) + Expect(payloadFrames).To(HaveLen(maxFramesPerPacket)) + payloadFrames, err = packer.composeNextPacket(maxFrameSize, false) + Expect(err).ToNot(HaveOccurred()) + Expect(payloadFrames).To(HaveLen(10)) + }) + + It("only increases the packet number when there is an actual packet to send", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData().Times(2) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + packer.packetNumberGenerator.nextToSkip = 1000 + p, err := packer.PackPacket() + Expect(p).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(packer.packetNumberGenerator.Peek()).To(Equal(protocol.PacketNumber(1))) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Return([]*wire.StreamFrame{{ + StreamID: 5, + Data: []byte{0xDE, 0xCA, 0xFB, 0xAD}, + }}) + p, err = packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).ToNot(BeNil()) + Expect(p.header.PacketNumber).To(Equal(protocol.PacketNumber(1))) + Expect(packer.packetNumberGenerator.Peek()).To(Equal(protocol.PacketNumber(2))) + }) + + Context("making ACK packets retransmittable", func() { + sendMaxNumNonRetransmittableAcks := func() { + mockStreamFramer.EXPECT().HasCryptoStreamData().Times(protocol.MaxNonRetransmittableAcks) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Times(protocol.MaxNonRetransmittableAcks) + for i := 0; i < protocol.MaxNonRetransmittableAcks; i++ { + packer.QueueControlFrame(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}) + p, err := packer.PackPacket() + Expect(p).ToNot(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(1)) + } + } + + It("adds a PING frame when it's supposed to send a retransmittable packet", func() { + sendMaxNumNonRetransmittableAcks() + mockStreamFramer.EXPECT().HasCryptoStreamData().Times(2) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Times(2) + packer.QueueControlFrame(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}) + p, err := packer.PackPacket() + Expect(p).ToNot(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(ContainElement(&wire.PingFrame{})) + // make sure the next packet doesn't contain another PING + packer.QueueControlFrame(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}) + p, err = packer.PackPacket() + Expect(p).ToNot(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(1)) + }) + + It("waits until there's something to send before adding a PING frame", func() { + sendMaxNumNonRetransmittableAcks() + mockStreamFramer.EXPECT().HasCryptoStreamData().Times(2) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Times(2) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(BeNil()) + packer.QueueControlFrame(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}) + p, err = packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(2)) + Expect(p.frames).To(ContainElement(&wire.PingFrame{})) + }) + + It("doesn't send a PING if it already sent another retransmittable frame", func() { + sendMaxNumNonRetransmittableAcks() + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + packer.QueueControlFrame(&wire.MaxDataFrame{}) + packer.QueueControlFrame(&wire.StopWaitingFrame{}) + p, err := packer.PackPacket() + Expect(p).ToNot(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(2)) + Expect(p.frames).ToNot(ContainElement(&wire.PingFrame{})) + }) + }) + + Context("STREAM frame handling", func() { + It("does not splits a STREAM frame with maximum size, for gQUIC frames", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData().Times(2) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).DoAndReturn(func(maxSize protocol.ByteCount) []*wire.StreamFrame { + f := &wire.StreamFrame{ + Offset: 1, + StreamID: 5, + DataLenPresent: true, + } + f.Data = bytes.Repeat([]byte{'f'}, int(maxSize-f.Length(packer.version))) + return []*wire.StreamFrame{f} + }) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(1)) + Expect(p.raw).To(HaveLen(int(maxPacketSize))) + Expect(p.frames[0].(*wire.StreamFrame).DataLenPresent).To(BeFalse()) + p, err = packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(BeNil()) + }) + + It("does not splits a STREAM frame with maximum size, for IETF draft style frame", func() { + packer.version = versionIETFFrames + mockStreamFramer.EXPECT().HasCryptoStreamData().Times(2) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).DoAndReturn(func(maxSize protocol.ByteCount) []*wire.StreamFrame { + f := &wire.StreamFrame{ + Offset: 1, + StreamID: 5, + DataLenPresent: true, + } + f.Data = bytes.Repeat([]byte{'f'}, int(maxSize-f.Length(packer.version))) + return []*wire.StreamFrame{f} + }) + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(1)) + Expect(p.raw).To(HaveLen(int(maxPacketSize))) + Expect(p.frames[0].(*wire.StreamFrame).DataLenPresent).To(BeFalse()) + p, err = packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(BeNil()) + }) + + It("packs multiple small STREAM frames into single packet", func() { + f1 := &wire.StreamFrame{ + StreamID: 5, + Data: []byte("frame 1"), + DataLenPresent: true, + } + f2 := &wire.StreamFrame{ + StreamID: 5, + Data: []byte("frame 2"), + DataLenPresent: true, + } + f3 := &wire.StreamFrame{ + StreamID: 3, + Data: []byte("frame 3"), + DataLenPresent: true, + } + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Return([]*wire.StreamFrame{f1, f2, f3}) + p, err := packer.PackPacket() + Expect(p).ToNot(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(3)) + Expect(p.frames[0].(*wire.StreamFrame).Data).To(Equal([]byte("frame 1"))) + Expect(p.frames[1].(*wire.StreamFrame).Data).To(Equal([]byte("frame 2"))) + Expect(p.frames[2].(*wire.StreamFrame).Data).To(Equal([]byte("frame 3"))) + Expect(p.frames[0].(*wire.StreamFrame).DataLenPresent).To(BeTrue()) + Expect(p.frames[1].(*wire.StreamFrame).DataLenPresent).To(BeTrue()) + Expect(p.frames[2].(*wire.StreamFrame).DataLenPresent).To(BeFalse()) + }) + + It("refuses to send unencrypted stream data on a data stream", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + // don't expect a call to mockStreamFramer.PopStreamFrames + packer.cryptoSetup.(*mockCryptoSetup).encLevelSeal = protocol.EncryptionUnencrypted + p, err := packer.PackPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(p).To(BeNil()) + }) + + It("sends non forward-secure data as the client", func() { + f := &wire.StreamFrame{ + StreamID: 5, + Data: []byte("foobar"), + } + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).Return([]*wire.StreamFrame{f}) + packer.perspective = protocol.PerspectiveClient + packer.cryptoSetup.(*mockCryptoSetup).encLevelSeal = protocol.EncryptionSecure + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.encryptionLevel).To(Equal(protocol.EncryptionSecure)) + Expect(p.frames).To(Equal([]wire.Frame{f})) + }) + + It("does not send non forward-secure data as the server", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + // don't expect a call to mockStreamFramer.PopStreamFrames + packer.cryptoSetup.(*mockCryptoSetup).encLevelSeal = protocol.EncryptionSecure + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(BeNil()) + }) + + It("packs a maximum size crypto packet", func() { + var f *wire.StreamFrame + packer.version = versionIETFFrames + mockStreamFramer.EXPECT().HasCryptoStreamData().Return(true) + mockStreamFramer.EXPECT().PopCryptoStreamFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.StreamFrame { + f = &wire.StreamFrame{ + StreamID: packer.version.CryptoStreamID(), + Offset: 0x1337, + } + f.Data = bytes.Repeat([]byte{'f'}, int(size-f.Length(packer.version))) + return f + }) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(HaveLen(1)) + expectedPacketLen := packer.maxPacketSize - protocol.NonForwardSecurePacketSizeReduction + Expect(p.raw).To(HaveLen(int(expectedPacketLen))) + Expect(p.header.IsLongHeader).To(BeTrue()) + checkPayloadLen(p.raw) + }) + + It("sends unencrypted stream data on the crypto stream", func() { + f := &wire.StreamFrame{ + StreamID: packer.version.CryptoStreamID(), + Data: []byte("foobar"), + } + mockStreamFramer.EXPECT().HasCryptoStreamData().Return(true) + mockStreamFramer.EXPECT().PopCryptoStreamFrame(gomock.Any()).Return(f) + packer.cryptoSetup.(*mockCryptoSetup).encLevelSealCrypto = protocol.EncryptionUnencrypted + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(Equal([]wire.Frame{f})) + Expect(p.encryptionLevel).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("sends encrypted stream data on the crypto stream", func() { + f := &wire.StreamFrame{ + StreamID: packer.version.CryptoStreamID(), + Data: []byte("foobar"), + } + mockStreamFramer.EXPECT().HasCryptoStreamData().Return(true) + mockStreamFramer.EXPECT().PopCryptoStreamFrame(gomock.Any()).Return(f) + packer.cryptoSetup.(*mockCryptoSetup).encLevelSealCrypto = protocol.EncryptionSecure + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(Equal([]wire.Frame{f})) + Expect(p.encryptionLevel).To(Equal(protocol.EncryptionSecure)) + }) + + It("does not pack STREAM frames if not allowed", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + // don't expect a call to mockStreamFramer.PopStreamFrames + packer.cryptoSetup.(*mockCryptoSetup).encLevelSeal = protocol.EncryptionUnencrypted + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Largest: 10, Smallest: 1}}} + packer.QueueControlFrame(ack) + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.frames).To(Equal([]wire.Frame{ack})) + }) + }) + + It("packs a single ACK", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Largest: 42, Smallest: 1}}} + packer.QueueControlFrame(ack) + p, err := packer.PackPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(p).ToNot(BeNil()) + Expect(p.frames[0]).To(Equal(ack)) + }) + + It("does not return nil if we only have a single ACK but request it to be sent", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()) + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}} + packer.QueueControlFrame(ack) + p, err := packer.PackPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(p).ToNot(BeNil()) + }) + + Context("retransmitting of handshake packets", func() { + swf := &wire.StopWaitingFrame{LeastUnacked: 1} + sf := &wire.StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + } + + BeforeEach(func() { + packer.QueueControlFrame(swf) + }) + + It("packs a retransmission for a packet sent with no encryption", func() { + packet := &ackhandler.Packet{ + PacketType: protocol.PacketTypeHandshake, + EncryptionLevel: protocol.EncryptionUnencrypted, + Frames: []wire.Frame{sf}, + } + p, err := packer.PackRetransmission(packet) + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(HaveLen(1)) + Expect(p[0].header.Type).To(Equal(protocol.PacketTypeHandshake)) + Expect(p[0].frames).To(Equal([]wire.Frame{swf, sf})) + Expect(p[0].encryptionLevel).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("doesn't add a STOP_WAITING frame for IETF QUIC", func() { + packer.version = versionIETFFrames + packet := &ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionUnencrypted, + Frames: []wire.Frame{sf}, + } + p, err := packer.PackRetransmission(packet) + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(HaveLen(1)) + Expect(p[0].frames).To(Equal([]wire.Frame{sf})) + Expect(p[0].encryptionLevel).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("packs a retransmission for a packet sent with initial encryption", func() { + packet := &ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionSecure, + Frames: []wire.Frame{sf}, + } + p, err := packer.PackRetransmission(packet) + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(HaveLen(1)) + Expect(p[0].frames).To(Equal([]wire.Frame{swf, sf})) + Expect(p[0].encryptionLevel).To(Equal(protocol.EncryptionSecure)) + // a packet sent by the server with initial encryption contains the SHLO + // it needs to have a diversification nonce + Expect(p[0].raw).To(ContainSubstring(string(divNonce))) + }) + + It("includes the diversification nonce on packets sent with initial encryption", func() { + packet := &ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionSecure, + Frames: []wire.Frame{sf}, + } + p, err := packer.PackRetransmission(packet) + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(HaveLen(1)) + Expect(p[0].encryptionLevel).To(Equal(protocol.EncryptionSecure)) + }) + + // this should never happen, since non forward-secure packets are limited to a size smaller than MaxPacketSize, such that it is always possible to retransmit them without splitting the StreamFrame + // (note that the retransmitted packet needs to have enough space for the StopWaitingFrame) + It("refuses to send a packet larger than MaxPacketSize", func() { + packet := &ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionSecure, + Frames: []wire.Frame{ + &wire.StreamFrame{ + StreamID: 1, + Data: bytes.Repeat([]byte{'f'}, int(maxPacketSize-5)), + }, + }, + } + _, err := packer.PackRetransmission(packet) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("PacketPacker BUG: packet too large")) + }) + + It("pads Initial packets to the required minimum packet size", func() { + f := &wire.StreamFrame{ + StreamID: packer.version.CryptoStreamID(), + Data: []byte("foobar"), + } + mockStreamFramer.EXPECT().HasCryptoStreamData().Return(true) + mockStreamFramer.EXPECT().PopCryptoStreamFrame(gomock.Any()).Return(f) + packer.version = protocol.VersionTLS + packer.hasSentPacket = false + packer.perspective = protocol.PerspectiveClient + packer.cryptoSetup.(*mockCryptoSetup).encLevelSealCrypto = protocol.EncryptionUnencrypted + packet, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(packet.header.Token).To(Equal(token)) + Expect(packet.raw).To(HaveLen(protocol.MinInitialPacketSize)) + Expect(packet.frames).To(HaveLen(1)) + sf := packet.frames[0].(*wire.StreamFrame) + Expect(sf.Data).To(Equal([]byte("foobar"))) + Expect(sf.DataLenPresent).To(BeTrue()) + }) + + It("set the correct payload length for an Initial packet", func() { + mockStreamFramer.EXPECT().HasCryptoStreamData().Return(true) + mockStreamFramer.EXPECT().PopCryptoStreamFrame(gomock.Any()).Return(&wire.StreamFrame{ + StreamID: packer.version.CryptoStreamID(), + Data: []byte("foobar"), + }) + packer.version = protocol.VersionTLS + packer.hasSentPacket = false + packer.perspective = protocol.PerspectiveClient + packer.cryptoSetup.(*mockCryptoSetup).encLevelSealCrypto = protocol.EncryptionUnencrypted + packet, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + checkPayloadLen(packet.raw) + }) + + It("packs a retransmission for an Initial packet", func() { + packer.version = versionIETFFrames + packer.perspective = protocol.PerspectiveClient + packet := &ackhandler.Packet{ + PacketType: protocol.PacketTypeInitial, + EncryptionLevel: protocol.EncryptionUnencrypted, + Frames: []wire.Frame{sf}, + } + p, err := packer.PackRetransmission(packet) + Expect(err).ToNot(HaveOccurred()) + Expect(p).To(HaveLen(1)) + Expect(p[0].frames).To(Equal([]wire.Frame{sf})) + Expect(p[0].encryptionLevel).To(Equal(protocol.EncryptionUnencrypted)) + Expect(p[0].header.Type).To(Equal(protocol.PacketTypeInitial)) + Expect(p[0].header.Token).To(Equal(token)) + }) + + It("refuses to retransmit packets without a STOP_WAITING Frame", func() { + packer.stopWaiting = nil + _, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionSecure, + }) + Expect(err).To(MatchError("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame")) + }) + }) + + Context("retransmission of forward-secure packets", func() { + BeforeEach(func() { + packer.packetNumberGenerator.next = 15 + packer.stopWaiting = &wire.StopWaitingFrame{LeastUnacked: 7} + }) + + It("retransmits a small packet", func() { + frames := []wire.Frame{ + &wire.MaxDataFrame{ByteOffset: 0x1234}, + &wire.StreamFrame{StreamID: 42, Data: []byte("foobar")}, + } + packets, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: frames, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.encryptionLevel).To(Equal(protocol.EncryptionForwardSecure)) + Expect(p.frames).To(HaveLen(3)) + Expect(p.frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(p.frames[0].(*wire.StopWaitingFrame).LeastUnacked).To(Equal(protocol.PacketNumber(7))) + Expect(p.frames[0].(*wire.StopWaitingFrame).PacketNumber).To(Equal(p.header.PacketNumber)) + Expect(p.frames[0].(*wire.StopWaitingFrame).PacketNumberLen).To(Equal(p.header.PacketNumberLen)) + Expect(p.frames[1:]).To(Equal(frames)) + }) + + It("refuses to retransmit packets without a STOP_WAITING Frame", func() { + packer.stopWaiting = nil + _, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: []wire.Frame{&wire.MaxDataFrame{ByteOffset: 0x1234}}, + }) + Expect(err).To(MatchError("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame")) + }) + + It("packs two packets for retransmission if the original packet contained many control frames", func() { + var frames []wire.Frame + var totalLen protocol.ByteCount + // pack a bunch of control frames, such that the packet is way bigger than a single packet + for i := 0; totalLen < maxPacketSize*3/2; i++ { + f := &wire.MaxStreamDataFrame{StreamID: protocol.StreamID(i), ByteOffset: protocol.ByteCount(i)} + frames = append(frames, f) + totalLen += f.Length(packer.version) + } + packets, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: frames, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(packets).To(HaveLen(2)) + Expect(len(packets[0].frames) + len(packets[1].frames)).To(Equal(len(frames) + 2)) // all frames, plus 2 STOP_WAITING frames + Expect(packets[0].frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(packets[1].frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(packets[0].frames[1:]).To(Equal(frames[:len(packets[0].frames)-1])) + Expect(packets[1].frames[1:]).To(Equal(frames[len(packets[0].frames)-1:])) + // check that the first packet was filled up as far as possible: + // if the first frame (after the STOP_WAITING) was packed into the first packet, it would have overflown the MaxPacketSize + Expect(len(packets[0].raw) + int(packets[1].frames[1].Length(packer.version))).To(BeNumerically(">", maxPacketSize)) + }) + + It("splits a STREAM frame that doesn't fit", func() { + packets, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: []wire.Frame{&wire.StreamFrame{ + StreamID: 42, + Offset: 1337, + Data: bytes.Repeat([]byte{'a'}, int(maxPacketSize)*3/2), + }}, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(packets).To(HaveLen(2)) + Expect(packets[0].frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(packets[1].frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(packets[0].frames[1]).To(BeAssignableToTypeOf(&wire.StreamFrame{})) + Expect(packets[1].frames[1]).To(BeAssignableToTypeOf(&wire.StreamFrame{})) + sf1 := packets[0].frames[1].(*wire.StreamFrame) + sf2 := packets[1].frames[1].(*wire.StreamFrame) + Expect(sf1.StreamID).To(Equal(protocol.StreamID(42))) + Expect(sf1.Offset).To(Equal(protocol.ByteCount(1337))) + Expect(sf1.DataLenPresent).To(BeFalse()) + Expect(sf2.StreamID).To(Equal(protocol.StreamID(42))) + Expect(sf2.Offset).To(Equal(protocol.ByteCount(1337) + sf1.DataLen())) + Expect(sf2.DataLenPresent).To(BeFalse()) + Expect(sf1.DataLen() + sf2.DataLen()).To(Equal(maxPacketSize * 3 / 2)) + Expect(packets[0].raw).To(HaveLen(int(maxPacketSize))) + }) + + It("packs two packets for retransmission if the original packet contained many STREAM frames", func() { + var frames []wire.Frame + var totalLen protocol.ByteCount + // pack a bunch of control frames, such that the packet is way bigger than a single packet + for i := 0; totalLen < maxPacketSize*3/2; i++ { + f := &wire.StreamFrame{ + StreamID: protocol.StreamID(i), + Data: []byte("foobar"), + DataLenPresent: true, + } + frames = append(frames, f) + totalLen += f.Length(packer.version) + } + packets, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: frames, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(packets).To(HaveLen(2)) + Expect(len(packets[0].frames) + len(packets[1].frames)).To(Equal(len(frames) + 2)) // all frames, plus 2 STOP_WAITING frames + Expect(packets[0].frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(packets[1].frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(packets[0].frames[1:]).To(Equal(frames[:len(packets[0].frames)-1])) + Expect(packets[1].frames[1:]).To(Equal(frames[len(packets[0].frames)-1:])) + // check that the first packet was filled up as far as possible: + // if the first frame (after the STOP_WAITING) was packed into the first packet, it would have overflown the MaxPacketSize + Expect(len(packets[0].raw) + int(packets[1].frames[1].Length(packer.version))).To(BeNumerically(">", maxPacketSize-protocol.MinStreamFrameSize)) + }) + + It("correctly sets the DataLenPresent on STREAM frames", func() { + frames := []wire.Frame{ + &wire.StreamFrame{StreamID: 4, Data: []byte("foobar"), DataLenPresent: true}, + &wire.StreamFrame{StreamID: 5, Data: []byte("barfoo")}, + } + packets, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: frames, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.frames).To(HaveLen(3)) + Expect(p.frames[1]).To(BeAssignableToTypeOf(&wire.StreamFrame{})) + Expect(p.frames[2]).To(BeAssignableToTypeOf(&wire.StreamFrame{})) + sf1 := p.frames[1].(*wire.StreamFrame) + sf2 := p.frames[2].(*wire.StreamFrame) + Expect(sf1.StreamID).To(Equal(protocol.StreamID(4))) + Expect(sf1.DataLenPresent).To(BeTrue()) + Expect(sf2.StreamID).To(Equal(protocol.StreamID(5))) + Expect(sf2.DataLenPresent).To(BeFalse()) + }) + }) + + Context("packing ACK packets", func() { + It("packs ACK packets", func() { + packer.QueueControlFrame(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + p, err := packer.PackAckPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(p.frames).To(HaveLen(1)) + Expect(p.frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{})) + ack := p.frames[0].(*wire.AckFrame) + Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(10))) + }) + + It("packs ACK packets with STOP_WAITING frames", func() { + packer.QueueControlFrame(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}) + packer.QueueControlFrame(&wire.StopWaitingFrame{}) + p, err := packer.PackAckPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(p.frames).To(HaveLen(2)) + Expect(p.frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{})) + Expect(p.frames[1]).To(Equal(&wire.StopWaitingFrame{PacketNumber: 1, PacketNumberLen: 2})) + }) + }) + + Context("max packet size", func() { + It("sets the maximum packet size", func() { + for i := 0; i < 10*int(maxPacketSize); i++ { + packer.QueueControlFrame(&wire.PingFrame{}) + } + mockStreamFramer.EXPECT().HasCryptoStreamData().AnyTimes() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).AnyTimes() + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.raw).To(HaveLen(int(maxPacketSize))) + // now reduce the maxPacketSize + packer.SetMaxPacketSize(maxPacketSize - 10) + p, err = packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.raw).To(HaveLen(int(maxPacketSize) - 10)) + }) + + It("doesn't increase the max packet size", func() { + for i := 0; i < 10*int(maxPacketSize); i++ { + packer.QueueControlFrame(&wire.PingFrame{}) + } + mockStreamFramer.EXPECT().HasCryptoStreamData().AnyTimes() + mockStreamFramer.EXPECT().PopStreamFrames(gomock.Any()).AnyTimes() + p, err := packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.raw).To(HaveLen(int(maxPacketSize))) + // now try to increase the maxPacketSize + packer.SetMaxPacketSize(maxPacketSize + 10) + p, err = packer.PackPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(p.raw).To(HaveLen(int(maxPacketSize))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/packet_unpacker.go b/vendor/lucas-clemente/quic-go/packet_unpacker.go new file mode 100644 index 00000000..99497907 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_unpacker.go @@ -0,0 +1,127 @@ +package quic + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +type unpackedPacket struct { + encryptionLevel protocol.EncryptionLevel + frames []wire.Frame +} + +type gQUICAEAD interface { + Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) +} + +type quicAEAD interface { + OpenHandshake(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) + Open1RTT(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) +} + +type packetUnpackerBase struct { + version protocol.VersionNumber +} + +func (u *packetUnpackerBase) parseFrames(decrypted []byte, hdr *wire.Header) ([]wire.Frame, error) { + r := bytes.NewReader(decrypted) + if r.Len() == 0 { + return nil, qerr.MissingPayload + } + + fs := make([]wire.Frame, 0, 2) + // Read all frames in the packet + for { + frame, err := wire.ParseNextFrame(r, hdr, u.version) + if err != nil { + return nil, err + } + if frame == nil { + break + } + fs = append(fs, frame) + } + return fs, nil +} + +// The packetUnpackerGQUIC unpacks gQUIC packets. +type packetUnpackerGQUIC struct { + packetUnpackerBase + aead gQUICAEAD +} + +var _ unpacker = &packetUnpackerGQUIC{} + +func newPacketUnpackerGQUIC(aead gQUICAEAD, version protocol.VersionNumber) unpacker { + return &packetUnpackerGQUIC{ + packetUnpackerBase: packetUnpackerBase{version: version}, + aead: aead, + } +} + +func (u *packetUnpackerGQUIC) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) { + decrypted, encryptionLevel, err := u.aead.Open(data[:0], data, hdr.PacketNumber, headerBinary) + if err != nil { + // Wrap err in quicError so that public reset is sent by session + return nil, qerr.Error(qerr.DecryptionFailure, err.Error()) + } + + fs, err := u.parseFrames(decrypted, hdr) + if err != nil { + return nil, err + } + + return &unpackedPacket{ + encryptionLevel: encryptionLevel, + frames: fs, + }, nil +} + +// The packetUnpacker unpacks IETF QUIC packets. +type packetUnpacker struct { + packetUnpackerBase + aead quicAEAD +} + +var _ unpacker = &packetUnpacker{} + +func newPacketUnpacker(aead quicAEAD, version protocol.VersionNumber) unpacker { + return &packetUnpacker{ + packetUnpackerBase: packetUnpackerBase{version: version}, + aead: aead, + } +} + +func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) { + buf := *getPacketBuffer() + buf = buf[:0] + defer putPacketBuffer(&buf) + + var decrypted []byte + var encryptionLevel protocol.EncryptionLevel + var err error + if hdr.IsLongHeader { + decrypted, err = u.aead.OpenHandshake(buf, data, hdr.PacketNumber, headerBinary) + encryptionLevel = protocol.EncryptionUnencrypted + } else { + decrypted, err = u.aead.Open1RTT(buf, data, hdr.PacketNumber, headerBinary) + encryptionLevel = protocol.EncryptionForwardSecure + } + if err != nil { + // Wrap err in quicError so that public reset is sent by session + return nil, qerr.Error(qerr.DecryptionFailure, err.Error()) + } + + fs, err := u.parseFrames(decrypted, hdr) + if err != nil { + return nil, err + } + + return &unpackedPacket{ + encryptionLevel: encryptionLevel, + frames: fs, + }, nil +} diff --git a/vendor/lucas-clemente/quic-go/packet_unpacker_test.go b/vendor/lucas-clemente/quic-go/packet_unpacker_test.go new file mode 100644 index 00000000..1ed5b840 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/packet_unpacker_test.go @@ -0,0 +1,98 @@ +package quic + +import ( + "bytes" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Packet Unpacker (for gQUIC)", func() { + var ( + unpacker *packetUnpackerGQUIC + hdr *wire.Header + aead *MockGQUICAEAD + ) + + BeforeEach(func() { + aead = NewMockGQUICAEAD(mockCtrl) + hdr = &wire.Header{ + PacketNumber: 10, + PacketNumberLen: 1, + Raw: []byte{0x04, 0x4c, 0x01}, + } + unpacker = newPacketUnpackerGQUIC(aead, versionGQUICFrames).(*packetUnpackerGQUIC) + }) + + It("errors if the packet doesn't contain any payload", func() { + data := []byte("foobar") + aead.EXPECT().Open(gomock.Any(), []byte("foobar"), hdr.PacketNumber, hdr.Raw).Return([]byte{}, protocol.EncryptionForwardSecure, nil) + _, err := unpacker.Unpack(hdr.Raw, hdr, data) + Expect(err).To(MatchError(qerr.MissingPayload)) + }) + + It("saves the encryption level", func() { + aead.EXPECT().Open(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return([]byte{0}, protocol.EncryptionSecure, nil) + packet, err := unpacker.Unpack(hdr.Raw, hdr, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.encryptionLevel).To(Equal(protocol.EncryptionSecure)) + }) + + It("unpacks the frames", func() { + buf := &bytes.Buffer{} + (&wire.PingFrame{}).Write(buf, versionGQUICFrames) + (&wire.BlockedFrame{}).Write(buf, versionGQUICFrames) + aead.EXPECT().Open(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return(buf.Bytes(), protocol.EncryptionForwardSecure, nil) + packet, err := unpacker.Unpack(hdr.Raw, hdr, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]wire.Frame{&wire.PingFrame{}, &wire.BlockedFrame{}})) + }) +}) + +var _ = Describe("Packet Unpacker (for IETF QUIC)", func() { + var ( + unpacker *packetUnpacker + hdr *wire.Header + aead *MockQuicAEAD + ) + + BeforeEach(func() { + aead = NewMockQuicAEAD(mockCtrl) + hdr = &wire.Header{ + PacketNumber: 10, + PacketNumberLen: 1, + Raw: []byte{0x04, 0x4c, 0x01}, + } + unpacker = newPacketUnpacker(aead, versionIETFFrames).(*packetUnpacker) + }) + + It("errors if the packet doesn't contain any payload", func() { + data := []byte("foobar") + aead.EXPECT().Open1RTT(gomock.Any(), []byte("foobar"), hdr.PacketNumber, hdr.Raw).Return([]byte{}, nil) + _, err := unpacker.Unpack(hdr.Raw, hdr, data) + Expect(err).To(MatchError(qerr.MissingPayload)) + }) + + It("opens handshake packets", func() { + hdr.IsLongHeader = true + aead.EXPECT().OpenHandshake(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return([]byte{0}, nil) + packet, err := unpacker.Unpack(hdr.Raw, hdr, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.encryptionLevel).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("unpacks the frames", func() { + buf := &bytes.Buffer{} + (&wire.PingFrame{}).Write(buf, versionIETFFrames) + (&wire.BlockedFrame{}).Write(buf, versionIETFFrames) + aead.EXPECT().Open1RTT(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return(buf.Bytes(), nil) + packet, err := unpacker.Unpack(hdr.Raw, hdr, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]wire.Frame{&wire.PingFrame{}, &wire.BlockedFrame{}})) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/qerr/error_codes.go b/vendor/lucas-clemente/quic-go/qerr/error_codes.go new file mode 100644 index 00000000..f3e6dd9c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/qerr/error_codes.go @@ -0,0 +1,193 @@ +package qerr + +// The error codes defined by QUIC +// Remember to run `go generate ./...` whenever the error codes change. +//go:generate stringer -type=ErrorCode +const ( + InternalError ErrorCode = 1 + // There were data frames after the a fin or reset. + StreamDataAfterTermination ErrorCode = 2 + // Control frame is malformed. + InvalidPacketHeader ErrorCode = 3 + // Frame data is malformed. + InvalidFrameData ErrorCode = 4 + // The packet contained no payload. + MissingPayload ErrorCode = 48 + // FEC data is malformed. + InvalidFecData ErrorCode = 5 + // STREAM frame data is malformed. + InvalidStreamData ErrorCode = 46 + // STREAM frame data overlaps with buffered data. + OverlappingStreamData ErrorCode = 87 + // Received STREAM frame data is not encrypted. + UnencryptedStreamData ErrorCode = 61 + // Attempt to send unencrypted STREAM frame. + AttemptToSendUnencryptedStreamData ErrorCode = 88 + // FEC frame data is not encrypted. + UnencryptedFecData ErrorCode = 77 + // RST_STREAM frame data is malformed. + InvalidRstStreamData ErrorCode = 6 + // CONNECTION_CLOSE frame data is malformed. + InvalidConnectionCloseData ErrorCode = 7 + // GOAWAY frame data is malformed. + InvalidGoawayData ErrorCode = 8 + // WINDOW_UPDATE frame data is malformed. + InvalidWindowUpdateData ErrorCode = 57 + // BLOCKED frame data is malformed. + InvalidBlockedData ErrorCode = 58 + // STOP_WAITING frame data is malformed. + InvalidStopWaitingData ErrorCode = 60 + // PATH_CLOSE frame data is malformed. + InvalidPathCloseData ErrorCode = 78 + // ACK frame data is malformed. + InvalidAckData ErrorCode = 9 + + // Version negotiation packet is malformed. + InvalidVersionNegotiationPacket ErrorCode = 10 + // Public RST packet is malformed. + InvalidPublicRstPacket ErrorCode = 11 + // There was an error decrypting. + DecryptionFailure ErrorCode = 12 + // There was an error encrypting. + EncryptionFailure ErrorCode = 13 + // The packet exceeded kMaxPacketSize. + PacketTooLarge ErrorCode = 14 + // The peer is going away. May be a client or server. + PeerGoingAway ErrorCode = 16 + // A stream ID was invalid. + InvalidStreamID ErrorCode = 17 + // A priority was invalid. + InvalidPriority ErrorCode = 49 + // Too many streams already open. + TooManyOpenStreams ErrorCode = 18 + // The peer created too many available streams. + TooManyAvailableStreams ErrorCode = 76 + // Received public reset for this connection. + PublicReset ErrorCode = 19 + // Invalid protocol version. + InvalidVersion ErrorCode = 20 + + // The Header ID for a stream was too far from the previous. + InvalidHeaderID ErrorCode = 22 + // Negotiable parameter received during handshake had invalid value. + InvalidNegotiatedValue ErrorCode = 23 + // There was an error decompressing data. + DecompressionFailure ErrorCode = 24 + // The connection timed out due to no network activity. + NetworkIdleTimeout ErrorCode = 25 + // The connection timed out waiting for the handshake to complete. + HandshakeTimeout ErrorCode = 67 + // There was an error encountered migrating addresses. + ErrorMigratingAddress ErrorCode = 26 + // There was an error encountered migrating port only. + ErrorMigratingPort ErrorCode = 86 + // There was an error while writing to the socket. + PacketWriteError ErrorCode = 27 + // There was an error while reading from the socket. + PacketReadError ErrorCode = 51 + // We received a STREAM_FRAME with no data and no fin flag set. + EmptyStreamFrameNoFin ErrorCode = 50 + // We received invalid data on the headers stream. + InvalidHeadersStreamData ErrorCode = 56 + // Invalid data on the headers stream received because of decompression + // failure. + HeadersStreamDataDecompressFailure ErrorCode = 97 + // The peer received too much data, violating flow control. + FlowControlReceivedTooMuchData ErrorCode = 59 + // The peer sent too much data, violating flow control. + FlowControlSentTooMuchData ErrorCode = 63 + // The peer received an invalid flow control window. + FlowControlInvalidWindow ErrorCode = 64 + // The connection has been IP pooled into an existing connection. + ConnectionIPPooled ErrorCode = 62 + // The connection has too many outstanding sent packets. + TooManyOutstandingSentPackets ErrorCode = 68 + // The connection has too many outstanding received packets. + TooManyOutstandingReceivedPackets ErrorCode = 69 + // The quic connection has been cancelled. + ConnectionCancelled ErrorCode = 70 + // Disabled QUIC because of high packet loss rate. + BadPacketLossRate ErrorCode = 71 + // Disabled QUIC because of too many PUBLIC_RESETs post handshake. + PublicResetsPostHandshake ErrorCode = 73 + // Disabled QUIC because of too many timeouts with streams open. + TimeoutsWithOpenStreams ErrorCode = 74 + // Closed because we failed to serialize a packet. + FailedToSerializePacket ErrorCode = 75 + // QUIC timed out after too many RTOs. + TooManyRtos ErrorCode = 85 + + // Crypto errors. + + // Hanshake failed. + HandshakeFailed ErrorCode = 28 + // Handshake message contained out of order tags. + CryptoTagsOutOfOrder ErrorCode = 29 + // Handshake message contained too many entries. + CryptoTooManyEntries ErrorCode = 30 + // Handshake message contained an invalid value length. + CryptoInvalidValueLength ErrorCode = 31 + // A crypto message was received after the handshake was complete. + CryptoMessageAfterHandshakeComplete ErrorCode = 32 + // A crypto message was received with an illegal message tag. + InvalidCryptoMessageType ErrorCode = 33 + // A crypto message was received with an illegal parameter. + InvalidCryptoMessageParameter ErrorCode = 34 + // An invalid channel id signature was supplied. + InvalidChannelIDSignature ErrorCode = 52 + // A crypto message was received with a mandatory parameter missing. + CryptoMessageParameterNotFound ErrorCode = 35 + // A crypto message was received with a parameter that has no overlap + // with the local parameter. + CryptoMessageParameterNoOverlap ErrorCode = 36 + // A crypto message was received that contained a parameter with too few + // values. + CryptoMessageIndexNotFound ErrorCode = 37 + // An internal error occurred in crypto processing. + CryptoInternalError ErrorCode = 38 + // A crypto handshake message specified an unsupported version. + CryptoVersionNotSupported ErrorCode = 39 + // A crypto handshake message resulted in a stateless reject. + CryptoHandshakeStatelessReject ErrorCode = 72 + // There was no intersection between the crypto primitives supported by the + // peer and ourselves. + CryptoNoSupport ErrorCode = 40 + // The server rejected our client hello messages too many times. + CryptoTooManyRejects ErrorCode = 41 + // The client rejected the server's certificate chain or signature. + ProofInvalid ErrorCode = 42 + // A crypto message was received with a duplicate tag. + CryptoDuplicateTag ErrorCode = 43 + // A crypto message was received with the wrong encryption level (i.e. it + // should have been encrypted but was not.) + CryptoEncryptionLevelIncorrect ErrorCode = 44 + // The server config for a server has expired. + CryptoServerConfigExpired ErrorCode = 45 + // We failed to setup the symmetric keys for a connection. + CryptoSymmetricKeySetupFailed ErrorCode = 53 + // A handshake message arrived, but we are still validating the + // previous handshake message. + CryptoMessageWhileValidatingClientHello ErrorCode = 54 + // A server config update arrived before the handshake is complete. + CryptoUpdateBeforeHandshakeComplete ErrorCode = 65 + // This connection involved a version negotiation which appears to have been + // tampered with. + VersionNegotiationMismatch ErrorCode = 55 + + // Multipath is not enabled, but a packet with multipath flag on is received. + BadMultipathFlag ErrorCode = 79 + + // IP address changed causing connection close. + IPAddressChanged ErrorCode = 80 + + // Connection migration errors. + // Network changed, but connection had no migratable streams. + ConnectionMigrationNoMigratableStreams ErrorCode = 81 + // Connection changed networks too many times. + ConnectionMigrationTooManyChanges ErrorCode = 82 + // Connection migration was attempted, but there was no new network to + // migrate to. + ConnectionMigrationNoNewNetwork ErrorCode = 83 + // Network changed, but connection had one or more non-migratable streams. + ConnectionMigrationNonMigratableStream ErrorCode = 84 +) diff --git a/vendor/lucas-clemente/quic-go/qerr/errorcode_string.go b/vendor/lucas-clemente/quic-go/qerr/errorcode_string.go new file mode 100644 index 00000000..22d0c85a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/qerr/errorcode_string.go @@ -0,0 +1,46 @@ +// Code generated by "stringer -type=ErrorCode"; DO NOT EDIT. + +package qerr + +import "strconv" + +const ( + _ErrorCode_name_0 = "InternalErrorStreamDataAfterTerminationInvalidPacketHeaderInvalidFrameDataInvalidFecDataInvalidRstStreamDataInvalidConnectionCloseDataInvalidGoawayDataInvalidAckDataInvalidVersionNegotiationPacketInvalidPublicRstPacketDecryptionFailureEncryptionFailurePacketTooLarge" + _ErrorCode_name_1 = "PeerGoingAwayInvalidStreamIDTooManyOpenStreamsPublicResetInvalidVersion" + _ErrorCode_name_2 = "InvalidHeaderIDInvalidNegotiatedValueDecompressionFailureNetworkIdleTimeoutErrorMigratingAddressPacketWriteErrorHandshakeFailedCryptoTagsOutOfOrderCryptoTooManyEntriesCryptoInvalidValueLengthCryptoMessageAfterHandshakeCompleteInvalidCryptoMessageTypeInvalidCryptoMessageParameterCryptoMessageParameterNotFoundCryptoMessageParameterNoOverlapCryptoMessageIndexNotFoundCryptoInternalErrorCryptoVersionNotSupportedCryptoNoSupportCryptoTooManyRejectsProofInvalidCryptoDuplicateTagCryptoEncryptionLevelIncorrectCryptoServerConfigExpiredInvalidStreamData" + _ErrorCode_name_3 = "MissingPayloadInvalidPriorityEmptyStreamFrameNoFinPacketReadErrorInvalidChannelIDSignatureCryptoSymmetricKeySetupFailedCryptoMessageWhileValidatingClientHelloVersionNegotiationMismatchInvalidHeadersStreamDataInvalidWindowUpdateDataInvalidBlockedDataFlowControlReceivedTooMuchDataInvalidStopWaitingDataUnencryptedStreamDataConnectionIPPooledFlowControlSentTooMuchDataFlowControlInvalidWindowCryptoUpdateBeforeHandshakeComplete" + _ErrorCode_name_4 = "HandshakeTimeoutTooManyOutstandingSentPacketsTooManyOutstandingReceivedPacketsConnectionCancelledBadPacketLossRateCryptoHandshakeStatelessRejectPublicResetsPostHandshakeTimeoutsWithOpenStreamsFailedToSerializePacketTooManyAvailableStreamsUnencryptedFecDataInvalidPathCloseDataBadMultipathFlagIPAddressChangedConnectionMigrationNoMigratableStreamsConnectionMigrationTooManyChangesConnectionMigrationNoNewNetworkConnectionMigrationNonMigratableStreamTooManyRtosErrorMigratingPortOverlappingStreamDataAttemptToSendUnencryptedStreamData" + _ErrorCode_name_5 = "HeadersStreamDataDecompressFailure" +) + +var ( + _ErrorCode_index_0 = [...]uint16{0, 13, 39, 58, 74, 88, 108, 134, 151, 165, 196, 218, 235, 252, 266} + _ErrorCode_index_1 = [...]uint8{0, 13, 28, 46, 57, 71} + _ErrorCode_index_2 = [...]uint16{0, 15, 37, 57, 75, 96, 112, 127, 147, 167, 191, 226, 250, 279, 309, 340, 366, 385, 410, 425, 445, 457, 475, 505, 530, 547} + _ErrorCode_index_3 = [...]uint16{0, 14, 29, 50, 65, 90, 119, 158, 184, 208, 231, 249, 279, 301, 322, 340, 366, 390, 425} + _ErrorCode_index_4 = [...]uint16{0, 16, 45, 78, 97, 114, 144, 169, 192, 215, 238, 256, 276, 292, 308, 346, 379, 410, 448, 459, 477, 498, 532} +) + +func (i ErrorCode) String() string { + switch { + case 1 <= i && i <= 14: + i -= 1 + return _ErrorCode_name_0[_ErrorCode_index_0[i]:_ErrorCode_index_0[i+1]] + case 16 <= i && i <= 20: + i -= 16 + return _ErrorCode_name_1[_ErrorCode_index_1[i]:_ErrorCode_index_1[i+1]] + case 22 <= i && i <= 46: + i -= 22 + return _ErrorCode_name_2[_ErrorCode_index_2[i]:_ErrorCode_index_2[i+1]] + case 48 <= i && i <= 65: + i -= 48 + return _ErrorCode_name_3[_ErrorCode_index_3[i]:_ErrorCode_index_3[i+1]] + case 67 <= i && i <= 88: + i -= 67 + return _ErrorCode_name_4[_ErrorCode_index_4[i]:_ErrorCode_index_4[i+1]] + case i == 97: + return _ErrorCode_name_5 + default: + return "ErrorCode(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/vendor/lucas-clemente/quic-go/qerr/errorcodes_test.go b/vendor/lucas-clemente/quic-go/qerr/errorcodes_test.go new file mode 100644 index 00000000..f8cde224 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/qerr/errorcodes_test.go @@ -0,0 +1,38 @@ +package qerr + +import ( + "go/ast" + "go/parser" + "go/token" + "path" + "runtime" + "strconv" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("error codes", func() { + // If this test breaks, you should run `go generate ./...` + It("has a string representation for every error code", func() { + // We parse the error code file, extract all constants, and verify that + // each of them has a string version. Go FTW! + _, thisfile, _, ok := runtime.Caller(0) + if !ok { + panic("Failed to get current frame") + } + filename := path.Join(path.Dir(thisfile), "error_codes.go") + fileAst, err := parser.ParseFile(token.NewFileSet(), filename, nil, 0) + Expect(err).NotTo(HaveOccurred()) + constSpecs := fileAst.Decls[0].(*ast.GenDecl).Specs + Expect(len(constSpecs)).To(BeNumerically(">", 4)) // at time of writing + for _, c := range constSpecs { + name := c.(*ast.ValueSpec).Names[0].Name + valString := c.(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value + val, err := strconv.Atoi(valString) + Expect(err).NotTo(HaveOccurred()) + Expect(ErrorCode(val).String()).To(Equal(name)) + } + Expect(ErrorCode(0).String()).To(Equal("ErrorCode(0)")) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/qerr/errors_suite_test.go b/vendor/lucas-clemente/quic-go/qerr/errors_suite_test.go new file mode 100644 index 00000000..749cdedc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/qerr/errors_suite_test.go @@ -0,0 +1,13 @@ +package qerr + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestErrorcodes(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Errors Suite") +} diff --git a/vendor/lucas-clemente/quic-go/qerr/quic_error.go b/vendor/lucas-clemente/quic-go/qerr/quic_error.go new file mode 100644 index 00000000..42d08c4c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/qerr/quic_error.go @@ -0,0 +1,53 @@ +package qerr + +import ( + "fmt" +) + +// ErrorCode can be used as a normal error without reason. +type ErrorCode uint32 + +func (e ErrorCode) Error() string { + return e.String() +} + +// A QuicError consists of an error code plus a error reason +type QuicError struct { + ErrorCode ErrorCode + ErrorMessage string +} + +// Error creates a new QuicError instance +func Error(errorCode ErrorCode, errorMessage string) *QuicError { + return &QuicError{ + ErrorCode: errorCode, + ErrorMessage: errorMessage, + } +} + +func (e *QuicError) Error() string { + return fmt.Sprintf("%s: %s", e.ErrorCode.String(), e.ErrorMessage) +} + +// Timeout says if this error is a timeout. +func (e *QuicError) Timeout() bool { + switch e.ErrorCode { + case NetworkIdleTimeout, + HandshakeTimeout, + TimeoutsWithOpenStreams: + return true + } + return false +} + +// ToQuicError converts an arbitrary error to a QuicError. It leaves QuicErrors +// unchanged, and properly handles `ErrorCode`s. +func ToQuicError(err error) *QuicError { + switch e := err.(type) { + case *QuicError: + return e + case ErrorCode: + return Error(e, "") + } + return Error(InternalError, err.Error()) +} diff --git a/vendor/lucas-clemente/quic-go/qerr/quic_error_test.go b/vendor/lucas-clemente/quic-go/qerr/quic_error_test.go new file mode 100644 index 00000000..58d48feb --- /dev/null +++ b/vendor/lucas-clemente/quic-go/qerr/quic_error_test.go @@ -0,0 +1,47 @@ +package qerr + +import ( + "io" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Quic error", func() { + Context("QuicError", func() { + It("has a string representation", func() { + err := Error(DecryptionFailure, "foobar") + Expect(err.Error()).To(Equal("DecryptionFailure: foobar")) + }) + }) + + Context("ErrorCode", func() { + It("works as error", func() { + var err error = DecryptionFailure + Expect(err).To(MatchError("DecryptionFailure")) + }) + }) + + Context("TimeoutError", func() { + It("works as timeout error", func() { + err := Error(HandshakeTimeout, "handshake timeout") + Expect(err.Timeout()).Should(BeTrue()) + }) + }) + + Context("ToQuicError", func() { + It("leaves QuicError unchanged", func() { + err := Error(DecryptionFailure, "foo") + Expect(ToQuicError(err)).To(Equal(err)) + }) + + It("wraps ErrorCode properly", func() { + var err error = DecryptionFailure + Expect(ToQuicError(err)).To(Equal(Error(DecryptionFailure, ""))) + }) + + It("changes default errors to InternalError", func() { + Expect(ToQuicError(io.EOF)).To(Equal(Error(InternalError, "EOF"))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/quic_suite_test.go b/vendor/lucas-clemente/quic-go/quic_suite_test.go new file mode 100644 index 00000000..fefe277f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/quic_suite_test.go @@ -0,0 +1,37 @@ +package quic + +import ( + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestQuicGo(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "QUIC Suite") +} + +const ( + versionGQUICFrames = protocol.Version39 + versionIETFFrames = protocol.VersionTLS +) + +var mockCtrl *gomock.Controller + +var _ = BeforeSuite(func() { + Expect(versionGQUICFrames.CryptoStreamID()).To(Equal(protocol.StreamID(1))) + Expect(versionGQUICFrames.UsesIETFFrameFormat()).To(BeFalse()) + Expect(versionIETFFrames.CryptoStreamID()).To(Equal(protocol.StreamID(0))) + Expect(versionIETFFrames.UsesIETFFrameFormat()).To(BeTrue()) +}) + +var _ = BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) +}) + +var _ = AfterEach(func() { + mockCtrl.Finish() +}) diff --git a/vendor/lucas-clemente/quic-go/receive_stream.go b/vendor/lucas-clemente/quic-go/receive_stream.go new file mode 100644 index 00000000..43c7bcf6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/receive_stream.go @@ -0,0 +1,304 @@ +package quic + +import ( + "fmt" + "io" + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type receiveStreamI interface { + ReceiveStream + + handleStreamFrame(*wire.StreamFrame) error + handleRstStreamFrame(*wire.RstStreamFrame) error + closeForShutdown(error) + getWindowUpdate() protocol.ByteCount +} + +type receiveStream struct { + mutex sync.Mutex + + streamID protocol.StreamID + + sender streamSender + + frameQueue *frameSorter + readOffset protocol.ByteCount + + currentFrame []byte + currentFrameIsLast bool // is the currentFrame the last frame on this stream + readPosInFrame int + + closeForShutdownErr error + cancelReadErr error + resetRemotelyErr StreamError + + closedForShutdown bool // set when CloseForShutdown() is called + finRead bool // set once we read a frame with a FinBit + canceledRead bool // set when CancelRead() is called + resetRemotely bool // set when HandleRstStreamFrame() is called + + readChan chan struct{} + readDeadline time.Time + + flowController flowcontrol.StreamFlowController + version protocol.VersionNumber +} + +var _ ReceiveStream = &receiveStream{} +var _ receiveStreamI = &receiveStream{} + +func newReceiveStream( + streamID protocol.StreamID, + sender streamSender, + flowController flowcontrol.StreamFlowController, + version protocol.VersionNumber, +) *receiveStream { + return &receiveStream{ + streamID: streamID, + sender: sender, + flowController: flowController, + frameQueue: newFrameSorter(), + readChan: make(chan struct{}, 1), + version: version, + } +} + +func (s *receiveStream) StreamID() protocol.StreamID { + return s.streamID +} + +// Read implements io.Reader. It is not thread safe! +func (s *receiveStream) Read(p []byte) (int, error) { + completed, n, err := s.readImpl(p) + if completed { + s.sender.onStreamCompleted(s.streamID) + } + return n, err +} + +func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.finRead { + return false, 0, io.EOF + } + if s.canceledRead { + return false, 0, s.cancelReadErr + } + if s.resetRemotely { + return false, 0, s.resetRemotelyErr + } + if s.closedForShutdown { + return false, 0, s.closeForShutdownErr + } + + bytesRead := 0 + for bytesRead < len(p) { + if s.currentFrame == nil || s.readPosInFrame >= len(s.currentFrame) { + s.dequeueNextFrame() + } + if s.currentFrame == nil && bytesRead > 0 { + return false, bytesRead, s.closeForShutdownErr + } + + for { + // Stop waiting on errors + if s.closedForShutdown { + return false, bytesRead, s.closeForShutdownErr + } + if s.canceledRead { + return false, bytesRead, s.cancelReadErr + } + if s.resetRemotely { + return false, bytesRead, s.resetRemotelyErr + } + + deadline := s.readDeadline + if !deadline.IsZero() && !time.Now().Before(deadline) { + return false, bytesRead, errDeadline + } + + if s.currentFrame != nil || s.currentFrameIsLast { + break + } + + s.mutex.Unlock() + if deadline.IsZero() { + <-s.readChan + } else { + select { + case <-s.readChan: + case <-time.After(time.Until(deadline)): + } + } + s.mutex.Lock() + if s.currentFrame == nil { + s.dequeueNextFrame() + } + } + + if bytesRead > len(p) { + return false, bytesRead, fmt.Errorf("BUG: bytesRead (%d) > len(p) (%d) in stream.Read", bytesRead, len(p)) + } + if s.readPosInFrame > len(s.currentFrame) { + return false, bytesRead, fmt.Errorf("BUG: readPosInFrame (%d) > frame.DataLen (%d) in stream.Read", s.readPosInFrame, len(s.currentFrame)) + } + + s.mutex.Unlock() + + m := copy(p[bytesRead:], s.currentFrame[s.readPosInFrame:]) + s.readPosInFrame += m + bytesRead += m + s.readOffset += protocol.ByteCount(m) + + s.mutex.Lock() + // when a RST_STREAM was received, the was already informed about the final byteOffset for this stream + if !s.resetRemotely { + s.flowController.AddBytesRead(protocol.ByteCount(m)) + } + // increase the flow control window, if necessary + s.flowController.MaybeQueueWindowUpdate() + + if s.readPosInFrame >= len(s.currentFrame) && s.currentFrameIsLast { + s.finRead = true + return true, bytesRead, io.EOF + } + } + return false, bytesRead, nil +} + +func (s *receiveStream) dequeueNextFrame() { + s.currentFrame, s.currentFrameIsLast = s.frameQueue.Pop() + s.readPosInFrame = 0 +} + +func (s *receiveStream) CancelRead(errorCode protocol.ApplicationErrorCode) error { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.finRead { + return nil + } + if s.canceledRead { + return nil + } + s.canceledRead = true + s.cancelReadErr = fmt.Errorf("Read on stream %d canceled with error code %d", s.streamID, errorCode) + s.signalRead() + if s.version.UsesIETFFrameFormat() { + s.sender.queueControlFrame(&wire.StopSendingFrame{ + StreamID: s.streamID, + ErrorCode: errorCode, + }) + } + return nil +} + +func (s *receiveStream) handleStreamFrame(frame *wire.StreamFrame) error { + maxOffset := frame.Offset + frame.DataLen() + if err := s.flowController.UpdateHighestReceived(maxOffset, frame.FinBit); err != nil { + return err + } + + s.mutex.Lock() + defer s.mutex.Unlock() + if err := s.frameQueue.Push(frame.Data, frame.Offset, frame.FinBit); err != nil { + return err + } + s.signalRead() + return nil +} + +func (s *receiveStream) handleRstStreamFrame(frame *wire.RstStreamFrame) error { + completed, err := s.handleRstStreamFrameImpl(frame) + if completed { + s.sender.onStreamCompleted(s.streamID) + } + return err +} + +func (s *receiveStream) handleRstStreamFrameImpl(frame *wire.RstStreamFrame) (bool /*completed */, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.closedForShutdown { + return false, nil + } + if err := s.flowController.UpdateHighestReceived(frame.ByteOffset, true); err != nil { + return false, err + } + // In gQUIC, error code 0 has a special meaning. + // The peer will reliably continue transmitting, but is not interested in reading from the stream. + // We should therefore just continue reading from the stream, until we encounter the FIN bit. + if !s.version.UsesIETFFrameFormat() && frame.ErrorCode == 0 { + return false, nil + } + + // ignore duplicate RST_STREAM frames for this stream (after checking their final offset) + if s.resetRemotely { + return false, nil + } + s.resetRemotely = true + s.resetRemotelyErr = streamCanceledError{ + errorCode: frame.ErrorCode, + error: fmt.Errorf("Stream %d was reset with error code %d", s.streamID, frame.ErrorCode), + } + s.signalRead() + return true, nil +} + +func (s *receiveStream) CloseRemote(offset protocol.ByteCount) { + s.handleStreamFrame(&wire.StreamFrame{FinBit: true, Offset: offset}) +} + +func (s *receiveStream) onClose(offset protocol.ByteCount) { + if s.canceledRead && !s.version.UsesIETFFrameFormat() { + s.sender.queueControlFrame(&wire.RstStreamFrame{ + StreamID: s.streamID, + ByteOffset: offset, + ErrorCode: 0, + }) + } +} + +func (s *receiveStream) SetReadDeadline(t time.Time) error { + s.mutex.Lock() + oldDeadline := s.readDeadline + s.readDeadline = t + s.mutex.Unlock() + // if the new deadline is before the currently set deadline, wake up Read() + if t.Before(oldDeadline) { + s.signalRead() + } + return nil +} + +// CloseForShutdown closes a stream abruptly. +// It makes Read unblock (and return the error) immediately. +// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST. +func (s *receiveStream) closeForShutdown(err error) { + s.mutex.Lock() + s.closedForShutdown = true + s.closeForShutdownErr = err + s.mutex.Unlock() + s.signalRead() +} + +func (s *receiveStream) getWindowUpdate() protocol.ByteCount { + return s.flowController.GetWindowUpdate() +} + +// signalRead performs a non-blocking send on the readChan +func (s *receiveStream) signalRead() { + select { + case s.readChan <- struct{}{}: + default: + } +} diff --git a/vendor/lucas-clemente/quic-go/receive_stream_test.go b/vendor/lucas-clemente/quic-go/receive_stream_test.go new file mode 100644 index 00000000..1b3f5c35 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/receive_stream_test.go @@ -0,0 +1,630 @@ +package quic + +import ( + "errors" + "io" + "runtime" + "time" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/mocks" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" +) + +var _ = Describe("Receive Stream", func() { + const streamID protocol.StreamID = 1337 + + var ( + str *receiveStream + strWithTimeout io.Reader // str wrapped with gbytes.TimeoutReader + mockFC *mocks.MockStreamFlowController + mockSender *MockStreamSender + ) + + BeforeEach(func() { + mockSender = NewMockStreamSender(mockCtrl) + mockFC = mocks.NewMockStreamFlowController(mockCtrl) + str = newReceiveStream(streamID, mockSender, mockFC, versionIETFFrames) + + timeout := scaleDuration(250 * time.Millisecond) + strWithTimeout = gbytes.TimeoutReader(str, timeout) + }) + + It("gets stream id", func() { + Expect(str.StreamID()).To(Equal(protocol.StreamID(1337))) + }) + + Context("reading", func() { + It("reads a single STREAM frame", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4)) + mockFC.EXPECT().MaybeQueueWindowUpdate() + frame := wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD, 0xBE, 0xEF}, + } + err := str.handleStreamFrame(&frame) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(4)) + Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) + }) + + It("reads a single STREAM frame in multiple goes", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + frame := wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD, 0xBE, 0xEF}, + } + err := str.handleStreamFrame(&frame) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 2) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(2)) + Expect(b).To(Equal([]byte{0xDE, 0xAD})) + n, err = strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(2)) + Expect(b).To(Equal([]byte{0xBE, 0xEF})) + }) + + It("reads all data available", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + frame1 := wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD}, + } + frame2 := wire.StreamFrame{ + Offset: 2, + Data: []byte{0xBE, 0xEF}, + } + err := str.handleStreamFrame(&frame1) + Expect(err).ToNot(HaveOccurred()) + err = str.handleStreamFrame(&frame2) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 6) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(4)) + Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00})) + }) + + It("assembles multiple STREAM frames", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + frame1 := wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD}, + } + frame2 := wire.StreamFrame{ + Offset: 2, + Data: []byte{0xBE, 0xEF}, + } + err := str.handleStreamFrame(&frame1) + Expect(err).ToNot(HaveOccurred()) + err = str.handleStreamFrame(&frame2) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(4)) + Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) + }) + + It("waits until data is available", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)) + mockFC.EXPECT().MaybeQueueWindowUpdate() + go func() { + defer GinkgoRecover() + frame := wire.StreamFrame{Data: []byte{0xDE, 0xAD}} + time.Sleep(10 * time.Millisecond) + err := str.handleStreamFrame(&frame) + Expect(err).ToNot(HaveOccurred()) + }() + b := make([]byte, 2) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(2)) + }) + + It("handles STREAM frames in wrong order", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + frame1 := wire.StreamFrame{ + Offset: 2, + Data: []byte{0xBE, 0xEF}, + } + frame2 := wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD}, + } + err := str.handleStreamFrame(&frame1) + Expect(err).ToNot(HaveOccurred()) + err = str.handleStreamFrame(&frame2) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(4)) + Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) + }) + + It("ignores duplicate STREAM frames", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + frame1 := wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD}, + } + frame2 := wire.StreamFrame{ + Offset: 0, + Data: []byte{0x13, 0x37}, + } + frame3 := wire.StreamFrame{ + Offset: 2, + Data: []byte{0xBE, 0xEF}, + } + err := str.handleStreamFrame(&frame1) + Expect(err).ToNot(HaveOccurred()) + err = str.handleStreamFrame(&frame2) + Expect(err).ToNot(HaveOccurred()) + err = str.handleStreamFrame(&frame3) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(4)) + Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) + }) + + It("doesn't rejects a STREAM frames with an overlapping data range", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4)) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + frame1 := wire.StreamFrame{ + Offset: 0, + Data: []byte("foob"), + } + frame2 := wire.StreamFrame{ + Offset: 2, + Data: []byte("obar"), + } + err := str.handleStreamFrame(&frame1) + Expect(err).ToNot(HaveOccurred()) + err = str.handleStreamFrame(&frame2) + Expect(err).ToNot(HaveOccurred()) + b := make([]byte, 6) + n, err := strWithTimeout.Read(b) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(6)) + Expect(b).To(Equal([]byte("foobar"))) + }) + + Context("deadlines", func() { + It("the deadline error has the right net.Error properties", func() { + Expect(errDeadline.Temporary()).To(BeTrue()) + Expect(errDeadline.Timeout()).To(BeTrue()) + Expect(errDeadline).To(MatchError("deadline exceeded")) + }) + + It("returns an error when Read is called after the deadline", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false).AnyTimes() + f := &wire.StreamFrame{Data: []byte("foobar")} + err := str.handleStreamFrame(f) + Expect(err).ToNot(HaveOccurred()) + str.SetReadDeadline(time.Now().Add(-time.Second)) + b := make([]byte, 6) + n, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + }) + + It("unblocks after the deadline", func() { + deadline := time.Now().Add(scaleDuration(50 * time.Millisecond)) + str.SetReadDeadline(deadline) + b := make([]byte, 6) + n, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(10*time.Millisecond))) + }) + + It("doesn't unblock if the deadline is changed before the first one expires", func() { + deadline1 := time.Now().Add(scaleDuration(50 * time.Millisecond)) + deadline2 := time.Now().Add(scaleDuration(100 * time.Millisecond)) + str.SetReadDeadline(deadline1) + go func() { + defer GinkgoRecover() + time.Sleep(scaleDuration(20 * time.Millisecond)) + str.SetReadDeadline(deadline2) + // make sure that this was actually execute before the deadline expires + Expect(time.Now()).To(BeTemporally("<", deadline1)) + }() + runtime.Gosched() + b := make([]byte, 10) + n, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond))) + }) + + It("unblocks earlier, when a new deadline is set", func() { + deadline1 := time.Now().Add(scaleDuration(200 * time.Millisecond)) + deadline2 := time.Now().Add(scaleDuration(50 * time.Millisecond)) + go func() { + defer GinkgoRecover() + time.Sleep(scaleDuration(10 * time.Millisecond)) + str.SetReadDeadline(deadline2) + // make sure that this was actually execute before the deadline expires + Expect(time.Now()).To(BeTemporally("<", deadline2)) + }() + str.SetReadDeadline(deadline1) + runtime.Gosched() + b := make([]byte, 10) + _, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(errDeadline)) + Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(25*time.Millisecond))) + }) + }) + + Context("closing", func() { + Context("with FIN bit", func() { + It("returns EOFs", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4)) + mockFC.EXPECT().MaybeQueueWindowUpdate() + str.handleStreamFrame(&wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD, 0xBE, 0xEF}, + FinBit: true, + }) + mockSender.EXPECT().onStreamCompleted(streamID) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(io.EOF)) + Expect(n).To(Equal(4)) + Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) + n, err = strWithTimeout.Read(b) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(io.EOF)) + }) + + It("handles out-of-order frames", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + frame1 := wire.StreamFrame{ + Offset: 2, + Data: []byte{0xBE, 0xEF}, + FinBit: true, + } + frame2 := wire.StreamFrame{ + Offset: 0, + Data: []byte{0xDE, 0xAD}, + } + err := str.handleStreamFrame(&frame1) + Expect(err).ToNot(HaveOccurred()) + err = str.handleStreamFrame(&frame2) + Expect(err).ToNot(HaveOccurred()) + mockSender.EXPECT().onStreamCompleted(streamID) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(io.EOF)) + Expect(n).To(Equal(4)) + Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF})) + n, err = strWithTimeout.Read(b) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(io.EOF)) + }) + + It("returns EOFs with partial read", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), true) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)) + mockFC.EXPECT().MaybeQueueWindowUpdate() + err := str.handleStreamFrame(&wire.StreamFrame{ + Offset: 0, + Data: []byte{0xde, 0xad}, + FinBit: true, + }) + Expect(err).ToNot(HaveOccurred()) + mockSender.EXPECT().onStreamCompleted(streamID) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(io.EOF)) + Expect(n).To(Equal(2)) + Expect(b[:n]).To(Equal([]byte{0xde, 0xad})) + }) + + It("handles immediate FINs", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(0), true) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(0)) + mockFC.EXPECT().MaybeQueueWindowUpdate() + err := str.handleStreamFrame(&wire.StreamFrame{ + Offset: 0, + FinBit: true, + }) + Expect(err).ToNot(HaveOccurred()) + mockSender.EXPECT().onStreamCompleted(streamID) + b := make([]byte, 4) + n, err := strWithTimeout.Read(b) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(io.EOF)) + }) + }) + + It("closes when CloseRemote is called", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(0), true) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(0)) + mockFC.EXPECT().MaybeQueueWindowUpdate() + str.CloseRemote(0) + mockSender.EXPECT().onStreamCompleted(streamID) + b := make([]byte, 8) + n, err := strWithTimeout.Read(b) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(io.EOF)) + }) + }) + + Context("closing for shutdown", func() { + testErr := errors.New("test error") + + It("immediately returns all reads", func() { + done := make(chan struct{}) + b := make([]byte, 4) + go func() { + defer GinkgoRecover() + n, err := strWithTimeout.Read(b) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(testErr)) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + str.closeForShutdown(testErr) + Eventually(done).Should(BeClosed()) + }) + + It("errors for all following reads", func() { + str.closeForShutdown(testErr) + b := make([]byte, 1) + n, err := strWithTimeout.Read(b) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(testErr)) + }) + }) + }) + + Context("stream cancelations", func() { + Context("canceling read", func() { + It("unblocks Read", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Read([]byte{0}) + Expect(err).To(MatchError("Read on stream 1337 canceled with error code 1234")) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + err := str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + }) + + It("doesn't allow further calls to Read", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + err := str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + _, err = strWithTimeout.Read([]byte{0}) + Expect(err).To(MatchError("Read on stream 1337 canceled with error code 1234")) + }) + + It("does nothing when CancelRead is called twice", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + err := str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + err = str.CancelRead(2345) + Expect(err).ToNot(HaveOccurred()) + _, err = strWithTimeout.Read([]byte{0}) + Expect(err).To(MatchError("Read on stream 1337 canceled with error code 1234")) + }) + + It("doesn't send a RST_STREAM frame, if the FIN was already read", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true) + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(6)) + mockFC.EXPECT().MaybeQueueWindowUpdate() + // no calls to mockSender.queueControlFrame + err := str.handleStreamFrame(&wire.StreamFrame{ + StreamID: streamID, + Data: []byte("foobar"), + FinBit: true, + }) + Expect(err).ToNot(HaveOccurred()) + mockSender.EXPECT().onStreamCompleted(streamID) + _, err = strWithTimeout.Read(make([]byte, 100)) + Expect(err).To(MatchError(io.EOF)) + err = str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + }) + + It("queues a STOP_SENDING frame, for IETF QUIC", func() { + str.version = versionIETFFrames + mockSender.EXPECT().queueControlFrame(&wire.StopSendingFrame{ + StreamID: streamID, + ErrorCode: 1234, + }) + err := str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't queue a STOP_SENDING frame, for gQUIC", func() { + str.version = versionGQUICFrames + // no calls to mockSender.queueControlFrame + err := str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("receiving RST_STREAM frames", func() { + rst := &wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 42, + ErrorCode: 1234, + } + + It("unblocks Read", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Read([]byte{0}) + Expect(err).To(MatchError("Stream 1337 was reset with error code 1234")) + Expect(err).To(BeAssignableToTypeOf(streamCanceledError{})) + Expect(err.(streamCanceledError).Canceled()).To(BeTrue()) + Expect(err.(streamCanceledError).ErrorCode()).To(Equal(protocol.ApplicationErrorCode(1234))) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + mockSender.EXPECT().onStreamCompleted(streamID) + str.handleRstStreamFrame(rst) + Eventually(done).Should(BeClosed()) + }) + + It("doesn't allow further calls to Read", func() { + mockSender.EXPECT().onStreamCompleted(streamID) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true) + err := str.handleRstStreamFrame(rst) + Expect(err).ToNot(HaveOccurred()) + _, err = strWithTimeout.Read([]byte{0}) + Expect(err).To(MatchError("Stream 1337 was reset with error code 1234")) + Expect(err).To(BeAssignableToTypeOf(streamCanceledError{})) + Expect(err.(streamCanceledError).Canceled()).To(BeTrue()) + Expect(err.(streamCanceledError).ErrorCode()).To(Equal(protocol.ApplicationErrorCode(1234))) + }) + + It("errors when receiving a RST_STREAM with an inconsistent offset", func() { + testErr := errors.New("already received a different final offset before") + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Return(testErr) + err := str.handleRstStreamFrame(rst) + Expect(err).To(MatchError(testErr)) + }) + + It("ignores duplicate RST_STREAM frames", func() { + mockSender.EXPECT().onStreamCompleted(streamID) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2) + err := str.handleRstStreamFrame(rst) + Expect(err).ToNot(HaveOccurred()) + err = str.handleRstStreamFrame(rst) + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't do anyting when it was closed for shutdown", func() { + str.closeForShutdown(nil) + err := str.handleRstStreamFrame(rst) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("for gQUIC", func() { + BeforeEach(func() { + str.version = versionGQUICFrames + }) + + It("unblocks Read when receiving a RST_STREAM frame with non-zero error code", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true) + readReturned := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Read([]byte{0}) + Expect(err).To(MatchError("Stream 1337 was reset with error code 1234")) + Expect(err).To(BeAssignableToTypeOf(streamCanceledError{})) + Expect(err.(streamCanceledError).Canceled()).To(BeTrue()) + Expect(err.(streamCanceledError).ErrorCode()).To(Equal(protocol.ApplicationErrorCode(1234))) + close(readReturned) + }() + Consistently(readReturned).ShouldNot(BeClosed()) + mockSender.EXPECT().onStreamCompleted(streamID) + err := str.handleRstStreamFrame(rst) + Expect(err).ToNot(HaveOccurred()) + Eventually(readReturned).Should(BeClosed()) + }) + + It("continues reading until the end when receiving a RST_STREAM frame with error code 0", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true).Times(2) + gomock.InOrder( + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4)), + mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)), + mockSender.EXPECT().onStreamCompleted(streamID), + ) + mockFC.EXPECT().MaybeQueueWindowUpdate().Times(2) + readReturned := make(chan struct{}) + go func() { + defer GinkgoRecover() + n, err := strWithTimeout.Read(make([]byte, 4)) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(4)) + n, err = strWithTimeout.Read(make([]byte, 4)) + Expect(err).To(MatchError(io.EOF)) + Expect(n).To(Equal(2)) + close(readReturned) + }() + Consistently(readReturned).ShouldNot(BeClosed()) + err := str.handleStreamFrame(&wire.StreamFrame{ + StreamID: streamID, + Data: []byte("foobar"), + FinBit: true, + }) + Expect(err).ToNot(HaveOccurred()) + err = str.handleRstStreamFrame(&wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 6, + ErrorCode: 0, + }) + Expect(err).ToNot(HaveOccurred()) + Eventually(readReturned).Should(BeClosed()) + }) + }) + }) + }) + + Context("flow control", func() { + It("errors when a STREAM frame causes a flow control violation", func() { + testErr := errors.New("flow control violation") + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(8), false).Return(testErr) + frame := wire.StreamFrame{ + Offset: 2, + Data: []byte("foobar"), + } + err := str.handleStreamFrame(&frame) + Expect(err).To(MatchError(testErr)) + }) + + It("gets a window update", func() { + mockFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0x100)) + Expect(str.getWindowUpdate()).To(Equal(protocol.ByteCount(0x100))) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/send_stream.go b/vendor/lucas-clemente/quic-go/send_stream.go new file mode 100644 index 00000000..eee66b6e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/send_stream.go @@ -0,0 +1,325 @@ +package quic + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type sendStreamI interface { + SendStream + handleStopSendingFrame(*wire.StopSendingFrame) + popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool) + closeForShutdown(error) + handleMaxStreamDataFrame(*wire.MaxStreamDataFrame) +} + +type sendStream struct { + mutex sync.Mutex + + ctx context.Context + ctxCancel context.CancelFunc + + streamID protocol.StreamID + sender streamSender + + writeOffset protocol.ByteCount + + cancelWriteErr error + closeForShutdownErr error + + closedForShutdown bool // set when CloseForShutdown() is called + finishedWriting bool // set once Close() is called + canceledWrite bool // set when CancelWrite() is called, or a STOP_SENDING frame is received + finSent bool // set when a STREAM_FRAME with FIN bit has b + + dataForWriting []byte + writeChan chan struct{} + writeDeadline time.Time + + flowController flowcontrol.StreamFlowController + + version protocol.VersionNumber +} + +var _ SendStream = &sendStream{} +var _ sendStreamI = &sendStream{} + +func newSendStream( + streamID protocol.StreamID, + sender streamSender, + flowController flowcontrol.StreamFlowController, + version protocol.VersionNumber, +) *sendStream { + s := &sendStream{ + streamID: streamID, + sender: sender, + flowController: flowController, + writeChan: make(chan struct{}, 1), + version: version, + } + s.ctx, s.ctxCancel = context.WithCancel(context.Background()) + return s +} + +func (s *sendStream) StreamID() protocol.StreamID { + return s.streamID // same for receiveStream and sendStream +} + +func (s *sendStream) Write(p []byte) (int, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.finishedWriting { + return 0, fmt.Errorf("write on closed stream %d", s.streamID) + } + if s.canceledWrite { + return 0, s.cancelWriteErr + } + if s.closeForShutdownErr != nil { + return 0, s.closeForShutdownErr + } + if !s.writeDeadline.IsZero() && !time.Now().Before(s.writeDeadline) { + return 0, errDeadline + } + if len(p) == 0 { + return 0, nil + } + + s.dataForWriting = make([]byte, len(p)) + copy(s.dataForWriting, p) + s.sender.onHasStreamData(s.streamID) + + var bytesWritten int + var err error + for { + bytesWritten = len(p) - len(s.dataForWriting) + deadline := s.writeDeadline + if !deadline.IsZero() && !time.Now().Before(deadline) { + s.dataForWriting = nil + err = errDeadline + break + } + if s.dataForWriting == nil || s.canceledWrite || s.closedForShutdown { + break + } + + s.mutex.Unlock() + if deadline.IsZero() { + <-s.writeChan + } else { + select { + case <-s.writeChan: + case <-time.After(time.Until(deadline)): + } + } + s.mutex.Lock() + } + + if s.closeForShutdownErr != nil { + err = s.closeForShutdownErr + } else if s.cancelWriteErr != nil { + err = s.cancelWriteErr + } + return bytesWritten, err +} + +// popStreamFrame returns the next STREAM frame that is supposed to be sent on this stream +// maxBytes is the maximum length this frame (including frame header) will have. +func (s *sendStream) popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool /* has more data to send */) { + completed, frame, hasMoreData := s.popStreamFrameImpl(maxBytes) + if completed { + s.sender.onStreamCompleted(s.streamID) + } + return frame, hasMoreData +} + +func (s *sendStream) popStreamFrameImpl(maxBytes protocol.ByteCount) (bool /* completed */, *wire.StreamFrame, bool /* has more data to send */) { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.closeForShutdownErr != nil { + return false, nil, false + } + + frame := &wire.StreamFrame{ + StreamID: s.streamID, + Offset: s.writeOffset, + DataLenPresent: true, + } + maxDataLen := frame.MaxDataLen(maxBytes, s.version) + if maxDataLen == 0 { // a STREAM frame must have at least one byte of data + return false, nil, s.dataForWriting != nil + } + frame.Data, frame.FinBit = s.getDataForWriting(maxDataLen) + if len(frame.Data) == 0 && !frame.FinBit { + // this can happen if: + // - popStreamFrame is called but there's no data for writing + // - there's data for writing, but the stream is stream-level flow control blocked + // - there's data for writing, but the stream is connection-level flow control blocked + if s.dataForWriting == nil { + return false, nil, false + } + if isBlocked, offset := s.flowController.IsNewlyBlocked(); isBlocked { + s.sender.queueControlFrame(&wire.StreamBlockedFrame{ + StreamID: s.streamID, + Offset: offset, + }) + return false, nil, false + } + return false, nil, true + } + if frame.FinBit { + s.finSent = true + } + return frame.FinBit, frame, s.dataForWriting != nil +} + +func (s *sendStream) getDataForWriting(maxBytes protocol.ByteCount) ([]byte, bool /* should send FIN */) { + if s.dataForWriting == nil { + return nil, s.finishedWriting && !s.finSent + } + + // TODO(#657): Flow control for the crypto stream + if s.streamID != s.version.CryptoStreamID() { + maxBytes = utils.MinByteCount(maxBytes, s.flowController.SendWindowSize()) + } + if maxBytes == 0 { + return nil, false + } + + var ret []byte + if protocol.ByteCount(len(s.dataForWriting)) > maxBytes { + ret = s.dataForWriting[:maxBytes] + s.dataForWriting = s.dataForWriting[maxBytes:] + } else { + ret = s.dataForWriting + s.dataForWriting = nil + s.signalWrite() + } + s.writeOffset += protocol.ByteCount(len(ret)) + s.flowController.AddBytesSent(protocol.ByteCount(len(ret))) + return ret, s.finishedWriting && s.dataForWriting == nil && !s.finSent +} + +func (s *sendStream) Close() error { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.canceledWrite { + return fmt.Errorf("Close called for canceled stream %d", s.streamID) + } + s.finishedWriting = true + s.sender.onHasStreamData(s.streamID) // need to send the FIN + s.ctxCancel() + return nil +} + +func (s *sendStream) CancelWrite(errorCode protocol.ApplicationErrorCode) error { + s.mutex.Lock() + completed, err := s.cancelWriteImpl(errorCode, fmt.Errorf("Write on stream %d canceled with error code %d", s.streamID, errorCode)) + s.mutex.Unlock() + + if completed { + s.sender.onStreamCompleted(s.streamID) + } + return err +} + +// must be called after locking the mutex +func (s *sendStream) cancelWriteImpl(errorCode protocol.ApplicationErrorCode, writeErr error) (bool /*completed */, error) { + if s.canceledWrite { + return false, nil + } + if s.finishedWriting { + return false, fmt.Errorf("CancelWrite for closed stream %d", s.streamID) + } + s.canceledWrite = true + s.cancelWriteErr = writeErr + s.signalWrite() + s.sender.queueControlFrame(&wire.RstStreamFrame{ + StreamID: s.streamID, + ByteOffset: s.writeOffset, + ErrorCode: errorCode, + }) + // TODO(#991): cancel retransmissions for this stream + s.ctxCancel() + return true, nil +} + +func (s *sendStream) handleStopSendingFrame(frame *wire.StopSendingFrame) { + if completed := s.handleStopSendingFrameImpl(frame); completed { + s.sender.onStreamCompleted(s.streamID) + } +} + +func (s *sendStream) handleMaxStreamDataFrame(frame *wire.MaxStreamDataFrame) { + s.flowController.UpdateSendWindow(frame.ByteOffset) + s.mutex.Lock() + if s.dataForWriting != nil { + s.sender.onHasStreamData(s.streamID) + } + s.mutex.Unlock() +} + +// must be called after locking the mutex +func (s *sendStream) handleStopSendingFrameImpl(frame *wire.StopSendingFrame) bool /*completed*/ { + s.mutex.Lock() + defer s.mutex.Unlock() + + writeErr := streamCanceledError{ + errorCode: frame.ErrorCode, + error: fmt.Errorf("Stream %d was reset with error code %d", s.streamID, frame.ErrorCode), + } + errorCode := errorCodeStopping + if !s.version.UsesIETFFrameFormat() { + errorCode = errorCodeStoppingGQUIC + } + completed, _ := s.cancelWriteImpl(errorCode, writeErr) + return completed +} + +func (s *sendStream) Context() context.Context { + return s.ctx +} + +func (s *sendStream) SetWriteDeadline(t time.Time) error { + s.mutex.Lock() + oldDeadline := s.writeDeadline + s.writeDeadline = t + s.mutex.Unlock() + if t.Before(oldDeadline) { + s.signalWrite() + } + return nil +} + +// CloseForShutdown closes a stream abruptly. +// It makes Write unblock (and return the error) immediately. +// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST. +func (s *sendStream) closeForShutdown(err error) { + s.mutex.Lock() + s.closedForShutdown = true + s.closeForShutdownErr = err + s.mutex.Unlock() + s.signalWrite() + s.ctxCancel() +} + +func (s *sendStream) getWriteOffset() protocol.ByteCount { + return s.writeOffset +} + +// signalWrite performs a non-blocking send on the writeChan +func (s *sendStream) signalWrite() { + select { + case s.writeChan <- struct{}{}: + default: + } +} diff --git a/vendor/lucas-clemente/quic-go/send_stream_test.go b/vendor/lucas-clemente/quic-go/send_stream_test.go new file mode 100644 index 00000000..76aabda1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/send_stream_test.go @@ -0,0 +1,599 @@ +package quic + +import ( + "bytes" + "errors" + "io" + "runtime" + "time" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/mocks" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" +) + +var _ = Describe("Send Stream", func() { + const streamID protocol.StreamID = 1337 + + var ( + str *sendStream + strWithTimeout io.Writer // str wrapped with gbytes.TimeoutWriter + mockFC *mocks.MockStreamFlowController + mockSender *MockStreamSender + ) + + BeforeEach(func() { + mockSender = NewMockStreamSender(mockCtrl) + mockFC = mocks.NewMockStreamFlowController(mockCtrl) + str = newSendStream(streamID, mockSender, mockFC, protocol.VersionWhatever) + + timeout := scaleDuration(250 * time.Millisecond) + strWithTimeout = gbytes.TimeoutWriter(str, timeout) + }) + + waitForWrite := func() { + EventuallyWithOffset(0, func() []byte { + str.mutex.Lock() + data := str.dataForWriting + str.mutex.Unlock() + return data + }).ShouldNot(BeEmpty()) + } + + It("gets stream id", func() { + Expect(str.StreamID()).To(Equal(protocol.StreamID(1337))) + }) + + Context("writing", func() { + It("writes and gets all data at once", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(9999)) + mockFC.EXPECT().AddBytesSent(protocol.ByteCount(6)) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + n, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(6)) + close(done) + }() + waitForWrite() + f, _ := str.popStreamFrame(1000) + Expect(f.Data).To(Equal([]byte("foobar"))) + Expect(f.FinBit).To(BeFalse()) + Expect(f.Offset).To(BeZero()) + Expect(f.DataLenPresent).To(BeTrue()) + Expect(str.writeOffset).To(Equal(protocol.ByteCount(6))) + Expect(str.dataForWriting).To(BeNil()) + Eventually(done).Should(BeClosed()) + }) + + It("writes and gets data in two turns", func() { + mockSender.EXPECT().onHasStreamData(streamID) + frameHeaderLen := protocol.ByteCount(4) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(9999)).Times(2) + mockFC.EXPECT().AddBytesSent(gomock.Any() /* protocol.ByteCount(3)*/).Times(2) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + n, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(6)) + close(done) + }() + waitForWrite() + f, _ := str.popStreamFrame(3 + frameHeaderLen) + Expect(f.Data).To(Equal([]byte("foo"))) + Expect(f.FinBit).To(BeFalse()) + Expect(f.Offset).To(BeZero()) + Expect(f.DataLenPresent).To(BeTrue()) + f, _ = str.popStreamFrame(100) + Expect(f.Data).To(Equal([]byte("bar"))) + Expect(f.FinBit).To(BeFalse()) + Expect(f.Offset).To(Equal(protocol.ByteCount(3))) + Expect(f.DataLenPresent).To(BeTrue()) + Expect(str.popStreamFrame(1000)).To(BeNil()) + Eventually(done).Should(BeClosed()) + }) + + It("popStreamFrame returns nil if no data is available", func() { + frame, hasMoreData := str.popStreamFrame(1000) + Expect(frame).To(BeNil()) + Expect(hasMoreData).To(BeFalse()) + }) + + It("says if it has more data for writing", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(9999)).Times(2) + mockFC.EXPECT().AddBytesSent(gomock.Any()).Times(2) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + n, err := strWithTimeout.Write(bytes.Repeat([]byte{0}, 100)) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(100)) + close(done) + }() + waitForWrite() + frame, hasMoreData := str.popStreamFrame(50) + Expect(frame).ToNot(BeNil()) + Expect(hasMoreData).To(BeTrue()) + frame, hasMoreData = str.popStreamFrame(1000) + Expect(frame).ToNot(BeNil()) + Expect(hasMoreData).To(BeFalse()) + frame, _ = str.popStreamFrame(1000) + Expect(frame).To(BeNil()) + Eventually(done).Should(BeClosed()) + }) + + It("copies the slice while writing", func() { + mockSender.EXPECT().onHasStreamData(streamID) + frameHeaderSize := protocol.ByteCount(4) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(9999)).Times(2) + mockFC.EXPECT().AddBytesSent(protocol.ByteCount(1)) + mockFC.EXPECT().AddBytesSent(protocol.ByteCount(2)) + s := []byte("foo") + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + n, err := strWithTimeout.Write(s) + Expect(err).ToNot(HaveOccurred()) + Expect(n).To(Equal(3)) + close(done) + }() + waitForWrite() + frame, _ := str.popStreamFrame(frameHeaderSize + 1) + Expect(frame.Data).To(Equal([]byte("f"))) + s[1] = 'e' + f, _ := str.popStreamFrame(100) + Expect(f).ToNot(BeNil()) + Expect(f.Data).To(Equal([]byte("oo"))) + Eventually(done).Should(BeClosed()) + }) + + It("returns when given a nil input", func() { + n, err := strWithTimeout.Write(nil) + Expect(n).To(BeZero()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("returns when given an empty slice", func() { + n, err := strWithTimeout.Write([]byte("")) + Expect(n).To(BeZero()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("cancels the context when Close is called", func() { + mockSender.EXPECT().onHasStreamData(streamID) + Expect(str.Context().Done()).ToNot(BeClosed()) + str.Close() + Expect(str.Context().Done()).To(BeClosed()) + }) + + Context("flow control blocking", func() { + It("queues a BLOCKED frame if the stream is flow control blocked", func() { + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(0)) + mockFC.EXPECT().IsNewlyBlocked().Return(true, protocol.ByteCount(12)) + mockSender.EXPECT().queueControlFrame(&wire.StreamBlockedFrame{ + StreamID: streamID, + Offset: 12, + }) + mockSender.EXPECT().onHasStreamData(streamID) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := str.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + waitForWrite() + f, hasMoreData := str.popStreamFrame(1000) + Expect(f).To(BeNil()) + Expect(hasMoreData).To(BeFalse()) + // make the Write go routine return + str.closeForShutdown(nil) + Eventually(done).Should(BeClosed()) + }) + + It("says that it doesn't have any more data, when it is flow control blocked", func() { + frameHeaderSize := protocol.ByteCount(4) + mockSender.EXPECT().onHasStreamData(streamID) + + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := str.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + waitForWrite() + + // first pop a STREAM frame of the maximum size allowed by flow control + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(3)) + mockFC.EXPECT().AddBytesSent(protocol.ByteCount(3)) + f, hasMoreData := str.popStreamFrame(frameHeaderSize + 3) + Expect(f).ToNot(BeNil()) + Expect(hasMoreData).To(BeTrue()) + + // try to pop again, this time noticing that we're blocked + mockFC.EXPECT().SendWindowSize() + // don't use offset 3 here, to make sure the BLOCKED frame contains the number returned by the flow controller + mockFC.EXPECT().IsNewlyBlocked().Return(true, protocol.ByteCount(10)) + mockSender.EXPECT().queueControlFrame(&wire.StreamBlockedFrame{ + StreamID: streamID, + Offset: 10, + }) + f, hasMoreData = str.popStreamFrame(1000) + Expect(f).To(BeNil()) + Expect(hasMoreData).To(BeFalse()) + // make the Write go routine return + str.closeForShutdown(nil) + Eventually(done).Should(BeClosed()) + }) + }) + + Context("deadlines", func() { + It("returns an error when Write is called after the deadline", func() { + str.SetWriteDeadline(time.Now().Add(-time.Second)) + n, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + }) + + It("unblocks after the deadline", func() { + mockSender.EXPECT().onHasStreamData(streamID) + deadline := time.Now().Add(scaleDuration(50 * time.Millisecond)) + str.SetWriteDeadline(deadline) + n, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(20*time.Millisecond))) + }) + + It("returns the number of bytes written, when the deadline expires", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(10000)).AnyTimes() + mockFC.EXPECT().AddBytesSent(gomock.Any()) + deadline := time.Now().Add(scaleDuration(50 * time.Millisecond)) + str.SetWriteDeadline(deadline) + var n int + writeReturned := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + n, err = strWithTimeout.Write(bytes.Repeat([]byte{0}, 100)) + Expect(err).To(MatchError(errDeadline)) + Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(20*time.Millisecond))) + close(writeReturned) + }() + waitForWrite() + frame, hasMoreData := str.popStreamFrame(50) + Expect(frame).ToNot(BeNil()) + Expect(hasMoreData).To(BeTrue()) + Eventually(writeReturned, scaleDuration(80*time.Millisecond)).Should(BeClosed()) + Expect(n).To(BeEquivalentTo(frame.DataLen())) + }) + + It("doesn't pop any data after the deadline expired", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(10000)).AnyTimes() + mockFC.EXPECT().AddBytesSent(gomock.Any()) + deadline := time.Now().Add(scaleDuration(50 * time.Millisecond)) + str.SetWriteDeadline(deadline) + writeReturned := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Write(bytes.Repeat([]byte{0}, 100)) + Expect(err).To(MatchError(errDeadline)) + close(writeReturned) + }() + waitForWrite() + frame, hasMoreData := str.popStreamFrame(50) + Expect(frame).ToNot(BeNil()) + Expect(hasMoreData).To(BeTrue()) + Eventually(writeReturned, scaleDuration(80*time.Millisecond)).Should(BeClosed()) + frame, hasMoreData = str.popStreamFrame(50) + Expect(frame).To(BeNil()) + Expect(hasMoreData).To(BeFalse()) + }) + + It("doesn't unblock if the deadline is changed before the first one expires", func() { + mockSender.EXPECT().onHasStreamData(streamID) + deadline1 := time.Now().Add(scaleDuration(50 * time.Millisecond)) + deadline2 := time.Now().Add(scaleDuration(100 * time.Millisecond)) + str.SetWriteDeadline(deadline1) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + time.Sleep(scaleDuration(20 * time.Millisecond)) + str.SetWriteDeadline(deadline2) + // make sure that this was actually execute before the deadline expires + Expect(time.Now()).To(BeTemporally("<", deadline1)) + close(done) + }() + runtime.Gosched() + n, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond))) + Eventually(done).Should(BeClosed()) + }) + + It("unblocks earlier, when a new deadline is set", func() { + mockSender.EXPECT().onHasStreamData(streamID) + deadline1 := time.Now().Add(scaleDuration(200 * time.Millisecond)) + deadline2 := time.Now().Add(scaleDuration(50 * time.Millisecond)) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + time.Sleep(scaleDuration(10 * time.Millisecond)) + str.SetWriteDeadline(deadline2) + // make sure that this was actually execute before the deadline expires + Expect(time.Now()).To(BeTemporally("<", deadline2)) + close(done) + }() + str.SetWriteDeadline(deadline1) + runtime.Gosched() + _, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError(errDeadline)) + Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond))) + Eventually(done).Should(BeClosed()) + }) + }) + + Context("closing", func() { + It("doesn't allow writes after it has been closed", func() { + mockSender.EXPECT().onHasStreamData(streamID) + str.Close() + _, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError("write on closed stream 1337")) + }) + + It("allows FIN", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockSender.EXPECT().onStreamCompleted(streamID) + str.Close() + f, hasMoreData := str.popStreamFrame(1000) + Expect(f).ToNot(BeNil()) + Expect(f.Data).To(BeEmpty()) + Expect(f.FinBit).To(BeTrue()) + Expect(hasMoreData).To(BeFalse()) + }) + + It("doesn't send a FIN when there's still data", func() { + mockSender.EXPECT().onHasStreamData(streamID) + frameHeaderLen := protocol.ByteCount(4) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(9999)).Times(2) + mockFC.EXPECT().AddBytesSent(gomock.Any()).Times(2) + str.dataForWriting = []byte("foobar") + Expect(str.Close()).To(Succeed()) + f, _ := str.popStreamFrame(3 + frameHeaderLen) + Expect(f).ToNot(BeNil()) + Expect(f.Data).To(Equal([]byte("foo"))) + Expect(f.FinBit).To(BeFalse()) + mockSender.EXPECT().onStreamCompleted(streamID) + f, _ = str.popStreamFrame(100) + Expect(f.Data).To(Equal([]byte("bar"))) + Expect(f.FinBit).To(BeTrue()) + }) + + It("doesn't allow FIN after it is closed for shutdown", func() { + str.closeForShutdown(errors.New("test")) + f, hasMoreData := str.popStreamFrame(1000) + Expect(f).To(BeNil()) + Expect(hasMoreData).To(BeFalse()) + }) + + It("doesn't allow FIN twice", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockSender.EXPECT().onStreamCompleted(streamID) + str.Close() + f, _ := str.popStreamFrame(1000) + Expect(f).ToNot(BeNil()) + Expect(f.Data).To(BeEmpty()) + Expect(f.FinBit).To(BeTrue()) + f, hasMoreData := str.popStreamFrame(1000) + Expect(f).To(BeNil()) + Expect(hasMoreData).To(BeFalse()) + }) + }) + + Context("closing for shutdown", func() { + testErr := errors.New("test") + + It("returns errors when the stream is cancelled", func() { + str.closeForShutdown(testErr) + n, err := strWithTimeout.Write([]byte("foo")) + Expect(n).To(BeZero()) + Expect(err).To(MatchError(testErr)) + }) + + It("doesn't get data for writing if an error occurred", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(9999)) + mockFC.EXPECT().AddBytesSent(gomock.Any()) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Write(bytes.Repeat([]byte{0}, 500)) + Expect(err).To(MatchError(testErr)) + close(done) + }() + waitForWrite() + frame, hasMoreData := str.popStreamFrame(50) // get a STREAM frame containing some data, but not all + Expect(frame).ToNot(BeNil()) + Expect(hasMoreData).To(BeTrue()) + str.closeForShutdown(testErr) + frame, hasMoreData = str.popStreamFrame(1000) + Expect(frame).To(BeNil()) + Expect(hasMoreData).To(BeFalse()) + Eventually(done).Should(BeClosed()) + }) + + It("cancels the context", func() { + Expect(str.Context().Done()).ToNot(BeClosed()) + str.closeForShutdown(testErr) + Expect(str.Context().Done()).To(BeClosed()) + }) + }) + }) + + Context("handling MAX_STREAM_DATA frames", func() { + It("informs the flow controller", func() { + mockFC.EXPECT().UpdateSendWindow(protocol.ByteCount(0x1337)) + str.handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{ + StreamID: streamID, + ByteOffset: 0x1337, + }) + }) + + It("says when it has data for sending", func() { + mockFC.EXPECT().UpdateSendWindow(gomock.Any()) + mockSender.EXPECT().onHasStreamData(streamID).Times(2) // once for Write, once for the MAX_STREAM_DATA frame + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := str.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + waitForWrite() + str.handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{ + StreamID: streamID, + ByteOffset: 42, + }) + // make sure the Write go routine returns + str.closeForShutdown(nil) + Eventually(done).Should(BeClosed()) + }) + }) + + Context("stream cancelations", func() { + Context("canceling writing", func() { + It("queues a RST_STREAM frame", func() { + mockSender.EXPECT().queueControlFrame(&wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 1234, + ErrorCode: 9876, + }) + mockSender.EXPECT().onStreamCompleted(streamID) + str.writeOffset = 1234 + err := str.CancelWrite(9876) + Expect(err).ToNot(HaveOccurred()) + }) + + It("unblocks Write", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockSender.EXPECT().onStreamCompleted(streamID) + mockSender.EXPECT().queueControlFrame(gomock.Any()) + mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount) + mockFC.EXPECT().AddBytesSent(gomock.Any()) + writeReturned := make(chan struct{}) + var n int + go func() { + defer GinkgoRecover() + var err error + n, err = strWithTimeout.Write(bytes.Repeat([]byte{0}, 100)) + Expect(err).To(MatchError("Write on stream 1337 canceled with error code 1234")) + close(writeReturned) + }() + waitForWrite() + frame, _ := str.popStreamFrame(50) + Expect(frame).ToNot(BeNil()) + err := str.CancelWrite(1234) + Expect(err).ToNot(HaveOccurred()) + Eventually(writeReturned).Should(BeClosed()) + Expect(n).To(BeEquivalentTo(frame.DataLen())) + }) + + It("cancels the context", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + mockSender.EXPECT().onStreamCompleted(streamID) + Expect(str.Context().Done()).ToNot(BeClosed()) + str.CancelWrite(1234) + Expect(str.Context().Done()).To(BeClosed()) + }) + + It("doesn't allow further calls to Write", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + mockSender.EXPECT().onStreamCompleted(streamID) + err := str.CancelWrite(1234) + Expect(err).ToNot(HaveOccurred()) + _, err = strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError("Write on stream 1337 canceled with error code 1234")) + }) + + It("only cancels once", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + mockSender.EXPECT().onStreamCompleted(streamID) + err := str.CancelWrite(1234) + Expect(err).ToNot(HaveOccurred()) + err = str.CancelWrite(4321) + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't cancel when the stream was already closed", func() { + mockSender.EXPECT().onHasStreamData(streamID) + err := str.Close() + Expect(err).ToNot(HaveOccurred()) + err = str.CancelWrite(123) + Expect(err).To(MatchError("CancelWrite for closed stream 1337")) + }) + }) + + Context("receiving STOP_SENDING frames", func() { + It("queues a RST_STREAM frames with error code Stopping", func() { + mockSender.EXPECT().queueControlFrame(&wire.RstStreamFrame{ + StreamID: streamID, + ErrorCode: errorCodeStopping, + }) + mockSender.EXPECT().onStreamCompleted(streamID) + str.handleStopSendingFrame(&wire.StopSendingFrame{ + StreamID: streamID, + ErrorCode: 101, + }) + }) + + It("unblocks Write", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockSender.EXPECT().queueControlFrame(gomock.Any()) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := str.Write([]byte("foobar")) + Expect(err).To(MatchError("Stream 1337 was reset with error code 123")) + Expect(err).To(BeAssignableToTypeOf(streamCanceledError{})) + Expect(err.(streamCanceledError).Canceled()).To(BeTrue()) + Expect(err.(streamCanceledError).ErrorCode()).To(Equal(protocol.ApplicationErrorCode(123))) + close(done) + }() + waitForWrite() + mockSender.EXPECT().onStreamCompleted(streamID) + str.handleStopSendingFrame(&wire.StopSendingFrame{ + StreamID: streamID, + ErrorCode: 123, + }) + Eventually(done).Should(BeClosed()) + }) + + It("doesn't allow further calls to Write", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + mockSender.EXPECT().onStreamCompleted(streamID) + str.handleStopSendingFrame(&wire.StopSendingFrame{ + StreamID: streamID, + ErrorCode: 123, + }) + _, err := str.Write([]byte("foobar")) + Expect(err).To(MatchError("Stream 1337 was reset with error code 123")) + Expect(err).To(BeAssignableToTypeOf(streamCanceledError{})) + Expect(err.(streamCanceledError).Canceled()).To(BeTrue()) + Expect(err.(streamCanceledError).ErrorCode()).To(Equal(protocol.ApplicationErrorCode(123))) + }) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/server.go b/vendor/lucas-clemente/quic-go/server.go new file mode 100644 index 00000000..d9af6a43 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/server.go @@ -0,0 +1,420 @@ +package quic + +import ( + "crypto/tls" + "errors" + "fmt" + "io" + "net" + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +// packetHandler handles packets +type packetHandler interface { + handlePacket(*receivedPacket) + io.Closer + destroy(error) + GetVersion() protocol.VersionNumber + GetPerspective() protocol.Perspective +} + +type unknownPacketHandler interface { + handlePacket(*receivedPacket) + closeWithError(error) error +} + +type packetHandlerManager interface { + Add(protocol.ConnectionID, packetHandler) + SetServer(unknownPacketHandler) + Remove(protocol.ConnectionID) + CloseServer() +} + +type quicSession interface { + Session + handlePacket(*receivedPacket) + GetVersion() protocol.VersionNumber + run() error + destroy(error) + closeRemote(error) +} + +type sessionRunner interface { + onHandshakeComplete(Session) + removeConnectionID(protocol.ConnectionID) +} + +type runner struct { + onHandshakeCompleteImpl func(Session) + removeConnectionIDImpl func(protocol.ConnectionID) +} + +func (r *runner) onHandshakeComplete(s Session) { r.onHandshakeCompleteImpl(s) } +func (r *runner) removeConnectionID(c protocol.ConnectionID) { r.removeConnectionIDImpl(c) } + +var _ sessionRunner = &runner{} + +// A Listener of QUIC +type server struct { + mutex sync.Mutex + + tlsConf *tls.Config + config *Config + + conn net.PacketConn + // If the server is started with ListenAddr, we create a packet conn. + // If it is started with Listen, we take a packet conn as a parameter. + createdPacketConn bool + + supportsTLS bool + serverTLS *serverTLS + + certChain crypto.CertChain + scfg *handshake.ServerConfig + + sessionHandler packetHandlerManager + + serverError error + errorChan chan struct{} + closed bool + + sessionQueue chan Session + + sessionRunner sessionRunner + // set as a member, so they can be set in the tests + newSession func(connection, sessionRunner, protocol.VersionNumber, protocol.ConnectionID, protocol.ConnectionID, *handshake.ServerConfig, *tls.Config, *Config, utils.Logger) (quicSession, error) + + logger utils.Logger +} + +var _ Listener = &server{} +var _ unknownPacketHandler = &server{} + +// ListenAddr creates a QUIC server listening on a given address. +// The tls.Config must not be nil, the quic.Config may be nil. +func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (Listener, error) { + udpAddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + return nil, err + } + conn, err := net.ListenUDP("udp", udpAddr) + if err != nil { + return nil, err + } + serv, err := listen(conn, tlsConf, config) + if err != nil { + return nil, err + } + serv.createdPacketConn = true + return serv, nil +} + +// Listen listens for QUIC connections on a given net.PacketConn. +// The tls.Config must not be nil, the quic.Config may be nil. +func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener, error) { + return listen(conn, tlsConf, config) +} + +func listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*server, error) { + certChain := crypto.NewCertChain(tlsConf) + kex, err := crypto.NewCurve25519KEX() + if err != nil { + return nil, err + } + scfg, err := handshake.NewServerConfig(kex, certChain) + if err != nil { + return nil, err + } + config = populateServerConfig(config) + + var supportsTLS bool + for _, v := range config.Versions { + if !protocol.IsValidVersion(v) { + return nil, fmt.Errorf("%s is not a valid QUIC version", v) + } + // check if any of the supported versions supports TLS + if v.UsesTLS() { + supportsTLS = true + break + } + } + + sessionHandler, err := getMultiplexer().AddConn(conn, config.ConnectionIDLength) + if err != nil { + return nil, err + } + s := &server{ + conn: conn, + tlsConf: tlsConf, + config: config, + certChain: certChain, + scfg: scfg, + newSession: newSession, + sessionHandler: sessionHandler, + sessionQueue: make(chan Session, 5), + errorChan: make(chan struct{}), + supportsTLS: supportsTLS, + logger: utils.DefaultLogger.WithPrefix("server"), + } + s.setup() + if supportsTLS { + if err := s.setupTLS(); err != nil { + return nil, err + } + } + sessionHandler.SetServer(s) + s.logger.Debugf("Listening for %s connections on %s", conn.LocalAddr().Network(), conn.LocalAddr().String()) + return s, nil +} + +func (s *server) setup() { + s.sessionRunner = &runner{ + onHandshakeCompleteImpl: func(sess Session) { s.sessionQueue <- sess }, + removeConnectionIDImpl: s.sessionHandler.Remove, + } +} + +func (s *server) setupTLS() error { + serverTLS, sessionChan, err := newServerTLS(s.conn, s.config, s.sessionRunner, s.tlsConf, s.logger) + if err != nil { + return err + } + s.serverTLS = serverTLS + // handle TLS connection establishment statelessly + go func() { + for { + select { + case <-s.errorChan: + return + case tlsSession := <-sessionChan: + // The connection ID is a randomly chosen value. + // It is safe to assume that it doesn't collide with other randomly chosen values. + serverSession := newServerSession(tlsSession.sess, s.config, s.logger) + s.sessionHandler.Add(tlsSession.connID, serverSession) + } + } + }() + return nil +} + +var defaultAcceptCookie = func(clientAddr net.Addr, cookie *Cookie) bool { + if cookie == nil { + return false + } + if time.Now().After(cookie.SentTime.Add(protocol.CookieExpiryTime)) { + return false + } + var sourceAddr string + if udpAddr, ok := clientAddr.(*net.UDPAddr); ok { + sourceAddr = udpAddr.IP.String() + } else { + sourceAddr = clientAddr.String() + } + return sourceAddr == cookie.RemoteAddr +} + +// populateServerConfig populates fields in the quic.Config with their default values, if none are set +// it may be called with nil +func populateServerConfig(config *Config) *Config { + if config == nil { + config = &Config{} + } + versions := config.Versions + if len(versions) == 0 { + versions = protocol.SupportedVersions + } + + vsa := defaultAcceptCookie + if config.AcceptCookie != nil { + vsa = config.AcceptCookie + } + + handshakeTimeout := protocol.DefaultHandshakeTimeout + if config.HandshakeTimeout != 0 { + handshakeTimeout = config.HandshakeTimeout + } + idleTimeout := protocol.DefaultIdleTimeout + if config.IdleTimeout != 0 { + idleTimeout = config.IdleTimeout + } + + maxReceiveStreamFlowControlWindow := config.MaxReceiveStreamFlowControlWindow + if maxReceiveStreamFlowControlWindow == 0 { + maxReceiveStreamFlowControlWindow = protocol.DefaultMaxReceiveStreamFlowControlWindowServer + } + maxReceiveConnectionFlowControlWindow := config.MaxReceiveConnectionFlowControlWindow + if maxReceiveConnectionFlowControlWindow == 0 { + maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindowServer + } + maxIncomingStreams := config.MaxIncomingStreams + if maxIncomingStreams == 0 { + maxIncomingStreams = protocol.DefaultMaxIncomingStreams + } else if maxIncomingStreams < 0 { + maxIncomingStreams = 0 + } + maxIncomingUniStreams := config.MaxIncomingUniStreams + if maxIncomingUniStreams == 0 { + maxIncomingUniStreams = protocol.DefaultMaxIncomingUniStreams + } else if maxIncomingUniStreams < 0 { + maxIncomingUniStreams = 0 + } + connIDLen := config.ConnectionIDLength + if connIDLen == 0 { + connIDLen = protocol.DefaultConnectionIDLength + } + for _, v := range versions { + if v == protocol.Version44 { + connIDLen = protocol.ConnectionIDLenGQUIC + } + } + + return &Config{ + Versions: versions, + HandshakeTimeout: handshakeTimeout, + IdleTimeout: idleTimeout, + AcceptCookie: vsa, + KeepAlive: config.KeepAlive, + MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, + MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, + MaxIncomingStreams: maxIncomingStreams, + MaxIncomingUniStreams: maxIncomingUniStreams, + ConnectionIDLength: connIDLen, + } +} + +// Accept returns newly openend sessions +func (s *server) Accept() (Session, error) { + var sess Session + select { + case sess = <-s.sessionQueue: + return sess, nil + case <-s.errorChan: + return nil, s.serverError + } +} + +// Close the server +func (s *server) Close() error { + s.mutex.Lock() + defer s.mutex.Unlock() + if s.closed { + return nil + } + return s.closeWithMutex() +} + +func (s *server) closeWithMutex() error { + s.sessionHandler.CloseServer() + if s.serverError == nil { + s.serverError = errors.New("server closed") + } + var err error + // If the server was started with ListenAddr, we created the packet conn. + // We need to close it in order to make the go routine reading from that conn return. + if s.createdPacketConn { + err = s.conn.Close() + } + s.closed = true + close(s.errorChan) + return err +} + +func (s *server) closeWithError(e error) error { + s.mutex.Lock() + defer s.mutex.Unlock() + if s.closed { + return nil + } + s.serverError = e + return s.closeWithMutex() +} + +// Addr returns the server's network address +func (s *server) Addr() net.Addr { + return s.conn.LocalAddr() +} + +func (s *server) handlePacket(p *receivedPacket) { + if err := s.handlePacketImpl(p); err != nil { + s.logger.Debugf("error handling packet from %s: %s", p.remoteAddr, err) + } +} + +func (s *server) handlePacketImpl(p *receivedPacket) error { + hdr := p.header + + if hdr.VersionFlag || hdr.IsLongHeader { + // send a Version Negotiation Packet if the client is speaking a different protocol version + if !protocol.IsSupportedVersion(s.config.Versions, hdr.Version) { + return s.sendVersionNegotiationPacket(p) + } + } + if hdr.Type == protocol.PacketTypeInitial && hdr.Version.UsesTLS() { + go s.serverTLS.HandleInitial(p) + return nil + } + + // TODO(#943): send Stateless Reset, if this an IETF QUIC packet + if !hdr.VersionFlag && !hdr.Version.UsesIETFHeaderFormat() { + _, err := s.conn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), p.remoteAddr) + return err + } + + // This is (potentially) a Client Hello. + // Make sure it has the minimum required size before spending any more ressources on it. + if len(p.data) < protocol.MinClientHelloSize { + return errors.New("dropping small packet for unknown connection") + } + + var destConnID, srcConnID protocol.ConnectionID + if hdr.Version.UsesIETFHeaderFormat() { + srcConnID = hdr.DestConnectionID + } else { + destConnID = hdr.DestConnectionID + srcConnID = hdr.DestConnectionID + } + s.logger.Infof("Serving new connection: %s, version %s from %v", hdr.DestConnectionID, hdr.Version, p.remoteAddr) + sess, err := s.newSession( + &conn{pconn: s.conn, currentAddr: p.remoteAddr}, + s.sessionRunner, + hdr.Version, + destConnID, + srcConnID, + s.scfg, + s.tlsConf, + s.config, + s.logger, + ) + if err != nil { + return err + } + s.sessionHandler.Add(hdr.DestConnectionID, newServerSession(sess, s.config, s.logger)) + go sess.run() + sess.handlePacket(p) + return nil +} + +func (s *server) sendVersionNegotiationPacket(p *receivedPacket) error { + hdr := p.header + s.logger.Debugf("Client offered version %s, sending VersionNegotiationPacket", hdr.Version) + + var data []byte + if hdr.IsPublicHeader { + data = wire.ComposeGQUICVersionNegotiation(hdr.DestConnectionID, s.config.Versions) + } else { + var err error + data, err = wire.ComposeVersionNegotiation(hdr.SrcConnectionID, hdr.DestConnectionID, s.config.Versions) + if err != nil { + return err + } + } + _, err := s.conn.WriteTo(data, p.remoteAddr) + return err +} diff --git a/vendor/lucas-clemente/quic-go/server_session.go b/vendor/lucas-clemente/quic-go/server_session.go new file mode 100644 index 00000000..51743b3a --- /dev/null +++ b/vendor/lucas-clemente/quic-go/server_session.go @@ -0,0 +1,63 @@ +package quic + +import ( + "fmt" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +type serverSession struct { + quicSession + + config *Config + + logger utils.Logger +} + +var _ packetHandler = &serverSession{} + +func newServerSession(sess quicSession, config *Config, logger utils.Logger) packetHandler { + return &serverSession{ + quicSession: sess, + config: config, + logger: logger, + } +} + +func (s *serverSession) handlePacket(p *receivedPacket) { + if err := s.handlePacketImpl(p); err != nil { + s.logger.Debugf("error handling packet from %s: %s", p.remoteAddr, err) + } +} + +func (s *serverSession) handlePacketImpl(p *receivedPacket) error { + hdr := p.header + // ignore all Public Reset packets + if hdr.ResetFlag { + return fmt.Errorf("Received unexpected Public Reset for connection %s", hdr.DestConnectionID) + } + + // Probably an old packet that was sent by the client before the version was negotiated. + // It is safe to drop it. + if (hdr.VersionFlag || hdr.IsLongHeader) && hdr.Version != s.quicSession.GetVersion() { + return nil + } + + if hdr.IsLongHeader { + switch hdr.Type { + case protocol.PacketTypeHandshake, protocol.PacketType0RTT: // 0-RTT accepted for gQUIC 44 + // nothing to do here. Packet will be passed to the session. + default: + // Note that this also drops 0-RTT packets. + return fmt.Errorf("Received unsupported packet type: %s", hdr.Type) + } + } + + s.quicSession.handlePacket(p) + return nil +} + +func (s *serverSession) GetPerspective() protocol.Perspective { + return protocol.PerspectiveServer +} diff --git a/vendor/lucas-clemente/quic-go/server_session_test.go b/vendor/lucas-clemente/quic-go/server_session_test.go new file mode 100644 index 00000000..4486d7e4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/server_session_test.go @@ -0,0 +1,101 @@ +package quic + +import ( + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Server Session", func() { + var ( + qsess *MockQuicSession + sess *serverSession + ) + + BeforeEach(func() { + qsess = NewMockQuicSession(mockCtrl) + sess = newServerSession(qsess, &Config{}, utils.DefaultLogger).(*serverSession) + }) + + It("handles packets", func() { + p := &receivedPacket{ + header: &wire.Header{DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5}}, + } + qsess.EXPECT().handlePacket(p) + sess.handlePacket(p) + }) + + It("ignores Public Resets", func() { + p := &receivedPacket{ + header: &wire.Header{ + ResetFlag: true, + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + }, + } + err := sess.handlePacketImpl(p) + Expect(err).To(MatchError("Received unexpected Public Reset for connection 0xdeadbeef")) + }) + + It("ignores delayed packets with mismatching versions, for gQUIC", func() { + qsess.EXPECT().GetVersion().Return(protocol.VersionNumber(100)) + // don't EXPECT any calls to handlePacket() + p := &receivedPacket{ + header: &wire.Header{ + VersionFlag: true, + Version: protocol.VersionNumber(123), + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + }, + } + err := sess.handlePacketImpl(p) + Expect(err).ToNot(HaveOccurred()) + }) + + It("ignores delayed packets with mismatching versions, for IETF QUIC", func() { + qsess.EXPECT().GetVersion().Return(protocol.VersionNumber(100)) + // don't EXPECT any calls to handlePacket() + p := &receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + Version: protocol.VersionNumber(123), + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + }, + } + err := sess.handlePacketImpl(p) + Expect(err).ToNot(HaveOccurred()) + }) + + It("ignores packets with the wrong Long Header type", func() { + qsess.EXPECT().GetVersion().Return(protocol.VersionNumber(100)) + p := &receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeRetry, + Version: protocol.VersionNumber(100), + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + }, + } + err := sess.handlePacketImpl(p) + Expect(err).To(MatchError("Received unsupported packet type: Retry")) + }) + + It("passes on Handshake packets", func() { + p := &receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeHandshake, + Version: protocol.VersionNumber(100), + DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + }, + } + qsess.EXPECT().GetVersion().Return(protocol.VersionNumber(100)) + qsess.EXPECT().handlePacket(p) + Expect(sess.handlePacketImpl(p)).To(Succeed()) + }) + + It("has the right perspective", func() { + Expect(sess.GetPerspective()).To(Equal(protocol.PerspectiveServer)) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/server_test.go b/vendor/lucas-clemente/quic-go/server_test.go new file mode 100644 index 00000000..387ec665 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/server_test.go @@ -0,0 +1,519 @@ +package quic + +import ( + "bytes" + "crypto/tls" + "errors" + "net" + "reflect" + "time" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockSession struct { + *MockQuicSession + + connID protocol.ConnectionID + runner sessionRunner +} + +func (s *mockSession) GetPerspective() protocol.Perspective { panic("not implemented") } + +var _ = Describe("Server", func() { + var ( + conn *mockPacketConn + config *Config + udpAddr = &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337} + ) + + BeforeEach(func() { + conn = newMockPacketConn() + conn.addr = &net.UDPAddr{} + config = &Config{Versions: protocol.SupportedVersions} + }) + + Context("quic.Config", func() { + It("setups with the right values", func() { + config := &Config{ + HandshakeTimeout: 1337 * time.Minute, + IdleTimeout: 42 * time.Hour, + RequestConnectionIDOmission: true, + MaxIncomingStreams: 1234, + MaxIncomingUniStreams: 4321, + ConnectionIDLength: 12, + Versions: []protocol.VersionNumber{VersionGQUIC43}, + } + c := populateServerConfig(config) + Expect(c.HandshakeTimeout).To(Equal(1337 * time.Minute)) + Expect(c.IdleTimeout).To(Equal(42 * time.Hour)) + Expect(c.RequestConnectionIDOmission).To(BeFalse()) + Expect(c.MaxIncomingStreams).To(Equal(1234)) + Expect(c.MaxIncomingUniStreams).To(Equal(4321)) + Expect(c.ConnectionIDLength).To(Equal(12)) + Expect(c.Versions).To(Equal([]protocol.VersionNumber{VersionGQUIC43})) + }) + + It("uses 8 byte connection IDs if gQUIC 44 is supported", func() { + config := &Config{ + Versions: []protocol.VersionNumber{protocol.Version43, protocol.Version44}, + ConnectionIDLength: 13, + } + c := populateServerConfig(config) + Expect(c.Versions).To(Equal([]protocol.VersionNumber{protocol.Version43, protocol.Version44})) + Expect(c.ConnectionIDLength).To(Equal(8)) + }) + + It("uses 4 byte connection IDs by default, if gQUIC 44 is not supported", func() { + config := &Config{ + Versions: []protocol.VersionNumber{protocol.Version39}, + } + c := populateServerConfig(config) + Expect(c.ConnectionIDLength).To(Equal(protocol.DefaultConnectionIDLength)) + }) + + It("disables bidirectional streams", func() { + config := &Config{ + MaxIncomingStreams: -1, + MaxIncomingUniStreams: 4321, + } + c := populateServerConfig(config) + Expect(c.MaxIncomingStreams).To(BeZero()) + Expect(c.MaxIncomingUniStreams).To(Equal(4321)) + }) + + It("disables unidirectional streams", func() { + config := &Config{ + MaxIncomingStreams: 1234, + MaxIncomingUniStreams: -1, + } + c := populateServerConfig(config) + Expect(c.MaxIncomingStreams).To(Equal(1234)) + Expect(c.MaxIncomingUniStreams).To(BeZero()) + }) + }) + + Context("with mock session", func() { + var ( + serv *server + firstPacket *receivedPacket + connID = protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6} + sessions = make([]*MockQuicSession, 0) + sessionHandler *MockPacketHandlerManager + ) + + BeforeEach(func() { + sessionHandler = NewMockPacketHandlerManager(mockCtrl) + newMockSession := func( + _ connection, + runner sessionRunner, + _ protocol.VersionNumber, + connID protocol.ConnectionID, + _ protocol.ConnectionID, + _ *handshake.ServerConfig, + _ *tls.Config, + _ *Config, + _ utils.Logger, + ) (quicSession, error) { + ExpectWithOffset(0, sessions).ToNot(BeEmpty()) + s := &mockSession{MockQuicSession: sessions[0]} + s.connID = connID + s.runner = runner + sessions = sessions[1:] + return s, nil + } + serv = &server{ + sessionHandler: sessionHandler, + newSession: newMockSession, + conn: conn, + config: config, + sessionQueue: make(chan Session, 5), + errorChan: make(chan struct{}), + logger: utils.DefaultLogger, + } + serv.setup() + b := &bytes.Buffer{} + utils.BigEndian.WriteUint32(b, uint32(protocol.SupportedVersions[0])) + firstPacket = &receivedPacket{ + header: &wire.Header{ + VersionFlag: true, + Version: serv.config.Versions[0], + DestConnectionID: protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}, + PacketNumber: 1, + }, + data: bytes.Repeat([]byte{0}, protocol.MinClientHelloSize), + rcvTime: time.Now(), + } + }) + + AfterEach(func() { + Expect(sessions).To(BeEmpty()) + }) + + It("returns the address", func() { + conn.addr = &net.UDPAddr{ + IP: net.IPv4(192, 168, 13, 37), + Port: 1234, + } + Expect(serv.Addr().String()).To(Equal("192.168.13.37:1234")) + }) + + It("creates new sessions", func() { + s := NewMockQuicSession(mockCtrl) + s.EXPECT().handlePacket(gomock.Any()) + run := make(chan struct{}) + s.EXPECT().run().Do(func() { close(run) }) + sessions = append(sessions, s) + + sessionHandler.EXPECT().Add(connID, gomock.Any()).Do(func(cid protocol.ConnectionID, _ packetHandler) { + Expect(cid).To(Equal(connID)) + }) + Expect(serv.handlePacketImpl(firstPacket)).To(Succeed()) + Eventually(run).Should(BeClosed()) + }) + + It("accepts new TLS sessions", func() { + connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8} + sess := NewMockQuicSession(mockCtrl) + err := serv.setupTLS() + Expect(err).ToNot(HaveOccurred()) + added := make(chan struct{}) + sessionHandler.EXPECT().Add(connID, gomock.Any()).Do(func(_ protocol.ConnectionID, ph packetHandler) { + Expect(ph.GetPerspective()).To(Equal(protocol.PerspectiveServer)) + close(added) + }) + serv.serverTLS.sessionChan <- tlsSession{ + connID: connID, + sess: sess, + } + Eventually(added).Should(BeClosed()) + }) + + It("accepts a session once the connection it is forward secure", func() { + s := NewMockQuicSession(mockCtrl) + s.EXPECT().handlePacket(gomock.Any()) + run := make(chan struct{}) + s.EXPECT().run().Do(func() { close(run) }) + sessions = append(sessions, s) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := serv.Accept() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + sessionHandler.EXPECT().Add(connID, gomock.Any()).Do(func(_ protocol.ConnectionID, sess packetHandler) { + Consistently(done).ShouldNot(BeClosed()) + sess.(*serverSession).quicSession.(*mockSession).runner.onHandshakeComplete(sess.(Session)) + }) + err := serv.handlePacketImpl(firstPacket) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + Eventually(run).Should(BeClosed()) + }) + + It("doesn't accept sessions that error during the handshake", func() { + run := make(chan error, 1) + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().handlePacket(gomock.Any()) + sess.EXPECT().run().DoAndReturn(func() error { return <-run }) + sessions = append(sessions, sess) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + serv.Accept() + close(done) + }() + sessionHandler.EXPECT().Add(connID, gomock.Any()).Do(func(protocol.ConnectionID, packetHandler) { + run <- errors.New("handshake error") + }) + Expect(serv.handlePacketImpl(firstPacket)).To(Succeed()) + Consistently(done).ShouldNot(BeClosed()) + + // make the go routine return + close(serv.errorChan) + Eventually(done).Should(BeClosed()) + }) + + It("closes the sessionHandler when Close is called", func() { + sessionHandler.EXPECT().CloseServer() + Expect(serv.Close()).To(Succeed()) + }) + + It("closes twice", func() { + sessionHandler.EXPECT().CloseServer() + Expect(serv.Close()).To(Succeed()) + Expect(serv.Close()).To(Succeed()) + }) + + It("works if no quic.Config is given", func(done Done) { + ln, err := ListenAddr("127.0.0.1:0", testdata.GetTLSConfig(), nil) + Expect(err).ToNot(HaveOccurred()) + Expect(ln.Close()).To(Succeed()) + close(done) + }, 1) + + It("closes properly", func() { + ln, err := ListenAddr("127.0.0.1:0", testdata.GetTLSConfig(), config) + Expect(err).ToNot(HaveOccurred()) + + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + ln.Accept() + close(done) + }() + ln.Close() + Eventually(done).Should(BeClosed()) + }) + + It("closes the connection when it was created with ListenAddr", func() { + addr, err := net.ResolveUDPAddr("udp", "localhost:12345") + Expect(err).ToNot(HaveOccurred()) + + serv, err := ListenAddr("localhost:0", nil, nil) + Expect(err).ToNot(HaveOccurred()) + // test that we can write on the packet conn + _, err = serv.(*server).conn.WriteTo([]byte("foobar"), addr) + Expect(err).ToNot(HaveOccurred()) + Expect(serv.Close()).To(Succeed()) + // test that we can't write any more on the packet conn + _, err = serv.(*server).conn.WriteTo([]byte("foobar"), addr) + Expect(err.Error()).To(ContainSubstring("use of closed network connection")) + }) + + It("returns Accept when it is closed", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := serv.Accept() + Expect(err).To(MatchError("server closed")) + close(done) + }() + sessionHandler.EXPECT().CloseServer() + Expect(serv.Close()).To(Succeed()) + Eventually(done).Should(BeClosed()) + }) + + It("returns Accept with the right error when closeWithError is called", func() { + testErr := errors.New("connection error") + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := serv.Accept() + Expect(err).To(MatchError(testErr)) + close(done) + }() + sessionHandler.EXPECT().CloseServer() + serv.closeWithError(testErr) + Eventually(done).Should(BeClosed()) + }) + + It("doesn't try to process a packet after sending a gQUIC Version Negotiation Packet", func() { + config.Versions = []protocol.VersionNumber{99} + p := &receivedPacket{ + header: &wire.Header{ + VersionFlag: true, + DestConnectionID: connID, + PacketNumber: 1, + PacketNumberLen: protocol.PacketNumberLen2, + }, + data: make([]byte, protocol.MinClientHelloSize), + } + Expect(serv.handlePacketImpl(p)).To(Succeed()) + Expect(conn.dataWritten.Bytes()).ToNot(BeEmpty()) + }) + + It("sends a PUBLIC_RESET for new connections that don't have the VersionFlag set", func() { + err := serv.handlePacketImpl(&receivedPacket{ + remoteAddr: udpAddr, + header: &wire.Header{ + IsPublicHeader: true, + Version: versionGQUICFrames, + }, + }) + Expect(err).ToNot(HaveOccurred()) + + Expect(conn.dataWritten.Len()).ToNot(BeZero()) + Expect(conn.dataWrittenTo).To(Equal(udpAddr)) + Expect(conn.dataWritten.Bytes()[0] & 0x02).ToNot(BeZero()) // check that the ResetFlag is set + }) + + It("sends a gQUIC Version Negotaion Packet, if the client sent a gQUIC Public Header", func() { + connID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + err := serv.handlePacketImpl(&receivedPacket{ + remoteAddr: udpAddr, + header: &wire.Header{ + IsPublicHeader: true, + VersionFlag: true, + DestConnectionID: connID, + PacketNumber: 1, + PacketNumberLen: protocol.PacketNumberLen2, + Version: protocol.Version39 - 1, + }, + }) + Expect(err).ToNot(HaveOccurred()) + + Expect(conn.dataWritten.Len()).ToNot(BeZero()) + Expect(conn.dataWrittenTo).To(Equal(udpAddr)) + r := bytes.NewReader(conn.dataWritten.Bytes()) + iHdr, err := wire.ParseInvariantHeader(r, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(iHdr.IsLongHeader).To(BeFalse()) + replyHdr, err := iHdr.Parse(r, protocol.PerspectiveServer, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(replyHdr.IsVersionNegotiation).To(BeTrue()) + Expect(replyHdr.DestConnectionID).To(Equal(connID)) + Expect(r.Len()).To(BeZero()) + }) + + It("sends an IETF draft style Version Negotaion Packet, if the client sent a IETF draft style header", func() { + connID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + err := serv.handlePacketImpl(&receivedPacket{ + remoteAddr: udpAddr, + header: &wire.Header{ + Type: protocol.PacketTypeInitial, + IsLongHeader: true, + DestConnectionID: connID, + SrcConnectionID: connID, + PacketNumber: 0x55, + PacketNumberLen: protocol.PacketNumberLen1, + Version: 0x1234, + PayloadLen: protocol.MinInitialPacketSize, + }, + }) + Expect(err).ToNot(HaveOccurred()) + + Expect(conn.dataWritten.Len()).ToNot(BeZero()) + Expect(conn.dataWrittenTo).To(Equal(udpAddr)) + r := bytes.NewReader(conn.dataWritten.Bytes()) + iHdr, err := wire.ParseInvariantHeader(r, 0) + Expect(err).ToNot(HaveOccurred()) + replyHdr, err := iHdr.Parse(r, protocol.PerspectiveServer, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(replyHdr.IsVersionNegotiation).To(BeTrue()) + Expect(replyHdr.DestConnectionID).To(Equal(connID)) + Expect(replyHdr.SrcConnectionID).To(Equal(connID)) + Expect(r.Len()).To(BeZero()) + }) + }) + + It("setups with the right values", func() { + supportedVersions := []protocol.VersionNumber{protocol.VersionTLS, protocol.Version39} + acceptCookie := func(_ net.Addr, _ *Cookie) bool { return true } + config := Config{ + Versions: supportedVersions, + AcceptCookie: acceptCookie, + HandshakeTimeout: 1337 * time.Hour, + IdleTimeout: 42 * time.Minute, + KeepAlive: true, + } + ln, err := Listen(conn, &tls.Config{}, &config) + Expect(err).ToNot(HaveOccurred()) + server := ln.(*server) + Expect(server.sessionHandler).ToNot(BeNil()) + Expect(server.scfg).ToNot(BeNil()) + Expect(server.config.Versions).To(Equal(supportedVersions)) + Expect(server.config.HandshakeTimeout).To(Equal(1337 * time.Hour)) + Expect(server.config.IdleTimeout).To(Equal(42 * time.Minute)) + Expect(reflect.ValueOf(server.config.AcceptCookie)).To(Equal(reflect.ValueOf(acceptCookie))) + Expect(server.config.KeepAlive).To(BeTrue()) + }) + + It("errors when the Config contains an invalid version", func() { + version := protocol.VersionNumber(0x1234) + _, err := Listen(conn, &tls.Config{}, &Config{Versions: []protocol.VersionNumber{version}}) + Expect(err).To(MatchError("0x1234 is not a valid QUIC version")) + }) + + It("fills in default values if options are not set in the Config", func() { + ln, err := Listen(conn, &tls.Config{}, &Config{}) + Expect(err).ToNot(HaveOccurred()) + server := ln.(*server) + Expect(server.config.Versions).To(Equal(protocol.SupportedVersions)) + Expect(server.config.HandshakeTimeout).To(Equal(protocol.DefaultHandshakeTimeout)) + Expect(server.config.IdleTimeout).To(Equal(protocol.DefaultIdleTimeout)) + Expect(reflect.ValueOf(server.config.AcceptCookie)).To(Equal(reflect.ValueOf(defaultAcceptCookie))) + Expect(server.config.KeepAlive).To(BeFalse()) + }) + + It("listens on a given address", func() { + addr := "127.0.0.1:13579" + ln, err := ListenAddr(addr, nil, config) + Expect(err).ToNot(HaveOccurred()) + serv := ln.(*server) + Expect(serv.Addr().String()).To(Equal(addr)) + }) + + It("errors if given an invalid address", func() { + addr := "127.0.0.1" + _, err := ListenAddr(addr, nil, config) + Expect(err).To(BeAssignableToTypeOf(&net.AddrError{})) + }) + + It("errors if given an invalid address", func() { + addr := "1.1.1.1:1111" + _, err := ListenAddr(addr, nil, config) + Expect(err).To(BeAssignableToTypeOf(&net.OpError{})) + }) +}) + +var _ = Describe("default source address verification", func() { + It("accepts a token", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} + cookie := &Cookie{ + RemoteAddr: "192.168.0.1", + SentTime: time.Now().Add(-protocol.CookieExpiryTime).Add(time.Second), // will expire in 1 second + } + Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeTrue()) + }) + + It("requests verification if no token is provided", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} + Expect(defaultAcceptCookie(remoteAddr, nil)).To(BeFalse()) + }) + + It("rejects a token if the address doesn't match", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} + cookie := &Cookie{ + RemoteAddr: "127.0.0.1", + SentTime: time.Now(), + } + Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeFalse()) + }) + + It("accepts a token for a remote address is not a UDP address", func() { + remoteAddr := &net.TCPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1337} + cookie := &Cookie{ + RemoteAddr: "192.168.0.1:1337", + SentTime: time.Now(), + } + Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeTrue()) + }) + + It("rejects an invalid token for a remote address is not a UDP address", func() { + remoteAddr := &net.TCPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1337} + cookie := &Cookie{ + RemoteAddr: "192.168.0.1:7331", // mismatching port + SentTime: time.Now(), + } + Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeFalse()) + }) + + It("rejects an expired token", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} + cookie := &Cookie{ + RemoteAddr: "192.168.0.1", + SentTime: time.Now().Add(-protocol.CookieExpiryTime).Add(-time.Second), // expired 1 second ago + } + Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeFalse()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/server_tls.go b/vendor/lucas-clemente/quic-go/server_tls.go new file mode 100644 index 00000000..01508df3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/server_tls.go @@ -0,0 +1,178 @@ +package quic + +import ( + "bytes" + "crypto/tls" + "errors" + "net" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type tlsSession struct { + connID protocol.ConnectionID + sess quicSession +} + +type serverTLS struct { + conn net.PacketConn + config *Config + mintConf *mint.Config + params *handshake.TransportParameters + cookieGenerator *handshake.CookieGenerator + + newSession func(connection, sessionRunner, protocol.ConnectionID, protocol.ConnectionID, protocol.ConnectionID, protocol.PacketNumber, *Config, *mint.Config, *handshake.TransportParameters, utils.Logger, protocol.VersionNumber) (quicSession, error) + + sessionRunner sessionRunner + sessionChan chan<- tlsSession + + logger utils.Logger +} + +func newServerTLS( + conn net.PacketConn, + config *Config, + runner sessionRunner, + tlsConf *tls.Config, + logger utils.Logger, +) (*serverTLS, <-chan tlsSession, error) { + cookieGenerator, err := handshake.NewCookieGenerator() + if err != nil { + return nil, nil, err + } + params := &handshake.TransportParameters{ + StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, + ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, + IdleTimeout: config.IdleTimeout, + MaxBidiStreams: uint16(config.MaxIncomingStreams), + MaxUniStreams: uint16(config.MaxIncomingUniStreams), + DisableMigration: true, + // TODO(#855): generate a real token + StatelessResetToken: bytes.Repeat([]byte{42}, 16), + } + mconf, err := tlsToMintConfig(tlsConf, protocol.PerspectiveServer) + if err != nil { + return nil, nil, err + } + + sessionChan := make(chan tlsSession) + s := &serverTLS{ + conn: conn, + config: config, + mintConf: mconf, + sessionRunner: runner, + sessionChan: sessionChan, + cookieGenerator: cookieGenerator, + params: params, + newSession: newTLSServerSession, + logger: logger, + } + return s, sessionChan, nil +} + +func (s *serverTLS) HandleInitial(p *receivedPacket) { + // TODO: add a check that DestConnID == SrcConnID + s.logger.Debugf("<- Received Initial packet.") + sess, connID, err := s.handleInitialImpl(p) + if err != nil { + s.logger.Errorf("Error occurred handling initial packet: %s", err) + return + } + if sess == nil { // a stateless reset was done + return + } + s.sessionChan <- tlsSession{ + connID: connID, + sess: sess, + } +} + +func (s *serverTLS) handleInitialImpl(p *receivedPacket) (quicSession, protocol.ConnectionID, error) { + hdr := p.header + if len(hdr.Token) == 0 && hdr.DestConnectionID.Len() < protocol.MinConnectionIDLenInitial { + return nil, nil, errors.New("dropping Initial packet with too short connection ID") + } + if len(hdr.Raw)+len(p.data) < protocol.MinInitialPacketSize { + return nil, nil, errors.New("dropping too small Initial packet") + } + + var cookie *handshake.Cookie + if len(hdr.Token) > 0 { + c, err := s.cookieGenerator.DecodeToken(hdr.Token) + if err == nil { + cookie = c + } + } + if !s.config.AcceptCookie(p.remoteAddr, cookie) { + // Log the Initial packet now. + // If no Retry is sent, the packet will be logged by the session. + p.header.Log(s.logger) + return nil, nil, s.sendRetry(p.remoteAddr, hdr) + } + + extHandler := handshake.NewExtensionHandlerServer(s.params, s.config.Versions, hdr.Version, s.logger) + mconf := s.mintConf.Clone() + mconf.ExtensionHandler = extHandler + + // A server is allowed to perform multiple Retries. + // It doesn't make much sense, but it's something that our API allows. + // In that case it must use a source connection ID of at least 8 bytes. + connID, err := protocol.GenerateConnectionID(s.config.ConnectionIDLength) + if err != nil { + return nil, nil, err + } + s.logger.Debugf("Changing connection ID to %s.", connID) + sess, err := s.newSession( + &conn{pconn: s.conn, currentAddr: p.remoteAddr}, + s.sessionRunner, + hdr.DestConnectionID, + hdr.SrcConnectionID, + connID, + 1, + s.config, + mconf, + s.params, + s.logger, + hdr.Version, + ) + if err != nil { + return nil, nil, err + } + go sess.run() + sess.handlePacket(p) + return sess, connID, nil +} + +func (s *serverTLS) sendRetry(remoteAddr net.Addr, hdr *wire.Header) error { + token, err := s.cookieGenerator.NewToken(remoteAddr) + if err != nil { + return err + } + connID, err := protocol.GenerateConnectionIDForInitial() + if err != nil { + return err + } + replyHdr := &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeRetry, + Version: hdr.Version, + SrcConnectionID: connID, + DestConnectionID: hdr.SrcConnectionID, + OrigDestConnectionID: hdr.DestConnectionID, + Token: token, + } + s.logger.Debugf("Changing connection ID to %s.\n-> Sending Retry", connID) + replyHdr.Log(s.logger) + buf := &bytes.Buffer{} + if err := replyHdr.Write(buf, protocol.PerspectiveServer, hdr.Version); err != nil { + return err + } + if _, err := s.conn.WriteTo(buf.Bytes(), remoteAddr); err != nil { + s.logger.Debugf("Error sending Retry: %s", err) + } + return nil +} diff --git a/vendor/lucas-clemente/quic-go/server_tls_test.go b/vendor/lucas-clemente/quic-go/server_tls_test.go new file mode 100644 index 00000000..16326ed5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/server_tls_test.go @@ -0,0 +1,125 @@ +package quic + +import ( + "bytes" + "net" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Stateless TLS handling", func() { + var ( + conn *mockPacketConn + server *serverTLS + sessionChan <-chan tlsSession + ) + + BeforeEach(func() { + conn = newMockPacketConn() + config := &Config{ + Versions: []protocol.VersionNumber{protocol.VersionTLS}, + } + var err error + server, sessionChan, err = newServerTLS(conn, config, nil, testdata.GetTLSConfig(), utils.DefaultLogger) + Expect(err).ToNot(HaveOccurred()) + }) + + parseHeader := func(data []byte) *wire.Header { + b := bytes.NewReader(data) + iHdr, err := wire.ParseInvariantHeader(b, 0) + Expect(err).ToNot(HaveOccurred()) + hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, protocol.VersionTLS) + Expect(err).ToNot(HaveOccurred()) + return hdr + } + + It("drops too small packets", func() { + server.HandleInitial(&receivedPacket{ + header: &wire.Header{}, + data: bytes.Repeat([]byte{0}, protocol.MinInitialPacketSize-1), // the packet is now 1 byte too small + }) + Expect(conn.dataWritten.Len()).To(BeZero()) + }) + + It("drops packets with a too short connection ID", func() { + hdr := &wire.Header{ + SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4}, + PacketNumberLen: protocol.PacketNumberLen1, + } + server.HandleInitial(&receivedPacket{ + header: hdr, + data: bytes.Repeat([]byte{0}, protocol.MinInitialPacketSize), + }) + Expect(conn.dataWritten.Len()).To(BeZero()) + }) + + It("replies with a Retry packet, if a Cookie is required", func() { + server.config.AcceptCookie = func(_ net.Addr, _ *handshake.Cookie) bool { return false } + hdr := &wire.Header{ + Type: protocol.PacketTypeInitial, + SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1}, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + Version: protocol.VersionTLS, + } + server.HandleInitial(&receivedPacket{ + remoteAddr: &net.UDPAddr{}, + header: hdr, + data: bytes.Repeat([]byte{0}, protocol.MinInitialPacketSize), + }) + Expect(conn.dataWritten.Len()).ToNot(BeZero()) + replyHdr := parseHeader(conn.dataWritten.Bytes()) + Expect(replyHdr.Type).To(Equal(protocol.PacketTypeRetry)) + Expect(replyHdr.SrcConnectionID).ToNot(Equal(hdr.DestConnectionID)) + Expect(replyHdr.SrcConnectionID.Len()).To(BeNumerically(">=", protocol.MinConnectionIDLenInitial)) + Expect(replyHdr.DestConnectionID).To(Equal(hdr.SrcConnectionID)) + Expect(replyHdr.OrigDestConnectionID).To(Equal(hdr.DestConnectionID)) + Expect(replyHdr.Token).ToNot(BeEmpty()) + Expect(sessionChan).ToNot(Receive()) + }) + + It("creates a session, if no Cookie is required", func() { + server.config.AcceptCookie = func(_ net.Addr, _ *handshake.Cookie) bool { return true } + hdr := &wire.Header{ + Type: protocol.PacketTypeInitial, + SrcConnectionID: protocol.ConnectionID{5, 4, 3, 2, 1}, + DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + Version: protocol.VersionTLS, + } + p := &receivedPacket{ + header: hdr, + data: bytes.Repeat([]byte{0}, protocol.MinInitialPacketSize), + } + run := make(chan struct{}) + server.newSession = func(connection, sessionRunner, protocol.ConnectionID, protocol.ConnectionID, protocol.ConnectionID, protocol.PacketNumber, *Config, *mint.Config, *handshake.TransportParameters, utils.Logger, protocol.VersionNumber) (quicSession, error) { + sess := NewMockQuicSession(mockCtrl) + sess.EXPECT().handlePacket(p) + sess.EXPECT().run().Do(func() { close(run) }) + return sess, nil + } + + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + server.HandleInitial(p) + // the Handshake packet is written by the session + Expect(conn.dataWritten.Len()).To(BeZero()) + close(done) + }() + var tlsSess tlsSession + Eventually(sessionChan).Should(Receive(&tlsSess)) + // make sure we're using a server-generated connection ID + Expect(tlsSess.connID).ToNot(Equal(hdr.SrcConnectionID)) + Expect(tlsSess.connID).ToNot(Equal(hdr.DestConnectionID)) + Eventually(run).Should(BeClosed()) + Eventually(done).Should(BeClosed()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/session.go b/vendor/lucas-clemente/quic-go/session.go new file mode 100644 index 00000000..81422d1f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/session.go @@ -0,0 +1,1283 @@ +package quic + +import ( + "context" + "crypto/rand" + "crypto/tls" + "errors" + "fmt" + "net" + "sync" + "time" + + "github.com/bifurcation/mint" + "github.com/lucas-clemente/quic-go/internal/ackhandler" + "github.com/lucas-clemente/quic-go/internal/congestion" + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +type unpacker interface { + Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) +} + +type streamGetter interface { + GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error) + GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error) +} + +type streamManager interface { + GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error) + GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error) + OpenStream() (Stream, error) + OpenUniStream() (SendStream, error) + OpenStreamSync() (Stream, error) + OpenUniStreamSync() (SendStream, error) + AcceptStream() (Stream, error) + AcceptUniStream() (ReceiveStream, error) + DeleteStream(protocol.StreamID) error + UpdateLimits(*handshake.TransportParameters) + HandleMaxStreamIDFrame(*wire.MaxStreamIDFrame) error + CloseWithError(error) +} + +type cryptoStreamHandler interface { + HandleCryptoStream() error + ConnectionState() handshake.ConnectionState +} + +type divNonceSetter interface { + SetDiversificationNonce([]byte) error +} + +type receivedPacket struct { + remoteAddr net.Addr + header *wire.Header + data []byte + rcvTime time.Time +} + +var ( + newCryptoSetup = handshake.NewCryptoSetup + newCryptoSetupClient = handshake.NewCryptoSetupClient +) + +type closeError struct { + err error + remote bool + sendClose bool +} + +// A Session is a QUIC session +type session struct { + sessionRunner sessionRunner + + destConnID protocol.ConnectionID + srcConnID protocol.ConnectionID + + perspective protocol.Perspective + version protocol.VersionNumber + config *Config + + conn connection + + streamsMap streamManager + cryptoStream cryptoStream + + rttStats *congestion.RTTStats + + sentPacketHandler ackhandler.SentPacketHandler + receivedPacketHandler ackhandler.ReceivedPacketHandler + streamFramer *streamFramer + windowUpdateQueue *windowUpdateQueue + connFlowController flowcontrol.ConnectionFlowController + + unpacker unpacker + packer *packetPacker + + cryptoStreamHandler cryptoStreamHandler + + receivedPackets chan *receivedPacket + sendingScheduled chan struct{} + // closeChan is used to notify the run loop that it should terminate. + closeChan chan closeError + closeOnce sync.Once + + ctx context.Context + ctxCancel context.CancelFunc + + // when we receive too many undecryptable packets during the handshake, we send a Public reset + // but only after a time of protocol.PublicResetTimeout has passed + undecryptablePackets []*receivedPacket + receivedTooManyUndecrytablePacketsTime time.Time + + // this channel is passed to the CryptoSetup and receives the transport parameters, as soon as the peer sends them + paramsChan <-chan handshake.TransportParameters + // the handshakeEvent channel is passed to the CryptoSetup. + // It receives when it makes sense to try decrypting undecryptable packets. + handshakeEvent <-chan struct{} + handshakeComplete bool + + receivedFirstPacket bool // since packet numbers start at 0, we can't use largestRcvdPacketNumber != 0 for this + receivedFirstForwardSecurePacket bool + lastRcvdPacketNumber protocol.PacketNumber + // Used to calculate the next packet number from the truncated wire + // representation, and sent back in public reset packets + largestRcvdPacketNumber protocol.PacketNumber + + sessionCreationTime time.Time + lastNetworkActivityTime time.Time + // pacingDeadline is the time when the next packet should be sent + pacingDeadline time.Time + + peerParams *handshake.TransportParameters + + timer *utils.Timer + // keepAlivePingSent stores whether a Ping frame was sent to the peer or not + // it is reset as soon as we receive a packet from the peer + keepAlivePingSent bool + + logger utils.Logger +} + +var _ Session = &session{} +var _ streamSender = &session{} + +// newSession makes a new session +func newSession( + conn connection, + sessionRunner sessionRunner, + v protocol.VersionNumber, + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, + scfg *handshake.ServerConfig, + tlsConf *tls.Config, + config *Config, + logger utils.Logger, +) (quicSession, error) { + logger.Debugf("Creating new session. Destination Connection ID: %s, Source Connection ID: %s", destConnID, srcConnID) + paramsChan := make(chan handshake.TransportParameters) + handshakeEvent := make(chan struct{}, 1) + s := &session{ + conn: conn, + sessionRunner: sessionRunner, + srcConnID: srcConnID, + destConnID: destConnID, + perspective: protocol.PerspectiveServer, + version: v, + config: config, + handshakeEvent: handshakeEvent, + paramsChan: paramsChan, + logger: logger, + } + s.preSetup() + transportParams := &handshake.TransportParameters{ + StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, + ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, + MaxStreams: uint32(s.config.MaxIncomingStreams), + IdleTimeout: s.config.IdleTimeout, + } + divNonce := make([]byte, 32) + if _, err := rand.Read(divNonce); err != nil { + return nil, err + } + cs, err := newCryptoSetup( + s.cryptoStream, + srcConnID, + s.conn.RemoteAddr(), + s.version, + divNonce, + scfg, + transportParams, + s.config.Versions, + s.config.AcceptCookie, + paramsChan, + handshakeEvent, + s.logger, + ) + if err != nil { + return nil, err + } + s.cryptoStreamHandler = cs + s.unpacker = newPacketUnpackerGQUIC(cs, s.version) + s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective) + s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) + s.packer = newPacketPacker( + destConnID, + srcConnID, + 1, + s.sentPacketHandler.GetPacketNumberLen, + s.RemoteAddr(), + nil, // no token + divNonce, + cs, + s.streamFramer, + s.perspective, + s.version, + ) + return s, s.postSetup() +} + +// declare this as a variable, so that we can it mock it in the tests +var newClientSession = func( + conn connection, + sessionRunner sessionRunner, + hostname string, + v protocol.VersionNumber, + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, + tlsConf *tls.Config, + config *Config, + initialVersion protocol.VersionNumber, + negotiatedVersions []protocol.VersionNumber, // needed for validation of the GQUIC version negotiation + logger utils.Logger, +) (quicSession, error) { + logger.Debugf("Creating new session. Destination Connection ID: %s, Source Connection ID: %s", destConnID, srcConnID) + paramsChan := make(chan handshake.TransportParameters) + handshakeEvent := make(chan struct{}, 1) + s := &session{ + conn: conn, + sessionRunner: sessionRunner, + srcConnID: srcConnID, + destConnID: destConnID, + perspective: protocol.PerspectiveClient, + version: v, + config: config, + handshakeEvent: handshakeEvent, + paramsChan: paramsChan, + logger: logger, + } + s.preSetup() + transportParams := &handshake.TransportParameters{ + StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, + ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, + MaxStreams: uint32(s.config.MaxIncomingStreams), + IdleTimeout: s.config.IdleTimeout, + OmitConnectionID: s.config.RequestConnectionIDOmission, + } + cs, err := newCryptoSetupClient( + s.cryptoStream, + hostname, + destConnID, + s.version, + tlsConf, + transportParams, + paramsChan, + handshakeEvent, + initialVersion, + negotiatedVersions, + s.logger, + ) + if err != nil { + return nil, err + } + s.cryptoStreamHandler = cs + s.unpacker = newPacketUnpackerGQUIC(cs, s.version) + s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective) + s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) + s.packer = newPacketPacker( + destConnID, + srcConnID, + 1, + s.sentPacketHandler.GetPacketNumberLen, + s.RemoteAddr(), + nil, // no token + nil, // no diversification nonce + cs, + s.streamFramer, + s.perspective, + s.version, + ) + return s, s.postSetup() +} + +func newTLSServerSession( + conn connection, + runner sessionRunner, + origConnID protocol.ConnectionID, + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, + initialPacketNumber protocol.PacketNumber, + config *Config, + mintConf *mint.Config, + peerParams *handshake.TransportParameters, + logger utils.Logger, + v protocol.VersionNumber, +) (quicSession, error) { + handshakeEvent := make(chan struct{}, 1) + s := &session{ + conn: conn, + sessionRunner: runner, + config: config, + srcConnID: srcConnID, + destConnID: destConnID, + perspective: protocol.PerspectiveServer, + version: v, + handshakeEvent: handshakeEvent, + logger: logger, + } + s.preSetup() + cs, err := handshake.NewCryptoSetupTLSServer( + s.cryptoStream, + origConnID, + mintConf, + handshakeEvent, + v, + ) + if err != nil { + return nil, err + } + s.cryptoStreamHandler = cs + s.streamsMap = newStreamsMap(s, s.newFlowController, s.config.MaxIncomingStreams, s.config.MaxIncomingUniStreams, s.perspective, s.version) + s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) + s.packer = newPacketPacker( + s.destConnID, + s.srcConnID, + initialPacketNumber, + s.sentPacketHandler.GetPacketNumberLen, + s.RemoteAddr(), + nil, // no token + nil, // no diversification nonce + cs, + s.streamFramer, + s.perspective, + s.version, + ) + if err := s.postSetup(); err != nil { + return nil, err + } + s.peerParams = peerParams + s.processTransportParameters(peerParams) + s.unpacker = newPacketUnpacker(cs, s.version) + return s, nil +} + +// declare this as a variable, such that we can it mock it in the tests +var newTLSClientSession = func( + conn connection, + runner sessionRunner, + token []byte, + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, + conf *Config, + mintConf *mint.Config, + paramsChan <-chan handshake.TransportParameters, + initialPacketNumber protocol.PacketNumber, + logger utils.Logger, + v protocol.VersionNumber, +) (quicSession, error) { + handshakeEvent := make(chan struct{}, 1) + s := &session{ + conn: conn, + sessionRunner: runner, + config: conf, + srcConnID: srcConnID, + destConnID: destConnID, + perspective: protocol.PerspectiveClient, + version: v, + handshakeEvent: handshakeEvent, + paramsChan: paramsChan, + logger: logger, + } + s.preSetup() + cs, err := handshake.NewCryptoSetupTLSClient( + s.cryptoStream, + s.destConnID, + mintConf, + handshakeEvent, + v, + ) + if err != nil { + return nil, err + } + s.cryptoStreamHandler = cs + s.unpacker = newPacketUnpacker(cs, s.version) + s.streamsMap = newStreamsMap(s, s.newFlowController, s.config.MaxIncomingStreams, s.config.MaxIncomingUniStreams, s.perspective, s.version) + s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) + s.packer = newPacketPacker( + s.destConnID, + s.srcConnID, + initialPacketNumber, + s.sentPacketHandler.GetPacketNumberLen, + s.RemoteAddr(), + token, + nil, // no diversification nonce + cs, + s.streamFramer, + s.perspective, + s.version, + ) + return s, s.postSetup() +} + +func (s *session) preSetup() { + s.rttStats = &congestion.RTTStats{} + s.sentPacketHandler = ackhandler.NewSentPacketHandler(s.rttStats, s.logger, s.version) + s.connFlowController = flowcontrol.NewConnectionFlowController( + protocol.ReceiveConnectionFlowControlWindow, + protocol.ByteCount(s.config.MaxReceiveConnectionFlowControlWindow), + s.onHasConnectionWindowUpdate, + s.rttStats, + s.logger, + ) + s.cryptoStream = s.newCryptoStream() +} + +func (s *session) postSetup() error { + s.receivedPackets = make(chan *receivedPacket, protocol.MaxSessionUnprocessedPackets) + s.closeChan = make(chan closeError, 1) + s.sendingScheduled = make(chan struct{}, 1) + s.undecryptablePackets = make([]*receivedPacket, 0, protocol.MaxUndecryptablePackets) + s.ctx, s.ctxCancel = context.WithCancel(context.Background()) + + s.timer = utils.NewTimer() + now := time.Now() + s.lastNetworkActivityTime = now + s.sessionCreationTime = now + + s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.rttStats, s.logger, s.version) + s.windowUpdateQueue = newWindowUpdateQueue(s.streamsMap, s.cryptoStream, s.connFlowController, s.packer.QueueControlFrame) + return nil +} + +// run the session main loop +func (s *session) run() error { + defer s.ctxCancel() + + go func() { + if err := s.cryptoStreamHandler.HandleCryptoStream(); err != nil { + s.closeLocal(err) + } + }() + + var closeErr closeError + +runLoop: + for { + + // Close immediately if requested + select { + case closeErr = <-s.closeChan: + break runLoop + case _, ok := <-s.handshakeEvent: + // when the handshake is completed, the channel will be closed + s.handleHandshakeEvent(!ok) + default: + } + + s.maybeResetTimer() + + select { + case closeErr = <-s.closeChan: + break runLoop + case <-s.timer.Chan(): + s.timer.SetRead() + // We do all the interesting stuff after the switch statement, so + // nothing to see here. + case <-s.sendingScheduled: + // We do all the interesting stuff after the switch statement, so + // nothing to see here. + case p := <-s.receivedPackets: + err := s.handlePacketImpl(p) + if err != nil { + if qErr, ok := err.(*qerr.QuicError); ok && qErr.ErrorCode == qerr.DecryptionFailure { + s.tryQueueingUndecryptablePacket(p) + continue + } + s.closeLocal(err) + continue + } + // This is a bit unclean, but works properly, since the packet always + // begins with the public header and we never copy it. + putPacketBuffer(&p.header.Raw) + case p := <-s.paramsChan: + s.processTransportParameters(&p) + case _, ok := <-s.handshakeEvent: + // when the handshake is completed, the channel will be closed + s.handleHandshakeEvent(!ok) + } + + now := time.Now() + if timeout := s.sentPacketHandler.GetAlarmTimeout(); !timeout.IsZero() && timeout.Before(now) { + // This could cause packets to be retransmitted. + // Check it before trying to send packets. + if err := s.sentPacketHandler.OnAlarm(); err != nil { + s.closeLocal(err) + } + } + + var pacingDeadline time.Time + if s.pacingDeadline.IsZero() { // the timer didn't have a pacing deadline set + pacingDeadline = s.sentPacketHandler.TimeUntilSend() + } + if s.config.KeepAlive && !s.keepAlivePingSent && s.handshakeComplete && time.Since(s.lastNetworkActivityTime) >= s.peerParams.IdleTimeout/2 { + // send a PING frame since there is no activity in the session + s.logger.Debugf("Sending a keep-alive ping to keep the connection alive.") + s.packer.QueueControlFrame(&wire.PingFrame{}) + s.keepAlivePingSent = true + } else if !pacingDeadline.IsZero() && now.Before(pacingDeadline) { + // If we get to this point before the pacing deadline, we should wait until that deadline. + // This can happen when scheduleSending is called, or a packet is received. + // Set the timer and restart the run loop. + s.pacingDeadline = pacingDeadline + continue + } + + if err := s.sendPackets(); err != nil { + s.closeLocal(err) + } + + if !s.receivedTooManyUndecrytablePacketsTime.IsZero() && s.receivedTooManyUndecrytablePacketsTime.Add(protocol.PublicResetTimeout).Before(now) && len(s.undecryptablePackets) != 0 { + s.closeLocal(qerr.Error(qerr.DecryptionFailure, "too many undecryptable packets received")) + } + if !s.handshakeComplete && now.Sub(s.sessionCreationTime) >= s.config.HandshakeTimeout { + s.closeLocal(qerr.Error(qerr.HandshakeTimeout, "Crypto handshake did not complete in time.")) + } + if s.handshakeComplete && now.Sub(s.lastNetworkActivityTime) >= s.config.IdleTimeout { + s.closeLocal(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity.")) + } + } + + if err := s.handleCloseError(closeErr); err != nil { + s.logger.Infof("Handling close error failed: %s", err) + } + s.logger.Infof("Connection %s closed.", s.srcConnID) + s.sessionRunner.removeConnectionID(s.srcConnID) + return closeErr.err +} + +func (s *session) Context() context.Context { + return s.ctx +} + +func (s *session) ConnectionState() ConnectionState { + return s.cryptoStreamHandler.ConnectionState() +} + +func (s *session) maybeResetTimer() { + var deadline time.Time + if s.config.KeepAlive && s.handshakeComplete && !s.keepAlivePingSent { + deadline = s.lastNetworkActivityTime.Add(s.peerParams.IdleTimeout / 2) + } else { + deadline = s.lastNetworkActivityTime.Add(s.config.IdleTimeout) + } + + if ackAlarm := s.receivedPacketHandler.GetAlarmTimeout(); !ackAlarm.IsZero() { + deadline = utils.MinTime(deadline, ackAlarm) + } + if lossTime := s.sentPacketHandler.GetAlarmTimeout(); !lossTime.IsZero() { + deadline = utils.MinTime(deadline, lossTime) + } + if !s.handshakeComplete { + handshakeDeadline := s.sessionCreationTime.Add(s.config.HandshakeTimeout) + deadline = utils.MinTime(deadline, handshakeDeadline) + } + if !s.receivedTooManyUndecrytablePacketsTime.IsZero() { + deadline = utils.MinTime(deadline, s.receivedTooManyUndecrytablePacketsTime.Add(protocol.PublicResetTimeout)) + } + if !s.pacingDeadline.IsZero() { + deadline = utils.MinTime(deadline, s.pacingDeadline) + } + + s.timer.Reset(deadline) +} + +func (s *session) handleHandshakeEvent(completed bool) { + if !completed { + s.tryDecryptingQueuedPackets() + return + } + s.handshakeComplete = true + s.handshakeEvent = nil // prevent this case from ever being selected again + s.sessionRunner.onHandshakeComplete(s) + + // In gQUIC, the server completes the handshake first (after sending the SHLO). + // In TLS 1.3, the client completes the handshake first (after sending the CFIN). + // We need to make sure they learn about the peer completing the handshake, + // in order to stop retransmitting handshake packets. + // They will stop retransmitting handshake packets when receiving the first forward-secure packet. + // We need to make sure that a retransmittable forward-secure packet is sent, + // independent from the application protocol. + if (!s.version.UsesTLS() && s.perspective == protocol.PerspectiveClient) || + (s.version.UsesTLS() && s.perspective == protocol.PerspectiveServer) { + s.queueControlFrame(&wire.PingFrame{}) + s.sentPacketHandler.SetHandshakeComplete() + } +} + +func (s *session) handlePacketImpl(p *receivedPacket) error { + hdr := p.header + // The server can change the source connection ID with the first Handshake packet. + // After this, all packets with a different source connection have to be ignored. + if s.receivedFirstPacket && hdr.IsLongHeader && !hdr.SrcConnectionID.Equal(s.destConnID) { + s.logger.Debugf("Dropping packet with unexpected source connection ID: %s (expected %s)", p.header.SrcConnectionID, s.destConnID) + return nil + } + if s.perspective == protocol.PerspectiveClient { + if divNonce := p.header.DiversificationNonce; len(divNonce) > 0 { + if err := s.cryptoStreamHandler.(divNonceSetter).SetDiversificationNonce(divNonce); err != nil { + return err + } + } + } + + if p.rcvTime.IsZero() { + // To simplify testing + p.rcvTime = time.Now() + } + + // Calculate packet number + hdr.PacketNumber = protocol.InferPacketNumber( + hdr.PacketNumberLen, + s.largestRcvdPacketNumber, + hdr.PacketNumber, + s.version, + ) + + packet, err := s.unpacker.Unpack(hdr.Raw, hdr, p.data) + if s.logger.Debug() { + if err != nil { + s.logger.Debugf("<- Reading packet 0x%x (%d bytes) for connection %s", hdr.PacketNumber, len(p.data)+len(hdr.Raw), hdr.DestConnectionID) + } else { + s.logger.Debugf("<- Reading packet 0x%x (%d bytes) for connection %s, %s", hdr.PacketNumber, len(p.data)+len(hdr.Raw), hdr.DestConnectionID, packet.encryptionLevel) + } + hdr.Log(s.logger) + } + // if the decryption failed, this might be a packet sent by an attacker + if err != nil { + return err + } + + // The server can change the source connection ID with the first Handshake packet. + if s.perspective == protocol.PerspectiveClient && !s.receivedFirstPacket && hdr.IsLongHeader && !hdr.SrcConnectionID.Equal(s.destConnID) { + s.logger.Debugf("Received first packet. Switching destination connection ID to: %s", hdr.SrcConnectionID) + s.destConnID = hdr.SrcConnectionID + s.packer.ChangeDestConnectionID(s.destConnID) + } + + s.receivedFirstPacket = true + s.lastNetworkActivityTime = p.rcvTime + s.keepAlivePingSent = false + + // In gQUIC, the server completes the handshake first (after sending the SHLO). + // In TLS 1.3, the client completes the handshake first (after sending the CFIN). + // We know that the peer completed the handshake as soon as we receive a forward-secure packet. + if (!s.version.UsesTLS() && s.perspective == protocol.PerspectiveServer) || + (s.version.UsesTLS() && s.perspective == protocol.PerspectiveClient) { + if !s.receivedFirstForwardSecurePacket && packet.encryptionLevel == protocol.EncryptionForwardSecure { + s.receivedFirstForwardSecurePacket = true + s.sentPacketHandler.SetHandshakeComplete() + } + } + + s.lastRcvdPacketNumber = hdr.PacketNumber + // Only do this after decrypting, so we are sure the packet is not attacker-controlled + s.largestRcvdPacketNumber = utils.MaxPacketNumber(s.largestRcvdPacketNumber, hdr.PacketNumber) + + // If this is a Retry packet, there's no need to send an ACK. + // The session will be closed and recreated as soon as the crypto setup processed the HRR. + if hdr.Type != protocol.PacketTypeRetry { + isRetransmittable := ackhandler.HasRetransmittableFrames(packet.frames) + if err := s.receivedPacketHandler.ReceivedPacket(hdr.PacketNumber, p.rcvTime, isRetransmittable); err != nil { + return err + } + } + + return s.handleFrames(packet.frames, packet.encryptionLevel) +} + +func (s *session) handleFrames(fs []wire.Frame, encLevel protocol.EncryptionLevel) error { + for _, ff := range fs { + var err error + wire.LogFrame(s.logger, ff, false) + switch frame := ff.(type) { + case *wire.StreamFrame: + err = s.handleStreamFrame(frame, encLevel) + case *wire.AckFrame: + err = s.handleAckFrame(frame, encLevel) + case *wire.ConnectionCloseFrame: + s.closeRemote(qerr.Error(frame.ErrorCode, frame.ReasonPhrase)) + case *wire.GoawayFrame: + err = errors.New("unimplemented: handling GOAWAY frames") + case *wire.StopWaitingFrame: // ignore STOP_WAITINGs + case *wire.RstStreamFrame: + err = s.handleRstStreamFrame(frame) + case *wire.MaxDataFrame: + s.handleMaxDataFrame(frame) + case *wire.MaxStreamDataFrame: + err = s.handleMaxStreamDataFrame(frame) + case *wire.MaxStreamIDFrame: + err = s.handleMaxStreamIDFrame(frame) + case *wire.BlockedFrame: + case *wire.StreamBlockedFrame: + case *wire.StreamIDBlockedFrame: + case *wire.StopSendingFrame: + err = s.handleStopSendingFrame(frame) + case *wire.PingFrame: + case *wire.PathChallengeFrame: + s.handlePathChallengeFrame(frame) + case *wire.PathResponseFrame: + // since we don't send PATH_CHALLENGEs, we don't expect PATH_RESPONSEs + err = errors.New("unexpected PATH_RESPONSE frame") + default: + return errors.New("Session BUG: unexpected frame type") + } + + if err != nil { + return err + } + } + return nil +} + +// handlePacket is called by the server with a new packet +func (s *session) handlePacket(p *receivedPacket) { + // Discard packets once the amount of queued packets is larger than + // the channel size, protocol.MaxSessionUnprocessedPackets + select { + case s.receivedPackets <- p: + default: + } +} + +func (s *session) handleStreamFrame(frame *wire.StreamFrame, encLevel protocol.EncryptionLevel) error { + if frame.StreamID == s.version.CryptoStreamID() { + if frame.FinBit { + return errors.New("Received STREAM frame with FIN bit for the crypto stream") + } + return s.cryptoStream.handleStreamFrame(frame) + } else if encLevel <= protocol.EncryptionUnencrypted { + return qerr.Error(qerr.UnencryptedStreamData, fmt.Sprintf("received unencrypted stream data on stream %d", frame.StreamID)) + } + str, err := s.streamsMap.GetOrOpenReceiveStream(frame.StreamID) + if err != nil { + return err + } + if str == nil { + // Stream is closed and already garbage collected + // ignore this StreamFrame + return nil + } + return str.handleStreamFrame(frame) +} + +func (s *session) handleMaxDataFrame(frame *wire.MaxDataFrame) { + s.connFlowController.UpdateSendWindow(frame.ByteOffset) +} + +func (s *session) handleMaxStreamDataFrame(frame *wire.MaxStreamDataFrame) error { + if frame.StreamID == s.version.CryptoStreamID() { + s.cryptoStream.handleMaxStreamDataFrame(frame) + return nil + } + str, err := s.streamsMap.GetOrOpenSendStream(frame.StreamID) + if err != nil { + return err + } + if str == nil { + // stream is closed and already garbage collected + return nil + } + str.handleMaxStreamDataFrame(frame) + return nil +} + +func (s *session) handleMaxStreamIDFrame(frame *wire.MaxStreamIDFrame) error { + return s.streamsMap.HandleMaxStreamIDFrame(frame) +} + +func (s *session) handleRstStreamFrame(frame *wire.RstStreamFrame) error { + if frame.StreamID == s.version.CryptoStreamID() { + return errors.New("Received RST_STREAM frame for the crypto stream") + } + str, err := s.streamsMap.GetOrOpenReceiveStream(frame.StreamID) + if err != nil { + return err + } + if str == nil { + // stream is closed and already garbage collected + return nil + } + return str.handleRstStreamFrame(frame) +} + +func (s *session) handleStopSendingFrame(frame *wire.StopSendingFrame) error { + if frame.StreamID == s.version.CryptoStreamID() { + return errors.New("Received a STOP_SENDING frame for the crypto stream") + } + str, err := s.streamsMap.GetOrOpenSendStream(frame.StreamID) + if err != nil { + return err + } + if str == nil { + // stream is closed and already garbage collected + return nil + } + str.handleStopSendingFrame(frame) + return nil +} + +func (s *session) handlePathChallengeFrame(frame *wire.PathChallengeFrame) { + s.queueControlFrame(&wire.PathResponseFrame{Data: frame.Data}) +} + +func (s *session) handleAckFrame(frame *wire.AckFrame, encLevel protocol.EncryptionLevel) error { + if err := s.sentPacketHandler.ReceivedAck(frame, s.lastRcvdPacketNumber, encLevel, s.lastNetworkActivityTime); err != nil { + return err + } + s.receivedPacketHandler.IgnoreBelow(s.sentPacketHandler.GetLowestPacketNotConfirmedAcked()) + return nil +} + +// closeLocal closes the session and send a CONNECTION_CLOSE containing the error +func (s *session) closeLocal(e error) { + s.closeOnce.Do(func() { + s.closeChan <- closeError{err: e, sendClose: true, remote: false} + }) +} + +// destroy closes the session without sending the error on the wire +func (s *session) destroy(e error) { + s.closeOnce.Do(func() { + s.closeChan <- closeError{err: e, sendClose: false, remote: false} + }) +} + +func (s *session) closeRemote(e error) { + s.closeOnce.Do(func() { + s.closeChan <- closeError{err: e, remote: true} + }) +} + +// Close the connection. It sends a qerr.PeerGoingAway. +// It waits until the run loop has stopped before returning +func (s *session) Close() error { + s.closeLocal(nil) + <-s.ctx.Done() + return nil +} + +func (s *session) CloseWithError(code protocol.ApplicationErrorCode, e error) error { + s.closeLocal(qerr.Error(qerr.ErrorCode(code), e.Error())) + <-s.ctx.Done() + return nil +} + +func (s *session) handleCloseError(closeErr closeError) error { + if closeErr.err == nil { + closeErr.err = qerr.PeerGoingAway + } + + var quicErr *qerr.QuicError + var ok bool + if quicErr, ok = closeErr.err.(*qerr.QuicError); !ok { + quicErr = qerr.ToQuicError(closeErr.err) + } + // Don't log 'normal' reasons + if quicErr.ErrorCode == qerr.PeerGoingAway || quicErr.ErrorCode == qerr.NetworkIdleTimeout { + s.logger.Infof("Closing connection %s.", s.srcConnID) + } else { + s.logger.Errorf("Closing session with error: %s", closeErr.err.Error()) + } + + s.cryptoStream.closeForShutdown(quicErr) + s.streamsMap.CloseWithError(quicErr) + + if !closeErr.sendClose { + return nil + } + + // If this is a remote close we're done here + if closeErr.remote { + return nil + } + + if quicErr.ErrorCode == qerr.DecryptionFailure || + quicErr == handshake.ErrNSTPExperiment { + return s.sendPublicReset(s.lastRcvdPacketNumber) + } + return s.sendConnectionClose(quicErr) +} + +func (s *session) processTransportParameters(params *handshake.TransportParameters) { + s.peerParams = params + s.streamsMap.UpdateLimits(params) + if params.OmitConnectionID { + s.packer.SetOmitConnectionID() + } + if params.MaxPacketSize != 0 { + s.packer.SetMaxPacketSize(params.MaxPacketSize) + } + s.connFlowController.UpdateSendWindow(params.ConnectionFlowControlWindow) + // the crypto stream is the only open stream at this moment + // so we don't need to update stream flow control windows +} + +func (s *session) sendPackets() error { + s.pacingDeadline = time.Time{} + + sendMode := s.sentPacketHandler.SendMode() + if sendMode == ackhandler.SendNone { // shortcut: return immediately if there's nothing to send + return nil + } + + numPackets := s.sentPacketHandler.ShouldSendNumPackets() + var numPacketsSent int +sendLoop: + for { + switch sendMode { + case ackhandler.SendNone: + break sendLoop + case ackhandler.SendAck: + // We can at most send a single ACK only packet. + // There will only be a new ACK after receiving new packets. + // SendAck is only returned when we're congestion limited, so we don't need to set the pacingt timer. + return s.maybeSendAckOnlyPacket() + case ackhandler.SendTLP, ackhandler.SendRTO: + if err := s.sendProbePacket(); err != nil { + return err + } + numPacketsSent++ + case ackhandler.SendRetransmission: + sentPacket, err := s.maybeSendRetransmission() + if err != nil { + return err + } + if sentPacket { + numPacketsSent++ + // This can happen if a retransmission queued, but it wasn't necessary to send it. + // e.g. when an Initial is queued, but we already received a packet from the server. + } + case ackhandler.SendAny: + sentPacket, err := s.sendPacket() + if err != nil { + return err + } + if !sentPacket { + break sendLoop + } + numPacketsSent++ + default: + return fmt.Errorf("BUG: invalid send mode %d", sendMode) + } + if numPacketsSent >= numPackets { + break + } + sendMode = s.sentPacketHandler.SendMode() + } + // Only start the pacing timer if we sent as many packets as we were allowed. + // There will probably be more to send when calling sendPacket again. + if numPacketsSent == numPackets { + s.pacingDeadline = s.sentPacketHandler.TimeUntilSend() + } + return nil +} + +func (s *session) maybeSendAckOnlyPacket() error { + ack := s.receivedPacketHandler.GetAckFrame() + if ack == nil { + return nil + } + s.packer.QueueControlFrame(ack) + + if s.version.UsesStopWaitingFrames() { // for gQUIC, maybe add a STOP_WAITING + if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil { + s.packer.QueueControlFrame(swf) + } + } + packet, err := s.packer.PackAckPacket() + if err != nil { + return err + } + s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket()) + return s.sendPackedPacket(packet) +} + +// maybeSendRetransmission sends retransmissions for at most one packet. +// It takes care that Initials aren't retransmitted, if a packet from the server was already received. +func (s *session) maybeSendRetransmission() (bool, error) { + var retransmitPacket *ackhandler.Packet + for { + retransmitPacket = s.sentPacketHandler.DequeuePacketForRetransmission() + if retransmitPacket == nil { + return false, nil + } + + // Don't retransmit Initial packets if we already received a response. + // An Initial might have been retransmitted multiple times before we receive a response. + // As soon as we receive one response, we don't need to send any more Initials. + if s.receivedFirstPacket && retransmitPacket.PacketType == protocol.PacketTypeInitial { + s.logger.Debugf("Skipping retransmission of packet %d. Already received a response to an Initial.", retransmitPacket.PacketNumber) + continue + } + break + } + + if retransmitPacket.EncryptionLevel != protocol.EncryptionForwardSecure { + s.logger.Debugf("Dequeueing handshake retransmission for packet 0x%x", retransmitPacket.PacketNumber) + } else { + s.logger.Debugf("Dequeueing retransmission for packet 0x%x", retransmitPacket.PacketNumber) + } + + if s.version.UsesStopWaitingFrames() { + s.packer.QueueControlFrame(s.sentPacketHandler.GetStopWaitingFrame(true)) + } + packets, err := s.packer.PackRetransmission(retransmitPacket) + if err != nil { + return false, err + } + ackhandlerPackets := make([]*ackhandler.Packet, len(packets)) + for i, packet := range packets { + ackhandlerPackets[i] = packet.ToAckHandlerPacket() + } + s.sentPacketHandler.SentPacketsAsRetransmission(ackhandlerPackets, retransmitPacket.PacketNumber) + for _, packet := range packets { + if err := s.sendPackedPacket(packet); err != nil { + return false, err + } + } + return true, nil +} + +func (s *session) sendProbePacket() error { + p, err := s.sentPacketHandler.DequeueProbePacket() + if err != nil { + return err + } + s.logger.Debugf("Sending a retransmission for %#x as a probe packet.", p.PacketNumber) + + if s.version.UsesStopWaitingFrames() { + s.packer.QueueControlFrame(s.sentPacketHandler.GetStopWaitingFrame(true)) + } + packets, err := s.packer.PackRetransmission(p) + if err != nil { + return err + } + ackhandlerPackets := make([]*ackhandler.Packet, len(packets)) + for i, packet := range packets { + ackhandlerPackets[i] = packet.ToAckHandlerPacket() + } + s.sentPacketHandler.SentPacketsAsRetransmission(ackhandlerPackets, p.PacketNumber) + for _, packet := range packets { + if err := s.sendPackedPacket(packet); err != nil { + return err + } + } + return nil +} + +func (s *session) sendPacket() (bool, error) { + if isBlocked, offset := s.connFlowController.IsNewlyBlocked(); isBlocked { + s.packer.QueueControlFrame(&wire.BlockedFrame{Offset: offset}) + } + s.windowUpdateQueue.QueueAll() + + if ack := s.receivedPacketHandler.GetAckFrame(); ack != nil { + s.packer.QueueControlFrame(ack) + if s.version.UsesStopWaitingFrames() { + if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil { + s.packer.QueueControlFrame(swf) + } + } + } + + packet, err := s.packer.PackPacket() + if err != nil || packet == nil { + return false, err + } + s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket()) + if err := s.sendPackedPacket(packet); err != nil { + return false, err + } + return true, nil +} + +func (s *session) sendPackedPacket(packet *packedPacket) error { + defer putPacketBuffer(&packet.raw) + s.logPacket(packet) + return s.conn.Write(packet.raw) +} + +func (s *session) sendConnectionClose(quicErr *qerr.QuicError) error { + packet, err := s.packer.PackConnectionClose(&wire.ConnectionCloseFrame{ + ErrorCode: quicErr.ErrorCode, + ReasonPhrase: quicErr.ErrorMessage, + }) + if err != nil { + return err + } + s.logPacket(packet) + return s.conn.Write(packet.raw) +} + +func (s *session) logPacket(packet *packedPacket) { + if !s.logger.Debug() { + // We don't need to allocate the slices for calling the format functions + return + } + s.logger.Debugf("-> Sending packet 0x%x (%d bytes) for connection %s, %s", packet.header.PacketNumber, len(packet.raw), s.srcConnID, packet.encryptionLevel) + packet.header.Log(s.logger) + for _, frame := range packet.frames { + wire.LogFrame(s.logger, frame, true) + } +} + +// GetOrOpenStream either returns an existing stream, a newly opened stream, or nil if a stream with the provided ID is already closed. +// It is *only* needed for gQUIC's H2. +// It will be removed as soon as gQUIC moves towards the IETF H2/QUIC stream mapping. +func (s *session) GetOrOpenStream(id protocol.StreamID) (Stream, error) { + str, err := s.streamsMap.GetOrOpenSendStream(id) + if str != nil { + if bstr, ok := str.(Stream); ok { + return bstr, err + } + return nil, fmt.Errorf("Stream %d is not a bidirectional stream", id) + } + // make sure to return an actual nil value here, not an Stream with value nil + return nil, err +} + +// AcceptStream returns the next stream openend by the peer +func (s *session) AcceptStream() (Stream, error) { + return s.streamsMap.AcceptStream() +} + +func (s *session) AcceptUniStream() (ReceiveStream, error) { + return s.streamsMap.AcceptUniStream() +} + +// OpenStream opens a stream +func (s *session) OpenStream() (Stream, error) { + return s.streamsMap.OpenStream() +} + +func (s *session) OpenStreamSync() (Stream, error) { + return s.streamsMap.OpenStreamSync() +} + +func (s *session) OpenUniStream() (SendStream, error) { + return s.streamsMap.OpenUniStream() +} + +func (s *session) OpenUniStreamSync() (SendStream, error) { + return s.streamsMap.OpenUniStreamSync() +} + +func (s *session) newStream(id protocol.StreamID) streamI { + flowController := s.newFlowController(id) + return newStream(id, s, flowController, s.version) +} + +func (s *session) newFlowController(id protocol.StreamID) flowcontrol.StreamFlowController { + var initialSendWindow protocol.ByteCount + if s.peerParams != nil { + initialSendWindow = s.peerParams.StreamFlowControlWindow + } + return flowcontrol.NewStreamFlowController( + id, + s.version.StreamContributesToConnectionFlowControl(id), + s.connFlowController, + protocol.ReceiveStreamFlowControlWindow, + protocol.ByteCount(s.config.MaxReceiveStreamFlowControlWindow), + initialSendWindow, + s.onHasStreamWindowUpdate, + s.rttStats, + s.logger, + ) +} + +func (s *session) newCryptoStream() cryptoStream { + id := s.version.CryptoStreamID() + flowController := flowcontrol.NewStreamFlowController( + id, + s.version.StreamContributesToConnectionFlowControl(id), + s.connFlowController, + protocol.ReceiveStreamFlowControlWindow, + protocol.ByteCount(s.config.MaxReceiveStreamFlowControlWindow), + 0, + s.onHasStreamWindowUpdate, + s.rttStats, + s.logger, + ) + return newCryptoStream(s, flowController, s.version) +} + +func (s *session) sendPublicReset(rejectedPacketNumber protocol.PacketNumber) error { + s.logger.Infof("Sending PUBLIC_RESET for connection %s, packet number %d", s.destConnID, rejectedPacketNumber) + return s.conn.Write(wire.WritePublicReset(s.destConnID, rejectedPacketNumber, 0)) +} + +// scheduleSending signals that we have data for sending +func (s *session) scheduleSending() { + select { + case s.sendingScheduled <- struct{}{}: + default: + } +} + +func (s *session) tryQueueingUndecryptablePacket(p *receivedPacket) { + if s.handshakeComplete { + s.logger.Debugf("Received undecryptable packet from %s after the handshake: %#v, %d bytes data", p.remoteAddr.String(), p.header, len(p.data)) + return + } + if len(s.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets { + // if this is the first time the undecryptablePackets runs full, start the timer to send a Public Reset + if s.receivedTooManyUndecrytablePacketsTime.IsZero() { + s.receivedTooManyUndecrytablePacketsTime = time.Now() + s.maybeResetTimer() + } + s.logger.Infof("Dropping undecrytable packet 0x%x (undecryptable packet queue full)", p.header.PacketNumber) + return + } + s.logger.Infof("Queueing packet 0x%x for later decryption", p.header.PacketNumber) + s.undecryptablePackets = append(s.undecryptablePackets, p) +} + +func (s *session) tryDecryptingQueuedPackets() { + for _, p := range s.undecryptablePackets { + s.handlePacket(p) + } + s.undecryptablePackets = s.undecryptablePackets[:0] +} + +func (s *session) queueControlFrame(f wire.Frame) { + s.packer.QueueControlFrame(f) + s.scheduleSending() +} + +func (s *session) onHasStreamWindowUpdate(id protocol.StreamID) { + s.windowUpdateQueue.AddStream(id) + s.scheduleSending() +} + +func (s *session) onHasConnectionWindowUpdate() { + s.windowUpdateQueue.AddConnection() + s.scheduleSending() +} + +func (s *session) onHasStreamData(id protocol.StreamID) { + s.streamFramer.AddActiveStream(id) + s.scheduleSending() +} + +func (s *session) onStreamCompleted(id protocol.StreamID) { + if err := s.streamsMap.DeleteStream(id); err != nil { + s.closeLocal(err) + } +} + +func (s *session) LocalAddr() net.Addr { + return s.conn.LocalAddr() +} + +func (s *session) RemoteAddr() net.Addr { + return s.conn.RemoteAddr() +} + +func (s *session) GetVersion() protocol.VersionNumber { + return s.version +} diff --git a/vendor/lucas-clemente/quic-go/session_test.go b/vendor/lucas-clemente/quic-go/session_test.go new file mode 100644 index 00000000..a2906046 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/session_test.go @@ -0,0 +1,1844 @@ +package quic + +import ( + "bytes" + "context" + "crypto/tls" + "errors" + "io" + "net" + "runtime/pprof" + "strings" + "time" + + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/lucas-clemente/quic-go/internal/ackhandler" + "github.com/lucas-clemente/quic-go/internal/crypto" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/mocks" + "github.com/lucas-clemente/quic-go/internal/mocks/ackhandler" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/testdata" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +type mockConnection struct { + remoteAddr net.Addr + localAddr net.Addr + written chan []byte +} + +func newMockConnection() *mockConnection { + return &mockConnection{ + remoteAddr: &net.UDPAddr{}, + written: make(chan []byte, 100), + } +} + +func (m *mockConnection) Write(p []byte) error { + b := make([]byte, len(p)) + copy(b, p) + select { + case m.written <- b: + default: + panic("mockConnection channel full") + } + return nil +} +func (m *mockConnection) Read([]byte) (int, net.Addr, error) { panic("not implemented") } + +func (m *mockConnection) SetCurrentRemoteAddr(addr net.Addr) { + m.remoteAddr = addr +} +func (m *mockConnection) LocalAddr() net.Addr { return m.localAddr } +func (m *mockConnection) RemoteAddr() net.Addr { return m.remoteAddr } +func (*mockConnection) Close() error { panic("not implemented") } + +func areSessionsRunning() bool { + var b bytes.Buffer + pprof.Lookup("goroutine").WriteTo(&b, 1) + return strings.Contains(b.String(), "quic-go.(*session).run") +} + +var _ = Describe("Session", func() { + var ( + sess *session + sessionRunner *MockSessionRunner + scfg *handshake.ServerConfig + mconn *mockConnection + cryptoSetup *mockCryptoSetup + streamManager *MockStreamManager + handshakeChan chan<- struct{} + ) + + BeforeEach(func() { + Eventually(areSessionsRunning).Should(BeFalse()) + + cryptoSetup = &mockCryptoSetup{} + newCryptoSetup = func( + _ io.ReadWriter, + _ protocol.ConnectionID, + _ net.Addr, + _ protocol.VersionNumber, + _ []byte, + _ *handshake.ServerConfig, + _ *handshake.TransportParameters, + _ []protocol.VersionNumber, + _ func(net.Addr, *Cookie) bool, + _ chan<- handshake.TransportParameters, + handshakeChanP chan<- struct{}, + _ utils.Logger, + ) (handshake.CryptoSetup, error) { + handshakeChan = handshakeChanP + return cryptoSetup, nil + } + + sessionRunner = NewMockSessionRunner(mockCtrl) + mconn = newMockConnection() + certChain := crypto.NewCertChain(testdata.GetTLSConfig()) + kex, err := crypto.NewCurve25519KEX() + Expect(err).NotTo(HaveOccurred()) + scfg, err = handshake.NewServerConfig(kex, certChain) + Expect(err).NotTo(HaveOccurred()) + var pSess Session + pSess, err = newSession( + mconn, + sessionRunner, + protocol.Version39, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + scfg, + nil, + populateServerConfig(&Config{}), + utils.DefaultLogger, + ) + Expect(err).NotTo(HaveOccurred()) + sess = pSess.(*session) + streamManager = NewMockStreamManager(mockCtrl) + sess.streamsMap = streamManager + }) + + AfterEach(func() { + newCryptoSetup = handshake.NewCryptoSetup + Eventually(areSessionsRunning).Should(BeFalse()) + }) + + Context("source address validation", func() { + var ( + cookieVerify func(net.Addr, *Cookie) bool + paramClientAddr net.Addr + paramCookie *Cookie + ) + remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 13, 37), Port: 1000} + + BeforeEach(func() { + newCryptoSetup = func( + _ io.ReadWriter, + _ protocol.ConnectionID, + _ net.Addr, + _ protocol.VersionNumber, + _ []byte, + _ *handshake.ServerConfig, + _ *handshake.TransportParameters, + _ []protocol.VersionNumber, + cookieFunc func(net.Addr, *Cookie) bool, + _ chan<- handshake.TransportParameters, + _ chan<- struct{}, + _ utils.Logger, + ) (handshake.CryptoSetup, error) { + cookieVerify = cookieFunc + return cryptoSetup, nil + } + + conf := populateServerConfig(&Config{}) + conf.AcceptCookie = func(clientAddr net.Addr, cookie *Cookie) bool { + paramClientAddr = clientAddr + paramCookie = cookie + return false + } + pSess, err := newSession( + mconn, + sessionRunner, + protocol.Version39, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + scfg, + nil, + conf, + utils.DefaultLogger, + ) + Expect(err).NotTo(HaveOccurred()) + sess = pSess.(*session) + }) + + It("calls the callback with the right parameters when the client didn't send an STK", func() { + cookieVerify(remoteAddr, nil) + Expect(paramClientAddr).To(Equal(remoteAddr)) + Expect(paramCookie).To(BeNil()) + }) + + It("calls the callback with the STK when the client sent an STK", func() { + cookieAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337} + sentTime := time.Now().Add(-time.Hour) + cookieVerify(remoteAddr, &Cookie{SentTime: sentTime, RemoteAddr: cookieAddr.String()}) + Expect(paramClientAddr).To(Equal(remoteAddr)) + Expect(paramCookie).ToNot(BeNil()) + Expect(paramCookie.RemoteAddr).To(Equal(cookieAddr.String())) + Expect(paramCookie.SentTime).To(Equal(sentTime)) + }) + }) + + Context("frame handling", func() { + Context("handling STREAM frames", func() { + It("passes STREAM frames to the stream", func() { + f := &wire.StreamFrame{ + StreamID: 5, + Data: []byte{0xde, 0xca, 0xfb, 0xad}, + } + str := NewMockReceiveStreamI(mockCtrl) + str.EXPECT().handleStreamFrame(f) + streamManager.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(5)).Return(str, nil) + err := sess.handleStreamFrame(f, protocol.EncryptionForwardSecure) + Expect(err).ToNot(HaveOccurred()) + }) + + It("returns errors", func() { + testErr := errors.New("test err") + f := &wire.StreamFrame{ + StreamID: 5, + Data: []byte{0xde, 0xca, 0xfb, 0xad}, + } + str := NewMockReceiveStreamI(mockCtrl) + str.EXPECT().handleStreamFrame(f).Return(testErr) + streamManager.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(5)).Return(str, nil) + err := sess.handleStreamFrame(f, protocol.EncryptionForwardSecure) + Expect(err).To(MatchError(testErr)) + }) + + It("ignores STREAM frames for closed streams", func() { + streamManager.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(5)).Return(nil, nil) // for closed streams, the streamManager returns nil + err := sess.handleStreamFrame(&wire.StreamFrame{ + StreamID: 5, + Data: []byte("foobar"), + }, protocol.EncryptionForwardSecure) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors on a STREAM frame that would close the crypto stream", func() { + err := sess.handleStreamFrame(&wire.StreamFrame{ + StreamID: sess.version.CryptoStreamID(), + Offset: 0x1337, + FinBit: true, + }, protocol.EncryptionForwardSecure) + Expect(err).To(MatchError("Received STREAM frame with FIN bit for the crypto stream")) + }) + + It("accepts unencrypted STREAM frames on the crypto stream", func() { + f := &wire.StreamFrame{ + StreamID: versionGQUICFrames.CryptoStreamID(), + Data: []byte("foobar"), + } + err := sess.handleStreamFrame(f, protocol.EncryptionUnencrypted) + Expect(err).ToNot(HaveOccurred()) + }) + + It("unpacks encrypted STREAM frames on the crypto stream", func() { + err := sess.handleStreamFrame(&wire.StreamFrame{ + StreamID: versionGQUICFrames.CryptoStreamID(), + Data: []byte("foobar"), + }, protocol.EncryptionSecure) + Expect(err).ToNot(HaveOccurred()) + }) + + It("does not unpack unencrypted STREAM frames on higher streams", func() { + err := sess.handleStreamFrame(&wire.StreamFrame{ + StreamID: 3, + Data: []byte("foobar"), + }, protocol.EncryptionUnencrypted) + Expect(err).To(MatchError(qerr.Error(qerr.UnencryptedStreamData, "received unencrypted stream data on stream 3"))) + }) + }) + + Context("handling ACK frames", func() { + It("informs the SentPacketHandler about ACKs", func() { + f := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 3}}} + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().ReceivedAck(f, protocol.PacketNumber(42), protocol.EncryptionSecure, gomock.Any()) + sph.EXPECT().GetLowestPacketNotConfirmedAcked() + sess.sentPacketHandler = sph + sess.lastRcvdPacketNumber = 42 + err := sess.handleAckFrame(f, protocol.EncryptionSecure) + Expect(err).ToNot(HaveOccurred()) + }) + + It("tells the ReceivedPacketHandler to ignore low ranges", func() { + ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 3}}} + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().ReceivedAck(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) + sph.EXPECT().GetLowestPacketNotConfirmedAcked().Return(protocol.PacketNumber(0x42)) + sess.sentPacketHandler = sph + rph := mockackhandler.NewMockReceivedPacketHandler(mockCtrl) + rph.EXPECT().IgnoreBelow(protocol.PacketNumber(0x42)) + sess.receivedPacketHandler = rph + err := sess.handleAckFrame(ack, protocol.EncryptionUnencrypted) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("handling RST_STREAM frames", func() { + It("closes the streams for writing", func() { + f := &wire.RstStreamFrame{ + StreamID: 555, + ErrorCode: 42, + ByteOffset: 0x1337, + } + str := NewMockReceiveStreamI(mockCtrl) + streamManager.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(555)).Return(str, nil) + str.EXPECT().handleRstStreamFrame(f) + err := sess.handleRstStreamFrame(f) + Expect(err).ToNot(HaveOccurred()) + }) + + It("returns errors", func() { + f := &wire.RstStreamFrame{ + StreamID: 7, + ByteOffset: 0x1337, + } + testErr := errors.New("flow control violation") + str := NewMockReceiveStreamI(mockCtrl) + streamManager.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(7)).Return(str, nil) + str.EXPECT().handleRstStreamFrame(f).Return(testErr) + err := sess.handleRstStreamFrame(f) + Expect(err).To(MatchError(testErr)) + }) + + It("ignores RST_STREAM frames for closed streams", func() { + streamManager.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(3)).Return(nil, nil) + err := sess.handleFrames([]wire.Frame{&wire.RstStreamFrame{ + StreamID: 3, + ErrorCode: 42, + }}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + + It("erros when a RST_STREAM frame would reset the crypto stream", func() { + err := sess.handleRstStreamFrame(&wire.RstStreamFrame{ + StreamID: sess.version.CryptoStreamID(), + ErrorCode: 123, + }) + Expect(err).To(MatchError("Received RST_STREAM frame for the crypto stream")) + }) + }) + + Context("handling MAX_DATA and MAX_STREAM_DATA frames", func() { + var connFC *mocks.MockConnectionFlowController + + BeforeEach(func() { + connFC = mocks.NewMockConnectionFlowController(mockCtrl) + sess.connFlowController = connFC + }) + + It("updates the flow control window of the crypto stream", func() { + fc := mocks.NewMockStreamFlowController(mockCtrl) + offset := protocol.ByteCount(0x4321) + fc.EXPECT().UpdateSendWindow(offset) + sess.cryptoStream.(*cryptoStreamImpl).sendStream.flowController = fc + err := sess.handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{ + StreamID: sess.version.CryptoStreamID(), + ByteOffset: offset, + }) + Expect(err).ToNot(HaveOccurred()) + }) + + It("updates the flow control window of a stream", func() { + f := &wire.MaxStreamDataFrame{ + StreamID: 12345, + ByteOffset: 0x1337, + } + str := NewMockSendStreamI(mockCtrl) + streamManager.EXPECT().GetOrOpenSendStream(protocol.StreamID(12345)).Return(str, nil) + str.EXPECT().handleMaxStreamDataFrame(f) + err := sess.handleMaxStreamDataFrame(f) + Expect(err).ToNot(HaveOccurred()) + }) + + It("updates the flow control window of the connection", func() { + offset := protocol.ByteCount(0x800000) + connFC.EXPECT().UpdateSendWindow(offset) + sess.handleMaxDataFrame(&wire.MaxDataFrame{ByteOffset: offset}) + }) + + It("ignores MAX_STREAM_DATA frames for a closed stream", func() { + streamManager.EXPECT().GetOrOpenSendStream(protocol.StreamID(10)).Return(nil, nil) + err := sess.handleFrames([]wire.Frame{&wire.MaxStreamDataFrame{ + StreamID: 10, + ByteOffset: 1337, + }}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("handling MAX_STREAM_ID frames", func() { + It("passes the frame to the streamsMap", func() { + f := &wire.MaxStreamIDFrame{StreamID: 10} + streamManager.EXPECT().HandleMaxStreamIDFrame(f) + err := sess.handleMaxStreamIDFrame(f) + Expect(err).ToNot(HaveOccurred()) + }) + + It("returns errors", func() { + f := &wire.MaxStreamIDFrame{StreamID: 10} + testErr := errors.New("test error") + streamManager.EXPECT().HandleMaxStreamIDFrame(f).Return(testErr) + err := sess.handleMaxStreamIDFrame(f) + Expect(err).To(MatchError(testErr)) + }) + }) + + Context("handling STOP_SENDING frames", func() { + It("passes the frame to the stream", func() { + f := &wire.StopSendingFrame{ + StreamID: 5, + ErrorCode: 10, + } + str := NewMockSendStreamI(mockCtrl) + streamManager.EXPECT().GetOrOpenSendStream(protocol.StreamID(5)).Return(str, nil) + str.EXPECT().handleStopSendingFrame(f) + err := sess.handleStopSendingFrame(f) + Expect(err).ToNot(HaveOccurred()) + }) + + It("errors when receiving a STOP_SENDING for the crypto stream", func() { + err := sess.handleStopSendingFrame(&wire.StopSendingFrame{ + StreamID: sess.version.CryptoStreamID(), + ErrorCode: 10, + }) + Expect(err).To(MatchError("Received a STOP_SENDING frame for the crypto stream")) + }) + + It("ignores STOP_SENDING frames for a closed stream", func() { + streamManager.EXPECT().GetOrOpenSendStream(protocol.StreamID(3)).Return(nil, nil) + err := sess.handleFrames([]wire.Frame{&wire.StopSendingFrame{ + StreamID: 3, + ErrorCode: 1337, + }}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + It("handles PING frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.PingFrame{}}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + + It("rejects PATH_RESPONSE frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.PathResponseFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}}}, protocol.EncryptionUnspecified) + Expect(err).To(MatchError("unexpected PATH_RESPONSE frame")) + }) + + It("handles PATH_CHALLENGE frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.PathChallengeFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}}}, protocol.EncryptionUnspecified) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.packer.controlFrames).To(HaveLen(1)) + Expect(sess.packer.controlFrames[0]).To(BeAssignableToTypeOf(&wire.PathResponseFrame{})) + Expect(sess.packer.controlFrames[0].(*wire.PathResponseFrame).Data).To(Equal([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) + }) + + It("handles BLOCKED frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.BlockedFrame{}}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + + It("handles STREAM_BLOCKED frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.StreamBlockedFrame{}}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + + It("handles STREAM_ID_BLOCKED frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.StreamIDBlockedFrame{}}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + + It("errors on GOAWAY frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.GoawayFrame{}}, protocol.EncryptionUnspecified) + Expect(err).To(MatchError("unimplemented: handling GOAWAY frames")) + }) + + It("handles STOP_WAITING frames", func() { + err := sess.handleFrames([]wire.Frame{&wire.StopWaitingFrame{LeastUnacked: 10}}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + }) + + It("handles CONNECTION_CLOSE frames", func() { + testErr := qerr.Error(qerr.ProofInvalid, "foobar") + streamManager.EXPECT().CloseWithError(testErr) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err).To(MatchError(testErr)) + }() + err := sess.handleFrames([]wire.Frame{&wire.ConnectionCloseFrame{ErrorCode: qerr.ProofInvalid, ReasonPhrase: "foobar"}}, protocol.EncryptionUnspecified) + Expect(err).NotTo(HaveOccurred()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + }) + + It("tells its versions", func() { + sess.version = 4242 + Expect(sess.GetVersion()).To(Equal(protocol.VersionNumber(4242))) + }) + + It("accepts new streams", func() { + mstr := NewMockStreamI(mockCtrl) + streamManager.EXPECT().AcceptStream().Return(mstr, nil) + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + + Context("closing", func() { + BeforeEach(func() { + Eventually(areSessionsRunning).Should(BeFalse()) + go func() { + defer GinkgoRecover() + sess.run() + }() + Eventually(areSessionsRunning).Should(BeTrue()) + }) + + It("shuts down without error", func() { + streamManager.EXPECT().CloseWithError(qerr.Error(qerr.PeerGoingAway, "")) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(areSessionsRunning).Should(BeFalse()) + Expect(mconn.written).To(HaveLen(1)) + buf := &bytes.Buffer{} + err := (&wire.ConnectionCloseFrame{ErrorCode: qerr.PeerGoingAway}).Write(buf, sess.version) + Expect(err).ToNot(HaveOccurred()) + Expect(mconn.written).To(Receive(ContainSubstring(buf.String()))) + Expect(sess.Context().Done()).To(BeClosed()) + }) + + It("only closes once", func() { + streamManager.EXPECT().CloseWithError(qerr.Error(qerr.PeerGoingAway, "")) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + sess.Close() + Eventually(areSessionsRunning).Should(BeFalse()) + Expect(mconn.written).To(HaveLen(1)) + Expect(sess.Context().Done()).To(BeClosed()) + }) + + It("closes streams with proper error", func() { + testErr := errors.New("test error") + streamManager.EXPECT().CloseWithError(qerr.Error(0x1337, testErr.Error())) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.CloseWithError(0x1337, testErr) + Eventually(areSessionsRunning).Should(BeFalse()) + Expect(sess.Context().Done()).To(BeClosed()) + }) + + It("closes the session in order to replace it with another QUIC version", func() { + streamManager.EXPECT().CloseWithError(gomock.Any()) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.destroy(errCloseSessionForNewVersion) + Eventually(areSessionsRunning).Should(BeFalse()) + Expect(mconn.written).To(BeEmpty()) // no CONNECTION_CLOSE or PUBLIC_RESET sent + }) + + It("sends a Public Reset if the client is initiating the no STOP_WAITING experiment", func() { + streamManager.EXPECT().CloseWithError(gomock.Any()) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.closeLocal(handshake.ErrNSTPExperiment) + Eventually(mconn.written).Should(HaveLen(1)) + Expect((<-mconn.written)[0] & 0x02).ToNot(BeZero()) // Public Reset + Expect(sess.Context().Done()).To(BeClosed()) + }) + + It("cancels the context when the run loop exists", func() { + streamManager.EXPECT().CloseWithError(gomock.Any()) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + returned := make(chan struct{}) + go func() { + defer GinkgoRecover() + ctx := sess.Context() + <-ctx.Done() + Expect(ctx.Err()).To(MatchError(context.Canceled)) + close(returned) + }() + Consistently(returned).ShouldNot(BeClosed()) + sess.Close() + Eventually(returned).Should(BeClosed()) + }) + }) + + Context("receiving packets", func() { + var hdr *wire.Header + var unpacker *MockUnpacker + + BeforeEach(func() { + unpacker = NewMockUnpacker(mockCtrl) + sess.unpacker = unpacker + hdr = &wire.Header{PacketNumberLen: protocol.PacketNumberLen6} + }) + + It("sets the {last,largest}RcvdPacketNumber", func() { + hdr.PacketNumber = 5 + hdr.Raw = []byte("raw header") + unpacker.EXPECT().Unpack([]byte("raw header"), hdr, []byte("foobar")).Return(&unpackedPacket{}, nil) + err := sess.handlePacketImpl(&receivedPacket{header: hdr, data: []byte("foobar")}) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.lastRcvdPacketNumber).To(Equal(protocol.PacketNumber(5))) + Expect(sess.largestRcvdPacketNumber).To(Equal(protocol.PacketNumber(5))) + }) + + It("informs the ReceivedPacketHandler", func() { + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil) + now := time.Now().Add(time.Hour) + rph := mockackhandler.NewMockReceivedPacketHandler(mockCtrl) + rph.EXPECT().ReceivedPacket(protocol.PacketNumber(5), now, false) + sess.receivedPacketHandler = rph + hdr.PacketNumber = 5 + err := sess.handlePacketImpl(&receivedPacket{header: hdr, rcvTime: now}) + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't inform the ReceivedPacketHandler about Retry packets", func() { + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil) + now := time.Now().Add(time.Hour) + rph := mockackhandler.NewMockReceivedPacketHandler(mockCtrl) + sess.receivedPacketHandler = rph + // don't EXPECT any call to ReceivedPacket + hdr.PacketNumber = 5 + hdr.Type = protocol.PacketTypeRetry + err := sess.handlePacketImpl(&receivedPacket{header: hdr, rcvTime: now}) + Expect(err).ToNot(HaveOccurred()) + }) + + It("closes when handling a packet fails", func() { + testErr := errors.New("unpack error") + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, testErr) + streamManager.EXPECT().CloseWithError(gomock.Any()) + hdr.PacketNumber = 5 + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err).To(MatchError(testErr)) + close(done) + }() + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.handlePacket(&receivedPacket{header: hdr}) + Eventually(done).Should(BeClosed()) + }) + + It("sets the {last,largest}RcvdPacketNumber, for an out-of-order packet", func() { + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil).Times(2) + hdr.PacketNumber = 5 + err := sess.handlePacketImpl(&receivedPacket{header: hdr}) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.lastRcvdPacketNumber).To(Equal(protocol.PacketNumber(5))) + Expect(sess.largestRcvdPacketNumber).To(Equal(protocol.PacketNumber(5))) + hdr.PacketNumber = 3 + err = sess.handlePacketImpl(&receivedPacket{header: hdr}) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.lastRcvdPacketNumber).To(Equal(protocol.PacketNumber(3))) + Expect(sess.largestRcvdPacketNumber).To(Equal(protocol.PacketNumber(5))) + }) + + It("handles duplicate packets", func() { + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil).Times(2) + hdr.PacketNumber = 5 + err := sess.handlePacketImpl(&receivedPacket{header: hdr}) + Expect(err).ToNot(HaveOccurred()) + err = sess.handlePacketImpl(&receivedPacket{header: hdr}) + Expect(err).ToNot(HaveOccurred()) + }) + + It("ignores packets with a different source connection ID", func() { + // Send one packet, which might change the connection ID. + // only EXPECT one call to the unpacker + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil) + err := sess.handlePacketImpl(&receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + DestConnectionID: sess.destConnID, + SrcConnectionID: sess.srcConnID, + }, + }) + Expect(err).ToNot(HaveOccurred()) + // The next packet has to be ignored, since the source connection ID doesn't match. + err = sess.handlePacketImpl(&receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + DestConnectionID: sess.destConnID, + SrcConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + }, + }) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("updating the remote address", func() { + It("doesn't support connection migration", func() { + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil) + origAddr := sess.conn.(*mockConnection).remoteAddr + remoteIP := &net.IPAddr{IP: net.IPv4(192, 168, 0, 100)} + Expect(origAddr).ToNot(Equal(remoteIP)) + p := receivedPacket{ + remoteAddr: remoteIP, + header: &wire.Header{PacketNumber: 1337}, + } + err := sess.handlePacketImpl(&p) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.conn.(*mockConnection).remoteAddr).To(Equal(origAddr)) + }) + }) + }) + + Context("sending packets", func() { + BeforeEach(func() { + sess.packer.hasSentPacket = true // make sure this is not the first packet the packer sends + }) + + It("sends ACK frames", func() { + packetNumber := protocol.PacketNumber(0x035e) + err := sess.receivedPacketHandler.ReceivedPacket(packetNumber, time.Now(), true) + Expect(err).ToNot(HaveOccurred()) + sent, err := sess.sendPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + Expect(mconn.written).To(HaveLen(1)) + Expect(mconn.written).To(Receive(ContainSubstring(string([]byte{0x03, 0x5e})))) + }) + + It("adds MAX_STREAM_DATA frames", func() { + sess.windowUpdateQueue.callback(&wire.MaxStreamDataFrame{ + StreamID: 2, + ByteOffset: 20, + }) + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) { + Expect(p.Frames).To(ContainElement(&wire.MaxStreamDataFrame{StreamID: 2, ByteOffset: 20})) + }) + sess.sentPacketHandler = sph + sent, err := sess.sendPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + }) + + It("adds a BLOCKED frame when it is connection-level flow control blocked", func() { + fc := mocks.NewMockConnectionFlowController(mockCtrl) + fc.EXPECT().IsNewlyBlocked().Return(true, protocol.ByteCount(1337)) + sess.connFlowController = fc + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) { + Expect(p.Frames).To(Equal([]wire.Frame{ + &wire.BlockedFrame{Offset: 1337}, + })) + }) + sess.sentPacketHandler = sph + sent, err := sess.sendPacket() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + }) + + It("sends public reset", func() { + err := sess.sendPublicReset(1) + Expect(err).NotTo(HaveOccurred()) + Expect(mconn.written).To(HaveLen(1)) + Expect(mconn.written).To(Receive(ContainSubstring("PRST"))) + }) + + It("doesn't retransmit an Initial packet if it already received a response", func() { + unpacker := NewMockUnpacker(mockCtrl) + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil) + sess.unpacker = unpacker + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sph.EXPECT().DequeuePacketForRetransmission().Return(&ackhandler.Packet{ + PacketNumber: 10, + PacketType: protocol.PacketTypeInitial, + }) + sph.EXPECT().DequeuePacketForRetransmission() + rph := mockackhandler.NewMockReceivedPacketHandler(mockCtrl) + rph.EXPECT().ReceivedPacket(gomock.Any(), gomock.Any(), gomock.Any()) + sess.receivedPacketHandler = rph + sess.sentPacketHandler = sph + err := sess.handlePacketImpl(&receivedPacket{ + header: &wire.Header{}, + data: []byte{0}, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(sess.receivedFirstPacket).To(BeTrue()) + sent, err := sess.maybeSendRetransmission() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeFalse()) + }) + + It("sends a retransmission and a regular packet in the same run", func() { + sess.windowUpdateQueue.callback(&wire.MaxDataFrame{}) + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sph.EXPECT().DequeuePacketForRetransmission().Return(&ackhandler.Packet{ + PacketNumber: 10, + PacketType: protocol.PacketTypeHandshake, + }) + sph.EXPECT().SendMode().Return(ackhandler.SendRetransmission) + sph.EXPECT().SendMode().Return(ackhandler.SendAny) + sph.EXPECT().ShouldSendNumPackets().Return(2) + sph.EXPECT().TimeUntilSend() + sph.EXPECT().GetStopWaitingFrame(gomock.Any()).Return(&wire.StopWaitingFrame{}) + gomock.InOrder( + sph.EXPECT().SentPacketsAsRetransmission(gomock.Any(), protocol.PacketNumber(10)).Do(func(packets []*ackhandler.Packet, _ protocol.PacketNumber) { + Expect(packets).To(HaveLen(1)) + Expect(len(packets[0].Frames)).To(BeNumerically(">", 0)) + Expect(packets[0].Frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(packets[0].SendTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond)) + }), + sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) { + Expect(p.Frames).To(HaveLen(1)) + Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.MaxDataFrame{})) + Expect(p.SendTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond)) + }), + ) + sess.sentPacketHandler = sph + err := sess.sendPackets() + Expect(err).ToNot(HaveOccurred()) + }) + + It("sends a probe packet", func() { + f := &wire.MaxDataFrame{ByteOffset: 1337} + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().TimeUntilSend() + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sph.EXPECT().SendMode().Return(ackhandler.SendTLP) + sph.EXPECT().ShouldSendNumPackets().Return(1) + sph.EXPECT().DequeueProbePacket().Return(&ackhandler.Packet{ + PacketNumber: 0x42, + Frames: []wire.Frame{f}, + }, nil) + sph.EXPECT().GetStopWaitingFrame(true).Return(&wire.StopWaitingFrame{}) + sph.EXPECT().SentPacketsAsRetransmission(gomock.Any(), protocol.PacketNumber(0x42)).Do(func(packets []*ackhandler.Packet, _ protocol.PacketNumber) { + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.Frames).To(HaveLen(2)) + Expect(p.Frames[1]).To(Equal(f)) + }) + sess.sentPacketHandler = sph + err := sess.sendPackets() + Expect(err).ToNot(HaveOccurred()) + }) + + It("doesn't send when the SentPacketHandler doesn't allow it", func() { + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().SendMode().Return(ackhandler.SendNone) + sess.sentPacketHandler = sph + err := sess.sendPackets() + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("packet pacing", func() { + var sph *mockackhandler.MockSentPacketHandler + + BeforeEach(func() { + sph = mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().GetAlarmTimeout().AnyTimes() + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sph.EXPECT().DequeuePacketForRetransmission().AnyTimes() + sess.sentPacketHandler = sph + sess.packer.hasSentPacket = true + streamManager.EXPECT().CloseWithError(gomock.Any()) + }) + + It("sends multiple packets one by one immediately", func() { + sph.EXPECT().SentPacket(gomock.Any()).Times(2) + sph.EXPECT().ShouldSendNumPackets().Return(1).Times(2) + sph.EXPECT().TimeUntilSend().Return(time.Now()).Times(2) + sph.EXPECT().TimeUntilSend().Return(time.Now().Add(time.Hour)) + sph.EXPECT().SendMode().Return(ackhandler.SendAny).Do(func() { + // make sure there's something to send + sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 1}) + }).Times(2) // allow 2 packets... + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + sess.scheduleSending() + Eventually(mconn.written).Should(HaveLen(2)) + Consistently(mconn.written).Should(HaveLen(2)) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + + // when becoming congestion limited, at some point the SendMode will change from SendAny to SendAck + // we shouldn't send the ACK in the same run + It("doesn't send an ACK right after becoming congestion limited", func() { + sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 1}) + sph.EXPECT().SentPacket(gomock.Any()) + sph.EXPECT().ShouldSendNumPackets().Return(1000) + sph.EXPECT().TimeUntilSend().Return(time.Now()) + sph.EXPECT().SendMode().Return(ackhandler.SendAny) + sph.EXPECT().SendMode().Return(ackhandler.SendAck) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + sess.scheduleSending() + Eventually(mconn.written).Should(HaveLen(1)) + Consistently(mconn.written).Should(HaveLen(1)) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + + It("paces packets", func() { + pacingDelay := scaleDuration(100 * time.Millisecond) + sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 1}) + sph.EXPECT().SentPacket(gomock.Any()).Times(2) + sph.EXPECT().TimeUntilSend().Return(time.Now().Add(-time.Minute)) // send one packet immediately + sph.EXPECT().TimeUntilSend().Return(time.Now().Add(pacingDelay)) // send one + sph.EXPECT().TimeUntilSend().Return(time.Now().Add(time.Hour)) + sph.EXPECT().ShouldSendNumPackets().Times(2).Return(1) + sph.EXPECT().SendMode().Return(ackhandler.SendAny).Do(func() { // after sending the first packet + // make sure there's something to send + sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 2}) + }).AnyTimes() + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + sess.scheduleSending() + Eventually(mconn.written).Should(HaveLen(1)) + Consistently(mconn.written, pacingDelay/2).Should(HaveLen(1)) + Eventually(mconn.written, 2*pacingDelay).Should(HaveLen(2)) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + + It("sends multiple packets at once", func() { + sph.EXPECT().SentPacket(gomock.Any()).Times(3) + sph.EXPECT().ShouldSendNumPackets().Return(3) + sph.EXPECT().TimeUntilSend().Return(time.Now()) + sph.EXPECT().TimeUntilSend().Return(time.Now().Add(time.Hour)) + sph.EXPECT().SendMode().Return(ackhandler.SendAny).Do(func() { + // make sure there's something to send + sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 1}) + }).Times(3) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + sess.scheduleSending() + Eventually(mconn.written).Should(HaveLen(3)) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + + It("doesn't set a pacing timer when there is no data to send", func() { + sph.EXPECT().TimeUntilSend().Return(time.Now()) + sph.EXPECT().ShouldSendNumPackets().Return(1) + sph.EXPECT().SendMode().Return(ackhandler.SendAny).AnyTimes() + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + sess.scheduleSending() // no packet will get sent + Consistently(mconn.written).ShouldNot(Receive()) + // queue a frame, and expect that it won't be sent + sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 1}) + Consistently(mconn.written).ShouldNot(Receive()) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + }) + + Context("sending ACK only packets", func() { + It("doesn't do anything if there's no ACK to be sent", func() { + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sess.sentPacketHandler = sph + err := sess.maybeSendAckOnlyPacket() + Expect(err).ToNot(HaveOccurred()) + Expect(mconn.written).To(BeEmpty()) + }) + + It("sends ACK only packets", func() { + swf := &wire.StopWaitingFrame{LeastUnacked: 10} + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sph.EXPECT().GetAlarmTimeout().AnyTimes() + sph.EXPECT().SendMode().Return(ackhandler.SendAck) + sph.EXPECT().ShouldSendNumPackets().Return(1000) + sph.EXPECT().GetStopWaitingFrame(false).Return(swf) + sph.EXPECT().TimeUntilSend() + sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) { + Expect(p.Frames).To(HaveLen(2)) + Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{})) + Expect(p.Frames[1]).To(Equal(swf)) + Expect(p.SendTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond)) + }) + sess.sentPacketHandler = sph + sess.packer.packetNumberGenerator.next = 0x1338 + sess.receivedPacketHandler.ReceivedPacket(1, time.Now(), true) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + sess.scheduleSending() + Eventually(mconn.written).Should(HaveLen(1)) + // make sure that the go routine returns + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + + It("doesn't include a STOP_WAITING for an ACK-only packet for IETF QUIC", func() { + sess.version = versionIETFFrames + done := make(chan struct{}) + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sph.EXPECT().GetAlarmTimeout().AnyTimes() + sph.EXPECT().SendMode().Return(ackhandler.SendAck) + sph.EXPECT().ShouldSendNumPackets().Return(1000) + sph.EXPECT().TimeUntilSend() + sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) { + Expect(p.Frames).To(HaveLen(1)) + Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{})) + Expect(p.SendTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond)) + }) + sess.sentPacketHandler = sph + sess.packer.packetNumberGenerator.next = 0x1338 + sess.receivedPacketHandler.ReceivedPacket(1, time.Now(), true) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + sess.scheduleSending() + Eventually(mconn.written).Should(HaveLen(1)) + // make sure that the go routine returns + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + }) + + Context("retransmissions", func() { + var sph *mockackhandler.MockSentPacketHandler + BeforeEach(func() { + // a STOP_WAITING frame is added, so make sure the packet number of the new package is higher than the packet number of the retransmitted packet + sess.packer.packetNumberGenerator.next = 0x1337 + 10 + sess.packer.hasSentPacket = true // make sure this is not the first packet the packer sends + sph = mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sess.sentPacketHandler = sph + sess.packer.cryptoSetup = &mockCryptoSetup{encLevelSeal: protocol.EncryptionForwardSecure} + }) + + Context("for handshake packets", func() { + It("retransmits an unencrypted packet, and adds a STOP_WAITING frame (for gQUIC)", func() { + sf := &wire.StreamFrame{StreamID: 1, Data: []byte("foobar")} + swf := &wire.StopWaitingFrame{LeastUnacked: 0x1337} + sph.EXPECT().GetStopWaitingFrame(true).Return(swf) + sph.EXPECT().DequeuePacketForRetransmission().Return(&ackhandler.Packet{ + PacketNumber: 42, + Frames: []wire.Frame{sf}, + EncryptionLevel: protocol.EncryptionUnencrypted, + }) + sph.EXPECT().SentPacketsAsRetransmission(gomock.Any(), protocol.PacketNumber(42)).Do(func(packets []*ackhandler.Packet, _ protocol.PacketNumber) { + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.EncryptionLevel).To(Equal(protocol.EncryptionUnencrypted)) + Expect(p.Frames).To(Equal([]wire.Frame{swf, sf})) + Expect(p.SendTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond)) + }) + sent, err := sess.maybeSendRetransmission() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + Expect(mconn.written).To(HaveLen(1)) + }) + + It("retransmits an unencrypted packet, and doesn't add a STOP_WAITING frame (for IETF QUIC)", func() { + sess.version = versionIETFFrames + sess.packer.version = versionIETFFrames + sess.packer.srcConnID = sess.destConnID + sf := &wire.StreamFrame{StreamID: 1, Data: []byte("foobar")} + sph.EXPECT().DequeuePacketForRetransmission().Return(&ackhandler.Packet{ + PacketNumber: 1337, + Frames: []wire.Frame{sf}, + EncryptionLevel: protocol.EncryptionUnencrypted, + }) + sph.EXPECT().SentPacketsAsRetransmission(gomock.Any(), protocol.PacketNumber(1337)).Do(func(packets []*ackhandler.Packet, _ protocol.PacketNumber) { + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.EncryptionLevel).To(Equal(protocol.EncryptionUnencrypted)) + Expect(p.Frames).To(Equal([]wire.Frame{sf})) + Expect(p.SendTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond)) + }) + sent, err := sess.maybeSendRetransmission() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + Expect(mconn.written).To(HaveLen(1)) + }) + }) + + Context("for packets after the handshake", func() { + It("sends a STREAM frame from a packet queued for retransmission, and adds a STOP_WAITING (for gQUIC)", func() { + f := &wire.StreamFrame{ + StreamID: 0x5, + Data: []byte("foobar"), + } + swf := &wire.StopWaitingFrame{LeastUnacked: 10} + sph.EXPECT().GetStopWaitingFrame(true).Return(swf) + sph.EXPECT().DequeuePacketForRetransmission().Return(&ackhandler.Packet{ + PacketNumber: 0x1337, + Frames: []wire.Frame{f}, + EncryptionLevel: protocol.EncryptionForwardSecure, + }) + sph.EXPECT().SentPacketsAsRetransmission(gomock.Any(), protocol.PacketNumber(0x1337)).Do(func(packets []*ackhandler.Packet, _ protocol.PacketNumber) { + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.Frames).To(HaveLen(2)) + Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.StopWaitingFrame{})) + Expect(p.Frames[1]).To(Equal(f)) + Expect(p.EncryptionLevel).To(Equal(protocol.EncryptionForwardSecure)) + }) + sent, err := sess.maybeSendRetransmission() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + Expect(mconn.written).To(HaveLen(1)) + }) + + It("sends a STREAM frame from a packet queued for retransmission, and doesn't add a STOP_WAITING (for IETF QUIC)", func() { + sess.version = versionIETFFrames + sess.packer.version = versionIETFFrames + f := &wire.StreamFrame{ + StreamID: 0x5, + Data: []byte("foobar"), + } + sph.EXPECT().DequeuePacketForRetransmission().Return(&ackhandler.Packet{ + PacketNumber: 42, + Frames: []wire.Frame{f}, + EncryptionLevel: protocol.EncryptionForwardSecure, + }) + sph.EXPECT().SentPacketsAsRetransmission(gomock.Any(), protocol.PacketNumber(42)).Do(func(packets []*ackhandler.Packet, _ protocol.PacketNumber) { + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.Frames).To(Equal([]wire.Frame{f})) + Expect(p.EncryptionLevel).To(Equal(protocol.EncryptionForwardSecure)) + }) + sent, err := sess.maybeSendRetransmission() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + Expect(mconn.written).To(HaveLen(1)) + }) + + It("sends multiple packets, if the retransmission is split", func() { + sess.version = versionIETFFrames + sess.packer.version = versionIETFFrames + f := &wire.StreamFrame{ + StreamID: 0x5, + Data: bytes.Repeat([]byte{'b'}, int(protocol.MaxPacketSizeIPv4)*3/2), + } + sph.EXPECT().DequeuePacketForRetransmission().Return(&ackhandler.Packet{ + PacketNumber: 42, + Frames: []wire.Frame{f}, + EncryptionLevel: protocol.EncryptionForwardSecure, + }) + sph.EXPECT().SentPacketsAsRetransmission(gomock.Any(), protocol.PacketNumber(42)).Do(func(packets []*ackhandler.Packet, _ protocol.PacketNumber) { + Expect(packets).To(HaveLen(2)) + for _, p := range packets { + Expect(p.Frames).To(HaveLen(1)) + Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.StreamFrame{})) + Expect(p.EncryptionLevel).To(Equal(protocol.EncryptionForwardSecure)) + } + }) + sent, err := sess.maybeSendRetransmission() + Expect(err).NotTo(HaveOccurred()) + Expect(sent).To(BeTrue()) + Expect(mconn.written).To(HaveLen(2)) + }) + }) + }) + + Context("scheduling sending", func() { + BeforeEach(func() { + sess.packer.hasSentPacket = true // make sure this is not the first packet the packer sends + sess.packer.cryptoSetup = &mockCryptoSetup{encLevelSeal: protocol.EncryptionForwardSecure} + }) + + It("sends when scheduleSending is called", func() { + sess.packer.packetNumberGenerator.next = 10000 + sess.packer.QueueControlFrame(&wire.BlockedFrame{}) + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().GetAlarmTimeout().AnyTimes() + sph.EXPECT().TimeUntilSend().AnyTimes() + sph.EXPECT().SendMode().Return(ackhandler.SendAny).AnyTimes() + sph.EXPECT().ShouldSendNumPackets().AnyTimes().Return(1) + sph.EXPECT().GetPacketNumberLen(gomock.Any()).Return(protocol.PacketNumberLen2).AnyTimes() + sph.EXPECT().SentPacket(gomock.Any()) + sess.sentPacketHandler = sph + + go func() { + defer GinkgoRecover() + sess.run() + }() + Consistently(mconn.written).ShouldNot(Receive()) + sess.scheduleSending() + Eventually(mconn.written).Should(Receive()) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + sess.Close() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("sets the timer to the ack timer", func() { + sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) + sph.EXPECT().TimeUntilSend().Return(time.Now()) + sph.EXPECT().TimeUntilSend().Return(time.Now().Add(time.Hour)) + sph.EXPECT().GetAlarmTimeout().AnyTimes() + sph.EXPECT().SendMode().Return(ackhandler.SendAny).AnyTimes() + sph.EXPECT().GetStopWaitingFrame(gomock.Any()) + sph.EXPECT().ShouldSendNumPackets().Return(1) + sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) { + Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{})) + Expect(p.Frames[0].(*wire.AckFrame).LargestAcked()).To(Equal(protocol.PacketNumber(0x1337))) + }) + sess.sentPacketHandler = sph + rph := mockackhandler.NewMockReceivedPacketHandler(mockCtrl) + rph.EXPECT().GetAckFrame().Return(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 0x1337}}}) + rph.EXPECT().GetAlarmTimeout().Return(time.Now().Add(10 * time.Millisecond)) + rph.EXPECT().GetAlarmTimeout().Return(time.Now().Add(time.Hour)) + sess.receivedPacketHandler = rph + + go func() { + defer GinkgoRecover() + sess.run() + }() + Eventually(mconn.written).Should(Receive()) + // make sure the go routine returns + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + sess.Close() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + }) + + It("closes when crypto stream errors", func() { + testErr := errors.New("crypto setup error") + streamManager.EXPECT().CloseWithError(qerr.Error(qerr.InternalError, testErr.Error())) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + cryptoSetup.handleErr = testErr + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err).To(MatchError(testErr)) + }() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + Context("sending a Public Reset when receiving undecryptable packets during the handshake", func() { + // sends protocol.MaxUndecryptablePackets+1 undecrytable packets + // this completely fills up the undecryptable packets queue and triggers the public reset timer + sendUndecryptablePackets := func() { + for i := 0; i < protocol.MaxUndecryptablePackets+1; i++ { + hdr := &wire.Header{ + PacketNumber: protocol.PacketNumber(i + 1), + } + sess.handlePacket(&receivedPacket{ + header: hdr, + remoteAddr: &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1234}, + data: []byte("foobar"), + }) + } + } + + BeforeEach(func() { + unpacker := NewMockUnpacker(mockCtrl) + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, qerr.Error(qerr.DecryptionFailure, "")).AnyTimes() + sess.unpacker = unpacker + sess.cryptoStreamHandler = &mockCryptoSetup{} + streamManager.EXPECT().CloseWithError(gomock.Any()).MaxTimes(1) + }) + + It("doesn't immediately send a Public Reset after receiving too many undecryptable packets", func() { + go func() { + defer GinkgoRecover() + sess.run() + }() + sendUndecryptablePackets() + sess.scheduleSending() + Consistently(mconn.written).Should(HaveLen(0)) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("sets a deadline to send a Public Reset after receiving too many undecryptable packets", func() { + go func() { + defer GinkgoRecover() + sess.run() + }() + sendUndecryptablePackets() + Eventually(func() time.Time { return sess.receivedTooManyUndecrytablePacketsTime }).Should(BeTemporally("~", time.Now(), 20*time.Millisecond)) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("drops undecryptable packets when the undecrytable packet queue is full", func() { + go func() { + defer GinkgoRecover() + sess.run() + }() + sendUndecryptablePackets() + Eventually(func() []*receivedPacket { return sess.undecryptablePackets }).Should(HaveLen(protocol.MaxUndecryptablePackets)) + // check that old packets are kept, and the new packets are dropped + Expect(sess.undecryptablePackets[0].header.PacketNumber).To(Equal(protocol.PacketNumber(1))) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("sends a Public Reset after a timeout", func() { + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.receivedTooManyUndecrytablePacketsTime).To(BeZero()) + go func() { + defer GinkgoRecover() + sess.run() + }() + sendUndecryptablePackets() + Eventually(func() time.Time { return sess.receivedTooManyUndecrytablePacketsTime }).Should(BeTemporally("~", time.Now(), time.Second)) + // speed up this test by manually setting back the time when too many packets were received + sess.receivedTooManyUndecrytablePacketsTime = time.Now().Add(-protocol.PublicResetTimeout) + time.Sleep(10 * time.Millisecond) // wait for the run loop to spin up + sess.scheduleSending() // wake up the run loop + Eventually(mconn.written).Should(HaveLen(1)) + Expect(mconn.written).To(Receive(ContainSubstring("PRST"))) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("doesn't send a Public Reset if decrypting them succeeded during the timeout", func() { + go func() { + defer GinkgoRecover() + sess.run() + }() + sess.receivedTooManyUndecrytablePacketsTime = time.Now().Add(-protocol.PublicResetTimeout).Add(-time.Millisecond) + sess.scheduleSending() // wake up the run loop + // there are no packets in the undecryptable packet queue + // in reality, this happens when the trial decryption succeeded during the Public Reset timeout + Consistently(mconn.written).ShouldNot(HaveLen(1)) + Expect(sess.Context().Done()).ToNot(Receive()) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("ignores undecryptable packets after the handshake is complete", func() { + sess.handshakeComplete = true + go func() { + defer GinkgoRecover() + sess.run() + }() + sendUndecryptablePackets() + Consistently(sess.undecryptablePackets).Should(BeEmpty()) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("unqueues undecryptable packets for later decryption", func() { + sess.undecryptablePackets = []*receivedPacket{{ + header: &wire.Header{PacketNumber: protocol.PacketNumber(42)}, + }} + Expect(sess.receivedPackets).NotTo(Receive()) + sess.tryDecryptingQueuedPackets() + Expect(sess.undecryptablePackets).To(BeEmpty()) + Expect(sess.receivedPackets).To(Receive()) + }) + }) + + It("doesn't do anything when the crypto setup says to decrypt undecryptable packets", func() { + go func() { + defer GinkgoRecover() + sess.run() + }() + handshakeChan <- struct{}{} + // don't EXPECT any calls to sessionRunner.onHandshakeComplete() + // make sure the go routine returns + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("calls the onHandshakeComplete callback when the handshake completes", func() { + go func() { + defer GinkgoRecover() + sess.run() + }() + sessionRunner.EXPECT().onHandshakeComplete(gomock.Any()) + close(handshakeChan) + Consistently(sess.Context().Done()).ShouldNot(BeClosed()) + // make sure the go routine returns + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("doesn't return a run error when closing", func() { + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + streamManager.EXPECT().CloseWithError(gomock.Any()) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(done).Should(BeClosed()) + }) + + It("passes errors to the session runner", func() { + testErr := errors.New("handshake error") + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err).To(MatchError(qerr.Error(0x1337, testErr.Error()))) + close(done) + }() + streamManager.EXPECT().CloseWithError(gomock.Any()) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.CloseWithError(0x1337, testErr)).To(Succeed()) + Eventually(done).Should(BeClosed()) + }) + + It("process transport parameters received from the peer", func() { + paramsChan := make(chan handshake.TransportParameters) + sess.paramsChan = paramsChan + go func() { + defer GinkgoRecover() + sess.run() + }() + params := handshake.TransportParameters{ + MaxStreams: 123, + IdleTimeout: 90 * time.Second, + StreamFlowControlWindow: 0x5000, + ConnectionFlowControlWindow: 0x5000, + OmitConnectionID: true, + MaxPacketSize: 0x42, + } + streamManager.EXPECT().UpdateLimits(¶ms) + paramsChan <- params + Eventually(func() *handshake.TransportParameters { return sess.peerParams }).Should(Equal(¶ms)) + Eventually(func() bool { return sess.packer.omitConnectionID }).Should(BeTrue()) + Eventually(func() protocol.ByteCount { return sess.packer.maxPacketSize }).Should(Equal(protocol.ByteCount(0x42))) + // make the go routine return + streamManager.EXPECT().CloseWithError(gomock.Any()) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + Context("keep-alives", func() { + // should be shorter than the local timeout for these tests + // otherwise we'd send a CONNECTION_CLOSE in the tests where we're testing that no PING is sent + remoteIdleTimeout := 20 * time.Second + + BeforeEach(func() { + sess.peerParams = &handshake.TransportParameters{IdleTimeout: remoteIdleTimeout} + }) + + It("sends a PING", func() { + sess.handshakeComplete = true + sess.config.KeepAlive = true + sess.lastNetworkActivityTime = time.Now().Add(-remoteIdleTimeout / 2) + sess.packer.hasSentPacket = true // make sure this is not the first packet the packer sends + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + var data []byte + Eventually(mconn.written).Should(Receive(&data)) + // -12 because of the crypto tag. This should be 7 (the frame id for a ping frame). + Expect(data[len(data)-12-1 : len(data)-12]).To(Equal([]byte{0x07})) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + + It("doesn't send a PING packet if keep-alive is disabled", func() { + sess.handshakeComplete = true + sess.config.KeepAlive = false + sess.lastNetworkActivityTime = time.Now().Add(-remoteIdleTimeout / 2) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + Consistently(mconn.written).ShouldNot(Receive()) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + + It("doesn't send a PING if the handshake isn't completed yet", func() { + sess.handshakeComplete = false + sess.config.KeepAlive = true + sess.lastNetworkActivityTime = time.Now().Add(-remoteIdleTimeout / 2) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess.run() + close(done) + }() + Consistently(mconn.written).ShouldNot(Receive()) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + streamManager.EXPECT().CloseWithError(gomock.Any()) + sess.Close() + Eventually(done).Should(BeClosed()) + }) + }) + + Context("timeouts", func() { + BeforeEach(func() { + streamManager.EXPECT().CloseWithError(gomock.Any()) + }) + + It("times out due to no network activity", func() { + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.handshakeComplete = true + sess.lastNetworkActivityTime = time.Now().Add(-time.Hour) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.NetworkIdleTimeout)) + close(done) + }() + Eventually(done).Should(BeClosed()) + Expect(mconn.written).To(Receive(ContainSubstring("No recent network activity."))) + }) + + It("times out due to non-completed handshake", func() { + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.sessionCreationTime = time.Now().Add(-protocol.DefaultHandshakeTimeout).Add(-time.Second) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.HandshakeTimeout)) + close(done) + }() + Eventually(done).Should(BeClosed()) + Expect(mconn.written).To(Receive(ContainSubstring("Crypto handshake did not complete in time."))) + }) + + It("does not use the idle timeout before the handshake complete", func() { + sess.config.IdleTimeout = 9999 * time.Second + defer sess.Close() + sess.lastNetworkActivityTime = time.Now().Add(-time.Minute) + // the handshake timeout is irrelevant here, since it depends on the time the session was created, + // and not on the last network activity + go func() { + defer GinkgoRecover() + sess.run() + }() + Consistently(sess.Context().Done()).ShouldNot(BeClosed()) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.Close() + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("closes the session due to the idle timeout after handshake", func() { + sessionRunner.EXPECT().onHandshakeComplete(sess) + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + sess.config.IdleTimeout = 0 + close(handshakeChan) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + err := sess.run() + Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.NetworkIdleTimeout)) + close(done) + }() + Eventually(done).Should(BeClosed()) + Expect(mconn.written).To(Receive(ContainSubstring("No recent network activity."))) + }) + }) + + It("stores up to MaxSessionUnprocessedPackets packets", func(done Done) { + // Nothing here should block + for i := protocol.PacketNumber(0); i < protocol.MaxSessionUnprocessedPackets+10; i++ { + sess.handlePacket(&receivedPacket{}) + } + close(done) + }, 0.5) + + Context("getting streams", func() { + It("returns a new stream", func() { + mstr := NewMockStreamI(mockCtrl) + streamManager.EXPECT().GetOrOpenSendStream(protocol.StreamID(11)).Return(mstr, nil) + str, err := sess.GetOrOpenStream(11) + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + + It("returns a nil-value (not an interface with value nil) for closed streams", func() { + strI := Stream(nil) + streamManager.EXPECT().GetOrOpenSendStream(protocol.StreamID(1337)).Return(strI, nil) + str, err := sess.GetOrOpenStream(1337) + Expect(err).ToNot(HaveOccurred()) + // make sure that the returned value is a plain nil, not an Stream with value nil + _, ok := str.(Stream) + Expect(ok).To(BeFalse()) + }) + + It("errors when trying to get a unidirectional stream", func() { + streamManager.EXPECT().GetOrOpenSendStream(protocol.StreamID(100)).Return(&sendStream{}, nil) + _, err := sess.GetOrOpenStream(100) + Expect(err).To(MatchError("Stream 100 is not a bidirectional stream")) + }) + + It("opens streams", func() { + mstr := NewMockStreamI(mockCtrl) + streamManager.EXPECT().OpenStream().Return(mstr, nil) + str, err := sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + + It("opens streams synchronously", func() { + mstr := NewMockStreamI(mockCtrl) + streamManager.EXPECT().OpenStreamSync().Return(mstr, nil) + str, err := sess.OpenStreamSync() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + + It("opens unidirectional streams", func() { + mstr := NewMockSendStreamI(mockCtrl) + streamManager.EXPECT().OpenUniStream().Return(mstr, nil) + str, err := sess.OpenUniStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + + It("opens unidirectional streams synchronously", func() { + mstr := NewMockSendStreamI(mockCtrl) + streamManager.EXPECT().OpenUniStreamSync().Return(mstr, nil) + str, err := sess.OpenUniStreamSync() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + + It("accepts streams", func() { + mstr := NewMockStreamI(mockCtrl) + streamManager.EXPECT().AcceptStream().Return(mstr, nil) + str, err := sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + + It("accepts unidirectional streams", func() { + mstr := NewMockReceiveStreamI(mockCtrl) + streamManager.EXPECT().AcceptUniStream().Return(mstr, nil) + str, err := sess.AcceptUniStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(Equal(mstr)) + }) + }) + + It("returns the local address", func() { + addr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337} + mconn.localAddr = addr + Expect(sess.LocalAddr()).To(Equal(addr)) + }) + + It("returns the remote address", func() { + addr := &net.UDPAddr{IP: net.IPv4(1, 2, 7, 1), Port: 7331} + mconn.remoteAddr = addr + Expect(sess.RemoteAddr()).To(Equal(addr)) + }) +}) + +var _ = Describe("Client Session", func() { + var ( + sess *session + sessionRunner *MockSessionRunner + mconn *mockConnection + handshakeChan chan<- struct{} + + cryptoSetup *mockCryptoSetup + ) + + BeforeEach(func() { + Eventually(areSessionsRunning).Should(BeFalse()) + + cryptoSetup = &mockCryptoSetup{} + newCryptoSetupClient = func( + _ io.ReadWriter, + _ string, + _ protocol.ConnectionID, + _ protocol.VersionNumber, + _ *tls.Config, + _ *handshake.TransportParameters, + _ chan<- handshake.TransportParameters, + handshakeChanP chan<- struct{}, + _ protocol.VersionNumber, + _ []protocol.VersionNumber, + _ utils.Logger, + ) (handshake.CryptoSetup, error) { + handshakeChan = handshakeChanP + return cryptoSetup, nil + } + + mconn = newMockConnection() + sessionRunner = NewMockSessionRunner(mockCtrl) + sessP, err := newClientSession( + mconn, + sessionRunner, + "hostname", + protocol.Version39, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + nil, + populateClientConfig(&Config{}, false), + protocol.VersionWhatever, + nil, + utils.DefaultLogger, + ) + sess = sessP.(*session) + Expect(err).ToNot(HaveOccurred()) + }) + + AfterEach(func() { + newCryptoSetupClient = handshake.NewCryptoSetupClient + }) + + It("sends a forward-secure packet when the handshake completes", func() { + sessionRunner.EXPECT().onHandshakeComplete(gomock.Any()) + sess.packer.hasSentPacket = true + go func() { + defer GinkgoRecover() + sess.run() + }() + close(handshakeChan) + Eventually(mconn.written).Should(Receive()) + //make sure the go routine returns + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + It("changes the connection ID when receiving the first packet from the server", func() { + sess.version = protocol.VersionTLS + sess.packer.version = protocol.VersionTLS + sess.packer.srcConnID = sess.destConnID + unpacker := NewMockUnpacker(mockCtrl) + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil) + sess.unpacker = unpacker + go func() { + defer GinkgoRecover() + sess.run() + }() + err := sess.handlePacketImpl(&receivedPacket{ + header: &wire.Header{ + IsLongHeader: true, + Type: protocol.PacketTypeHandshake, + SrcConnectionID: protocol.ConnectionID{1, 3, 3, 7, 1, 3, 3, 7}, + DestConnectionID: sess.srcConnID, + }, + data: []byte{0}, + }) + Expect(err).ToNot(HaveOccurred()) + // the session should have changed the dest connection ID now + sess.packer.hasSentPacket = true + sess.queueControlFrame(&wire.PingFrame{}) + var packet []byte + Eventually(mconn.written).Should(Receive(&packet)) + hdr, err := wire.ParseInvariantHeader(bytes.NewReader(packet), 0) + Expect(err).ToNot(HaveOccurred()) + Expect(hdr.DestConnectionID).To(Equal(protocol.ConnectionID{1, 3, 3, 7, 1, 3, 3, 7})) + // make sure the go routine returns + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + + Context("receiving packets", func() { + var hdr *wire.Header + + BeforeEach(func() { + hdr = &wire.Header{PacketNumberLen: protocol.PacketNumberLen6} + }) + + It("passes the diversification nonce to the crypto setup", func() { + cryptoSetup := &mockCryptoSetup{} + sess.cryptoStreamHandler = cryptoSetup + unpacker := NewMockUnpacker(mockCtrl) + unpacker.EXPECT().Unpack(gomock.Any(), gomock.Any(), gomock.Any()).Return(&unpackedPacket{}, nil) + sess.unpacker = unpacker + go func() { + defer GinkgoRecover() + sess.run() + }() + hdr.PacketNumber = 5 + hdr.DiversificationNonce = []byte("foobar") + err := sess.handlePacketImpl(&receivedPacket{header: hdr}) + Expect(err).ToNot(HaveOccurred()) + Expect(cryptoSetup.divNonce).To(Equal(hdr.DiversificationNonce)) + // make the go routine return + sessionRunner.EXPECT().removeConnectionID(gomock.Any()) + Expect(sess.Close()).To(Succeed()) + Eventually(sess.Context().Done()).Should(BeClosed()) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/stream.go b/vendor/lucas-clemente/quic-go/stream.go new file mode 100644 index 00000000..5d6ce671 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/stream.go @@ -0,0 +1,176 @@ +package quic + +import ( + "net" + "sync" + "time" + + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +const ( + errorCodeStopping protocol.ApplicationErrorCode = 0 + errorCodeStoppingGQUIC protocol.ApplicationErrorCode = 7 +) + +// The streamSender is notified by the stream about various events. +type streamSender interface { + queueControlFrame(wire.Frame) + onHasStreamData(protocol.StreamID) + // must be called without holding the mutex that is acquired by closeForShutdown + onStreamCompleted(protocol.StreamID) +} + +// Each of the both stream halves gets its own uniStreamSender. +// This is necessary in order to keep track when both halves have been completed. +type uniStreamSender struct { + streamSender + onStreamCompletedImpl func() +} + +func (s *uniStreamSender) queueControlFrame(f wire.Frame) { + s.streamSender.queueControlFrame(f) +} + +func (s *uniStreamSender) onHasStreamData(id protocol.StreamID) { + s.streamSender.onHasStreamData(id) +} + +func (s *uniStreamSender) onStreamCompleted(protocol.StreamID) { + s.onStreamCompletedImpl() +} + +var _ streamSender = &uniStreamSender{} + +type streamI interface { + Stream + closeForShutdown(error) + // for receiving + handleStreamFrame(*wire.StreamFrame) error + handleRstStreamFrame(*wire.RstStreamFrame) error + getWindowUpdate() protocol.ByteCount + // for sending + handleStopSendingFrame(*wire.StopSendingFrame) + popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool) + handleMaxStreamDataFrame(*wire.MaxStreamDataFrame) +} + +var _ receiveStreamI = (streamI)(nil) +var _ sendStreamI = (streamI)(nil) + +// A Stream assembles the data from StreamFrames and provides a super-convenient Read-Interface +// +// Read() and Write() may be called concurrently, but multiple calls to Read() or Write() individually must be synchronized manually. +type stream struct { + receiveStream + sendStream + + completedMutex sync.Mutex + sender streamSender + receiveStreamCompleted bool + sendStreamCompleted bool + + version protocol.VersionNumber +} + +var _ Stream = &stream{} + +type deadlineError struct{} + +func (deadlineError) Error() string { return "deadline exceeded" } +func (deadlineError) Temporary() bool { return true } +func (deadlineError) Timeout() bool { return true } + +var errDeadline net.Error = &deadlineError{} + +type streamCanceledError struct { + error + errorCode protocol.ApplicationErrorCode +} + +func (streamCanceledError) Canceled() bool { return true } +func (e streamCanceledError) ErrorCode() protocol.ApplicationErrorCode { return e.errorCode } + +var _ StreamError = &streamCanceledError{} + +// newStream creates a new Stream +func newStream(streamID protocol.StreamID, + sender streamSender, + flowController flowcontrol.StreamFlowController, + version protocol.VersionNumber, +) *stream { + s := &stream{sender: sender, version: version} + senderForSendStream := &uniStreamSender{ + streamSender: sender, + onStreamCompletedImpl: func() { + s.completedMutex.Lock() + s.sendStreamCompleted = true + s.checkIfCompleted() + s.completedMutex.Unlock() + }, + } + s.sendStream = *newSendStream(streamID, senderForSendStream, flowController, version) + senderForReceiveStream := &uniStreamSender{ + streamSender: sender, + onStreamCompletedImpl: func() { + s.completedMutex.Lock() + s.receiveStreamCompleted = true + s.checkIfCompleted() + s.completedMutex.Unlock() + }, + } + s.receiveStream = *newReceiveStream(streamID, senderForReceiveStream, flowController, version) + return s +} + +// need to define StreamID() here, since both receiveStream and readStream have a StreamID() +func (s *stream) StreamID() protocol.StreamID { + // the result is same for receiveStream and sendStream + return s.sendStream.StreamID() +} + +func (s *stream) Close() error { + if err := s.sendStream.Close(); err != nil { + return err + } + // in gQUIC, we need to send a RST_STREAM with the final offset if CancelRead() was called + s.receiveStream.onClose(s.sendStream.getWriteOffset()) + return nil +} + +func (s *stream) SetDeadline(t time.Time) error { + _ = s.SetReadDeadline(t) // SetReadDeadline never errors + _ = s.SetWriteDeadline(t) // SetWriteDeadline never errors + return nil +} + +// CloseForShutdown closes a stream abruptly. +// It makes Read and Write unblock (and return the error) immediately. +// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST. +func (s *stream) closeForShutdown(err error) { + s.sendStream.closeForShutdown(err) + s.receiveStream.closeForShutdown(err) +} + +func (s *stream) handleRstStreamFrame(frame *wire.RstStreamFrame) error { + if err := s.receiveStream.handleRstStreamFrame(frame); err != nil { + return err + } + if !s.version.UsesIETFFrameFormat() { + s.handleStopSendingFrame(&wire.StopSendingFrame{ + StreamID: s.StreamID(), + ErrorCode: frame.ErrorCode, + }) + } + return nil +} + +// checkIfCompleted is called from the uniStreamSender, when one of the stream halves is completed. +// It makes sure that the onStreamCompleted callback is only called if both receive and send side have completed. +func (s *stream) checkIfCompleted() { + if s.sendStreamCompleted && s.receiveStreamCompleted { + s.sender.onStreamCompleted(s.StreamID()) + } +} diff --git a/vendor/lucas-clemente/quic-go/stream_framer.go b/vendor/lucas-clemente/quic-go/stream_framer.go new file mode 100644 index 00000000..aabfac9f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/stream_framer.go @@ -0,0 +1,98 @@ +package quic + +import ( + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type streamFramer struct { + streamGetter streamGetter + cryptoStream cryptoStream + version protocol.VersionNumber + + streamQueueMutex sync.Mutex + activeStreams map[protocol.StreamID]struct{} + streamQueue []protocol.StreamID + hasCryptoStreamData bool +} + +func newStreamFramer( + cryptoStream cryptoStream, + streamGetter streamGetter, + v protocol.VersionNumber, +) *streamFramer { + return &streamFramer{ + streamGetter: streamGetter, + cryptoStream: cryptoStream, + activeStreams: make(map[protocol.StreamID]struct{}), + version: v, + } +} + +func (f *streamFramer) AddActiveStream(id protocol.StreamID) { + if id == f.version.CryptoStreamID() { // the crypto stream is handled separately + f.streamQueueMutex.Lock() + f.hasCryptoStreamData = true + f.streamQueueMutex.Unlock() + return + } + f.streamQueueMutex.Lock() + if _, ok := f.activeStreams[id]; !ok { + f.streamQueue = append(f.streamQueue, id) + f.activeStreams[id] = struct{}{} + } + f.streamQueueMutex.Unlock() +} + +func (f *streamFramer) HasCryptoStreamData() bool { + f.streamQueueMutex.Lock() + hasCryptoStreamData := f.hasCryptoStreamData + f.streamQueueMutex.Unlock() + return hasCryptoStreamData +} + +func (f *streamFramer) PopCryptoStreamFrame(maxLen protocol.ByteCount) *wire.StreamFrame { + f.streamQueueMutex.Lock() + frame, hasMoreData := f.cryptoStream.popStreamFrame(maxLen) + f.hasCryptoStreamData = hasMoreData + f.streamQueueMutex.Unlock() + return frame +} + +func (f *streamFramer) PopStreamFrames(maxTotalLen protocol.ByteCount) []*wire.StreamFrame { + var currentLen protocol.ByteCount + var frames []*wire.StreamFrame + f.streamQueueMutex.Lock() + // pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet + numActiveStreams := len(f.streamQueue) + for i := 0; i < numActiveStreams; i++ { + if maxTotalLen-currentLen < protocol.MinStreamFrameSize { + break + } + id := f.streamQueue[0] + f.streamQueue = f.streamQueue[1:] + // This should never return an error. Better check it anyway. + // The stream will only be in the streamQueue, if it enqueued itself there. + str, err := f.streamGetter.GetOrOpenSendStream(id) + // The stream can be nil if it completed after it said it had data. + if str == nil || err != nil { + delete(f.activeStreams, id) + continue + } + frame, hasMoreData := str.popStreamFrame(maxTotalLen - currentLen) + if hasMoreData { // put the stream back in the queue (at the end) + f.streamQueue = append(f.streamQueue, id) + } else { // no more data to send. Stream is not active any more + delete(f.activeStreams, id) + } + if frame == nil { // can happen if the receiveStream was canceled after it said it had data + continue + } + frames = append(frames, frame) + currentLen += frame.Length(f.version) + } + f.streamQueueMutex.Unlock() + return frames +} diff --git a/vendor/lucas-clemente/quic-go/stream_framer_test.go b/vendor/lucas-clemente/quic-go/stream_framer_test.go new file mode 100644 index 00000000..fff5e223 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/stream_framer_test.go @@ -0,0 +1,207 @@ +package quic + +import ( + "bytes" + + "github.com/golang/mock/gomock" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Stream Framer", func() { + const ( + id1 = protocol.StreamID(10) + id2 = protocol.StreamID(11) + ) + + var ( + framer *streamFramer + cryptoStream *MockCryptoStream + stream1, stream2 *MockSendStreamI + streamGetter *MockStreamGetter + ) + + BeforeEach(func() { + streamGetter = NewMockStreamGetter(mockCtrl) + stream1 = NewMockSendStreamI(mockCtrl) + stream1.EXPECT().StreamID().Return(protocol.StreamID(5)).AnyTimes() + stream2 = NewMockSendStreamI(mockCtrl) + stream2.EXPECT().StreamID().Return(protocol.StreamID(6)).AnyTimes() + cryptoStream = NewMockCryptoStream(mockCtrl) + framer = newStreamFramer(cryptoStream, streamGetter, versionGQUICFrames) + }) + + Context("handling the crypto stream", func() { + It("says if it has crypto stream data", func() { + Expect(framer.HasCryptoStreamData()).To(BeFalse()) + framer.AddActiveStream(framer.version.CryptoStreamID()) + Expect(framer.HasCryptoStreamData()).To(BeTrue()) + }) + + It("says that it doesn't have crypto stream data after popping all data", func() { + streamID := framer.version.CryptoStreamID() + f := &wire.StreamFrame{ + StreamID: streamID, + Data: []byte("foobar"), + } + cryptoStream.EXPECT().popStreamFrame(protocol.ByteCount(1000)).Return(f, false) + framer.AddActiveStream(streamID) + Expect(framer.PopCryptoStreamFrame(1000)).To(Equal(f)) + Expect(framer.HasCryptoStreamData()).To(BeFalse()) + }) + + It("says that it has more crypto stream data if not all data was popped", func() { + streamID := framer.version.CryptoStreamID() + f := &wire.StreamFrame{ + StreamID: streamID, + Data: []byte("foobar"), + } + cryptoStream.EXPECT().popStreamFrame(protocol.ByteCount(1000)).Return(f, true) + framer.AddActiveStream(streamID) + Expect(framer.PopCryptoStreamFrame(1000)).To(Equal(f)) + Expect(framer.HasCryptoStreamData()).To(BeTrue()) + }) + }) + + Context("Popping", func() { + It("returns nil when popping an empty framer", func() { + Expect(framer.PopStreamFrames(1000)).To(BeEmpty()) + }) + + It("returns STREAM frames", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) + f := &wire.StreamFrame{ + StreamID: id1, + Data: []byte("foobar"), + Offset: 42, + } + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f, false) + framer.AddActiveStream(id1) + fs := framer.PopStreamFrames(1000) + Expect(fs).To(Equal([]*wire.StreamFrame{f})) + }) + + It("skips a stream that was reported active, but was completed shortly after", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(nil, nil) + streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) + f := &wire.StreamFrame{ + StreamID: id2, + Data: []byte("foobar"), + } + stream2.EXPECT().popStreamFrame(gomock.Any()).Return(f, false) + framer.AddActiveStream(id1) + framer.AddActiveStream(id2) + Expect(framer.PopStreamFrames(1000)).To(Equal([]*wire.StreamFrame{f})) + }) + + It("skips a stream that was reported active, but doesn't have any data", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) + streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) + f := &wire.StreamFrame{ + StreamID: id2, + Data: []byte("foobar"), + } + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(nil, false) + stream2.EXPECT().popStreamFrame(gomock.Any()).Return(f, false) + framer.AddActiveStream(id1) + framer.AddActiveStream(id2) + Expect(framer.PopStreamFrames(1000)).To(Equal([]*wire.StreamFrame{f})) + }) + + It("pops from a stream multiple times, if it has enough data", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2) + f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")} + f2 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")} + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f1, true) + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f2, false) + framer.AddActiveStream(id1) // only add it once + Expect(framer.PopStreamFrames(protocol.MinStreamFrameSize)).To(Equal([]*wire.StreamFrame{f1})) + Expect(framer.PopStreamFrames(protocol.MinStreamFrameSize)).To(Equal([]*wire.StreamFrame{f2})) + // no further calls to popStreamFrame, after popStreamFrame said there's no more data + Expect(framer.PopStreamFrames(protocol.MinStreamFrameSize)).To(BeNil()) + }) + + It("re-queues a stream at the end, if it has enough data", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2) + streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) + f11 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")} + f12 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")} + f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")} + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f11, true) + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f12, false) + stream2.EXPECT().popStreamFrame(gomock.Any()).Return(f2, false) + framer.AddActiveStream(id1) // only add it once + framer.AddActiveStream(id2) + Expect(framer.PopStreamFrames(protocol.MinStreamFrameSize)).To(Equal([]*wire.StreamFrame{f11})) // first a frame from stream 1 + Expect(framer.PopStreamFrames(protocol.MinStreamFrameSize)).To(Equal([]*wire.StreamFrame{f2})) // then a frame from stream 2 + Expect(framer.PopStreamFrames(protocol.MinStreamFrameSize)).To(Equal([]*wire.StreamFrame{f12})) // then another frame from stream 1 + }) + + It("only dequeues data from each stream once per packet", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) + streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) + f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")} + f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")} + // both streams have more data, and will be re-queued + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f1, true) + stream2.EXPECT().popStreamFrame(gomock.Any()).Return(f2, true) + framer.AddActiveStream(id1) + framer.AddActiveStream(id2) + Expect(framer.PopStreamFrames(1000)).To(Equal([]*wire.StreamFrame{f1, f2})) + }) + + It("returns multiple normal frames in the order they were reported active", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) + streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil) + f1 := &wire.StreamFrame{Data: []byte("foobar")} + f2 := &wire.StreamFrame{Data: []byte("foobaz")} + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f1, false) + stream2.EXPECT().popStreamFrame(gomock.Any()).Return(f2, false) + framer.AddActiveStream(id2) + framer.AddActiveStream(id1) + Expect(framer.PopStreamFrames(1000)).To(Equal([]*wire.StreamFrame{f2, f1})) + }) + + It("only asks a stream for data once, even if it was reported active multiple times", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) + f := &wire.StreamFrame{Data: []byte("foobar")} + stream1.EXPECT().popStreamFrame(gomock.Any()).Return(f, false) // only one call to this function + framer.AddActiveStream(id1) + framer.AddActiveStream(id1) + Expect(framer.PopStreamFrames(1000)).To(HaveLen(1)) + }) + + It("does not pop empty frames", func() { + fs := framer.PopStreamFrames(500) + Expect(fs).To(BeEmpty()) + }) + + It("pops frames that have the minimum size", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) + stream1.EXPECT().popStreamFrame(protocol.MinStreamFrameSize).Return(&wire.StreamFrame{Data: []byte("foobar")}, false) + framer.AddActiveStream(id1) + framer.PopStreamFrames(protocol.MinStreamFrameSize) + }) + + It("does not pop frames smaller than the minimum size", func() { + // don't expect a call to PopStreamFrame() + framer.PopStreamFrames(protocol.MinStreamFrameSize - 1) + }) + + It("stops iterating when the remaining size is smaller than the minimum STREAM frame size", func() { + streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil) + // pop a frame such that the remaining size is one byte less than the minimum STREAM frame size + f := &wire.StreamFrame{ + StreamID: id1, + Data: bytes.Repeat([]byte("f"), int(500-protocol.MinStreamFrameSize)), + } + stream1.EXPECT().popStreamFrame(protocol.ByteCount(500)).Return(f, false) + framer.AddActiveStream(id1) + fs := framer.PopStreamFrames(500) + Expect(fs).To(Equal([]*wire.StreamFrame{f})) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/stream_test.go b/vendor/lucas-clemente/quic-go/stream_test.go new file mode 100644 index 00000000..864e0edb --- /dev/null +++ b/vendor/lucas-clemente/quic-go/stream_test.go @@ -0,0 +1,208 @@ +package quic + +import ( + "io" + "os" + "strconv" + "time" + + "github.com/lucas-clemente/quic-go/internal/mocks" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" +) + +// in the tests for the stream deadlines we set a deadline +// and wait to make an assertion when Read / Write was unblocked +// on the CIs, the timing is a lot less precise, so scale every duration by this factor +func scaleDuration(t time.Duration) time.Duration { + scaleFactor := 1 + if f, err := strconv.Atoi(os.Getenv("TIMESCALE_FACTOR")); err == nil { // parsing "" errors, so this works fine if the env is not set + scaleFactor = f + } + Expect(scaleFactor).ToNot(BeZero()) + return time.Duration(scaleFactor) * t +} + +var _ = Describe("Stream", func() { + const streamID protocol.StreamID = 1337 + + var ( + str *stream + strWithTimeout io.ReadWriter // str wrapped with gbytes.Timeout{Reader,Writer} + mockFC *mocks.MockStreamFlowController + mockSender *MockStreamSender + ) + + BeforeEach(func() { + mockSender = NewMockStreamSender(mockCtrl) + mockFC = mocks.NewMockStreamFlowController(mockCtrl) + str = newStream(streamID, mockSender, mockFC, protocol.VersionWhatever) + + timeout := scaleDuration(250 * time.Millisecond) + strWithTimeout = struct { + io.Reader + io.Writer + }{ + gbytes.TimeoutReader(str, timeout), + gbytes.TimeoutWriter(str, timeout), + } + }) + + It("gets stream id", func() { + Expect(str.StreamID()).To(Equal(protocol.StreamID(1337))) + }) + + // need some stream cancelation tests here, since gQUIC doesn't cleanly separate the two stream halves + Context("stream cancelations", func() { + Context("for gQUIC", func() { + BeforeEach(func() { + str.version = versionGQUICFrames + str.receiveStream.version = versionGQUICFrames + str.sendStream.version = versionGQUICFrames + }) + + It("unblocks Write when receiving a RST_STREAM frame with non-zero error code", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockSender.EXPECT().queueControlFrame(&wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 1000, + ErrorCode: errorCodeStoppingGQUIC, + }) + mockSender.EXPECT().onStreamCompleted(streamID) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true) + str.writeOffset = 1000 + f := &wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 6, + ErrorCode: 123, + } + writeReturned := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError("Stream 1337 was reset with error code 123")) + Expect(err).To(BeAssignableToTypeOf(streamCanceledError{})) + Expect(err.(streamCanceledError).Canceled()).To(BeTrue()) + Expect(err.(streamCanceledError).ErrorCode()).To(Equal(protocol.ApplicationErrorCode(123))) + close(writeReturned) + }() + Consistently(writeReturned).ShouldNot(BeClosed()) + err := str.handleRstStreamFrame(f) + Expect(err).ToNot(HaveOccurred()) + Eventually(writeReturned).Should(BeClosed()) + }) + + It("unblocks Write when receiving a RST_STREAM frame with error code 0", func() { + mockSender.EXPECT().onHasStreamData(streamID) + mockSender.EXPECT().queueControlFrame(&wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 1000, + ErrorCode: errorCodeStoppingGQUIC, + }) + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true) + str.writeOffset = 1000 + f := &wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 6, + ErrorCode: 0, + } + writeReturned := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError("Stream 1337 was reset with error code 0")) + Expect(err).To(BeAssignableToTypeOf(streamCanceledError{})) + Expect(err.(streamCanceledError).Canceled()).To(BeTrue()) + Expect(err.(streamCanceledError).ErrorCode()).To(Equal(protocol.ApplicationErrorCode(0))) + close(writeReturned) + }() + Consistently(writeReturned).ShouldNot(BeClosed()) + err := str.handleRstStreamFrame(f) + Expect(err).ToNot(HaveOccurred()) + Eventually(writeReturned).Should(BeClosed()) + }) + + It("sends a RST_STREAM with error code 0, after the stream is closed", func() { + str.version = versionGQUICFrames + mockSender.EXPECT().onHasStreamData(streamID).Times(2) // once for the Write, once for the Close + mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).AnyTimes() + mockFC.EXPECT().AddBytesSent(protocol.ByteCount(6)) + err := str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + writeReturned := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).ToNot(HaveOccurred()) + close(writeReturned) + }() + Eventually(func() *wire.StreamFrame { + frame, _ := str.popStreamFrame(1000) + return frame + }).ShouldNot(BeNil()) + Eventually(writeReturned).Should(BeClosed()) + mockSender.EXPECT().queueControlFrame(&wire.RstStreamFrame{ + StreamID: streamID, + ByteOffset: 6, + ErrorCode: 0, + }) + Expect(str.Close()).To(Succeed()) + }) + }) + + Context("for IETF QUIC", func() { + It("doesn't queue a RST_STREAM after closing the stream", func() { // this is what it does for gQUIC + mockSender.EXPECT().queueControlFrame(&wire.StopSendingFrame{ + StreamID: streamID, + ErrorCode: 1234, + }) + mockSender.EXPECT().onHasStreamData(streamID) + err := str.CancelRead(1234) + Expect(err).ToNot(HaveOccurred()) + Expect(str.Close()).To(Succeed()) + }) + }) + }) + + Context("deadlines", func() { + It("sets a write deadline, when SetDeadline is called", func() { + str.SetDeadline(time.Now().Add(-time.Second)) + n, err := strWithTimeout.Write([]byte("foobar")) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + }) + + It("sets a read deadline, when SetDeadline is called", func() { + mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false).AnyTimes() + f := &wire.StreamFrame{Data: []byte("foobar")} + err := str.handleStreamFrame(f) + Expect(err).ToNot(HaveOccurred()) + str.SetDeadline(time.Now().Add(-time.Second)) + b := make([]byte, 6) + n, err := strWithTimeout.Read(b) + Expect(err).To(MatchError(errDeadline)) + Expect(n).To(BeZero()) + }) + }) + + Context("completing", func() { + It("is not completed when only the receive side is completed", func() { + // don't EXPECT a call to mockSender.onStreamCompleted() + str.receiveStream.sender.onStreamCompleted(streamID) + }) + + It("is not completed when only the send side is completed", func() { + // don't EXPECT a call to mockSender.onStreamCompleted() + str.sendStream.sender.onStreamCompleted(streamID) + }) + + It("is completed when both sides are completed", func() { + mockSender.EXPECT().onStreamCompleted(streamID) + str.sendStream.sender.onStreamCompleted(streamID) + str.receiveStream.sender.onStreamCompleted(streamID) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/streams_map.go b/vendor/lucas-clemente/quic-go/streams_map.go new file mode 100644 index 00000000..b9a56d6b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map.go @@ -0,0 +1,224 @@ +package quic + +import ( + "fmt" + + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type streamType int + +const ( + streamTypeOutgoingBidi streamType = iota + streamTypeIncomingBidi + streamTypeOutgoingUni + streamTypeIncomingUni +) + +type streamsMap struct { + perspective protocol.Perspective + + sender streamSender + newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController + + outgoingBidiStreams *outgoingBidiStreamsMap + outgoingUniStreams *outgoingUniStreamsMap + incomingBidiStreams *incomingBidiStreamsMap + incomingUniStreams *incomingUniStreamsMap +} + +var _ streamManager = &streamsMap{} + +func newStreamsMap( + sender streamSender, + newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController, + maxIncomingStreams int, + maxIncomingUniStreams int, + perspective protocol.Perspective, + version protocol.VersionNumber, +) streamManager { + m := &streamsMap{ + perspective: perspective, + newFlowController: newFlowController, + sender: sender, + } + var firstOutgoingBidiStream, firstOutgoingUniStream, firstIncomingBidiStream, firstIncomingUniStream protocol.StreamID + if perspective == protocol.PerspectiveServer { + firstOutgoingBidiStream = 1 + firstIncomingBidiStream = 4 // the crypto stream is handled separately + firstOutgoingUniStream = 3 + firstIncomingUniStream = 2 + } else { + firstOutgoingBidiStream = 4 // the crypto stream is handled separately + firstIncomingBidiStream = 1 + firstOutgoingUniStream = 2 + firstIncomingUniStream = 3 + } + newBidiStream := func(id protocol.StreamID) streamI { + return newStream(id, m.sender, m.newFlowController(id), version) + } + newUniSendStream := func(id protocol.StreamID) sendStreamI { + return newSendStream(id, m.sender, m.newFlowController(id), version) + } + newUniReceiveStream := func(id protocol.StreamID) receiveStreamI { + return newReceiveStream(id, m.sender, m.newFlowController(id), version) + } + m.outgoingBidiStreams = newOutgoingBidiStreamsMap( + firstOutgoingBidiStream, + newBidiStream, + sender.queueControlFrame, + ) + m.incomingBidiStreams = newIncomingBidiStreamsMap( + firstIncomingBidiStream, + protocol.MaxBidiStreamID(maxIncomingStreams, perspective), + maxIncomingStreams, + sender.queueControlFrame, + newBidiStream, + ) + m.outgoingUniStreams = newOutgoingUniStreamsMap( + firstOutgoingUniStream, + newUniSendStream, + sender.queueControlFrame, + ) + m.incomingUniStreams = newIncomingUniStreamsMap( + firstIncomingUniStream, + protocol.MaxUniStreamID(maxIncomingUniStreams, perspective), + maxIncomingUniStreams, + sender.queueControlFrame, + newUniReceiveStream, + ) + return m +} + +func (m *streamsMap) getStreamType(id protocol.StreamID) streamType { + if m.perspective == protocol.PerspectiveServer { + switch id % 4 { + case 0: + return streamTypeIncomingBidi + case 1: + return streamTypeOutgoingBidi + case 2: + return streamTypeIncomingUni + case 3: + return streamTypeOutgoingUni + } + } else { + switch id % 4 { + case 0: + return streamTypeOutgoingBidi + case 1: + return streamTypeIncomingBidi + case 2: + return streamTypeOutgoingUni + case 3: + return streamTypeIncomingUni + } + } + panic("") +} + +func (m *streamsMap) OpenStream() (Stream, error) { + return m.outgoingBidiStreams.OpenStream() +} + +func (m *streamsMap) OpenStreamSync() (Stream, error) { + return m.outgoingBidiStreams.OpenStreamSync() +} + +func (m *streamsMap) OpenUniStream() (SendStream, error) { + return m.outgoingUniStreams.OpenStream() +} + +func (m *streamsMap) OpenUniStreamSync() (SendStream, error) { + return m.outgoingUniStreams.OpenStreamSync() +} + +func (m *streamsMap) AcceptStream() (Stream, error) { + return m.incomingBidiStreams.AcceptStream() +} + +func (m *streamsMap) AcceptUniStream() (ReceiveStream, error) { + return m.incomingUniStreams.AcceptStream() +} + +func (m *streamsMap) DeleteStream(id protocol.StreamID) error { + switch m.getStreamType(id) { + case streamTypeIncomingBidi: + return m.incomingBidiStreams.DeleteStream(id) + case streamTypeOutgoingBidi: + return m.outgoingBidiStreams.DeleteStream(id) + case streamTypeIncomingUni: + return m.incomingUniStreams.DeleteStream(id) + case streamTypeOutgoingUni: + return m.outgoingUniStreams.DeleteStream(id) + default: + panic("invalid stream type") + } +} + +func (m *streamsMap) GetOrOpenReceiveStream(id protocol.StreamID) (receiveStreamI, error) { + switch m.getStreamType(id) { + case streamTypeOutgoingBidi: + return m.outgoingBidiStreams.GetStream(id) + case streamTypeIncomingBidi: + return m.incomingBidiStreams.GetOrOpenStream(id) + case streamTypeIncomingUni: + return m.incomingUniStreams.GetOrOpenStream(id) + case streamTypeOutgoingUni: + // an outgoing unidirectional stream is a send stream, not a receive stream + return nil, fmt.Errorf("peer attempted to open receive stream %d", id) + default: + panic("invalid stream type") + } +} + +func (m *streamsMap) GetOrOpenSendStream(id protocol.StreamID) (sendStreamI, error) { + switch m.getStreamType(id) { + case streamTypeOutgoingBidi: + return m.outgoingBidiStreams.GetStream(id) + case streamTypeIncomingBidi: + return m.incomingBidiStreams.GetOrOpenStream(id) + case streamTypeOutgoingUni: + return m.outgoingUniStreams.GetStream(id) + case streamTypeIncomingUni: + // an incoming unidirectional stream is a receive stream, not a send stream + return nil, fmt.Errorf("peer attempted to open send stream %d", id) + default: + panic("invalid stream type") + } +} + +func (m *streamsMap) HandleMaxStreamIDFrame(f *wire.MaxStreamIDFrame) error { + id := f.StreamID + switch m.getStreamType(id) { + case streamTypeOutgoingBidi: + m.outgoingBidiStreams.SetMaxStream(id) + return nil + case streamTypeOutgoingUni: + m.outgoingUniStreams.SetMaxStream(id) + return nil + default: + return fmt.Errorf("received MAX_STREAM_DATA frame for incoming stream %d", id) + } +} + +func (m *streamsMap) UpdateLimits(p *handshake.TransportParameters) { + // Max{Uni,Bidi}StreamID returns the highest stream ID that the peer is allowed to open. + // Invert the perspective to determine the value that we are allowed to open. + peerPers := protocol.PerspectiveServer + if m.perspective == protocol.PerspectiveServer { + peerPers = protocol.PerspectiveClient + } + m.outgoingBidiStreams.SetMaxStream(protocol.MaxBidiStreamID(int(p.MaxBidiStreams), peerPers)) + m.outgoingUniStreams.SetMaxStream(protocol.MaxUniStreamID(int(p.MaxUniStreams), peerPers)) +} + +func (m *streamsMap) CloseWithError(err error) { + m.outgoingBidiStreams.CloseWithError(err) + m.outgoingUniStreams.CloseWithError(err) + m.incomingBidiStreams.CloseWithError(err) + m.incomingUniStreams.CloseWithError(err) +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_generic_helper.go b/vendor/lucas-clemente/quic-go/streams_map_generic_helper.go new file mode 100644 index 00000000..f48db212 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_generic_helper.go @@ -0,0 +1,11 @@ +package quic + +import "github.com/cheekybits/genny/generic" + +// In the auto-generated streams maps, we need to be able to close the streams. +// Therefore, extend the generic.Type with the stream close method. +// This definition must be in a file that Genny doesn't process. +type item interface { + generic.Type + closeForShutdown(error) +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_incoming_bidi.go b/vendor/lucas-clemente/quic-go/streams_map_incoming_bidi.go new file mode 100644 index 00000000..317f5e23 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_incoming_bidi.go @@ -0,0 +1,131 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package quic + +import ( + "fmt" + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type incomingBidiStreamsMap struct { + mutex sync.RWMutex + cond sync.Cond + + streams map[protocol.StreamID]streamI + + nextStream protocol.StreamID // the next stream that will be returned by AcceptStream() + highestStream protocol.StreamID // the highest stream that the peer openend + maxStream protocol.StreamID // the highest stream that the peer is allowed to open + maxNumStreams int // maximum number of streams + + newStream func(protocol.StreamID) streamI + queueMaxStreamID func(*wire.MaxStreamIDFrame) + + closeErr error +} + +func newIncomingBidiStreamsMap( + nextStream protocol.StreamID, + initialMaxStreamID protocol.StreamID, + maxNumStreams int, + queueControlFrame func(wire.Frame), + newStream func(protocol.StreamID) streamI, +) *incomingBidiStreamsMap { + m := &incomingBidiStreamsMap{ + streams: make(map[protocol.StreamID]streamI), + nextStream: nextStream, + maxStream: initialMaxStreamID, + maxNumStreams: maxNumStreams, + newStream: newStream, + queueMaxStreamID: func(f *wire.MaxStreamIDFrame) { queueControlFrame(f) }, + } + m.cond.L = &m.mutex + return m +} + +func (m *incomingBidiStreamsMap) AcceptStream() (streamI, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + var str streamI + for { + var ok bool + if m.closeErr != nil { + return nil, m.closeErr + } + str, ok = m.streams[m.nextStream] + if ok { + break + } + m.cond.Wait() + } + m.nextStream += 4 + return str, nil +} + +func (m *incomingBidiStreamsMap) GetOrOpenStream(id protocol.StreamID) (streamI, error) { + m.mutex.RLock() + if id > m.maxStream { + m.mutex.RUnlock() + return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) + } + // if the id is smaller than the highest we accepted + // * this stream exists in the map, and we can return it, or + // * this stream was already closed, then we can return the nil + if id <= m.highestStream { + s := m.streams[id] + m.mutex.RUnlock() + return s, nil + } + m.mutex.RUnlock() + + m.mutex.Lock() + // no need to check the two error conditions from above again + // * maxStream can only increase, so if the id was valid before, it definitely is valid now + // * highestStream is only modified by this function + var start protocol.StreamID + if m.highestStream == 0 { + start = m.nextStream + } else { + start = m.highestStream + 4 + } + for newID := start; newID <= id; newID += 4 { + m.streams[newID] = m.newStream(newID) + m.cond.Signal() + } + m.highestStream = id + s := m.streams[id] + m.mutex.Unlock() + return s, nil +} + +func (m *incomingBidiStreamsMap) DeleteStream(id protocol.StreamID) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + if _, ok := m.streams[id]; !ok { + return fmt.Errorf("Tried to delete unknown stream %d", id) + } + delete(m.streams, id) + // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream + if numNewStreams := m.maxNumStreams - len(m.streams); numNewStreams > 0 { + m.maxStream = m.highestStream + protocol.StreamID(numNewStreams*4) + m.queueMaxStreamID(&wire.MaxStreamIDFrame{StreamID: m.maxStream}) + } + return nil +} + +func (m *incomingBidiStreamsMap) CloseWithError(err error) { + m.mutex.Lock() + m.closeErr = err + for _, str := range m.streams { + str.closeForShutdown(err) + } + m.mutex.Unlock() + m.cond.Broadcast() +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_incoming_generic.go b/vendor/lucas-clemente/quic-go/streams_map_incoming_generic.go new file mode 100644 index 00000000..58f1ccbe --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_incoming_generic.go @@ -0,0 +1,129 @@ +package quic + +import ( + "fmt" + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +//go:generate genny -in $GOFILE -out streams_map_incoming_bidi.go gen "item=streamI Item=BidiStream" +//go:generate genny -in $GOFILE -out streams_map_incoming_uni.go gen "item=receiveStreamI Item=UniStream" +type incomingItemsMap struct { + mutex sync.RWMutex + cond sync.Cond + + streams map[protocol.StreamID]item + + nextStream protocol.StreamID // the next stream that will be returned by AcceptStream() + highestStream protocol.StreamID // the highest stream that the peer openend + maxStream protocol.StreamID // the highest stream that the peer is allowed to open + maxNumStreams int // maximum number of streams + + newStream func(protocol.StreamID) item + queueMaxStreamID func(*wire.MaxStreamIDFrame) + + closeErr error +} + +func newIncomingItemsMap( + nextStream protocol.StreamID, + initialMaxStreamID protocol.StreamID, + maxNumStreams int, + queueControlFrame func(wire.Frame), + newStream func(protocol.StreamID) item, +) *incomingItemsMap { + m := &incomingItemsMap{ + streams: make(map[protocol.StreamID]item), + nextStream: nextStream, + maxStream: initialMaxStreamID, + maxNumStreams: maxNumStreams, + newStream: newStream, + queueMaxStreamID: func(f *wire.MaxStreamIDFrame) { queueControlFrame(f) }, + } + m.cond.L = &m.mutex + return m +} + +func (m *incomingItemsMap) AcceptStream() (item, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + var str item + for { + var ok bool + if m.closeErr != nil { + return nil, m.closeErr + } + str, ok = m.streams[m.nextStream] + if ok { + break + } + m.cond.Wait() + } + m.nextStream += 4 + return str, nil +} + +func (m *incomingItemsMap) GetOrOpenStream(id protocol.StreamID) (item, error) { + m.mutex.RLock() + if id > m.maxStream { + m.mutex.RUnlock() + return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) + } + // if the id is smaller than the highest we accepted + // * this stream exists in the map, and we can return it, or + // * this stream was already closed, then we can return the nil + if id <= m.highestStream { + s := m.streams[id] + m.mutex.RUnlock() + return s, nil + } + m.mutex.RUnlock() + + m.mutex.Lock() + // no need to check the two error conditions from above again + // * maxStream can only increase, so if the id was valid before, it definitely is valid now + // * highestStream is only modified by this function + var start protocol.StreamID + if m.highestStream == 0 { + start = m.nextStream + } else { + start = m.highestStream + 4 + } + for newID := start; newID <= id; newID += 4 { + m.streams[newID] = m.newStream(newID) + m.cond.Signal() + } + m.highestStream = id + s := m.streams[id] + m.mutex.Unlock() + return s, nil +} + +func (m *incomingItemsMap) DeleteStream(id protocol.StreamID) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + if _, ok := m.streams[id]; !ok { + return fmt.Errorf("Tried to delete unknown stream %d", id) + } + delete(m.streams, id) + // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream + if numNewStreams := m.maxNumStreams - len(m.streams); numNewStreams > 0 { + m.maxStream = m.highestStream + protocol.StreamID(numNewStreams*4) + m.queueMaxStreamID(&wire.MaxStreamIDFrame{StreamID: m.maxStream}) + } + return nil +} + +func (m *incomingItemsMap) CloseWithError(err error) { + m.mutex.Lock() + m.closeErr = err + for _, str := range m.streams { + str.closeForShutdown(err) + } + m.mutex.Unlock() + m.cond.Broadcast() +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_incoming_generic_test.go b/vendor/lucas-clemente/quic-go/streams_map_incoming_generic_test.go new file mode 100644 index 00000000..e9d8dbb4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_incoming_generic_test.go @@ -0,0 +1,165 @@ +package quic + +import ( + "errors" + "fmt" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mockGenericStream struct { + id protocol.StreamID + + closed bool + closeErr error +} + +func (s *mockGenericStream) closeForShutdown(err error) { + s.closed = true + s.closeErr = err +} + +var _ = Describe("Streams Map (incoming)", func() { + const ( + firstNewStream protocol.StreamID = 20 + maxNumStreams int = 10 + initialMaxStream protocol.StreamID = firstNewStream + 4*protocol.StreamID(maxNumStreams-1) + ) + + var ( + m *incomingItemsMap + newItem func(id protocol.StreamID) item + newItemCounter int + mockSender *MockStreamSender + ) + + BeforeEach(func() { + newItemCounter = 0 + newItem = func(id protocol.StreamID) item { + newItemCounter++ + return &mockGenericStream{id: id} + } + mockSender = NewMockStreamSender(mockCtrl) + m = newIncomingItemsMap(firstNewStream, initialMaxStream, maxNumStreams, mockSender.queueControlFrame, newItem) + }) + + It("opens all streams up to the id on GetOrOpenStream", func() { + _, err := m.GetOrOpenStream(firstNewStream + 4*5) + Expect(err).ToNot(HaveOccurred()) + Expect(newItemCounter).To(Equal(6)) + }) + + It("starts opening streams at the right position", func() { + // like the test above, but with 2 calls to GetOrOpenStream + _, err := m.GetOrOpenStream(firstNewStream + 4) + Expect(err).ToNot(HaveOccurred()) + Expect(newItemCounter).To(Equal(2)) + _, err = m.GetOrOpenStream(firstNewStream + 4*5) + Expect(err).ToNot(HaveOccurred()) + Expect(newItemCounter).To(Equal(6)) + }) + + It("accepts streams in the right order", func() { + _, err := m.GetOrOpenStream(firstNewStream + 4) // open stream 20 and 24 + Expect(err).ToNot(HaveOccurred()) + str, err := m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream)) + str, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream + 4)) + }) + + It("allows opening the maximum stream ID", func() { + str, err := m.GetOrOpenStream(initialMaxStream) + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(initialMaxStream)) + }) + + It("errors when trying to get a stream ID higher than the maximum", func() { + _, err := m.GetOrOpenStream(initialMaxStream + 4) + Expect(err).To(MatchError(fmt.Errorf("peer tried to open stream %d (current limit: %d)", initialMaxStream+4, initialMaxStream))) + }) + + It("blocks AcceptStream until a new stream is available", func() { + strChan := make(chan item) + go func() { + defer GinkgoRecover() + str, err := m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + strChan <- str + }() + Consistently(strChan).ShouldNot(Receive()) + str, err := m.GetOrOpenStream(firstNewStream) + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream)) + var acceptedStr item + Eventually(strChan).Should(Receive(&acceptedStr)) + Expect(acceptedStr.(*mockGenericStream).id).To(Equal(firstNewStream)) + }) + + It("unblocks AcceptStream when it is closed", func() { + testErr := errors.New("test error") + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := m.AcceptStream() + Expect(err).To(MatchError(testErr)) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + m.CloseWithError(testErr) + Eventually(done).Should(BeClosed()) + }) + + It("errors AcceptStream immediately if it is closed", func() { + testErr := errors.New("test error") + m.CloseWithError(testErr) + _, err := m.AcceptStream() + Expect(err).To(MatchError(testErr)) + }) + + It("closes all streams when CloseWithError is called", func() { + str1, err := m.GetOrOpenStream(20) + Expect(err).ToNot(HaveOccurred()) + str2, err := m.GetOrOpenStream(20 + 8) + Expect(err).ToNot(HaveOccurred()) + testErr := errors.New("test err") + m.CloseWithError(testErr) + Expect(str1.(*mockGenericStream).closed).To(BeTrue()) + Expect(str1.(*mockGenericStream).closeErr).To(MatchError(testErr)) + Expect(str2.(*mockGenericStream).closed).To(BeTrue()) + Expect(str2.(*mockGenericStream).closeErr).To(MatchError(testErr)) + }) + + It("deletes streams", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + _, err := m.GetOrOpenStream(20) + Expect(err).ToNot(HaveOccurred()) + err = m.DeleteStream(20) + Expect(err).ToNot(HaveOccurred()) + str, err := m.GetOrOpenStream(20) + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeNil()) + }) + + It("errors when deleting a non-existing stream", func() { + err := m.DeleteStream(1337) + Expect(err).To(MatchError("Tried to delete unknown stream 1337")) + }) + + It("sends MAX_STREAM_ID frames when streams are deleted", func() { + // open a bunch of streams + _, err := m.GetOrOpenStream(firstNewStream + 4*4) + Expect(err).ToNot(HaveOccurred()) + mockSender.EXPECT().queueControlFrame(&wire.MaxStreamIDFrame{StreamID: initialMaxStream + 4}) + Expect(m.DeleteStream(firstNewStream + 4)).To(Succeed()) + mockSender.EXPECT().queueControlFrame(&wire.MaxStreamIDFrame{StreamID: initialMaxStream + 8}) + Expect(m.DeleteStream(firstNewStream + 3*4)).To(Succeed()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/streams_map_incoming_uni.go b/vendor/lucas-clemente/quic-go/streams_map_incoming_uni.go new file mode 100644 index 00000000..8e775aac --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_incoming_uni.go @@ -0,0 +1,131 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package quic + +import ( + "fmt" + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type incomingUniStreamsMap struct { + mutex sync.RWMutex + cond sync.Cond + + streams map[protocol.StreamID]receiveStreamI + + nextStream protocol.StreamID // the next stream that will be returned by AcceptStream() + highestStream protocol.StreamID // the highest stream that the peer openend + maxStream protocol.StreamID // the highest stream that the peer is allowed to open + maxNumStreams int // maximum number of streams + + newStream func(protocol.StreamID) receiveStreamI + queueMaxStreamID func(*wire.MaxStreamIDFrame) + + closeErr error +} + +func newIncomingUniStreamsMap( + nextStream protocol.StreamID, + initialMaxStreamID protocol.StreamID, + maxNumStreams int, + queueControlFrame func(wire.Frame), + newStream func(protocol.StreamID) receiveStreamI, +) *incomingUniStreamsMap { + m := &incomingUniStreamsMap{ + streams: make(map[protocol.StreamID]receiveStreamI), + nextStream: nextStream, + maxStream: initialMaxStreamID, + maxNumStreams: maxNumStreams, + newStream: newStream, + queueMaxStreamID: func(f *wire.MaxStreamIDFrame) { queueControlFrame(f) }, + } + m.cond.L = &m.mutex + return m +} + +func (m *incomingUniStreamsMap) AcceptStream() (receiveStreamI, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + var str receiveStreamI + for { + var ok bool + if m.closeErr != nil { + return nil, m.closeErr + } + str, ok = m.streams[m.nextStream] + if ok { + break + } + m.cond.Wait() + } + m.nextStream += 4 + return str, nil +} + +func (m *incomingUniStreamsMap) GetOrOpenStream(id protocol.StreamID) (receiveStreamI, error) { + m.mutex.RLock() + if id > m.maxStream { + m.mutex.RUnlock() + return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) + } + // if the id is smaller than the highest we accepted + // * this stream exists in the map, and we can return it, or + // * this stream was already closed, then we can return the nil + if id <= m.highestStream { + s := m.streams[id] + m.mutex.RUnlock() + return s, nil + } + m.mutex.RUnlock() + + m.mutex.Lock() + // no need to check the two error conditions from above again + // * maxStream can only increase, so if the id was valid before, it definitely is valid now + // * highestStream is only modified by this function + var start protocol.StreamID + if m.highestStream == 0 { + start = m.nextStream + } else { + start = m.highestStream + 4 + } + for newID := start; newID <= id; newID += 4 { + m.streams[newID] = m.newStream(newID) + m.cond.Signal() + } + m.highestStream = id + s := m.streams[id] + m.mutex.Unlock() + return s, nil +} + +func (m *incomingUniStreamsMap) DeleteStream(id protocol.StreamID) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + if _, ok := m.streams[id]; !ok { + return fmt.Errorf("Tried to delete unknown stream %d", id) + } + delete(m.streams, id) + // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream + if numNewStreams := m.maxNumStreams - len(m.streams); numNewStreams > 0 { + m.maxStream = m.highestStream + protocol.StreamID(numNewStreams*4) + m.queueMaxStreamID(&wire.MaxStreamIDFrame{StreamID: m.maxStream}) + } + return nil +} + +func (m *incomingUniStreamsMap) CloseWithError(err error) { + m.mutex.Lock() + m.closeErr = err + for _, str := range m.streams { + str.closeForShutdown(err) + } + m.mutex.Unlock() + m.cond.Broadcast() +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_legacy.go b/vendor/lucas-clemente/quic-go/streams_map_legacy.go new file mode 100644 index 00000000..240eeea1 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_legacy.go @@ -0,0 +1,277 @@ +package quic + +import ( + "errors" + "fmt" + "sync" + + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +type streamsMapLegacy struct { + mutex sync.RWMutex + + perspective protocol.Perspective + + streams map[protocol.StreamID]streamI + + nextStreamToOpen protocol.StreamID // StreamID of the next Stream that will be returned by OpenStream() + highestStreamOpenedByPeer protocol.StreamID + nextStreamOrErrCond sync.Cond + openStreamOrErrCond sync.Cond + + closeErr error + nextStreamToAccept protocol.StreamID + + newStream func(protocol.StreamID) streamI + + numOutgoingStreams uint32 + numIncomingStreams uint32 + maxIncomingStreams uint32 + maxOutgoingStreams uint32 +} + +var _ streamManager = &streamsMapLegacy{} + +var errMapAccess = errors.New("streamsMap: Error accessing the streams map") + +func newStreamsMapLegacy(newStream func(protocol.StreamID) streamI, maxStreams int, pers protocol.Perspective) streamManager { + // add some tolerance to the maximum incoming streams value + maxIncomingStreams := utils.MaxUint32( + uint32(maxStreams)+protocol.MaxStreamsMinimumIncrement, + uint32(float64(maxStreams)*float64(protocol.MaxStreamsMultiplier)), + ) + sm := streamsMapLegacy{ + perspective: pers, + streams: make(map[protocol.StreamID]streamI), + newStream: newStream, + maxIncomingStreams: maxIncomingStreams, + } + sm.nextStreamOrErrCond.L = &sm.mutex + sm.openStreamOrErrCond.L = &sm.mutex + + nextServerInitiatedStream := protocol.StreamID(2) + nextClientInitiatedStream := protocol.StreamID(3) + if pers == protocol.PerspectiveServer { + sm.highestStreamOpenedByPeer = 1 + } + if pers == protocol.PerspectiveServer { + sm.nextStreamToOpen = nextServerInitiatedStream + sm.nextStreamToAccept = nextClientInitiatedStream + } else { + sm.nextStreamToOpen = nextClientInitiatedStream + sm.nextStreamToAccept = nextServerInitiatedStream + } + return &sm +} + +// getStreamPerspective says which side should initiate a stream +func (m *streamsMapLegacy) streamInitiatedBy(id protocol.StreamID) protocol.Perspective { + if id%2 == 0 { + return protocol.PerspectiveServer + } + return protocol.PerspectiveClient +} + +func (m *streamsMapLegacy) GetOrOpenReceiveStream(id protocol.StreamID) (receiveStreamI, error) { + // every bidirectional stream is also a receive stream + return m.getOrOpenStream(id) +} + +func (m *streamsMapLegacy) GetOrOpenSendStream(id protocol.StreamID) (sendStreamI, error) { + // every bidirectional stream is also a send stream + return m.getOrOpenStream(id) +} + +// getOrOpenStream either returns an existing stream, a newly opened stream, or nil if a stream with the provided ID is already closed. +// Newly opened streams should only originate from the client. To open a stream from the server, OpenStream should be used. +func (m *streamsMapLegacy) getOrOpenStream(id protocol.StreamID) (streamI, error) { + m.mutex.RLock() + s, ok := m.streams[id] + m.mutex.RUnlock() + if ok { + return s, nil + } + + // ... we don't have an existing stream + m.mutex.Lock() + defer m.mutex.Unlock() + // We need to check whether another invocation has already created a stream (between RUnlock() and Lock()). + s, ok = m.streams[id] + if ok { + return s, nil + } + + if m.perspective == m.streamInitiatedBy(id) { + if id <= m.nextStreamToOpen { // this is a stream opened by us. Must have been closed already + return nil, nil + } + return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) + } + if id <= m.highestStreamOpenedByPeer { // this is a peer-initiated stream that doesn't exist anymore. Must have been closed already + return nil, nil + } + + for sid := m.highestStreamOpenedByPeer + 2; sid <= id; sid += 2 { + if _, err := m.openRemoteStream(sid); err != nil { + return nil, err + } + } + + m.nextStreamOrErrCond.Broadcast() + return m.streams[id], nil +} + +func (m *streamsMapLegacy) openRemoteStream(id protocol.StreamID) (streamI, error) { + if m.numIncomingStreams >= m.maxIncomingStreams { + return nil, qerr.TooManyOpenStreams + } + // maxNewStreamIDDelta is the maximum difference between and a newly opened Stream and the highest StreamID that a client has ever opened + // note that the number of streams is half this value, since the client can only open streams with open StreamID + maxStreamIDDelta := protocol.StreamID(4 * m.maxIncomingStreams) + if id+maxStreamIDDelta < m.highestStreamOpenedByPeer { + return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("attempted to open stream %d, which is a lot smaller than the highest opened stream, %d", id, m.highestStreamOpenedByPeer)) + } + + m.numIncomingStreams++ + if id > m.highestStreamOpenedByPeer { + m.highestStreamOpenedByPeer = id + } + + s := m.newStream(id) + return s, m.putStream(s) +} + +func (m *streamsMapLegacy) openStreamImpl() (streamI, error) { + if m.numOutgoingStreams >= m.maxOutgoingStreams { + return nil, qerr.TooManyOpenStreams + } + + m.numOutgoingStreams++ + s := m.newStream(m.nextStreamToOpen) + m.nextStreamToOpen += 2 + return s, m.putStream(s) +} + +// OpenStream opens the next available stream +func (m *streamsMapLegacy) OpenStream() (Stream, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + if m.closeErr != nil { + return nil, m.closeErr + } + return m.openStreamImpl() +} + +func (m *streamsMapLegacy) OpenStreamSync() (Stream, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + for { + if m.closeErr != nil { + return nil, m.closeErr + } + str, err := m.openStreamImpl() + if err == nil { + return str, err + } + if err != nil && err != qerr.TooManyOpenStreams { + return nil, err + } + m.openStreamOrErrCond.Wait() + } +} + +func (m *streamsMapLegacy) OpenUniStream() (SendStream, error) { + return nil, errors.New("gQUIC doesn't support unidirectional streams") +} + +func (m *streamsMapLegacy) OpenUniStreamSync() (SendStream, error) { + return nil, errors.New("gQUIC doesn't support unidirectional streams") +} + +// AcceptStream returns the next stream opened by the peer +// it blocks until a new stream is opened +func (m *streamsMapLegacy) AcceptStream() (Stream, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + var str streamI + for { + var ok bool + if m.closeErr != nil { + return nil, m.closeErr + } + str, ok = m.streams[m.nextStreamToAccept] + if ok { + break + } + m.nextStreamOrErrCond.Wait() + } + m.nextStreamToAccept += 2 + return str, nil +} + +func (m *streamsMapLegacy) AcceptUniStream() (ReceiveStream, error) { + return nil, errors.New("gQUIC doesn't support unidirectional streams") +} + +func (m *streamsMapLegacy) DeleteStream(id protocol.StreamID) error { + m.mutex.Lock() + defer m.mutex.Unlock() + _, ok := m.streams[id] + if !ok { + return errMapAccess + } + delete(m.streams, id) + if m.streamInitiatedBy(id) == m.perspective { + m.numOutgoingStreams-- + } else { + m.numIncomingStreams-- + } + m.openStreamOrErrCond.Signal() + return nil +} + +func (m *streamsMapLegacy) putStream(s streamI) error { + id := s.StreamID() + if _, ok := m.streams[id]; ok { + return fmt.Errorf("a stream with ID %d already exists", id) + } + m.streams[id] = s + return nil +} + +func (m *streamsMapLegacy) CloseWithError(err error) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.closeErr = err + m.nextStreamOrErrCond.Broadcast() + m.openStreamOrErrCond.Broadcast() + for _, s := range m.streams { + s.closeForShutdown(err) + } +} + +// TODO(#952): this won't be needed when gQUIC supports stateless handshakes +func (m *streamsMapLegacy) UpdateLimits(params *handshake.TransportParameters) { + m.mutex.Lock() + m.maxOutgoingStreams = params.MaxStreams + for id, str := range m.streams { + str.handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{ + StreamID: id, + ByteOffset: params.StreamFlowControlWindow, + }) + } + m.mutex.Unlock() + m.openStreamOrErrCond.Broadcast() +} + +// should never be called, since MAX_STREAM_ID frames can only be unpacked for IETF QUIC +func (m *streamsMapLegacy) HandleMaxStreamIDFrame(f *wire.MaxStreamIDFrame) error { + return errors.New("gQUIC doesn't have MAX_STREAM_ID frames") +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_legacy_test.go b/vendor/lucas-clemente/quic-go/streams_map_legacy_test.go new file mode 100644 index 00000000..b9450bc0 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_legacy_test.go @@ -0,0 +1,564 @@ +package quic + +import ( + "errors" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Streams Map (for gQUIC)", func() { + var m *streamsMapLegacy + + newStream := func(id protocol.StreamID) streamI { + str := NewMockStreamI(mockCtrl) + str.EXPECT().StreamID().Return(id).AnyTimes() + return str + } + + setNewStreamsMap := func(p protocol.Perspective) { + m = newStreamsMapLegacy(newStream, protocol.DefaultMaxIncomingStreams, p).(*streamsMapLegacy) + } + + deleteStream := func(id protocol.StreamID) { + ExpectWithOffset(1, m.DeleteStream(id)).To(Succeed()) + } + + It("applies the max stream limit for small number of streams", func() { + sm := newStreamsMapLegacy(newStream, 1, protocol.PerspectiveServer).(*streamsMapLegacy) + Expect(sm.maxIncomingStreams).To(BeEquivalentTo(1 + protocol.MaxStreamsMinimumIncrement)) + }) + + It("applies the max stream limit for big number of streams", func() { + sm := newStreamsMapLegacy(newStream, 1000, protocol.PerspectiveServer).(*streamsMapLegacy) + Expect(sm.maxIncomingStreams).To(BeEquivalentTo(1000 * protocol.MaxStreamsMultiplier)) + }) + + Context("getting and creating streams", func() { + Context("as a server", func() { + BeforeEach(func() { + setNewStreamsMap(protocol.PerspectiveServer) + }) + + Context("client-side streams", func() { + It("gets new streams", func() { + s, err := m.getOrOpenStream(3) + Expect(err).NotTo(HaveOccurred()) + Expect(s).ToNot(BeNil()) + Expect(s.StreamID()).To(Equal(protocol.StreamID(3))) + Expect(m.streams).To(HaveLen(1)) + Expect(m.numIncomingStreams).To(BeEquivalentTo(1)) + Expect(m.numOutgoingStreams).To(BeZero()) + }) + + It("rejects streams with even IDs", func() { + _, err := m.getOrOpenStream(6) + Expect(err).To(MatchError("InvalidStreamID: peer attempted to open stream 6")) + }) + + It("rejects streams with even IDs, which are lower thatn the highest client-side stream", func() { + _, err := m.getOrOpenStream(5) + Expect(err).NotTo(HaveOccurred()) + _, err = m.getOrOpenStream(4) + Expect(err).To(MatchError("InvalidStreamID: peer attempted to open stream 4")) + }) + + It("gets existing streams", func() { + s, err := m.getOrOpenStream(5) + Expect(err).NotTo(HaveOccurred()) + Expect(s.StreamID()).To(Equal(protocol.StreamID(5))) + numStreams := m.numIncomingStreams + s, err = m.getOrOpenStream(5) + Expect(err).NotTo(HaveOccurred()) + Expect(s.StreamID()).To(Equal(protocol.StreamID(5))) + Expect(m.numIncomingStreams).To(Equal(numStreams)) + }) + + It("returns nil for closed streams", func() { + _, err := m.getOrOpenStream(5) + Expect(err).NotTo(HaveOccurred()) + deleteStream(5) + s, err := m.getOrOpenStream(5) + Expect(err).NotTo(HaveOccurred()) + Expect(s).To(BeNil()) + }) + + It("opens skipped streams", func() { + _, err := m.getOrOpenStream(7) + Expect(err).NotTo(HaveOccurred()) + Expect(m.streams).To(HaveKey(protocol.StreamID(3))) + Expect(m.streams).To(HaveKey(protocol.StreamID(5))) + Expect(m.streams).To(HaveKey(protocol.StreamID(7))) + }) + + It("doesn't reopen an already closed stream", func() { + _, err := m.getOrOpenStream(5) + Expect(err).ToNot(HaveOccurred()) + deleteStream(5) + Expect(err).ToNot(HaveOccurred()) + str, err := m.getOrOpenStream(5) + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeNil()) + }) + + Context("counting streams", func() { + It("errors when too many streams are opened", func() { + for i := uint32(0); i < m.maxIncomingStreams; i++ { + _, err := m.getOrOpenStream(protocol.StreamID(i*2 + 1)) + Expect(err).NotTo(HaveOccurred()) + } + _, err := m.getOrOpenStream(protocol.StreamID(2*m.maxIncomingStreams + 3)) + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + }) + + It("errors when too many streams are opened implicitly", func() { + _, err := m.getOrOpenStream(protocol.StreamID(m.maxIncomingStreams*2 + 3)) + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + }) + + It("does not error when many streams are opened and closed", func() { + for i := uint32(2); i < 10*m.maxIncomingStreams; i++ { + str, err := m.getOrOpenStream(protocol.StreamID(i*2 + 1)) + Expect(err).NotTo(HaveOccurred()) + deleteStream(str.StreamID()) + } + }) + }) + }) + + Context("server-side streams", func() { + It("doesn't allow opening streams before receiving the transport parameters", func() { + _, err := m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + }) + + It("opens a stream 2 first", func() { + m.UpdateLimits(&handshake.TransportParameters{MaxStreams: 10000}) + s, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(s).ToNot(BeNil()) + Expect(s.StreamID()).To(Equal(protocol.StreamID(2))) + Expect(m.numIncomingStreams).To(BeZero()) + Expect(m.numOutgoingStreams).To(BeEquivalentTo(1)) + }) + + It("returns the error when the streamsMap was closed", func() { + testErr := errors.New("test error") + m.CloseWithError(testErr) + _, err := m.OpenStream() + Expect(err).To(MatchError(testErr)) + }) + + It("doesn't reopen an already closed stream", func() { + m.UpdateLimits(&handshake.TransportParameters{MaxStreams: 10000}) + str, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(2))) + deleteStream(2) + Expect(err).ToNot(HaveOccurred()) + str, err = m.getOrOpenStream(2) + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeNil()) + }) + + Context("counting streams", func() { + const maxOutgoingStreams = 50 + + BeforeEach(func() { + m.UpdateLimits(&handshake.TransportParameters{MaxStreams: maxOutgoingStreams}) + }) + + It("errors when too many streams are opened", func() { + for i := 1; i <= maxOutgoingStreams; i++ { + _, err := m.OpenStream() + Expect(err).NotTo(HaveOccurred()) + } + _, err := m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + }) + + It("does not error when many streams are opened and closed", func() { + for i := 2; i < 10*maxOutgoingStreams; i++ { + str, err := m.OpenStream() + Expect(err).NotTo(HaveOccurred()) + deleteStream(str.StreamID()) + } + }) + + It("allows many server- and client-side streams at the same time", func() { + for i := 1; i < maxOutgoingStreams; i++ { + _, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + } + for i := 0; i < maxOutgoingStreams; i++ { + _, err := m.getOrOpenStream(protocol.StreamID(2*i + 1)) + Expect(err).ToNot(HaveOccurred()) + } + }) + }) + + Context("opening streams synchronously", func() { + const maxOutgoingStreams = 10 + + BeforeEach(func() { + m.UpdateLimits(&handshake.TransportParameters{MaxStreams: maxOutgoingStreams}) + }) + + openMaxNumStreams := func() { + for i := 1; i <= maxOutgoingStreams; i++ { + _, err := m.OpenStream() + Expect(err).NotTo(HaveOccurred()) + } + _, err := m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + } + + It("waits until another stream is closed", func() { + openMaxNumStreams() + var str Stream + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + str, err = m.OpenStreamSync() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + deleteStream(6) + Eventually(done).Should(BeClosed()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(2*maxOutgoingStreams + 2))) + }) + + It("stops waiting when an error is registered", func() { + testErr := errors.New("test error") + openMaxNumStreams() + for _, str := range m.streams { + str.(*MockStreamI).EXPECT().closeForShutdown(testErr) + } + + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := m.OpenStreamSync() + Expect(err).To(MatchError(testErr)) + close(done) + }() + + Consistently(done).ShouldNot(BeClosed()) + m.CloseWithError(testErr) + Eventually(done).Should(BeClosed()) + }) + + It("immediately returns when OpenStreamSync is called after an error was registered", func() { + testErr := errors.New("test error") + m.CloseWithError(testErr) + _, err := m.OpenStreamSync() + Expect(err).To(MatchError(testErr)) + }) + }) + }) + + Context("accepting streams", func() { + It("does nothing if no stream is opened", func() { + var accepted bool + go func() { + _, _ = m.AcceptStream() + accepted = true + }() + Consistently(func() bool { return accepted }).Should(BeFalse()) + }) + + It("starts with stream 3", func() { + var str Stream + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + str, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + _, err := m.getOrOpenStream(3) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(3))) + }) + + It("returns an implicitly opened stream, if a stream number is skipped", func() { + var str Stream + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + str, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + _, err := m.getOrOpenStream(5) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(3))) + }) + + It("returns to multiple accepts", func() { + var str1, str2 Stream + done1 := make(chan struct{}) + done2 := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + str1, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + close(done1) + }() + go func() { + defer GinkgoRecover() + var err error + str2, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + close(done2) + }() + _, err := m.getOrOpenStream(5) // opens stream 3 and 5 + Expect(err).ToNot(HaveOccurred()) + Eventually(done1).Should(BeClosed()) + Eventually(done2).Should(BeClosed()) + Expect(str1.StreamID()).ToNot(Equal(str2.StreamID())) + Expect(str1.StreamID() + str2.StreamID()).To(BeEquivalentTo(3 + 5)) + }) + + It("waits until a new stream is available", func() { + var str Stream + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + str, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + _, err := m.getOrOpenStream(3) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(3))) + }) + + It("returns multiple streams on subsequent Accept calls, if available", func() { + var str Stream + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + str, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + _, err := m.getOrOpenStream(5) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(3))) + str, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(5))) + }) + + It("blocks after accepting a stream", func() { + _, err := m.getOrOpenStream(3) + Expect(err).ToNot(HaveOccurred()) + str, err := m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(3))) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, _ = m.AcceptStream() + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + // make the go routine return + str.(*MockStreamI).EXPECT().closeForShutdown(gomock.Any()) + m.CloseWithError(errors.New("shut down")) + Eventually(done).Should(BeClosed()) + }) + + It("stops waiting when an error is registered", func() { + testErr := errors.New("testErr") + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := m.AcceptStream() + Expect(err).To(MatchError(testErr)) + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) + m.CloseWithError(testErr) + Eventually(done).Should(BeClosed()) + }) + It("immediately returns when Accept is called after an error was registered", func() { + testErr := errors.New("testErr") + m.CloseWithError(testErr) + _, err := m.AcceptStream() + Expect(err).To(MatchError(testErr)) + }) + }) + }) + + Context("as a client", func() { + BeforeEach(func() { + setNewStreamsMap(protocol.PerspectiveClient) + m.UpdateLimits(&handshake.TransportParameters{MaxStreams: 10000}) + }) + + Context("server-side streams", func() { + It("rejects streams with odd IDs", func() { + _, err := m.getOrOpenStream(5) + Expect(err).To(MatchError("InvalidStreamID: peer attempted to open stream 5")) + }) + + It("rejects streams with odds IDs, which are lower than the highest server-side stream", func() { + _, err := m.getOrOpenStream(6) + Expect(err).NotTo(HaveOccurred()) + _, err = m.getOrOpenStream(5) + Expect(err).To(MatchError("InvalidStreamID: peer attempted to open stream 5")) + }) + + It("gets new streams", func() { + s, err := m.getOrOpenStream(2) + Expect(err).NotTo(HaveOccurred()) + Expect(s.StreamID()).To(Equal(protocol.StreamID(2))) + Expect(m.streams).To(HaveLen(1)) + Expect(m.numOutgoingStreams).To(BeZero()) + Expect(m.numIncomingStreams).To(BeEquivalentTo(1)) + }) + + It("opens skipped streams", func() { + _, err := m.getOrOpenStream(6) + Expect(err).NotTo(HaveOccurred()) + Expect(m.streams).To(HaveKey(protocol.StreamID(2))) + Expect(m.streams).To(HaveKey(protocol.StreamID(4))) + Expect(m.streams).To(HaveKey(protocol.StreamID(6))) + Expect(m.numOutgoingStreams).To(BeZero()) + Expect(m.numIncomingStreams).To(BeEquivalentTo(3)) + }) + + It("doesn't reopen an already closed stream", func() { + str, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(3))) + deleteStream(3) + Expect(err).ToNot(HaveOccurred()) + str, err = m.getOrOpenStream(3) + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeNil()) + }) + }) + + Context("client-side streams", func() { + It("starts with stream 3", func() { + s, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(s).ToNot(BeNil()) + Expect(s.StreamID()).To(BeEquivalentTo(3)) + Expect(m.numOutgoingStreams).To(BeEquivalentTo(1)) + Expect(m.numIncomingStreams).To(BeZero()) + }) + + It("opens multiple streams", func() { + s1, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + s2, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(s2.StreamID()).To(Equal(s1.StreamID() + 2)) + }) + + It("doesn't reopen an already closed stream", func() { + _, err := m.getOrOpenStream(4) + Expect(err).ToNot(HaveOccurred()) + deleteStream(4) + Expect(err).ToNot(HaveOccurred()) + str, err := m.getOrOpenStream(4) + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeNil()) + }) + }) + + Context("accepting streams", func() { + It("accepts stream 2 first", func() { + var str Stream + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + var err error + str, err = m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + _, err := m.getOrOpenStream(2) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + Expect(str.StreamID()).To(Equal(protocol.StreamID(2))) + }) + }) + }) + }) + + Context("deleting streams", func() { + BeforeEach(func() { + setNewStreamsMap(protocol.PerspectiveServer) + }) + + It("deletes an incoming stream", func() { + _, err := m.getOrOpenStream(5) // open stream 3 and 5 + Expect(err).ToNot(HaveOccurred()) + Expect(m.numIncomingStreams).To(BeEquivalentTo(2)) + err = m.DeleteStream(3) + Expect(err).ToNot(HaveOccurred()) + Expect(m.streams).To(HaveLen(1)) + Expect(m.streams).To(HaveKey(protocol.StreamID(5))) + Expect(m.numIncomingStreams).To(BeEquivalentTo(1)) + }) + + It("deletes an outgoing stream", func() { + m.UpdateLimits(&handshake.TransportParameters{MaxStreams: 10000}) + _, err := m.OpenStream() // open stream 2 + Expect(err).ToNot(HaveOccurred()) + _, err = m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(m.numOutgoingStreams).To(BeEquivalentTo(2)) + err = m.DeleteStream(2) + Expect(err).ToNot(HaveOccurred()) + Expect(m.numOutgoingStreams).To(BeEquivalentTo(1)) + }) + + It("errors when the stream doesn't exist", func() { + err := m.DeleteStream(1337) + Expect(err).To(MatchError(errMapAccess)) + }) + }) + + It("sets the flow control limit", func() { + setNewStreamsMap(protocol.PerspectiveServer) + _, err := m.getOrOpenStream(5) + Expect(err).ToNot(HaveOccurred()) + m.streams[3].(*MockStreamI).EXPECT().handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{ + StreamID: 3, + ByteOffset: 321, + }) + m.streams[5].(*MockStreamI).EXPECT().handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{ + StreamID: 5, + ByteOffset: 321, + }) + m.UpdateLimits(&handshake.TransportParameters{StreamFlowControlWindow: 321}) + }) + + It("doesn't accept MAX_STREAM_ID frames", func() { + Expect(m.HandleMaxStreamIDFrame(&wire.MaxStreamIDFrame{})).ToNot(Succeed()) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/streams_map_outgoing_bidi.go b/vendor/lucas-clemente/quic-go/streams_map_outgoing_bidi.go new file mode 100644 index 00000000..ea9f47e6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_outgoing_bidi.go @@ -0,0 +1,126 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package quic + +import ( + "fmt" + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +type outgoingBidiStreamsMap struct { + mutex sync.RWMutex + cond sync.Cond + + streams map[protocol.StreamID]streamI + + nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync) + maxStream protocol.StreamID // the maximum stream ID we're allowed to open + highestBlocked protocol.StreamID // the highest stream ID that we queued a STREAM_ID_BLOCKED frame for + + newStream func(protocol.StreamID) streamI + queueStreamIDBlocked func(*wire.StreamIDBlockedFrame) + + closeErr error +} + +func newOutgoingBidiStreamsMap( + nextStream protocol.StreamID, + newStream func(protocol.StreamID) streamI, + queueControlFrame func(wire.Frame), +) *outgoingBidiStreamsMap { + m := &outgoingBidiStreamsMap{ + streams: make(map[protocol.StreamID]streamI), + nextStream: nextStream, + newStream: newStream, + queueStreamIDBlocked: func(f *wire.StreamIDBlockedFrame) { queueControlFrame(f) }, + } + m.cond.L = &m.mutex + return m +} + +func (m *outgoingBidiStreamsMap) OpenStream() (streamI, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + return m.openStreamImpl() +} + +func (m *outgoingBidiStreamsMap) OpenStreamSync() (streamI, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + for { + str, err := m.openStreamImpl() + if err == nil { + return str, err + } + if err != nil && err != qerr.TooManyOpenStreams { + return nil, err + } + m.cond.Wait() + } +} + +func (m *outgoingBidiStreamsMap) openStreamImpl() (streamI, error) { + if m.closeErr != nil { + return nil, m.closeErr + } + if m.nextStream > m.maxStream { + if m.maxStream == 0 || m.highestBlocked < m.maxStream { + m.queueStreamIDBlocked(&wire.StreamIDBlockedFrame{StreamID: m.maxStream}) + m.highestBlocked = m.maxStream + } + return nil, qerr.TooManyOpenStreams + } + s := m.newStream(m.nextStream) + m.streams[m.nextStream] = s + m.nextStream += 4 + return s, nil +} + +func (m *outgoingBidiStreamsMap) GetStream(id protocol.StreamID) (streamI, error) { + m.mutex.RLock() + if id >= m.nextStream { + m.mutex.RUnlock() + return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) + } + s := m.streams[id] + m.mutex.RUnlock() + return s, nil +} + +func (m *outgoingBidiStreamsMap) DeleteStream(id protocol.StreamID) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + if _, ok := m.streams[id]; !ok { + return fmt.Errorf("Tried to delete unknown stream %d", id) + } + delete(m.streams, id) + return nil +} + +func (m *outgoingBidiStreamsMap) SetMaxStream(id protocol.StreamID) { + m.mutex.Lock() + if id > m.maxStream { + m.maxStream = id + m.cond.Broadcast() + } + m.mutex.Unlock() +} + +func (m *outgoingBidiStreamsMap) CloseWithError(err error) { + m.mutex.Lock() + m.closeErr = err + for _, str := range m.streams { + str.closeForShutdown(err) + } + m.cond.Broadcast() + m.mutex.Unlock() +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_outgoing_generic.go b/vendor/lucas-clemente/quic-go/streams_map_outgoing_generic.go new file mode 100644 index 00000000..f4b3eb61 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_outgoing_generic.go @@ -0,0 +1,124 @@ +package quic + +import ( + "fmt" + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +//go:generate genny -in $GOFILE -out streams_map_outgoing_bidi.go gen "item=streamI Item=BidiStream" +//go:generate genny -in $GOFILE -out streams_map_outgoing_uni.go gen "item=sendStreamI Item=UniStream" +type outgoingItemsMap struct { + mutex sync.RWMutex + cond sync.Cond + + streams map[protocol.StreamID]item + + nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync) + maxStream protocol.StreamID // the maximum stream ID we're allowed to open + highestBlocked protocol.StreamID // the highest stream ID that we queued a STREAM_ID_BLOCKED frame for + + newStream func(protocol.StreamID) item + queueStreamIDBlocked func(*wire.StreamIDBlockedFrame) + + closeErr error +} + +func newOutgoingItemsMap( + nextStream protocol.StreamID, + newStream func(protocol.StreamID) item, + queueControlFrame func(wire.Frame), +) *outgoingItemsMap { + m := &outgoingItemsMap{ + streams: make(map[protocol.StreamID]item), + nextStream: nextStream, + newStream: newStream, + queueStreamIDBlocked: func(f *wire.StreamIDBlockedFrame) { queueControlFrame(f) }, + } + m.cond.L = &m.mutex + return m +} + +func (m *outgoingItemsMap) OpenStream() (item, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + return m.openStreamImpl() +} + +func (m *outgoingItemsMap) OpenStreamSync() (item, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + for { + str, err := m.openStreamImpl() + if err == nil { + return str, err + } + if err != nil && err != qerr.TooManyOpenStreams { + return nil, err + } + m.cond.Wait() + } +} + +func (m *outgoingItemsMap) openStreamImpl() (item, error) { + if m.closeErr != nil { + return nil, m.closeErr + } + if m.nextStream > m.maxStream { + if m.maxStream == 0 || m.highestBlocked < m.maxStream { + m.queueStreamIDBlocked(&wire.StreamIDBlockedFrame{StreamID: m.maxStream}) + m.highestBlocked = m.maxStream + } + return nil, qerr.TooManyOpenStreams + } + s := m.newStream(m.nextStream) + m.streams[m.nextStream] = s + m.nextStream += 4 + return s, nil +} + +func (m *outgoingItemsMap) GetStream(id protocol.StreamID) (item, error) { + m.mutex.RLock() + if id >= m.nextStream { + m.mutex.RUnlock() + return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) + } + s := m.streams[id] + m.mutex.RUnlock() + return s, nil +} + +func (m *outgoingItemsMap) DeleteStream(id protocol.StreamID) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + if _, ok := m.streams[id]; !ok { + return fmt.Errorf("Tried to delete unknown stream %d", id) + } + delete(m.streams, id) + return nil +} + +func (m *outgoingItemsMap) SetMaxStream(id protocol.StreamID) { + m.mutex.Lock() + if id > m.maxStream { + m.maxStream = id + m.cond.Broadcast() + } + m.mutex.Unlock() +} + +func (m *outgoingItemsMap) CloseWithError(err error) { + m.mutex.Lock() + m.closeErr = err + for _, str := range m.streams { + str.closeForShutdown(err) + } + m.cond.Broadcast() + m.mutex.Unlock() +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_outgoing_generic_test.go b/vendor/lucas-clemente/quic-go/streams_map_outgoing_generic_test.go new file mode 100644 index 00000000..c8426899 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_outgoing_generic_test.go @@ -0,0 +1,170 @@ +package quic + +import ( + "errors" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Streams Map (outgoing)", func() { + const firstNewStream protocol.StreamID = 10 + var ( + m *outgoingItemsMap + newItem func(id protocol.StreamID) item + mockSender *MockStreamSender + ) + + BeforeEach(func() { + newItem = func(id protocol.StreamID) item { + return &mockGenericStream{id: id} + } + mockSender = NewMockStreamSender(mockCtrl) + m = newOutgoingItemsMap(firstNewStream, newItem, mockSender.queueControlFrame) + }) + + Context("no stream ID limit", func() { + BeforeEach(func() { + m.SetMaxStream(0xffffffff) + }) + + It("opens streams", func() { + str, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream)) + str, err = m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream + 4)) + }) + + It("doesn't open streams after it has been closed", func() { + testErr := errors.New("close") + m.CloseWithError(testErr) + _, err := m.OpenStream() + Expect(err).To(MatchError(testErr)) + }) + + It("gets streams", func() { + _, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + str, err := m.GetStream(firstNewStream) + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream)) + }) + + It("errors when trying to get a stream that has not yet been opened", func() { + _, err := m.GetStream(10) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidStreamID, "peer attempted to open stream 10"))) + }) + + It("deletes streams", func() { + _, err := m.OpenStream() // opens stream 10 + Expect(err).ToNot(HaveOccurred()) + err = m.DeleteStream(10) + Expect(err).ToNot(HaveOccurred()) + str, err := m.GetStream(10) + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeNil()) + }) + + It("errors when deleting a non-existing stream", func() { + err := m.DeleteStream(1337) + Expect(err).To(MatchError("Tried to delete unknown stream 1337")) + }) + + It("errors when deleting a stream twice", func() { + _, err := m.OpenStream() // opens stream 10 + Expect(err).ToNot(HaveOccurred()) + err = m.DeleteStream(10) + Expect(err).ToNot(HaveOccurred()) + err = m.DeleteStream(10) + Expect(err).To(MatchError("Tried to delete unknown stream 10")) + }) + + It("closes all streams when CloseWithError is called", func() { + str1, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + str2, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + testErr := errors.New("test err") + m.CloseWithError(testErr) + Expect(str1.(*mockGenericStream).closed).To(BeTrue()) + Expect(str1.(*mockGenericStream).closeErr).To(MatchError(testErr)) + Expect(str2.(*mockGenericStream).closed).To(BeTrue()) + Expect(str2.(*mockGenericStream).closeErr).To(MatchError(testErr)) + }) + }) + + Context("with stream ID limits", func() { + It("errors when no stream can be opened immediately", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + _, err := m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + }) + + It("blocks until a stream can be opened synchronously", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + str, err := m.OpenStreamSync() + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream)) + close(done) + }() + + Consistently(done).ShouldNot(BeClosed()) + m.SetMaxStream(firstNewStream) + Eventually(done).Should(BeClosed()) + }) + + It("stops opening synchronously when it is closed", func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + testErr := errors.New("test error") + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := m.OpenStreamSync() + Expect(err).To(MatchError(testErr)) + close(done) + }() + + Consistently(done).ShouldNot(BeClosed()) + m.CloseWithError(testErr) + Eventually(done).Should(BeClosed()) + }) + + It("doesn't reduce the stream limit", func() { + m.SetMaxStream(firstNewStream) + m.SetMaxStream(firstNewStream - 4) + str, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.(*mockGenericStream).id).To(Equal(firstNewStream)) + }) + + It("queues a STREAM_ID_BLOCKED frame if no stream can be opened", func() { + m.SetMaxStream(firstNewStream) + mockSender.EXPECT().queueControlFrame(&wire.StreamIDBlockedFrame{StreamID: firstNewStream}) + _, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + _, err = m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + }) + + It("only sends one STREAM_ID_BLOCKED frame for one stream ID", func() { + m.SetMaxStream(firstNewStream) + mockSender.EXPECT().queueControlFrame(&wire.StreamIDBlockedFrame{StreamID: firstNewStream}) + _, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + // try to open a stream twice, but expect only one STREAM_ID_BLOCKED to be sent + _, err = m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + _, err = m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + }) + }) +}) diff --git a/vendor/lucas-clemente/quic-go/streams_map_outgoing_uni.go b/vendor/lucas-clemente/quic-go/streams_map_outgoing_uni.go new file mode 100644 index 00000000..6ad0348c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_outgoing_uni.go @@ -0,0 +1,126 @@ +// This file was automatically generated by genny. +// Any changes will be lost if this file is regenerated. +// see https://github.com/cheekybits/genny + +package quic + +import ( + "fmt" + "sync" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" +) + +type outgoingUniStreamsMap struct { + mutex sync.RWMutex + cond sync.Cond + + streams map[protocol.StreamID]sendStreamI + + nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync) + maxStream protocol.StreamID // the maximum stream ID we're allowed to open + highestBlocked protocol.StreamID // the highest stream ID that we queued a STREAM_ID_BLOCKED frame for + + newStream func(protocol.StreamID) sendStreamI + queueStreamIDBlocked func(*wire.StreamIDBlockedFrame) + + closeErr error +} + +func newOutgoingUniStreamsMap( + nextStream protocol.StreamID, + newStream func(protocol.StreamID) sendStreamI, + queueControlFrame func(wire.Frame), +) *outgoingUniStreamsMap { + m := &outgoingUniStreamsMap{ + streams: make(map[protocol.StreamID]sendStreamI), + nextStream: nextStream, + newStream: newStream, + queueStreamIDBlocked: func(f *wire.StreamIDBlockedFrame) { queueControlFrame(f) }, + } + m.cond.L = &m.mutex + return m +} + +func (m *outgoingUniStreamsMap) OpenStream() (sendStreamI, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + return m.openStreamImpl() +} + +func (m *outgoingUniStreamsMap) OpenStreamSync() (sendStreamI, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + for { + str, err := m.openStreamImpl() + if err == nil { + return str, err + } + if err != nil && err != qerr.TooManyOpenStreams { + return nil, err + } + m.cond.Wait() + } +} + +func (m *outgoingUniStreamsMap) openStreamImpl() (sendStreamI, error) { + if m.closeErr != nil { + return nil, m.closeErr + } + if m.nextStream > m.maxStream { + if m.maxStream == 0 || m.highestBlocked < m.maxStream { + m.queueStreamIDBlocked(&wire.StreamIDBlockedFrame{StreamID: m.maxStream}) + m.highestBlocked = m.maxStream + } + return nil, qerr.TooManyOpenStreams + } + s := m.newStream(m.nextStream) + m.streams[m.nextStream] = s + m.nextStream += 4 + return s, nil +} + +func (m *outgoingUniStreamsMap) GetStream(id protocol.StreamID) (sendStreamI, error) { + m.mutex.RLock() + if id >= m.nextStream { + m.mutex.RUnlock() + return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) + } + s := m.streams[id] + m.mutex.RUnlock() + return s, nil +} + +func (m *outgoingUniStreamsMap) DeleteStream(id protocol.StreamID) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + if _, ok := m.streams[id]; !ok { + return fmt.Errorf("Tried to delete unknown stream %d", id) + } + delete(m.streams, id) + return nil +} + +func (m *outgoingUniStreamsMap) SetMaxStream(id protocol.StreamID) { + m.mutex.Lock() + if id > m.maxStream { + m.maxStream = id + m.cond.Broadcast() + } + m.mutex.Unlock() +} + +func (m *outgoingUniStreamsMap) CloseWithError(err error) { + m.mutex.Lock() + m.closeErr = err + for _, str := range m.streams { + str.closeForShutdown(err) + } + m.cond.Broadcast() + m.mutex.Unlock() +} diff --git a/vendor/lucas-clemente/quic-go/streams_map_test.go b/vendor/lucas-clemente/quic-go/streams_map_test.go new file mode 100644 index 00000000..2cd58a3e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/streams_map_test.go @@ -0,0 +1,365 @@ +package quic + +import ( + "errors" + "fmt" + "math" + + "github.com/golang/mock/gomock" + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/mocks" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + "github.com/lucas-clemente/quic-go/qerr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type streamMapping struct { + firstIncomingBidiStream protocol.StreamID + firstIncomingUniStream protocol.StreamID + firstOutgoingBidiStream protocol.StreamID + firstOutgoingUniStream protocol.StreamID +} + +var _ = Describe("Streams Map (for IETF QUIC)", func() { + newFlowController := func(protocol.StreamID) flowcontrol.StreamFlowController { + return mocks.NewMockStreamFlowController(mockCtrl) + } + + serverStreamMapping := streamMapping{ + firstIncomingBidiStream: 4, + firstOutgoingBidiStream: 1, + firstIncomingUniStream: 2, + firstOutgoingUniStream: 3, + } + clientStreamMapping := streamMapping{ + firstIncomingBidiStream: 1, + firstOutgoingBidiStream: 4, + firstIncomingUniStream: 3, + firstOutgoingUniStream: 2, + } + + for _, p := range []protocol.Perspective{protocol.PerspectiveServer, protocol.PerspectiveClient} { + perspective := p + var ids streamMapping + if perspective == protocol.PerspectiveClient { + ids = clientStreamMapping + } else { + ids = serverStreamMapping + } + + Context(perspective.String(), func() { + var ( + m *streamsMap + mockSender *MockStreamSender + ) + + const ( + maxBidiStreams = 111 + maxUniStreams = 222 + ) + + allowUnlimitedStreams := func() { + m.UpdateLimits(&handshake.TransportParameters{ + MaxBidiStreams: math.MaxUint16, + MaxUniStreams: math.MaxUint16, + }) + } + + BeforeEach(func() { + mockSender = NewMockStreamSender(mockCtrl) + m = newStreamsMap(mockSender, newFlowController, maxBidiStreams, maxUniStreams, perspective, versionIETFFrames).(*streamsMap) + }) + + Context("opening", func() { + It("opens bidirectional streams", func() { + allowUnlimitedStreams() + str, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeAssignableToTypeOf(&stream{})) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingBidiStream)) + str, err = m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeAssignableToTypeOf(&stream{})) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingBidiStream + 4)) + }) + + It("opens unidirectional streams", func() { + allowUnlimitedStreams() + str, err := m.OpenUniStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeAssignableToTypeOf(&sendStream{})) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingUniStream)) + str, err = m.OpenUniStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeAssignableToTypeOf(&sendStream{})) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingUniStream + 4)) + }) + }) + + Context("accepting", func() { + It("accepts bidirectional streams", func() { + _, err := m.GetOrOpenReceiveStream(ids.firstIncomingBidiStream) + Expect(err).ToNot(HaveOccurred()) + str, err := m.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeAssignableToTypeOf(&stream{})) + Expect(str.StreamID()).To(Equal(ids.firstIncomingBidiStream)) + }) + + It("accepts unidirectional streams", func() { + _, err := m.GetOrOpenReceiveStream(ids.firstIncomingUniStream) + Expect(err).ToNot(HaveOccurred()) + str, err := m.AcceptUniStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str).To(BeAssignableToTypeOf(&receiveStream{})) + Expect(str.StreamID()).To(Equal(ids.firstIncomingUniStream)) + }) + }) + + Context("deleting", func() { + BeforeEach(func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()).AnyTimes() + allowUnlimitedStreams() + }) + + It("deletes outgoing bidirectional streams", func() { + id := ids.firstOutgoingBidiStream + str, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(id)) + Expect(m.DeleteStream(id)).To(Succeed()) + dstr, err := m.GetOrOpenSendStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(dstr).To(BeNil()) + }) + + It("deletes incoming bidirectional streams", func() { + id := ids.firstIncomingBidiStream + str, err := m.GetOrOpenReceiveStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(id)) + Expect(m.DeleteStream(id)).To(Succeed()) + dstr, err := m.GetOrOpenReceiveStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(dstr).To(BeNil()) + }) + + It("deletes outgoing unidirectional streams", func() { + id := ids.firstOutgoingUniStream + str, err := m.OpenUniStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(id)) + Expect(m.DeleteStream(id)).To(Succeed()) + dstr, err := m.GetOrOpenSendStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(dstr).To(BeNil()) + }) + + It("deletes incoming unidirectional streams", func() { + id := ids.firstIncomingUniStream + str, err := m.GetOrOpenReceiveStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(id)) + Expect(m.DeleteStream(id)).To(Succeed()) + dstr, err := m.GetOrOpenReceiveStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(dstr).To(BeNil()) + }) + }) + + Context("getting streams", func() { + BeforeEach(func() { + allowUnlimitedStreams() + }) + + Context("send streams", func() { + It("gets an outgoing bidirectional stream", func() { + // need to open the stream ourselves first + // the peer is not allowed to create a stream initiated by us + _, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + str, err := m.GetOrOpenSendStream(ids.firstOutgoingBidiStream) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingBidiStream)) + }) + + It("errors when the peer tries to open a higher outgoing bidirectional stream", func() { + id := ids.firstOutgoingBidiStream + 5*4 + _, err := m.GetOrOpenSendStream(id) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)))) + }) + + It("gets an outgoing unidirectional stream", func() { + // need to open the stream ourselves first + // the peer is not allowed to create a stream initiated by us + _, err := m.OpenUniStream() + Expect(err).ToNot(HaveOccurred()) + str, err := m.GetOrOpenSendStream(ids.firstOutgoingUniStream) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingUniStream)) + }) + + It("errors when the peer tries to open a higher outgoing bidirectional stream", func() { + id := ids.firstOutgoingUniStream + 5*4 + _, err := m.GetOrOpenSendStream(id) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)))) + }) + + It("gets an incoming bidirectional stream", func() { + id := ids.firstIncomingBidiStream + 4*7 + str, err := m.GetOrOpenSendStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(id)) + }) + + It("errors when trying to get an incoming unidirectional stream", func() { + id := ids.firstIncomingUniStream + _, err := m.GetOrOpenSendStream(id) + Expect(err).To(MatchError(fmt.Errorf("peer attempted to open send stream %d", id))) + }) + }) + + Context("receive streams", func() { + It("gets an outgoing bidirectional stream", func() { + // need to open the stream ourselves first + // the peer is not allowed to create a stream initiated by us + _, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + str, err := m.GetOrOpenReceiveStream(ids.firstOutgoingBidiStream) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingBidiStream)) + }) + + It("errors when the peer tries to open a higher outgoing bidirectional stream", func() { + id := ids.firstOutgoingBidiStream + 5*4 + _, err := m.GetOrOpenReceiveStream(id) + Expect(err).To(MatchError(qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)))) + }) + + It("gets an incoming bidirectional stream", func() { + id := ids.firstIncomingBidiStream + 4*7 + str, err := m.GetOrOpenReceiveStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(id)) + }) + + It("gets an incoming unidirectional stream", func() { + id := ids.firstIncomingUniStream + 4*10 + str, err := m.GetOrOpenReceiveStream(id) + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(id)) + }) + + It("errors when trying to get an outgoing unidirectional stream", func() { + id := ids.firstOutgoingUniStream + _, err := m.GetOrOpenReceiveStream(id) + Expect(err).To(MatchError(fmt.Errorf("peer attempted to open receive stream %d", id))) + }) + }) + }) + + Context("updating stream ID limits", func() { + BeforeEach(func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()) + }) + + It("processes the parameter for outgoing streams, as a server", func() { + m.perspective = protocol.PerspectiveServer + _, err := m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + m.UpdateLimits(&handshake.TransportParameters{ + MaxBidiStreams: 5, + MaxUniStreams: 5, + }) + Expect(m.outgoingBidiStreams.maxStream).To(Equal(protocol.StreamID(17))) + Expect(m.outgoingUniStreams.maxStream).To(Equal(protocol.StreamID(19))) + }) + + It("processes the parameter for outgoing streams, as a client", func() { + m.perspective = protocol.PerspectiveClient + _, err := m.OpenUniStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + m.UpdateLimits(&handshake.TransportParameters{ + MaxBidiStreams: 5, + MaxUniStreams: 5, + }) + Expect(m.outgoingBidiStreams.maxStream).To(Equal(protocol.StreamID(20))) + Expect(m.outgoingUniStreams.maxStream).To(Equal(protocol.StreamID(18))) + }) + }) + + Context("handling MAX_STREAM_ID frames", func() { + BeforeEach(func() { + mockSender.EXPECT().queueControlFrame(gomock.Any()).AnyTimes() + }) + + It("processes IDs for outgoing bidirectional streams", func() { + _, err := m.OpenStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + err = m.HandleMaxStreamIDFrame(&wire.MaxStreamIDFrame{StreamID: ids.firstOutgoingBidiStream}) + Expect(err).ToNot(HaveOccurred()) + str, err := m.OpenStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingBidiStream)) + }) + + It("processes IDs for outgoing bidirectional streams", func() { + _, err := m.OpenUniStream() + Expect(err).To(MatchError(qerr.TooManyOpenStreams)) + err = m.HandleMaxStreamIDFrame(&wire.MaxStreamIDFrame{StreamID: ids.firstOutgoingUniStream}) + Expect(err).ToNot(HaveOccurred()) + str, err := m.OpenUniStream() + Expect(err).ToNot(HaveOccurred()) + Expect(str.StreamID()).To(Equal(ids.firstOutgoingUniStream)) + }) + + It("rejects IDs for incoming bidirectional streams", func() { + err := m.HandleMaxStreamIDFrame(&wire.MaxStreamIDFrame{StreamID: ids.firstIncomingBidiStream}) + Expect(err).To(MatchError(fmt.Sprintf("received MAX_STREAM_DATA frame for incoming stream %d", ids.firstIncomingBidiStream))) + }) + + It("rejects IDs for incoming unidirectional streams", func() { + err := m.HandleMaxStreamIDFrame(&wire.MaxStreamIDFrame{StreamID: ids.firstIncomingUniStream}) + Expect(err).To(MatchError(fmt.Sprintf("received MAX_STREAM_DATA frame for incoming stream %d", ids.firstIncomingUniStream))) + }) + }) + + Context("sending MAX_STREAM_ID frames", func() { + It("sends MAX_STREAM_ID frames for bidirectional streams", func() { + _, err := m.GetOrOpenReceiveStream(ids.firstIncomingBidiStream + 4*10) + Expect(err).ToNot(HaveOccurred()) + mockSender.EXPECT().queueControlFrame(&wire.MaxStreamIDFrame{ + StreamID: protocol.MaxBidiStreamID(maxBidiStreams, perspective) + 4, + }) + Expect(m.DeleteStream(ids.firstIncomingBidiStream)).To(Succeed()) + }) + + It("sends MAX_STREAM_ID frames for unidirectional streams", func() { + _, err := m.GetOrOpenReceiveStream(ids.firstIncomingUniStream + 4*10) + Expect(err).ToNot(HaveOccurred()) + mockSender.EXPECT().queueControlFrame(&wire.MaxStreamIDFrame{ + StreamID: protocol.MaxUniStreamID(maxUniStreams, perspective) + 4, + }) + Expect(m.DeleteStream(ids.firstIncomingUniStream)).To(Succeed()) + }) + }) + + It("closes", func() { + testErr := errors.New("test error") + m.CloseWithError(testErr) + _, err := m.OpenStream() + Expect(err).To(MatchError(testErr)) + _, err = m.OpenUniStream() + Expect(err).To(MatchError(testErr)) + _, err = m.AcceptStream() + Expect(err).To(MatchError(testErr)) + _, err = m.AcceptUniStream() + Expect(err).To(MatchError(testErr)) + }) + }) + } +}) diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/LICENSE.md b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/LICENSE.md new file mode 100644 index 00000000..63858124 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Richard Barnes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/README.md b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/README.md new file mode 100644 index 00000000..9fa05ddd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/README.md @@ -0,0 +1,94 @@ +![A lock with a mint leaf](https://ipv.sx/mint/mint.svg) + +mint - A Minimal TLS 1.3 stack +============================== + +[![Build Status](https://circleci.com/gh/bifurcation/mint.svg)](https://circleci.com/gh/bifurcation/mint) + +This project is primarily a learning effort for me to understand the [TLS +1.3](http://tlswg.github.io/tls13-spec/) protocol. The goal is to arrive at a +pretty complete implementation of TLS 1.3, with minimal, elegant code that +demonstrates how things work. Testing is a priority to ensure correctness, but +otherwise, the quality of the software engineering might not be at a level where +it makes sense to integrate this with other libraries. Backward compatibility +is not an objective. + +We borrow liberally from the [Go TLS +library](https://golang.org/pkg/crypto/tls/), especially where TLS 1.3 aligns +with earlier TLS versions. However, unnecessary parts will be ruthlessly cut +off. + +## DTLS Support + +Mint has partial support for DTLS, but that support is not yet complete +and may still contain serious defects. + + +## Quickstart + +Installation is the same as for any other Go package: + +``` +go get github.com/bifurcation/mint +``` + +The API is pretty much the same as for the TLS module, with `Dial` and `Listen` +methods wrapping the underlying socket APIs. + +``` +conn, err := mint.Dial("tcp", "localhost:4430", &mint.Config{...}) +... +listener, err := mint.Listen("tcp", "localhost:4430", &mint.Config{...}) +``` + +Documentation is available on +[godoc.org](https://godoc.org/github.com/bifurcation/mint) + + +## Interoperability testing + +The `mint-client` and `mint-server` executables are included to make it easy to +do basic interoperability tests with other TLS 1.3 implementations. The steps +for testing against NSS are as follows. + +``` +# Install mint +go get github.com/bifurcation/mint + +# Environment for NSS (you'll probably want a new directory) +NSS_ROOT= +mkdir $NSS_ROOT +cd $NSS_ROOT +export USE_64=1 +export ENABLE_TLS_1_3=1 +export HOST=localhost +export DOMSUF=localhost + +# Build NSS +hg clone https://hg.mozilla.org/projects/nss +hg clone https://hg.mozilla.org/projects/nspr +cd nss +make nss_build_all + +export PLATFORM=`cat $NSS_ROOT/dist/latest` +export DYLD_LIBRARY_PATH=$NSS_ROOT/dist/$PLATFORM/lib +export LD_LIBRARY_PATH=$NSS_ROOT/dist/$PLATFORM/lib + +# Run NSS tests (this creates data for the server to use) +cd tests/ssl_gtests +./ssl_gtests.sh + +# Test with client=mint server=NSS +cd $NSS_ROOT +./dist/$PLATFORM/bin/selfserv -d tests_results/security/$HOST.1/ssl_gtests/ -n rsa -p 4430 +# if you get `NSS_Init failed.`, check the path above, particularly around $HOST +# ... +go run $GOPATH/src/github.com/bifurcation/mint/bin/mint-client/main.go + +# Test with client=NSS server=mint +go run $GOPATH/src/github.com/bifurcation/mint/bin/mint-server/main.go +# ... +cd $NSS_ROOT +dist/$PLATFORM/bin/tstclnt -d tests_results/security/$HOST/ssl_gtests/ -V tls1.3:tls1.3 -h 127.0.0.1 -p 4430 -o +``` + diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/alert.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/alert.go new file mode 100644 index 00000000..430e4554 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/alert.go @@ -0,0 +1,101 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mint + +import "strconv" + +type Alert uint8 + +const ( + // alert level + AlertLevelWarning = 1 + AlertLevelError = 2 +) + +const ( + AlertCloseNotify Alert = 0 + AlertUnexpectedMessage Alert = 10 + AlertBadRecordMAC Alert = 20 + AlertDecryptionFailed Alert = 21 + AlertRecordOverflow Alert = 22 + AlertDecompressionFailure Alert = 30 + AlertHandshakeFailure Alert = 40 + AlertBadCertificate Alert = 42 + AlertUnsupportedCertificate Alert = 43 + AlertCertificateRevoked Alert = 44 + AlertCertificateExpired Alert = 45 + AlertCertificateUnknown Alert = 46 + AlertIllegalParameter Alert = 47 + AlertUnknownCA Alert = 48 + AlertAccessDenied Alert = 49 + AlertDecodeError Alert = 50 + AlertDecryptError Alert = 51 + AlertProtocolVersion Alert = 70 + AlertInsufficientSecurity Alert = 71 + AlertInternalError Alert = 80 + AlertInappropriateFallback Alert = 86 + AlertUserCanceled Alert = 90 + AlertNoRenegotiation Alert = 100 + AlertMissingExtension Alert = 109 + AlertUnsupportedExtension Alert = 110 + AlertCertificateUnobtainable Alert = 111 + AlertUnrecognizedName Alert = 112 + AlertBadCertificateStatsResponse Alert = 113 + AlertBadCertificateHashValue Alert = 114 + AlertUnknownPSKIdentity Alert = 115 + AlertNoApplicationProtocol Alert = 120 + AlertStatelessRetry Alert = 253 + AlertWouldBlock Alert = 254 + AlertNoAlert Alert = 255 +) + +var alertText = map[Alert]string{ + AlertCloseNotify: "close notify", + AlertUnexpectedMessage: "unexpected message", + AlertBadRecordMAC: "bad record MAC", + AlertDecryptionFailed: "decryption failed", + AlertRecordOverflow: "record overflow", + AlertDecompressionFailure: "decompression failure", + AlertHandshakeFailure: "handshake failure", + AlertBadCertificate: "bad certificate", + AlertUnsupportedCertificate: "unsupported certificate", + AlertCertificateRevoked: "revoked certificate", + AlertCertificateExpired: "expired certificate", + AlertCertificateUnknown: "unknown certificate", + AlertIllegalParameter: "illegal parameter", + AlertUnknownCA: "unknown certificate authority", + AlertAccessDenied: "access denied", + AlertDecodeError: "error decoding message", + AlertDecryptError: "error decrypting message", + AlertProtocolVersion: "protocol version not supported", + AlertInsufficientSecurity: "insufficient security level", + AlertInternalError: "internal error", + AlertInappropriateFallback: "inappropriate fallback", + AlertUserCanceled: "user canceled", + AlertMissingExtension: "missing extension", + AlertUnsupportedExtension: "unsupported extension", + AlertCertificateUnobtainable: "certificate unobtainable", + AlertUnrecognizedName: "unrecognized name", + AlertBadCertificateStatsResponse: "bad certificate status response", + AlertBadCertificateHashValue: "bad certificate hash value", + AlertUnknownPSKIdentity: "unknown PSK identity", + AlertNoApplicationProtocol: "no application protocol", + AlertNoRenegotiation: "no renegotiation", + AlertStatelessRetry: "stateless retry", + AlertWouldBlock: "would have blocked", + AlertNoAlert: "no alert", +} + +func (e Alert) String() string { + s, ok := alertText[e] + if ok { + return s + } + return "alert(" + strconv.Itoa(int(e)) + ")" +} + +func (e Alert) Error() string { + return e.String() +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/client-state-machine.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/client-state-machine.go new file mode 100644 index 00000000..07e7f53f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/client-state-machine.go @@ -0,0 +1,1083 @@ +package mint + +import ( + "bytes" + "crypto" + "crypto/x509" + "hash" + "time" +) + +// Client State Machine +// +// START <----+ +// Send ClientHello | | Recv HelloRetryRequest +// / v | +// | WAIT_SH ---+ +// Can | | Recv ServerHello +// send | V +// early | WAIT_EE +// data | | Recv EncryptedExtensions +// | +--------+--------+ +// | Using | | Using certificate +// | PSK | v +// | | WAIT_CERT_CR +// | | Recv | | Recv CertificateRequest +// | | Certificate | v +// | | | WAIT_CERT +// | | | | Recv Certificate +// | | v v +// | | WAIT_CV +// | | | Recv CertificateVerify +// | +> WAIT_FINISHED <+ +// | | Recv Finished +// \ | +// | [Send EndOfEarlyData] +// | [Send Certificate [+ CertificateVerify]] +// | Send Finished +// Can send v +// app data --> CONNECTED +// after +// here +// +// State Instructions +// START Send(CH); [RekeyOut; SendEarlyData] +// WAIT_SH Send(CH) || RekeyIn +// WAIT_EE {} +// WAIT_CERT_CR {} +// WAIT_CERT {} +// WAIT_CV {} +// WAIT_FINISHED RekeyIn; [Send(EOED);] RekeyOut; [SendCert; SendCV;] SendFin; RekeyOut; +// CONNECTED StoreTicket || (RekeyIn; [RekeyOut]) + +type clientStateStart struct { + Config *Config + Opts ConnectionOptions + Params ConnectionParameters + + cookie []byte + firstClientHello *HandshakeMessage + helloRetryRequest *HandshakeMessage + hsCtx *HandshakeContext +} + +var _ HandshakeState = &clientStateStart{} + +func (state clientStateStart) State() State { + return StateClientStart +} + +func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + // key_shares + offeredDH := map[NamedGroup][]byte{} + ks := KeyShareExtension{ + HandshakeType: HandshakeTypeClientHello, + Shares: make([]KeyShareEntry, len(state.Config.Groups)), + } + for i, group := range state.Config.Groups { + pub, priv, err := newKeyShare(group) + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error generating key share [%v]", err) + return nil, nil, AlertInternalError + } + + ks.Shares[i].Group = group + ks.Shares[i].KeyExchange = pub + offeredDH[group] = priv + } + + logf(logTypeHandshake, "opts: %+v", state.Opts) + + // supported_versions, supported_groups, signature_algorithms, server_name + sv := SupportedVersionsExtension{HandshakeType: HandshakeTypeClientHello, Versions: []uint16{supportedVersion}} + sni := ServerNameExtension(state.Opts.ServerName) + sg := SupportedGroupsExtension{Groups: state.Config.Groups} + sa := SignatureAlgorithmsExtension{Algorithms: state.Config.SignatureSchemes} + + state.Params.ServerName = state.Opts.ServerName + + // Application Layer Protocol Negotiation + var alpn *ALPNExtension + if (state.Opts.NextProtos != nil) && (len(state.Opts.NextProtos) > 0) { + alpn = &ALPNExtension{Protocols: state.Opts.NextProtos} + } + + // Construct base ClientHello + ch := &ClientHelloBody{ + LegacyVersion: wireVersion(state.hsCtx.hIn), + CipherSuites: state.Config.CipherSuites, + } + _, err := prng.Read(ch.Random[:]) + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error creating ClientHello random [%v]", err) + return nil, nil, AlertInternalError + } + for _, ext := range []ExtensionBody{&sv, &sni, &ks, &sg, &sa} { + err := ch.Extensions.Add(ext) + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error adding extension type=[%v] [%v]", ext.Type(), err) + return nil, nil, AlertInternalError + } + } + // XXX: These optional extensions can't be folded into the above because Go + // interface-typed values are never reported as nil + if alpn != nil { + err := ch.Extensions.Add(alpn) + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error adding ALPN extension [%v]", err) + return nil, nil, AlertInternalError + } + } + if state.cookie != nil { + err := ch.Extensions.Add(&CookieExtension{Cookie: state.cookie}) + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error adding ALPN extension [%v]", err) + return nil, nil, AlertInternalError + } + } + + // Run the external extension handler. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Send(HandshakeTypeClientHello, &ch.Extensions) + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error running external extension sender [%v]", err) + return nil, nil, AlertInternalError + } + } + + // Handle PSK and EarlyData just before transmitting, so that we can + // calculate the PSK binder value + var psk *PreSharedKeyExtension + var ed *EarlyDataExtension + var offeredPSK PreSharedKey + var earlyHash crypto.Hash + var earlySecret []byte + var clientEarlyTrafficKeys keySet + var clientHello *HandshakeMessage + if key, ok := state.Config.PSKs.Get(state.Opts.ServerName); ok { + offeredPSK = key + + // Narrow ciphersuites to ones that match PSK hash + params, ok := cipherSuiteMap[key.CipherSuite] + if !ok { + logf(logTypeHandshake, "[ClientStateStart] PSK for unknown ciphersuite") + return nil, nil, AlertInternalError + } + + compatibleSuites := []CipherSuite{} + for _, suite := range ch.CipherSuites { + if cipherSuiteMap[suite].Hash == params.Hash { + compatibleSuites = append(compatibleSuites, suite) + } + } + ch.CipherSuites = compatibleSuites + + // TODO(ekr@rtfm.com): Check that the ticket can be used for early + // data. + // Signal early data if we're going to do it + if state.Config.AllowEarlyData && state.helloRetryRequest == nil { + state.Params.ClientSendingEarlyData = true + ed = &EarlyDataExtension{} + err = ch.Extensions.Add(ed) + if err != nil { + logf(logTypeHandshake, "Error adding early data extension: %v", err) + return nil, nil, AlertInternalError + } + } + + // Signal supported PSK key exchange modes + if len(state.Config.PSKModes) == 0 { + logf(logTypeHandshake, "PSK selected, but no PSKModes") + return nil, nil, AlertInternalError + } + kem := &PSKKeyExchangeModesExtension{KEModes: state.Config.PSKModes} + err = ch.Extensions.Add(kem) + if err != nil { + logf(logTypeHandshake, "Error adding PSKKeyExchangeModes extension: %v", err) + return nil, nil, AlertInternalError + } + + // Add the shim PSK extension to the ClientHello + logf(logTypeHandshake, "Adding PSK extension with id = %x", key.Identity) + psk = &PreSharedKeyExtension{ + HandshakeType: HandshakeTypeClientHello, + Identities: []PSKIdentity{ + { + Identity: key.Identity, + ObfuscatedTicketAge: uint32(time.Since(key.ReceivedAt)/time.Millisecond) + key.TicketAgeAdd, + }, + }, + Binders: []PSKBinderEntry{ + // Note: Stub to get the length fields right + {Binder: bytes.Repeat([]byte{0x00}, params.Hash.Size())}, + }, + } + ch.Extensions.Add(psk) + + // Compute the binder key + h0 := params.Hash.New().Sum(nil) + zero := bytes.Repeat([]byte{0}, params.Hash.Size()) + + earlyHash = params.Hash + earlySecret = HkdfExtract(params.Hash, zero, key.Key) + logf(logTypeCrypto, "early secret: [%d] %x", len(earlySecret), earlySecret) + + binderLabel := labelExternalBinder + if key.IsResumption { + binderLabel = labelResumptionBinder + } + binderKey := deriveSecret(params, earlySecret, binderLabel, h0) + logf(logTypeCrypto, "binder key: [%d] %x", len(binderKey), binderKey) + + // Compute the binder value + trunc, err := ch.Truncated() + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error marshaling truncated ClientHello [%v]", err) + return nil, nil, AlertInternalError + } + + truncHash := params.Hash.New() + truncHash.Write(trunc) + + binder := computeFinishedData(params, binderKey, truncHash.Sum(nil)) + + // Replace the PSK extension + psk.Binders[0].Binder = binder + ch.Extensions.Add(psk) + + // If we got here, the earlier marshal succeeded (in ch.Truncated()), so + // this one should too. + clientHello, _ = state.hsCtx.hOut.HandshakeMessageFromBody(ch) + + // Compute early traffic keys + h := params.Hash.New() + h.Write(clientHello.Marshal()) + chHash := h.Sum(nil) + + earlyTrafficSecret := deriveSecret(params, earlySecret, labelEarlyTrafficSecret, chHash) + logf(logTypeCrypto, "early traffic secret: [%d] %x", len(earlyTrafficSecret), earlyTrafficSecret) + clientEarlyTrafficKeys = makeTrafficKeys(params, earlyTrafficSecret) + } else { + clientHello, err = state.hsCtx.hOut.HandshakeMessageFromBody(ch) + if err != nil { + logf(logTypeHandshake, "[ClientStateStart] Error marshaling ClientHello [%v]", err) + return nil, nil, AlertInternalError + } + } + + logf(logTypeHandshake, "[ClientStateStart] -> [ClientStateWaitSH]") + state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2. + nextState := clientStateWaitSH{ + Config: state.Config, + Opts: state.Opts, + Params: state.Params, + hsCtx: state.hsCtx, + OfferedDH: offeredDH, + OfferedPSK: offeredPSK, + + earlySecret: earlySecret, + earlyHash: earlyHash, + + firstClientHello: state.firstClientHello, + helloRetryRequest: state.helloRetryRequest, + clientHello: clientHello, + } + + toSend := []HandshakeAction{ + QueueHandshakeMessage{clientHello}, + SendQueuedHandshake{}, + } + if state.Params.ClientSendingEarlyData { + toSend = append(toSend, []HandshakeAction{ + RekeyOut{epoch: EpochEarlyData, KeySet: clientEarlyTrafficKeys}, + }...) + } + + return nextState, toSend, AlertNoAlert +} + +type clientStateWaitSH struct { + Config *Config + Opts ConnectionOptions + Params ConnectionParameters + hsCtx *HandshakeContext + OfferedDH map[NamedGroup][]byte + OfferedPSK PreSharedKey + PSK []byte + + earlySecret []byte + earlyHash crypto.Hash + + firstClientHello *HandshakeMessage + helloRetryRequest *HandshakeMessage + clientHello *HandshakeMessage +} + +var _ HandshakeState = &clientStateWaitSH{} + +func (state clientStateWaitSH) State() State { + return StateClientWaitSH +} + +func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + + if hm == nil || hm.msgType != HandshakeTypeServerHello { + logf(logTypeHandshake, "[ClientStateWaitSH] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + sh := &ServerHelloBody{} + if _, err := sh.Unmarshal(hm.body); err != nil { + logf(logTypeHandshake, "[ClientStateWaitSH] unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + // Common SH/HRR processing first. + // 1. Check that sh.version is TLS 1.2 + if sh.Version != tls12Version { + logf(logTypeHandshake, "[ClientStateWaitSH] illegal legacy version [%v]", sh.Version) + return nil, nil, AlertIllegalParameter + } + + // 2. Check that it responded with a valid version. + supportedVersions := SupportedVersionsExtension{HandshakeType: HandshakeTypeServerHello} + foundSupportedVersions, err := sh.Extensions.Find(&supportedVersions) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitSH] invalid supported_versions extension [%v]", err) + return nil, nil, AlertDecodeError + } + if !foundSupportedVersions { + logf(logTypeHandshake, "[ClientStateWaitSH] no supported_versions extension") + return nil, nil, AlertMissingExtension + } + if supportedVersions.Versions[0] != supportedVersion { + logf(logTypeHandshake, "[ClientStateWaitSH] unsupported version [%x]", supportedVersions.Versions[0]) + return nil, nil, AlertProtocolVersion + } + // 3. Check that the server provided a supported ciphersuite + supportedCipherSuite := false + for _, suite := range state.Config.CipherSuites { + supportedCipherSuite = supportedCipherSuite || (suite == sh.CipherSuite) + } + if !supportedCipherSuite { + logf(logTypeHandshake, "[ClientStateWaitSH] Unsupported ciphersuite [%04x]", sh.CipherSuite) + return nil, nil, AlertHandshakeFailure + } + + // Now check for the sentinel. + + if sh.Random == hrrRandomSentinel { + // This is actually HRR. + hrr := sh + + // Narrow the supported ciphersuites to the server-provided one + state.Config.CipherSuites = []CipherSuite{hrr.CipherSuite} + + // Handle external extensions. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Receive(HandshakeTypeHelloRetryRequest, &hrr.Extensions) + if err != nil { + logf(logTypeHandshake, "[ClientWaitSH] Error running external extension handler [%v]", err) + return nil, nil, AlertInternalError + } + } + + // The only thing we know how to respond to in an HRR is the Cookie + // extension, so if there is either no Cookie extension or anything other + // than a Cookie extension and SupportedVersions we have to fail. + serverCookie := new(CookieExtension) + foundCookie, err := hrr.Extensions.Find(serverCookie) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitSH] Invalid server cookie extension [%v]", err) + return nil, nil, AlertDecodeError + } + if !foundCookie || len(hrr.Extensions) != 2 { + logf(logTypeHandshake, "[ClientStateWaitSH] No Cookie or extra extensions [%v] [%d]", foundCookie, len(hrr.Extensions)) + return nil, nil, AlertIllegalParameter + } + + // Hash the body into a pseudo-message + // XXX: Ignoring some errors here + params := cipherSuiteMap[hrr.CipherSuite] + h := params.Hash.New() + h.Write(state.clientHello.Marshal()) + firstClientHello := &HandshakeMessage{ + msgType: HandshakeTypeMessageHash, + body: h.Sum(nil), + } + + state.hsCtx.receivedEndOfFlight() + + // TODO(ekr@rtfm.com): Need to rekey with cleartext if we are on 0-RTT + // mode. In DTLS, we also need to bump the sequence number. + // This is a pre-existing defect in Mint. Issue #175. + logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateStart]") + return clientStateStart{ + Config: state.Config, + Opts: state.Opts, + hsCtx: state.hsCtx, + cookie: serverCookie.Cookie, + firstClientHello: firstClientHello, + helloRetryRequest: hm, + }, []HandshakeAction{ResetOut{1}}, AlertNoAlert + } + + // This is SH. + // Handle external extensions. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Receive(HandshakeTypeServerHello, &sh.Extensions) + if err != nil { + logf(logTypeHandshake, "[ClientWaitSH] Error running external extension handler [%v]", err) + return nil, nil, AlertInternalError + } + } + + // Do PSK or key agreement depending on extensions + serverPSK := PreSharedKeyExtension{HandshakeType: HandshakeTypeServerHello} + serverKeyShare := KeyShareExtension{HandshakeType: HandshakeTypeServerHello} + + foundExts, err := sh.Extensions.Parse( + []ExtensionBody{ + &serverPSK, + &serverKeyShare, + }) + if err != nil { + logf(logTypeHandshake, "[ClientWaitSH] Error processing extensions [%v]", err) + return nil, nil, AlertDecodeError + } + + if foundExts[ExtensionTypePreSharedKey] && (serverPSK.SelectedIdentity == 0) { + state.Params.UsingPSK = true + } + + var dhSecret []byte + if foundExts[ExtensionTypeKeyShare] { + sks := serverKeyShare.Shares[0] + priv, ok := state.OfferedDH[sks.Group] + if !ok { + logf(logTypeHandshake, "[ClientStateWaitSH] Key share for unknown group") + return nil, nil, AlertIllegalParameter + } + + state.Params.UsingDH = true + dhSecret, _ = keyAgreement(sks.Group, sks.KeyExchange, priv) + } + + suite := sh.CipherSuite + state.Params.CipherSuite = suite + + params, ok := cipherSuiteMap[suite] + if !ok { + logf(logTypeCrypto, "Unsupported ciphersuite [%04x]", suite) + return nil, nil, AlertHandshakeFailure + } + + // Start up the handshake hash + handshakeHash := params.Hash.New() + handshakeHash.Write(state.firstClientHello.Marshal()) + handshakeHash.Write(state.helloRetryRequest.Marshal()) + handshakeHash.Write(state.clientHello.Marshal()) + handshakeHash.Write(hm.Marshal()) + + // Compute handshake secrets + zero := bytes.Repeat([]byte{0}, params.Hash.Size()) + + var earlySecret []byte + if state.Params.UsingPSK { + if params.Hash != state.earlyHash { + logf(logTypeCrypto, "Change of hash between early and normal init early=[%02x] suite=[%04x] hash=[%02x]", + state.earlyHash, suite, params.Hash) + } + + earlySecret = state.earlySecret + } else { + earlySecret = HkdfExtract(params.Hash, zero, zero) + } + + if dhSecret == nil { + dhSecret = zero + } + + h0 := params.Hash.New().Sum(nil) + h2 := handshakeHash.Sum(nil) + preHandshakeSecret := deriveSecret(params, earlySecret, labelDerived, h0) + handshakeSecret := HkdfExtract(params.Hash, preHandshakeSecret, dhSecret) + clientHandshakeTrafficSecret := deriveSecret(params, handshakeSecret, labelClientHandshakeTrafficSecret, h2) + serverHandshakeTrafficSecret := deriveSecret(params, handshakeSecret, labelServerHandshakeTrafficSecret, h2) + preMasterSecret := deriveSecret(params, handshakeSecret, labelDerived, h0) + masterSecret := HkdfExtract(params.Hash, preMasterSecret, zero) + + logf(logTypeCrypto, "early secret: [%d] %x", len(earlySecret), earlySecret) + logf(logTypeCrypto, "handshake secret: [%d] %x", len(handshakeSecret), handshakeSecret) + logf(logTypeCrypto, "client handshake traffic secret: [%d] %x", len(clientHandshakeTrafficSecret), clientHandshakeTrafficSecret) + logf(logTypeCrypto, "server handshake traffic secret: [%d] %x", len(serverHandshakeTrafficSecret), serverHandshakeTrafficSecret) + logf(logTypeCrypto, "master secret: [%d] %x", len(masterSecret), masterSecret) + + serverHandshakeKeys := makeTrafficKeys(params, serverHandshakeTrafficSecret) + logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateWaitEE]") + nextState := clientStateWaitEE{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: params, + handshakeHash: handshakeHash, + masterSecret: masterSecret, + clientHandshakeTrafficSecret: clientHandshakeTrafficSecret, + serverHandshakeTrafficSecret: serverHandshakeTrafficSecret, + } + toSend := []HandshakeAction{ + RekeyIn{epoch: EpochHandshakeData, KeySet: serverHandshakeKeys}, + } + // We're definitely not going to have to send anything with + // early data. + if !state.Params.ClientSendingEarlyData { + toSend = append(toSend, RekeyOut{epoch: EpochHandshakeData, + KeySet: makeTrafficKeys(params, clientHandshakeTrafficSecret)}) + } + + return nextState, toSend, AlertNoAlert +} + +type clientStateWaitEE struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + handshakeHash hash.Hash + masterSecret []byte + clientHandshakeTrafficSecret []byte + serverHandshakeTrafficSecret []byte +} + +var _ HandshakeState = &clientStateWaitEE{} + +func (state clientStateWaitEE) State() State { + return StateClientWaitEE +} + +func (state clientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeEncryptedExtensions { + logf(logTypeHandshake, "[ClientStateWaitEE] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + ee := EncryptedExtensionsBody{} + if err := safeUnmarshal(&ee, hm.body); err != nil { + logf(logTypeHandshake, "[ClientStateWaitEE] Error decoding message: %v", err) + return nil, nil, AlertDecodeError + } + + // Handle external extensions. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Receive(HandshakeTypeEncryptedExtensions, &ee.Extensions) + if err != nil { + logf(logTypeHandshake, "[ClientWaitStateEE] Error running external extension handler [%v]", err) + return nil, nil, AlertInternalError + } + } + + serverALPN := &ALPNExtension{} + serverEarlyData := &EarlyDataExtension{} + + foundExts, err := ee.Extensions.Parse( + []ExtensionBody{ + serverALPN, + serverEarlyData, + }) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitEE] Error decoding extensions: %v", err) + return nil, nil, AlertDecodeError + } + + state.Params.UsingEarlyData = foundExts[ExtensionTypeEarlyData] + + if foundExts[ExtensionTypeALPN] && len(serverALPN.Protocols) > 0 { + state.Params.NextProto = serverALPN.Protocols[0] + } + + state.handshakeHash.Write(hm.Marshal()) + + toSend := []HandshakeAction{} + + if state.Params.ClientSendingEarlyData && !state.Params.UsingEarlyData { + // We didn't get 0-RTT, so rekey to handshake. + toSend = append(toSend, RekeyOut{epoch: EpochHandshakeData, + KeySet: makeTrafficKeys(state.cryptoParams, state.clientHandshakeTrafficSecret)}) + } + + if state.Params.UsingPSK { + logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitFinished]") + nextState := clientStateWaitFinished{ + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + certificates: state.Config.Certificates, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, + } + return nextState, toSend, AlertNoAlert + } + + logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitCertCR]") + nextState := clientStateWaitCertCR{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, + } + return nextState, toSend, AlertNoAlert +} + +type clientStateWaitCertCR struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + handshakeHash hash.Hash + masterSecret []byte + clientHandshakeTrafficSecret []byte + serverHandshakeTrafficSecret []byte +} + +var _ HandshakeState = &clientStateWaitCertCR{} + +func (state clientStateWaitCertCR) State() State { + return StateClientWaitCertCR +} + +func (state clientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil { + logf(logTypeHandshake, "[ClientStateWaitCertCR] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + bodyGeneric, err := hm.ToBody() + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitCertCR] Error decoding message: %v", err) + return nil, nil, AlertDecodeError + } + + state.handshakeHash.Write(hm.Marshal()) + + switch body := bodyGeneric.(type) { + case *CertificateBody: + logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCV]") + nextState := clientStateWaitCV{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + serverCertificate: body, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, + } + return nextState, nil, AlertNoAlert + + case *CertificateRequestBody: + // A certificate request in the handshake should have a zero-length context + if len(body.CertificateRequestContext) > 0 { + logf(logTypeHandshake, "[ClientStateWaitCertCR] Certificate request with non-empty context: %v", err) + return nil, nil, AlertIllegalParameter + } + + state.Params.UsingClientAuth = true + + logf(logTypeHandshake, "[ClientStateWaitCertCR] -> [ClientStateWaitCert]") + nextState := clientStateWaitCert{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + serverCertificateRequest: body, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, + } + return nextState, nil, AlertNoAlert + } + + return nil, nil, AlertUnexpectedMessage +} + +type clientStateWaitCert struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + handshakeHash hash.Hash + + serverCertificateRequest *CertificateRequestBody + + masterSecret []byte + clientHandshakeTrafficSecret []byte + serverHandshakeTrafficSecret []byte +} + +var _ HandshakeState = &clientStateWaitCert{} + +func (state clientStateWaitCert) State() State { + return StateClientWaitCert +} + +func (state clientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeCertificate { + logf(logTypeHandshake, "[ClientStateWaitCert] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + cert := &CertificateBody{} + if err := safeUnmarshal(cert, hm.body); err != nil { + logf(logTypeHandshake, "[ClientStateWaitCert] Error decoding message: %v", err) + return nil, nil, AlertDecodeError + } + + state.handshakeHash.Write(hm.Marshal()) + + logf(logTypeHandshake, "[ClientStateWaitCert] -> [ClientStateWaitCV]") + nextState := clientStateWaitCV{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + serverCertificate: cert, + serverCertificateRequest: state.serverCertificateRequest, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, + } + return nextState, nil, AlertNoAlert +} + +type clientStateWaitCV struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + handshakeHash hash.Hash + + serverCertificate *CertificateBody + serverCertificateRequest *CertificateRequestBody + + masterSecret []byte + clientHandshakeTrafficSecret []byte + serverHandshakeTrafficSecret []byte +} + +var _ HandshakeState = &clientStateWaitCV{} + +func (state clientStateWaitCV) State() State { + return StateClientWaitCV +} + +func (state clientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeCertificateVerify { + logf(logTypeHandshake, "[ClientStateWaitCV] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + certVerify := CertificateVerifyBody{} + if err := safeUnmarshal(&certVerify, hm.body); err != nil { + logf(logTypeHandshake, "[ClientStateWaitCV] Error decoding message: %v", err) + return nil, nil, AlertDecodeError + } + + hcv := state.handshakeHash.Sum(nil) + logf(logTypeHandshake, "Handshake Hash to be verified: [%d] %x", len(hcv), hcv) + + serverPublicKey := state.serverCertificate.CertificateList[0].CertData.PublicKey + if err := certVerify.Verify(serverPublicKey, hcv); err != nil { + logf(logTypeHandshake, "[ClientStateWaitCV] Server signature failed to verify") + return nil, nil, AlertHandshakeFailure + } + + certs := make([]*x509.Certificate, len(state.serverCertificate.CertificateList)) + rawCerts := make([][]byte, len(state.serverCertificate.CertificateList)) + for i, certEntry := range state.serverCertificate.CertificateList { + certs[i] = certEntry.CertData + rawCerts[i] = certEntry.CertData.Raw + } + + var verifiedChains [][]*x509.Certificate + if !state.Config.InsecureSkipVerify { + opts := x509.VerifyOptions{ + Roots: state.Config.RootCAs, + CurrentTime: state.Config.time(), + DNSName: state.Config.ServerName, + Intermediates: x509.NewCertPool(), + } + + for i, cert := range certs { + if i == 0 { + continue + } + opts.Intermediates.AddCert(cert) + } + var err error + verifiedChains, err = certs[0].Verify(opts) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitCV] Certificate verification failed: %s", err) + return nil, nil, AlertBadCertificate + } + } + + if state.Config.VerifyPeerCertificate != nil { + if err := state.Config.VerifyPeerCertificate(rawCerts, verifiedChains); err != nil { + logf(logTypeHandshake, "[ClientStateWaitCV] Application rejected server certificate: %s", err) + return nil, nil, AlertBadCertificate + } + } + + state.handshakeHash.Write(hm.Marshal()) + + logf(logTypeHandshake, "[ClientStateWaitCV] -> [ClientStateWaitFinished]") + nextState := clientStateWaitFinished{ + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + certificates: state.Config.Certificates, + serverCertificateRequest: state.serverCertificateRequest, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, + peerCertificates: certs, + verifiedChains: verifiedChains, + } + return nextState, nil, AlertNoAlert +} + +type clientStateWaitFinished struct { + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + handshakeHash hash.Hash + + certificates []*Certificate + serverCertificateRequest *CertificateRequestBody + peerCertificates []*x509.Certificate + verifiedChains [][]*x509.Certificate + + masterSecret []byte + clientHandshakeTrafficSecret []byte + serverHandshakeTrafficSecret []byte +} + +var _ HandshakeState = &clientStateWaitFinished{} + +func (state clientStateWaitFinished) State() State { + return StateClientWaitFinished +} + +func (state clientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeFinished { + logf(logTypeHandshake, "[ClientStateWaitFinished] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + // Verify server's Finished + h3 := state.handshakeHash.Sum(nil) + logf(logTypeCrypto, "handshake hash 3 [%d] %x", len(h3), h3) + logf(logTypeCrypto, "handshake hash for server Finished: [%d] %x", len(h3), h3) + + serverFinishedData := computeFinishedData(state.cryptoParams, state.serverHandshakeTrafficSecret, h3) + logf(logTypeCrypto, "server finished data: [%d] %x", len(serverFinishedData), serverFinishedData) + + fin := &FinishedBody{VerifyDataLen: len(serverFinishedData)} + if err := safeUnmarshal(fin, hm.body); err != nil { + logf(logTypeHandshake, "[ClientStateWaitFinished] Error decoding message: %v", err) + return nil, nil, AlertDecodeError + } + + if !bytes.Equal(fin.VerifyData, serverFinishedData) { + logf(logTypeHandshake, "[ClientStateWaitFinished] Server's Finished failed to verify [%x] != [%x]", + fin.VerifyData, serverFinishedData) + return nil, nil, AlertHandshakeFailure + } + + // Update the handshake hash with the Finished + state.handshakeHash.Write(hm.Marshal()) + logf(logTypeCrypto, "input to handshake hash [%d]: %x", len(hm.Marshal()), hm.Marshal()) + h4 := state.handshakeHash.Sum(nil) + logf(logTypeCrypto, "handshake hash 4 [%d]: %x", len(h4), h4) + + // Compute traffic secrets and keys + clientTrafficSecret := deriveSecret(state.cryptoParams, state.masterSecret, labelClientApplicationTrafficSecret, h4) + serverTrafficSecret := deriveSecret(state.cryptoParams, state.masterSecret, labelServerApplicationTrafficSecret, h4) + logf(logTypeCrypto, "client traffic secret: [%d] %x", len(clientTrafficSecret), clientTrafficSecret) + logf(logTypeCrypto, "server traffic secret: [%d] %x", len(serverTrafficSecret), serverTrafficSecret) + + clientTrafficKeys := makeTrafficKeys(state.cryptoParams, clientTrafficSecret) + serverTrafficKeys := makeTrafficKeys(state.cryptoParams, serverTrafficSecret) + + exporterSecret := deriveSecret(state.cryptoParams, state.masterSecret, labelExporterSecret, h4) + logf(logTypeCrypto, "client exporter secret: [%d] %x", len(exporterSecret), exporterSecret) + + // Assemble client's second flight + toSend := []HandshakeAction{} + + if state.Params.UsingEarlyData { + logf(logTypeHandshake, "Sending end of early data") + // Note: We only send EOED if the server is actually going to use the early + // data. Otherwise, it will never see it, and the transcripts will + // mismatch. + // EOED marshal is infallible + eoedm, _ := state.hsCtx.hOut.HandshakeMessageFromBody(&EndOfEarlyDataBody{}) + toSend = append(toSend, QueueHandshakeMessage{eoedm}) + + state.handshakeHash.Write(eoedm.Marshal()) + logf(logTypeCrypto, "input to handshake hash [%d]: %x", len(eoedm.Marshal()), eoedm.Marshal()) + + // And then rekey to handshake + toSend = append(toSend, RekeyOut{epoch: EpochHandshakeData, + KeySet: makeTrafficKeys(state.cryptoParams, state.clientHandshakeTrafficSecret)}) + } + + if state.Params.UsingClientAuth { + // Extract constraints from certicateRequest + schemes := SignatureAlgorithmsExtension{} + gotSchemes, err := state.serverCertificateRequest.Extensions.Find(&schemes) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitFinished] WARNING invalid signature_schemes extension [%v]", err) + return nil, nil, AlertDecodeError + } + if !gotSchemes { + logf(logTypeHandshake, "[ClientStateWaitFinished] WARNING no appropriate certificate found") + return nil, nil, AlertIllegalParameter + } + + // Select a certificate + cert, certScheme, err := CertificateSelection(nil, schemes.Algorithms, state.certificates) + if err != nil { + // XXX: Signal this to the application layer? + logf(logTypeHandshake, "[ClientStateWaitFinished] WARNING no appropriate certificate found [%v]", err) + + certificate := &CertificateBody{} + certm, err := state.hsCtx.hOut.HandshakeMessageFromBody(certificate) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitFinished] Error marshaling Certificate [%v]", err) + return nil, nil, AlertInternalError + } + + toSend = append(toSend, QueueHandshakeMessage{certm}) + state.handshakeHash.Write(certm.Marshal()) + } else { + // Create and send Certificate, CertificateVerify + certificate := &CertificateBody{ + CertificateList: make([]CertificateEntry, len(cert.Chain)), + } + for i, entry := range cert.Chain { + certificate.CertificateList[i] = CertificateEntry{CertData: entry} + } + certm, err := state.hsCtx.hOut.HandshakeMessageFromBody(certificate) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitFinished] Error marshaling Certificate [%v]", err) + return nil, nil, AlertInternalError + } + + toSend = append(toSend, QueueHandshakeMessage{certm}) + state.handshakeHash.Write(certm.Marshal()) + + hcv := state.handshakeHash.Sum(nil) + logf(logTypeHandshake, "Handshake Hash to be verified: [%d] %x", len(hcv), hcv) + + certificateVerify := &CertificateVerifyBody{Algorithm: certScheme} + logf(logTypeHandshake, "Creating CertVerify: %04x %v", certScheme, state.cryptoParams.Hash) + + err = certificateVerify.Sign(cert.PrivateKey, hcv) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitFinished] Error signing CertificateVerify [%v]", err) + return nil, nil, AlertInternalError + } + certvm, err := state.hsCtx.hOut.HandshakeMessageFromBody(certificateVerify) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitFinished] Error marshaling CertificateVerify [%v]", err) + return nil, nil, AlertInternalError + } + + toSend = append(toSend, QueueHandshakeMessage{certvm}) + state.handshakeHash.Write(certvm.Marshal()) + } + } + + // Compute the client's Finished message + h5 := state.handshakeHash.Sum(nil) + logf(logTypeCrypto, "handshake hash for client Finished: [%d] %x", len(h5), h5) + + clientFinishedData := computeFinishedData(state.cryptoParams, state.clientHandshakeTrafficSecret, h5) + logf(logTypeCrypto, "client Finished data: [%d] %x", len(clientFinishedData), clientFinishedData) + + fin = &FinishedBody{ + VerifyDataLen: len(clientFinishedData), + VerifyData: clientFinishedData, + } + finm, err := state.hsCtx.hOut.HandshakeMessageFromBody(fin) + if err != nil { + logf(logTypeHandshake, "[ClientStateWaitFinished] Error marshaling client Finished [%v]", err) + return nil, nil, AlertInternalError + } + + // Compute the resumption secret + state.handshakeHash.Write(finm.Marshal()) + h6 := state.handshakeHash.Sum(nil) + + resumptionSecret := deriveSecret(state.cryptoParams, state.masterSecret, labelResumptionSecret, h6) + logf(logTypeCrypto, "resumption secret: [%d] %x", len(resumptionSecret), resumptionSecret) + + toSend = append(toSend, []HandshakeAction{ + QueueHandshakeMessage{finm}, + SendQueuedHandshake{}, + RekeyIn{epoch: EpochApplicationData, KeySet: serverTrafficKeys}, + RekeyOut{epoch: EpochApplicationData, KeySet: clientTrafficKeys}, + }...) + + state.hsCtx.receivedEndOfFlight() + + logf(logTypeHandshake, "[ClientStateWaitFinished] -> [StateConnected]") + nextState := stateConnected{ + Params: state.Params, + hsCtx: state.hsCtx, + isClient: true, + cryptoParams: state.cryptoParams, + resumptionSecret: resumptionSecret, + clientTrafficSecret: clientTrafficSecret, + serverTrafficSecret: serverTrafficSecret, + exporterSecret: exporterSecret, + peerCertificates: state.peerCertificates, + verifiedChains: state.verifiedChains, + } + return nextState, toSend, AlertNoAlert +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/common.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/common.go new file mode 100644 index 00000000..05af3e95 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/common.go @@ -0,0 +1,266 @@ +package mint + +import ( + "fmt" + "strconv" +) + +const ( + supportedVersion uint16 = 0x7f16 // draft-22 + tls12Version uint16 = 0x0303 + tls10Version uint16 = 0x0301 + dtls12WireVersion uint16 = 0xfefd +) + +var ( + // Flags for some minor compat issues + allowWrongVersionNumber = true + allowPKCS1 = true +) + +// enum {...} ContentType; +type RecordType byte + +const ( + RecordTypeAlert RecordType = 21 + RecordTypeHandshake RecordType = 22 + RecordTypeApplicationData RecordType = 23 + RecordTypeAck RecordType = 25 +) + +// enum {...} HandshakeType; +type HandshakeType byte + +const ( + // Omitted: *_RESERVED + HandshakeTypeClientHello HandshakeType = 1 + HandshakeTypeServerHello HandshakeType = 2 + HandshakeTypeNewSessionTicket HandshakeType = 4 + HandshakeTypeEndOfEarlyData HandshakeType = 5 + HandshakeTypeHelloRetryRequest HandshakeType = 6 + HandshakeTypeEncryptedExtensions HandshakeType = 8 + HandshakeTypeCertificate HandshakeType = 11 + HandshakeTypeCertificateRequest HandshakeType = 13 + HandshakeTypeCertificateVerify HandshakeType = 15 + HandshakeTypeServerConfiguration HandshakeType = 17 + HandshakeTypeFinished HandshakeType = 20 + HandshakeTypeKeyUpdate HandshakeType = 24 + HandshakeTypeMessageHash HandshakeType = 254 +) + +var hrrRandomSentinel = [32]byte{ + 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, + 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, + 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, + 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, +} + +// uint8 CipherSuite[2]; +type CipherSuite uint16 + +const ( + // XXX: Actually TLS_NULL_WITH_NULL_NULL, but we need a way to label the zero + // value for this type so that we can detect when a field is set. + CIPHER_SUITE_UNKNOWN CipherSuite = 0x0000 + TLS_AES_128_GCM_SHA256 CipherSuite = 0x1301 + TLS_AES_256_GCM_SHA384 CipherSuite = 0x1302 + TLS_CHACHA20_POLY1305_SHA256 CipherSuite = 0x1303 + TLS_AES_128_CCM_SHA256 CipherSuite = 0x1304 + TLS_AES_256_CCM_8_SHA256 CipherSuite = 0x1305 +) + +func (c CipherSuite) String() string { + switch c { + case CIPHER_SUITE_UNKNOWN: + return "unknown" + case TLS_AES_128_GCM_SHA256: + return "TLS_AES_128_GCM_SHA256" + case TLS_AES_256_GCM_SHA384: + return "TLS_AES_256_GCM_SHA384" + case TLS_CHACHA20_POLY1305_SHA256: + return "TLS_CHACHA20_POLY1305_SHA256" + case TLS_AES_128_CCM_SHA256: + return "TLS_AES_128_CCM_SHA256" + case TLS_AES_256_CCM_8_SHA256: + return "TLS_AES_256_CCM_8_SHA256" + } + // cannot use %x here, since it calls String(), leading to infinite recursion + return fmt.Sprintf("invalid CipherSuite value: 0x%s", strconv.FormatUint(uint64(c), 16)) +} + +// enum {...} SignatureScheme +type SignatureScheme uint16 + +const ( + // RSASSA-PKCS1-v1_5 algorithms + RSA_PKCS1_SHA1 SignatureScheme = 0x0201 + RSA_PKCS1_SHA256 SignatureScheme = 0x0401 + RSA_PKCS1_SHA384 SignatureScheme = 0x0501 + RSA_PKCS1_SHA512 SignatureScheme = 0x0601 + // ECDSA algorithms + ECDSA_P256_SHA256 SignatureScheme = 0x0403 + ECDSA_P384_SHA384 SignatureScheme = 0x0503 + ECDSA_P521_SHA512 SignatureScheme = 0x0603 + // RSASSA-PSS algorithms + RSA_PSS_SHA256 SignatureScheme = 0x0804 + RSA_PSS_SHA384 SignatureScheme = 0x0805 + RSA_PSS_SHA512 SignatureScheme = 0x0806 + // EdDSA algorithms + Ed25519 SignatureScheme = 0x0807 + Ed448 SignatureScheme = 0x0808 +) + +// enum {...} ExtensionType +type ExtensionType uint16 + +const ( + ExtensionTypeServerName ExtensionType = 0 + ExtensionTypeSupportedGroups ExtensionType = 10 + ExtensionTypeSignatureAlgorithms ExtensionType = 13 + ExtensionTypeALPN ExtensionType = 16 + ExtensionTypeKeyShare ExtensionType = 40 + ExtensionTypePreSharedKey ExtensionType = 41 + ExtensionTypeEarlyData ExtensionType = 42 + ExtensionTypeSupportedVersions ExtensionType = 43 + ExtensionTypeCookie ExtensionType = 44 + ExtensionTypePSKKeyExchangeModes ExtensionType = 45 + ExtensionTypeTicketEarlyDataInfo ExtensionType = 46 +) + +// enum {...} NamedGroup +type NamedGroup uint16 + +const ( + // Elliptic Curve Groups. + P256 NamedGroup = 23 + P384 NamedGroup = 24 + P521 NamedGroup = 25 + // ECDH functions. + X25519 NamedGroup = 29 + X448 NamedGroup = 30 + // Finite field groups. + FFDHE2048 NamedGroup = 256 + FFDHE3072 NamedGroup = 257 + FFDHE4096 NamedGroup = 258 + FFDHE6144 NamedGroup = 259 + FFDHE8192 NamedGroup = 260 +) + +// enum {...} PskKeyExchangeMode; +type PSKKeyExchangeMode uint8 + +const ( + PSKModeKE PSKKeyExchangeMode = 0 + PSKModeDHEKE PSKKeyExchangeMode = 1 +) + +// enum { +// update_not_requested(0), update_requested(1), (255) +// } KeyUpdateRequest; +type KeyUpdateRequest uint8 + +const ( + KeyUpdateNotRequested KeyUpdateRequest = 0 + KeyUpdateRequested KeyUpdateRequest = 1 +) + +type State uint8 + +const ( + StateInit = 0 + + // states valid for the client + StateClientStart State = iota + StateClientWaitSH + StateClientWaitEE + StateClientWaitCert + StateClientWaitCV + StateClientWaitFinished + StateClientWaitCertCR + StateClientConnected + // states valid for the server + StateServerStart State = iota + StateServerRecvdCH + StateServerNegotiated + StateServerReadPastEarlyData + StateServerWaitEOED + StateServerWaitFlight2 + StateServerWaitCert + StateServerWaitCV + StateServerWaitFinished + StateServerConnected +) + +func (s State) String() string { + switch s { + case StateClientStart: + return "Client START" + case StateClientWaitSH: + return "Client WAIT_SH" + case StateClientWaitEE: + return "Client WAIT_EE" + case StateClientWaitCert: + return "Client WAIT_CERT" + case StateClientWaitCV: + return "Client WAIT_CV" + case StateClientWaitFinished: + return "Client WAIT_FINISHED" + case StateClientWaitCertCR: + return "Client WAIT_CERT_CR" + case StateClientConnected: + return "Client CONNECTED" + case StateServerStart: + return "Server START" + case StateServerRecvdCH: + return "Server RECVD_CH" + case StateServerNegotiated: + return "Server NEGOTIATED" + case StateServerReadPastEarlyData: + return "Server READ_PAST_EARLY_DATA" + case StateServerWaitEOED: + return "Server WAIT_EOED" + case StateServerWaitFlight2: + return "Server WAIT_FLIGHT2" + case StateServerWaitCert: + return "Server WAIT_CERT" + case StateServerWaitCV: + return "Server WAIT_CV" + case StateServerWaitFinished: + return "Server WAIT_FINISHED" + case StateServerConnected: + return "Server CONNECTED" + default: + return fmt.Sprintf("unknown state: %d", s) + } +} + +// Epochs for DTLS (also used for key phase labelling) +type Epoch uint16 + +const ( + EpochClear Epoch = 0 + EpochEarlyData Epoch = 1 + EpochHandshakeData Epoch = 2 + EpochApplicationData Epoch = 3 + EpochUpdate Epoch = 4 +) + +func (e Epoch) label() string { + switch e { + case EpochClear: + return "clear" + case EpochEarlyData: + return "early data" + case EpochHandshakeData: + return "handshake" + case EpochApplicationData: + return "application data" + } + return "Application data (updated)" +} + +func assert(b bool) { + if !b { + panic("Assertion failed") + } +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/conn.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/conn.go new file mode 100644 index 00000000..12a99171 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/conn.go @@ -0,0 +1,921 @@ +package mint + +import ( + "crypto" + "crypto/x509" + "encoding/hex" + "errors" + "fmt" + "io" + "net" + "reflect" + "sync" + "time" +) + +type Certificate struct { + Chain []*x509.Certificate + PrivateKey crypto.Signer +} + +type PreSharedKey struct { + CipherSuite CipherSuite + IsResumption bool + Identity []byte + Key []byte + NextProto string + ReceivedAt time.Time + ExpiresAt time.Time + TicketAgeAdd uint32 +} + +type PreSharedKeyCache interface { + Get(string) (PreSharedKey, bool) + Put(string, PreSharedKey) + Size() int +} + +// A CookieHandler can be used to give the application more fine-grained control over Cookies. +// Generate receives the Conn as an argument, so the CookieHandler can decide when to send the cookie based on that, and offload state to the client by encoding that into the Cookie. +// When the client echoes the Cookie, Validate is called. The application can then recover the state from the cookie. +type CookieHandler interface { + // Generate a byte string that is sent as a part of a cookie to the client in the HelloRetryRequest + // If Generate returns nil, mint will not send a HelloRetryRequest. + Generate(*Conn) ([]byte, error) + // Validate is called when receiving a ClientHello containing a Cookie. + // If validation failed, the handshake is aborted. + Validate(*Conn, []byte) bool +} + +type PSKMapCache map[string]PreSharedKey + +func (cache PSKMapCache) Get(key string) (psk PreSharedKey, ok bool) { + psk, ok = cache[key] + return +} + +func (cache *PSKMapCache) Put(key string, psk PreSharedKey) { + (*cache)[key] = psk +} + +func (cache PSKMapCache) Size() int { + return len(cache) +} + +// Config is the struct used to pass configuration settings to a TLS client or +// server instance. The settings for client and server are pretty different, +// but we just throw them all in here. +type Config struct { + // Client fields + ServerName string + + // Server fields + SendSessionTickets bool + TicketLifetime uint32 + TicketLen int + EarlyDataLifetime uint32 + AllowEarlyData bool + // Require the client to echo a cookie. + RequireCookie bool + // A CookieHandler can be used to set and validate a cookie. + // The cookie returned by the CookieHandler will be part of the cookie sent on the wire, and encoded using the CookieProtector. + // If no CookieHandler is set, mint will always send a cookie. + // The CookieHandler can be used to decide on a per-connection basis, if a cookie should be sent. + CookieHandler CookieHandler + // The CookieProtector is used to encrypt / decrypt cookies. + // It should make sure that the Cookie cannot be read and tampered with by the client. + // If non-blocking mode is used, and cookies are required, this field has to be set. + // In blocking mode, a default cookie protector is used, if this is unused. + CookieProtector CookieProtector + // The ExtensionHandler is used to add custom extensions. + ExtensionHandler AppExtensionHandler + RequireClientAuth bool + + // Time returns the current time as the number of seconds since the epoch. + // If Time is nil, TLS uses time.Now. + Time func() time.Time + // RootCAs defines the set of root certificate authorities + // that clients use when verifying server certificates. + // If RootCAs is nil, TLS uses the host's root CA set. + RootCAs *x509.CertPool + // InsecureSkipVerify controls whether a client verifies the + // server's certificate chain and host name. + // If InsecureSkipVerify is true, TLS accepts any certificate + // presented by the server and any host name in that certificate. + // In this mode, TLS is susceptible to man-in-the-middle attacks. + // This should be used only for testing. + InsecureSkipVerify bool + + // Shared fields + Certificates []*Certificate + // VerifyPeerCertificate, if not nil, is called after normal + // certificate verification by either a TLS client or server. It + // receives the raw ASN.1 certificates provided by the peer and also + // any verified chains that normal processing found. If it returns a + // non-nil error, the handshake is aborted and that error results. + // + // If normal verification fails then the handshake will abort before + // considering this callback. If normal verification is disabled by + // setting InsecureSkipVerify then this callback will be considered but + // the verifiedChains argument will always be nil. + VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error + + CipherSuites []CipherSuite + Groups []NamedGroup + SignatureSchemes []SignatureScheme + NextProtos []string + PSKs PreSharedKeyCache + PSKModes []PSKKeyExchangeMode + NonBlocking bool + UseDTLS bool + + // The same config object can be shared among different connections, so it + // needs its own mutex + mutex sync.RWMutex +} + +// Clone returns a shallow clone of c. It is safe to clone a Config that is +// being used concurrently by a TLS client or server. +func (c *Config) Clone() *Config { + c.mutex.Lock() + defer c.mutex.Unlock() + + return &Config{ + ServerName: c.ServerName, + + SendSessionTickets: c.SendSessionTickets, + TicketLifetime: c.TicketLifetime, + TicketLen: c.TicketLen, + EarlyDataLifetime: c.EarlyDataLifetime, + AllowEarlyData: c.AllowEarlyData, + RequireCookie: c.RequireCookie, + CookieHandler: c.CookieHandler, + CookieProtector: c.CookieProtector, + ExtensionHandler: c.ExtensionHandler, + RequireClientAuth: c.RequireClientAuth, + Time: c.Time, + RootCAs: c.RootCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + + Certificates: c.Certificates, + VerifyPeerCertificate: c.VerifyPeerCertificate, + CipherSuites: c.CipherSuites, + Groups: c.Groups, + SignatureSchemes: c.SignatureSchemes, + NextProtos: c.NextProtos, + PSKs: c.PSKs, + PSKModes: c.PSKModes, + NonBlocking: c.NonBlocking, + UseDTLS: c.UseDTLS, + } +} + +func (c *Config) Init(isClient bool) error { + c.mutex.Lock() + defer c.mutex.Unlock() + + // Set defaults + if len(c.CipherSuites) == 0 { + c.CipherSuites = defaultSupportedCipherSuites + } + if len(c.Groups) == 0 { + c.Groups = defaultSupportedGroups + } + if len(c.SignatureSchemes) == 0 { + c.SignatureSchemes = defaultSignatureSchemes + } + if c.TicketLen == 0 { + c.TicketLen = defaultTicketLen + } + if !reflect.ValueOf(c.PSKs).IsValid() { + c.PSKs = &PSKMapCache{} + } + if len(c.PSKModes) == 0 { + c.PSKModes = defaultPSKModes + } + return nil +} + +func (c *Config) ValidForServer() bool { + return (reflect.ValueOf(c.PSKs).IsValid() && c.PSKs.Size() > 0) || + (len(c.Certificates) > 0 && + len(c.Certificates[0].Chain) > 0 && + c.Certificates[0].PrivateKey != nil) +} + +func (c *Config) ValidForClient() bool { + return len(c.ServerName) > 0 +} + +func (c *Config) time() time.Time { + t := c.Time + if t == nil { + t = time.Now + } + return t() +} + +var ( + defaultSupportedCipherSuites = []CipherSuite{ + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + } + + defaultSupportedGroups = []NamedGroup{ + P256, + P384, + FFDHE2048, + X25519, + } + + defaultSignatureSchemes = []SignatureScheme{ + RSA_PSS_SHA256, + RSA_PSS_SHA384, + RSA_PSS_SHA512, + ECDSA_P256_SHA256, + ECDSA_P384_SHA384, + ECDSA_P521_SHA512, + } + + defaultTicketLen = 16 + + defaultPSKModes = []PSKKeyExchangeMode{ + PSKModeKE, + PSKModeDHEKE, + } +) + +type ConnectionState struct { + HandshakeState State + CipherSuite CipherSuiteParams // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) + PeerCertificates []*x509.Certificate // certificate chain presented by remote peer + VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates + NextProto string // Selected ALPN proto + UsingPSK bool // Are we using PSK. + UsingEarlyData bool // Did we negotiate 0-RTT. +} + +// Conn implements the net.Conn interface, as with "crypto/tls" +// * Read, Write, and Close are provided locally +// * LocalAddr, RemoteAddr, and Set*Deadline are forwarded to the inner Conn +type Conn struct { + config *Config + conn net.Conn + isClient bool + + state stateConnected + hState HandshakeState + handshakeMutex sync.Mutex + handshakeAlert Alert + handshakeComplete bool + + readBuffer []byte + in, out *RecordLayer + hsCtx *HandshakeContext +} + +func NewConn(conn net.Conn, config *Config, isClient bool) *Conn { + c := &Conn{conn: conn, config: config, isClient: isClient, hsCtx: &HandshakeContext{}} + if !config.UseDTLS { + c.in = NewRecordLayerTLS(c.conn, directionRead) + c.out = NewRecordLayerTLS(c.conn, directionWrite) + c.hsCtx.hIn = NewHandshakeLayerTLS(c.hsCtx, c.in) + c.hsCtx.hOut = NewHandshakeLayerTLS(c.hsCtx, c.out) + } else { + c.in = NewRecordLayerDTLS(c.conn, directionRead) + c.out = NewRecordLayerDTLS(c.conn, directionWrite) + c.hsCtx.hIn = NewHandshakeLayerDTLS(c.hsCtx, c.in) + c.hsCtx.hOut = NewHandshakeLayerDTLS(c.hsCtx, c.out) + c.hsCtx.timeoutMS = initialTimeout + c.hsCtx.timers = newTimerSet() + c.hsCtx.waitingNextFlight = true + } + c.in.label = c.label() + c.out.label = c.label() + c.hsCtx.hIn.nonblocking = c.config.NonBlocking + return c +} + +// Read up +func (c *Conn) consumeRecord() error { + pt, err := c.in.ReadRecord() + if pt == nil { + logf(logTypeIO, "extendBuffer returns error %v", err) + return err + } + + switch pt.contentType { + case RecordTypeHandshake: + logf(logTypeHandshake, "Received post-handshake message") + // We do not support fragmentation of post-handshake handshake messages. + // TODO: Factor this more elegantly; coalesce with handshakeLayer.ReadMessage() + start := 0 + headerLen := handshakeHeaderLenTLS + if c.config.UseDTLS { + headerLen = handshakeHeaderLenDTLS + } + for start < len(pt.fragment) { + if len(pt.fragment[start:]) < headerLen { + return fmt.Errorf("Post-handshake handshake message too short for header") + } + + hm := &HandshakeMessage{} + hm.msgType = HandshakeType(pt.fragment[start]) + hmLen := (int(pt.fragment[start+1]) << 16) + (int(pt.fragment[start+2]) << 8) + int(pt.fragment[start+3]) + + if len(pt.fragment[start+headerLen:]) < hmLen { + return fmt.Errorf("Post-handshake handshake message too short for body") + } + hm.body = pt.fragment[start+headerLen : start+headerLen+hmLen] + + // XXX: If we want to support more advanced cases, e.g., post-handshake + // authentication, we'll need to allow transitions other than + // Connected -> Connected + state, actions, alert := c.state.ProcessMessage(hm) + if alert != AlertNoAlert { + logf(logTypeHandshake, "Error in state transition: %v", alert) + c.sendAlert(alert) + return io.EOF + } + + for _, action := range actions { + alert = c.takeAction(action) + if alert != AlertNoAlert { + logf(logTypeHandshake, "Error during handshake actions: %v", alert) + c.sendAlert(alert) + return io.EOF + } + } + + var connected bool + c.state, connected = state.(stateConnected) + if !connected { + logf(logTypeHandshake, "Disconnected after state transition: %v", alert) + c.sendAlert(alert) + return io.EOF + } + + start += headerLen + hmLen + } + case RecordTypeAlert: + logf(logTypeIO, "extended buffer (for alert): [%d] %x", len(c.readBuffer), c.readBuffer) + if len(pt.fragment) != 2 { + c.sendAlert(AlertUnexpectedMessage) + return io.EOF + } + if Alert(pt.fragment[1]) == AlertCloseNotify { + return io.EOF + } + + switch pt.fragment[0] { + case AlertLevelWarning: + // drop on the floor + case AlertLevelError: + return Alert(pt.fragment[1]) + default: + c.sendAlert(AlertUnexpectedMessage) + return io.EOF + } + + case RecordTypeAck: + if !c.hsCtx.hIn.datagram { + logf(logTypeHandshake, "Received ACK in TLS mode") + return AlertUnexpectedMessage + } + return c.hsCtx.processAck(pt.fragment) + + case RecordTypeApplicationData: + c.readBuffer = append(c.readBuffer, pt.fragment...) + logf(logTypeIO, "extended buffer: [%d] %x", len(c.readBuffer), c.readBuffer) + + } + + return err +} + +func readPartial(in *[]byte, buffer []byte) int { + logf(logTypeIO, "conn.Read input buffer now has len %d", len((*in))) + read := copy(buffer, *in) + *in = (*in)[read:] + + logf(logTypeVerbose, "Returning %v", string(buffer)) + return read +} + +// Read application data up to the size of buffer. Handshake and alert records +// are consumed by the Conn object directly. +func (c *Conn) Read(buffer []byte) (int, error) { + if _, connected := c.hState.(stateConnected); !connected { + // Clients can't call Read prior to handshake completion. + if c.isClient { + return 0, errors.New("Read called before the handshake completed") + } + + // Neither can servers that don't allow early data. + if !c.config.AllowEarlyData { + return 0, errors.New("Read called before the handshake completed") + } + + // If there's no early data, then return WouldBlock + if len(c.hsCtx.earlyData) == 0 { + return 0, AlertWouldBlock + } + + return readPartial(&c.hsCtx.earlyData, buffer), nil + } + + // The handshake is now connected. + logf(logTypeHandshake, "conn.Read with buffer = %d", len(buffer)) + if alert := c.Handshake(); alert != AlertNoAlert { + return 0, alert + } + + if len(buffer) == 0 { + return 0, nil + } + + // Run our timers. + if c.config.UseDTLS { + if err := c.hsCtx.timers.check(time.Now()); err != nil { + return 0, AlertInternalError + } + } + + // Lock the input channel + c.in.Lock() + defer c.in.Unlock() + for len(c.readBuffer) == 0 { + err := c.consumeRecord() + + // err can be nil if consumeRecord processed a non app-data + // record. + if err != nil { + if c.config.NonBlocking || err != AlertWouldBlock { + logf(logTypeIO, "conn.Read returns err=%v", err) + return 0, err + } + } + } + + return readPartial(&c.readBuffer, buffer), nil +} + +// Write application data +func (c *Conn) Write(buffer []byte) (int, error) { + // Lock the output channel + c.out.Lock() + defer c.out.Unlock() + + if !c.Writable() { + return 0, errors.New("Write called before the handshake completed (and early data not in use)") + } + + // Send full-size fragments + var start int + sent := 0 + for start = 0; len(buffer)-start >= maxFragmentLen; start += maxFragmentLen { + err := c.out.WriteRecord(&TLSPlaintext{ + contentType: RecordTypeApplicationData, + fragment: buffer[start : start+maxFragmentLen], + }) + + if err != nil { + return sent, err + } + sent += maxFragmentLen + } + + // Send a final partial fragment if necessary + if start < len(buffer) { + err := c.out.WriteRecord(&TLSPlaintext{ + contentType: RecordTypeApplicationData, + fragment: buffer[start:], + }) + + if err != nil { + return sent, err + } + sent += len(buffer[start:]) + } + return sent, nil +} + +// sendAlert sends a TLS alert message. +// c.out.Mutex <= L. +func (c *Conn) sendAlert(err Alert) error { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + var level int + switch err { + case AlertNoRenegotiation, AlertCloseNotify: + level = AlertLevelWarning + default: + level = AlertLevelError + } + + buf := []byte{byte(err), byte(level)} + c.out.WriteRecord(&TLSPlaintext{ + contentType: RecordTypeAlert, + fragment: buf, + }) + + // close_notify and end_of_early_data are not actually errors + if level == AlertLevelWarning { + return &net.OpError{Op: "local error", Err: err} + } + + return c.Close() +} + +// Close closes the connection. +func (c *Conn) Close() error { + // XXX crypto/tls has an interlock with Write here. Do we need that? + + return c.conn.Close() +} + +// LocalAddr returns the local network address. +func (c *Conn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +// RemoteAddr returns the remote network address. +func (c *Conn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +// SetDeadline sets the read and write deadlines associated with the connection. +// A zero value for t means Read and Write will not time out. +// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. +func (c *Conn) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} + +// SetReadDeadline sets the read deadline on the underlying connection. +// A zero value for t means Read will not time out. +func (c *Conn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +// SetWriteDeadline sets the write deadline on the underlying connection. +// A zero value for t means Write will not time out. +// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. +func (c *Conn) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +} + +func (c *Conn) takeAction(actionGeneric HandshakeAction) Alert { + label := "[server]" + if c.isClient { + label = "[client]" + } + + switch action := actionGeneric.(type) { + case QueueHandshakeMessage: + logf(logTypeHandshake, "%s queuing handshake message type=%v", label, action.Message.msgType) + err := c.hsCtx.hOut.QueueMessage(action.Message) + if err != nil { + logf(logTypeHandshake, "%s Error writing handshake message: %v", label, err) + return AlertInternalError + } + + case SendQueuedHandshake: + _, err := c.hsCtx.hOut.SendQueuedMessages() + if err != nil { + logf(logTypeHandshake, "%s Error writing handshake message: %v", label, err) + return AlertInternalError + } + if c.config.UseDTLS { + c.hsCtx.timers.start(retransmitTimerLabel, + c.hsCtx.handshakeRetransmit, + c.hsCtx.timeoutMS) + } + case RekeyIn: + logf(logTypeHandshake, "%s Rekeying in to %s: %+v", label, action.epoch.label(), action.KeySet) + // Check that we don't have an input data in the handshake frame parser. + if len(c.hsCtx.hIn.frame.remainder) > 0 { + logf(logTypeHandshake, "%s Rekey with data still in handshake buffers", label) + return AlertDecodeError + } + err := c.in.Rekey(action.epoch, action.KeySet.cipher, action.KeySet.key, action.KeySet.iv) + if err != nil { + logf(logTypeHandshake, "%s Unable to rekey inbound: %v", label, err) + return AlertInternalError + } + + case RekeyOut: + logf(logTypeHandshake, "%s Rekeying out to %s: %+v", label, action.epoch.label(), action.KeySet) + err := c.out.Rekey(action.epoch, action.KeySet.cipher, action.KeySet.key, action.KeySet.iv) + if err != nil { + logf(logTypeHandshake, "%s Unable to rekey outbound: %v", label, err) + return AlertInternalError + } + + case ResetOut: + logf(logTypeHandshake, "%s Rekeying out to %s seq=%v", label, EpochClear, action.seq) + c.out.ResetClear(action.seq) + + case StorePSK: + logf(logTypeHandshake, "%s Storing new session ticket with identity [%x]", label, action.PSK.Identity) + if c.isClient { + // Clients look up PSKs based on server name + c.config.PSKs.Put(c.config.ServerName, action.PSK) + } else { + // Servers look them up based on the identity in the extension + c.config.PSKs.Put(hex.EncodeToString(action.PSK.Identity), action.PSK) + } + + default: + logf(logTypeHandshake, "%s Unknown action type", label) + assert(false) + return AlertInternalError + } + + return AlertNoAlert +} + +func (c *Conn) HandshakeSetup() Alert { + var state HandshakeState + var actions []HandshakeAction + var alert Alert + + if err := c.config.Init(c.isClient); err != nil { + logf(logTypeHandshake, "Error initializing config: %v", err) + return AlertInternalError + } + + opts := ConnectionOptions{ + ServerName: c.config.ServerName, + NextProtos: c.config.NextProtos, + } + + if c.isClient { + state, actions, alert = clientStateStart{Config: c.config, Opts: opts, hsCtx: c.hsCtx}.Next(nil) + if alert != AlertNoAlert { + logf(logTypeHandshake, "Error initializing client state: %v", alert) + return alert + } + + for _, action := range actions { + alert = c.takeAction(action) + if alert != AlertNoAlert { + logf(logTypeHandshake, "Error during handshake actions: %v", alert) + return alert + } + } + } else { + if c.config.RequireCookie && c.config.CookieProtector == nil { + logf(logTypeHandshake, "RequireCookie set, but no CookieProtector provided. Using default cookie protector. Stateless Retry not possible.") + if c.config.NonBlocking { + logf(logTypeHandshake, "Not possible in non-blocking mode.") + return AlertInternalError + } + var err error + c.config.CookieProtector, err = NewDefaultCookieProtector() + if err != nil { + logf(logTypeHandshake, "Error initializing cookie source: %v", alert) + return AlertInternalError + } + } + state = serverStateStart{Config: c.config, conn: c, hsCtx: c.hsCtx} + } + + c.hState = state + return AlertNoAlert +} + +type handshakeMessageReader interface { + ReadMessage() (*HandshakeMessage, Alert) +} + +type handshakeMessageReaderImpl struct { + hsCtx *HandshakeContext +} + +var _ handshakeMessageReader = &handshakeMessageReaderImpl{} + +func (r *handshakeMessageReaderImpl) ReadMessage() (*HandshakeMessage, Alert) { + var hm *HandshakeMessage + var err error + for { + hm, err = r.hsCtx.hIn.ReadMessage() + if err == AlertWouldBlock { + return nil, AlertWouldBlock + } + if err != nil { + logf(logTypeHandshake, "Error reading message: %v", err) + return nil, AlertCloseNotify + } + if hm != nil { + break + } + } + + return hm, AlertNoAlert +} + +// Handshake causes a TLS handshake on the connection. The `isClient` member +// determines whether a client or server handshake is performed. If a +// handshake has already been performed, then its result will be returned. +func (c *Conn) Handshake() Alert { + label := "[server]" + if c.isClient { + label = "[client]" + } + + // TODO Lock handshakeMutex + // TODO Remove CloseNotify hack + if c.handshakeAlert != AlertNoAlert && c.handshakeAlert != AlertCloseNotify { + logf(logTypeHandshake, "Pre-existing handshake error: %v", c.handshakeAlert) + return c.handshakeAlert + } + if c.handshakeComplete { + return AlertNoAlert + } + + if c.hState == nil { + logf(logTypeHandshake, "%s First time through handshake (or after stateless retry), setting up", label) + alert := c.HandshakeSetup() + if alert != AlertNoAlert || (c.isClient && c.config.NonBlocking) { + return alert + } + } + + logf(logTypeHandshake, "(Re-)entering handshake, state=%v", c.hState) + state := c.hState + _, connected := state.(stateConnected) + + hmr := &handshakeMessageReaderImpl{hsCtx: c.hsCtx} + for !connected { + var alert Alert + var actions []HandshakeAction + + // Advance the state machine + state, actions, alert = state.Next(hmr) + if alert == AlertWouldBlock { + logf(logTypeHandshake, "%s Would block reading message: %s", label, alert) + // If we blocked, then run our timers to see if any have expired. + if c.hsCtx.hIn.datagram { + if err := c.hsCtx.timers.check(time.Now()); err != nil { + return AlertInternalError + } + } + return AlertWouldBlock + } + if alert == AlertCloseNotify { + logf(logTypeHandshake, "%s Error reading message: %s", label, alert) + c.sendAlert(AlertCloseNotify) + return AlertCloseNotify + } + if alert != AlertNoAlert && alert != AlertStatelessRetry { + logf(logTypeHandshake, "Error in state transition: %v", alert) + return alert + } + + for index, action := range actions { + logf(logTypeHandshake, "%s taking next action (%d)", label, index) + if alert := c.takeAction(action); alert != AlertNoAlert { + logf(logTypeHandshake, "Error during handshake actions: %v", alert) + c.sendAlert(alert) + return alert + } + } + + c.hState = state + logf(logTypeHandshake, "state is now %s", c.GetHsState()) + _, connected = state.(stateConnected) + if connected { + c.state = state.(stateConnected) + c.handshakeComplete = true + + if !c.isClient { + // Send NewSessionTicket if configured to + if c.config.SendSessionTickets { + actions, alert := c.state.NewSessionTicket( + c.config.TicketLen, + c.config.TicketLifetime, + c.config.EarlyDataLifetime) + + for _, action := range actions { + alert = c.takeAction(action) + if alert != AlertNoAlert { + logf(logTypeHandshake, "Error during handshake actions: %v", alert) + c.sendAlert(alert) + return alert + } + } + } + + // If there is early data, move it into the main buffer + if c.hsCtx.earlyData != nil { + c.readBuffer = c.hsCtx.earlyData + c.hsCtx.earlyData = nil + } + + } else { + assert(c.hsCtx.earlyData == nil) + } + } + + if c.config.NonBlocking { + if alert == AlertStatelessRetry { + return AlertStatelessRetry + } + return AlertNoAlert + } + } + + return AlertNoAlert +} + +func (c *Conn) SendKeyUpdate(requestUpdate bool) error { + if !c.handshakeComplete { + return fmt.Errorf("Cannot update keys until after handshake") + } + + request := KeyUpdateNotRequested + if requestUpdate { + request = KeyUpdateRequested + } + + // Create the key update and update state + actions, alert := c.state.KeyUpdate(request) + if alert != AlertNoAlert { + c.sendAlert(alert) + return fmt.Errorf("Alert while generating key update: %v", alert) + } + + // Take actions (send key update and rekey) + for _, action := range actions { + alert = c.takeAction(action) + if alert != AlertNoAlert { + c.sendAlert(alert) + return fmt.Errorf("Alert during key update actions: %v", alert) + } + } + + return nil +} + +func (c *Conn) GetHsState() State { + if c.hState == nil { + return StateInit + } + return c.hState.State() +} + +func (c *Conn) ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) { + _, connected := c.hState.(stateConnected) + if !connected { + return nil, fmt.Errorf("Cannot compute exporter when state is not connected") + } + + if c.state.exporterSecret == nil { + return nil, fmt.Errorf("Internal error: no exporter secret") + } + + h0 := c.state.cryptoParams.Hash.New().Sum(nil) + tmpSecret := deriveSecret(c.state.cryptoParams, c.state.exporterSecret, label, h0) + + hc := c.state.cryptoParams.Hash.New().Sum(context) + return HkdfExpandLabel(c.state.cryptoParams.Hash, tmpSecret, "exporter", hc, keyLength), nil +} + +func (c *Conn) ConnectionState() ConnectionState { + state := ConnectionState{ + HandshakeState: c.GetHsState(), + } + + if c.handshakeComplete { + state.CipherSuite = cipherSuiteMap[c.state.Params.CipherSuite] + state.NextProto = c.state.Params.NextProto + state.VerifiedChains = c.state.verifiedChains + state.PeerCertificates = c.state.peerCertificates + state.UsingPSK = c.state.Params.UsingPSK + state.UsingEarlyData = c.state.Params.UsingEarlyData + } + + return state +} + +func (c *Conn) Writable() bool { + // If we're connected, we're writable. + if _, connected := c.hState.(stateConnected); connected { + return true + } + + // If we're a client in 0-RTT, then we're writable. + if c.isClient && c.out.cipher.epoch == EpochEarlyData { + return true + } + + return false +} + +func (c *Conn) label() string { + if c.isClient { + return "client" + } + return "server" +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/cookie-protector.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/cookie-protector.go new file mode 100644 index 00000000..73dd80ba --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/cookie-protector.go @@ -0,0 +1,86 @@ +package mint + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "fmt" + "io" + + "golang.org/x/crypto/hkdf" +) + +// CookieProtector is used to create and verify a cookie +type CookieProtector interface { + // NewToken creates a new token + NewToken([]byte) ([]byte, error) + // DecodeToken decodes a token + DecodeToken([]byte) ([]byte, error) +} + +const cookieSecretSize = 32 +const cookieNonceSize = 32 + +// The DefaultCookieProtector is a simple implementation for the CookieProtector. +type DefaultCookieProtector struct { + secret []byte +} + +var _ CookieProtector = &DefaultCookieProtector{} + +// NewDefaultCookieProtector creates a source for source address tokens +func NewDefaultCookieProtector() (CookieProtector, error) { + secret := make([]byte, cookieSecretSize) + if _, err := rand.Read(secret); err != nil { + return nil, err + } + return &DefaultCookieProtector{secret: secret}, nil +} + +// NewToken encodes data into a new token. +func (s *DefaultCookieProtector) NewToken(data []byte) ([]byte, error) { + nonce := make([]byte, cookieNonceSize) + if _, err := rand.Read(nonce); err != nil { + return nil, err + } + aead, aeadNonce, err := s.createAEAD(nonce) + if err != nil { + return nil, err + } + return append(nonce, aead.Seal(nil, aeadNonce, data, nil)...), nil +} + +// DecodeToken decodes a token. +func (s *DefaultCookieProtector) DecodeToken(p []byte) ([]byte, error) { + if len(p) < cookieNonceSize { + return nil, fmt.Errorf("Token too short: %d", len(p)) + } + nonce := p[:cookieNonceSize] + aead, aeadNonce, err := s.createAEAD(nonce) + if err != nil { + return nil, err + } + return aead.Open(nil, aeadNonce, p[cookieNonceSize:], nil) +} + +func (s *DefaultCookieProtector) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) { + h := hkdf.New(sha256.New, s.secret, nonce, []byte("mint cookie source")) + key := make([]byte, 32) // use a 32 byte key, in order to select AES-256 + if _, err := io.ReadFull(h, key); err != nil { + return nil, nil, err + } + aeadNonce := make([]byte, 12) + if _, err := io.ReadFull(h, aeadNonce); err != nil { + return nil, nil, err + } + c, err := aes.NewCipher(key) + if err != nil { + return nil, nil, err + } + aead, err := cipher.NewGCM(c) + if err != nil { + return nil, nil, err + } + return aead, aeadNonce, nil +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/crypto.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/crypto.go new file mode 100644 index 00000000..ef7397d8 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/crypto.go @@ -0,0 +1,667 @@ +package mint + +import ( + "bytes" + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/hmac" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "fmt" + "math/big" + "time" + + "golang.org/x/crypto/curve25519" + + // Blank includes to ensure hash support + _ "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" +) + +var prng = rand.Reader + +type aeadFactory func(key []byte) (cipher.AEAD, error) + +type CipherSuiteParams struct { + Suite CipherSuite + Cipher aeadFactory // Cipher factory + Hash crypto.Hash // Hash function + KeyLen int // Key length in octets + IvLen int // IV length in octets +} + +type signatureAlgorithm uint8 + +const ( + signatureAlgorithmUnknown = iota + signatureAlgorithmRSA_PKCS1 + signatureAlgorithmRSA_PSS + signatureAlgorithmECDSA +) + +var ( + hashMap = map[SignatureScheme]crypto.Hash{ + RSA_PKCS1_SHA1: crypto.SHA1, + RSA_PKCS1_SHA256: crypto.SHA256, + RSA_PKCS1_SHA384: crypto.SHA384, + RSA_PKCS1_SHA512: crypto.SHA512, + ECDSA_P256_SHA256: crypto.SHA256, + ECDSA_P384_SHA384: crypto.SHA384, + ECDSA_P521_SHA512: crypto.SHA512, + RSA_PSS_SHA256: crypto.SHA256, + RSA_PSS_SHA384: crypto.SHA384, + RSA_PSS_SHA512: crypto.SHA512, + } + + sigMap = map[SignatureScheme]signatureAlgorithm{ + RSA_PKCS1_SHA1: signatureAlgorithmRSA_PKCS1, + RSA_PKCS1_SHA256: signatureAlgorithmRSA_PKCS1, + RSA_PKCS1_SHA384: signatureAlgorithmRSA_PKCS1, + RSA_PKCS1_SHA512: signatureAlgorithmRSA_PKCS1, + ECDSA_P256_SHA256: signatureAlgorithmECDSA, + ECDSA_P384_SHA384: signatureAlgorithmECDSA, + ECDSA_P521_SHA512: signatureAlgorithmECDSA, + RSA_PSS_SHA256: signatureAlgorithmRSA_PSS, + RSA_PSS_SHA384: signatureAlgorithmRSA_PSS, + RSA_PSS_SHA512: signatureAlgorithmRSA_PSS, + } + + curveMap = map[SignatureScheme]NamedGroup{ + ECDSA_P256_SHA256: P256, + ECDSA_P384_SHA384: P384, + ECDSA_P521_SHA512: P521, + } + + newAESGCM = func(key []byte) (cipher.AEAD, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + // TLS always uses 12-byte nonces + return cipher.NewGCMWithNonceSize(block, 12) + } + + cipherSuiteMap = map[CipherSuite]CipherSuiteParams{ + TLS_AES_128_GCM_SHA256: { + Suite: TLS_AES_128_GCM_SHA256, + Cipher: newAESGCM, + Hash: crypto.SHA256, + KeyLen: 16, + IvLen: 12, + }, + TLS_AES_256_GCM_SHA384: { + Suite: TLS_AES_256_GCM_SHA384, + Cipher: newAESGCM, + Hash: crypto.SHA384, + KeyLen: 32, + IvLen: 12, + }, + } + + x509AlgMap = map[SignatureScheme]x509.SignatureAlgorithm{ + RSA_PKCS1_SHA1: x509.SHA1WithRSA, + RSA_PKCS1_SHA256: x509.SHA256WithRSA, + RSA_PKCS1_SHA384: x509.SHA384WithRSA, + RSA_PKCS1_SHA512: x509.SHA512WithRSA, + ECDSA_P256_SHA256: x509.ECDSAWithSHA256, + ECDSA_P384_SHA384: x509.ECDSAWithSHA384, + ECDSA_P521_SHA512: x509.ECDSAWithSHA512, + } + + defaultRSAKeySize = 2048 +) + +func curveFromNamedGroup(group NamedGroup) (crv elliptic.Curve) { + switch group { + case P256: + crv = elliptic.P256() + case P384: + crv = elliptic.P384() + case P521: + crv = elliptic.P521() + } + return +} + +func namedGroupFromECDSAKey(key *ecdsa.PublicKey) (g NamedGroup) { + switch key.Curve.Params().Name { + case elliptic.P256().Params().Name: + g = P256 + case elliptic.P384().Params().Name: + g = P384 + case elliptic.P521().Params().Name: + g = P521 + } + return +} + +func keyExchangeSizeFromNamedGroup(group NamedGroup) (size int) { + size = 0 + switch group { + case X25519: + size = 32 + case P256: + size = 65 + case P384: + size = 97 + case P521: + size = 133 + case FFDHE2048: + size = 256 + case FFDHE3072: + size = 384 + case FFDHE4096: + size = 512 + case FFDHE6144: + size = 768 + case FFDHE8192: + size = 1024 + } + return +} + +func primeFromNamedGroup(group NamedGroup) (p *big.Int) { + switch group { + case FFDHE2048: + p = finiteFieldPrime2048 + case FFDHE3072: + p = finiteFieldPrime3072 + case FFDHE4096: + p = finiteFieldPrime4096 + case FFDHE6144: + p = finiteFieldPrime6144 + case FFDHE8192: + p = finiteFieldPrime8192 + } + return +} + +func schemeValidForKey(alg SignatureScheme, key crypto.Signer) bool { + sigType := sigMap[alg] + switch key.(type) { + case *rsa.PrivateKey: + return sigType == signatureAlgorithmRSA_PKCS1 || sigType == signatureAlgorithmRSA_PSS + case *ecdsa.PrivateKey: + return sigType == signatureAlgorithmECDSA + default: + return false + } +} + +func ffdheKeyShareFromPrime(p *big.Int) (priv, pub *big.Int, err error) { + primeLen := len(p.Bytes()) + for { + // g = 2 for all ffdhe groups + priv, err = rand.Int(prng, p) + if err != nil { + return + } + + pub = big.NewInt(0) + pub.Exp(big.NewInt(2), priv, p) + + if len(pub.Bytes()) == primeLen { + return + } + } +} + +func newKeyShare(group NamedGroup) (pub []byte, priv []byte, err error) { + switch group { + case P256, P384, P521: + var x, y *big.Int + crv := curveFromNamedGroup(group) + priv, x, y, err = elliptic.GenerateKey(crv, prng) + if err != nil { + return + } + + pub = elliptic.Marshal(crv, x, y) + return + + case FFDHE2048, FFDHE3072, FFDHE4096, FFDHE6144, FFDHE8192: + p := primeFromNamedGroup(group) + x, X, err2 := ffdheKeyShareFromPrime(p) + if err2 != nil { + err = err2 + return + } + + priv = x.Bytes() + pubBytes := X.Bytes() + + numBytes := keyExchangeSizeFromNamedGroup(group) + + pub = make([]byte, numBytes) + copy(pub[numBytes-len(pubBytes):], pubBytes) + + return + + case X25519: + var private, public [32]byte + _, err = prng.Read(private[:]) + if err != nil { + return + } + + curve25519.ScalarBaseMult(&public, &private) + priv = private[:] + pub = public[:] + return + + default: + return nil, nil, fmt.Errorf("tls.newkeyshare: Unsupported group %v", group) + } +} + +func keyAgreement(group NamedGroup, pub []byte, priv []byte) ([]byte, error) { + switch group { + case P256, P384, P521: + if len(pub) != keyExchangeSizeFromNamedGroup(group) { + return nil, fmt.Errorf("tls.keyagreement: Wrong public key size") + } + + crv := curveFromNamedGroup(group) + pubX, pubY := elliptic.Unmarshal(crv, pub) + x, _ := crv.Params().ScalarMult(pubX, pubY, priv) + xBytes := x.Bytes() + + numBytes := len(crv.Params().P.Bytes()) + + ret := make([]byte, numBytes) + copy(ret[numBytes-len(xBytes):], xBytes) + + return ret, nil + + case FFDHE2048, FFDHE3072, FFDHE4096, FFDHE6144, FFDHE8192: + numBytes := keyExchangeSizeFromNamedGroup(group) + if len(pub) != numBytes { + return nil, fmt.Errorf("tls.keyagreement: Wrong public key size") + } + p := primeFromNamedGroup(group) + x := big.NewInt(0).SetBytes(priv) + Y := big.NewInt(0).SetBytes(pub) + ZBytes := big.NewInt(0).Exp(Y, x, p).Bytes() + + ret := make([]byte, numBytes) + copy(ret[numBytes-len(ZBytes):], ZBytes) + + return ret, nil + + case X25519: + if len(pub) != keyExchangeSizeFromNamedGroup(group) { + return nil, fmt.Errorf("tls.keyagreement: Wrong public key size") + } + + var private, public, ret [32]byte + copy(private[:], priv) + copy(public[:], pub) + curve25519.ScalarMult(&ret, &private, &public) + + return ret[:], nil + + default: + return nil, fmt.Errorf("tls.keyagreement: Unsupported group %v", group) + } +} + +func newSigningKey(sig SignatureScheme) (crypto.Signer, error) { + switch sig { + case RSA_PKCS1_SHA1, RSA_PKCS1_SHA256, + RSA_PKCS1_SHA384, RSA_PKCS1_SHA512, + RSA_PSS_SHA256, RSA_PSS_SHA384, + RSA_PSS_SHA512: + return rsa.GenerateKey(prng, defaultRSAKeySize) + case ECDSA_P256_SHA256: + return ecdsa.GenerateKey(elliptic.P256(), prng) + case ECDSA_P384_SHA384: + return ecdsa.GenerateKey(elliptic.P384(), prng) + case ECDSA_P521_SHA512: + return ecdsa.GenerateKey(elliptic.P521(), prng) + default: + return nil, fmt.Errorf("tls.newsigningkey: Unsupported signature algorithm [%04x]", sig) + } +} + +// XXX(rlb): Copied from crypto/x509 +type ecdsaSignature struct { + R, S *big.Int +} + +func sign(alg SignatureScheme, privateKey crypto.Signer, sigInput []byte) ([]byte, error) { + var opts crypto.SignerOpts + + hash := hashMap[alg] + if hash == crypto.SHA1 { + return nil, fmt.Errorf("tls.crypt.sign: Use of SHA-1 is forbidden") + } + + sigType := sigMap[alg] + var realInput []byte + switch key := privateKey.(type) { + case *rsa.PrivateKey: + switch { + case allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1: + logf(logTypeCrypto, "signing with PKCS1, hashSize=[%d]", hash.Size()) + opts = hash + case !allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1: + fallthrough + case sigType == signatureAlgorithmRSA_PSS: + logf(logTypeCrypto, "signing with PSS, hashSize=[%d]", hash.Size()) + opts = &rsa.PSSOptions{SaltLength: hash.Size(), Hash: hash} + default: + return nil, fmt.Errorf("tls.crypto.sign: Unsupported algorithm for RSA key") + } + + h := hash.New() + h.Write(sigInput) + realInput = h.Sum(nil) + case *ecdsa.PrivateKey: + if sigType != signatureAlgorithmECDSA { + return nil, fmt.Errorf("tls.crypto.sign: Unsupported algorithm for ECDSA key") + } + + algGroup := curveMap[alg] + keyGroup := namedGroupFromECDSAKey(key.Public().(*ecdsa.PublicKey)) + if algGroup != keyGroup { + return nil, fmt.Errorf("tls.crypto.sign: Unsupported hash/curve combination") + } + + h := hash.New() + h.Write(sigInput) + realInput = h.Sum(nil) + default: + return nil, fmt.Errorf("tls.crypto.sign: Unsupported private key type") + } + + sig, err := privateKey.Sign(prng, realInput, opts) + logf(logTypeCrypto, "signature: %x", sig) + return sig, err +} + +func verify(alg SignatureScheme, publicKey crypto.PublicKey, sigInput []byte, sig []byte) error { + hash := hashMap[alg] + + if hash == crypto.SHA1 { + return fmt.Errorf("tls.crypt.sign: Use of SHA-1 is forbidden") + } + + sigType := sigMap[alg] + switch pub := publicKey.(type) { + case *rsa.PublicKey: + switch { + case allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1: + logf(logTypeCrypto, "verifying with PKCS1, hashSize=[%d]", hash.Size()) + + h := hash.New() + h.Write(sigInput) + realInput := h.Sum(nil) + return rsa.VerifyPKCS1v15(pub, hash, realInput, sig) + case !allowPKCS1 && sigType == signatureAlgorithmRSA_PKCS1: + fallthrough + case sigType == signatureAlgorithmRSA_PSS: + logf(logTypeCrypto, "verifying with PSS, hashSize=[%d]", hash.Size()) + opts := &rsa.PSSOptions{SaltLength: hash.Size(), Hash: hash} + + h := hash.New() + h.Write(sigInput) + realInput := h.Sum(nil) + return rsa.VerifyPSS(pub, hash, realInput, sig, opts) + default: + return fmt.Errorf("tls.verify: Unsupported algorithm for RSA key") + } + + case *ecdsa.PublicKey: + if sigType != signatureAlgorithmECDSA { + return fmt.Errorf("tls.verify: Unsupported algorithm for ECDSA key") + } + + if curveMap[alg] != namedGroupFromECDSAKey(pub) { + return fmt.Errorf("tls.verify: Unsupported curve for ECDSA key") + } + + ecdsaSig := new(ecdsaSignature) + if rest, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { + return err + } else if len(rest) != 0 { + return fmt.Errorf("tls.verify: trailing data after ECDSA signature") + } + if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { + return fmt.Errorf("tls.verify: ECDSA signature contained zero or negative values") + } + + h := hash.New() + h.Write(sigInput) + realInput := h.Sum(nil) + if !ecdsa.Verify(pub, realInput, ecdsaSig.R, ecdsaSig.S) { + return fmt.Errorf("tls.verify: ECDSA verification failure") + } + return nil + default: + return fmt.Errorf("tls.verify: Unsupported key type") + } +} + +// 0 +// | +// v +// PSK -> HKDF-Extract = Early Secret +// | +// +-----> Derive-Secret(., +// | "ext binder" | +// | "res binder", +// | "") +// | = binder_key +// | +// +-----> Derive-Secret(., "c e traffic", +// | ClientHello) +// | = client_early_traffic_secret +// | +// +-----> Derive-Secret(., "e exp master", +// | ClientHello) +// | = early_exporter_master_secret +// v +// Derive-Secret(., "derived", "") +// | +// v +// (EC)DHE -> HKDF-Extract = Handshake Secret +// | +// +-----> Derive-Secret(., "c hs traffic", +// | ClientHello...ServerHello) +// | = client_handshake_traffic_secret +// | +// +-----> Derive-Secret(., "s hs traffic", +// | ClientHello...ServerHello) +// | = server_handshake_traffic_secret +// v +// Derive-Secret(., "derived", "") +// | +// v +// 0 -> HKDF-Extract = Master Secret +// | +// +-----> Derive-Secret(., "c ap traffic", +// | ClientHello...server Finished) +// | = client_application_traffic_secret_0 +// | +// +-----> Derive-Secret(., "s ap traffic", +// | ClientHello...server Finished) +// | = server_application_traffic_secret_0 +// | +// +-----> Derive-Secret(., "exp master", +// | ClientHello...server Finished) +// | = exporter_master_secret +// | +// +-----> Derive-Secret(., "res master", +// ClientHello...client Finished) +// = resumption_master_secret + +// From RFC 5869 +// PRK = HMAC-Hash(salt, IKM) +func HkdfExtract(hash crypto.Hash, saltIn, input []byte) []byte { + salt := saltIn + + // if [salt is] not provided, it is set to a string of HashLen zeros + if salt == nil { + salt = bytes.Repeat([]byte{0}, hash.Size()) + } + + h := hmac.New(hash.New, salt) + h.Write(input) + out := h.Sum(nil) + + logf(logTypeCrypto, "HKDF Extract:\n") + logf(logTypeCrypto, "Salt [%d]: %x\n", len(salt), salt) + logf(logTypeCrypto, "Input [%d]: %x\n", len(input), input) + logf(logTypeCrypto, "Output [%d]: %x\n", len(out), out) + + return out +} + +const ( + labelExternalBinder = "ext binder" + labelResumptionBinder = "res binder" + labelEarlyTrafficSecret = "c e traffic" + labelEarlyExporterSecret = "e exp master" + labelClientHandshakeTrafficSecret = "c hs traffic" + labelServerHandshakeTrafficSecret = "s hs traffic" + labelClientApplicationTrafficSecret = "c ap traffic" + labelServerApplicationTrafficSecret = "s ap traffic" + labelExporterSecret = "exp master" + labelResumptionSecret = "res master" + labelDerived = "derived" + labelFinished = "finished" + labelResumption = "resumption" +) + +// struct HkdfLabel { +// uint16 length; +// opaque label<9..255>; +// opaque hash_value<0..255>; +// }; +func hkdfEncodeLabel(labelIn string, hashValue []byte, outLen int) []byte { + label := "tls13 " + labelIn + + labelLen := len(label) + hashLen := len(hashValue) + hkdfLabel := make([]byte, 2+1+labelLen+1+hashLen) + hkdfLabel[0] = byte(outLen >> 8) + hkdfLabel[1] = byte(outLen) + hkdfLabel[2] = byte(labelLen) + copy(hkdfLabel[3:3+labelLen], []byte(label)) + hkdfLabel[3+labelLen] = byte(hashLen) + copy(hkdfLabel[3+labelLen+1:], hashValue) + + return hkdfLabel +} + +func HkdfExpand(hash crypto.Hash, prk, info []byte, outLen int) []byte { + out := []byte{} + T := []byte{} + i := byte(1) + for len(out) < outLen { + block := append(T, info...) + block = append(block, i) + + h := hmac.New(hash.New, prk) + h.Write(block) + + T = h.Sum(nil) + out = append(out, T...) + i++ + } + return out[:outLen] +} + +func HkdfExpandLabel(hash crypto.Hash, secret []byte, label string, hashValue []byte, outLen int) []byte { + info := hkdfEncodeLabel(label, hashValue, outLen) + derived := HkdfExpand(hash, secret, info, outLen) + + logf(logTypeCrypto, "HKDF Expand: label=[tls13 ] + '%s',requested length=%d\n", label, outLen) + logf(logTypeCrypto, "PRK [%d]: %x\n", len(secret), secret) + logf(logTypeCrypto, "Hash [%d]: %x\n", len(hashValue), hashValue) + logf(logTypeCrypto, "Info [%d]: %x\n", len(info), info) + logf(logTypeCrypto, "Derived key [%d]: %x\n", len(derived), derived) + + return derived +} + +func deriveSecret(params CipherSuiteParams, secret []byte, label string, messageHash []byte) []byte { + return HkdfExpandLabel(params.Hash, secret, label, messageHash, params.Hash.Size()) +} + +func computeFinishedData(params CipherSuiteParams, baseKey []byte, input []byte) []byte { + macKey := HkdfExpandLabel(params.Hash, baseKey, labelFinished, []byte{}, params.Hash.Size()) + mac := hmac.New(params.Hash.New, macKey) + mac.Write(input) + return mac.Sum(nil) +} + +type keySet struct { + cipher aeadFactory + key []byte + iv []byte +} + +func makeTrafficKeys(params CipherSuiteParams, secret []byte) keySet { + logf(logTypeCrypto, "making traffic keys: secret=%x", secret) + return keySet{ + cipher: params.Cipher, + key: HkdfExpandLabel(params.Hash, secret, "key", []byte{}, params.KeyLen), + iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen), + } +} + +func MakeNewSelfSignedCert(name string, alg SignatureScheme) (crypto.Signer, *x509.Certificate, error) { + priv, err := newSigningKey(alg) + if err != nil { + return nil, nil, err + } + + cert, err := newSelfSigned(name, alg, priv) + if err != nil { + return nil, nil, err + } + return priv, cert, nil +} + +func newSelfSigned(name string, alg SignatureScheme, priv crypto.Signer) (*x509.Certificate, error) { + sigAlg, ok := x509AlgMap[alg] + if !ok { + return nil, fmt.Errorf("tls.selfsigned: Unknown signature algorithm [%04x]", alg) + } + if len(name) == 0 { + return nil, fmt.Errorf("tls.selfsigned: No name provided") + } + + serial, err := rand.Int(rand.Reader, big.NewInt(0xA0A0A0A0)) + if err != nil { + return nil, err + } + + template := &x509.Certificate{ + SerialNumber: serial, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(0, 0, 1), + SignatureAlgorithm: sigAlg, + Subject: pkix.Name{CommonName: name}, + DNSNames: []string{name}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageKeyEncipherment, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + } + der, err := x509.CreateCertificate(prng, template, template, priv.Public(), priv) + if err != nil { + return nil, err + } + + // It is safe to ignore the error here because we're parsing known-good data + cert, _ := x509.ParseCertificate(der) + return cert, nil +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/dtls.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/dtls.go new file mode 100644 index 00000000..aa914e3e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/dtls.go @@ -0,0 +1,222 @@ +package mint + +import ( + "fmt" + "github.com/bifurcation/mint/syntax" + "time" +) + +const ( + initialMtu = 1200 + initialTimeout = 100 +) + +// labels for timers +const ( + retransmitTimerLabel = "handshake retransmit" + ackTimerLabel = "ack timer" +) + +type SentHandshakeFragment struct { + seq uint32 + offset int + fragLength int + record uint64 + acked bool +} + +type DtlsAck struct { + RecordNumbers []uint64 `tls:"head=2"` +} + +func wireVersion(h *HandshakeLayer) uint16 { + if h.datagram { + return dtls12WireVersion + } + return tls12Version +} + +func dtlsConvertVersion(version uint16) uint16 { + if version == tls12Version { + return dtls12WireVersion + } + if version == tls10Version { + return 0xfeff + } + panic(fmt.Sprintf("Internal error, unexpected version=%d", version)) +} + +// TODO(ekr@rtfm.com): Move these to state-machine.go +func (h *HandshakeContext) handshakeRetransmit() error { + if _, err := h.hOut.SendQueuedMessages(); err != nil { + return err + } + + h.timers.start(retransmitTimerLabel, + h.handshakeRetransmit, + h.timeoutMS) + + // TODO(ekr@rtfm.com): Back off timer + return nil +} + +func (h *HandshakeContext) sendAck() error { + toack := h.hIn.recvdRecords + + count := (initialMtu - 2) / 8 // TODO(ekr@rtfm.com): Current MTU + if len(toack) > count { + toack = toack[:count] + } + logf(logTypeHandshake, "Sending ACK: [%x]", toack) + + ack := &DtlsAck{toack} + body, err := syntax.Marshal(&ack) + if err != nil { + return err + } + err = h.hOut.conn.WriteRecord(&TLSPlaintext{ + contentType: RecordTypeAck, + fragment: body, + }) + if err != nil { + return err + } + return nil +} + +func (h *HandshakeContext) processAck(data []byte) error { + // Cancel the retransmit timer because we will be resending + // and possibly re-arming later. + h.timers.cancel(retransmitTimerLabel) + + ack := &DtlsAck{} + read, err := syntax.Unmarshal(data, &ack) + if err != nil { + return err + } + if len(data) != read { + return fmt.Errorf("Invalid encoding: Extra data not consumed") + } + logf(logTypeHandshake, "ACK: [%x]", ack.RecordNumbers) + + for _, r := range ack.RecordNumbers { + for _, m := range h.sentFragments { + if r == m.record { + logf(logTypeHandshake, "Marking %v %v(%v) as acked", + m.seq, m.offset, m.fragLength) + m.acked = true + } + } + } + + count, err := h.hOut.SendQueuedMessages() + if err != nil { + return err + } + + if count == 0 { + logf(logTypeHandshake, "All messages ACKed") + h.hOut.ClearQueuedMessages() + return nil + } + + // Reset the timer + h.timers.start(retransmitTimerLabel, + h.handshakeRetransmit, + h.timeoutMS) + + return nil +} + +func (c *Conn) GetDTLSTimeout() (bool, time.Duration) { + return c.hsCtx.timers.remaining() +} + +func (h *HandshakeContext) receivedHandshakeMessage() { + logf(logTypeHandshake, "%p Received handshake, waiting for start of flight = %v", h, h.waitingNextFlight) + // This just enables tests. + if h.hIn == nil { + return + } + + if !h.hIn.datagram { + return + } + + if h.waitingNextFlight { + logf(logTypeHandshake, "Received the start of the flight") + + // Clear the outgoing DTLS queue and terminate the retransmit timer + h.hOut.ClearQueuedMessages() + h.timers.cancel(retransmitTimerLabel) + + // OK, we're not waiting any more. + h.waitingNextFlight = false + } + + // Now pre-emptively arm the ACK timer if it's not armed already. + // We'll automatically dis-arm it at the end of the handshake. + if h.timers.getTimer(ackTimerLabel) == nil { + h.timers.start(ackTimerLabel, h.sendAck, h.timeoutMS/4) + } +} + +func (h *HandshakeContext) receivedEndOfFlight() { + logf(logTypeHandshake, "%p Received the end of the flight", h) + if !h.hIn.datagram { + return + } + + // Empty incoming queue + h.hIn.queued = nil + + // Note that we are waiting for the next flight. + h.waitingNextFlight = true + + // Clear the ACK queue. + h.hIn.recvdRecords = nil + + // Disarm the ACK timer + h.timers.cancel(ackTimerLabel) +} + +func (h *HandshakeContext) receivedFinalFlight() { + logf(logTypeHandshake, "%p Received final flight", h) + if !h.hIn.datagram { + return + } + + // Disarm the ACK timer + h.timers.cancel(ackTimerLabel) + + // But send an ACK immediately. + h.sendAck() +} + +func (h *HandshakeContext) fragmentAcked(seq uint32, offset int, fraglen int) bool { + logf(logTypeHandshake, "Looking to see if fragment %v %v(%v) was acked", seq, offset, fraglen) + for _, f := range h.sentFragments { + if !f.acked { + continue + } + + if f.seq != seq { + continue + } + + if f.offset > offset { + continue + } + + // At this point, we know that the stored fragment starts + // at or before what we want to send, so check where the end + // is. + if f.offset+f.fragLength < offset+fraglen { + continue + } + + return true + } + + return false +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/extensions.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/extensions.go new file mode 100644 index 00000000..07cb16c6 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/extensions.go @@ -0,0 +1,626 @@ +package mint + +import ( + "bytes" + "fmt" + "github.com/bifurcation/mint/syntax" +) + +type ExtensionBody interface { + Type() ExtensionType + Marshal() ([]byte, error) + Unmarshal(data []byte) (int, error) +} + +// struct { +// ExtensionType extension_type; +// opaque extension_data<0..2^16-1>; +// } Extension; +type Extension struct { + ExtensionType ExtensionType + ExtensionData []byte `tls:"head=2"` +} + +func (ext Extension) Marshal() ([]byte, error) { + return syntax.Marshal(ext) +} + +func (ext *Extension) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, ext) +} + +type ExtensionList []Extension + +type extensionListInner struct { + List []Extension `tls:"head=2"` +} + +func (el ExtensionList) Marshal() ([]byte, error) { + return syntax.Marshal(extensionListInner{el}) +} + +func (el *ExtensionList) Unmarshal(data []byte) (int, error) { + var list extensionListInner + read, err := syntax.Unmarshal(data, &list) + if err != nil { + return 0, err + } + + *el = list.List + return read, nil +} + +func (el *ExtensionList) Add(src ExtensionBody) error { + data, err := src.Marshal() + if err != nil { + return err + } + + if el == nil { + el = new(ExtensionList) + } + + // If one already exists with this type, replace it + for i := range *el { + if (*el)[i].ExtensionType == src.Type() { + (*el)[i].ExtensionData = data + return nil + } + } + + // Otherwise append + *el = append(*el, Extension{ + ExtensionType: src.Type(), + ExtensionData: data, + }) + return nil +} + +func (el ExtensionList) Parse(dsts []ExtensionBody) (map[ExtensionType]bool, error) { + found := make(map[ExtensionType]bool) + + for _, dst := range dsts { + for _, ext := range el { + if ext.ExtensionType == dst.Type() { + if found[dst.Type()] { + return nil, fmt.Errorf("Duplicate extension of type [%v]", dst.Type()) + } + + err := safeUnmarshal(dst, ext.ExtensionData) + if err != nil { + return nil, err + } + + found[dst.Type()] = true + } + } + } + + return found, nil +} + +func (el ExtensionList) Find(dst ExtensionBody) (bool, error) { + for _, ext := range el { + if ext.ExtensionType == dst.Type() { + err := safeUnmarshal(dst, ext.ExtensionData) + if err != nil { + return true, err + } + return true, nil + } + } + return false, nil +} + +// struct { +// NameType name_type; +// select (name_type) { +// case host_name: HostName; +// } name; +// } ServerName; +// +// enum { +// host_name(0), (255) +// } NameType; +// +// opaque HostName<1..2^16-1>; +// +// struct { +// ServerName server_name_list<1..2^16-1> +// } ServerNameList; +// +// But we only care about the case where there's a single DNS hostname. We +// will never create anything else, and throw if we receive something else +// +// 2 1 2 +// | listLen | NameType | nameLen | name | +type ServerNameExtension string + +type serverNameInner struct { + NameType uint8 + HostName []byte `tls:"head=2,min=1"` +} + +type serverNameListInner struct { + ServerNameList []serverNameInner `tls:"head=2,min=1"` +} + +func (sni ServerNameExtension) Type() ExtensionType { + return ExtensionTypeServerName +} + +func (sni ServerNameExtension) Marshal() ([]byte, error) { + list := serverNameListInner{ + ServerNameList: []serverNameInner{{ + NameType: 0x00, // host_name + HostName: []byte(sni), + }}, + } + + return syntax.Marshal(list) +} + +func (sni *ServerNameExtension) Unmarshal(data []byte) (int, error) { + var list serverNameListInner + read, err := syntax.Unmarshal(data, &list) + if err != nil { + return 0, err + } + + // Syntax requires at least one entry + // Entries beyond the first are ignored + if nameType := list.ServerNameList[0].NameType; nameType != 0x00 { + return 0, fmt.Errorf("tls.servername: Unsupported name type [%x]", nameType) + } + + *sni = ServerNameExtension(list.ServerNameList[0].HostName) + return read, nil +} + +// struct { +// NamedGroup group; +// opaque key_exchange<1..2^16-1>; +// } KeyShareEntry; +// +// struct { +// select (Handshake.msg_type) { +// case client_hello: +// KeyShareEntry client_shares<0..2^16-1>; +// +// case hello_retry_request: +// NamedGroup selected_group; +// +// case server_hello: +// KeyShareEntry server_share; +// }; +// } KeyShare; +type KeyShareEntry struct { + Group NamedGroup + KeyExchange []byte `tls:"head=2,min=1"` +} + +func (kse KeyShareEntry) SizeValid() bool { + return len(kse.KeyExchange) == keyExchangeSizeFromNamedGroup(kse.Group) +} + +type KeyShareExtension struct { + HandshakeType HandshakeType + SelectedGroup NamedGroup + Shares []KeyShareEntry +} + +type KeyShareClientHelloInner struct { + ClientShares []KeyShareEntry `tls:"head=2,min=0"` +} +type KeyShareHelloRetryInner struct { + SelectedGroup NamedGroup +} +type KeyShareServerHelloInner struct { + ServerShare KeyShareEntry +} + +func (ks KeyShareExtension) Type() ExtensionType { + return ExtensionTypeKeyShare +} + +func (ks KeyShareExtension) Marshal() ([]byte, error) { + switch ks.HandshakeType { + case HandshakeTypeClientHello: + for _, share := range ks.Shares { + if !share.SizeValid() { + return nil, fmt.Errorf("tls.keyshare: Key share has wrong size for group") + } + } + return syntax.Marshal(KeyShareClientHelloInner{ks.Shares}) + + case HandshakeTypeHelloRetryRequest: + if len(ks.Shares) > 0 { + return nil, fmt.Errorf("tls.keyshare: Key shares not allowed for HelloRetryRequest") + } + + return syntax.Marshal(KeyShareHelloRetryInner{ks.SelectedGroup}) + + case HandshakeTypeServerHello: + if len(ks.Shares) != 1 { + return nil, fmt.Errorf("tls.keyshare: Server must send exactly one key share") + } + + if !ks.Shares[0].SizeValid() { + return nil, fmt.Errorf("tls.keyshare: Key share has wrong size for group") + } + + return syntax.Marshal(KeyShareServerHelloInner{ks.Shares[0]}) + + default: + return nil, fmt.Errorf("tls.keyshare: Handshake type not allowed") + } +} + +func (ks *KeyShareExtension) Unmarshal(data []byte) (int, error) { + switch ks.HandshakeType { + case HandshakeTypeClientHello: + var inner KeyShareClientHelloInner + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + + for _, share := range inner.ClientShares { + if !share.SizeValid() { + return 0, fmt.Errorf("tls.keyshare: Key share has wrong size for group") + } + } + + ks.Shares = inner.ClientShares + return read, nil + + case HandshakeTypeHelloRetryRequest: + var inner KeyShareHelloRetryInner + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + + ks.SelectedGroup = inner.SelectedGroup + return read, nil + + case HandshakeTypeServerHello: + var inner KeyShareServerHelloInner + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + + if !inner.ServerShare.SizeValid() { + return 0, fmt.Errorf("tls.keyshare: Key share has wrong size for group") + } + + ks.Shares = []KeyShareEntry{inner.ServerShare} + return read, nil + + default: + return 0, fmt.Errorf("tls.keyshare: Handshake type not allowed") + } +} + +// struct { +// NamedGroup named_group_list<2..2^16-1>; +// } NamedGroupList; +type SupportedGroupsExtension struct { + Groups []NamedGroup `tls:"head=2,min=2"` +} + +func (sg SupportedGroupsExtension) Type() ExtensionType { + return ExtensionTypeSupportedGroups +} + +func (sg SupportedGroupsExtension) Marshal() ([]byte, error) { + return syntax.Marshal(sg) +} + +func (sg *SupportedGroupsExtension) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, sg) +} + +// struct { +// SignatureScheme supported_signature_algorithms<2..2^16-2>; +// } SignatureSchemeList +type SignatureAlgorithmsExtension struct { + Algorithms []SignatureScheme `tls:"head=2,min=2"` +} + +func (sa SignatureAlgorithmsExtension) Type() ExtensionType { + return ExtensionTypeSignatureAlgorithms +} + +func (sa SignatureAlgorithmsExtension) Marshal() ([]byte, error) { + return syntax.Marshal(sa) +} + +func (sa *SignatureAlgorithmsExtension) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, sa) +} + +// struct { +// opaque identity<1..2^16-1>; +// uint32 obfuscated_ticket_age; +// } PskIdentity; +// +// opaque PskBinderEntry<32..255>; +// +// struct { +// select (Handshake.msg_type) { +// case client_hello: +// PskIdentity identities<7..2^16-1>; +// PskBinderEntry binders<33..2^16-1>; +// +// case server_hello: +// uint16 selected_identity; +// }; +// +// } PreSharedKeyExtension; +type PSKIdentity struct { + Identity []byte `tls:"head=2,min=1"` + ObfuscatedTicketAge uint32 +} + +type PSKBinderEntry struct { + Binder []byte `tls:"head=1,min=32"` +} + +type PreSharedKeyExtension struct { + HandshakeType HandshakeType + Identities []PSKIdentity + Binders []PSKBinderEntry + SelectedIdentity uint16 +} + +type preSharedKeyClientInner struct { + Identities []PSKIdentity `tls:"head=2,min=7"` + Binders []PSKBinderEntry `tls:"head=2,min=33"` +} + +type preSharedKeyServerInner struct { + SelectedIdentity uint16 +} + +func (psk PreSharedKeyExtension) Type() ExtensionType { + return ExtensionTypePreSharedKey +} + +func (psk PreSharedKeyExtension) Marshal() ([]byte, error) { + switch psk.HandshakeType { + case HandshakeTypeClientHello: + return syntax.Marshal(preSharedKeyClientInner{ + Identities: psk.Identities, + Binders: psk.Binders, + }) + + case HandshakeTypeServerHello: + if len(psk.Identities) > 0 || len(psk.Binders) > 0 { + return nil, fmt.Errorf("tls.presharedkey: Server can only provide an index") + } + return syntax.Marshal(preSharedKeyServerInner{psk.SelectedIdentity}) + + default: + return nil, fmt.Errorf("tls.presharedkey: Handshake type not supported") + } +} + +func (psk *PreSharedKeyExtension) Unmarshal(data []byte) (int, error) { + switch psk.HandshakeType { + case HandshakeTypeClientHello: + var inner preSharedKeyClientInner + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + + if len(inner.Identities) != len(inner.Binders) { + return 0, fmt.Errorf("Lengths of identities and binders not equal") + } + + psk.Identities = inner.Identities + psk.Binders = inner.Binders + return read, nil + + case HandshakeTypeServerHello: + var inner preSharedKeyServerInner + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + + psk.SelectedIdentity = inner.SelectedIdentity + return read, nil + + default: + return 0, fmt.Errorf("tls.presharedkey: Handshake type not supported") + } +} + +func (psk PreSharedKeyExtension) HasIdentity(id []byte) ([]byte, bool) { + for i, localID := range psk.Identities { + if bytes.Equal(localID.Identity, id) { + return psk.Binders[i].Binder, true + } + } + return nil, false +} + +// enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode; +// +// struct { +// PskKeyExchangeMode ke_modes<1..255>; +// } PskKeyExchangeModes; +type PSKKeyExchangeModesExtension struct { + KEModes []PSKKeyExchangeMode `tls:"head=1,min=1"` +} + +func (pkem PSKKeyExchangeModesExtension) Type() ExtensionType { + return ExtensionTypePSKKeyExchangeModes +} + +func (pkem PSKKeyExchangeModesExtension) Marshal() ([]byte, error) { + return syntax.Marshal(pkem) +} + +func (pkem *PSKKeyExchangeModesExtension) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, pkem) +} + +// struct { +// } EarlyDataIndication; + +type EarlyDataExtension struct{} + +func (ed EarlyDataExtension) Type() ExtensionType { + return ExtensionTypeEarlyData +} + +func (ed EarlyDataExtension) Marshal() ([]byte, error) { + return []byte{}, nil +} + +func (ed *EarlyDataExtension) Unmarshal(data []byte) (int, error) { + return 0, nil +} + +// struct { +// uint32 max_early_data_size; +// } TicketEarlyDataInfo; + +type TicketEarlyDataInfoExtension struct { + MaxEarlyDataSize uint32 +} + +func (tedi TicketEarlyDataInfoExtension) Type() ExtensionType { + return ExtensionTypeTicketEarlyDataInfo +} + +func (tedi TicketEarlyDataInfoExtension) Marshal() ([]byte, error) { + return syntax.Marshal(tedi) +} + +func (tedi *TicketEarlyDataInfoExtension) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, tedi) +} + +// opaque ProtocolName<1..2^8-1>; +// +// struct { +// ProtocolName protocol_name_list<2..2^16-1> +// } ProtocolNameList; +type ALPNExtension struct { + Protocols []string +} + +type protocolNameInner struct { + Name []byte `tls:"head=1,min=1"` +} + +type alpnExtensionInner struct { + Protocols []protocolNameInner `tls:"head=2,min=2"` +} + +func (alpn ALPNExtension) Type() ExtensionType { + return ExtensionTypeALPN +} + +func (alpn ALPNExtension) Marshal() ([]byte, error) { + protocols := make([]protocolNameInner, len(alpn.Protocols)) + for i, protocol := range alpn.Protocols { + protocols[i] = protocolNameInner{[]byte(protocol)} + } + return syntax.Marshal(alpnExtensionInner{protocols}) +} + +func (alpn *ALPNExtension) Unmarshal(data []byte) (int, error) { + var inner alpnExtensionInner + read, err := syntax.Unmarshal(data, &inner) + + if err != nil { + return 0, err + } + + alpn.Protocols = make([]string, len(inner.Protocols)) + for i, protocol := range inner.Protocols { + alpn.Protocols[i] = string(protocol.Name) + } + return read, nil +} + +// struct { +// ProtocolVersion versions<2..254>; +// } SupportedVersions; +type SupportedVersionsExtension struct { + HandshakeType HandshakeType + Versions []uint16 +} + +type SupportedVersionsClientHelloInner struct { + Versions []uint16 `tls:"head=1,min=2,max=254"` +} + +type SupportedVersionsServerHelloInner struct { + Version uint16 +} + +func (sv SupportedVersionsExtension) Type() ExtensionType { + return ExtensionTypeSupportedVersions +} + +func (sv SupportedVersionsExtension) Marshal() ([]byte, error) { + switch sv.HandshakeType { + case HandshakeTypeClientHello: + return syntax.Marshal(SupportedVersionsClientHelloInner{sv.Versions}) + case HandshakeTypeServerHello, HandshakeTypeHelloRetryRequest: + return syntax.Marshal(SupportedVersionsServerHelloInner{sv.Versions[0]}) + default: + return nil, fmt.Errorf("tls.supported_versions: Handshake type not allowed") + } +} + +func (sv *SupportedVersionsExtension) Unmarshal(data []byte) (int, error) { + switch sv.HandshakeType { + case HandshakeTypeClientHello: + var inner SupportedVersionsClientHelloInner + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + sv.Versions = inner.Versions + return read, nil + + case HandshakeTypeServerHello, HandshakeTypeHelloRetryRequest: + var inner SupportedVersionsServerHelloInner + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + sv.Versions = []uint16{inner.Version} + return read, nil + + default: + return 0, fmt.Errorf("tls.supported_versions: Handshake type not allowed") + } +} + +// struct { +// opaque cookie<1..2^16-1>; +// } Cookie; +type CookieExtension struct { + Cookie []byte `tls:"head=2,min=1"` +} + +func (c CookieExtension) Type() ExtensionType { + return ExtensionTypeCookie +} + +func (c CookieExtension) Marshal() ([]byte, error) { + return syntax.Marshal(c) +} + +func (c *CookieExtension) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, c) +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/ffdhe.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/ffdhe.go new file mode 100644 index 00000000..59d1f7f9 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/ffdhe.go @@ -0,0 +1,147 @@ +package mint + +import ( + "encoding/hex" + "math/big" +) + +var ( + finiteFieldPrime2048hex = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B423861285C97FFFFFFFFFFFFFFFF" + finiteFieldPrime2048bytes, _ = hex.DecodeString(finiteFieldPrime2048hex) + finiteFieldPrime2048 = big.NewInt(0).SetBytes(finiteFieldPrime2048bytes) + + finiteFieldPrime3072hex = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF" + finiteFieldPrime3072bytes, _ = hex.DecodeString(finiteFieldPrime3072hex) + finiteFieldPrime3072 = big.NewInt(0).SetBytes(finiteFieldPrime3072bytes) + + finiteFieldPrime4096hex = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" + + "FFFFFFFFFFFFFFFF" + finiteFieldPrime4096bytes, _ = hex.DecodeString(finiteFieldPrime4096hex) + finiteFieldPrime4096 = big.NewInt(0).SetBytes(finiteFieldPrime4096bytes) + + finiteFieldPrime6144hex = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF" + finiteFieldPrime6144bytes, _ = hex.DecodeString(finiteFieldPrime6144hex) + finiteFieldPrime6144 = big.NewInt(0).SetBytes(finiteFieldPrime6144bytes) + + finiteFieldPrime8192hex = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" + + "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" + + "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" + + "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" + + "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" + + "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" + + "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" + + "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" + + "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" + + "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" + + "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" + + "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF" + finiteFieldPrime8192bytes, _ = hex.DecodeString(finiteFieldPrime8192hex) + finiteFieldPrime8192 = big.NewInt(0).SetBytes(finiteFieldPrime8192bytes) +) diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/frame-reader.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/frame-reader.go new file mode 100644 index 00000000..4ccfc23f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/frame-reader.go @@ -0,0 +1,98 @@ +// Read a generic "framed" packet consisting of a header and a +// This is used for both TLS Records and TLS Handshake Messages +package mint + +type framing interface { + headerLen() int + defaultReadLen() int + frameLen(hdr []byte) (int, error) +} + +const ( + kFrameReaderHdr = 0 + kFrameReaderBody = 1 +) + +type frameNextAction func(f *frameReader) error + +type frameReader struct { + details framing + state uint8 + header []byte + body []byte + working []byte + writeOffset int + remainder []byte +} + +func newFrameReader(d framing) *frameReader { + hdr := make([]byte, d.headerLen()) + return &frameReader{ + d, + kFrameReaderHdr, + hdr, + nil, + hdr, + 0, + nil, + } +} + +func dup(a []byte) []byte { + r := make([]byte, len(a)) + copy(r, a) + return r +} + +func (f *frameReader) needed() int { + tmp := (len(f.working) - f.writeOffset) - len(f.remainder) + if tmp < 0 { + return 0 + } + return tmp +} + +func (f *frameReader) addChunk(in []byte) { + // Append to the buffer. + logf(logTypeFrameReader, "Appending %v", len(in)) + f.remainder = append(f.remainder, in...) +} + +func (f *frameReader) process() (hdr []byte, body []byte, err error) { + for f.needed() == 0 { + logf(logTypeFrameReader, "%v bytes needed for next block", len(f.working)-f.writeOffset) + // Fill out our working block + copied := copy(f.working[f.writeOffset:], f.remainder) + f.remainder = f.remainder[copied:] + f.writeOffset += copied + if f.writeOffset < len(f.working) { + logf(logTypeVerbose, "Read would have blocked 1") + return nil, nil, AlertWouldBlock + } + // Reset the write offset, because we are now full. + f.writeOffset = 0 + + // We have read a full frame + if f.state == kFrameReaderBody { + logf(logTypeFrameReader, "Returning frame hdr=%#x len=%d buffered=%d", f.header, len(f.body), len(f.remainder)) + f.state = kFrameReaderHdr + f.working = f.header + return dup(f.header), dup(f.body), nil + } + + // We have read the header + bodyLen, err := f.details.frameLen(f.header) + if err != nil { + return nil, nil, err + } + logf(logTypeFrameReader, "Processed header, body len = %v", bodyLen) + + f.body = make([]byte, bodyLen) + f.working = f.body + f.writeOffset = 0 + f.state = kFrameReaderBody + } + + logf(logTypeVerbose, "Read would have blocked 2") + return nil, nil, AlertWouldBlock +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-layer.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-layer.go new file mode 100644 index 00000000..de17b30b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-layer.go @@ -0,0 +1,551 @@ +package mint + +import ( + "fmt" + "io" + "net" +) + +const ( + handshakeHeaderLenTLS = 4 // handshake message header length + handshakeHeaderLenDTLS = 12 // handshake message header length + maxHandshakeMessageLen = 1 << 24 // max handshake message length +) + +// struct { +// HandshakeType msg_type; /* handshake type */ +// uint24 length; /* bytes in message */ +// select (HandshakeType) { +// ... +// } body; +// } Handshake; +// +// We do the select{...} part in a different layer, so we treat the +// actual message body as opaque: +// +// struct { +// HandshakeType msg_type; +// opaque msg<0..2^24-1> +// } Handshake; +// +type HandshakeMessage struct { + msgType HandshakeType + seq uint32 + body []byte + datagram bool + offset uint32 // Used for DTLS + length uint32 + cipher *cipherState +} + +// Note: This could be done with the `syntax` module, using the simplified +// syntax as discussed above. However, since this is so simple, there's not +// much benefit to doing so. +// When datagram is set, we marshal this as a whole DTLS record. +func (hm *HandshakeMessage) Marshal() []byte { + if hm == nil { + return []byte{} + } + + fragLen := len(hm.body) + var data []byte + + if hm.datagram { + data = make([]byte, handshakeHeaderLenDTLS+fragLen) + } else { + data = make([]byte, handshakeHeaderLenTLS+fragLen) + } + tmp := data + tmp = encodeUint(uint64(hm.msgType), 1, tmp) + tmp = encodeUint(uint64(hm.length), 3, tmp) + if hm.datagram { + tmp = encodeUint(uint64(hm.seq), 2, tmp) + tmp = encodeUint(uint64(hm.offset), 3, tmp) + tmp = encodeUint(uint64(fragLen), 3, tmp) + } + copy(tmp, hm.body) + return data +} + +func (hm HandshakeMessage) ToBody() (HandshakeMessageBody, error) { + logf(logTypeHandshake, "HandshakeMessage.toBody [%d] [%x]", hm.msgType, hm.body) + + var body HandshakeMessageBody + switch hm.msgType { + case HandshakeTypeClientHello: + body = new(ClientHelloBody) + case HandshakeTypeServerHello: + body = new(ServerHelloBody) + case HandshakeTypeEncryptedExtensions: + body = new(EncryptedExtensionsBody) + case HandshakeTypeCertificate: + body = new(CertificateBody) + case HandshakeTypeCertificateRequest: + body = new(CertificateRequestBody) + case HandshakeTypeCertificateVerify: + body = new(CertificateVerifyBody) + case HandshakeTypeFinished: + body = &FinishedBody{VerifyDataLen: len(hm.body)} + case HandshakeTypeNewSessionTicket: + body = new(NewSessionTicketBody) + case HandshakeTypeKeyUpdate: + body = new(KeyUpdateBody) + case HandshakeTypeEndOfEarlyData: + body = new(EndOfEarlyDataBody) + default: + return body, fmt.Errorf("tls.handshakemessage: Unsupported body type") + } + + err := safeUnmarshal(body, hm.body) + return body, err +} + +func (h *HandshakeLayer) HandshakeMessageFromBody(body HandshakeMessageBody) (*HandshakeMessage, error) { + data, err := body.Marshal() + if err != nil { + return nil, err + } + + m := &HandshakeMessage{ + msgType: body.Type(), + body: data, + seq: h.msgSeq, + datagram: h.datagram, + length: uint32(len(data)), + } + h.msgSeq++ + return m, nil +} + +type HandshakeLayer struct { + ctx *HandshakeContext // The handshake we are attached to + nonblocking bool // Should we operate in nonblocking mode + conn *RecordLayer // Used for reading/writing records + frame *frameReader // The buffered frame reader + datagram bool // Is this DTLS? + msgSeq uint32 // The DTLS message sequence number + queued []*HandshakeMessage // In/out queue + sent []*HandshakeMessage // Sent messages for DTLS + recvdRecords []uint64 // Records we have received. + maxFragmentLen int +} + +type handshakeLayerFrameDetails struct { + datagram bool +} + +func (d handshakeLayerFrameDetails) headerLen() int { + if d.datagram { + return handshakeHeaderLenDTLS + } + return handshakeHeaderLenTLS +} + +func (d handshakeLayerFrameDetails) defaultReadLen() int { + return d.headerLen() + maxFragmentLen +} + +func (d handshakeLayerFrameDetails) frameLen(hdr []byte) (int, error) { + logf(logTypeIO, "Header=%x", hdr) + // The length of this fragment (as opposed to the message) + // is always the last three bytes for both TLS and DTLS + val, _ := decodeUint(hdr[len(hdr)-3:], 3) + return int(val), nil +} + +func NewHandshakeLayerTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer { + h := HandshakeLayer{} + h.ctx = c + h.conn = r + h.datagram = false + h.frame = newFrameReader(&handshakeLayerFrameDetails{false}) + h.maxFragmentLen = maxFragmentLen + return &h +} + +func NewHandshakeLayerDTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer { + h := HandshakeLayer{} + h.ctx = c + h.conn = r + h.datagram = true + h.frame = newFrameReader(&handshakeLayerFrameDetails{true}) + h.maxFragmentLen = initialMtu // Not quite right + return &h +} + +func (h *HandshakeLayer) readRecord() error { + logf(logTypeVerbose, "Trying to read record") + pt, err := h.conn.readRecordAnyEpoch() + if err != nil { + return err + } + + switch pt.contentType { + case RecordTypeHandshake, RecordTypeAlert, RecordTypeAck: + default: + return fmt.Errorf("tls.handshakelayer: Unexpected record type %d", pt.contentType) + } + + if pt.contentType == RecordTypeAck { + if !h.datagram { + return fmt.Errorf("tls.handshakelayer: can't have ACK with TLS") + } + logf(logTypeIO, "read ACK") + return h.ctx.processAck(pt.fragment) + } + + if pt.contentType == RecordTypeAlert { + logf(logTypeIO, "read alert %v", pt.fragment[1]) + if len(pt.fragment) < 2 { + h.sendAlert(AlertUnexpectedMessage) + return io.EOF + } + return Alert(pt.fragment[1]) + } + + assert(h.ctx.hIn.conn != nil) + if pt.epoch != h.ctx.hIn.conn.cipher.epoch { + // This is out of order but we're dropping it. + // TODO(ekr@rtfm.com): If server, need to retransmit Finished. + if pt.epoch == EpochClear || pt.epoch == EpochHandshakeData { + return nil + } + + // Anything else shouldn't happen. + return AlertIllegalParameter + } + + h.recvdRecords = append(h.recvdRecords, pt.seq) + h.frame.addChunk(pt.fragment) + + return nil +} + +// sendAlert sends a TLS alert message. +func (h *HandshakeLayer) sendAlert(err Alert) error { + tmp := make([]byte, 2) + tmp[0] = AlertLevelError + tmp[1] = byte(err) + h.conn.WriteRecord(&TLSPlaintext{ + contentType: RecordTypeAlert, + fragment: tmp}, + ) + + // closeNotify is a special case in that it isn't an error: + if err != AlertCloseNotify { + return &net.OpError{Op: "local error", Err: err} + } + return nil +} + +func (h *HandshakeLayer) noteMessageDelivered(seq uint32) { + h.msgSeq = seq + 1 + var i int + var m *HandshakeMessage + for i, m = range h.queued { + if m.seq > seq { + break + } + } + h.queued = h.queued[i:] +} + +func (h *HandshakeLayer) newFragmentReceived(hm *HandshakeMessage) (*HandshakeMessage, error) { + if hm.seq < h.msgSeq { + return nil, nil + } + + // TODO(ekr@rtfm.com): Send an ACK immediately if we got something + // out of order. + h.ctx.receivedHandshakeMessage() + + if hm.seq == h.msgSeq && hm.offset == 0 && hm.length == uint32(len(hm.body)) { + // TODO(ekr@rtfm.com): Check the length? + // This is complete. + h.noteMessageDelivered(hm.seq) + return hm, nil + } + + // Now insert sorted. + var i int + for i = 0; i < len(h.queued); i++ { + f := h.queued[i] + if hm.seq < f.seq { + break + } + if hm.offset < f.offset { + break + } + } + tmp := make([]*HandshakeMessage, 0, len(h.queued)+1) + tmp = append(tmp, h.queued[:i]...) + tmp = append(tmp, hm) + tmp = append(tmp, h.queued[i:]...) + h.queued = tmp + + return h.checkMessageAvailable() +} + +func (h *HandshakeLayer) checkMessageAvailable() (*HandshakeMessage, error) { + if len(h.queued) == 0 { + return nil, nil + } + + hm := h.queued[0] + if hm.seq != h.msgSeq { + return nil, nil + } + + if hm.seq == h.msgSeq && hm.offset == 0 && hm.length == uint32(len(hm.body)) { + // TODO(ekr@rtfm.com): Check the length? + // This is complete. + h.noteMessageDelivered(hm.seq) + return hm, nil + } + + // OK, this at least might complete the message. + end := uint32(0) + buf := make([]byte, hm.length) + + for _, f := range h.queued { + // Out of fragments + if f.seq > hm.seq { + break + } + + if f.length != uint32(len(buf)) { + return nil, fmt.Errorf("Mismatched DTLS length") + } + + if f.offset > end { + break + } + + if f.offset+uint32(len(f.body)) > end { + // OK, this is adding something we don't know about + copy(buf[f.offset:], f.body) + end = f.offset + uint32(len(f.body)) + if end == hm.length { + h2 := *hm + h2.offset = 0 + h2.body = buf + h.noteMessageDelivered(hm.seq) + return &h2, nil + } + } + + } + + return nil, nil +} + +func (h *HandshakeLayer) ReadMessage() (*HandshakeMessage, error) { + var hdr, body []byte + var err error + + hm, err := h.checkMessageAvailable() + if err != nil { + return nil, err + } + if hm != nil { + return hm, nil + } + for { + logf(logTypeVerbose, "ReadMessage() buffered=%v", len(h.frame.remainder)) + if h.frame.needed() > 0 { + logf(logTypeVerbose, "Trying to read a new record") + err = h.readRecord() + + if err != nil && (h.nonblocking || err != AlertWouldBlock) { + return nil, err + } + } + + hdr, body, err = h.frame.process() + if err == nil { + break + } + if err != nil && (h.nonblocking || err != AlertWouldBlock) { + return nil, err + } + } + + logf(logTypeHandshake, "read handshake message") + + hm = &HandshakeMessage{} + hm.msgType = HandshakeType(hdr[0]) + hm.datagram = h.datagram + hm.body = make([]byte, len(body)) + copy(hm.body, body) + logf(logTypeHandshake, "Read message with type: %v", hm.msgType) + if h.datagram { + tmp, hdr := decodeUint(hdr[1:], 3) + hm.length = uint32(tmp) + tmp, hdr = decodeUint(hdr, 2) + hm.seq = uint32(tmp) + tmp, hdr = decodeUint(hdr, 3) + hm.offset = uint32(tmp) + + return h.newFragmentReceived(hm) + } + + hm.length = uint32(len(body)) + return hm, nil +} + +func (h *HandshakeLayer) QueueMessage(hm *HandshakeMessage) error { + hm.cipher = h.conn.cipher + h.queued = append(h.queued, hm) + return nil +} + +func (h *HandshakeLayer) SendQueuedMessages() (int, error) { + logf(logTypeHandshake, "Sending outgoing messages") + count, err := h.WriteMessages(h.queued) + if !h.datagram { + h.ClearQueuedMessages() + } + return count, err +} + +func (h *HandshakeLayer) ClearQueuedMessages() { + logf(logTypeHandshake, "Clearing outgoing hs message queue") + h.queued = nil +} + +func (h *HandshakeLayer) writeFragment(hm *HandshakeMessage, start int, room int) (bool, int, error) { + var buf []byte + + // Figure out if we're going to want the full header or just + // the body + hdrlen := 0 + if hm.datagram { + hdrlen = handshakeHeaderLenDTLS + } else if start == 0 { + hdrlen = handshakeHeaderLenTLS + } + + // Compute the amount of body we can fit in + room -= hdrlen + if room == 0 { + // This works because we are doing one record per + // message + panic("Too short max fragment len") + } + bodylen := len(hm.body) - start + if bodylen > room { + bodylen = room + } + body := hm.body[start : start+bodylen] + + // Now see if this chunk has been ACKed. This doesn't produce ideal + // retransmission but is simple. + if h.ctx.fragmentAcked(hm.seq, start, bodylen) { + logf(logTypeHandshake, "Fragment %v %v(%v) already acked. Skipping", hm.seq, start, bodylen) + return false, start + bodylen, nil + } + + // Encode the data. + if hdrlen > 0 { + hm2 := *hm + hm2.offset = uint32(start) + hm2.body = body + buf = hm2.Marshal() + hm = &hm2 + } else { + buf = body + } + + if h.datagram { + // Remember that we sent this. + h.ctx.sentFragments = append(h.ctx.sentFragments, &SentHandshakeFragment{ + hm.seq, + start, + len(body), + h.conn.cipher.combineSeq(true), + false, + }) + } + return true, start + bodylen, h.conn.writeRecordWithPadding( + &TLSPlaintext{ + contentType: RecordTypeHandshake, + fragment: buf, + }, + hm.cipher, 0) +} + +func (h *HandshakeLayer) WriteMessage(hm *HandshakeMessage) (int, error) { + start := int(0) + + if len(hm.body) > maxHandshakeMessageLen { + return 0, fmt.Errorf("Tried to write a handshake message that's too long") + } + + written := 0 + wrote := false + + // Always make one pass through to allow EOED (which is empty). + for { + var err error + wrote, start, err = h.writeFragment(hm, start, h.maxFragmentLen) + if err != nil { + return 0, err + } + if wrote { + written++ + } + if start >= len(hm.body) { + break + } + } + + return written, nil +} + +func (h *HandshakeLayer) WriteMessages(hms []*HandshakeMessage) (int, error) { + written := 0 + for _, hm := range hms { + logf(logTypeHandshake, "WriteMessage [%d] %x", hm.msgType, hm.body) + + wrote, err := h.WriteMessage(hm) + if err != nil { + return 0, err + } + written += wrote + } + return written, nil +} + +func encodeUint(v uint64, size int, out []byte) []byte { + for i := size - 1; i >= 0; i-- { + out[i] = byte(v & 0xff) + v >>= 8 + } + return out[size:] +} + +func decodeUint(in []byte, size int) (uint64, []byte) { + val := uint64(0) + + for i := 0; i < size; i++ { + val <<= 8 + val += uint64(in[i]) + } + return val, in[size:] +} + +type marshalledPDU interface { + Marshal() ([]byte, error) + Unmarshal(data []byte) (int, error) +} + +func safeUnmarshal(pdu marshalledPDU, data []byte) error { + read, err := pdu.Unmarshal(data) + if err != nil { + return err + } + if len(data) != read { + return fmt.Errorf("Invalid encoding: Extra data not consumed") + } + return nil +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-messages.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-messages.go new file mode 100644 index 00000000..5a229f1d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/handshake-messages.go @@ -0,0 +1,481 @@ +package mint + +import ( + "bytes" + "crypto" + "crypto/x509" + "encoding/binary" + "fmt" + + "github.com/bifurcation/mint/syntax" +) + +type HandshakeMessageBody interface { + Type() HandshakeType + Marshal() ([]byte, error) + Unmarshal(data []byte) (int, error) +} + +// struct { +// ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */ +// Random random; +// opaque legacy_session_id<0..32>; +// CipherSuite cipher_suites<2..2^16-2>; +// opaque legacy_compression_methods<1..2^8-1>; +// Extension extensions<0..2^16-1>; +// } ClientHello; +type ClientHelloBody struct { + LegacyVersion uint16 + Random [32]byte + LegacySessionID []byte + CipherSuites []CipherSuite + Extensions ExtensionList +} + +type clientHelloBodyInnerTLS struct { + LegacyVersion uint16 + Random [32]byte + LegacySessionID []byte `tls:"head=1,max=32"` + CipherSuites []CipherSuite `tls:"head=2,min=2"` + LegacyCompressionMethods []byte `tls:"head=1,min=1"` + Extensions []Extension `tls:"head=2"` +} + +type clientHelloBodyInnerDTLS struct { + LegacyVersion uint16 + Random [32]byte + LegacySessionID []byte `tls:"head=1,max=32"` + EmptyCookie uint8 + CipherSuites []CipherSuite `tls:"head=2,min=2"` + LegacyCompressionMethods []byte `tls:"head=1,min=1"` + Extensions []Extension `tls:"head=2"` +} + +func (ch ClientHelloBody) Type() HandshakeType { + return HandshakeTypeClientHello +} + +func (ch ClientHelloBody) Marshal() ([]byte, error) { + if ch.LegacyVersion == tls12Version { + return syntax.Marshal(clientHelloBodyInnerTLS{ + LegacyVersion: ch.LegacyVersion, + Random: ch.Random, + LegacySessionID: []byte{}, + CipherSuites: ch.CipherSuites, + LegacyCompressionMethods: []byte{0}, + Extensions: ch.Extensions, + }) + } else { + return syntax.Marshal(clientHelloBodyInnerDTLS{ + LegacyVersion: ch.LegacyVersion, + Random: ch.Random, + LegacySessionID: []byte{}, + CipherSuites: ch.CipherSuites, + LegacyCompressionMethods: []byte{0}, + Extensions: ch.Extensions, + }) + } + +} + +func (ch *ClientHelloBody) Unmarshal(data []byte) (int, error) { + var read int + var err error + + // Note that this might be 0, in which case we do TLS. That + // makes the tests easier. + if ch.LegacyVersion != dtls12WireVersion { + var inner clientHelloBodyInnerTLS + read, err = syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + + if len(inner.LegacyCompressionMethods) != 1 || inner.LegacyCompressionMethods[0] != 0 { + return 0, fmt.Errorf("tls.clienthello: Invalid compression method") + } + + ch.LegacyVersion = inner.LegacyVersion + ch.Random = inner.Random + ch.LegacySessionID = inner.LegacySessionID + ch.CipherSuites = inner.CipherSuites + ch.Extensions = inner.Extensions + } else { + var inner clientHelloBodyInnerDTLS + read, err = syntax.Unmarshal(data, &inner) + if err != nil { + return 0, err + } + + if inner.EmptyCookie != 0 { + return 0, fmt.Errorf("tls.clienthello: Invalid cookie") + } + + if len(inner.LegacyCompressionMethods) != 1 || inner.LegacyCompressionMethods[0] != 0 { + return 0, fmt.Errorf("tls.clienthello: Invalid compression method") + } + + ch.LegacyVersion = inner.LegacyVersion + ch.Random = inner.Random + ch.LegacySessionID = inner.LegacySessionID + ch.CipherSuites = inner.CipherSuites + ch.Extensions = inner.Extensions + } + return read, nil +} + +// TODO: File a spec bug to clarify this +func (ch ClientHelloBody) Truncated() ([]byte, error) { + if len(ch.Extensions) == 0 { + return nil, fmt.Errorf("tls.clienthello.truncate: No extensions") + } + + pskExt := ch.Extensions[len(ch.Extensions)-1] + if pskExt.ExtensionType != ExtensionTypePreSharedKey { + return nil, fmt.Errorf("tls.clienthello.truncate: Last extension is not PSK") + } + + body, err := ch.Marshal() + if err != nil { + return nil, err + } + chm := &HandshakeMessage{ + msgType: ch.Type(), + body: body, + length: uint32(len(body)), + } + chData := chm.Marshal() + + psk := PreSharedKeyExtension{ + HandshakeType: HandshakeTypeClientHello, + } + _, err = psk.Unmarshal(pskExt.ExtensionData) + if err != nil { + return nil, err + } + + // Marshal just the binders so that we know how much to truncate + binders := struct { + Binders []PSKBinderEntry `tls:"head=2,min=33"` + }{Binders: psk.Binders} + binderData, _ := syntax.Marshal(binders) + binderLen := len(binderData) + + chLen := len(chData) + return chData[:chLen-binderLen], nil +} + +// struct { +// ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */ +// Random random; +// opaque legacy_session_id_echo<0..32>; +// CipherSuite cipher_suite; +// uint8 legacy_compression_method = 0; +// Extension extensions<6..2^16-1>; +// } ServerHello; +type ServerHelloBody struct { + Version uint16 + Random [32]byte + LegacySessionID []byte `tls:"head=1,max=32"` + CipherSuite CipherSuite + LegacyCompressionMethod uint8 + Extensions ExtensionList `tls:"head=2"` +} + +func (sh ServerHelloBody) Type() HandshakeType { + return HandshakeTypeServerHello +} + +func (sh ServerHelloBody) Marshal() ([]byte, error) { + return syntax.Marshal(sh) +} + +func (sh *ServerHelloBody) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, sh) +} + +// struct { +// opaque verify_data[verify_data_length]; +// } Finished; +// +// verifyDataLen is not a field in the TLS struct, but we add it here so +// that calling code can tell us how much data to expect when we marshal / +// unmarshal. (We could add this to the marshal/unmarshal methods, but let's +// try to keep the signature consistent for now.) +// +// For similar reasons, we don't use the `syntax` module here, because this +// struct doesn't map well to standard TLS presentation language concepts. +// +// TODO: File a spec bug +type FinishedBody struct { + VerifyDataLen int + VerifyData []byte +} + +func (fin FinishedBody) Type() HandshakeType { + return HandshakeTypeFinished +} + +func (fin FinishedBody) Marshal() ([]byte, error) { + if len(fin.VerifyData) != fin.VerifyDataLen { + return nil, fmt.Errorf("tls.finished: data length mismatch") + } + + body := make([]byte, len(fin.VerifyData)) + copy(body, fin.VerifyData) + return body, nil +} + +func (fin *FinishedBody) Unmarshal(data []byte) (int, error) { + if len(data) < fin.VerifyDataLen { + return 0, fmt.Errorf("tls.finished: Malformed finished; too short") + } + + fin.VerifyData = make([]byte, fin.VerifyDataLen) + copy(fin.VerifyData, data[:fin.VerifyDataLen]) + return fin.VerifyDataLen, nil +} + +// struct { +// Extension extensions<0..2^16-1>; +// } EncryptedExtensions; +// +// Marshal() and Unmarshal() are handled by ExtensionList +type EncryptedExtensionsBody struct { + Extensions ExtensionList `tls:"head=2"` +} + +func (ee EncryptedExtensionsBody) Type() HandshakeType { + return HandshakeTypeEncryptedExtensions +} + +func (ee EncryptedExtensionsBody) Marshal() ([]byte, error) { + return syntax.Marshal(ee) +} + +func (ee *EncryptedExtensionsBody) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, ee) +} + +// opaque ASN1Cert<1..2^24-1>; +// +// struct { +// ASN1Cert cert_data; +// Extension extensions<0..2^16-1> +// } CertificateEntry; +// +// struct { +// opaque certificate_request_context<0..2^8-1>; +// CertificateEntry certificate_list<0..2^24-1>; +// } Certificate; +type CertificateEntry struct { + CertData *x509.Certificate + Extensions ExtensionList +} + +type CertificateBody struct { + CertificateRequestContext []byte + CertificateList []CertificateEntry +} + +type certificateEntryInner struct { + CertData []byte `tls:"head=3,min=1"` + Extensions ExtensionList `tls:"head=2"` +} + +type certificateBodyInner struct { + CertificateRequestContext []byte `tls:"head=1"` + CertificateList []certificateEntryInner `tls:"head=3"` +} + +func (c CertificateBody) Type() HandshakeType { + return HandshakeTypeCertificate +} + +func (c CertificateBody) Marshal() ([]byte, error) { + inner := certificateBodyInner{ + CertificateRequestContext: c.CertificateRequestContext, + CertificateList: make([]certificateEntryInner, len(c.CertificateList)), + } + + for i, entry := range c.CertificateList { + inner.CertificateList[i] = certificateEntryInner{ + CertData: entry.CertData.Raw, + Extensions: entry.Extensions, + } + } + + return syntax.Marshal(inner) +} + +func (c *CertificateBody) Unmarshal(data []byte) (int, error) { + inner := certificateBodyInner{} + read, err := syntax.Unmarshal(data, &inner) + if err != nil { + return read, err + } + + c.CertificateRequestContext = inner.CertificateRequestContext + c.CertificateList = make([]CertificateEntry, len(inner.CertificateList)) + + for i, entry := range inner.CertificateList { + c.CertificateList[i].CertData, err = x509.ParseCertificate(entry.CertData) + if err != nil { + return 0, fmt.Errorf("tls:certificate: Certificate failed to parse: %v", err) + } + + c.CertificateList[i].Extensions = entry.Extensions + } + + return read, nil +} + +// struct { +// SignatureScheme algorithm; +// opaque signature<0..2^16-1>; +// } CertificateVerify; +type CertificateVerifyBody struct { + Algorithm SignatureScheme + Signature []byte `tls:"head=2"` +} + +func (cv CertificateVerifyBody) Type() HandshakeType { + return HandshakeTypeCertificateVerify +} + +func (cv CertificateVerifyBody) Marshal() ([]byte, error) { + return syntax.Marshal(cv) +} + +func (cv *CertificateVerifyBody) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, cv) +} + +func (cv *CertificateVerifyBody) EncodeSignatureInput(data []byte) []byte { + // TODO: Change context for client auth + // TODO: Put this in a const + const context = "TLS 1.3, server CertificateVerify" + sigInput := bytes.Repeat([]byte{0x20}, 64) + sigInput = append(sigInput, []byte(context)...) + sigInput = append(sigInput, []byte{0}...) + sigInput = append(sigInput, data...) + return sigInput +} + +func (cv *CertificateVerifyBody) Sign(privateKey crypto.Signer, handshakeHash []byte) (err error) { + sigInput := cv.EncodeSignatureInput(handshakeHash) + cv.Signature, err = sign(cv.Algorithm, privateKey, sigInput) + logf(logTypeHandshake, "Signed: alg=[%04x] sigInput=[%x], sig=[%x]", cv.Algorithm, sigInput, cv.Signature) + return +} + +func (cv *CertificateVerifyBody) Verify(publicKey crypto.PublicKey, handshakeHash []byte) error { + sigInput := cv.EncodeSignatureInput(handshakeHash) + logf(logTypeHandshake, "About to verify: alg=[%04x] sigInput=[%x], sig=[%x]", cv.Algorithm, sigInput, cv.Signature) + return verify(cv.Algorithm, publicKey, sigInput, cv.Signature) +} + +// struct { +// opaque certificate_request_context<0..2^8-1>; +// Extension extensions<2..2^16-1>; +// } CertificateRequest; +type CertificateRequestBody struct { + CertificateRequestContext []byte `tls:"head=1"` + Extensions ExtensionList `tls:"head=2"` +} + +func (cr CertificateRequestBody) Type() HandshakeType { + return HandshakeTypeCertificateRequest +} + +func (cr CertificateRequestBody) Marshal() ([]byte, error) { + return syntax.Marshal(cr) +} + +func (cr *CertificateRequestBody) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, cr) +} + +// struct { +// uint32 ticket_lifetime; +// uint32 ticket_age_add; +// opaque ticket_nonce<1..255>; +// opaque ticket<1..2^16-1>; +// Extension extensions<0..2^16-2>; +// } NewSessionTicket; +type NewSessionTicketBody struct { + TicketLifetime uint32 + TicketAgeAdd uint32 + TicketNonce []byte `tls:"head=1,min=1"` + Ticket []byte `tls:"head=2,min=1"` + Extensions ExtensionList `tls:"head=2"` +} + +const ticketNonceLen = 16 + +func NewSessionTicket(ticketLen int, ticketLifetime uint32) (*NewSessionTicketBody, error) { + buf := make([]byte, 4+ticketNonceLen+ticketLen) + _, err := prng.Read(buf) + if err != nil { + return nil, err + } + + tkt := &NewSessionTicketBody{ + TicketLifetime: ticketLifetime, + TicketAgeAdd: binary.BigEndian.Uint32(buf[:4]), + TicketNonce: buf[4 : 4+ticketNonceLen], + Ticket: buf[4+ticketNonceLen:], + } + + return tkt, err +} + +func (tkt NewSessionTicketBody) Type() HandshakeType { + return HandshakeTypeNewSessionTicket +} + +func (tkt NewSessionTicketBody) Marshal() ([]byte, error) { + return syntax.Marshal(tkt) +} + +func (tkt *NewSessionTicketBody) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, tkt) +} + +// enum { +// update_not_requested(0), update_requested(1), (255) +// } KeyUpdateRequest; +// +// struct { +// KeyUpdateRequest request_update; +// } KeyUpdate; +type KeyUpdateBody struct { + KeyUpdateRequest KeyUpdateRequest +} + +func (ku KeyUpdateBody) Type() HandshakeType { + return HandshakeTypeKeyUpdate +} + +func (ku KeyUpdateBody) Marshal() ([]byte, error) { + return syntax.Marshal(ku) +} + +func (ku *KeyUpdateBody) Unmarshal(data []byte) (int, error) { + return syntax.Unmarshal(data, ku) +} + +// struct {} EndOfEarlyData; +type EndOfEarlyDataBody struct{} + +func (eoed EndOfEarlyDataBody) Type() HandshakeType { + return HandshakeTypeEndOfEarlyData +} + +func (eoed EndOfEarlyDataBody) Marshal() ([]byte, error) { + return []byte{}, nil +} + +func (eoed *EndOfEarlyDataBody) Unmarshal(data []byte) (int, error) { + return 0, nil +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/log.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/log.go new file mode 100644 index 00000000..2fba90de --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/log.go @@ -0,0 +1,55 @@ +package mint + +import ( + "fmt" + "log" + "os" + "strings" +) + +// We use this environment variable to control logging. It should be a +// comma-separated list of log tags (see below) or "*" to enable all logging. +const logConfigVar = "MINT_LOG" + +// Pre-defined log types +const ( + logTypeCrypto = "crypto" + logTypeHandshake = "handshake" + logTypeNegotiation = "negotiation" + logTypeIO = "io" + logTypeFrameReader = "frame" + logTypeVerbose = "verbose" +) + +var ( + logFunction = log.Printf + logAll = false + logSettings = map[string]bool{} +) + +func init() { + parseLogEnv(os.Environ()) +} + +func parseLogEnv(env []string) { + for _, stmt := range env { + if strings.HasPrefix(stmt, logConfigVar+"=") { + val := stmt[len(logConfigVar)+1:] + + if val == "*" { + logAll = true + } else { + for _, t := range strings.Split(val, ",") { + logSettings[t] = true + } + } + } + } +} + +func logf(tag string, format string, args ...interface{}) { + if logAll || logSettings[tag] { + fullFormat := fmt.Sprintf("[%s] %s", tag, format) + logFunction(fullFormat, args...) + } +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/mint.svg b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/mint.svg new file mode 100644 index 00000000..ae32703d --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/mint.svg @@ -0,0 +1,101 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/negotiation.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/negotiation.go new file mode 100644 index 00000000..2c80b8d7 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/negotiation.go @@ -0,0 +1,218 @@ +package mint + +import ( + "bytes" + "encoding/hex" + "fmt" + "time" +) + +func VersionNegotiation(offered, supported []uint16) (bool, uint16) { + for _, offeredVersion := range offered { + for _, supportedVersion := range supported { + logf(logTypeHandshake, "[server] version offered by client [%04x] <> [%04x]", offeredVersion, supportedVersion) + if offeredVersion == supportedVersion { + // XXX: Should probably be highest supported version, but for now, we + // only support one version, so it doesn't really matter. + return true, offeredVersion + } + } + } + + return false, 0 +} + +func DHNegotiation(keyShares []KeyShareEntry, groups []NamedGroup) (bool, NamedGroup, []byte, []byte) { + for _, share := range keyShares { + for _, group := range groups { + if group != share.Group { + continue + } + + pub, priv, err := newKeyShare(share.Group) + if err != nil { + // If we encounter an error, just keep looking + continue + } + + dhSecret, err := keyAgreement(share.Group, share.KeyExchange, priv) + if err != nil { + // If we encounter an error, just keep looking + continue + } + + return true, group, pub, dhSecret + } + } + + return false, 0, nil, nil +} + +const ( + ticketAgeTolerance uint32 = 5 * 1000 // five seconds in milliseconds +) + +func PSKNegotiation(identities []PSKIdentity, binders []PSKBinderEntry, context []byte, psks PreSharedKeyCache) (bool, int, *PreSharedKey, CipherSuiteParams, error) { + logf(logTypeNegotiation, "Negotiating PSK offered=[%d] supported=[%d]", len(identities), psks.Size()) + for i, id := range identities { + identityHex := hex.EncodeToString(id.Identity) + + psk, ok := psks.Get(identityHex) + if !ok { + logf(logTypeNegotiation, "No PSK for identity %x", identityHex) + continue + } + + // For resumption, make sure the ticket age is correct + if psk.IsResumption { + extTicketAge := id.ObfuscatedTicketAge - psk.TicketAgeAdd + knownTicketAge := uint32(time.Since(psk.ReceivedAt) / time.Millisecond) + ticketAgeDelta := knownTicketAge - extTicketAge + if knownTicketAge < extTicketAge { + ticketAgeDelta = extTicketAge - knownTicketAge + } + if ticketAgeDelta > ticketAgeTolerance { + logf(logTypeNegotiation, "WARNING potential replay [%x]", psk.Identity) + logf(logTypeNegotiation, "Ticket age exceeds tolerance |%d - %d| = [%d] > [%d]", + extTicketAge, knownTicketAge, ticketAgeDelta, ticketAgeTolerance) + return false, 0, nil, CipherSuiteParams{}, fmt.Errorf("WARNING Potential replay for identity %x", psk.Identity) + } + } + + params, ok := cipherSuiteMap[psk.CipherSuite] + if !ok { + err := fmt.Errorf("tls.cryptoinit: Unsupported ciphersuite from PSK [%04x]", psk.CipherSuite) + return false, 0, nil, CipherSuiteParams{}, err + } + + // Compute binder + binderLabel := labelExternalBinder + if psk.IsResumption { + binderLabel = labelResumptionBinder + } + + h0 := params.Hash.New().Sum(nil) + zero := bytes.Repeat([]byte{0}, params.Hash.Size()) + earlySecret := HkdfExtract(params.Hash, zero, psk.Key) + binderKey := deriveSecret(params, earlySecret, binderLabel, h0) + + // context = ClientHello[truncated] + // context = ClientHello1 + HelloRetryRequest + ClientHello2[truncated] + ctxHash := params.Hash.New() + ctxHash.Write(context) + + binder := computeFinishedData(params, binderKey, ctxHash.Sum(nil)) + if !bytes.Equal(binder, binders[i].Binder) { + logf(logTypeNegotiation, "Binder check failed for identity %x; [%x] != [%x]", psk.Identity, binder, binders[i].Binder) + return false, 0, nil, CipherSuiteParams{}, fmt.Errorf("Binder check failed identity %x", psk.Identity) + } + + logf(logTypeNegotiation, "Using PSK with identity %x", psk.Identity) + return true, i, &psk, params, nil + } + + logf(logTypeNegotiation, "Failed to find a usable PSK") + return false, 0, nil, CipherSuiteParams{}, nil +} + +func PSKModeNegotiation(canDoDH, canDoPSK bool, modes []PSKKeyExchangeMode) (bool, bool) { + logf(logTypeNegotiation, "Negotiating PSK modes [%v] [%v] [%+v]", canDoDH, canDoPSK, modes) + dhAllowed := false + dhRequired := true + for _, mode := range modes { + dhAllowed = dhAllowed || (mode == PSKModeDHEKE) + dhRequired = dhRequired && (mode == PSKModeDHEKE) + } + + // Use PSK if we can meet DH requirement and modes were provided + usingPSK := canDoPSK && (!dhRequired || canDoDH) && (len(modes) > 0) + + // Use DH if allowed + usingDH := canDoDH && (dhAllowed || !usingPSK) + + logf(logTypeNegotiation, "Results of PSK mode negotiation: usingDH=[%v] usingPSK=[%v]", usingDH, usingPSK) + return usingDH, usingPSK +} + +func CertificateSelection(serverName *string, signatureSchemes []SignatureScheme, certs []*Certificate) (*Certificate, SignatureScheme, error) { + // Select for server name if provided + candidates := certs + if serverName != nil { + candidatesByName := []*Certificate{} + for _, cert := range certs { + for _, name := range cert.Chain[0].DNSNames { + if len(*serverName) > 0 && name == *serverName { + candidatesByName = append(candidatesByName, cert) + } + } + } + + if len(candidatesByName) == 0 { + return nil, 0, fmt.Errorf("No certificates available for server name: %s", *serverName) + } + + candidates = candidatesByName + } + + // Select for signature scheme + for _, cert := range candidates { + for _, scheme := range signatureSchemes { + if !schemeValidForKey(scheme, cert.PrivateKey) { + continue + } + + return cert, scheme, nil + } + } + + return nil, 0, fmt.Errorf("No certificates compatible with signature schemes") +} + +func EarlyDataNegotiation(usingPSK, gotEarlyData, allowEarlyData bool) (using bool, rejected bool) { + using = gotEarlyData && usingPSK && allowEarlyData + rejected = gotEarlyData && !using + logf(logTypeNegotiation, "Early data negotiation (%v, %v, %v) => %v, %v", usingPSK, gotEarlyData, allowEarlyData, using, rejected) + return +} + +func CipherSuiteNegotiation(psk *PreSharedKey, offered, supported []CipherSuite) (CipherSuite, error) { + for _, s1 := range offered { + if psk != nil { + if s1 == psk.CipherSuite { + return s1, nil + } + continue + } + + for _, s2 := range supported { + if s1 == s2 { + return s1, nil + } + } + } + + return 0, fmt.Errorf("No overlap between offered and supproted ciphersuites (psk? [%v])", psk != nil) +} + +func ALPNNegotiation(psk *PreSharedKey, offered, supported []string) (string, error) { + for _, p1 := range offered { + if psk != nil { + if p1 != psk.NextProto { + continue + } + } + + for _, p2 := range supported { + if p1 == p2 { + return p1, nil + } + } + } + + // If the client offers ALPN on resumption, it must match the earlier one + var err error + if psk != nil && psk.IsResumption && (len(offered) > 0) { + err = fmt.Errorf("ALPN for PSK not provided") + } + return "", err +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/record-layer.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/record-layer.go new file mode 100644 index 00000000..5cf8ae2c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/record-layer.go @@ -0,0 +1,458 @@ +package mint + +import ( + "crypto/cipher" + "fmt" + "io" + "sync" +) + +const ( + sequenceNumberLen = 8 // sequence number length + recordHeaderLenTLS = 5 // record header length (TLS) + recordHeaderLenDTLS = 13 // record header length (DTLS) + maxFragmentLen = 1 << 14 // max number of bytes in a record +) + +type DecryptError string + +func (err DecryptError) Error() string { + return string(err) +} + +type direction uint8 + +const ( + directionWrite = direction(1) + directionRead = direction(2) +) + +// struct { +// ContentType type; +// ProtocolVersion record_version [0301 for CH, 0303 for others] +// uint16 length; +// opaque fragment[TLSPlaintext.length]; +// } TLSPlaintext; +type TLSPlaintext struct { + // Omitted: record_version (static) + // Omitted: length (computed from fragment) + contentType RecordType + epoch Epoch + seq uint64 + fragment []byte +} + +type cipherState struct { + epoch Epoch // DTLS epoch + ivLength int // Length of the seq and nonce fields + seq uint64 // Zero-padded sequence number + iv []byte // Buffer for the IV + cipher cipher.AEAD // AEAD cipher +} + +type RecordLayer struct { + sync.Mutex + label string + direction direction + version uint16 // The current version number + conn io.ReadWriter // The underlying connection + frame *frameReader // The buffered frame reader + nextData []byte // The next record to send + cachedRecord *TLSPlaintext // Last record read, cached to enable "peek" + cachedError error // Error on the last record read + + cipher *cipherState + readCiphers map[Epoch]*cipherState + + datagram bool +} + +type recordLayerFrameDetails struct { + datagram bool +} + +func (d recordLayerFrameDetails) headerLen() int { + if d.datagram { + return recordHeaderLenDTLS + } + return recordHeaderLenTLS +} + +func (d recordLayerFrameDetails) defaultReadLen() int { + return d.headerLen() + maxFragmentLen +} + +func (d recordLayerFrameDetails) frameLen(hdr []byte) (int, error) { + return (int(hdr[d.headerLen()-2]) << 8) | int(hdr[d.headerLen()-1]), nil +} + +func newCipherStateNull() *cipherState { + return &cipherState{EpochClear, 0, 0, nil, nil} +} + +func newCipherStateAead(epoch Epoch, factory aeadFactory, key []byte, iv []byte) (*cipherState, error) { + cipher, err := factory(key) + if err != nil { + return nil, err + } + + return &cipherState{epoch, len(iv), 0, iv, cipher}, nil +} + +func NewRecordLayerTLS(conn io.ReadWriter, dir direction) *RecordLayer { + r := RecordLayer{} + r.label = "" + r.direction = dir + r.conn = conn + r.frame = newFrameReader(recordLayerFrameDetails{false}) + r.cipher = newCipherStateNull() + r.version = tls10Version + return &r +} + +func NewRecordLayerDTLS(conn io.ReadWriter, dir direction) *RecordLayer { + r := RecordLayer{} + r.label = "" + r.direction = dir + r.conn = conn + r.frame = newFrameReader(recordLayerFrameDetails{true}) + r.cipher = newCipherStateNull() + r.readCiphers = make(map[Epoch]*cipherState, 0) + r.readCiphers[0] = r.cipher + r.datagram = true + return &r +} + +func (r *RecordLayer) SetVersion(v uint16) { + r.version = v +} + +func (r *RecordLayer) ResetClear(seq uint64) { + r.cipher = newCipherStateNull() + r.cipher.seq = seq +} + +func (r *RecordLayer) Rekey(epoch Epoch, factory aeadFactory, key []byte, iv []byte) error { + cipher, err := newCipherStateAead(epoch, factory, key, iv) + if err != nil { + return err + } + r.cipher = cipher + if r.datagram && r.direction == directionRead { + r.readCiphers[epoch] = cipher + } + return nil +} + +// TODO(ekr@rtfm.com): This is never used, which is a bug. +func (r *RecordLayer) DiscardReadKey(epoch Epoch) { + if !r.datagram { + return + } + + _, ok := r.readCiphers[epoch] + assert(ok) + delete(r.readCiphers, epoch) +} + +func (c *cipherState) combineSeq(datagram bool) uint64 { + seq := c.seq + if datagram { + seq |= uint64(c.epoch) << 48 + } + return seq +} + +func (c *cipherState) computeNonce(seq uint64) []byte { + nonce := make([]byte, len(c.iv)) + copy(nonce, c.iv) + + s := seq + + offset := len(c.iv) + for i := 0; i < 8; i++ { + nonce[(offset-i)-1] ^= byte(s & 0xff) + s >>= 8 + } + logf(logTypeCrypto, "Computing nonce for sequence # %x -> %x", seq, nonce) + + return nonce +} + +func (c *cipherState) incrementSequenceNumber() { + if c.seq >= (1<<48 - 1) { + // Not allowed to let sequence number wrap. + // Instead, must renegotiate before it does. + // Not likely enough to bother. This is the + // DTLS limit. + panic("TLS: sequence number wraparound") + } + c.seq++ +} + +func (c *cipherState) overhead() int { + if c.cipher == nil { + return 0 + } + return c.cipher.Overhead() +} + +func (r *RecordLayer) encrypt(cipher *cipherState, seq uint64, pt *TLSPlaintext, padLen int) *TLSPlaintext { + assert(r.direction == directionWrite) + logf(logTypeIO, "%s Encrypt seq=[%x]", r.label, seq) + // Expand the fragment to hold contentType, padding, and overhead + originalLen := len(pt.fragment) + plaintextLen := originalLen + 1 + padLen + ciphertextLen := plaintextLen + cipher.overhead() + + // Assemble the revised plaintext + out := &TLSPlaintext{ + + contentType: RecordTypeApplicationData, + fragment: make([]byte, ciphertextLen), + } + copy(out.fragment, pt.fragment) + out.fragment[originalLen] = byte(pt.contentType) + for i := 1; i <= padLen; i++ { + out.fragment[originalLen+i] = 0 + } + + // Encrypt the fragment + payload := out.fragment[:plaintextLen] + cipher.cipher.Seal(payload[:0], cipher.computeNonce(seq), payload, nil) + return out +} + +func (r *RecordLayer) decrypt(pt *TLSPlaintext, seq uint64) (*TLSPlaintext, int, error) { + assert(r.direction == directionRead) + logf(logTypeIO, "%s Decrypt seq=[%x]", r.label, seq) + if len(pt.fragment) < r.cipher.overhead() { + msg := fmt.Sprintf("tls.record.decrypt: Record too short [%d] < [%d]", len(pt.fragment), r.cipher.overhead()) + return nil, 0, DecryptError(msg) + } + + decryptLen := len(pt.fragment) - r.cipher.overhead() + out := &TLSPlaintext{ + contentType: pt.contentType, + fragment: make([]byte, decryptLen), + } + + // Decrypt + _, err := r.cipher.cipher.Open(out.fragment[:0], r.cipher.computeNonce(seq), pt.fragment, nil) + if err != nil { + logf(logTypeIO, "%s AEAD decryption failure [%x]", r.label, pt) + return nil, 0, DecryptError("tls.record.decrypt: AEAD decrypt failed") + } + + // Find the padding boundary + padLen := 0 + for ; padLen < decryptLen+1 && out.fragment[decryptLen-padLen-1] == 0; padLen++ { + } + + // Transfer the content type + newLen := decryptLen - padLen - 1 + out.contentType = RecordType(out.fragment[newLen]) + + // Truncate the message to remove contentType, padding, overhead + out.fragment = out.fragment[:newLen] + out.seq = seq + return out, padLen, nil +} + +func (r *RecordLayer) PeekRecordType(block bool) (RecordType, error) { + var pt *TLSPlaintext + var err error + + for { + pt, err = r.nextRecord(false) + if err == nil { + break + } + if !block || err != AlertWouldBlock { + return 0, err + } + } + return pt.contentType, nil +} + +func (r *RecordLayer) ReadRecord() (*TLSPlaintext, error) { + pt, err := r.nextRecord(false) + + // Consume the cached record if there was one + r.cachedRecord = nil + r.cachedError = nil + + return pt, err +} + +func (r *RecordLayer) readRecordAnyEpoch() (*TLSPlaintext, error) { + pt, err := r.nextRecord(true) + + // Consume the cached record if there was one + r.cachedRecord = nil + r.cachedError = nil + + return pt, err +} + +func (r *RecordLayer) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) { + cipher := r.cipher + if r.cachedRecord != nil { + logf(logTypeIO, "%s Returning cached record", r.label) + return r.cachedRecord, r.cachedError + } + + // Loop until one of three things happens: + // + // 1. We get a frame + // 2. We try to read off the socket and get nothing, in which case + // returnAlertWouldBlock + // 3. We get an error. + var err error + err = AlertWouldBlock + var header, body []byte + + for err != nil { + if r.frame.needed() > 0 { + buf := make([]byte, r.frame.details.headerLen()+maxFragmentLen) + n, err := r.conn.Read(buf) + if err != nil { + logf(logTypeIO, "%s Error reading, %v", r.label, err) + return nil, err + } + + if n == 0 { + return nil, AlertWouldBlock + } + + logf(logTypeIO, "%s Read %v bytes", r.label, n) + + buf = buf[:n] + r.frame.addChunk(buf) + } + + header, body, err = r.frame.process() + // Loop around onAlertWouldBlock to see if some + // data is now available. + if err != nil && err != AlertWouldBlock { + return nil, err + } + } + + pt := &TLSPlaintext{} + // Validate content type + switch RecordType(header[0]) { + default: + return nil, fmt.Errorf("tls.record: Unknown content type %02x", header[0]) + case RecordTypeAlert, RecordTypeHandshake, RecordTypeApplicationData, RecordTypeAck: + pt.contentType = RecordType(header[0]) + } + + // Validate version + if !allowWrongVersionNumber && (header[1] != 0x03 || header[2] != 0x01) { + return nil, fmt.Errorf("tls.record: Invalid version %02x%02x", header[1], header[2]) + } + + // Validate size < max + size := (int(header[len(header)-2]) << 8) + int(header[len(header)-1]) + + if size > maxFragmentLen+256 { + return nil, fmt.Errorf("tls.record: Ciphertext size too big") + } + + pt.fragment = make([]byte, size) + copy(pt.fragment, body) + + // TODO(ekr@rtfm.com): Enforce that for epoch > 0, the content type is app data. + + // Attempt to decrypt fragment + seq := cipher.seq + if r.datagram { + // TODO(ekr@rtfm.com): Handle duplicates. + seq, _ = decodeUint(header[3:11], 8) + epoch := Epoch(seq >> 48) + + // Look up the cipher suite from the epoch + c, ok := r.readCiphers[epoch] + if !ok { + logf(logTypeIO, "%s Message from unknown epoch: [%v]", r.label, epoch) + return nil, AlertWouldBlock + } + + if epoch != cipher.epoch { + logf(logTypeIO, "%s Message from non-current epoch: [%v != %v] out-of-epoch reads=%v", r.label, epoch, + cipher.epoch, allowOldEpoch) + if !allowOldEpoch { + return nil, AlertWouldBlock + } + cipher = c + } + } + + if cipher.cipher != nil { + logf(logTypeIO, "%s RecordLayer.ReadRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), seq, pt.contentType, pt.fragment) + pt, _, err = r.decrypt(pt, seq) + if err != nil { + logf(logTypeIO, "%s Decryption failed", r.label) + return nil, err + } + } + pt.epoch = cipher.epoch + + // Check that plaintext length is not too long + if len(pt.fragment) > maxFragmentLen { + return nil, fmt.Errorf("tls.record: Plaintext size too big") + } + + logf(logTypeIO, "%s RecordLayer.ReadRecord [%d] [%x]", r.label, pt.contentType, pt.fragment) + + r.cachedRecord = pt + cipher.incrementSequenceNumber() + return pt, nil +} + +func (r *RecordLayer) WriteRecord(pt *TLSPlaintext) error { + return r.writeRecordWithPadding(pt, r.cipher, 0) +} + +func (r *RecordLayer) WriteRecordWithPadding(pt *TLSPlaintext, padLen int) error { + return r.writeRecordWithPadding(pt, r.cipher, padLen) +} + +func (r *RecordLayer) writeRecordWithPadding(pt *TLSPlaintext, cipher *cipherState, padLen int) error { + seq := cipher.combineSeq(r.datagram) + if cipher.cipher != nil { + logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] plaintext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment) + pt = r.encrypt(cipher, seq, pt, padLen) + } else if padLen > 0 { + return fmt.Errorf("tls.record: Padding can only be done on encrypted records") + } + + if len(pt.fragment) > maxFragmentLen { + return fmt.Errorf("tls.record: Record size too big") + } + + length := len(pt.fragment) + var header []byte + + if !r.datagram { + header = []byte{byte(pt.contentType), + byte(r.version >> 8), byte(r.version & 0xff), + byte(length >> 8), byte(length)} + } else { + header = make([]byte, 13) + version := dtlsConvertVersion(r.version) + copy(header, []byte{byte(pt.contentType), + byte(version >> 8), byte(version & 0xff), + }) + encodeUint(seq, 8, header[3:]) + encodeUint(uint64(length), 2, header[11:]) + } + record := append(header, pt.fragment...) + + logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment) + + cipher.incrementSequenceNumber() + _, err := r.conn.Write(record) + return err +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/server-state-machine.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/server-state-machine.go new file mode 100644 index 00000000..f91b22e4 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/server-state-machine.go @@ -0,0 +1,1177 @@ +package mint + +import ( + "bytes" + "crypto/x509" + "fmt" + "hash" + "reflect" + + "github.com/bifurcation/mint/syntax" +) + +// Server State Machine +// +// START <-----+ +// Recv ClientHello | | Send HelloRetryRequest +// v | +// RECVD_CH ----+ +// | Select parameters +// | Send ServerHello +// v +// NEGOTIATED +// | Send EncryptedExtensions +// | [Send CertificateRequest] +// Can send | [Send Certificate + CertificateVerify] +// app data --> | Send Finished +// after here | +// +-----------+--------+ +// | | | +// Rejected 0-RTT | No | | 0-RTT +// | 0-RTT | | +// | | v +// +---->READ_PAST | WAIT_EOED <---+ +// Decrypt | | | Decrypt | Recv | | | Recv +// error | | | OK + HS | EOED | | | early data +// +-----+ | V | +-----+ +// +---> WAIT_FLIGHT2 <-+ +// | +// +--------+--------+ +// No auth | | Client auth +// | | +// | v +// | WAIT_CERT +// | Recv | | Recv Certificate +// | empty | v +// | Certificate | WAIT_CV +// | | | Recv +// | v | CertificateVerify +// +-> WAIT_FINISHED <---+ +// | Recv Finished +// v +// CONNECTED +// +// NB: Not using state RECVD_CH +// +// State Instructions +// START {} +// NEGOTIATED Send(SH); [RekeyIn;] RekeyOut; Send(EE); [Send(CertReq);] [Send(Cert); Send(CV)] +// WAIT_EOED RekeyIn; +// READ_PAST {} +// WAIT_FLIGHT2 {} +// WAIT_CERT_CR {} +// WAIT_CERT {} +// WAIT_CV {} +// WAIT_FINISHED RekeyIn; RekeyOut; +// CONNECTED StoreTicket || (RekeyIn; [RekeyOut]) + +// A cookie can be sent to the client in a HRR. +type cookie struct { + // The CipherSuite that was selected when the client sent the first ClientHello + CipherSuite CipherSuite + ClientHelloHash []byte `tls:"head=2"` + + // The ApplicationCookie can be provided by the application (by setting a Config.CookieHandler) + ApplicationCookie []byte `tls:"head=2"` +} + +type serverStateStart struct { + Config *Config + conn *Conn + hsCtx *HandshakeContext +} + +var _ HandshakeState = &serverStateStart{} + +func (state serverStateStart) State() State { + return StateServerStart +} + +func (state serverStateStart) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeClientHello { + logf(logTypeHandshake, "[ServerStateStart] unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + ch := &ClientHelloBody{LegacyVersion: wireVersion(state.hsCtx.hIn)} + if err := safeUnmarshal(ch, hm.body); err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error decoding message: %v", err) + return nil, nil, AlertDecodeError + } + + // We are strict about these things because we only support 1.3 + if ch.LegacyVersion != wireVersion(state.hsCtx.hIn) { + logf(logTypeHandshake, "[ServerStateStart] Invalid version number: %v", ch.LegacyVersion) + return nil, nil, AlertDecodeError + } + + clientHello := hm + connParams := ConnectionParameters{} + + supportedVersions := &SupportedVersionsExtension{HandshakeType: HandshakeTypeClientHello} + serverName := new(ServerNameExtension) + supportedGroups := new(SupportedGroupsExtension) + signatureAlgorithms := new(SignatureAlgorithmsExtension) + clientKeyShares := &KeyShareExtension{HandshakeType: HandshakeTypeClientHello} + clientPSK := &PreSharedKeyExtension{HandshakeType: HandshakeTypeClientHello} + clientEarlyData := &EarlyDataExtension{} + clientALPN := new(ALPNExtension) + clientPSKModes := new(PSKKeyExchangeModesExtension) + clientCookie := new(CookieExtension) + + // Handle external extensions. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Receive(HandshakeTypeClientHello, &ch.Extensions) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error running external extension handler [%v]", err) + return nil, nil, AlertInternalError + } + } + + foundExts, err := ch.Extensions.Parse( + []ExtensionBody{ + supportedVersions, + serverName, + supportedGroups, + signatureAlgorithms, + clientEarlyData, + clientKeyShares, + clientPSK, + clientALPN, + clientPSKModes, + clientCookie, + }) + + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error parsing extensions [%v]", err) + return nil, nil, AlertDecodeError + } + + clientSentCookie := len(clientCookie.Cookie) > 0 + + if foundExts[ExtensionTypeServerName] { + connParams.ServerName = string(*serverName) + } + + // If the client didn't send supportedVersions or doesn't support 1.3, + // then we're done here. + if !foundExts[ExtensionTypeSupportedVersions] { + logf(logTypeHandshake, "[ServerStateStart] Client did not send supported_versions") + return nil, nil, AlertProtocolVersion + } + versionOK, _ := VersionNegotiation(supportedVersions.Versions, []uint16{supportedVersion}) + if !versionOK { + logf(logTypeHandshake, "[ServerStateStart] Client does not support the same version") + return nil, nil, AlertProtocolVersion + } + + // The client sent a cookie. So this is probably the second ClientHello (sent as a response to a HRR) + var firstClientHello *HandshakeMessage + var initialCipherSuite CipherSuiteParams // the cipher suite that was negotiated when sending the HelloRetryRequest + if clientSentCookie { + plainCookie, err := state.Config.CookieProtector.DecodeToken(clientCookie.Cookie) + if err != nil { + logf(logTypeHandshake, fmt.Sprintf("[ServerStateStart] Error decoding token [%v]", err)) + return nil, nil, AlertDecryptError + } + cookie := &cookie{} + if rb, err := syntax.Unmarshal(plainCookie, cookie); err != nil && rb != len(plainCookie) { // this should never happen + logf(logTypeHandshake, fmt.Sprintf("[ServerStateStart] Error unmarshaling cookie [%v]", err)) + return nil, nil, AlertInternalError + } + // restore the hash of initial ClientHello from the cookie + firstClientHello = &HandshakeMessage{ + msgType: HandshakeTypeMessageHash, + body: cookie.ClientHelloHash, + } + // have the application validate its part of the cookie + if state.Config.CookieHandler != nil && !state.Config.CookieHandler.Validate(state.conn, cookie.ApplicationCookie) { + logf(logTypeHandshake, "[ServerStateStart] Cookie mismatch") + return nil, nil, AlertAccessDenied + } + var ok bool + initialCipherSuite, ok = cipherSuiteMap[cookie.CipherSuite] + if !ok { + logf(logTypeHandshake, fmt.Sprintf("[ServerStateStart] Cookie contained invalid cipher suite: %#x", cookie.CipherSuite)) + return nil, nil, AlertInternalError + } + } + + if len(ch.LegacySessionID) != 0 && len(ch.LegacySessionID) != 32 { + logf(logTypeHandshake, "[ServerStateStart] invalid session ID") + return nil, nil, AlertIllegalParameter + } + + // Figure out if we can do DH + canDoDH, dhGroup, dhPublic, dhSecret := DHNegotiation(clientKeyShares.Shares, state.Config.Groups) + + // Figure out if we can do PSK + var canDoPSK bool + var selectedPSK int + var params CipherSuiteParams + var psk *PreSharedKey + if len(clientPSK.Identities) > 0 { + contextBase := []byte{} + if clientSentCookie { + contextBase = append(contextBase, firstClientHello.Marshal()...) + // fill in the cookie sent by the client. Needed to calculate the correct hash + cookieExt := &CookieExtension{Cookie: clientCookie.Cookie} + hrr, err := state.generateHRR(params.Suite, + ch.LegacySessionID, cookieExt) + if err != nil { + return nil, nil, AlertInternalError + } + contextBase = append(contextBase, hrr.Marshal()...) + } + chTrunc, err := ch.Truncated() + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error computing truncated ClientHello [%v]", err) + return nil, nil, AlertDecodeError + } + context := append(contextBase, chTrunc...) + + canDoPSK, selectedPSK, psk, params, err = PSKNegotiation(clientPSK.Identities, clientPSK.Binders, context, state.Config.PSKs) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error in PSK negotiation [%v]", err) + return nil, nil, AlertInternalError + } + } + + // Figure out if we actually should do DH / PSK + connParams.UsingDH, connParams.UsingPSK = PSKModeNegotiation(canDoDH, canDoPSK, clientPSKModes.KEModes) + + // Select a ciphersuite + connParams.CipherSuite, err = CipherSuiteNegotiation(psk, ch.CipherSuites, state.Config.CipherSuites) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] No common ciphersuite found [%v]", err) + return nil, nil, AlertHandshakeFailure + } + if clientSentCookie && initialCipherSuite.Suite != connParams.CipherSuite { + logf(logTypeHandshake, "[ServerStateStart] Would have selected a different CipherSuite after receiving the client's Cookie") + return nil, nil, AlertInternalError + } + + var helloRetryRequest *HandshakeMessage + if state.Config.RequireCookie { + // Send a cookie if required + // NB: Need to do this here because it's after ciphersuite selection, which + // has to be after PSK selection. + var shouldSendHRR bool + var cookieExt *CookieExtension + if !clientSentCookie { // this is the first ClientHello that we receive + var appCookie []byte + if state.Config.CookieHandler == nil { // if Config.RequireCookie is set, but no CookieHandler was provided, we definitely need to send a cookie + shouldSendHRR = true + } else { // if the CookieHandler was set, we just send a cookie when the application provides one + var err error + appCookie, err = state.Config.CookieHandler.Generate(state.conn) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error generating cookie [%v]", err) + return nil, nil, AlertInternalError + } + shouldSendHRR = appCookie != nil + } + if shouldSendHRR { + params := cipherSuiteMap[connParams.CipherSuite] + h := params.Hash.New() + h.Write(clientHello.Marshal()) + plainCookie, err := syntax.Marshal(cookie{ + CipherSuite: connParams.CipherSuite, + ClientHelloHash: h.Sum(nil), + ApplicationCookie: appCookie, + }) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error marshalling cookie [%v]", err) + return nil, nil, AlertInternalError + } + cookieData, err := state.Config.CookieProtector.NewToken(plainCookie) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error encoding cookie [%v]", err) + return nil, nil, AlertInternalError + } + cookieExt = &CookieExtension{Cookie: cookieData} + } + } else { + cookieExt = &CookieExtension{Cookie: clientCookie.Cookie} + } + + // Generate a HRR. We will need it in both of the two cases: + // 1. We need to send a Cookie. Then this HRR will be sent on the wire + // 2. We need to validate a cookie. Then we need its hash + // Ignoring errors because everything here is newly constructed, so there + // shouldn't be marshal errors + if shouldSendHRR || clientSentCookie { + helloRetryRequest, err = state.generateHRR(connParams.CipherSuite, + ch.LegacySessionID, cookieExt) + if err != nil { + return nil, nil, AlertInternalError + } + } + + if shouldSendHRR { + toSend := []HandshakeAction{ + QueueHandshakeMessage{helloRetryRequest}, + SendQueuedHandshake{}, + } + logf(logTypeHandshake, "[ServerStateStart] -> [ServerStateStart]") + return state, toSend, AlertStatelessRetry + } + } + + // If we've got no entropy to make keys from, fail + if !connParams.UsingDH && !connParams.UsingPSK { + logf(logTypeHandshake, "[ServerStateStart] Neither DH nor PSK negotiated") + return nil, nil, AlertHandshakeFailure + } + + var pskSecret []byte + var cert *Certificate + var certScheme SignatureScheme + if connParams.UsingPSK { + pskSecret = psk.Key + } else { + psk = nil + + // If we're not using a PSK mode, then we need to have certain extensions + if !(foundExts[ExtensionTypeServerName] && + foundExts[ExtensionTypeSupportedGroups] && + foundExts[ExtensionTypeSignatureAlgorithms]) { + logf(logTypeHandshake, "[ServerStateStart] Insufficient extensions (%v)", foundExts) + return nil, nil, AlertMissingExtension + } + + // Select a certificate + name := string(*serverName) + var err error + cert, certScheme, err = CertificateSelection(&name, signatureAlgorithms.Algorithms, state.Config.Certificates) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] No appropriate certificate found [%v]", err) + return nil, nil, AlertAccessDenied + } + } + + if !connParams.UsingDH { + dhSecret = nil + } + + // Figure out if we're going to do early data + var clientEarlyTrafficSecret []byte + connParams.ClientSendingEarlyData = foundExts[ExtensionTypeEarlyData] + connParams.UsingEarlyData, connParams.RejectedEarlyData = EarlyDataNegotiation(connParams.UsingPSK, foundExts[ExtensionTypeEarlyData], state.Config.AllowEarlyData) + if connParams.UsingEarlyData { + h := params.Hash.New() + h.Write(clientHello.Marshal()) + chHash := h.Sum(nil) + + zero := bytes.Repeat([]byte{0}, params.Hash.Size()) + earlySecret := HkdfExtract(params.Hash, zero, pskSecret) + clientEarlyTrafficSecret = deriveSecret(params, earlySecret, labelEarlyTrafficSecret, chHash) + } + + // Select a next protocol + connParams.NextProto, err = ALPNNegotiation(psk, clientALPN.Protocols, state.Config.NextProtos) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] No common application-layer protocol found [%v]", err) + return nil, nil, AlertNoApplicationProtocol + } + + state.hsCtx.receivedEndOfFlight() + + logf(logTypeHandshake, "[ServerStateStart] -> [ServerStateNegotiated]") + state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2. + return serverStateNegotiated{ + Config: state.Config, + Params: connParams, + hsCtx: state.hsCtx, + dhGroup: dhGroup, + dhPublic: dhPublic, + dhSecret: dhSecret, + pskSecret: pskSecret, + selectedPSK: selectedPSK, + cert: cert, + certScheme: certScheme, + legacySessionId: ch.LegacySessionID, + clientEarlyTrafficSecret: clientEarlyTrafficSecret, + + firstClientHello: firstClientHello, + helloRetryRequest: helloRetryRequest, + clientHello: clientHello, + }, nil, AlertNoAlert +} + +func (state *serverStateStart) generateHRR(cs CipherSuite, legacySessionId []byte, + cookieExt *CookieExtension) (*HandshakeMessage, error) { + var helloRetryRequest *HandshakeMessage + hrr := &ServerHelloBody{ + Version: tls12Version, + Random: hrrRandomSentinel, + CipherSuite: cs, + LegacySessionID: legacySessionId, + LegacyCompressionMethod: 0, + } + + sv := &SupportedVersionsExtension{ + HandshakeType: HandshakeTypeServerHello, + Versions: []uint16{supportedVersion}, + } + + if err := hrr.Extensions.Add(sv); err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error adding SupportedVersion [%v]", err) + return nil, err + } + + if err := hrr.Extensions.Add(cookieExt); err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error adding CookieExtension [%v]", err) + return nil, err + } + // Run the external extension handler. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Send(HandshakeTypeHelloRetryRequest, &hrr.Extensions) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error running external extension sender [%v]", err) + return nil, err + } + } + helloRetryRequest, err := state.hsCtx.hOut.HandshakeMessageFromBody(hrr) + if err != nil { + logf(logTypeHandshake, "[ServerStateStart] Error marshaling HRR [%v]", err) + return nil, err + } + return helloRetryRequest, nil +} + +type serverStateNegotiated struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + dhGroup NamedGroup + dhPublic []byte + dhSecret []byte + pskSecret []byte + clientEarlyTrafficSecret []byte + selectedPSK int + cert *Certificate + certScheme SignatureScheme + legacySessionId []byte + firstClientHello *HandshakeMessage + helloRetryRequest *HandshakeMessage + clientHello *HandshakeMessage +} + +var _ HandshakeState = &serverStateNegotiated{} + +func (state serverStateNegotiated) State() State { + return StateServerNegotiated +} + +func (state serverStateNegotiated) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + // Create the ServerHello + sh := &ServerHelloBody{ + Version: tls12Version, + CipherSuite: state.Params.CipherSuite, + LegacySessionID: state.legacySessionId, + LegacyCompressionMethod: 0, + } + if _, err := prng.Read(sh.Random[:]); err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error creating server random [%v]", err) + return nil, nil, AlertInternalError + } + + err := sh.Extensions.Add(&SupportedVersionsExtension{ + HandshakeType: HandshakeTypeServerHello, + Versions: []uint16{supportedVersion}, + }) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error adding supported_versions extension [%v]", err) + return nil, nil, AlertInternalError + } + if state.Params.UsingDH { + logf(logTypeHandshake, "[ServerStateNegotiated] sending DH extension") + err := sh.Extensions.Add(&KeyShareExtension{ + HandshakeType: HandshakeTypeServerHello, + Shares: []KeyShareEntry{{Group: state.dhGroup, KeyExchange: state.dhPublic}}, + }) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error adding key_shares extension [%v]", err) + return nil, nil, AlertInternalError + } + } + if state.Params.UsingPSK { + logf(logTypeHandshake, "[ServerStateNegotiated] sending PSK extension") + err := sh.Extensions.Add(&PreSharedKeyExtension{ + HandshakeType: HandshakeTypeServerHello, + SelectedIdentity: uint16(state.selectedPSK), + }) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error adding PSK extension [%v]", err) + return nil, nil, AlertInternalError + } + } + + // Run the external extension handler. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Send(HandshakeTypeServerHello, &sh.Extensions) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error running external extension sender [%v]", err) + return nil, nil, AlertInternalError + } + } + + serverHello, err := state.hsCtx.hOut.HandshakeMessageFromBody(sh) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error marshaling ServerHello [%v]", err) + return nil, nil, AlertInternalError + } + + // Look up crypto params + params, ok := cipherSuiteMap[sh.CipherSuite] + if !ok { + logf(logTypeCrypto, "Unsupported ciphersuite [%04x]", sh.CipherSuite) + return nil, nil, AlertHandshakeFailure + } + + // Start up the handshake hash + handshakeHash := params.Hash.New() + handshakeHash.Write(state.firstClientHello.Marshal()) + handshakeHash.Write(state.helloRetryRequest.Marshal()) + handshakeHash.Write(state.clientHello.Marshal()) + handshakeHash.Write(serverHello.Marshal()) + + // Compute handshake secrets + zero := bytes.Repeat([]byte{0}, params.Hash.Size()) + + var earlySecret []byte + if state.Params.UsingPSK { + earlySecret = HkdfExtract(params.Hash, zero, state.pskSecret) + } else { + earlySecret = HkdfExtract(params.Hash, zero, zero) + } + + if state.dhSecret == nil { + state.dhSecret = zero + } + + h0 := params.Hash.New().Sum(nil) + h2 := handshakeHash.Sum(nil) + preHandshakeSecret := deriveSecret(params, earlySecret, labelDerived, h0) + handshakeSecret := HkdfExtract(params.Hash, preHandshakeSecret, state.dhSecret) + clientHandshakeTrafficSecret := deriveSecret(params, handshakeSecret, labelClientHandshakeTrafficSecret, h2) + serverHandshakeTrafficSecret := deriveSecret(params, handshakeSecret, labelServerHandshakeTrafficSecret, h2) + preMasterSecret := deriveSecret(params, handshakeSecret, labelDerived, h0) + masterSecret := HkdfExtract(params.Hash, preMasterSecret, zero) + + logf(logTypeCrypto, "early secret (init!): [%d] %x", len(earlySecret), earlySecret) + logf(logTypeCrypto, "handshake secret: [%d] %x", len(handshakeSecret), handshakeSecret) + logf(logTypeCrypto, "client handshake traffic secret: [%d] %x", len(clientHandshakeTrafficSecret), clientHandshakeTrafficSecret) + logf(logTypeCrypto, "server handshake traffic secret: [%d] %x", len(serverHandshakeTrafficSecret), serverHandshakeTrafficSecret) + logf(logTypeCrypto, "master secret: [%d] %x", len(masterSecret), masterSecret) + + clientHandshakeKeys := makeTrafficKeys(params, clientHandshakeTrafficSecret) + serverHandshakeKeys := makeTrafficKeys(params, serverHandshakeTrafficSecret) + + // Send an EncryptedExtensions message (even if it's empty) + eeList := ExtensionList{} + if state.Params.NextProto != "" { + logf(logTypeHandshake, "[server] sending ALPN extension") + err = eeList.Add(&ALPNExtension{Protocols: []string{state.Params.NextProto}}) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error adding ALPN to EncryptedExtensions [%v]", err) + return nil, nil, AlertInternalError + } + } + if state.Params.UsingEarlyData { + logf(logTypeHandshake, "[server] sending EDI extension") + err = eeList.Add(&EarlyDataExtension{}) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error adding EDI to EncryptedExtensions [%v]", err) + return nil, nil, AlertInternalError + } + } + ee := &EncryptedExtensionsBody{eeList} + + // Run the external extension handler. + if state.Config.ExtensionHandler != nil { + err := state.Config.ExtensionHandler.Send(HandshakeTypeEncryptedExtensions, &ee.Extensions) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error running external extension sender [%v]", err) + return nil, nil, AlertInternalError + } + } + + eem, err := state.hsCtx.hOut.HandshakeMessageFromBody(ee) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error marshaling EncryptedExtensions [%v]", err) + return nil, nil, AlertInternalError + } + + handshakeHash.Write(eem.Marshal()) + + toSend := []HandshakeAction{ + QueueHandshakeMessage{serverHello}, + RekeyOut{epoch: EpochHandshakeData, KeySet: serverHandshakeKeys}, + QueueHandshakeMessage{eem}, + } + + // Authenticate with a certificate if required + if !state.Params.UsingPSK { + // Send a CertificateRequest message if we want client auth + if state.Config.RequireClientAuth { + state.Params.UsingClientAuth = true + + // XXX: We don't support sending any constraints besides a list of + // supported signature algorithms + cr := &CertificateRequestBody{} + schemes := &SignatureAlgorithmsExtension{Algorithms: state.Config.SignatureSchemes} + err := cr.Extensions.Add(schemes) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error adding supported schemes to CertificateRequest [%v]", err) + return nil, nil, AlertInternalError + } + + crm, err := state.hsCtx.hOut.HandshakeMessageFromBody(cr) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error marshaling CertificateRequest [%v]", err) + return nil, nil, AlertInternalError + } + //TODO state.state.serverCertificateRequest = cr + + toSend = append(toSend, QueueHandshakeMessage{crm}) + handshakeHash.Write(crm.Marshal()) + } + + // Create and send Certificate, CertificateVerify + certificate := &CertificateBody{ + CertificateList: make([]CertificateEntry, len(state.cert.Chain)), + } + for i, entry := range state.cert.Chain { + certificate.CertificateList[i] = CertificateEntry{CertData: entry} + } + certm, err := state.hsCtx.hOut.HandshakeMessageFromBody(certificate) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error marshaling Certificate [%v]", err) + return nil, nil, AlertInternalError + } + + toSend = append(toSend, QueueHandshakeMessage{certm}) + handshakeHash.Write(certm.Marshal()) + + certificateVerify := &CertificateVerifyBody{Algorithm: state.certScheme} + logf(logTypeHandshake, "Creating CertVerify: %04x %v", state.certScheme, params.Hash) + + hcv := handshakeHash.Sum(nil) + logf(logTypeHandshake, "Handshake Hash to be verified: [%d] %x", len(hcv), hcv) + + err = certificateVerify.Sign(state.cert.PrivateKey, hcv) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error signing CertificateVerify [%v]", err) + return nil, nil, AlertInternalError + } + certvm, err := state.hsCtx.hOut.HandshakeMessageFromBody(certificateVerify) + if err != nil { + logf(logTypeHandshake, "[ServerStateNegotiated] Error marshaling CertificateVerify [%v]", err) + return nil, nil, AlertInternalError + } + + toSend = append(toSend, QueueHandshakeMessage{certvm}) + handshakeHash.Write(certvm.Marshal()) + } + + // Compute secrets resulting from the server's first flight + h3 := handshakeHash.Sum(nil) + logf(logTypeCrypto, "handshake hash 3 [%d] %x", len(h3), h3) + logf(logTypeCrypto, "handshake hash for server Finished: [%d] %x", len(h3), h3) + + serverFinishedData := computeFinishedData(params, serverHandshakeTrafficSecret, h3) + logf(logTypeCrypto, "server finished data: [%d] %x", len(serverFinishedData), serverFinishedData) + + // Assemble the Finished message + fin := &FinishedBody{ + VerifyDataLen: len(serverFinishedData), + VerifyData: serverFinishedData, + } + finm, _ := state.hsCtx.hOut.HandshakeMessageFromBody(fin) + + toSend = append(toSend, QueueHandshakeMessage{finm}) + handshakeHash.Write(finm.Marshal()) + toSend = append(toSend, SendQueuedHandshake{}) + + // Compute traffic secrets + h4 := handshakeHash.Sum(nil) + logf(logTypeCrypto, "handshake hash 4 [%d] %x", len(h4), h4) + logf(logTypeCrypto, "handshake hash for server Finished: [%d] %x", len(h4), h4) + + clientTrafficSecret := deriveSecret(params, masterSecret, labelClientApplicationTrafficSecret, h4) + serverTrafficSecret := deriveSecret(params, masterSecret, labelServerApplicationTrafficSecret, h4) + logf(logTypeCrypto, "client traffic secret: [%d] %x", len(clientTrafficSecret), clientTrafficSecret) + logf(logTypeCrypto, "server traffic secret: [%d] %x", len(serverTrafficSecret), serverTrafficSecret) + + serverTrafficKeys := makeTrafficKeys(params, serverTrafficSecret) + toSend = append(toSend, RekeyOut{epoch: EpochApplicationData, KeySet: serverTrafficKeys}) + + exporterSecret := deriveSecret(params, masterSecret, labelExporterSecret, h4) + logf(logTypeCrypto, "server exporter secret: [%d] %x", len(exporterSecret), exporterSecret) + + if state.Params.UsingEarlyData { + clientEarlyTrafficKeys := makeTrafficKeys(params, state.clientEarlyTrafficSecret) + + logf(logTypeHandshake, "[ServerStateNegotiated] -> [ServerStateWaitEOED]") + nextState := serverStateWaitEOED{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: params, + handshakeHash: handshakeHash, + masterSecret: masterSecret, + clientHandshakeTrafficSecret: clientHandshakeTrafficSecret, + clientTrafficSecret: clientTrafficSecret, + serverTrafficSecret: serverTrafficSecret, + exporterSecret: exporterSecret, + } + toSend = append(toSend, []HandshakeAction{ + RekeyIn{epoch: EpochEarlyData, KeySet: clientEarlyTrafficKeys}, + }...) + return nextState, toSend, AlertNoAlert + } + + logf(logTypeHandshake, "[ServerStateNegotiated] -> [ServerStateWaitFlight2]") + toSend = append(toSend, []HandshakeAction{ + RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys}, + }...) + var nextState HandshakeState + nextState = serverStateWaitFlight2{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: params, + handshakeHash: handshakeHash, + masterSecret: masterSecret, + clientHandshakeTrafficSecret: clientHandshakeTrafficSecret, + clientTrafficSecret: clientTrafficSecret, + serverTrafficSecret: serverTrafficSecret, + exporterSecret: exporterSecret, + } + if state.Params.RejectedEarlyData { + nextState = serverStateReadPastEarlyData{ + hsCtx: state.hsCtx, + next: &nextState, + } + } + return nextState, toSend, AlertNoAlert +} + +type serverStateWaitEOED struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + masterSecret []byte + clientHandshakeTrafficSecret []byte + handshakeHash hash.Hash + clientTrafficSecret []byte + serverTrafficSecret []byte + exporterSecret []byte +} + +var _ HandshakeState = &serverStateWaitEOED{} + +func (state serverStateWaitEOED) State() State { + return StateServerWaitEOED +} + +func (state serverStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + for { + logf(logTypeHandshake, "Server reading early data...") + assert(state.hsCtx.hIn.conn.cipher.epoch == EpochEarlyData) + t, err := state.hsCtx.hIn.conn.PeekRecordType(!state.hsCtx.hIn.nonblocking) + if err == AlertWouldBlock { + return nil, nil, AlertWouldBlock + } + + if err != nil { + logf(logTypeHandshake, "Server Error reading record type (1): %v", err) + return nil, nil, AlertBadRecordMAC + } + + logf(logTypeHandshake, "Server got record type(1): %v", t) + + if t != RecordTypeApplicationData { + break + } + + // Read a record into the buffer. Note that this is safe + // in blocking mode because we read the record in + // PeekRecordType. + pt, err := state.hsCtx.hIn.conn.ReadRecord() + if err != nil { + logf(logTypeHandshake, "Server error reading early data record: %v", err) + return nil, nil, AlertInternalError + } + + logf(logTypeHandshake, "Server read early data: %x", pt.fragment) + state.hsCtx.earlyData = append(state.hsCtx.earlyData, pt.fragment...) + } + + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeEndOfEarlyData { + logf(logTypeHandshake, "[ServerStateWaitEOED] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + if len(hm.body) > 0 { + logf(logTypeHandshake, "[ServerStateWaitEOED] Error decoding message [len > 0]") + return nil, nil, AlertDecodeError + } + + state.handshakeHash.Write(hm.Marshal()) + + clientHandshakeKeys := makeTrafficKeys(state.cryptoParams, state.clientHandshakeTrafficSecret) + + logf(logTypeHandshake, "[ServerStateWaitEOED] -> [ServerStateWaitFlight2]") + toSend := []HandshakeAction{ + RekeyIn{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys}, + } + waitFlight2 := serverStateWaitFlight2{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + clientTrafficSecret: state.clientTrafficSecret, + serverTrafficSecret: state.serverTrafficSecret, + exporterSecret: state.exporterSecret, + } + return waitFlight2, toSend, AlertNoAlert +} + +var _ HandshakeState = &serverStateReadPastEarlyData{} + +type serverStateReadPastEarlyData struct { + hsCtx *HandshakeContext + next *HandshakeState +} + +func (state serverStateReadPastEarlyData) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + for { + logf(logTypeHandshake, "Server reading past early data...") + // Scan past all records that fail to decrypt + _, err := state.hsCtx.hIn.conn.PeekRecordType(!state.hsCtx.hIn.nonblocking) + if err == nil { + break + } + + if err == AlertWouldBlock { + return nil, nil, AlertWouldBlock + } + + // Continue on DecryptError + _, ok := err.(DecryptError) + if !ok { + return nil, nil, AlertInternalError // Really need something else. + } + } + + return *state.next, nil, AlertNoAlert +} + +func (state serverStateReadPastEarlyData) State() State { + return StateServerReadPastEarlyData +} + +type serverStateWaitFlight2 struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + masterSecret []byte + clientHandshakeTrafficSecret []byte + handshakeHash hash.Hash + clientTrafficSecret []byte + serverTrafficSecret []byte + exporterSecret []byte +} + +var _ HandshakeState = &serverStateWaitFlight2{} + +func (state serverStateWaitFlight2) State() State { + return StateServerWaitFlight2 +} + +func (state serverStateWaitFlight2) Next(_ handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + if state.Params.UsingClientAuth { + logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitCert]") + nextState := serverStateWaitCert{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + handshakeHash: state.handshakeHash, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + clientTrafficSecret: state.clientTrafficSecret, + serverTrafficSecret: state.serverTrafficSecret, + exporterSecret: state.exporterSecret, + } + return nextState, nil, AlertNoAlert + } + + logf(logTypeHandshake, "[ServerStateWaitFlight2] -> [ServerStateWaitFinished]") + nextState := serverStateWaitFinished{ + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + handshakeHash: state.handshakeHash, + clientTrafficSecret: state.clientTrafficSecret, + serverTrafficSecret: state.serverTrafficSecret, + exporterSecret: state.exporterSecret, + } + return nextState, nil, AlertNoAlert +} + +type serverStateWaitCert struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + masterSecret []byte + clientHandshakeTrafficSecret []byte + handshakeHash hash.Hash + clientTrafficSecret []byte + serverTrafficSecret []byte + exporterSecret []byte +} + +var _ HandshakeState = &serverStateWaitCert{} + +func (state serverStateWaitCert) State() State { + return StateServerWaitCert +} + +func (state serverStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeCertificate { + logf(logTypeHandshake, "[ServerStateWaitCert] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + cert := &CertificateBody{} + if err := safeUnmarshal(cert, hm.body); err != nil { + logf(logTypeHandshake, "[ServerStateWaitCert] Unexpected message") + return nil, nil, AlertDecodeError + } + + state.handshakeHash.Write(hm.Marshal()) + + if len(cert.CertificateList) == 0 { + logf(logTypeHandshake, "[ServerStateWaitCert] WARNING client did not provide a certificate") + + logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitFinished]") + nextState := serverStateWaitFinished{ + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + handshakeHash: state.handshakeHash, + clientTrafficSecret: state.clientTrafficSecret, + serverTrafficSecret: state.serverTrafficSecret, + exporterSecret: state.exporterSecret, + } + return nextState, nil, AlertNoAlert + } + + logf(logTypeHandshake, "[ServerStateWaitCert] -> [ServerStateWaitCV]") + nextState := serverStateWaitCV{ + Config: state.Config, + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + handshakeHash: state.handshakeHash, + clientTrafficSecret: state.clientTrafficSecret, + serverTrafficSecret: state.serverTrafficSecret, + clientCertificate: cert, + exporterSecret: state.exporterSecret, + } + return nextState, nil, AlertNoAlert +} + +type serverStateWaitCV struct { + Config *Config + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + + masterSecret []byte + clientHandshakeTrafficSecret []byte + + handshakeHash hash.Hash + clientTrafficSecret []byte + serverTrafficSecret []byte + exporterSecret []byte + + clientCertificate *CertificateBody +} + +var _ HandshakeState = &serverStateWaitCV{} + +func (state serverStateWaitCV) State() State { + return StateServerWaitCV +} + +func (state serverStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeCertificateVerify { + logf(logTypeHandshake, "[ServerStateWaitCV] Unexpected message [%+v] [%s]", hm, reflect.TypeOf(hm)) + return nil, nil, AlertUnexpectedMessage + } + + certVerify := &CertificateVerifyBody{} + if err := safeUnmarshal(certVerify, hm.body); err != nil { + logf(logTypeHandshake, "[ServerStateWaitCert] Error decoding message %v", err) + return nil, nil, AlertDecodeError + } + + rawCerts := make([][]byte, len(state.clientCertificate.CertificateList)) + certs := make([]*x509.Certificate, len(state.clientCertificate.CertificateList)) + for i, certEntry := range state.clientCertificate.CertificateList { + certs[i] = certEntry.CertData + rawCerts[i] = certEntry.CertData.Raw + } + + // Verify client signature over handshake hash + hcv := state.handshakeHash.Sum(nil) + logf(logTypeHandshake, "Handshake Hash to be verified: [%d] %x", len(hcv), hcv) + + clientPublicKey := state.clientCertificate.CertificateList[0].CertData.PublicKey + if err := certVerify.Verify(clientPublicKey, hcv); err != nil { + logf(logTypeHandshake, "[ServerStateWaitCV] Failure in client auth verification [%v]", err) + return nil, nil, AlertHandshakeFailure + } + + if state.Config.VerifyPeerCertificate != nil { + // TODO(#171): pass in the verified chains, once we support different client auth types + if err := state.Config.VerifyPeerCertificate(rawCerts, nil); err != nil { + logf(logTypeHandshake, "[ServerStateWaitCV] Application rejected client certificate: %s", err) + return nil, nil, AlertBadCertificate + } + } + + // If it passes, record the certificateVerify in the transcript hash + state.handshakeHash.Write(hm.Marshal()) + + logf(logTypeHandshake, "[ServerStateWaitCV] -> [ServerStateWaitFinished]") + nextState := serverStateWaitFinished{ + Params: state.Params, + hsCtx: state.hsCtx, + cryptoParams: state.cryptoParams, + masterSecret: state.masterSecret, + clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, + handshakeHash: state.handshakeHash, + clientTrafficSecret: state.clientTrafficSecret, + serverTrafficSecret: state.serverTrafficSecret, + exporterSecret: state.exporterSecret, + peerCertificates: certs, + verifiedChains: nil, // TODO(#171): set this value + } + return nextState, nil, AlertNoAlert +} + +type serverStateWaitFinished struct { + Params ConnectionParameters + hsCtx *HandshakeContext + cryptoParams CipherSuiteParams + + masterSecret []byte + clientHandshakeTrafficSecret []byte + peerCertificates []*x509.Certificate + verifiedChains [][]*x509.Certificate + + handshakeHash hash.Hash + clientTrafficSecret []byte + serverTrafficSecret []byte + exporterSecret []byte +} + +var _ HandshakeState = &serverStateWaitFinished{} + +func (state serverStateWaitFinished) State() State { + return StateServerWaitFinished +} + +func (state serverStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + hm, alert := hr.ReadMessage() + if alert != AlertNoAlert { + return nil, nil, alert + } + if hm == nil || hm.msgType != HandshakeTypeFinished { + logf(logTypeHandshake, "[ServerStateWaitFinished] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + fin := &FinishedBody{VerifyDataLen: state.cryptoParams.Hash.Size()} + if err := safeUnmarshal(fin, hm.body); err != nil { + logf(logTypeHandshake, "[ServerStateWaitFinished] Error decoding message %v", err) + return nil, nil, AlertDecodeError + } + + // Verify client Finished data + h5 := state.handshakeHash.Sum(nil) + logf(logTypeCrypto, "handshake hash for client Finished: [%d] %x", len(h5), h5) + + clientFinishedData := computeFinishedData(state.cryptoParams, state.clientHandshakeTrafficSecret, h5) + logf(logTypeCrypto, "client Finished data: [%d] %x", len(clientFinishedData), clientFinishedData) + + if !bytes.Equal(fin.VerifyData, clientFinishedData) { + logf(logTypeHandshake, "[ServerStateWaitFinished] Client's Finished failed to verify") + return nil, nil, AlertHandshakeFailure + } + + // Compute the resumption secret + state.handshakeHash.Write(hm.Marshal()) + h6 := state.handshakeHash.Sum(nil) + logf(logTypeCrypto, "handshake hash 6 [%d]: %x", len(h6), h6) + + resumptionSecret := deriveSecret(state.cryptoParams, state.masterSecret, labelResumptionSecret, h6) + logf(logTypeCrypto, "resumption secret: [%d] %x", len(resumptionSecret), resumptionSecret) + + // Compute client traffic keys + clientTrafficKeys := makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret) + + state.hsCtx.receivedFinalFlight() + + logf(logTypeHandshake, "[ServerStateWaitFinished] -> [StateConnected]") + nextState := stateConnected{ + Params: state.Params, + hsCtx: state.hsCtx, + isClient: false, + cryptoParams: state.cryptoParams, + resumptionSecret: resumptionSecret, + clientTrafficSecret: state.clientTrafficSecret, + serverTrafficSecret: state.serverTrafficSecret, + exporterSecret: state.exporterSecret, + peerCertificates: state.peerCertificates, + verifiedChains: state.verifiedChains, + } + toSend := []HandshakeAction{ + RekeyIn{epoch: EpochApplicationData, KeySet: clientTrafficKeys}, + } + return nextState, toSend, AlertNoAlert +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/state-machine.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/state-machine.go new file mode 100644 index 00000000..558b76cc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/state-machine.go @@ -0,0 +1,247 @@ +package mint + +import ( + "crypto/x509" + "time" +) + +// Marker interface for actions that an implementation should take based on +// state transitions. +type HandshakeAction interface{} + +type QueueHandshakeMessage struct { + Message *HandshakeMessage +} + +type SendQueuedHandshake struct{} + +type SendEarlyData struct{} + +type RekeyIn struct { + epoch Epoch + KeySet keySet +} + +type RekeyOut struct { + epoch Epoch + KeySet keySet +} + +type ResetOut struct { + seq uint64 +} + +type StorePSK struct { + PSK PreSharedKey +} + +type HandshakeState interface { + Next(handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) + State() State +} + +type AppExtensionHandler interface { + Send(hs HandshakeType, el *ExtensionList) error + Receive(hs HandshakeType, el *ExtensionList) error +} + +// ConnectionOptions objects represent per-connection settings for a client +// initiating a connection +type ConnectionOptions struct { + ServerName string + NextProtos []string +} + +// ConnectionParameters objects represent the parameters negotiated for a +// connection. +type ConnectionParameters struct { + UsingPSK bool + UsingDH bool + ClientSendingEarlyData bool + UsingEarlyData bool + RejectedEarlyData bool + UsingClientAuth bool + + CipherSuite CipherSuite + ServerName string + NextProto string +} + +// Working state for the handshake. +type HandshakeContext struct { + timeoutMS uint32 + timers *timerSet + recvdRecords []uint64 + sentFragments []*SentHandshakeFragment + hIn, hOut *HandshakeLayer + waitingNextFlight bool + earlyData []byte +} + +func (hc *HandshakeContext) SetVersion(version uint16) { + if hc.hIn.conn != nil { + hc.hIn.conn.SetVersion(version) + } + if hc.hOut.conn != nil { + hc.hOut.conn.SetVersion(version) + } +} + +// stateConnected is symmetric between client and server +type stateConnected struct { + Params ConnectionParameters + hsCtx *HandshakeContext + isClient bool + cryptoParams CipherSuiteParams + resumptionSecret []byte + clientTrafficSecret []byte + serverTrafficSecret []byte + exporterSecret []byte + peerCertificates []*x509.Certificate + verifiedChains [][]*x509.Certificate +} + +var _ HandshakeState = &stateConnected{} + +func (state stateConnected) State() State { + if state.isClient { + return StateClientConnected + } + return StateServerConnected +} + +func (state *stateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) { + var trafficKeys keySet + if state.isClient { + state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret, + labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size()) + trafficKeys = makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret) + } else { + state.serverTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.serverTrafficSecret, + labelServerApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size()) + trafficKeys = makeTrafficKeys(state.cryptoParams, state.serverTrafficSecret) + } + + kum, err := state.hsCtx.hOut.HandshakeMessageFromBody(&KeyUpdateBody{KeyUpdateRequest: request}) + if err != nil { + logf(logTypeHandshake, "[StateConnected] Error marshaling key update message: %v", err) + return nil, AlertInternalError + } + + toSend := []HandshakeAction{ + QueueHandshakeMessage{kum}, + SendQueuedHandshake{}, + RekeyOut{epoch: EpochUpdate, KeySet: trafficKeys}, + } + return toSend, AlertNoAlert +} + +func (state *stateConnected) NewSessionTicket(length int, lifetime, earlyDataLifetime uint32) ([]HandshakeAction, Alert) { + tkt, err := NewSessionTicket(length, lifetime) + if err != nil { + logf(logTypeHandshake, "[StateConnected] Error generating NewSessionTicket: %v", err) + return nil, AlertInternalError + } + + err = tkt.Extensions.Add(&TicketEarlyDataInfoExtension{earlyDataLifetime}) + if err != nil { + logf(logTypeHandshake, "[StateConnected] Error adding extension to NewSessionTicket: %v", err) + return nil, AlertInternalError + } + + resumptionKey := HkdfExpandLabel(state.cryptoParams.Hash, state.resumptionSecret, + labelResumption, tkt.TicketNonce, state.cryptoParams.Hash.Size()) + + newPSK := PreSharedKey{ + CipherSuite: state.cryptoParams.Suite, + IsResumption: true, + Identity: tkt.Ticket, + Key: resumptionKey, + NextProto: state.Params.NextProto, + ReceivedAt: time.Now(), + ExpiresAt: time.Now().Add(time.Duration(tkt.TicketLifetime) * time.Second), + TicketAgeAdd: tkt.TicketAgeAdd, + } + + tktm, err := state.hsCtx.hOut.HandshakeMessageFromBody(tkt) + if err != nil { + logf(logTypeHandshake, "[StateConnected] Error marshaling NewSessionTicket: %v", err) + return nil, AlertInternalError + } + + toSend := []HandshakeAction{ + StorePSK{newPSK}, + QueueHandshakeMessage{tktm}, + SendQueuedHandshake{}, + } + return toSend, AlertNoAlert +} + +// Next does nothing for this state. +func (state stateConnected) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) { + return state, nil, AlertNoAlert +} + +func (state stateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState, []HandshakeAction, Alert) { + if hm == nil { + logf(logTypeHandshake, "[StateConnected] Unexpected message") + return nil, nil, AlertUnexpectedMessage + } + + bodyGeneric, err := hm.ToBody() + if err != nil { + logf(logTypeHandshake, "[StateConnected] Error decoding message: %v", err) + return nil, nil, AlertDecodeError + } + + switch body := bodyGeneric.(type) { + case *KeyUpdateBody: + var trafficKeys keySet + if !state.isClient { + state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret, + labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size()) + trafficKeys = makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret) + } else { + state.serverTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.serverTrafficSecret, + labelServerApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size()) + trafficKeys = makeTrafficKeys(state.cryptoParams, state.serverTrafficSecret) + } + + toSend := []HandshakeAction{RekeyIn{epoch: EpochUpdate, KeySet: trafficKeys}} + + // If requested, roll outbound keys and send a KeyUpdate + if body.KeyUpdateRequest == KeyUpdateRequested { + logf(logTypeHandshake, "Received key update, update requested", body.KeyUpdateRequest) + moreToSend, alert := state.KeyUpdate(KeyUpdateNotRequested) + if alert != AlertNoAlert { + return nil, nil, alert + } + toSend = append(toSend, moreToSend...) + } + return state, toSend, AlertNoAlert + case *NewSessionTicketBody: + // XXX: Allow NewSessionTicket in both directions? + if !state.isClient { + return nil, nil, AlertUnexpectedMessage + } + + resumptionKey := HkdfExpandLabel(state.cryptoParams.Hash, state.resumptionSecret, + labelResumption, body.TicketNonce, state.cryptoParams.Hash.Size()) + psk := PreSharedKey{ + CipherSuite: state.cryptoParams.Suite, + IsResumption: true, + Identity: body.Ticket, + Key: resumptionKey, + NextProto: state.Params.NextProto, + ReceivedAt: time.Now(), + ExpiresAt: time.Now().Add(time.Duration(body.TicketLifetime) * time.Second), + TicketAgeAdd: body.TicketAgeAdd, + } + + toSend := []HandshakeAction{StorePSK{psk}} + return state, toSend, AlertNoAlert + } + + logf(logTypeHandshake, "[StateConnected] Unexpected message type %v", hm.msgType) + return nil, nil, AlertUnexpectedMessage +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/README.md b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/README.md new file mode 100644 index 00000000..dbf4ec2e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/README.md @@ -0,0 +1,74 @@ +TLS Syntax +========== + +TLS defines [its own syntax](https://tlswg.github.io/tls13-spec/#rfc.section.3) +for describing structures used in that protocol. To facilitate experimentation +with TLS in Go, this module maps that syntax to the Go structure syntax, taking +advantage of Go's type annotations to encode non-type information carried in the +TLS presentation format. + +For example, in the TLS specification, a ClientHello message has the following +structure: + +~~~~~ +uint16 ProtocolVersion; +opaque Random[32]; +uint8 CipherSuite[2]; +enum { ... (65535)} ExtensionType; + +struct { + ExtensionType extension_type; + opaque extension_data<0..2^16-1>; +} Extension; + +struct { + ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */ + Random random; + opaque legacy_session_id<0..32>; + CipherSuite cipher_suites<2..2^16-2>; + opaque legacy_compression_methods<1..2^8-1>; + Extension extensions<0..2^16-1>; +} ClientHello; +~~~~~ + +This maps to the following Go type definitions: + +~~~~~ +type protocolVersion uint16 +type random [32]byte +type cipherSuite uint16 // or [2]byte +type extensionType uint16 + +type extension struct { + ExtensionType extensionType + ExtensionData []byte `tls:"head=2"` +} + +type clientHello struct { + LegacyVersion protocolVersion + Random random + LegacySessionID []byte `tls:"head=1,max=32"` + CipherSuites []cipherSuite `tls:"head=2,min=2"` + LegacyCompressionMethods []byte `tls:"head=1,min=1"` + Extensions []extension `tls:"head=2"` +} +~~~~~ + +Then you can just declare, marshal, and unmarshal structs just like you would +with, say JSON. + +The available annotations right now are all related to vectors: + +* `head`: The number of bytes of length to use as a "header" +* `min`: The minimum length of the vector, in bytes +* `max`: The maximum length of the vector, in bytes + +## Not supported + +* The `select()` syntax for creating alternate version of the same struct (see, + e.g., the KeyShare extension) + +* The backreference syntax for array lengths or select parameters, as in `opaque + fragment[TLSPlaintext.length]`. Note, however, that in cases where the length + immediately preceds the array, these can be reframed as vectors with + appropriate sizes. diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/decode.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/decode.go new file mode 100644 index 00000000..92c036fc --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/decode.go @@ -0,0 +1,310 @@ +package syntax + +import ( + "bytes" + "fmt" + "reflect" + "runtime" +) + +func Unmarshal(data []byte, v interface{}) (int, error) { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + d := decodeState{} + d.Write(data) + return d.unmarshal(v) +} + +// Unmarshaler is the interface implemented by types that can +// unmarshal a TLS description of themselves. Note that unlike the +// JSON unmarshaler interface, it is not known a priori how much of +// the input data will be consumed. So the Unmarshaler must state +// how much of the input data it consumed. +type Unmarshaler interface { + UnmarshalTLS([]byte) (int, error) +} + +// These are the options that can be specified in the struct tag. Right now, +// all of them apply to variable-length vectors and nothing else +type decOpts struct { + head uint // length of length in bytes + min uint // minimum size in bytes + max uint // maximum size in bytes + varint bool // whether to decode as a varint +} + +type decodeState struct { + bytes.Buffer +} + +func (d *decodeState) unmarshal(v interface{}) (read int, err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + if s, ok := r.(string); ok { + panic(s) + } + err = r.(error) + } + }() + + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + return 0, fmt.Errorf("Invalid unmarshal target (non-pointer or nil)") + } + + read = d.value(rv) + return read, nil +} + +func (e *decodeState) value(v reflect.Value) int { + return valueDecoder(v)(e, v, decOpts{}) +} + +type decoderFunc func(e *decodeState, v reflect.Value, opts decOpts) int + +func valueDecoder(v reflect.Value) decoderFunc { + return typeDecoder(v.Type().Elem()) +} + +func typeDecoder(t reflect.Type) decoderFunc { + // Note: Omits the caching / wait-group things that encoding/json uses + return newTypeDecoder(t) +} + +var ( + unmarshalerType = reflect.TypeOf(new(Unmarshaler)).Elem() +) + +func newTypeDecoder(t reflect.Type) decoderFunc { + if t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(unmarshalerType) { + return unmarshalerDecoder + } + + switch t.Kind() { + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return uintDecoder + case reflect.Array: + return newArrayDecoder(t) + case reflect.Slice: + return newSliceDecoder(t) + case reflect.Struct: + return newStructDecoder(t) + case reflect.Ptr: + return newPointerDecoder(t) + default: + panic(fmt.Errorf("Unsupported type (%s)", t)) + } +} + +///// Specific decoders below + +func unmarshalerDecoder(d *decodeState, v reflect.Value, opts decOpts) int { + um, ok := v.Interface().(Unmarshaler) + if !ok { + panic(fmt.Errorf("Non-Unmarshaler passed to unmarshalerEncoder")) + } + + read, err := um.UnmarshalTLS(d.Bytes()) + if err != nil { + panic(err) + } + + if read > d.Len() { + panic(fmt.Errorf("Invalid return value from UnmarshalTLS")) + } + + d.Next(read) + return read +} + +////////// + +func uintDecoder(d *decodeState, v reflect.Value, opts decOpts) int { + if opts.varint { + return varintDecoder(d, v, opts) + } + + uintLen := int(v.Elem().Type().Size()) + buf := d.Next(uintLen) + if len(buf) != uintLen { + panic(fmt.Errorf("Insufficient data to read uint")) + } + + return setUintFromBuffer(v, buf) +} + +func varintDecoder(d *decodeState, v reflect.Value, opts decOpts) int { + // Read the first octet and decide the size of the presented varint + first := d.Next(1) + if len(first) != 1 { + panic(fmt.Errorf("Insufficient data to read varint length")) + } + + uintLen := int(v.Elem().Type().Size()) + twoBits := uint(first[0] >> 6) + varintLen := 1 << twoBits + + if uintLen < varintLen { + panic(fmt.Errorf("Uint too small to fit varint: %d < %d")) + } + + rest := d.Next(varintLen - 1) + if len(rest) != varintLen-1 { + panic(fmt.Errorf("Insufficient data to read varint")) + } + + buf := append(first, rest...) + buf[0] &= 0x3f + return setUintFromBuffer(v, buf) +} + +func setUintFromBuffer(v reflect.Value, buf []byte) int { + val := uint64(0) + for _, b := range buf { + val = (val << 8) + uint64(b) + } + + v.Elem().SetUint(val) + return len(buf) +} + +////////// + +type arrayDecoder struct { + elemDec decoderFunc +} + +func (ad *arrayDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int { + n := v.Elem().Type().Len() + read := 0 + for i := 0; i < n; i += 1 { + read += ad.elemDec(d, v.Elem().Index(i).Addr(), opts) + } + return read +} + +func newArrayDecoder(t reflect.Type) decoderFunc { + dec := &arrayDecoder{typeDecoder(t.Elem())} + return dec.decode +} + +////////// + +type sliceDecoder struct { + elementType reflect.Type + elementDec decoderFunc +} + +func (sd *sliceDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int { + if opts.head == 0 { + panic(fmt.Errorf("Cannot decode a slice without a header length")) + } + + lengthBytes := d.Next(int(opts.head)) + if len(lengthBytes) != int(opts.head) { + panic(fmt.Errorf("Not enough data to read header")) + } + + length := uint(0) + for _, b := range lengthBytes { + length = (length << 8) + uint(b) + } + + if opts.max > 0 && length > opts.max { + panic(fmt.Errorf("Length of vector exceeds declared max")) + } + if length < opts.min { + panic(fmt.Errorf("Length of vector below declared min")) + } + + data := d.Next(int(length)) + if len(data) != int(length) { + panic(fmt.Errorf("Available data less than declared length [%d < %d]", len(data), length)) + } + + elemBuf := &decodeState{} + elemBuf.Write(data) + elems := []reflect.Value{} + read := int(opts.head) + for elemBuf.Len() > 0 { + elem := reflect.New(sd.elementType) + read += sd.elementDec(elemBuf, elem, opts) + elems = append(elems, elem) + } + + v.Elem().Set(reflect.MakeSlice(v.Elem().Type(), len(elems), len(elems))) + for i := 0; i < len(elems); i += 1 { + v.Elem().Index(i).Set(elems[i].Elem()) + } + return read +} + +func newSliceDecoder(t reflect.Type) decoderFunc { + dec := &sliceDecoder{ + elementType: t.Elem(), + elementDec: typeDecoder(t.Elem()), + } + return dec.decode +} + +////////// + +type structDecoder struct { + fieldOpts []decOpts + fieldDecs []decoderFunc +} + +func (sd *structDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int { + read := 0 + for i := range sd.fieldDecs { + read += sd.fieldDecs[i](d, v.Elem().Field(i).Addr(), sd.fieldOpts[i]) + } + return read +} + +func newStructDecoder(t reflect.Type) decoderFunc { + n := t.NumField() + sd := structDecoder{ + fieldOpts: make([]decOpts, n), + fieldDecs: make([]decoderFunc, n), + } + + for i := 0; i < n; i += 1 { + f := t.Field(i) + + tag := f.Tag.Get("tls") + tagOpts := parseTag(tag) + + sd.fieldOpts[i] = decOpts{ + head: tagOpts["head"], + max: tagOpts["max"], + min: tagOpts["min"], + varint: tagOpts[varintOption] > 0, + } + + sd.fieldDecs[i] = typeDecoder(f.Type) + } + + return sd.decode +} + +////////// + +type pointerDecoder struct { + base decoderFunc +} + +func (pd *pointerDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int { + v.Elem().Set(reflect.New(v.Elem().Type().Elem())) + return pd.base(d, v.Elem(), opts) +} + +func newPointerDecoder(t reflect.Type) decoderFunc { + baseDecoder := typeDecoder(t.Elem()) + pd := pointerDecoder{base: baseDecoder} + return pd.decode +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/encode.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/encode.go new file mode 100644 index 00000000..63283936 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/encode.go @@ -0,0 +1,266 @@ +package syntax + +import ( + "bytes" + "fmt" + "reflect" + "runtime" +) + +func Marshal(v interface{}) ([]byte, error) { + e := &encodeState{} + err := e.marshal(v, encOpts{}) + if err != nil { + return nil, err + } + return e.Bytes(), nil +} + +// Marshaler is the interface implemented by types that +// have a defined TLS encoding. +type Marshaler interface { + MarshalTLS() ([]byte, error) +} + +// These are the options that can be specified in the struct tag. Right now, +// all of them apply to variable-length vectors and nothing else +type encOpts struct { + head uint // length of length in bytes + min uint // minimum size in bytes + max uint // maximum size in bytes + varint bool // whether to encode as a varint +} + +type encodeState struct { + bytes.Buffer +} + +func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + if s, ok := r.(string); ok { + panic(s) + } + err = r.(error) + } + }() + e.reflectValue(reflect.ValueOf(v), opts) + return nil +} + +func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) { + valueEncoder(v)(e, v, opts) +} + +type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts) + +func valueEncoder(v reflect.Value) encoderFunc { + if !v.IsValid() { + panic(fmt.Errorf("Cannot encode an invalid value")) + } + return typeEncoder(v.Type()) +} + +func typeEncoder(t reflect.Type) encoderFunc { + // Note: Omits the caching / wait-group things that encoding/json uses + return newTypeEncoder(t) +} + +var ( + marshalerType = reflect.TypeOf(new(Marshaler)).Elem() +) + +func newTypeEncoder(t reflect.Type) encoderFunc { + if t.Implements(marshalerType) { + return marshalerEncoder + } + + switch t.Kind() { + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return uintEncoder + case reflect.Array: + return newArrayEncoder(t) + case reflect.Slice: + return newSliceEncoder(t) + case reflect.Struct: + return newStructEncoder(t) + case reflect.Ptr: + return newPointerEncoder(t) + default: + panic(fmt.Errorf("Unsupported type (%s)", t)) + } +} + +///// Specific encoders below + +func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { + if v.Kind() == reflect.Ptr && v.IsNil() { + panic(fmt.Errorf("Cannot encode nil pointer")) + } + + m, ok := v.Interface().(Marshaler) + if !ok { + panic(fmt.Errorf("Non-Marshaler passed to marshalerEncoder")) + } + + b, err := m.MarshalTLS() + if err == nil { + _, err = e.Write(b) + } + + if err != nil { + panic(err) + } +} + +////////// + +func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) { + if opts.varint { + varintEncoder(e, v, opts) + return + } + + writeUint(e, v.Uint(), int(v.Type().Size())) +} + +func varintEncoder(e *encodeState, v reflect.Value, opts encOpts) { + u := v.Uint() + if (u >> 62) > 0 { + panic(fmt.Errorf("uint value is too big for varint")) + } + + var varintLen int + for _, len := range []uint{1, 2, 4, 8} { + if u < (uint64(1) << (8*len - 2)) { + varintLen = int(len) + break + } + } + + twoBits := map[int]uint64{1: 0x00, 2: 0x01, 4: 0x02, 8: 0x03}[varintLen] + shift := uint(8*varintLen - 2) + writeUint(e, u|(twoBits<> uint(8*(len-i-1))) + } + e.Write(data) +} + +////////// + +type arrayEncoder struct { + elemEnc encoderFunc +} + +func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { + n := v.Len() + for i := 0; i < n; i += 1 { + ae.elemEnc(e, v.Index(i), opts) + } +} + +func newArrayEncoder(t reflect.Type) encoderFunc { + enc := &arrayEncoder{typeEncoder(t.Elem())} + return enc.encode +} + +////////// + +type sliceEncoder struct { + ae *arrayEncoder +} + +func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { + if opts.head == 0 { + panic(fmt.Errorf("Cannot encode a slice without a header length")) + } + + arrayState := &encodeState{} + se.ae.encode(arrayState, v, opts) + + n := uint(arrayState.Len()) + if opts.max > 0 && n > opts.max { + panic(fmt.Errorf("Encoded length more than max [%d > %d]", n, opts.max)) + } + if n>>(8*opts.head) > 0 { + panic(fmt.Errorf("Encoded length too long for header length [%d, %d]", n, opts.head)) + } + if n < opts.min { + panic(fmt.Errorf("Encoded length less than min [%d < %d]", n, opts.min)) + } + + for i := int(opts.head - 1); i >= 0; i -= 1 { + e.WriteByte(byte(n >> (8 * uint(i)))) + } + e.Write(arrayState.Bytes()) +} + +func newSliceEncoder(t reflect.Type) encoderFunc { + enc := &sliceEncoder{&arrayEncoder{typeEncoder(t.Elem())}} + return enc.encode +} + +////////// + +type structEncoder struct { + fieldOpts []encOpts + fieldEncs []encoderFunc +} + +func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { + for i := range se.fieldEncs { + se.fieldEncs[i](e, v.Field(i), se.fieldOpts[i]) + } +} + +func newStructEncoder(t reflect.Type) encoderFunc { + n := t.NumField() + se := structEncoder{ + fieldOpts: make([]encOpts, n), + fieldEncs: make([]encoderFunc, n), + } + + for i := 0; i < n; i += 1 { + f := t.Field(i) + tag := f.Tag.Get("tls") + tagOpts := parseTag(tag) + + se.fieldOpts[i] = encOpts{ + head: tagOpts["head"], + max: tagOpts["max"], + min: tagOpts["min"], + varint: tagOpts[varintOption] > 0, + } + se.fieldEncs[i] = typeEncoder(f.Type) + } + + return se.encode +} + +////////// + +type pointerEncoder struct { + base encoderFunc +} + +func (pe pointerEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { + if v.IsNil() { + panic(fmt.Errorf("Cannot marshal a struct containing a nil pointer")) + } + + pe.base(e, v.Elem(), opts) +} + +func newPointerEncoder(t reflect.Type) encoderFunc { + baseEncoder := typeEncoder(t.Elem()) + pe := pointerEncoder{base: baseEncoder} + return pe.encode +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/tags.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/tags.go new file mode 100644 index 00000000..1bb3718e --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/syntax/tags.go @@ -0,0 +1,40 @@ +package syntax + +import ( + "strconv" + "strings" +) + +// `tls:"head=2,min=2,max=255,varint"` + +type tagOptions map[string]uint + +var ( + varintOption = "varint" +) + +// parseTag parses a struct field's "tls" tag as a comma-separated list of +// name=value pairs, where the values MUST be unsigned integers +func parseTag(tag string) tagOptions { + opts := tagOptions{} + for _, token := range strings.Split(tag, ",") { + if token == varintOption { + opts[varintOption] = 1 + continue + } + + parts := strings.Split(token, "=") + if len(parts[0]) == 0 { + continue + } + + if len(parts) == 1 { + continue + } + + if val, err := strconv.Atoi(parts[1]); err == nil && val >= 0 { + opts[parts[0]] = uint(val) + } + } + return opts +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/timer.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/timer.go new file mode 100644 index 00000000..0b7f7aff --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/timer.go @@ -0,0 +1,122 @@ +package mint + +import ( + "time" +) + +// This is a simple timer implementation. Timers are stored in a sorted +// list. +// TODO(ekr@rtfm.com): Add a way to uncouple these from the system +// clock. +type timerCb func() error + +type timer struct { + label string + cb timerCb + deadline time.Time + duration uint32 +} + +type timerSet struct { + ts []*timer +} + +func newTimerSet() *timerSet { + return &timerSet{} +} + +func (ts *timerSet) start(label string, cb timerCb, delayMs uint32) *timer { + now := time.Now() + t := timer{ + label, + cb, + now.Add(time.Millisecond * time.Duration(delayMs)), + delayMs, + } + logf(logTypeHandshake, "Timer %s set [%v -> %v]", t.label, now, t.deadline) + + var i int + ntimers := len(ts.ts) + for i = 0; i < ntimers; i++ { + if t.deadline.Before(ts.ts[i].deadline) { + break + } + } + + tmp := make([]*timer, 0, ntimers+1) + tmp = append(tmp, ts.ts[:i]...) + tmp = append(tmp, &t) + tmp = append(tmp, ts.ts[i:]...) + ts.ts = tmp + + return &t +} + +// TODO(ekr@rtfm.com): optimize this now that the list is sorted. +// We should be able to do just one list manipulation, as long +// as we're careful about how we handle inserts during callbacks. +func (ts *timerSet) check(now time.Time) error { + for i, t := range ts.ts { + if now.After(t.deadline) { + ts.ts = append(ts.ts[:i], ts.ts[:i+1]...) + if t.cb != nil { + logf(logTypeHandshake, "Timer %s expired [%v > %v]", t.label, now, t.deadline) + cb := t.cb + t.cb = nil + err := cb() + if err != nil { + return err + } + } + } else { + break + } + } + return nil +} + +// Returns the next time any of the timers would fire. +func (ts *timerSet) remaining() (bool, time.Duration) { + for _, t := range ts.ts { + if t.cb != nil { + return true, time.Until(t.deadline) + } + } + + return false, time.Duration(0) +} + +func (ts *timerSet) cancel(label string) { + for _, t := range ts.ts { + if t.label == label { + t.cancel() + } + } +} + +func (ts *timerSet) getTimer(label string) *timer { + for _, t := range ts.ts { + if t.label == label && t.cb != nil { + return t + } + } + return nil +} + +func (ts *timerSet) getAllTimers() []string { + var ret []string + + for _, t := range ts.ts { + if t.cb != nil { + ret = append(ret, t.label) + } + } + + return ret +} + +func (t *timer) cancel() { + logf(logTypeHandshake, "Timer %s cancelled", t.label) + t.cb = nil + t.label = "" +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/tls.go b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/tls.go new file mode 100644 index 00000000..4d228692 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/bifurcation/mint/tls.go @@ -0,0 +1,179 @@ +package mint + +// XXX(rlb): This file is borrowed pretty much wholesale from crypto/tls + +import ( + "errors" + "net" + "strings" + "time" +) + +// Server returns a new TLS server side connection +// using conn as the underlying transport. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Server(conn net.Conn, config *Config) *Conn { + return NewConn(conn, config, false) +} + +// Client returns a new TLS client side connection +// using conn as the underlying transport. +// The config cannot be nil: users must set either ServerName or +// InsecureSkipVerify in the config. +func Client(conn net.Conn, config *Config) *Conn { + return NewConn(conn, config, true) +} + +// A listener implements a network listener (net.Listener) for TLS connections. +type Listener struct { + net.Listener + config *Config +} + +// Accept waits for and returns the next incoming TLS connection. +// The returned connection c is a *tls.Conn. +func (l *Listener) Accept() (c net.Conn, err error) { + c, err = l.Listener.Accept() + if err != nil { + return + } + server := Server(c, l.config) + err = server.Handshake() + if err == AlertNoAlert { + err = nil + } + c = server + return +} + +// NewListener creates a Listener which accepts connections from an inner +// Listener and wraps each connection with Server. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func NewListener(inner net.Listener, config *Config) (net.Listener, error) { + if config != nil && config.NonBlocking { + return nil, errors.New("listening not possible in non-blocking mode") + } + l := new(Listener) + l.Listener = inner + l.config = config + return l, nil +} + +// Listen creates a TLS listener accepting connections on the +// given network address using net.Listen. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Listen(network, laddr string, config *Config) (net.Listener, error) { + if config == nil || !config.ValidForServer() { + return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config") + } + l, err := net.Listen(network, laddr) + if err != nil { + return nil, err + } + return NewListener(l, config) +} + +type TimeoutError struct{} + +func (TimeoutError) Error() string { return "tls: DialWithDialer timed out" } +func (TimeoutError) Timeout() bool { return true } +func (TimeoutError) Temporary() bool { return true } + +// DialWithDialer connects to the given network address using dialer.Dial and +// then initiates a TLS handshake, returning the resulting TLS connection. Any +// timeout or deadline given in the dialer apply to connection and TLS +// handshake as a whole. +// +// DialWithDialer interprets a nil configuration as equivalent to the zero +// configuration; see the documentation of Config for the defaults. +func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + if config != nil && config.NonBlocking { + return nil, errors.New("dialing not possible in non-blocking mode") + } + + // We want the Timeout and Deadline values from dialer to cover the + // whole process: TCP connection and TLS handshake. This means that we + // also need to start our own timers now. + timeout := dialer.Timeout + + if !dialer.Deadline.IsZero() { + deadlineTimeout := dialer.Deadline.Sub(time.Now()) + if timeout == 0 || deadlineTimeout < timeout { + timeout = deadlineTimeout + } + } + + var errChannel chan error + + if timeout != 0 { + errChannel = make(chan error, 2) + time.AfterFunc(timeout, func() { + errChannel <- TimeoutError{} + }) + } + + rawConn, err := dialer.Dial(network, addr) + if err != nil { + return nil, err + } + + colonPos := strings.LastIndex(addr, ":") + if colonPos == -1 { + colonPos = len(addr) + } + hostname := addr[:colonPos] + + if config == nil { + config = &Config{} + } else { + config = config.Clone() + } + + // If no ServerName is set, infer the ServerName + // from the hostname we're connecting to. + if config.ServerName == "" { + config.ServerName = hostname + + } + + // Set up DTLS as needed. + config.UseDTLS = (network == "udp") + + conn := Client(rawConn, config) + + if timeout == 0 { + err = conn.Handshake() + if err == AlertNoAlert { + err = nil + } + } else { + go func() { + errChannel <- conn.Handshake() + }() + + err = <-errChannel + if err == AlertNoAlert { + err = nil + } + } + + if err != nil { + rawConn.Close() + return nil, err + } + + return conn, nil +} + +// Dial connects to the given network address using net.Dial +// and then initiates a TLS handshake, returning the resulting +// TLS connection. +// Dial interprets a nil configuration as equivalent to +// the zero configuration; see the documentation of Config +// for the defaults. +func Dial(network, addr string, config *Config) (*Conn, error) { + return DialWithDialer(new(net.Dialer), network, addr, config) +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/LICENSE b/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/LICENSE new file mode 100644 index 00000000..519d7f22 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 cheekybits + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/doc.go b/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/doc.go new file mode 100644 index 00000000..3bd6c869 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/doc.go @@ -0,0 +1,2 @@ +// Package generic contains the generic marker types. +package generic diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/generic.go b/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/generic.go new file mode 100644 index 00000000..04a2306c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/cheekybits/genny/generic/generic.go @@ -0,0 +1,13 @@ +package generic + +// Type is the placeholder type that indicates a generic value. +// When genny is executed, variables of this type will be replaced with +// references to the specific types. +// var GenericType generic.Type +type Type interface{} + +// Number is the placehoder type that indiccates a generic numerical value. +// When genny is executed, variables of this type will be replaced with +// references to the specific types. +// var GenericType generic.Number +type Number float64 diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/2q.go b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/2q.go new file mode 100644 index 00000000..e474cd07 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/2q.go @@ -0,0 +1,223 @@ +package lru + +import ( + "fmt" + "sync" + + "github.com/hashicorp/golang-lru/simplelru" +) + +const ( + // Default2QRecentRatio is the ratio of the 2Q cache dedicated + // to recently added entries that have only been accessed once. + Default2QRecentRatio = 0.25 + + // Default2QGhostEntries is the default ratio of ghost + // entries kept to track entries recently evicted + Default2QGhostEntries = 0.50 +) + +// TwoQueueCache is a thread-safe fixed size 2Q cache. +// 2Q is an enhancement over the standard LRU cache +// in that it tracks both frequently and recently used +// entries separately. This avoids a burst in access to new +// entries from evicting frequently used entries. It adds some +// additional tracking overhead to the standard LRU cache, and is +// computationally about 2x the cost, and adds some metadata over +// head. The ARCCache is similar, but does not require setting any +// parameters. +type TwoQueueCache struct { + size int + recentSize int + + recent simplelru.LRUCache + frequent simplelru.LRUCache + recentEvict simplelru.LRUCache + lock sync.RWMutex +} + +// New2Q creates a new TwoQueueCache using the default +// values for the parameters. +func New2Q(size int) (*TwoQueueCache, error) { + return New2QParams(size, Default2QRecentRatio, Default2QGhostEntries) +} + +// New2QParams creates a new TwoQueueCache using the provided +// parameter values. +func New2QParams(size int, recentRatio float64, ghostRatio float64) (*TwoQueueCache, error) { + if size <= 0 { + return nil, fmt.Errorf("invalid size") + } + if recentRatio < 0.0 || recentRatio > 1.0 { + return nil, fmt.Errorf("invalid recent ratio") + } + if ghostRatio < 0.0 || ghostRatio > 1.0 { + return nil, fmt.Errorf("invalid ghost ratio") + } + + // Determine the sub-sizes + recentSize := int(float64(size) * recentRatio) + evictSize := int(float64(size) * ghostRatio) + + // Allocate the LRUs + recent, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + frequent, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + recentEvict, err := simplelru.NewLRU(evictSize, nil) + if err != nil { + return nil, err + } + + // Initialize the cache + c := &TwoQueueCache{ + size: size, + recentSize: recentSize, + recent: recent, + frequent: frequent, + recentEvict: recentEvict, + } + return c, nil +} + +// Get looks up a key's value from the cache. +func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) { + c.lock.Lock() + defer c.lock.Unlock() + + // Check if this is a frequent value + if val, ok := c.frequent.Get(key); ok { + return val, ok + } + + // If the value is contained in recent, then we + // promote it to frequent + if val, ok := c.recent.Peek(key); ok { + c.recent.Remove(key) + c.frequent.Add(key, val) + return val, ok + } + + // No hit + return nil, false +} + +// Add adds a value to the cache. +func (c *TwoQueueCache) Add(key, value interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + + // Check if the value is frequently used already, + // and just update the value + if c.frequent.Contains(key) { + c.frequent.Add(key, value) + return + } + + // Check if the value is recently used, and promote + // the value into the frequent list + if c.recent.Contains(key) { + c.recent.Remove(key) + c.frequent.Add(key, value) + return + } + + // If the value was recently evicted, add it to the + // frequently used list + if c.recentEvict.Contains(key) { + c.ensureSpace(true) + c.recentEvict.Remove(key) + c.frequent.Add(key, value) + return + } + + // Add to the recently seen list + c.ensureSpace(false) + c.recent.Add(key, value) + return +} + +// ensureSpace is used to ensure we have space in the cache +func (c *TwoQueueCache) ensureSpace(recentEvict bool) { + // If we have space, nothing to do + recentLen := c.recent.Len() + freqLen := c.frequent.Len() + if recentLen+freqLen < c.size { + return + } + + // If the recent buffer is larger than + // the target, evict from there + if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) { + k, _, _ := c.recent.RemoveOldest() + c.recentEvict.Add(k, nil) + return + } + + // Remove from the frequent list otherwise + c.frequent.RemoveOldest() +} + +// Len returns the number of items in the cache. +func (c *TwoQueueCache) Len() int { + c.lock.RLock() + defer c.lock.RUnlock() + return c.recent.Len() + c.frequent.Len() +} + +// Keys returns a slice of the keys in the cache. +// The frequently used keys are first in the returned slice. +func (c *TwoQueueCache) Keys() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + k1 := c.frequent.Keys() + k2 := c.recent.Keys() + return append(k1, k2...) +} + +// Remove removes the provided key from the cache. +func (c *TwoQueueCache) Remove(key interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + if c.frequent.Remove(key) { + return + } + if c.recent.Remove(key) { + return + } + if c.recentEvict.Remove(key) { + return + } +} + +// Purge is used to completely clear the cache. +func (c *TwoQueueCache) Purge() { + c.lock.Lock() + defer c.lock.Unlock() + c.recent.Purge() + c.frequent.Purge() + c.recentEvict.Purge() +} + +// Contains is used to check if the cache contains a key +// without updating recency or frequency. +func (c *TwoQueueCache) Contains(key interface{}) bool { + c.lock.RLock() + defer c.lock.RUnlock() + return c.frequent.Contains(key) || c.recent.Contains(key) +} + +// Peek is used to inspect the cache value of a key +// without updating recency or frequency. +func (c *TwoQueueCache) Peek(key interface{}) (value interface{}, ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + if val, ok := c.frequent.Peek(key); ok { + return val, ok + } + return c.recent.Peek(key) +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/LICENSE b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/LICENSE new file mode 100644 index 00000000..be2cc4df --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/README.md b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/README.md new file mode 100644 index 00000000..33e58cfa --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/README.md @@ -0,0 +1,25 @@ +golang-lru +========== + +This provides the `lru` package which implements a fixed-size +thread safe LRU cache. It is based on the cache in Groupcache. + +Documentation +============= + +Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru) + +Example +======= + +Using the LRU is very simple: + +```go +l, _ := New(128) +for i := 0; i < 256; i++ { + l.Add(i, nil) +} +if l.Len() != 128 { + panic(fmt.Sprintf("bad len: %v", l.Len())) +} +``` diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/arc.go b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/arc.go new file mode 100644 index 00000000..555225a2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/arc.go @@ -0,0 +1,257 @@ +package lru + +import ( + "sync" + + "github.com/hashicorp/golang-lru/simplelru" +) + +// ARCCache is a thread-safe fixed size Adaptive Replacement Cache (ARC). +// ARC is an enhancement over the standard LRU cache in that tracks both +// frequency and recency of use. This avoids a burst in access to new +// entries from evicting the frequently used older entries. It adds some +// additional tracking overhead to a standard LRU cache, computationally +// it is roughly 2x the cost, and the extra memory overhead is linear +// with the size of the cache. ARC has been patented by IBM, but is +// similar to the TwoQueueCache (2Q) which requires setting parameters. +type ARCCache struct { + size int // Size is the total capacity of the cache + p int // P is the dynamic preference towards T1 or T2 + + t1 simplelru.LRUCache // T1 is the LRU for recently accessed items + b1 simplelru.LRUCache // B1 is the LRU for evictions from t1 + + t2 simplelru.LRUCache // T2 is the LRU for frequently accessed items + b2 simplelru.LRUCache // B2 is the LRU for evictions from t2 + + lock sync.RWMutex +} + +// NewARC creates an ARC of the given size +func NewARC(size int) (*ARCCache, error) { + // Create the sub LRUs + b1, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + b2, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + t1, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + t2, err := simplelru.NewLRU(size, nil) + if err != nil { + return nil, err + } + + // Initialize the ARC + c := &ARCCache{ + size: size, + p: 0, + t1: t1, + b1: b1, + t2: t2, + b2: b2, + } + return c, nil +} + +// Get looks up a key's value from the cache. +func (c *ARCCache) Get(key interface{}) (value interface{}, ok bool) { + c.lock.Lock() + defer c.lock.Unlock() + + // If the value is contained in T1 (recent), then + // promote it to T2 (frequent) + if val, ok := c.t1.Peek(key); ok { + c.t1.Remove(key) + c.t2.Add(key, val) + return val, ok + } + + // Check if the value is contained in T2 (frequent) + if val, ok := c.t2.Get(key); ok { + return val, ok + } + + // No hit + return nil, false +} + +// Add adds a value to the cache. +func (c *ARCCache) Add(key, value interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + + // Check if the value is contained in T1 (recent), and potentially + // promote it to frequent T2 + if c.t1.Contains(key) { + c.t1.Remove(key) + c.t2.Add(key, value) + return + } + + // Check if the value is already in T2 (frequent) and update it + if c.t2.Contains(key) { + c.t2.Add(key, value) + return + } + + // Check if this value was recently evicted as part of the + // recently used list + if c.b1.Contains(key) { + // T1 set is too small, increase P appropriately + delta := 1 + b1Len := c.b1.Len() + b2Len := c.b2.Len() + if b2Len > b1Len { + delta = b2Len / b1Len + } + if c.p+delta >= c.size { + c.p = c.size + } else { + c.p += delta + } + + // Potentially need to make room in the cache + if c.t1.Len()+c.t2.Len() >= c.size { + c.replace(false) + } + + // Remove from B1 + c.b1.Remove(key) + + // Add the key to the frequently used list + c.t2.Add(key, value) + return + } + + // Check if this value was recently evicted as part of the + // frequently used list + if c.b2.Contains(key) { + // T2 set is too small, decrease P appropriately + delta := 1 + b1Len := c.b1.Len() + b2Len := c.b2.Len() + if b1Len > b2Len { + delta = b1Len / b2Len + } + if delta >= c.p { + c.p = 0 + } else { + c.p -= delta + } + + // Potentially need to make room in the cache + if c.t1.Len()+c.t2.Len() >= c.size { + c.replace(true) + } + + // Remove from B2 + c.b2.Remove(key) + + // Add the key to the frequently used list + c.t2.Add(key, value) + return + } + + // Potentially need to make room in the cache + if c.t1.Len()+c.t2.Len() >= c.size { + c.replace(false) + } + + // Keep the size of the ghost buffers trim + if c.b1.Len() > c.size-c.p { + c.b1.RemoveOldest() + } + if c.b2.Len() > c.p { + c.b2.RemoveOldest() + } + + // Add to the recently seen list + c.t1.Add(key, value) + return +} + +// replace is used to adaptively evict from either T1 or T2 +// based on the current learned value of P +func (c *ARCCache) replace(b2ContainsKey bool) { + t1Len := c.t1.Len() + if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) { + k, _, ok := c.t1.RemoveOldest() + if ok { + c.b1.Add(k, nil) + } + } else { + k, _, ok := c.t2.RemoveOldest() + if ok { + c.b2.Add(k, nil) + } + } +} + +// Len returns the number of cached entries +func (c *ARCCache) Len() int { + c.lock.RLock() + defer c.lock.RUnlock() + return c.t1.Len() + c.t2.Len() +} + +// Keys returns all the cached keys +func (c *ARCCache) Keys() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + k1 := c.t1.Keys() + k2 := c.t2.Keys() + return append(k1, k2...) +} + +// Remove is used to purge a key from the cache +func (c *ARCCache) Remove(key interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + if c.t1.Remove(key) { + return + } + if c.t2.Remove(key) { + return + } + if c.b1.Remove(key) { + return + } + if c.b2.Remove(key) { + return + } +} + +// Purge is used to clear the cache +func (c *ARCCache) Purge() { + c.lock.Lock() + defer c.lock.Unlock() + c.t1.Purge() + c.t2.Purge() + c.b1.Purge() + c.b2.Purge() +} + +// Contains is used to check if the cache contains a key +// without updating recency or frequency. +func (c *ARCCache) Contains(key interface{}) bool { + c.lock.RLock() + defer c.lock.RUnlock() + return c.t1.Contains(key) || c.t2.Contains(key) +} + +// Peek is used to inspect the cache value of a key +// without updating recency or frequency. +func (c *ARCCache) Peek(key interface{}) (value interface{}, ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + if val, ok := c.t1.Peek(key); ok { + return val, ok + } + return c.t2.Peek(key) +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/doc.go b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/doc.go new file mode 100644 index 00000000..2547df97 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/doc.go @@ -0,0 +1,21 @@ +// Package lru provides three different LRU caches of varying sophistication. +// +// Cache is a simple LRU cache. It is based on the +// LRU implementation in groupcache: +// https://github.com/golang/groupcache/tree/master/lru +// +// TwoQueueCache tracks frequently used and recently used entries separately. +// This avoids a burst of accesses from taking out frequently used entries, +// at the cost of about 2x computational overhead and some extra bookkeeping. +// +// ARCCache is an adaptive replacement cache. It tracks recent evictions as +// well as recent usage in both the frequent and recent caches. Its +// computational overhead is comparable to TwoQueueCache, but the memory +// overhead is linear with the size of the cache. +// +// ARC has been patented by IBM, so do not use it if that is problematic for +// your program. +// +// All caches in this package take locks while operating, and are therefore +// thread-safe for consumers. +package lru diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/lru.go b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/lru.go new file mode 100644 index 00000000..c8d9b0a2 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/lru.go @@ -0,0 +1,110 @@ +package lru + +import ( + "sync" + + "github.com/hashicorp/golang-lru/simplelru" +) + +// Cache is a thread-safe fixed size LRU cache. +type Cache struct { + lru simplelru.LRUCache + lock sync.RWMutex +} + +// New creates an LRU of the given size. +func New(size int) (*Cache, error) { + return NewWithEvict(size, nil) +} + +// NewWithEvict constructs a fixed size cache with the given eviction +// callback. +func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) { + lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted)) + if err != nil { + return nil, err + } + c := &Cache{ + lru: lru, + } + return c, nil +} + +// Purge is used to completely clear the cache. +func (c *Cache) Purge() { + c.lock.Lock() + c.lru.Purge() + c.lock.Unlock() +} + +// Add adds a value to the cache. Returns true if an eviction occurred. +func (c *Cache) Add(key, value interface{}) (evicted bool) { + c.lock.Lock() + defer c.lock.Unlock() + return c.lru.Add(key, value) +} + +// Get looks up a key's value from the cache. +func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { + c.lock.Lock() + defer c.lock.Unlock() + return c.lru.Get(key) +} + +// Contains checks if a key is in the cache, without updating the +// recent-ness or deleting it for being stale. +func (c *Cache) Contains(key interface{}) bool { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Contains(key) +} + +// Peek returns the key value (or undefined if not found) without updating +// the "recently used"-ness of the key. +func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Peek(key) +} + +// ContainsOrAdd checks if a key is in the cache without updating the +// recent-ness or deleting it for being stale, and if not, adds the value. +// Returns whether found and whether an eviction occurred. +func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) { + c.lock.Lock() + defer c.lock.Unlock() + + if c.lru.Contains(key) { + return true, false + } + evicted = c.lru.Add(key, value) + return false, evicted +} + +// Remove removes the provided key from the cache. +func (c *Cache) Remove(key interface{}) { + c.lock.Lock() + c.lru.Remove(key) + c.lock.Unlock() +} + +// RemoveOldest removes the oldest item from the cache. +func (c *Cache) RemoveOldest() { + c.lock.Lock() + c.lru.RemoveOldest() + c.lock.Unlock() +} + +// Keys returns a slice of the keys in the cache, from oldest to newest. +func (c *Cache) Keys() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Keys() +} + +// Len returns the number of items in the cache. +func (c *Cache) Len() int { + c.lock.RLock() + defer c.lock.RUnlock() + return c.lru.Len() +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go new file mode 100644 index 00000000..5673773b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go @@ -0,0 +1,161 @@ +package simplelru + +import ( + "container/list" + "errors" +) + +// EvictCallback is used to get a callback when a cache entry is evicted +type EvictCallback func(key interface{}, value interface{}) + +// LRU implements a non-thread safe fixed size LRU cache +type LRU struct { + size int + evictList *list.List + items map[interface{}]*list.Element + onEvict EvictCallback +} + +// entry is used to hold a value in the evictList +type entry struct { + key interface{} + value interface{} +} + +// NewLRU constructs an LRU of the given size +func NewLRU(size int, onEvict EvictCallback) (*LRU, error) { + if size <= 0 { + return nil, errors.New("Must provide a positive size") + } + c := &LRU{ + size: size, + evictList: list.New(), + items: make(map[interface{}]*list.Element), + onEvict: onEvict, + } + return c, nil +} + +// Purge is used to completely clear the cache. +func (c *LRU) Purge() { + for k, v := range c.items { + if c.onEvict != nil { + c.onEvict(k, v.Value.(*entry).value) + } + delete(c.items, k) + } + c.evictList.Init() +} + +// Add adds a value to the cache. Returns true if an eviction occurred. +func (c *LRU) Add(key, value interface{}) (evicted bool) { + // Check for existing item + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + ent.Value.(*entry).value = value + return false + } + + // Add new item + ent := &entry{key, value} + entry := c.evictList.PushFront(ent) + c.items[key] = entry + + evict := c.evictList.Len() > c.size + // Verify size not exceeded + if evict { + c.removeOldest() + } + return evict +} + +// Get looks up a key's value from the cache. +func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + return ent.Value.(*entry).value, true + } + return +} + +// Contains checks if a key is in the cache, without updating the recent-ness +// or deleting it for being stale. +func (c *LRU) Contains(key interface{}) (ok bool) { + _, ok = c.items[key] + return ok +} + +// Peek returns the key value (or undefined if not found) without updating +// the "recently used"-ness of the key. +func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) { + var ent *list.Element + if ent, ok = c.items[key]; ok { + return ent.Value.(*entry).value, true + } + return nil, ok +} + +// Remove removes the provided key from the cache, returning if the +// key was contained. +func (c *LRU) Remove(key interface{}) (present bool) { + if ent, ok := c.items[key]; ok { + c.removeElement(ent) + return true + } + return false +} + +// RemoveOldest removes the oldest item from the cache. +func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) { + ent := c.evictList.Back() + if ent != nil { + c.removeElement(ent) + kv := ent.Value.(*entry) + return kv.key, kv.value, true + } + return nil, nil, false +} + +// GetOldest returns the oldest entry +func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) { + ent := c.evictList.Back() + if ent != nil { + kv := ent.Value.(*entry) + return kv.key, kv.value, true + } + return nil, nil, false +} + +// Keys returns a slice of the keys in the cache, from oldest to newest. +func (c *LRU) Keys() []interface{} { + keys := make([]interface{}, len(c.items)) + i := 0 + for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() { + keys[i] = ent.Value.(*entry).key + i++ + } + return keys +} + +// Len returns the number of items in the cache. +func (c *LRU) Len() int { + return c.evictList.Len() +} + +// removeOldest removes the oldest item from the cache. +func (c *LRU) removeOldest() { + ent := c.evictList.Back() + if ent != nil { + c.removeElement(ent) + } +} + +// removeElement is used to remove a given list element from the cache +func (c *LRU) removeElement(e *list.Element) { + c.evictList.Remove(e) + kv := e.Value.(*entry) + delete(c.items, kv.key) + if c.onEvict != nil { + c.onEvict(kv.key, kv.value) + } +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go new file mode 100644 index 00000000..74c70774 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go @@ -0,0 +1,36 @@ +package simplelru + +// LRUCache is the interface for simple LRU cache. +type LRUCache interface { + // Adds a value to the cache, returns true if an eviction occurred and + // updates the "recently used"-ness of the key. + Add(key, value interface{}) bool + + // Returns key's value from the cache and + // updates the "recently used"-ness of the key. #value, isFound + Get(key interface{}) (value interface{}, ok bool) + + // Check if a key exsists in cache without updating the recent-ness. + Contains(key interface{}) (ok bool) + + // Returns key's value without updating the "recently used"-ness of the key. + Peek(key interface{}) (value interface{}, ok bool) + + // Removes a key from the cache. + Remove(key interface{}) bool + + // Removes the oldest entry from cache. + RemoveOldest() (interface{}, interface{}, bool) + + // Returns the oldest entry from the cache. #key, value, isFound + GetOldest() (interface{}, interface{}, bool) + + // Returns a slice of the keys in the cache, from oldest to newest. + Keys() []interface{} + + // Returns the number of items in the cache. + Len() int + + // Clear all cache entries + Purge() +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/LICENSE b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/LICENSE new file mode 100644 index 00000000..2c08ae24 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Lucas Clemente + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/Readme.md b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/Readme.md new file mode 100644 index 00000000..ef4e316f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/Readme.md @@ -0,0 +1,28 @@ +# aes12 + +This package modifies the AES-GCM implementation from Go's standard library to use 12 byte tag sizes. It is not intended for a general audience, and used in [quic-go](https://github.com/lucas-clemente/quic-go). + +To make use of the in-place encryption / decryption feature, the `dst` parameter to `Seal` and `Open` should be 16 bytes longer than plaintext, not 12. + +Command for testing: + +``` +go test . --bench=. && GOARCH=386 go test . --bench=. +``` + +The output (on my machine): + +``` +BenchmarkAESGCMSeal1K-8 3000000 467 ns/op 2192.37 MB/s +BenchmarkAESGCMOpen1K-8 3000000 416 ns/op 2456.72 MB/s +BenchmarkAESGCMSeal8K-8 500000 2742 ns/op 2986.53 MB/s +BenchmarkAESGCMOpen8K-8 500000 2791 ns/op 2934.65 MB/s +PASS +ok github.com/lucas-clemente/aes12 6.383s +BenchmarkAESGCMSeal1K-8 50000 35233 ns/op 29.06 MB/s +BenchmarkAESGCMOpen1K-8 50000 34529 ns/op 29.66 MB/s +BenchmarkAESGCMSeal8K-8 5000 262678 ns/op 31.19 MB/s +BenchmarkAESGCMOpen8K-8 5000 267296 ns/op 30.65 MB/s +PASS +ok github.com/lucas-clemente/aes12 6.972s +``` diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/aes_gcm.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/aes_gcm.go new file mode 100644 index 00000000..21f2b233 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/aes_gcm.go @@ -0,0 +1,148 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64 + +package aes12 + +import "crypto/subtle" + +// The following functions are defined in gcm_amd64.s. +func hasGCMAsm() bool + +//go:noescape +func aesEncBlock(dst, src *[16]byte, ks []uint32) + +//go:noescape +func gcmAesInit(productTable *[256]byte, ks []uint32) + +//go:noescape +func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte) + +//go:noescape +func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) + +//go:noescape +func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) + +//go:noescape +func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) + +// aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM +// will use the optimised implementation in this file when possible. Instances +// of this type only exist when hasGCMAsm returns true. +type aesCipherGCM struct { + aesCipherAsm +} + +// Assert that aesCipherGCM implements the gcmAble interface. +var _ gcmAble = (*aesCipherGCM)(nil) + +// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only +// called by crypto/cipher.NewGCM via the gcmAble interface. +func (c *aesCipherGCM) NewGCM(nonceSize int) (AEAD, error) { + g := &gcmAsm{ks: c.enc, nonceSize: nonceSize} + gcmAesInit(&g.productTable, g.ks) + return g, nil +} + +type gcmAsm struct { + // ks is the key schedule, the length of which depends on the size of + // the AES key. + ks []uint32 + // productTable contains pre-computed multiples of the binary-field + // element used in GHASH. + productTable [256]byte + // nonceSize contains the expected size of the nonce, in bytes. + nonceSize int +} + +func (g *gcmAsm) NonceSize() int { + return g.nonceSize +} + +func (*gcmAsm) Overhead() int { + return gcmTagSize +} + +// Seal encrypts and authenticates plaintext. See the AEAD interface for +// details. +func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { + if len(nonce) != g.nonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + + var counter, tagMask [gcmBlockSize]byte + + if len(nonce) == gcmStandardNonceSize { + // Init counter to nonce||1 + copy(counter[:], nonce) + counter[gcmBlockSize-1] = 1 + } else { + // Otherwise counter = GHASH(nonce) + gcmAesData(&g.productTable, nonce, &counter) + gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) + } + + aesEncBlock(&tagMask, &counter, g.ks) + + var tagOut [16]byte + gcmAesData(&g.productTable, data, &tagOut) + + ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize) + if len(plaintext) > 0 { + gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks) + } + gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data))) + copy(out[len(plaintext):], tagOut[:gcmTagSize]) + + return ret +} + +// Open authenticates and decrypts ciphertext. See the AEAD interface +// for details. +func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { + if len(nonce) != g.nonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + + if len(ciphertext) < gcmTagSize { + return nil, errOpen + } + tag := ciphertext[len(ciphertext)-gcmTagSize:] + ciphertext = ciphertext[:len(ciphertext)-gcmTagSize] + + // See GCM spec, section 7.1. + var counter, tagMask [gcmBlockSize]byte + + if len(nonce) == gcmStandardNonceSize { + // Init counter to nonce||1 + copy(counter[:], nonce) + counter[gcmBlockSize-1] = 1 + } else { + // Otherwise counter = GHASH(nonce) + gcmAesData(&g.productTable, nonce, &counter) + gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) + } + + aesEncBlock(&tagMask, &counter, g.ks) + + var expectedTag [16]byte + gcmAesData(&g.productTable, data, &expectedTag) + + ret, out := sliceForAppend(dst, len(ciphertext)) + if len(ciphertext) > 0 { + gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) + } + gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) + + if subtle.ConstantTimeCompare(expectedTag[:12], tag) != 1 { + for i := range out { + out[i] = 0 + } + return nil, errOpen + } + + return ret, nil +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/asm_amd64.s b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/asm_amd64.s new file mode 100644 index 00000000..b2579987 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/asm_amd64.s @@ -0,0 +1,285 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +// func hasAsm() bool +// returns whether AES-NI is supported +TEXT ·hasAsm(SB),NOSPLIT,$0 + XORQ AX, AX + INCL AX + CPUID + SHRQ $25, CX + ANDQ $1, CX + MOVB CX, ret+0(FP) + RET + +// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·encryptBlockAsm(SB),NOSPLIT,$0 + MOVQ nr+0(FP), CX + MOVQ xk+8(FP), AX + MOVQ dst+16(FP), DX + MOVQ src+24(FP), BX + MOVUPS 0(AX), X1 + MOVUPS 0(BX), X0 + ADDQ $16, AX + PXOR X1, X0 + SUBQ $12, CX + JE Lenc196 + JB Lenc128 +Lenc256: + MOVUPS 0(AX), X1 + AESENC X1, X0 + MOVUPS 16(AX), X1 + AESENC X1, X0 + ADDQ $32, AX +Lenc196: + MOVUPS 0(AX), X1 + AESENC X1, X0 + MOVUPS 16(AX), X1 + AESENC X1, X0 + ADDQ $32, AX +Lenc128: + MOVUPS 0(AX), X1 + AESENC X1, X0 + MOVUPS 16(AX), X1 + AESENC X1, X0 + MOVUPS 32(AX), X1 + AESENC X1, X0 + MOVUPS 48(AX), X1 + AESENC X1, X0 + MOVUPS 64(AX), X1 + AESENC X1, X0 + MOVUPS 80(AX), X1 + AESENC X1, X0 + MOVUPS 96(AX), X1 + AESENC X1, X0 + MOVUPS 112(AX), X1 + AESENC X1, X0 + MOVUPS 128(AX), X1 + AESENC X1, X0 + MOVUPS 144(AX), X1 + AESENCLAST X1, X0 + MOVUPS X0, 0(DX) + RET + +// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·decryptBlockAsm(SB),NOSPLIT,$0 + MOVQ nr+0(FP), CX + MOVQ xk+8(FP), AX + MOVQ dst+16(FP), DX + MOVQ src+24(FP), BX + MOVUPS 0(AX), X1 + MOVUPS 0(BX), X0 + ADDQ $16, AX + PXOR X1, X0 + SUBQ $12, CX + JE Ldec196 + JB Ldec128 +Ldec256: + MOVUPS 0(AX), X1 + AESDEC X1, X0 + MOVUPS 16(AX), X1 + AESDEC X1, X0 + ADDQ $32, AX +Ldec196: + MOVUPS 0(AX), X1 + AESDEC X1, X0 + MOVUPS 16(AX), X1 + AESDEC X1, X0 + ADDQ $32, AX +Ldec128: + MOVUPS 0(AX), X1 + AESDEC X1, X0 + MOVUPS 16(AX), X1 + AESDEC X1, X0 + MOVUPS 32(AX), X1 + AESDEC X1, X0 + MOVUPS 48(AX), X1 + AESDEC X1, X0 + MOVUPS 64(AX), X1 + AESDEC X1, X0 + MOVUPS 80(AX), X1 + AESDEC X1, X0 + MOVUPS 96(AX), X1 + AESDEC X1, X0 + MOVUPS 112(AX), X1 + AESDEC X1, X0 + MOVUPS 128(AX), X1 + AESDEC X1, X0 + MOVUPS 144(AX), X1 + AESDECLAST X1, X0 + MOVUPS X0, 0(DX) + RET + +// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) { +// Note that round keys are stored in uint128 format, not uint32 +TEXT ·expandKeyAsm(SB),NOSPLIT,$0 + MOVQ nr+0(FP), CX + MOVQ key+8(FP), AX + MOVQ enc+16(FP), BX + MOVQ dec+24(FP), DX + MOVUPS (AX), X0 + // enc + MOVUPS X0, (BX) + ADDQ $16, BX + PXOR X4, X4 // _expand_key_* expect X4 to be zero + CMPL CX, $12 + JE Lexp_enc196 + JB Lexp_enc128 +Lexp_enc256: + MOVUPS 16(AX), X2 + MOVUPS X2, (BX) + ADDQ $16, BX + AESKEYGENASSIST $0x01, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x01, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x02, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x02, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x04, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x04, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x08, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x08, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x10, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x10, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x20, X2, X1 + CALL _expand_key_256a<>(SB) + AESKEYGENASSIST $0x20, X0, X1 + CALL _expand_key_256b<>(SB) + AESKEYGENASSIST $0x40, X2, X1 + CALL _expand_key_256a<>(SB) + JMP Lexp_dec +Lexp_enc196: + MOVQ 16(AX), X2 + AESKEYGENASSIST $0x01, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x02, X2, X1 + CALL _expand_key_192b<>(SB) + AESKEYGENASSIST $0x04, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x08, X2, X1 + CALL _expand_key_192b<>(SB) + AESKEYGENASSIST $0x10, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x20, X2, X1 + CALL _expand_key_192b<>(SB) + AESKEYGENASSIST $0x40, X2, X1 + CALL _expand_key_192a<>(SB) + AESKEYGENASSIST $0x80, X2, X1 + CALL _expand_key_192b<>(SB) + JMP Lexp_dec +Lexp_enc128: + AESKEYGENASSIST $0x01, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x02, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x04, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x08, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x10, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x20, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x40, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x80, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x1b, X0, X1 + CALL _expand_key_128<>(SB) + AESKEYGENASSIST $0x36, X0, X1 + CALL _expand_key_128<>(SB) +Lexp_dec: + // dec + SUBQ $16, BX + MOVUPS (BX), X1 + MOVUPS X1, (DX) + DECQ CX +Lexp_dec_loop: + MOVUPS -16(BX), X1 + AESIMC X1, X0 + MOVUPS X0, 16(DX) + SUBQ $16, BX + ADDQ $16, DX + DECQ CX + JNZ Lexp_dec_loop + MOVUPS -16(BX), X0 + MOVUPS X0, 16(DX) + RET + +TEXT _expand_key_128<>(SB),NOSPLIT,$0 + PSHUFD $0xff, X1, X1 + SHUFPS $0x10, X0, X4 + PXOR X4, X0 + SHUFPS $0x8c, X0, X4 + PXOR X4, X0 + PXOR X1, X0 + MOVUPS X0, (BX) + ADDQ $16, BX + RET + +TEXT _expand_key_192a<>(SB),NOSPLIT,$0 + PSHUFD $0x55, X1, X1 + SHUFPS $0x10, X0, X4 + PXOR X4, X0 + SHUFPS $0x8c, X0, X4 + PXOR X4, X0 + PXOR X1, X0 + + MOVAPS X2, X5 + MOVAPS X2, X6 + PSLLDQ $0x4, X5 + PSHUFD $0xff, X0, X3 + PXOR X3, X2 + PXOR X5, X2 + + MOVAPS X0, X1 + SHUFPS $0x44, X0, X6 + MOVUPS X6, (BX) + SHUFPS $0x4e, X2, X1 + MOVUPS X1, 16(BX) + ADDQ $32, BX + RET + +TEXT _expand_key_192b<>(SB),NOSPLIT,$0 + PSHUFD $0x55, X1, X1 + SHUFPS $0x10, X0, X4 + PXOR X4, X0 + SHUFPS $0x8c, X0, X4 + PXOR X4, X0 + PXOR X1, X0 + + MOVAPS X2, X5 + PSLLDQ $0x4, X5 + PSHUFD $0xff, X0, X3 + PXOR X3, X2 + PXOR X5, X2 + + MOVUPS X0, (BX) + ADDQ $16, BX + RET + +TEXT _expand_key_256a<>(SB),NOSPLIT,$0 + JMP _expand_key_128<>(SB) + +TEXT _expand_key_256b<>(SB),NOSPLIT,$0 + PSHUFD $0xaa, X1, X1 + SHUFPS $0x10, X2, X4 + PXOR X4, X2 + SHUFPS $0x8c, X2, X4 + PXOR X4, X2 + PXOR X1, X2 + + MOVUPS X2, (BX) + ADDQ $16, BX + RET diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/block.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/block.go new file mode 100644 index 00000000..1f29ddaa --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/block.go @@ -0,0 +1,176 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This Go implementation is derived in part from the reference +// ANSI C implementation, which carries the following notice: +// +// rijndael-alg-fst.c +// +// @version 3.0 (December 2000) +// +// Optimised ANSI C code for the Rijndael cipher (now AES) +// +// @author Vincent Rijmen +// @author Antoon Bosselaers +// @author Paulo Barreto +// +// This code is hereby placed in the public domain. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS +// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission +// for implementation details. +// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf + +package aes12 + +// Encrypt one block from src into dst, using the expanded key xk. +func encryptBlockGo(xk []uint32, dst, src []byte) { + var s0, s1, s2, s3, t0, t1, t2, t3 uint32 + + s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11]) + s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15]) + + // First round just XORs input with key. + s0 ^= xk[0] + s1 ^= xk[1] + s2 ^= xk[2] + s3 ^= xk[3] + + // Middle rounds shuffle using tables. + // Number of rounds is set by length of expanded key. + nr := len(xk)/4 - 2 // - 2: one above, one more below + k := 4 + for r := 0; r < nr; r++ { + t0 = xk[k+0] ^ te0[uint8(s0>>24)] ^ te1[uint8(s1>>16)] ^ te2[uint8(s2>>8)] ^ te3[uint8(s3)] + t1 = xk[k+1] ^ te0[uint8(s1>>24)] ^ te1[uint8(s2>>16)] ^ te2[uint8(s3>>8)] ^ te3[uint8(s0)] + t2 = xk[k+2] ^ te0[uint8(s2>>24)] ^ te1[uint8(s3>>16)] ^ te2[uint8(s0>>8)] ^ te3[uint8(s1)] + t3 = xk[k+3] ^ te0[uint8(s3>>24)] ^ te1[uint8(s0>>16)] ^ te2[uint8(s1>>8)] ^ te3[uint8(s2)] + k += 4 + s0, s1, s2, s3 = t0, t1, t2, t3 + } + + // Last round uses s-box directly and XORs to produce output. + s0 = uint32(sbox0[t0>>24])<<24 | uint32(sbox0[t1>>16&0xff])<<16 | uint32(sbox0[t2>>8&0xff])<<8 | uint32(sbox0[t3&0xff]) + s1 = uint32(sbox0[t1>>24])<<24 | uint32(sbox0[t2>>16&0xff])<<16 | uint32(sbox0[t3>>8&0xff])<<8 | uint32(sbox0[t0&0xff]) + s2 = uint32(sbox0[t2>>24])<<24 | uint32(sbox0[t3>>16&0xff])<<16 | uint32(sbox0[t0>>8&0xff])<<8 | uint32(sbox0[t1&0xff]) + s3 = uint32(sbox0[t3>>24])<<24 | uint32(sbox0[t0>>16&0xff])<<16 | uint32(sbox0[t1>>8&0xff])<<8 | uint32(sbox0[t2&0xff]) + + s0 ^= xk[k+0] + s1 ^= xk[k+1] + s2 ^= xk[k+2] + s3 ^= xk[k+3] + + dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0) + dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1) + dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2) + dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3) +} + +// Decrypt one block from src into dst, using the expanded key xk. +func decryptBlockGo(xk []uint32, dst, src []byte) { + var s0, s1, s2, s3, t0, t1, t2, t3 uint32 + + s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11]) + s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15]) + + // First round just XORs input with key. + s0 ^= xk[0] + s1 ^= xk[1] + s2 ^= xk[2] + s3 ^= xk[3] + + // Middle rounds shuffle using tables. + // Number of rounds is set by length of expanded key. + nr := len(xk)/4 - 2 // - 2: one above, one more below + k := 4 + for r := 0; r < nr; r++ { + t0 = xk[k+0] ^ td0[uint8(s0>>24)] ^ td1[uint8(s3>>16)] ^ td2[uint8(s2>>8)] ^ td3[uint8(s1)] + t1 = xk[k+1] ^ td0[uint8(s1>>24)] ^ td1[uint8(s0>>16)] ^ td2[uint8(s3>>8)] ^ td3[uint8(s2)] + t2 = xk[k+2] ^ td0[uint8(s2>>24)] ^ td1[uint8(s1>>16)] ^ td2[uint8(s0>>8)] ^ td3[uint8(s3)] + t3 = xk[k+3] ^ td0[uint8(s3>>24)] ^ td1[uint8(s2>>16)] ^ td2[uint8(s1>>8)] ^ td3[uint8(s0)] + k += 4 + s0, s1, s2, s3 = t0, t1, t2, t3 + } + + // Last round uses s-box directly and XORs to produce output. + s0 = uint32(sbox1[t0>>24])<<24 | uint32(sbox1[t3>>16&0xff])<<16 | uint32(sbox1[t2>>8&0xff])<<8 | uint32(sbox1[t1&0xff]) + s1 = uint32(sbox1[t1>>24])<<24 | uint32(sbox1[t0>>16&0xff])<<16 | uint32(sbox1[t3>>8&0xff])<<8 | uint32(sbox1[t2&0xff]) + s2 = uint32(sbox1[t2>>24])<<24 | uint32(sbox1[t1>>16&0xff])<<16 | uint32(sbox1[t0>>8&0xff])<<8 | uint32(sbox1[t3&0xff]) + s3 = uint32(sbox1[t3>>24])<<24 | uint32(sbox1[t2>>16&0xff])<<16 | uint32(sbox1[t1>>8&0xff])<<8 | uint32(sbox1[t0&0xff]) + + s0 ^= xk[k+0] + s1 ^= xk[k+1] + s2 ^= xk[k+2] + s3 ^= xk[k+3] + + dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0) + dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1) + dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2) + dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3) +} + +// Apply sbox0 to each byte in w. +func subw(w uint32) uint32 { + return uint32(sbox0[w>>24])<<24 | + uint32(sbox0[w>>16&0xff])<<16 | + uint32(sbox0[w>>8&0xff])<<8 | + uint32(sbox0[w&0xff]) +} + +// Rotate +func rotw(w uint32) uint32 { return w<<8 | w>>24 } + +// Key expansion algorithm. See FIPS-197, Figure 11. +// Their rcon[i] is our powx[i-1] << 24. +func expandKeyGo(key []byte, enc, dec []uint32) { + // Encryption key setup. + var i int + nk := len(key) / 4 + for i = 0; i < nk; i++ { + enc[i] = uint32(key[4*i])<<24 | uint32(key[4*i+1])<<16 | uint32(key[4*i+2])<<8 | uint32(key[4*i+3]) + } + for ; i < len(enc); i++ { + t := enc[i-1] + if i%nk == 0 { + t = subw(rotw(t)) ^ (uint32(powx[i/nk-1]) << 24) + } else if nk > 6 && i%nk == 4 { + t = subw(t) + } + enc[i] = enc[i-nk] ^ t + } + + // Derive decryption key from encryption key. + // Reverse the 4-word round key sets from enc to produce dec. + // All sets but the first and last get the MixColumn transform applied. + if dec == nil { + return + } + n := len(enc) + for i := 0; i < n; i += 4 { + ei := n - i - 4 + for j := 0; j < 4; j++ { + x := enc[ei+j] + if i > 0 && i+4 < n { + x = td0[sbox0[x>>24]] ^ td1[sbox0[x>>16&0xff]] ^ td2[sbox0[x>>8&0xff]] ^ td3[sbox0[x&0xff]] + } + dec[i+j] = x + } + } +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher.go new file mode 100644 index 00000000..a9b8e547 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher.go @@ -0,0 +1,68 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package aes12 + +import "strconv" + +// The AES block size in bytes. +const BlockSize = 16 + +// A cipher is an instance of AES encryption using a particular key. +type aesCipher struct { + enc []uint32 + dec []uint32 +} + +type KeySizeError int + +func (k KeySizeError) Error() string { + return "crypto/aes: invalid key size " + strconv.Itoa(int(k)) +} + +// NewCipher creates and returns a new Block. +// The key argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func NewCipher(key []byte) (Block, error) { + k := len(key) + switch k { + default: + return nil, KeySizeError(k) + case 16, 24, 32: + break + } + return newCipher(key) +} + +// newCipherGeneric creates and returns a new Block +// implemented in pure Go. +func newCipherGeneric(key []byte) (Block, error) { + n := len(key) + 28 + c := aesCipher{make([]uint32, n), make([]uint32, n)} + expandKeyGo(key, c.enc, c.dec) + return &c, nil +} + +func (c *aesCipher) BlockSize() int { return BlockSize } + +func (c *aesCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + encryptBlockGo(c.enc, dst, src) +} + +func (c *aesCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + decryptBlockGo(c.dec, dst, src) +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_2.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_2.go new file mode 100644 index 00000000..ae2f520b --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_2.go @@ -0,0 +1,56 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package aes12 implements standard block cipher modes that can be wrapped +// around low-level block cipher implementations. +// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html +// and NIST Special Publication 800-38A. +package aes12 + +// A Block represents an implementation of block cipher +// using a given key. It provides the capability to encrypt +// or decrypt individual blocks. The mode implementations +// extend that capability to streams of blocks. +type Block interface { + // BlockSize returns the cipher's block size. + BlockSize() int + + // Encrypt encrypts the first block in src into dst. + // Dst and src may point at the same memory. + Encrypt(dst, src []byte) + + // Decrypt decrypts the first block in src into dst. + // Dst and src may point at the same memory. + Decrypt(dst, src []byte) +} + +// A Stream represents a stream cipher. +type Stream interface { + // XORKeyStream XORs each byte in the given slice with a byte from the + // cipher's key stream. Dst and src may point to the same memory. + // If len(dst) < len(src), XORKeyStream should panic. It is acceptable + // to pass a dst bigger than src, and in that case, XORKeyStream will + // only update dst[:len(src)] and will not touch the rest of dst. + XORKeyStream(dst, src []byte) +} + +// A BlockMode represents a block cipher running in a block-based mode (CBC, +// ECB etc). +type BlockMode interface { + // BlockSize returns the mode's block size. + BlockSize() int + + // CryptBlocks encrypts or decrypts a number of blocks. The length of + // src must be a multiple of the block size. Dst and src may point to + // the same memory. + CryptBlocks(dst, src []byte) +} + +// Utility routines + +func dup(p []byte) []byte { + q := make([]byte, len(p)) + copy(q, p) + return q +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_amd64.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_amd64.go new file mode 100644 index 00000000..cd0544f3 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_amd64.go @@ -0,0 +1,79 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package aes12 + +// defined in asm_amd64.s +func hasAsm() bool +func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) +func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) +func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32) + +type aesCipherAsm struct { + aesCipher +} + +var useAsm = hasAsm() + +func newCipher(key []byte) (Block, error) { + if !useAsm { + return newCipherGeneric(key) + } + n := len(key) + 28 + c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}} + rounds := 10 + switch len(key) { + case 128 / 8: + rounds = 10 + case 192 / 8: + rounds = 12 + case 256 / 8: + rounds = 14 + } + expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0]) + if hasGCMAsm() { + return &aesCipherGCM{c}, nil + } + + return &c, nil +} + +func (c *aesCipherAsm) BlockSize() int { return BlockSize } + +func (c *aesCipherAsm) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) +} + +func (c *aesCipherAsm) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) +} + +// expandKey is used by BenchmarkExpand to ensure that the asm implementation +// of key expansion is used for the benchmark when it is available. +func expandKey(key []byte, enc, dec []uint32) { + if useAsm { + rounds := 10 // rounds needed for AES128 + switch len(key) { + case 192 / 8: + rounds = 12 + case 256 / 8: + rounds = 14 + } + expandKeyAsm(rounds, &key[0], &enc[0], &dec[0]) + } else { + expandKeyGo(key, enc, dec) + } +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_generic.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_generic.go new file mode 100644 index 00000000..6861677f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/cipher_generic.go @@ -0,0 +1,22 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !amd64 + +package aes12 + +// newCipher calls the newCipherGeneric function +// directly. Platforms with hardware accelerated +// implementations of AES should implement their +// own version of newCipher (which may then call +// newCipherGeneric if needed). +func newCipher(key []byte) (Block, error) { + return newCipherGeneric(key) +} + +// expandKey is used by BenchmarkExpand and should +// call an assembly implementation if one is available. +func expandKey(key []byte, enc, dec []uint32) { + expandKeyGo(key, enc, dec) +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/const.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/const.go new file mode 100644 index 00000000..40296fa7 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/const.go @@ -0,0 +1,358 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package aes12 implements AES encryption (formerly Rijndael), as defined in +// U.S. Federal Information Processing Standards Publication 197. +package aes12 + +// This file contains AES constants - 8720 bytes of initialized data. + +// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf + +// AES is based on the mathematical behavior of binary polynomials +// (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x³ + x + 1. +// Addition of these binary polynomials corresponds to binary xor. +// Reducing mod poly corresponds to binary xor with poly every +// time a 0x100 bit appears. +const poly = 1<<8 | 1<<4 | 1<<3 | 1<<1 | 1<<0 // x⁸ + x⁴ + x³ + x + 1 + +// Powers of x mod poly in GF(2). +var powx = [16]byte{ + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80, + 0x1b, + 0x36, + 0x6c, + 0xd8, + 0xab, + 0x4d, + 0x9a, + 0x2f, +} + +// FIPS-197 Figure 7. S-box substitution values in hexadecimal format. +var sbox0 = [256]byte{ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +} + +// FIPS-197 Figure 14. Inverse S-box substitution values in hexadecimal format. +var sbox1 = [256]byte{ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, +} + +// Lookup tables for encryption. +// These can be recomputed by adapting the tests in aes_test.go. + +var te0 = [256]uint32{ + 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, + 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, + 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, + 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, + 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, + 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, + 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, + 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, + 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, + 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, + 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, + 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, + 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, + 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, + 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, + 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, + 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, + 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, + 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, + 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, + 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, + 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, + 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, + 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, + 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, + 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, + 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, + 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, + 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, + 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, + 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, +} +var te1 = [256]uint32{ + 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, + 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, + 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, + 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, + 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, + 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, + 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, + 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, + 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, + 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, + 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, + 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, + 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, + 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, + 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, + 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, + 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, + 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, + 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, + 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, + 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, + 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, + 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, + 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, + 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, + 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, + 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, + 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, + 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, + 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, + 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, + 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616, +} +var te2 = [256]uint32{ + 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, + 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, + 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, + 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, + 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, + 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, + 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, + 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, + 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, + 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, + 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, + 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, + 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, + 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, + 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, + 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, + 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, + 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, + 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, + 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, + 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, + 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, + 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, + 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, + 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, + 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, + 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, + 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, + 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, + 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, + 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, + 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, +} +var te3 = [256]uint32{ + 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, + 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, + 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, + 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, + 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, + 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, + 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, + 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, + 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, + 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, + 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, + 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, + 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, + 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, + 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, + 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, + 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, + 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, + 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, + 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, + 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, + 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, + 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, + 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, + 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, + 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, + 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, + 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, + 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, + 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, + 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, + 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, +} + +// Lookup tables for decryption. +// These can be recomputed by adapting the tests in aes_test.go. + +var td0 = [256]uint32{ + 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, + 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, + 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, + 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, + 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, + 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, + 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, + 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, + 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, + 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, + 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, + 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, + 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, + 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, + 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, + 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, + 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, + 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, + 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, + 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, + 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, + 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, + 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, + 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, + 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, + 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, + 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, + 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, + 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, + 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, + 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742, +} +var td1 = [256]uint32{ + 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, + 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, + 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, + 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, + 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, + 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, + 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, + 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, + 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, + 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, + 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, + 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, + 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, + 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, + 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, + 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, + 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, + 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, + 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, + 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, + 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, + 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, + 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, + 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, + 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, + 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, + 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, + 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, + 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, + 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, + 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, + 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857, +} +var td2 = [256]uint32{ + 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, + 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, + 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, + 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, + 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, + 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, + 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, + 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, + 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, + 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, + 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, + 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, + 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, + 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, + 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, + 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, + 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, + 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, + 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, + 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, + 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, + 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, + 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, + 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, + 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, + 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, + 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, + 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, + 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, + 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, + 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, + 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8, +} +var td3 = [256]uint32{ + 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, + 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, + 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, + 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, + 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, + 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, + 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, + 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, + 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, + 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, + 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, + 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, + 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, + 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, + 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, + 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, + 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, + 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, + 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, + 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, + 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, + 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, + 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, + 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, + 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, + 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, + 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, + 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, + 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, + 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, + 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, + 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm.go new file mode 100644 index 00000000..ed7dc918 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm.go @@ -0,0 +1,401 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package aes12 + +import ( + "crypto/subtle" + "errors" +) + +// AEAD is a cipher mode providing authenticated encryption with associated +// data. For a description of the methodology, see +// https://en.wikipedia.org/wiki/Authenticated_encryption +type AEAD interface { + // NonceSize returns the size of the nonce that must be passed to Seal + // and Open. + NonceSize() int + + // Overhead returns the maximum difference between the lengths of a + // plaintext and its ciphertext. + Overhead() int + + // Seal encrypts and authenticates plaintext, authenticates the + // additional data and appends the result to dst, returning the updated + // slice. The nonce must be NonceSize() bytes long and unique for all + // time, for a given key. + // + // The plaintext and dst may alias exactly or not at all. To reuse + // plaintext's storage for the encrypted output, use plaintext[:0] as dst. + Seal(dst, nonce, plaintext, additionalData []byte) []byte + + // Open decrypts and authenticates ciphertext, authenticates the + // additional data and, if successful, appends the resulting plaintext + // to dst, returning the updated slice. The nonce must be NonceSize() + // bytes long and both it and the additional data must match the + // value passed to Seal. + // + // The ciphertext and dst may alias exactly or not at all. To reuse + // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst. + // + // Even if the function fails, the contents of dst, up to its capacity, + // may be overwritten. + Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) +} + +// gcmAble is an interface implemented by ciphers that have a specific optimized +// implementation of GCM, like crypto/aes. NewGCM will check for this interface +// and return the specific AEAD if found. +type gcmAble interface { + NewGCM(int) (AEAD, error) +} + +// gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM +// standard and make getUint64 suitable for marshaling these values, the bits +// are stored backwards. For example: +// the coefficient of x⁰ can be obtained by v.low >> 63. +// the coefficient of x⁶³ can be obtained by v.low & 1. +// the coefficient of x⁶⁴ can be obtained by v.high >> 63. +// the coefficient of x¹²⁷ can be obtained by v.high & 1. +type gcmFieldElement struct { + low, high uint64 +} + +// gcm represents a Galois Counter Mode with a specific key. See +// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf +type gcm struct { + cipher Block + nonceSize int + // productTable contains the first sixteen powers of the key, H. + // However, they are in bit reversed order. See NewGCMWithNonceSize. + productTable [16]gcmFieldElement +} + +// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode +// with the standard nonce length. +func NewGCM(cipher Block) (AEAD, error) { + return NewGCMWithNonceSize(cipher, gcmStandardNonceSize) +} + +// NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois +// Counter Mode, which accepts nonces of the given length. +// +// Only use this function if you require compatibility with an existing +// cryptosystem that uses non-standard nonce lengths. All other users should use +// NewGCM, which is faster and more resistant to misuse. +func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) { + if cipher, ok := cipher.(gcmAble); ok { + return cipher.NewGCM(size) + } + + if cipher.BlockSize() != gcmBlockSize { + return nil, errors.New("cipher: NewGCM requires 128-bit block cipher") + } + + var key [gcmBlockSize]byte + cipher.Encrypt(key[:], key[:]) + + g := &gcm{cipher: cipher, nonceSize: size} + + // We precompute 16 multiples of |key|. However, when we do lookups + // into this table we'll be using bits from a field element and + // therefore the bits will be in the reverse order. So normally one + // would expect, say, 4*key to be in index 4 of the table but due to + // this bit ordering it will actually be in index 0010 (base 2) = 2. + x := gcmFieldElement{ + getUint64(key[:8]), + getUint64(key[8:]), + } + g.productTable[reverseBits(1)] = x + + for i := 2; i < 16; i += 2 { + g.productTable[reverseBits(i)] = gcmDouble(&g.productTable[reverseBits(i/2)]) + g.productTable[reverseBits(i+1)] = gcmAdd(&g.productTable[reverseBits(i)], &x) + } + + return g, nil +} + +const ( + gcmBlockSize = 16 + gcmTagSize = 12 + gcmStandardNonceSize = 12 +) + +func (g *gcm) NonceSize() int { + return g.nonceSize +} + +func (*gcm) Overhead() int { + return gcmTagSize +} + +func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte { + if len(nonce) != g.nonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize) + + var counter, tagMask [gcmBlockSize]byte + g.deriveCounter(&counter, nonce) + + g.cipher.Encrypt(tagMask[:], counter[:]) + gcmInc32(&counter) + + g.counterCrypt(out, plaintext, &counter) + + tag := make([]byte, 16) + g.auth(tag, out[:len(plaintext)], data, &tagMask) + copy(ret[len(ret)-12:], tag) + + return ret +} + +var errOpen = errors.New("cipher: message authentication failed") + +func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { + if len(nonce) != g.nonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + + if len(ciphertext) < gcmTagSize { + return nil, errOpen + } + tag := ciphertext[len(ciphertext)-gcmTagSize:] + ciphertext = ciphertext[:len(ciphertext)-gcmTagSize] + + var counter, tagMask [gcmBlockSize]byte + g.deriveCounter(&counter, nonce) + + g.cipher.Encrypt(tagMask[:], counter[:]) + gcmInc32(&counter) + + var expectedTag [gcmBlockSize]byte + g.auth(expectedTag[:], ciphertext, data, &tagMask) + + ret, out := sliceForAppend(dst, len(ciphertext)) + + if subtle.ConstantTimeCompare(expectedTag[:gcmTagSize], tag) != 1 { + // The AESNI code decrypts and authenticates concurrently, and + // so overwrites dst in the event of a tag mismatch. That + // behaviour is mimicked here in order to be consistent across + // platforms. + for i := range out { + out[i] = 0 + } + return nil, errOpen + } + + g.counterCrypt(out, ciphertext, &counter) + + return ret, nil +} + +// reverseBits reverses the order of the bits of 4-bit number in i. +func reverseBits(i int) int { + i = ((i << 2) & 0xc) | ((i >> 2) & 0x3) + i = ((i << 1) & 0xa) | ((i >> 1) & 0x5) + return i +} + +// gcmAdd adds two elements of GF(2¹²⁸) and returns the sum. +func gcmAdd(x, y *gcmFieldElement) gcmFieldElement { + // Addition in a characteristic 2 field is just XOR. + return gcmFieldElement{x.low ^ y.low, x.high ^ y.high} +} + +// gcmDouble returns the result of doubling an element of GF(2¹²⁸). +func gcmDouble(x *gcmFieldElement) (double gcmFieldElement) { + msbSet := x.high&1 == 1 + + // Because of the bit-ordering, doubling is actually a right shift. + double.high = x.high >> 1 + double.high |= x.low << 63 + double.low = x.low >> 1 + + // If the most-significant bit was set before shifting then it, + // conceptually, becomes a term of x^128. This is greater than the + // irreducible polynomial so the result has to be reduced. The + // irreducible polynomial is 1+x+x^2+x^7+x^128. We can subtract that to + // eliminate the term at x^128 which also means subtracting the other + // four terms. In characteristic 2 fields, subtraction == addition == + // XOR. + if msbSet { + double.low ^= 0xe100000000000000 + } + + return +} + +var gcmReductionTable = []uint16{ + 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0, +} + +// mul sets y to y*H, where H is the GCM key, fixed during NewGCMWithNonceSize. +func (g *gcm) mul(y *gcmFieldElement) { + var z gcmFieldElement + + for i := 0; i < 2; i++ { + word := y.high + if i == 1 { + word = y.low + } + + // Multiplication works by multiplying z by 16 and adding in + // one of the precomputed multiples of H. + for j := 0; j < 64; j += 4 { + msw := z.high & 0xf + z.high >>= 4 + z.high |= z.low << 60 + z.low >>= 4 + z.low ^= uint64(gcmReductionTable[msw]) << 48 + + // the values in |table| are ordered for + // little-endian bit positions. See the comment + // in NewGCMWithNonceSize. + t := &g.productTable[word&0xf] + + z.low ^= t.low + z.high ^= t.high + word >>= 4 + } + } + + *y = z +} + +// updateBlocks extends y with more polynomial terms from blocks, based on +// Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks. +func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) { + for len(blocks) > 0 { + y.low ^= getUint64(blocks) + y.high ^= getUint64(blocks[8:]) + g.mul(y) + blocks = blocks[gcmBlockSize:] + } +} + +// update extends y with more polynomial terms from data. If data is not a +// multiple of gcmBlockSize bytes long then the remainder is zero padded. +func (g *gcm) update(y *gcmFieldElement, data []byte) { + fullBlocks := (len(data) >> 4) << 4 + g.updateBlocks(y, data[:fullBlocks]) + + if len(data) != fullBlocks { + var partialBlock [gcmBlockSize]byte + copy(partialBlock[:], data[fullBlocks:]) + g.updateBlocks(y, partialBlock[:]) + } +} + +// gcmInc32 treats the final four bytes of counterBlock as a big-endian value +// and increments it. +func gcmInc32(counterBlock *[16]byte) { + for i := gcmBlockSize - 1; i >= gcmBlockSize-4; i-- { + counterBlock[i]++ + if counterBlock[i] != 0 { + break + } + } +} + +// sliceForAppend takes a slice and a requested number of bytes. It returns a +// slice with the contents of the given slice followed by that many bytes and a +// second slice that aliases into it and contains only the extra bytes. If the +// original slice has sufficient capacity then no allocation is performed. +func sliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return +} + +// counterCrypt crypts in to out using g.cipher in counter mode. +func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) { + var mask [gcmBlockSize]byte + + for len(in) >= gcmBlockSize { + g.cipher.Encrypt(mask[:], counter[:]) + gcmInc32(counter) + + xorWords(out, in, mask[:]) + out = out[gcmBlockSize:] + in = in[gcmBlockSize:] + } + + if len(in) > 0 { + g.cipher.Encrypt(mask[:], counter[:]) + gcmInc32(counter) + xorBytes(out, in, mask[:]) + } +} + +// deriveCounter computes the initial GCM counter state from the given nonce. +// See NIST SP 800-38D, section 7.1. This assumes that counter is filled with +// zeros on entry. +func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) { + // GCM has two modes of operation with respect to the initial counter + // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path" + // for nonces of other lengths. For a 96-bit nonce, the nonce, along + // with a four-byte big-endian counter starting at one, is used + // directly as the starting counter. For other nonce sizes, the counter + // is computed by passing it through the GHASH function. + if len(nonce) == gcmStandardNonceSize { + copy(counter[:], nonce) + counter[gcmBlockSize-1] = 1 + } else { + var y gcmFieldElement + g.update(&y, nonce) + y.high ^= uint64(len(nonce)) * 8 + g.mul(&y) + putUint64(counter[:8], y.low) + putUint64(counter[8:], y.high) + } +} + +// auth calculates GHASH(ciphertext, additionalData), masks the result with +// tagMask and writes the result to out. +func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmBlockSize]byte) { + var y gcmFieldElement + g.update(&y, additionalData) + g.update(&y, ciphertext) + + y.low ^= uint64(len(additionalData)) * 8 + y.high ^= uint64(len(ciphertext)) * 8 + + g.mul(&y) + + putUint64(out, y.low) + putUint64(out[8:], y.high) + + xorWords(out, out, tagMask[:]) +} + +func getUint64(data []byte) uint64 { + r := uint64(data[0])<<56 | + uint64(data[1])<<48 | + uint64(data[2])<<40 | + uint64(data[3])<<32 | + uint64(data[4])<<24 | + uint64(data[5])<<16 | + uint64(data[6])<<8 | + uint64(data[7]) + return r +} + +func putUint64(out []byte, v uint64) { + out[0] = byte(v >> 56) + out[1] = byte(v >> 48) + out[2] = byte(v >> 40) + out[3] = byte(v >> 32) + out[4] = byte(v >> 24) + out[5] = byte(v >> 16) + out[6] = byte(v >> 8) + out[7] = byte(v) +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm_amd64.s b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm_amd64.s new file mode 100644 index 00000000..c25badd5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/gcm_amd64.s @@ -0,0 +1,1277 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is an optimized implementation of AES-GCM using AES-NI and CLMUL-NI +// The implementation uses some optimization as described in: +// [1] Gueron, S., Kounavis, M.E.: Intel® Carry-Less Multiplication +// Instruction and its Usage for Computing the GCM Mode rev. 2.02 +// [2] Gueron, S., Krasnov, V.: Speeding up Counter Mode in Software and +// Hardware + +#include "textflag.h" + +#define B0 X0 +#define B1 X1 +#define B2 X2 +#define B3 X3 +#define B4 X4 +#define B5 X5 +#define B6 X6 +#define B7 X7 + +#define ACC0 X8 +#define ACC1 X9 +#define ACCM X10 + +#define T0 X11 +#define T1 X12 +#define T2 X13 +#define POLY X14 +#define BSWAP X15 + +DATA bswapMask<>+0x00(SB)/8, $0x08090a0b0c0d0e0f +DATA bswapMask<>+0x08(SB)/8, $0x0001020304050607 + +DATA gcmPoly<>+0x00(SB)/8, $0x0000000000000001 +DATA gcmPoly<>+0x08(SB)/8, $0xc200000000000000 + +DATA andMask<>+0x00(SB)/8, $0x00000000000000ff +DATA andMask<>+0x08(SB)/8, $0x0000000000000000 +DATA andMask<>+0x10(SB)/8, $0x000000000000ffff +DATA andMask<>+0x18(SB)/8, $0x0000000000000000 +DATA andMask<>+0x20(SB)/8, $0x0000000000ffffff +DATA andMask<>+0x28(SB)/8, $0x0000000000000000 +DATA andMask<>+0x30(SB)/8, $0x00000000ffffffff +DATA andMask<>+0x38(SB)/8, $0x0000000000000000 +DATA andMask<>+0x40(SB)/8, $0x000000ffffffffff +DATA andMask<>+0x48(SB)/8, $0x0000000000000000 +DATA andMask<>+0x50(SB)/8, $0x0000ffffffffffff +DATA andMask<>+0x58(SB)/8, $0x0000000000000000 +DATA andMask<>+0x60(SB)/8, $0x00ffffffffffffff +DATA andMask<>+0x68(SB)/8, $0x0000000000000000 +DATA andMask<>+0x70(SB)/8, $0xffffffffffffffff +DATA andMask<>+0x78(SB)/8, $0x0000000000000000 +DATA andMask<>+0x80(SB)/8, $0xffffffffffffffff +DATA andMask<>+0x88(SB)/8, $0x00000000000000ff +DATA andMask<>+0x90(SB)/8, $0xffffffffffffffff +DATA andMask<>+0x98(SB)/8, $0x000000000000ffff +DATA andMask<>+0xa0(SB)/8, $0xffffffffffffffff +DATA andMask<>+0xa8(SB)/8, $0x0000000000ffffff +DATA andMask<>+0xb0(SB)/8, $0xffffffffffffffff +DATA andMask<>+0xb8(SB)/8, $0x00000000ffffffff +DATA andMask<>+0xc0(SB)/8, $0xffffffffffffffff +DATA andMask<>+0xc8(SB)/8, $0x000000ffffffffff +DATA andMask<>+0xd0(SB)/8, $0xffffffffffffffff +DATA andMask<>+0xd8(SB)/8, $0x0000ffffffffffff +DATA andMask<>+0xe0(SB)/8, $0xffffffffffffffff +DATA andMask<>+0xe8(SB)/8, $0x00ffffffffffffff + +GLOBL bswapMask<>(SB), (NOPTR+RODATA), $16 +GLOBL gcmPoly<>(SB), (NOPTR+RODATA), $16 +GLOBL andMask<>(SB), (NOPTR+RODATA), $240 + +// func hasGCMAsm() bool +// returns whether AES-NI AND CLMUL-NI are supported +TEXT ·hasGCMAsm(SB),NOSPLIT,$0 + XORQ AX, AX + INCL AX + CPUID + MOVQ CX, DX + SHRQ $25, CX + SHRQ $1, DX + ANDQ DX, CX + ANDQ $1, CX + MOVB CX, ret+0(FP) + RET + +// func aesEncBlock(dst, src *[16]byte, ks []uint32) +TEXT ·aesEncBlock(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ ks_base+16(FP), DX + MOVQ ks_len+24(FP), CX + + SHRQ $2, CX + DECQ CX + + MOVOU (SI), X0 + MOVOU (16*0)(DX), X1 + PXOR X1, X0 + MOVOU (16*1)(DX), X1 + AESENC X1, X0 + MOVOU (16*2)(DX), X1 + AESENC X1, X0 + MOVOU (16*3)(DX), X1 + AESENC X1, X0 + MOVOU (16*4)(DX), X1 + AESENC X1, X0 + MOVOU (16*5)(DX), X1 + AESENC X1, X0 + MOVOU (16*6)(DX), X1 + AESENC X1, X0 + MOVOU (16*7)(DX), X1 + AESENC X1, X0 + MOVOU (16*8)(DX), X1 + AESENC X1, X0 + MOVOU (16*9)(DX), X1 + AESENC X1, X0 + MOVOU (16*10)(DX), X1 + CMPQ CX, $12 + JB encLast + AESENC X1, X0 + MOVOU (16*11)(DX), X1 + AESENC X1, X0 + MOVOU (16*12)(DX), X1 + JE encLast + AESENC X1, X0 + MOVOU (16*13)(DX), X1 + AESENC X1, X0 + MOVOU (16*14)(DX), X1 + +encLast: + AESENCLAST X1, X0 + MOVOU X0, (DI) + + RET + +// func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) +TEXT ·gcmAesFinish(SB),NOSPLIT,$0 +#define pTbl DI +#define tMsk SI +#define tPtr DX +#define plen AX +#define dlen CX + + MOVQ productTable+0(FP), pTbl + MOVQ tagMask+8(FP), tMsk + MOVQ T+16(FP), tPtr + MOVQ pLen+24(FP), plen + MOVQ dLen+32(FP), dlen + + MOVOU (tPtr), ACC0 + MOVOU (tMsk), T2 + + MOVOU bswapMask<>(SB), BSWAP + MOVOU gcmPoly<>(SB), POLY + + SHLQ $3, plen + SHLQ $3, dlen + + MOVQ plen, B0 + PINSRQ $1, dlen, B0 + + PXOR ACC0, B0 + + MOVOU (16*14)(pTbl), ACC0 + MOVOU (16*15)(pTbl), ACCM + MOVOU ACC0, ACC1 + + PCLMULQDQ $0x00, B0, ACC0 + PCLMULQDQ $0x11, B0, ACC1 + PSHUFD $78, B0, T0 + PXOR B0, T0 + PCLMULQDQ $0x00, T0, ACCM + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + MOVOU POLY, T0 + PCLMULQDQ $0x01, ACC0, T0 + PSHUFD $78, ACC0, ACC0 + PXOR T0, ACC0 + + MOVOU POLY, T0 + PCLMULQDQ $0x01, ACC0, T0 + PSHUFD $78, ACC0, ACC0 + PXOR T0, ACC0 + + PXOR ACC1, ACC0 + + PSHUFB BSWAP, ACC0 + PXOR T2, ACC0 + MOVOU ACC0, (tPtr) + + RET +#undef pTbl +#undef tMsk +#undef tPtr +#undef plen +#undef dlen + +// func gcmAesInit(productTable *[256]byte, ks []uint32) +TEXT ·gcmAesInit(SB),NOSPLIT,$0 +#define dst DI +#define KS SI +#define NR DX + + MOVQ productTable+0(FP), dst + MOVQ ks_base+8(FP), KS + MOVQ ks_len+16(FP), NR + + SHRQ $2, NR + DECQ NR + + MOVOU bswapMask<>(SB), BSWAP + MOVOU gcmPoly<>(SB), POLY + + // Encrypt block 0, with the AES key to generate the hash key H + MOVOU (16*0)(KS), B0 + MOVOU (16*1)(KS), T0 + AESENC T0, B0 + MOVOU (16*2)(KS), T0 + AESENC T0, B0 + MOVOU (16*3)(KS), T0 + AESENC T0, B0 + MOVOU (16*4)(KS), T0 + AESENC T0, B0 + MOVOU (16*5)(KS), T0 + AESENC T0, B0 + MOVOU (16*6)(KS), T0 + AESENC T0, B0 + MOVOU (16*7)(KS), T0 + AESENC T0, B0 + MOVOU (16*8)(KS), T0 + AESENC T0, B0 + MOVOU (16*9)(KS), T0 + AESENC T0, B0 + MOVOU (16*10)(KS), T0 + CMPQ NR, $12 + JB initEncLast + AESENC T0, B0 + MOVOU (16*11)(KS), T0 + AESENC T0, B0 + MOVOU (16*12)(KS), T0 + JE initEncLast + AESENC T0, B0 + MOVOU (16*13)(KS), T0 + AESENC T0, B0 + MOVOU (16*14)(KS), T0 +initEncLast: + AESENCLAST T0, B0 + + PSHUFB BSWAP, B0 + // H * 2 + PSHUFD $0xff, B0, T0 + MOVOU B0, T1 + PSRAL $31, T0 + PAND POLY, T0 + PSRLL $31, T1 + PSLLDQ $4, T1 + PSLLL $1, B0 + PXOR T0, B0 + PXOR T1, B0 + // Karatsuba pre-computations + MOVOU B0, (16*14)(dst) + PSHUFD $78, B0, B1 + PXOR B0, B1 + MOVOU B1, (16*15)(dst) + + MOVOU B0, B2 + MOVOU B1, B3 + // Now prepare powers of H and pre-computations for them + MOVQ $7, AX + +initLoop: + MOVOU B2, T0 + MOVOU B2, T1 + MOVOU B3, T2 + PCLMULQDQ $0x00, B0, T0 + PCLMULQDQ $0x11, B0, T1 + PCLMULQDQ $0x00, B1, T2 + + PXOR T0, T2 + PXOR T1, T2 + MOVOU T2, B4 + PSLLDQ $8, B4 + PSRLDQ $8, T2 + PXOR B4, T0 + PXOR T2, T1 + + MOVOU POLY, B2 + PCLMULQDQ $0x01, T0, B2 + PSHUFD $78, T0, T0 + PXOR B2, T0 + MOVOU POLY, B2 + PCLMULQDQ $0x01, T0, B2 + PSHUFD $78, T0, T0 + PXOR T0, B2 + PXOR T1, B2 + + MOVOU B2, (16*12)(dst) + PSHUFD $78, B2, B3 + PXOR B2, B3 + MOVOU B3, (16*13)(dst) + + DECQ AX + LEAQ (-16*2)(dst), dst + JNE initLoop + + RET +#undef NR +#undef KS +#undef dst + +// func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte) +TEXT ·gcmAesData(SB),NOSPLIT,$0 +#define pTbl DI +#define aut SI +#define tPtr CX +#define autLen DX + + MOVQ productTable+0(FP), pTbl + MOVQ data_base+8(FP), aut + MOVQ data_len+16(FP), autLen + MOVQ T+32(FP), tPtr + + PXOR ACC0, ACC0 + MOVOU bswapMask<>(SB), BSWAP + MOVOU gcmPoly<>(SB), POLY + + MOVOU (16*14)(pTbl), T1 + MOVOU (16*15)(pTbl), T2 + + TESTQ autLen, autLen + JEQ dataBail + + CMPQ autLen, $13 // optimize the TLS case + JNE dataSinglesLoop + + PXOR B0, B0 + MOVQ (aut), B0 + PINSRD $2, 8(aut), B0 + PINSRB $12, 12(aut), B0 + XORQ autLen, autLen + JMP dataMul + +dataSinglesLoop: + + CMPQ autLen, $16 + JB dataEnd + SUBQ $16, autLen + + MOVOU (aut), B0 +dataMul: + PSHUFB BSWAP, B0 + PXOR ACC0, B0 + + MOVOU T1, ACC0 + MOVOU T2, ACCM + MOVOU T1, ACC1 + + PSHUFD $78, B0, T0 + PXOR B0, T0 + PCLMULQDQ $0x00, B0, ACC0 + PCLMULQDQ $0x11, B0, ACC1 + PCLMULQDQ $0x00, T0, ACCM + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + MOVOU POLY, T0 + PCLMULQDQ $0x01, ACC0, T0 + PSHUFD $78, ACC0, ACC0 + PXOR T0, ACC0 + + MOVOU POLY, T0 + PCLMULQDQ $0x01, ACC0, T0 + PSHUFD $78, ACC0, ACC0 + PXOR T0, ACC0 + PXOR ACC1, ACC0 + + LEAQ 16(aut), aut + + JMP dataSinglesLoop + +dataEnd: + + TESTQ autLen, autLen + JEQ dataBail + + PXOR B0, B0 + LEAQ -1(aut)(autLen*1), aut + +dataLoadLoop: + + PSLLDQ $1, B0 + PINSRB $0, (aut), B0 + + LEAQ -1(aut), aut + DECQ autLen + JNE dataLoadLoop + + JMP dataMul + +dataBail: + MOVOU ACC0, (tPtr) + RET +#undef pTbl +#undef aut +#undef tPtr +#undef autLen + +// func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) +TEXT ·gcmAesEnc(SB),0,$256-96 +#define pTbl DI +#define ctx DX +#define ctrPtr CX +#define ptx SI +#define ks AX +#define tPtr R8 +#define ptxLen R9 +#define aluCTR R10 +#define aluTMP R11 +#define aluK R12 +#define NR R13 + +#define increment(i) ADDL $1, aluCTR; MOVL aluCTR, aluTMP; XORL aluK, aluTMP; BSWAPL aluTMP; MOVL aluTMP, (3*4 + 8*16 + i*16)(SP) +#define aesRnd(k) AESENC k, B0; AESENC k, B1; AESENC k, B2; AESENC k, B3; AESENC k, B4; AESENC k, B5; AESENC k, B6; AESENC k, B7 +#define aesRound(i) MOVOU (16*i)(ks), T0;AESENC T0, B0; AESENC T0, B1; AESENC T0, B2; AESENC T0, B3; AESENC T0, B4; AESENC T0, B5; AESENC T0, B6; AESENC T0, B7 +#define aesRndLast(k) AESENCLAST k, B0; AESENCLAST k, B1; AESENCLAST k, B2; AESENCLAST k, B3; AESENCLAST k, B4; AESENCLAST k, B5; AESENCLAST k, B6; AESENCLAST k, B7 +#define reduceRound(a) MOVOU POLY, T0; PCLMULQDQ $0x01, a, T0; PSHUFD $78, a, a; PXOR T0, a +#define combinedRound(i) \ + MOVOU (16*i)(ks), T0;\ + AESENC T0, B0;\ + AESENC T0, B1;\ + AESENC T0, B2;\ + AESENC T0, B3;\ + MOVOU (16*(i*2))(pTbl), T1;\ + MOVOU T1, T2;\ + AESENC T0, B4;\ + AESENC T0, B5;\ + AESENC T0, B6;\ + AESENC T0, B7;\ + MOVOU (16*i)(SP), T0;\ + PCLMULQDQ $0x00, T0, T1;\ + PXOR T1, ACC0;\ + PSHUFD $78, T0, T1;\ + PCLMULQDQ $0x11, T0, T2;\ + PXOR T1, T0;\ + PXOR T2, ACC1;\ + MOVOU (16*(i*2+1))(pTbl), T2;\ + PCLMULQDQ $0x00, T2, T0;\ + PXOR T0, ACCM +#define mulRound(i) \ + MOVOU (16*i)(SP), T0;\ + MOVOU (16*(i*2))(pTbl), T1;\ + MOVOU T1, T2;\ + PCLMULQDQ $0x00, T0, T1;\ + PXOR T1, ACC0;\ + PCLMULQDQ $0x11, T0, T2;\ + PXOR T2, ACC1;\ + PSHUFD $78, T0, T1;\ + PXOR T1, T0;\ + MOVOU (16*(i*2+1))(pTbl), T1;\ + PCLMULQDQ $0x00, T0, T1;\ + PXOR T1, ACCM + + MOVQ productTable+0(FP), pTbl + MOVQ dst+8(FP), ctx + MOVQ src_base+32(FP), ptx + MOVQ src_len+40(FP), ptxLen + MOVQ ctr+56(FP), ctrPtr + MOVQ T+64(FP), tPtr + MOVQ ks_base+72(FP), ks + MOVQ ks_len+80(FP), NR + + SHRQ $2, NR + DECQ NR + + MOVOU bswapMask<>(SB), BSWAP + MOVOU gcmPoly<>(SB), POLY + + MOVOU (tPtr), ACC0 + PXOR ACC1, ACC1 + PXOR ACCM, ACCM + MOVOU (ctrPtr), B0 + MOVL (3*4)(ctrPtr), aluCTR + MOVOU (ks), T0 + MOVL (3*4)(ks), aluK + BSWAPL aluCTR + BSWAPL aluK + + PXOR B0, T0 + MOVOU T0, (8*16 + 0*16)(SP) + increment(0) + + CMPQ ptxLen, $128 + JB gcmAesEncSingles + SUBQ $128, ptxLen + + // We have at least 8 blocks to encrypt, prepare the rest of the counters + MOVOU T0, (8*16 + 1*16)(SP) + increment(1) + MOVOU T0, (8*16 + 2*16)(SP) + increment(2) + MOVOU T0, (8*16 + 3*16)(SP) + increment(3) + MOVOU T0, (8*16 + 4*16)(SP) + increment(4) + MOVOU T0, (8*16 + 5*16)(SP) + increment(5) + MOVOU T0, (8*16 + 6*16)(SP) + increment(6) + MOVOU T0, (8*16 + 7*16)(SP) + increment(7) + + MOVOU (8*16 + 0*16)(SP), B0 + MOVOU (8*16 + 1*16)(SP), B1 + MOVOU (8*16 + 2*16)(SP), B2 + MOVOU (8*16 + 3*16)(SP), B3 + MOVOU (8*16 + 4*16)(SP), B4 + MOVOU (8*16 + 5*16)(SP), B5 + MOVOU (8*16 + 6*16)(SP), B6 + MOVOU (8*16 + 7*16)(SP), B7 + + aesRound(1) + increment(0) + aesRound(2) + increment(1) + aesRound(3) + increment(2) + aesRound(4) + increment(3) + aesRound(5) + increment(4) + aesRound(6) + increment(5) + aesRound(7) + increment(6) + aesRound(8) + increment(7) + aesRound(9) + MOVOU (16*10)(ks), T0 + CMPQ NR, $12 + JB encLast1 + aesRnd(T0) + aesRound(11) + MOVOU (16*12)(ks), T0 + JE encLast1 + aesRnd(T0) + aesRound(13) + MOVOU (16*14)(ks), T0 +encLast1: + aesRndLast(T0) + + MOVOU (16*0)(ptx), T0 + PXOR T0, B0 + MOVOU (16*1)(ptx), T0 + PXOR T0, B1 + MOVOU (16*2)(ptx), T0 + PXOR T0, B2 + MOVOU (16*3)(ptx), T0 + PXOR T0, B3 + MOVOU (16*4)(ptx), T0 + PXOR T0, B4 + MOVOU (16*5)(ptx), T0 + PXOR T0, B5 + MOVOU (16*6)(ptx), T0 + PXOR T0, B6 + MOVOU (16*7)(ptx), T0 + PXOR T0, B7 + + MOVOU B0, (16*0)(ctx) + PSHUFB BSWAP, B0 + PXOR ACC0, B0 + MOVOU B1, (16*1)(ctx) + PSHUFB BSWAP, B1 + MOVOU B2, (16*2)(ctx) + PSHUFB BSWAP, B2 + MOVOU B3, (16*3)(ctx) + PSHUFB BSWAP, B3 + MOVOU B4, (16*4)(ctx) + PSHUFB BSWAP, B4 + MOVOU B5, (16*5)(ctx) + PSHUFB BSWAP, B5 + MOVOU B6, (16*6)(ctx) + PSHUFB BSWAP, B6 + MOVOU B7, (16*7)(ctx) + PSHUFB BSWAP, B7 + + MOVOU B0, (16*0)(SP) + MOVOU B1, (16*1)(SP) + MOVOU B2, (16*2)(SP) + MOVOU B3, (16*3)(SP) + MOVOU B4, (16*4)(SP) + MOVOU B5, (16*5)(SP) + MOVOU B6, (16*6)(SP) + MOVOU B7, (16*7)(SP) + + LEAQ 128(ptx), ptx + LEAQ 128(ctx), ctx + +gcmAesEncOctetsLoop: + + CMPQ ptxLen, $128 + JB gcmAesEncOctetsEnd + SUBQ $128, ptxLen + + MOVOU (8*16 + 0*16)(SP), B0 + MOVOU (8*16 + 1*16)(SP), B1 + MOVOU (8*16 + 2*16)(SP), B2 + MOVOU (8*16 + 3*16)(SP), B3 + MOVOU (8*16 + 4*16)(SP), B4 + MOVOU (8*16 + 5*16)(SP), B5 + MOVOU (8*16 + 6*16)(SP), B6 + MOVOU (8*16 + 7*16)(SP), B7 + + MOVOU (16*0)(SP), T0 + PSHUFD $78, T0, T1 + PXOR T0, T1 + + MOVOU (16*0)(pTbl), ACC0 + MOVOU (16*1)(pTbl), ACCM + MOVOU ACC0, ACC1 + + PCLMULQDQ $0x00, T1, ACCM + PCLMULQDQ $0x00, T0, ACC0 + PCLMULQDQ $0x11, T0, ACC1 + + combinedRound(1) + increment(0) + combinedRound(2) + increment(1) + combinedRound(3) + increment(2) + combinedRound(4) + increment(3) + combinedRound(5) + increment(4) + combinedRound(6) + increment(5) + combinedRound(7) + increment(6) + + aesRound(8) + increment(7) + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + reduceRound(ACC0) + aesRound(9) + + reduceRound(ACC0) + PXOR ACC1, ACC0 + + MOVOU (16*10)(ks), T0 + CMPQ NR, $12 + JB encLast2 + aesRnd(T0) + aesRound(11) + MOVOU (16*12)(ks), T0 + JE encLast2 + aesRnd(T0) + aesRound(13) + MOVOU (16*14)(ks), T0 +encLast2: + aesRndLast(T0) + + MOVOU (16*0)(ptx), T0 + PXOR T0, B0 + MOVOU (16*1)(ptx), T0 + PXOR T0, B1 + MOVOU (16*2)(ptx), T0 + PXOR T0, B2 + MOVOU (16*3)(ptx), T0 + PXOR T0, B3 + MOVOU (16*4)(ptx), T0 + PXOR T0, B4 + MOVOU (16*5)(ptx), T0 + PXOR T0, B5 + MOVOU (16*6)(ptx), T0 + PXOR T0, B6 + MOVOU (16*7)(ptx), T0 + PXOR T0, B7 + + MOVOU B0, (16*0)(ctx) + PSHUFB BSWAP, B0 + PXOR ACC0, B0 + MOVOU B1, (16*1)(ctx) + PSHUFB BSWAP, B1 + MOVOU B2, (16*2)(ctx) + PSHUFB BSWAP, B2 + MOVOU B3, (16*3)(ctx) + PSHUFB BSWAP, B3 + MOVOU B4, (16*4)(ctx) + PSHUFB BSWAP, B4 + MOVOU B5, (16*5)(ctx) + PSHUFB BSWAP, B5 + MOVOU B6, (16*6)(ctx) + PSHUFB BSWAP, B6 + MOVOU B7, (16*7)(ctx) + PSHUFB BSWAP, B7 + + MOVOU B0, (16*0)(SP) + MOVOU B1, (16*1)(SP) + MOVOU B2, (16*2)(SP) + MOVOU B3, (16*3)(SP) + MOVOU B4, (16*4)(SP) + MOVOU B5, (16*5)(SP) + MOVOU B6, (16*6)(SP) + MOVOU B7, (16*7)(SP) + + LEAQ 128(ptx), ptx + LEAQ 128(ctx), ctx + + JMP gcmAesEncOctetsLoop + +gcmAesEncOctetsEnd: + + MOVOU (16*0)(SP), T0 + MOVOU (16*0)(pTbl), ACC0 + MOVOU (16*1)(pTbl), ACCM + MOVOU ACC0, ACC1 + PSHUFD $78, T0, T1 + PXOR T0, T1 + PCLMULQDQ $0x00, T0, ACC0 + PCLMULQDQ $0x11, T0, ACC1 + PCLMULQDQ $0x00, T1, ACCM + + mulRound(1) + mulRound(2) + mulRound(3) + mulRound(4) + mulRound(5) + mulRound(6) + mulRound(7) + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + reduceRound(ACC0) + reduceRound(ACC0) + PXOR ACC1, ACC0 + + TESTQ ptxLen, ptxLen + JE gcmAesEncDone + + SUBQ $7, aluCTR + +gcmAesEncSingles: + + MOVOU (16*1)(ks), B1 + MOVOU (16*2)(ks), B2 + MOVOU (16*3)(ks), B3 + MOVOU (16*4)(ks), B4 + MOVOU (16*5)(ks), B5 + MOVOU (16*6)(ks), B6 + MOVOU (16*7)(ks), B7 + + MOVOU (16*14)(pTbl), T2 + +gcmAesEncSinglesLoop: + + CMPQ ptxLen, $16 + JB gcmAesEncTail + SUBQ $16, ptxLen + + MOVOU (8*16 + 0*16)(SP), B0 + increment(0) + + AESENC B1, B0 + AESENC B2, B0 + AESENC B3, B0 + AESENC B4, B0 + AESENC B5, B0 + AESENC B6, B0 + AESENC B7, B0 + MOVOU (16*8)(ks), T0 + AESENC T0, B0 + MOVOU (16*9)(ks), T0 + AESENC T0, B0 + MOVOU (16*10)(ks), T0 + CMPQ NR, $12 + JB encLast3 + AESENC T0, B0 + MOVOU (16*11)(ks), T0 + AESENC T0, B0 + MOVOU (16*12)(ks), T0 + JE encLast3 + AESENC T0, B0 + MOVOU (16*13)(ks), T0 + AESENC T0, B0 + MOVOU (16*14)(ks), T0 +encLast3: + AESENCLAST T0, B0 + + MOVOU (ptx), T0 + PXOR T0, B0 + MOVOU B0, (ctx) + + PSHUFB BSWAP, B0 + PXOR ACC0, B0 + + MOVOU T2, ACC0 + MOVOU T2, ACC1 + MOVOU (16*15)(pTbl), ACCM + + PSHUFD $78, B0, T0 + PXOR B0, T0 + PCLMULQDQ $0x00, B0, ACC0 + PCLMULQDQ $0x11, B0, ACC1 + PCLMULQDQ $0x00, T0, ACCM + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + reduceRound(ACC0) + reduceRound(ACC0) + PXOR ACC1, ACC0 + + LEAQ (16*1)(ptx), ptx + LEAQ (16*1)(ctx), ctx + + JMP gcmAesEncSinglesLoop + +gcmAesEncTail: + TESTQ ptxLen, ptxLen + JE gcmAesEncDone + + MOVOU (8*16 + 0*16)(SP), B0 + AESENC B1, B0 + AESENC B2, B0 + AESENC B3, B0 + AESENC B4, B0 + AESENC B5, B0 + AESENC B6, B0 + AESENC B7, B0 + MOVOU (16*8)(ks), T0 + AESENC T0, B0 + MOVOU (16*9)(ks), T0 + AESENC T0, B0 + MOVOU (16*10)(ks), T0 + CMPQ NR, $12 + JB encLast4 + AESENC T0, B0 + MOVOU (16*11)(ks), T0 + AESENC T0, B0 + MOVOU (16*12)(ks), T0 + JE encLast4 + AESENC T0, B0 + MOVOU (16*13)(ks), T0 + AESENC T0, B0 + MOVOU (16*14)(ks), T0 +encLast4: + AESENCLAST T0, B0 + MOVOU B0, T0 + + LEAQ -1(ptx)(ptxLen*1), ptx + + MOVQ ptxLen, aluTMP + SHLQ $4, aluTMP + + LEAQ andMask<>(SB), aluCTR + MOVOU -16(aluCTR)(aluTMP*1), T1 + + PXOR B0, B0 +ptxLoadLoop: + PSLLDQ $1, B0 + PINSRB $0, (ptx), B0 + LEAQ -1(ptx), ptx + DECQ ptxLen + JNE ptxLoadLoop + + PXOR T0, B0 + PAND T1, B0 + MOVOU B0, (ctx) // I assume there is always space, due to TAG in the end of the CT + + PSHUFB BSWAP, B0 + PXOR ACC0, B0 + + MOVOU T2, ACC0 + MOVOU T2, ACC1 + MOVOU (16*15)(pTbl), ACCM + + PSHUFD $78, B0, T0 + PXOR B0, T0 + PCLMULQDQ $0x00, B0, ACC0 + PCLMULQDQ $0x11, B0, ACC1 + PCLMULQDQ $0x00, T0, ACCM + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + reduceRound(ACC0) + reduceRound(ACC0) + PXOR ACC1, ACC0 + +gcmAesEncDone: + MOVOU ACC0, (tPtr) + RET +#undef increment + +// func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) +TEXT ·gcmAesDec(SB),0,$128-96 +#define increment(i) ADDL $1, aluCTR; MOVL aluCTR, aluTMP; XORL aluK, aluTMP; BSWAPL aluTMP; MOVL aluTMP, (3*4 + i*16)(SP) +#define combinedDecRound(i) \ + MOVOU (16*i)(ks), T0;\ + AESENC T0, B0;\ + AESENC T0, B1;\ + AESENC T0, B2;\ + AESENC T0, B3;\ + MOVOU (16*(i*2))(pTbl), T1;\ + MOVOU T1, T2;\ + AESENC T0, B4;\ + AESENC T0, B5;\ + AESENC T0, B6;\ + AESENC T0, B7;\ + MOVOU (16*i)(ctx), T0;\ + PSHUFB BSWAP, T0;\ + PCLMULQDQ $0x00, T0, T1;\ + PXOR T1, ACC0;\ + PSHUFD $78, T0, T1;\ + PCLMULQDQ $0x11, T0, T2;\ + PXOR T1, T0;\ + PXOR T2, ACC1;\ + MOVOU (16*(i*2+1))(pTbl), T2;\ + PCLMULQDQ $0x00, T2, T0;\ + PXOR T0, ACCM + + MOVQ productTable+0(FP), pTbl + MOVQ dst+8(FP), ptx + MOVQ src_base+32(FP), ctx + MOVQ src_len+40(FP), ptxLen + MOVQ ctr+56(FP), ctrPtr + MOVQ T+64(FP), tPtr + MOVQ ks_base+72(FP), ks + MOVQ ks_len+80(FP), NR + + SHRQ $2, NR + DECQ NR + + MOVOU bswapMask<>(SB), BSWAP + MOVOU gcmPoly<>(SB), POLY + + MOVOU (tPtr), ACC0 + PXOR ACC1, ACC1 + PXOR ACCM, ACCM + MOVOU (ctrPtr), B0 + MOVL (3*4)(ctrPtr), aluCTR + MOVOU (ks), T0 + MOVL (3*4)(ks), aluK + BSWAPL aluCTR + BSWAPL aluK + + PXOR B0, T0 + MOVOU T0, (0*16)(SP) + increment(0) + + CMPQ ptxLen, $128 + JB gcmAesDecSingles + + MOVOU T0, (1*16)(SP) + increment(1) + MOVOU T0, (2*16)(SP) + increment(2) + MOVOU T0, (3*16)(SP) + increment(3) + MOVOU T0, (4*16)(SP) + increment(4) + MOVOU T0, (5*16)(SP) + increment(5) + MOVOU T0, (6*16)(SP) + increment(6) + MOVOU T0, (7*16)(SP) + increment(7) + +gcmAesDecOctetsLoop: + + CMPQ ptxLen, $128 + JB gcmAesDecEndOctets + SUBQ $128, ptxLen + + MOVOU (0*16)(SP), B0 + MOVOU (1*16)(SP), B1 + MOVOU (2*16)(SP), B2 + MOVOU (3*16)(SP), B3 + MOVOU (4*16)(SP), B4 + MOVOU (5*16)(SP), B5 + MOVOU (6*16)(SP), B6 + MOVOU (7*16)(SP), B7 + + MOVOU (16*0)(ctx), T0 + PSHUFB BSWAP, T0 + PXOR ACC0, T0 + PSHUFD $78, T0, T1 + PXOR T0, T1 + + MOVOU (16*0)(pTbl), ACC0 + MOVOU (16*1)(pTbl), ACCM + MOVOU ACC0, ACC1 + + PCLMULQDQ $0x00, T1, ACCM + PCLMULQDQ $0x00, T0, ACC0 + PCLMULQDQ $0x11, T0, ACC1 + + combinedDecRound(1) + increment(0) + combinedDecRound(2) + increment(1) + combinedDecRound(3) + increment(2) + combinedDecRound(4) + increment(3) + combinedDecRound(5) + increment(4) + combinedDecRound(6) + increment(5) + combinedDecRound(7) + increment(6) + + aesRound(8) + increment(7) + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + reduceRound(ACC0) + aesRound(9) + + reduceRound(ACC0) + PXOR ACC1, ACC0 + + MOVOU (16*10)(ks), T0 + CMPQ NR, $12 + JB decLast1 + aesRnd(T0) + aesRound(11) + MOVOU (16*12)(ks), T0 + JE decLast1 + aesRnd(T0) + aesRound(13) + MOVOU (16*14)(ks), T0 +decLast1: + aesRndLast(T0) + + MOVOU (16*0)(ctx), T0 + PXOR T0, B0 + MOVOU (16*1)(ctx), T0 + PXOR T0, B1 + MOVOU (16*2)(ctx), T0 + PXOR T0, B2 + MOVOU (16*3)(ctx), T0 + PXOR T0, B3 + MOVOU (16*4)(ctx), T0 + PXOR T0, B4 + MOVOU (16*5)(ctx), T0 + PXOR T0, B5 + MOVOU (16*6)(ctx), T0 + PXOR T0, B6 + MOVOU (16*7)(ctx), T0 + PXOR T0, B7 + + MOVOU B0, (16*0)(ptx) + MOVOU B1, (16*1)(ptx) + MOVOU B2, (16*2)(ptx) + MOVOU B3, (16*3)(ptx) + MOVOU B4, (16*4)(ptx) + MOVOU B5, (16*5)(ptx) + MOVOU B6, (16*6)(ptx) + MOVOU B7, (16*7)(ptx) + + LEAQ 128(ptx), ptx + LEAQ 128(ctx), ctx + + JMP gcmAesDecOctetsLoop + +gcmAesDecEndOctets: + + SUBQ $7, aluCTR + +gcmAesDecSingles: + + MOVOU (16*1)(ks), B1 + MOVOU (16*2)(ks), B2 + MOVOU (16*3)(ks), B3 + MOVOU (16*4)(ks), B4 + MOVOU (16*5)(ks), B5 + MOVOU (16*6)(ks), B6 + MOVOU (16*7)(ks), B7 + + MOVOU (16*14)(pTbl), T2 + +gcmAesDecSinglesLoop: + + CMPQ ptxLen, $16 + JB gcmAesDecTail + SUBQ $16, ptxLen + + MOVOU (ctx), B0 + MOVOU B0, T1 + PSHUFB BSWAP, B0 + PXOR ACC0, B0 + + MOVOU T2, ACC0 + MOVOU T2, ACC1 + MOVOU (16*15)(pTbl), ACCM + + PCLMULQDQ $0x00, B0, ACC0 + PCLMULQDQ $0x11, B0, ACC1 + PSHUFD $78, B0, T0 + PXOR B0, T0 + PCLMULQDQ $0x00, T0, ACCM + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + reduceRound(ACC0) + reduceRound(ACC0) + PXOR ACC1, ACC0 + + MOVOU (0*16)(SP), B0 + increment(0) + AESENC B1, B0 + AESENC B2, B0 + AESENC B3, B0 + AESENC B4, B0 + AESENC B5, B0 + AESENC B6, B0 + AESENC B7, B0 + MOVOU (16*8)(ks), T0 + AESENC T0, B0 + MOVOU (16*9)(ks), T0 + AESENC T0, B0 + MOVOU (16*10)(ks), T0 + CMPQ NR, $12 + JB decLast2 + AESENC T0, B0 + MOVOU (16*11)(ks), T0 + AESENC T0, B0 + MOVOU (16*12)(ks), T0 + JE decLast2 + AESENC T0, B0 + MOVOU (16*13)(ks), T0 + AESENC T0, B0 + MOVOU (16*14)(ks), T0 +decLast2: + AESENCLAST T0, B0 + + PXOR T1, B0 + MOVOU B0, (ptx) + + LEAQ (16*1)(ptx), ptx + LEAQ (16*1)(ctx), ctx + + JMP gcmAesDecSinglesLoop + +gcmAesDecTail: + + TESTQ ptxLen, ptxLen + JE gcmAesDecDone + + MOVQ ptxLen, aluTMP + SHLQ $4, aluTMP + LEAQ andMask<>(SB), aluCTR + MOVOU -16(aluCTR)(aluTMP*1), T1 + + MOVOU (ctx), B0 // I assume there is TAG attached to the ctx, and there is no read overflow + PAND T1, B0 + + MOVOU B0, T1 + PSHUFB BSWAP, B0 + PXOR ACC0, B0 + + MOVOU (16*14)(pTbl), ACC0 + MOVOU (16*15)(pTbl), ACCM + MOVOU ACC0, ACC1 + + PCLMULQDQ $0x00, B0, ACC0 + PCLMULQDQ $0x11, B0, ACC1 + PSHUFD $78, B0, T0 + PXOR B0, T0 + PCLMULQDQ $0x00, T0, ACCM + + PXOR ACC0, ACCM + PXOR ACC1, ACCM + MOVOU ACCM, T0 + PSRLDQ $8, ACCM + PSLLDQ $8, T0 + PXOR ACCM, ACC1 + PXOR T0, ACC0 + + reduceRound(ACC0) + reduceRound(ACC0) + PXOR ACC1, ACC0 + + MOVOU (0*16)(SP), B0 + increment(0) + AESENC B1, B0 + AESENC B2, B0 + AESENC B3, B0 + AESENC B4, B0 + AESENC B5, B0 + AESENC B6, B0 + AESENC B7, B0 + MOVOU (16*8)(ks), T0 + AESENC T0, B0 + MOVOU (16*9)(ks), T0 + AESENC T0, B0 + MOVOU (16*10)(ks), T0 + CMPQ NR, $12 + JB decLast3 + AESENC T0, B0 + MOVOU (16*11)(ks), T0 + AESENC T0, B0 + MOVOU (16*12)(ks), T0 + JE decLast3 + AESENC T0, B0 + MOVOU (16*13)(ks), T0 + AESENC T0, B0 + MOVOU (16*14)(ks), T0 +decLast3: + AESENCLAST T0, B0 + PXOR T1, B0 + +ptxStoreLoop: + PEXTRB $0, B0, (ptx) + PSRLDQ $1, B0 + LEAQ 1(ptx), ptx + DECQ ptxLen + + JNE ptxStoreLoop + +gcmAesDecDone: + + MOVOU ACC0, (tPtr) + RET diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/xor.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/xor.go new file mode 100644 index 00000000..668c13fd --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/aes12/xor.go @@ -0,0 +1,84 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package aes12 + +import ( + "runtime" + "unsafe" +) + +const wordSize = int(unsafe.Sizeof(uintptr(0))) +const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" + +// fastXORBytes xors in bulk. It only works on architectures that +// support unaligned read/writes. +func fastXORBytes(dst, a, b []byte) int { + n := len(a) + if len(b) < n { + n = len(b) + } + + w := n / wordSize + if w > 0 { + dw := *(*[]uintptr)(unsafe.Pointer(&dst)) + aw := *(*[]uintptr)(unsafe.Pointer(&a)) + bw := *(*[]uintptr)(unsafe.Pointer(&b)) + for i := 0; i < w; i++ { + dw[i] = aw[i] ^ bw[i] + } + } + + for i := (n - n%wordSize); i < n; i++ { + dst[i] = a[i] ^ b[i] + } + + return n +} + +func safeXORBytes(dst, a, b []byte) int { + n := len(a) + if len(b) < n { + n = len(b) + } + for i := 0; i < n; i++ { + dst[i] = a[i] ^ b[i] + } + return n +} + +// xorBytes xors the bytes in a and b. The destination is assumed to have enough +// space. Returns the number of bytes xor'd. +func xorBytes(dst, a, b []byte) int { + if supportsUnaligned { + return fastXORBytes(dst, a, b) + } else { + // TODO(hanwen): if (dst, a, b) have common alignment + // we could still try fastXORBytes. It is not clear + // how often this happens, and it's only worth it if + // the block encryption itself is hardware + // accelerated. + return safeXORBytes(dst, a, b) + } +} + +// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.) +// The arguments are assumed to be of equal length. +func fastXORWords(dst, a, b []byte) { + dw := *(*[]uintptr)(unsafe.Pointer(&dst)) + aw := *(*[]uintptr)(unsafe.Pointer(&a)) + bw := *(*[]uintptr)(unsafe.Pointer(&b)) + n := len(b) / wordSize + for i := 0; i < n; i++ { + dw[i] = aw[i] ^ bw[i] + } +} + +func xorWords(dst, a, b []byte) { + if supportsUnaligned { + fastXORWords(dst, a, b) + } else { + safeXORBytes(dst, a, b) + } +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/LICENSE b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/LICENSE new file mode 100644 index 00000000..2c08ae24 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Lucas Clemente + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/README.md b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/README.md new file mode 100644 index 00000000..c9621d5c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/README.md @@ -0,0 +1,3 @@ +# certsets + +Common certificate sets for quic-go diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_2.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_2.go new file mode 100644 index 00000000..f2f2250f --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_2.go @@ -0,0 +1,5824 @@ +package certsets + +var CertSet2 = [][]byte{ + certSet2Cert0, + certSet2Cert1, + certSet2Cert2, + certSet2Cert3, + certSet2Cert4, + certSet2Cert5, + certSet2Cert6, + certSet2Cert7, + certSet2Cert8, + certSet2Cert9, + certSet2Cert10, + certSet2Cert11, + certSet2Cert12, + certSet2Cert13, + certSet2Cert14, + certSet2Cert15, + certSet2Cert16, + certSet2Cert17, + certSet2Cert18, + certSet2Cert19, + certSet2Cert20, + certSet2Cert21, + certSet2Cert22, + certSet2Cert23, + certSet2Cert24, + certSet2Cert25, + certSet2Cert26, + certSet2Cert27, + certSet2Cert28, + certSet2Cert29, + certSet2Cert30, + certSet2Cert31, + certSet2Cert32, + certSet2Cert33, + certSet2Cert34, + certSet2Cert35, + certSet2Cert36, + certSet2Cert37, + certSet2Cert38, + certSet2Cert39, + certSet2Cert40, + certSet2Cert41, + certSet2Cert42, + certSet2Cert43, + certSet2Cert44, + certSet2Cert45, + certSet2Cert46, + certSet2Cert47, + certSet2Cert48, + certSet2Cert49, + certSet2Cert50, + certSet2Cert51, + certSet2Cert52, + certSet2Cert53, +} + +const CertSet2Hash uint64 = (0xe81a92926081e801) + +var certSet2Cert0 = []byte{ + 0x30, 0x82, 0x03, 0x7d, 0x30, 0x82, 0x02, 0xe6, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x12, 0xbb, 0xe6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x45, + 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, + 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x32, 0x30, + 0x35, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x31, 0x38, 0x30, 0x38, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, + 0x5a, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0xcc, 0x18, 0x63, 0x30, 0xfd, + 0xf4, 0x17, 0x23, 0x1a, 0x56, 0x7e, 0x5b, 0xdf, 0x3c, 0x6c, 0x38, 0xe4, + 0x71, 0xb7, 0x78, 0x91, 0xd4, 0xbc, 0xa1, 0xd8, 0x4c, 0xf8, 0xa8, 0x43, + 0xb6, 0x03, 0xe9, 0x4d, 0x21, 0x07, 0x08, 0x88, 0xda, 0x58, 0x2f, 0x66, + 0x39, 0x29, 0xbd, 0x05, 0x78, 0x8b, 0x9d, 0x38, 0xe8, 0x05, 0xb7, 0x6a, + 0x7e, 0x71, 0xa4, 0xe6, 0xc4, 0x60, 0xa6, 0xb0, 0xef, 0x80, 0xe4, 0x89, + 0x28, 0x0f, 0x9e, 0x25, 0xd6, 0xed, 0x83, 0xf3, 0xad, 0xa6, 0x91, 0xc7, + 0x98, 0xc9, 0x42, 0x18, 0x35, 0x14, 0x9d, 0xad, 0x98, 0x46, 0x92, 0x2e, + 0x4f, 0xca, 0xf1, 0x87, 0x43, 0xc1, 0x16, 0x95, 0x57, 0x2d, 0x50, 0xef, + 0x89, 0x2d, 0x80, 0x7a, 0x57, 0xad, 0xf2, 0xee, 0x5f, 0x6b, 0xd2, 0x00, + 0x8d, 0xb9, 0x14, 0xf8, 0x14, 0x15, 0x35, 0xd9, 0xc0, 0x46, 0xa3, 0x7b, + 0x72, 0xc8, 0x91, 0xbf, 0xc9, 0x55, 0x2b, 0xcd, 0xd0, 0x97, 0x3e, 0x9c, + 0x26, 0x64, 0xcc, 0xdf, 0xce, 0x83, 0x19, 0x71, 0xca, 0x4e, 0xe6, 0xd4, + 0xd5, 0x7b, 0xa9, 0x19, 0xcd, 0x55, 0xde, 0xc8, 0xec, 0xd2, 0x5e, 0x38, + 0x53, 0xe5, 0x5c, 0x4f, 0x8c, 0x2d, 0xfe, 0x50, 0x23, 0x36, 0xfc, 0x66, + 0xe6, 0xcb, 0x8e, 0xa4, 0x39, 0x19, 0x00, 0xb7, 0x95, 0x02, 0x39, 0x91, + 0x0b, 0x0e, 0xfe, 0x38, 0x2e, 0xd1, 0x1d, 0x05, 0x9a, 0xf6, 0x4d, 0x3e, + 0x6f, 0x0f, 0x07, 0x1d, 0xaf, 0x2c, 0x1e, 0x8f, 0x60, 0x39, 0xe2, 0xfa, + 0x36, 0x53, 0x13, 0x39, 0xd4, 0x5e, 0x26, 0x2b, 0xdb, 0x3d, 0xa8, 0x14, + 0xbd, 0x32, 0xeb, 0x18, 0x03, 0x28, 0x52, 0x04, 0x71, 0xe5, 0xab, 0x33, + 0x3d, 0xe1, 0x38, 0xbb, 0x07, 0x36, 0x84, 0x62, 0x9c, 0x79, 0xea, 0x16, + 0x30, 0xf4, 0x5f, 0xc0, 0x2b, 0xe8, 0x71, 0x6b, 0xe4, 0xf9, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x81, 0xf0, 0x30, 0x81, 0xed, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x48, 0xe6, + 0x68, 0xf9, 0x2b, 0xd2, 0xb2, 0x95, 0xd7, 0x47, 0xd8, 0x23, 0x20, 0x10, + 0x4f, 0x33, 0x98, 0x90, 0x9f, 0xd4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, + 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, + 0x4e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3a, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, + 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x65, + 0x63, 0x75, 0x72, 0x65, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4e, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x47, 0x30, 0x45, 0x30, 0x43, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, + 0x00, 0x76, 0xe1, 0x12, 0x6e, 0x4e, 0x4b, 0x16, 0x12, 0x86, 0x30, 0x06, + 0xb2, 0x81, 0x08, 0xcf, 0xf0, 0x08, 0xc7, 0xc7, 0x71, 0x7e, 0x66, 0xee, + 0xc2, 0xed, 0xd4, 0x3b, 0x1f, 0xff, 0xf0, 0xf0, 0xc8, 0x4e, 0xd6, 0x43, + 0x38, 0xb0, 0xb9, 0x30, 0x7d, 0x18, 0xd0, 0x55, 0x83, 0xa2, 0x6a, 0xcb, + 0x36, 0x11, 0x9c, 0xe8, 0x48, 0x66, 0xa3, 0x6d, 0x7f, 0xb8, 0x13, 0xd4, + 0x47, 0xfe, 0x8b, 0x5a, 0x5c, 0x73, 0xfc, 0xae, 0xd9, 0x1b, 0x32, 0x19, + 0x38, 0xab, 0x97, 0x34, 0x14, 0xaa, 0x96, 0xd2, 0xeb, 0xa3, 0x1c, 0x14, + 0x08, 0x49, 0xb6, 0xbb, 0xe5, 0x91, 0xef, 0x83, 0x36, 0xeb, 0x1d, 0x56, + 0x6f, 0xca, 0xda, 0xbc, 0x73, 0x63, 0x90, 0xe4, 0x7f, 0x7b, 0x3e, 0x22, + 0xcb, 0x3d, 0x07, 0xed, 0x5f, 0x38, 0x74, 0x9c, 0xe3, 0x03, 0x50, 0x4e, + 0xa1, 0xaf, 0x98, 0xee, 0x61, 0xf2, 0x84, 0x3f, 0x12, +} + +var certSet2Cert1 = []byte{ + 0x30, 0x82, 0x03, 0x8b, 0x30, 0x82, 0x02, 0xf4, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x0d, 0x6e, 0x62, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x45, + 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, + 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, + 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x31, 0x38, 0x30, 0x38, 0x32, 0x31, 0x31, 0x36, 0x31, 0x35, 0x30, 0x30, + 0x5a, 0x30, 0x58, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x28, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xbe, 0xb8, 0x15, 0x7b, 0xff, 0xd4, 0x7c, 0x7d, + 0x67, 0xad, 0x83, 0x64, 0x7b, 0xc8, 0x42, 0x53, 0x2d, 0xdf, 0xf6, 0x84, + 0x08, 0x20, 0x61, 0xd6, 0x01, 0x59, 0x6a, 0x9c, 0x44, 0x11, 0xaf, 0xef, + 0x76, 0xfd, 0x95, 0x7e, 0xce, 0x61, 0x30, 0xbb, 0x7a, 0x83, 0x5f, 0x02, + 0xbd, 0x01, 0x66, 0xca, 0xee, 0x15, 0x8d, 0x6f, 0xa1, 0x30, 0x9c, 0xbd, + 0xa1, 0x85, 0x9e, 0x94, 0x3a, 0xf3, 0x56, 0x88, 0x00, 0x31, 0xcf, 0xd8, + 0xee, 0x6a, 0x96, 0x02, 0xd9, 0xed, 0x03, 0x8c, 0xfb, 0x75, 0x6d, 0xe7, + 0xea, 0xb8, 0x55, 0x16, 0x05, 0x16, 0x9a, 0xf4, 0xe0, 0x5e, 0xb1, 0x88, + 0xc0, 0x64, 0x85, 0x5c, 0x15, 0x4d, 0x88, 0xc7, 0xb7, 0xba, 0xe0, 0x75, + 0xe9, 0xad, 0x05, 0x3d, 0x9d, 0xc7, 0x89, 0x48, 0xe0, 0xbb, 0x28, 0xc8, + 0x03, 0xe1, 0x30, 0x93, 0x64, 0x5e, 0x52, 0xc0, 0x59, 0x70, 0x22, 0x35, + 0x57, 0x88, 0x8a, 0xf1, 0x95, 0x0a, 0x83, 0xd7, 0xbc, 0x31, 0x73, 0x01, + 0x34, 0xed, 0xef, 0x46, 0x71, 0xe0, 0x6b, 0x02, 0xa8, 0x35, 0x72, 0x6b, + 0x97, 0x9b, 0x66, 0xe0, 0xcb, 0x1c, 0x79, 0x5f, 0xd8, 0x1a, 0x04, 0x68, + 0x1e, 0x47, 0x02, 0xe6, 0x9d, 0x60, 0xe2, 0x36, 0x97, 0x01, 0xdf, 0xce, + 0x35, 0x92, 0xdf, 0xbe, 0x67, 0xc7, 0x6d, 0x77, 0x59, 0x3b, 0x8f, 0x9d, + 0xd6, 0x90, 0x15, 0x94, 0xbc, 0x42, 0x34, 0x10, 0xc1, 0x39, 0xf9, 0xb1, + 0x27, 0x3e, 0x7e, 0xd6, 0x8a, 0x75, 0xc5, 0xb2, 0xaf, 0x96, 0xd3, 0xa2, + 0xde, 0x9b, 0xe4, 0x98, 0xbe, 0x7d, 0xe1, 0xe9, 0x81, 0xad, 0xb6, 0x6f, + 0xfc, 0xd7, 0x0e, 0xda, 0xe0, 0x34, 0xb0, 0x0d, 0x1a, 0x77, 0xe7, 0xe3, + 0x08, 0x98, 0xef, 0x58, 0xfa, 0x9c, 0x84, 0xb7, 0x36, 0xaf, 0xc2, 0xdf, + 0xac, 0xd2, 0xf4, 0x10, 0x06, 0x70, 0x71, 0x35, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x81, 0xe8, 0x30, 0x81, 0xe5, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2c, 0xd5, + 0x50, 0x41, 0x97, 0x15, 0x8b, 0xf0, 0x8f, 0x36, 0x61, 0x5b, 0x4a, 0xfb, + 0x6b, 0xd9, 0x99, 0xc9, 0x33, 0x92, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x48, 0xe6, 0x68, 0xf9, 0x2b, + 0xd2, 0xb2, 0x95, 0xd7, 0x47, 0xd8, 0x23, 0x20, 0x10, 0x4f, 0x33, 0x98, + 0x90, 0x9f, 0xd4, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x3a, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, + 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x46, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x04, 0x55, + 0x1d, 0x20, 0x00, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0xaf, 0xf3, 0x0e, 0xd6, 0x72, 0xab, 0xc7, 0xa9, 0x97, + 0xca, 0x2a, 0x6b, 0x84, 0x39, 0xde, 0x79, 0xa9, 0xf0, 0x81, 0xe5, 0x08, + 0x67, 0xab, 0xd7, 0x2f, 0x20, 0x02, 0x01, 0x71, 0x0c, 0x04, 0x22, 0xc9, + 0x1e, 0x88, 0x95, 0x03, 0xc9, 0x49, 0x3a, 0xaf, 0x67, 0x08, 0x49, 0xb0, + 0xd5, 0x08, 0xf5, 0x20, 0x3d, 0x80, 0x91, 0xa0, 0xc5, 0x87, 0xa3, 0xfb, + 0xc9, 0xa3, 0x17, 0x91, 0xf9, 0xa8, 0x2f, 0xae, 0xe9, 0x0f, 0xdf, 0x96, + 0x72, 0x0f, 0x75, 0x17, 0x80, 0x5d, 0x78, 0x01, 0x4d, 0x9f, 0x1f, 0x6d, + 0x7b, 0xd8, 0xf5, 0x42, 0x38, 0x23, 0x1a, 0x99, 0x93, 0xf4, 0x83, 0xbe, + 0x3b, 0x35, 0x74, 0xe7, 0x37, 0x13, 0x35, 0x7a, 0xac, 0xb4, 0xb6, 0x90, + 0x82, 0x6c, 0x27, 0xa4, 0xe0, 0xec, 0x9e, 0x35, 0xbd, 0xbf, 0xe5, 0x29, + 0xa1, 0x47, 0x9f, 0x5b, 0x32, 0xfc, 0xe9, 0x99, 0x7d, 0x2b, 0x39, +} + +var certSet2Cert2 = []byte{ + 0x30, 0x82, 0x03, 0xd5, 0x30, 0x82, 0x02, 0xbd, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x36, 0xd1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, + 0x32, 0x31, 0x39, 0x32, 0x32, 0x34, 0x35, 0x30, 0x35, 0x5a, 0x17, 0x0d, + 0x32, 0x30, 0x30, 0x32, 0x31, 0x38, 0x32, 0x32, 0x34, 0x35, 0x30, 0x35, + 0x5a, 0x30, 0x3c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0e, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0b, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, + 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xc7, 0x71, 0xf8, 0x56, 0xc7, 0x1e, 0xd9, 0xcc, 0xb5, 0xad, 0xf6, 0xb4, + 0x97, 0xa3, 0xfb, 0xa1, 0xe6, 0x0b, 0x50, 0x5f, 0x50, 0xaa, 0x3a, 0xda, + 0x0f, 0xfc, 0x3d, 0x29, 0x24, 0x43, 0xc6, 0x10, 0x29, 0xc1, 0xfc, 0x55, + 0x40, 0x72, 0xee, 0xbd, 0xea, 0xdf, 0x9f, 0xb6, 0x41, 0xf4, 0x48, 0x4b, + 0xc8, 0x6e, 0xfe, 0x4f, 0x57, 0x12, 0x8b, 0x5b, 0xfa, 0x92, 0xdd, 0x5e, + 0xe8, 0xad, 0xf3, 0xf0, 0x1b, 0xb1, 0x7b, 0x4d, 0xfb, 0xcf, 0xfd, 0xd1, + 0xe5, 0xf8, 0xe3, 0xdc, 0xe7, 0xf5, 0x73, 0x7f, 0xdf, 0x01, 0x49, 0xcf, + 0x8c, 0x56, 0xc1, 0xbd, 0x37, 0xe3, 0x5b, 0xbe, 0xb5, 0x4f, 0x8b, 0x8b, + 0xf0, 0xda, 0x4f, 0xc7, 0xe3, 0xdd, 0x55, 0x47, 0x69, 0xdf, 0xf2, 0x5b, + 0x7b, 0x07, 0x4f, 0x3d, 0xe5, 0xac, 0x21, 0xc1, 0xc8, 0x1d, 0x7a, 0xe8, + 0xe7, 0xf6, 0x0f, 0xa1, 0xaa, 0xf5, 0x6f, 0xde, 0xa8, 0x65, 0x4f, 0x10, + 0x89, 0x9c, 0x03, 0xf3, 0x89, 0x7a, 0xa5, 0x5e, 0x01, 0x72, 0x33, 0xed, + 0xa9, 0xe9, 0x5a, 0x1e, 0x79, 0xf3, 0x87, 0xc8, 0xdf, 0xc8, 0xc5, 0xfc, + 0x37, 0xc8, 0x9a, 0x9a, 0xd7, 0xb8, 0x76, 0xcc, 0xb0, 0x3e, 0xe7, 0xfd, + 0xe6, 0x54, 0xea, 0xdf, 0x5f, 0x52, 0x41, 0x78, 0x59, 0x57, 0xad, 0xf1, + 0x12, 0xd6, 0x7f, 0xbc, 0xd5, 0x9f, 0x70, 0xd3, 0x05, 0x6c, 0xfa, 0xa3, + 0x7d, 0x67, 0x58, 0xdd, 0x26, 0x62, 0x1d, 0x31, 0x92, 0x0c, 0x79, 0x79, + 0x1c, 0x8e, 0xcf, 0xca, 0x7b, 0xc1, 0x66, 0xaf, 0xa8, 0x74, 0x48, 0xfb, + 0x8e, 0x82, 0xc2, 0x9e, 0x2c, 0x99, 0x5c, 0x7b, 0x2d, 0x5d, 0x9b, 0xbc, + 0x5b, 0x57, 0x9e, 0x7c, 0x3a, 0x7a, 0x13, 0xad, 0xf2, 0xa3, 0x18, 0x5b, + 0x2b, 0x59, 0x0f, 0xcd, 0x5c, 0x3a, 0xeb, 0x68, 0x33, 0xc6, 0x28, 0x1d, + 0x82, 0xd1, 0x50, 0x8b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xd9, + 0x30, 0x81, 0xd6, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6b, 0x69, 0x3d, 0x6a, 0x18, 0x42, + 0x4a, 0xdd, 0x8f, 0x02, 0x65, 0x39, 0xfd, 0x35, 0x24, 0x86, 0x78, 0x91, + 0x16, 0x30, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, + 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, + 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x3a, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, + 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x34, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, + 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, + 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, + 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xab, 0xbc, 0xbc, + 0x0a, 0x5d, 0x18, 0x94, 0xe3, 0xc1, 0xb1, 0xc3, 0xa8, 0x4c, 0x55, 0xd6, + 0xbe, 0xb4, 0x98, 0xf1, 0xee, 0x3c, 0x1c, 0xcd, 0xcf, 0xf3, 0x24, 0x24, + 0x5c, 0x96, 0x03, 0x27, 0x58, 0xfc, 0x36, 0xae, 0xa2, 0x2f, 0x8f, 0xf1, + 0xfe, 0xda, 0x2b, 0x02, 0xc3, 0x33, 0xbd, 0xc8, 0xdd, 0x48, 0x22, 0x2b, + 0x60, 0x0f, 0xa5, 0x03, 0x10, 0xfd, 0x77, 0xf8, 0xd0, 0xed, 0x96, 0x67, + 0x4f, 0xfd, 0xea, 0x47, 0x20, 0x70, 0x54, 0xdc, 0xa9, 0x0c, 0x55, 0x7e, + 0xe1, 0x96, 0x25, 0x8a, 0xd9, 0xb5, 0xda, 0x57, 0x4a, 0xbe, 0x8d, 0x8e, + 0x49, 0x43, 0x63, 0xa5, 0x6c, 0x4e, 0x27, 0x87, 0x25, 0xeb, 0x5b, 0x6d, + 0xfe, 0xa2, 0x7f, 0x38, 0x28, 0xe0, 0x36, 0xab, 0xad, 0x39, 0xa5, 0xa5, + 0x62, 0xc4, 0xb7, 0x5c, 0x58, 0x2c, 0xaa, 0x5d, 0x01, 0x60, 0xa6, 0x62, + 0x67, 0xa3, 0xc0, 0xc7, 0x62, 0x23, 0xf4, 0xe7, 0x6c, 0x46, 0xee, 0xb5, + 0xd3, 0x80, 0x6a, 0x22, 0x13, 0xd2, 0x2d, 0x3f, 0x74, 0x4f, 0xea, 0xaf, + 0x8c, 0x5f, 0xb4, 0x38, 0x9c, 0xdb, 0xae, 0xce, 0xaf, 0x84, 0x1e, 0xa6, + 0xf6, 0x34, 0x51, 0x59, 0x79, 0xd3, 0xe3, 0x75, 0xdc, 0xbc, 0xd7, 0xf3, + 0x73, 0xdf, 0x92, 0xec, 0xd2, 0x20, 0x59, 0x6f, 0x9c, 0xfb, 0x95, 0xf8, + 0x92, 0x76, 0x18, 0x0a, 0x7c, 0x0f, 0x2c, 0xa6, 0xca, 0xde, 0x8a, 0x62, + 0x7b, 0xd8, 0xf3, 0xce, 0x5f, 0x68, 0xbd, 0x8f, 0x3e, 0xc1, 0x74, 0xbb, + 0x15, 0x72, 0x3a, 0x16, 0x83, 0xa9, 0x0b, 0xe6, 0x4d, 0x99, 0x9c, 0xd8, + 0x57, 0xec, 0xa8, 0x01, 0x51, 0xc7, 0x6f, 0x57, 0x34, 0x5e, 0xab, 0x4a, + 0x2c, 0x42, 0xf6, 0x4f, 0x1c, 0x89, 0x78, 0xde, 0x26, 0x4e, 0xf5, 0x6f, + 0x93, 0x4c, 0x15, 0x6b, 0x27, 0x56, 0x4d, 0x00, 0x54, 0x6c, 0x7a, 0xb7, + 0xb7, +} + +var certSet2Cert3 = []byte{ + 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x83, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, + 0x34, 0x30, 0x35, 0x31, 0x35, 0x31, 0x35, 0x35, 0x36, 0x5a, 0x17, 0x0d, + 0x31, 0x36, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, + 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3, + 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a, + 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a, + 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f, + 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1, + 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4, + 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53, + 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f, + 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73, + 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b, + 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb, + 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4, + 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19, + 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65, + 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80, + 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99, + 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75, + 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e, + 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf, + 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2, + 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37, + 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, + 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, + 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, + 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, + 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, + 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, + 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, + 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, + 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10, + 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, + 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0xaa, 0xfa, 0xa9, 0x20, 0xcd, 0x6a, 0x67, 0x83, 0xed, 0x5e, 0xd4, 0x7e, + 0xde, 0x1d, 0xc4, 0x7f, 0xe0, 0x25, 0x06, 0x00, 0xc5, 0x24, 0xfb, 0xa9, + 0xc8, 0x2d, 0x6d, 0x7e, 0xde, 0x9d, 0x82, 0x65, 0x2c, 0x81, 0x63, 0x34, + 0x66, 0x3e, 0xe9, 0x52, 0xc2, 0x08, 0xb4, 0xcb, 0x2f, 0xf7, 0x5f, 0x99, + 0x3a, 0x6a, 0x9c, 0x50, 0x7a, 0x85, 0x05, 0x8c, 0x7d, 0xd1, 0x2a, 0x48, + 0x84, 0xd3, 0x09, 0x6c, 0x7c, 0xc2, 0xcd, 0x35, 0x9f, 0xf3, 0x82, 0xee, + 0x52, 0xde, 0x68, 0x5f, 0xe4, 0x00, 0x8a, 0x17, 0x20, 0x96, 0xf7, 0x29, + 0x8d, 0x9a, 0x4d, 0xcb, 0xa8, 0xde, 0x86, 0xc8, 0x0d, 0x6f, 0x56, 0x87, + 0x03, 0x7d, 0x03, 0x3f, 0xdc, 0xfa, 0x79, 0x7d, 0x21, 0x19, 0xf9, 0xc8, + 0x3a, 0x2f, 0x51, 0x76, 0x8c, 0xc7, 0x41, 0x92, 0x71, 0x8f, 0x25, 0xce, + 0x37, 0xf8, 0x4a, 0x4c, 0x00, 0x23, 0xef, 0xc4, 0x35, 0x10, 0xae, 0xe0, + 0x23, 0x80, 0x73, 0x7c, 0x4d, 0x34, 0x2e, 0xc8, 0x6e, 0x90, 0xd6, 0x10, + 0x1e, 0x99, 0x84, 0x73, 0x1a, 0x70, 0xf2, 0xed, 0x55, 0x0e, 0xee, 0x17, + 0x06, 0xea, 0x67, 0xee, 0x32, 0xeb, 0x2c, 0xdd, 0x67, 0x07, 0x3f, 0xf6, + 0x8b, 0xc2, 0x70, 0xde, 0x5b, 0x00, 0xe6, 0xbb, 0x1b, 0xd3, 0x36, 0x1a, + 0x22, 0x6c, 0x6c, 0xb0, 0x35, 0x42, 0x6c, 0x90, 0x09, 0x3d, 0x93, 0xe9, + 0x64, 0x09, 0x22, 0x0e, 0x85, 0x06, 0x9f, 0xc2, 0x73, 0x21, 0xd3, 0xe6, + 0x5f, 0x80, 0xe4, 0x8d, 0x85, 0x22, 0x3a, 0x73, 0x03, 0xb1, 0x60, 0x8e, + 0xae, 0x68, 0xe2, 0xf4, 0x3e, 0x97, 0xe7, 0x60, 0x12, 0x09, 0x68, 0x36, + 0xde, 0x3a, 0xd6, 0xe2, 0x43, 0x95, 0x5b, 0x37, 0x81, 0x92, 0x81, 0x1f, + 0xbb, 0x8d, 0xd7, 0xad, 0x52, 0x64, 0x16, 0x57, 0x96, 0xd9, 0x5e, 0x34, + 0x7e, 0xc8, 0x35, 0xd8, +} + +var certSet2Cert4 = []byte{ + 0x30, 0x82, 0x04, 0x15, 0x30, 0x82, 0x03, 0x7e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0x8e, 0xed, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, + 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x1e, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x23, 0x30, 0x21, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x47, 0x54, 0x45, 0x20, 0x43, + 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x32, 0x30, 0x34, 0x31, 0x38, 0x31, 0x36, 0x33, 0x36, 0x31, + 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x38, 0x31, 0x33, 0x31, 0x36, + 0x33, 0x35, 0x31, 0x37, 0x5a, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x45, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x42, 0x61, 0x6c, 0x74, 0x69, + 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, + 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, + 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x04, + 0xbb, 0x22, 0xab, 0x98, 0x3d, 0x57, 0xe8, 0x26, 0x72, 0x9a, 0xb5, 0x79, + 0xd4, 0x29, 0xe2, 0xe1, 0xe8, 0x95, 0x80, 0xb1, 0xb0, 0xe3, 0x5b, 0x8e, + 0x2b, 0x29, 0x9a, 0x64, 0xdf, 0xa1, 0x5d, 0xed, 0xb0, 0x09, 0x05, 0x6d, + 0xdb, 0x28, 0x2e, 0xce, 0x62, 0xa2, 0x62, 0xfe, 0xb4, 0x88, 0xda, 0x12, + 0xeb, 0x38, 0xeb, 0x21, 0x9d, 0xc0, 0x41, 0x2b, 0x01, 0x52, 0x7b, 0x88, + 0x77, 0xd3, 0x1c, 0x8f, 0xc7, 0xba, 0xb9, 0x88, 0xb5, 0x6a, 0x09, 0xe7, + 0x73, 0xe8, 0x11, 0x40, 0xa7, 0xd1, 0xcc, 0xca, 0x62, 0x8d, 0x2d, 0xe5, + 0x8f, 0x0b, 0xa6, 0x50, 0xd2, 0xa8, 0x50, 0xc3, 0x28, 0xea, 0xf5, 0xab, + 0x25, 0x87, 0x8a, 0x9a, 0x96, 0x1c, 0xa9, 0x67, 0xb8, 0x3f, 0x0c, 0xd5, + 0xf7, 0xf9, 0x52, 0x13, 0x2f, 0xc2, 0x1b, 0xd5, 0x70, 0x70, 0xf0, 0x8f, + 0xc0, 0x12, 0xca, 0x06, 0xcb, 0x9a, 0xe1, 0xd9, 0xca, 0x33, 0x7a, 0x77, + 0xd6, 0xf8, 0xec, 0xb9, 0xf1, 0x68, 0x44, 0x42, 0x48, 0x13, 0xd2, 0xc0, + 0xc2, 0xa4, 0xae, 0x5e, 0x60, 0xfe, 0xb6, 0xa6, 0x05, 0xfc, 0xb4, 0xdd, + 0x07, 0x59, 0x02, 0xd4, 0x59, 0x18, 0x98, 0x63, 0xf5, 0xa5, 0x63, 0xe0, + 0x90, 0x0c, 0x7d, 0x5d, 0xb2, 0x06, 0x7a, 0xf3, 0x85, 0xea, 0xeb, 0xd4, + 0x03, 0xae, 0x5e, 0x84, 0x3e, 0x5f, 0xff, 0x15, 0xed, 0x69, 0xbc, 0xf9, + 0x39, 0x36, 0x72, 0x75, 0xcf, 0x77, 0x52, 0x4d, 0xf3, 0xc9, 0x90, 0x2c, + 0xb9, 0x3d, 0xe5, 0xc9, 0x23, 0x53, 0x3f, 0x1f, 0x24, 0x98, 0x21, 0x5c, + 0x07, 0x99, 0x29, 0xbd, 0xc6, 0x3a, 0xec, 0xe7, 0x6e, 0x86, 0x3a, 0x6b, + 0x97, 0x74, 0x63, 0x33, 0xbd, 0x68, 0x18, 0x31, 0xf0, 0x78, 0x8d, 0x76, + 0xbf, 0xfc, 0x9e, 0x8e, 0x5d, 0x2a, 0x86, 0xa7, 0x4d, 0x90, 0xdc, 0x27, + 0x1a, 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x47, 0x30, + 0x82, 0x01, 0x43, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x03, 0x30, + 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x43, 0x30, 0x41, 0x30, 0x3f, + 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x37, 0x30, 0x35, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x29, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x81, 0x89, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x81, 0x81, 0x30, 0x7f, 0xa1, 0x79, 0xa4, 0x77, + 0x30, 0x75, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0f, 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x1e, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x23, + 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x47, 0x54, 0x45, + 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x82, + 0x02, 0x01, 0xa5, 0x30, 0x45, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x3e, + 0x30, 0x3c, 0x30, 0x3a, 0xa0, 0x38, 0xa0, 0x36, 0x86, 0x34, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x67, 0x69, 0x2d, 0x62, 0x69, 0x6e, 0x2f, 0x43, 0x52, + 0x4c, 0x2f, 0x32, 0x30, 0x31, 0x38, 0x2f, 0x63, 0x64, 0x70, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x93, 0x1d, 0xfe, + 0x8b, 0xae, 0x46, 0xec, 0xcb, 0xa9, 0x0f, 0xab, 0xe5, 0xef, 0xca, 0xb2, + 0x68, 0x16, 0x68, 0xd8, 0x8f, 0xfa, 0x13, 0xa9, 0xaf, 0xb3, 0xcb, 0x2d, + 0xe7, 0x4b, 0x6e, 0x8e, 0x69, 0x2a, 0xc2, 0x2b, 0x10, 0x0a, 0x8d, 0xf6, + 0xae, 0x73, 0xb6, 0xb9, 0xfb, 0x14, 0xfd, 0x5f, 0x6d, 0xb8, 0x50, 0xb6, + 0xc4, 0x8a, 0xd6, 0x40, 0x7e, 0xd7, 0xc3, 0xcb, 0x73, 0xdc, 0xc9, 0x5d, + 0x5b, 0xaf, 0xb0, 0x41, 0xb5, 0x37, 0xeb, 0xea, 0xdc, 0x20, 0x91, 0xc4, + 0x34, 0x6a, 0xf4, 0xa1, 0xf3, 0x96, 0x9d, 0x37, 0x86, 0x97, 0xe1, 0x71, + 0xa4, 0xdd, 0x7d, 0xfa, 0x44, 0x84, 0x94, 0xae, 0xd7, 0x09, 0x04, 0x22, + 0x76, 0x0f, 0x64, 0x51, 0x35, 0xa9, 0x24, 0x0f, 0xf9, 0x0b, 0xdb, 0x32, + 0xda, 0xc2, 0xfe, 0xc1, 0xb9, 0x2a, 0x5c, 0x7a, 0x27, 0x13, 0xca, 0xb1, + 0x48, 0x3a, 0x71, 0xd0, 0x43, +} + +var certSet2Cert5 = []byte{ + 0x30, 0x82, 0x04, 0x22, 0x30, 0x82, 0x03, 0x0a, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x79, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, + 0x39, 0x30, 0x38, 0x32, 0x30, 0x34, 0x31, 0x31, 0x30, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x30, 0x34, 0x31, 0x31, 0x30, + 0x5a, 0x30, 0x44, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x14, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9a, 0x7d, 0x98, 0x68, + 0x11, 0x40, 0xc1, 0x5f, 0x72, 0xec, 0x55, 0xb3, 0xb1, 0x63, 0xf3, 0x32, + 0x22, 0x72, 0x91, 0xc6, 0x16, 0x05, 0xbb, 0x08, 0x82, 0x31, 0xb4, 0xf6, + 0xee, 0xd4, 0x18, 0x39, 0x11, 0x2f, 0x2e, 0xda, 0x47, 0xfe, 0x51, 0x31, + 0x6e, 0x5b, 0xf2, 0xa9, 0x0a, 0xeb, 0x2f, 0xbb, 0xf5, 0x61, 0x59, 0x65, + 0x57, 0x02, 0xcd, 0x80, 0xff, 0xc7, 0x70, 0x32, 0x54, 0x89, 0xfd, 0xdb, + 0xae, 0x99, 0x72, 0xd4, 0x4f, 0x0c, 0x26, 0xb9, 0x2e, 0x63, 0x30, 0x7d, + 0xde, 0x14, 0x5b, 0x6a, 0xd7, 0x52, 0x78, 0x21, 0xf9, 0xbf, 0xbc, 0x50, + 0xd5, 0x54, 0x12, 0x59, 0xd8, 0xb5, 0x36, 0xd9, 0x21, 0x47, 0xb8, 0x3f, + 0x6a, 0x58, 0x1d, 0x8c, 0x72, 0xe1, 0x97, 0x95, 0xd3, 0xe1, 0x45, 0xa8, + 0xf1, 0x5a, 0xe5, 0xbe, 0xfe, 0xe3, 0x53, 0x7c, 0xa5, 0xf0, 0x52, 0xe0, + 0xcf, 0x39, 0x94, 0x0c, 0x19, 0x71, 0xf2, 0xc0, 0x25, 0x07, 0x48, 0x7d, + 0x1c, 0xe6, 0xf1, 0x39, 0x25, 0x2f, 0x98, 0x79, 0x43, 0xe8, 0x18, 0x72, + 0xf4, 0x65, 0x86, 0x98, 0x5a, 0x00, 0x04, 0x47, 0xda, 0x4b, 0x58, 0x1e, + 0x7c, 0x86, 0xb1, 0x4b, 0x35, 0xa6, 0x20, 0x00, 0x1c, 0xcd, 0x1b, 0x3b, + 0x22, 0x5d, 0xd1, 0x93, 0x28, 0x33, 0x12, 0x23, 0x94, 0x08, 0xaa, 0xc3, + 0x3a, 0xf5, 0xd1, 0xc6, 0x8c, 0x7e, 0x99, 0xd3, 0x18, 0xa0, 0xad, 0x9d, + 0x18, 0xcf, 0x49, 0xad, 0x10, 0x03, 0xf7, 0x99, 0x33, 0x26, 0x86, 0x46, + 0x9a, 0x2f, 0xa0, 0xba, 0x6c, 0x6e, 0xc8, 0x88, 0x02, 0xb7, 0x6e, 0xfa, + 0x7a, 0x9e, 0x98, 0x4a, 0xee, 0x9a, 0x31, 0x7d, 0x19, 0x14, 0x60, 0x0c, + 0xec, 0x8f, 0x20, 0x23, 0x3c, 0xda, 0x97, 0x26, 0xb6, 0xea, 0x80, 0x6c, + 0x8a, 0x57, 0x9e, 0x20, 0xee, 0x6f, 0x17, 0x25, 0x4a, 0x32, 0xad, 0x35, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, + 0x19, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, + 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xac, 0x32, 0xed, + 0x5a, 0xc9, 0xe0, 0xde, 0x30, 0x9c, 0x90, 0x58, 0x55, 0x26, 0x63, 0xf6, + 0x72, 0xa6, 0x54, 0x5f, 0xe3, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, + 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, + 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, + 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, + 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x61, 0x40, 0xad, 0x21, 0x0f, 0x03, 0xbb, 0x95, 0xdc, 0x89, + 0xfc, 0xa3, 0xcb, 0x05, 0x71, 0xe9, 0x1c, 0x59, 0x97, 0x35, 0xc2, 0xfa, + 0x6b, 0x05, 0xa4, 0x16, 0xc6, 0x56, 0x46, 0x37, 0x74, 0x1b, 0x1b, 0xf1, + 0x3e, 0x2c, 0xe8, 0x37, 0x19, 0xb7, 0x94, 0xd2, 0x0f, 0x0e, 0xc5, 0xbf, + 0x14, 0x07, 0x2b, 0x34, 0xcd, 0x5b, 0xb4, 0x8d, 0xc7, 0x56, 0x9d, 0x19, + 0xfc, 0x02, 0xb4, 0x9e, 0x90, 0x31, 0xfa, 0xa4, 0x44, 0xc6, 0x75, 0xdd, + 0xdd, 0x1f, 0x25, 0x54, 0xa3, 0x30, 0x4c, 0xac, 0xdb, 0xfe, 0xc4, 0x88, + 0xf7, 0x31, 0x26, 0x18, 0x47, 0xae, 0x4c, 0x20, 0x19, 0x1a, 0xc7, 0xae, + 0x3e, 0x98, 0x0a, 0x16, 0x3d, 0xd2, 0xc2, 0xa6, 0x5d, 0x0d, 0x2e, 0x29, + 0x7d, 0xb2, 0x9d, 0xc7, 0x41, 0x32, 0x17, 0xca, 0x9d, 0xae, 0x39, 0xbf, + 0x91, 0x98, 0xde, 0xe7, 0x44, 0xe2, 0x95, 0x9c, 0x94, 0x5c, 0x6c, 0x42, + 0x1b, 0x59, 0xc9, 0x7b, 0x68, 0x13, 0xa8, 0x96, 0x09, 0x74, 0xee, 0x40, + 0x14, 0xa4, 0xd5, 0xd7, 0xc9, 0x7b, 0x33, 0xa3, 0x0f, 0x5a, 0x69, 0x9c, + 0x1a, 0xfa, 0x6f, 0x12, 0x47, 0x1c, 0xdf, 0x1e, 0x4c, 0x70, 0x4e, 0x6d, + 0xdd, 0xfe, 0x1c, 0x87, 0xb5, 0x9d, 0xe1, 0x54, 0x07, 0x09, 0x8a, 0xcd, + 0xbe, 0xaa, 0xa8, 0x46, 0x78, 0x6e, 0x16, 0xf2, 0xe7, 0x91, 0x0e, 0xc3, + 0xaf, 0xda, 0x76, 0x00, 0xd1, 0xd8, 0xa2, 0x46, 0x24, 0x03, 0xa5, 0x1a, + 0x85, 0x81, 0x56, 0x83, 0x63, 0x27, 0xba, 0x90, 0x8e, 0xf9, 0x62, 0x11, + 0xba, 0xa7, 0x7c, 0x90, 0xa9, 0x1a, 0x66, 0xb4, 0xc5, 0xbc, 0x8f, 0x29, + 0x41, 0xab, 0xeb, 0x8d, 0x99, 0xa6, 0xcc, 0x91, 0x64, 0xba, 0xdc, 0xc6, + 0xa6, 0x4c, 0xb3, 0xb4, 0x23, 0x26, 0x51, 0x72, 0x56, 0xf9, 0xf3, 0x74, + 0x55, 0x9f, 0x25, 0x75, 0x4f, 0x2b, +} + +var certSet2Cert6 = []byte{ + 0x30, 0x82, 0x04, 0x25, 0x30, 0x82, 0x03, 0x0d, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x77, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, + 0x38, 0x32, 0x39, 0x32, 0x31, 0x33, 0x39, 0x33, 0x32, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x31, 0x33, 0x39, 0x33, 0x32, + 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, + 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, + 0x54, 0x9b, 0xd9, 0x58, 0x5d, 0x1e, 0x2c, 0x56, 0xc6, 0xd5, 0xe8, 0x7f, + 0xf4, 0x7d, 0x16, 0x03, 0xff, 0xd0, 0x8b, 0x5a, 0xe4, 0x8e, 0xa7, 0xdd, + 0x54, 0x2e, 0xd4, 0x04, 0xc0, 0x5d, 0x98, 0x9c, 0x8d, 0x90, 0x0f, 0xbc, + 0x10, 0x65, 0x5f, 0xda, 0x9a, 0xd6, 0x44, 0x7c, 0xc0, 0x9f, 0xb5, 0xe9, + 0x4a, 0x8c, 0x0b, 0x06, 0x43, 0x04, 0xbb, 0xf4, 0x96, 0xe2, 0x26, 0xf6, + 0x61, 0x01, 0x91, 0x66, 0x31, 0x22, 0xc3, 0x34, 0x34, 0x5f, 0x3f, 0x3f, + 0x91, 0x2f, 0x44, 0x5f, 0xdc, 0xc7, 0x14, 0xb6, 0x03, 0x9f, 0x86, 0x4b, + 0x0e, 0xa3, 0xff, 0xa0, 0x80, 0x02, 0x83, 0xc3, 0xd3, 0x1f, 0x69, 0x52, + 0xd6, 0x9d, 0x64, 0x0f, 0xc9, 0x83, 0xe7, 0x1b, 0xc4, 0x70, 0xac, 0x94, + 0xe7, 0xc3, 0xa4, 0x6a, 0x2c, 0xbd, 0xb8, 0x9e, 0x69, 0xd8, 0xbe, 0x0a, + 0x8f, 0x16, 0x63, 0x5a, 0x68, 0x71, 0x80, 0x7b, 0x30, 0xde, 0x15, 0x04, + 0xbf, 0xcc, 0xd3, 0xbf, 0x3e, 0x48, 0x05, 0x55, 0x7a, 0xb3, 0xd7, 0x10, + 0x0c, 0x03, 0xfc, 0x9b, 0xfd, 0x08, 0xa7, 0x8c, 0x8c, 0xdb, 0xa7, 0x8e, + 0xf1, 0x1e, 0x63, 0xdc, 0xb3, 0x01, 0x2f, 0x7f, 0xaf, 0x57, 0xc3, 0x3c, + 0x48, 0xa7, 0x83, 0x68, 0x21, 0xa7, 0x2f, 0xe7, 0xa7, 0x3f, 0xf0, 0xb5, + 0x0c, 0xfc, 0xf5, 0x84, 0xd1, 0x53, 0xbc, 0x0e, 0x72, 0x4f, 0x60, 0x0c, + 0x42, 0xb8, 0x98, 0xad, 0x19, 0x88, 0x57, 0xd7, 0x04, 0xec, 0x87, 0xbf, + 0x7e, 0x87, 0x4e, 0xa3, 0x21, 0xf9, 0x53, 0xfd, 0x36, 0x98, 0x48, 0x8d, + 0xd6, 0xf8, 0xbb, 0x48, 0xf2, 0x29, 0xc8, 0x64, 0xd1, 0xcc, 0x54, 0x48, + 0x53, 0x8b, 0xaf, 0xb7, 0x65, 0x1e, 0xbf, 0x29, 0x33, 0x29, 0xd9, 0x29, + 0x60, 0x48, 0xf8, 0xff, 0x91, 0xbc, 0x57, 0x58, 0xe5, 0x35, 0x2e, 0xbb, + 0x69, 0xb6, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1d, + 0x30, 0x82, 0x01, 0x19, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, + 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xc3, 0x9c, 0xf3, 0xfc, 0xd3, 0x46, 0x08, 0x34, 0xbb, 0xce, 0x46, 0x7f, + 0xa0, 0x7c, 0x5b, 0xf3, 0xe2, 0x08, 0xcb, 0x59, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x35, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, + 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, + 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, + 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, + 0x30, 0x43, 0x30, 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, + 0x45, 0x01, 0x07, 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x58, 0x1e, 0xc6, 0x43, 0x32, 0xac, + 0xac, 0x2f, 0x93, 0x78, 0xb7, 0xea, 0xae, 0x54, 0x40, 0x47, 0x2d, 0x7e, + 0x78, 0x8d, 0x50, 0xf6, 0xf8, 0x66, 0xac, 0xd6, 0x4f, 0x73, 0xd6, 0x44, + 0xef, 0xaf, 0x0b, 0xcc, 0x5b, 0xc1, 0xf4, 0x4f, 0x9a, 0x8f, 0x49, 0x7e, + 0x60, 0xaf, 0xc2, 0x27, 0xc7, 0x16, 0xf1, 0xfb, 0x93, 0x81, 0x90, 0xa9, + 0x7c, 0xef, 0x6f, 0x7e, 0x6e, 0x45, 0x94, 0x16, 0x84, 0xbd, 0xec, 0x49, + 0xf1, 0xc4, 0x0e, 0xf4, 0xaf, 0x04, 0x59, 0x83, 0x87, 0x0f, 0x2c, 0x3b, + 0x97, 0xc3, 0x5a, 0x12, 0x9b, 0x7b, 0x04, 0x35, 0x7b, 0xa3, 0x95, 0x33, + 0x08, 0x7b, 0x93, 0x71, 0x22, 0x42, 0xb3, 0xa9, 0xd9, 0x6f, 0x4f, 0x81, + 0x92, 0xfc, 0x07, 0xb6, 0x79, 0xbc, 0x84, 0x4a, 0x9d, 0x77, 0x09, 0xf1, + 0xc5, 0x89, 0xf2, 0xf0, 0xb4, 0x9c, 0x54, 0xaa, 0x12, 0x7b, 0x0d, 0xba, + 0x4f, 0xef, 0x93, 0x19, 0xec, 0xef, 0x7d, 0x4e, 0x61, 0xa3, 0x8e, 0x76, + 0x9c, 0x59, 0xcf, 0x8c, 0x94, 0xb1, 0x84, 0x97, 0xf7, 0x1a, 0xb9, 0x07, + 0xb8, 0xb2, 0xc6, 0x4f, 0x13, 0x79, 0xdb, 0xbf, 0x4f, 0x51, 0x1b, 0x7f, + 0x69, 0x0d, 0x51, 0x2a, 0xc1, 0xd6, 0x15, 0xff, 0x37, 0x51, 0x34, 0x65, + 0x51, 0xf4, 0x1e, 0xbe, 0x38, 0x6a, 0xec, 0x0e, 0xab, 0xbf, 0x3d, 0x7b, + 0x39, 0x05, 0x7b, 0xf4, 0xf3, 0xfb, 0x1a, 0xa1, 0xd0, 0xc8, 0x7e, 0x4e, + 0x64, 0x8d, 0xcd, 0x8c, 0x61, 0x55, 0x90, 0xfe, 0x3a, 0xca, 0x5d, 0x25, + 0x0f, 0xf8, 0x1d, 0xa3, 0x4a, 0x74, 0x56, 0x4f, 0x1a, 0x55, 0x40, 0x70, + 0x75, 0x25, 0xa6, 0x33, 0x2e, 0xba, 0x4b, 0xa5, 0x5d, 0x53, 0x9a, 0x0d, + 0x30, 0xe1, 0x8d, 0x5f, 0x61, 0x2c, 0xaf, 0xcc, 0xef, 0xb0, 0x99, 0xa1, + 0x80, 0xff, 0x0b, 0xf2, 0x62, 0x4c, 0x70, 0x26, 0x98, +} + +var certSet2Cert7 = []byte{ + 0x30, 0x82, 0x04, 0x2b, 0x30, 0x82, 0x03, 0x13, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x12, 0x11, 0x20, 0x96, 0xf6, 0xc8, 0x03, 0x7c, 0x9e, 0x07, + 0xb1, 0x38, 0xbf, 0x2e, 0x72, 0x10, 0x8a, 0xd7, 0xed, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x30, 0x3d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x46, 0x52, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x08, 0x43, 0x65, 0x72, 0x74, 0x70, 0x6c, 0x75, 0x73, 0x31, 0x1b, + 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x20, 0x32, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x30, + 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x39, + 0x30, 0x36, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, + 0x40, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x46, 0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x09, 0x4b, 0x45, 0x59, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x53, 0x31, 0x1d, + 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x43, 0x4c, 0x41, + 0x53, 0x53, 0x20, 0x32, 0x20, 0x4b, 0x45, 0x59, 0x4e, 0x45, 0x43, 0x54, + 0x49, 0x53, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xc6, 0xbe, 0xfe, 0x44, 0x23, 0x04, 0xd4, 0xef, 0x2f, 0x3b, + 0x86, 0xaa, 0x35, 0x58, 0x81, 0xd1, 0xe1, 0x9a, 0xd6, 0xb1, 0xd4, 0x27, + 0x45, 0x28, 0xfc, 0xd1, 0x1e, 0x46, 0x85, 0xba, 0x54, 0x23, 0x11, 0x7d, + 0xe0, 0x66, 0x3f, 0xd4, 0xa3, 0x57, 0x66, 0x78, 0xf9, 0x6b, 0xeb, 0x74, + 0x7c, 0x2a, 0xb8, 0x37, 0xa5, 0xe8, 0x70, 0xae, 0x82, 0xb5, 0x4e, 0xd4, + 0x81, 0xfe, 0x5b, 0xe2, 0xea, 0xe7, 0x22, 0x16, 0xf8, 0xf9, 0xd7, 0xba, + 0x3a, 0xf6, 0x88, 0x56, 0xdc, 0xc4, 0xf2, 0xa0, 0xa4, 0xe5, 0x75, 0x06, + 0x60, 0x72, 0x2b, 0xfb, 0xf5, 0x94, 0xee, 0x2c, 0x83, 0x28, 0xde, 0x91, + 0x9a, 0xb3, 0x83, 0x3a, 0xb0, 0x9f, 0x08, 0xfa, 0xdd, 0xd8, 0x9e, 0x8c, + 0x24, 0xe6, 0xdf, 0x66, 0x5b, 0xc8, 0x7e, 0xa3, 0x62, 0x4d, 0x3f, 0x3a, + 0x85, 0x23, 0xec, 0xe8, 0x71, 0x8f, 0x0a, 0x00, 0xac, 0x89, 0x6d, 0x7e, + 0xd8, 0x72, 0xe5, 0xdd, 0xc1, 0x94, 0x8e, 0x5f, 0xe4, 0x73, 0xe6, 0xc1, + 0xc6, 0x0c, 0x87, 0x58, 0x4f, 0x37, 0xda, 0xd1, 0xa9, 0x88, 0x26, 0x76, + 0xb4, 0xee, 0x11, 0x8d, 0xf6, 0xad, 0xb2, 0xa7, 0xbc, 0x73, 0xc4, 0xcd, + 0x1c, 0x6e, 0x1a, 0xe6, 0x8d, 0x72, 0x56, 0x44, 0xa0, 0x98, 0xf7, 0x92, + 0xf9, 0xd7, 0x79, 0x9b, 0x03, 0xe6, 0x68, 0x5f, 0xa4, 0x5c, 0x7c, 0x3d, + 0x50, 0xb4, 0x83, 0xcc, 0xe5, 0xac, 0x0d, 0xe1, 0x3e, 0x4f, 0x14, 0xf2, + 0xb4, 0xe4, 0x7d, 0xbf, 0x71, 0xa4, 0xc3, 0x97, 0x73, 0x38, 0xd6, 0x52, + 0x7c, 0xc8, 0xa4, 0xb5, 0xea, 0xe9, 0xb2, 0x54, 0x56, 0xd4, 0xeb, 0xb8, + 0x57, 0x3a, 0x40, 0x52, 0x5a, 0x5e, 0x46, 0x27, 0xa3, 0x7b, 0x30, 0x2d, + 0x08, 0x3d, 0x85, 0x1e, 0x9a, 0xf0, 0x32, 0xa8, 0xf2, 0x10, 0xa2, 0x83, + 0x9b, 0xe2, 0x28, 0xf6, 0x9d, 0xcb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x82, 0x01, 0x20, 0x30, 0x82, 0x01, 0x1c, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x7d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x76, + 0x30, 0x74, 0x30, 0x38, 0x06, 0x0b, 0x2b, 0x06, 0x04, 0x01, 0x81, 0xad, + 0x5a, 0x02, 0x05, 0x03, 0x03, 0x30, 0x29, 0x30, 0x27, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1b, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6b, 0x65, 0x79, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x43, + 0x30, 0x38, 0x06, 0x0b, 0x2b, 0x06, 0x04, 0x01, 0x81, 0xad, 0x5a, 0x02, + 0x05, 0x01, 0x03, 0x30, 0x29, 0x30, 0x27, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1b, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6b, 0x65, 0x79, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x43, 0x30, 0x37, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x30, 0x30, 0x2e, 0x30, 0x2c, 0xa0, + 0x2a, 0xa0, 0x28, 0x86, 0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x70, 0x6c, 0x75, 0x73, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x52, 0x4c, 0x2f, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x00, 0x11, + 0x41, 0xdf, 0x3b, 0x9d, 0x3b, 0xcb, 0xb8, 0xa2, 0xc1, 0x33, 0x92, 0xa8, + 0x81, 0xcc, 0xe5, 0x7d, 0xe7, 0x99, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe3, 0x73, 0x2d, 0xdf, 0xcb, + 0x0e, 0x28, 0x0c, 0xde, 0xdd, 0xb3, 0xa4, 0xca, 0x79, 0xb8, 0x8e, 0xbb, + 0xe8, 0x30, 0x89, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x08, + 0x88, 0xfe, 0x1f, 0xa2, 0xca, 0xcd, 0xe2, 0xa0, 0xf1, 0x2e, 0x7c, 0x67, + 0x49, 0xfb, 0xdc, 0x94, 0xac, 0x7f, 0x41, 0x0d, 0x78, 0x01, 0xba, 0x31, + 0xf7, 0x9b, 0xfb, 0x31, 0x18, 0x77, 0x2f, 0x66, 0x25, 0x94, 0xb8, 0x6d, + 0x16, 0x74, 0x81, 0xf1, 0xc0, 0xae, 0x67, 0xc6, 0x14, 0x45, 0x7a, 0x01, + 0xd1, 0x13, 0x88, 0xfc, 0xe2, 0x8d, 0x22, 0x1d, 0xbd, 0x1e, 0x0c, 0xc7, + 0xa9, 0x7e, 0xd0, 0xc3, 0x97, 0xf6, 0x37, 0x5b, 0x41, 0x5e, 0x67, 0x94, + 0x8e, 0xab, 0x69, 0x02, 0x17, 0x18, 0xf5, 0x4d, 0x38, 0xc2, 0x49, 0x28, + 0x09, 0x6e, 0x5a, 0x9b, 0xa6, 0x27, 0xdb, 0xc0, 0x5f, 0x8f, 0x44, 0x9c, + 0x90, 0x65, 0x99, 0xd8, 0xb3, 0x2e, 0xc1, 0x92, 0xee, 0x1a, 0x9d, 0x0f, + 0x72, 0x45, 0x20, 0xfa, 0x2c, 0x0c, 0x9c, 0x5d, 0xcd, 0x5b, 0x54, 0x41, + 0x54, 0x4f, 0xd3, 0xe2, 0xc7, 0x59, 0x84, 0x3f, 0x17, 0x7b, 0x7d, 0x0e, + 0xc2, 0xef, 0x62, 0xc7, 0xba, 0xb1, 0x26, 0x6c, 0x83, 0x4e, 0xd3, 0x19, + 0xc5, 0xff, 0x56, 0xa7, 0xb4, 0x45, 0x3f, 0x7a, 0x9e, 0xfa, 0xd0, 0x39, + 0x3e, 0x80, 0x46, 0x75, 0x5d, 0x5a, 0x79, 0x7a, 0x33, 0xc5, 0x01, 0xbc, + 0x02, 0x44, 0xce, 0x1b, 0xc0, 0x31, 0x4e, 0x47, 0x96, 0x15, 0x6e, 0xe7, + 0xe4, 0x76, 0xf0, 0xc2, 0x90, 0x0d, 0xa1, 0x78, 0xf4, 0x38, 0x00, 0x91, + 0x2b, 0x65, 0x7c, 0x79, 0x13, 0xa8, 0x3e, 0x91, 0x14, 0xdc, 0x88, 0x05, + 0x08, 0xd7, 0x6f, 0x53, 0xf6, 0x15, 0x43, 0xee, 0xc5, 0x53, 0x56, 0x1a, + 0x02, 0xb5, 0xa6, 0xa2, 0x46, 0x8d, 0x1e, 0x13, 0xe4, 0x67, 0xc2, 0x45, + 0x5f, 0x40, 0x5e, 0x10, 0x42, 0x58, 0xb5, 0xcd, 0x44, 0xa3, 0x94, 0x4c, + 0x1c, 0x54, 0x90, 0x4d, 0x91, 0x9a, 0x26, 0x8b, 0xad, 0xa2, 0x80, 0x50, + 0x8d, 0x14, 0x14, +} + +var certSet2Cert8 = []byte{ + 0x30, 0x82, 0x04, 0x38, 0x30, 0x82, 0x03, 0xa1, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0x6d, 0xb9, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, + 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x1e, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x23, 0x30, 0x21, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x47, 0x54, 0x45, 0x20, 0x43, + 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x30, 0x31, 0x31, 0x33, 0x30, 0x31, 0x36, 0x33, 0x35, 0x32, + 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x38, 0x31, 0x30, 0x31, 0x35, + 0x33, 0x34, 0x32, 0x36, 0x5a, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x45, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x42, 0x61, 0x6c, 0x74, 0x69, + 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, + 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, + 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x04, + 0xbb, 0x22, 0xab, 0x98, 0x3d, 0x57, 0xe8, 0x26, 0x72, 0x9a, 0xb5, 0x79, + 0xd4, 0x29, 0xe2, 0xe1, 0xe8, 0x95, 0x80, 0xb1, 0xb0, 0xe3, 0x5b, 0x8e, + 0x2b, 0x29, 0x9a, 0x64, 0xdf, 0xa1, 0x5d, 0xed, 0xb0, 0x09, 0x05, 0x6d, + 0xdb, 0x28, 0x2e, 0xce, 0x62, 0xa2, 0x62, 0xfe, 0xb4, 0x88, 0xda, 0x12, + 0xeb, 0x38, 0xeb, 0x21, 0x9d, 0xc0, 0x41, 0x2b, 0x01, 0x52, 0x7b, 0x88, + 0x77, 0xd3, 0x1c, 0x8f, 0xc7, 0xba, 0xb9, 0x88, 0xb5, 0x6a, 0x09, 0xe7, + 0x73, 0xe8, 0x11, 0x40, 0xa7, 0xd1, 0xcc, 0xca, 0x62, 0x8d, 0x2d, 0xe5, + 0x8f, 0x0b, 0xa6, 0x50, 0xd2, 0xa8, 0x50, 0xc3, 0x28, 0xea, 0xf5, 0xab, + 0x25, 0x87, 0x8a, 0x9a, 0x96, 0x1c, 0xa9, 0x67, 0xb8, 0x3f, 0x0c, 0xd5, + 0xf7, 0xf9, 0x52, 0x13, 0x2f, 0xc2, 0x1b, 0xd5, 0x70, 0x70, 0xf0, 0x8f, + 0xc0, 0x12, 0xca, 0x06, 0xcb, 0x9a, 0xe1, 0xd9, 0xca, 0x33, 0x7a, 0x77, + 0xd6, 0xf8, 0xec, 0xb9, 0xf1, 0x68, 0x44, 0x42, 0x48, 0x13, 0xd2, 0xc0, + 0xc2, 0xa4, 0xae, 0x5e, 0x60, 0xfe, 0xb6, 0xa6, 0x05, 0xfc, 0xb4, 0xdd, + 0x07, 0x59, 0x02, 0xd4, 0x59, 0x18, 0x98, 0x63, 0xf5, 0xa5, 0x63, 0xe0, + 0x90, 0x0c, 0x7d, 0x5d, 0xb2, 0x06, 0x7a, 0xf3, 0x85, 0xea, 0xeb, 0xd4, + 0x03, 0xae, 0x5e, 0x84, 0x3e, 0x5f, 0xff, 0x15, 0xed, 0x69, 0xbc, 0xf9, + 0x39, 0x36, 0x72, 0x75, 0xcf, 0x77, 0x52, 0x4d, 0xf3, 0xc9, 0x90, 0x2c, + 0xb9, 0x3d, 0xe5, 0xc9, 0x23, 0x53, 0x3f, 0x1f, 0x24, 0x98, 0x21, 0x5c, + 0x07, 0x99, 0x29, 0xbd, 0xc6, 0x3a, 0xec, 0xe7, 0x6e, 0x86, 0x3a, 0x6b, + 0x97, 0x74, 0x63, 0x33, 0xbd, 0x68, 0x18, 0x31, 0xf0, 0x78, 0x8d, 0x76, + 0xbf, 0xfc, 0x9e, 0x8e, 0x5d, 0x2a, 0x86, 0xa7, 0x4d, 0x90, 0xdc, 0x27, + 0x1a, 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x6a, 0x30, + 0x82, 0x01, 0x66, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x03, 0x30, + 0x4e, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x47, 0x30, 0x45, 0x30, 0x43, + 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x66, 0x6d, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, + 0x81, 0x89, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0x81, 0x30, 0x7f, + 0xa1, 0x79, 0xa4, 0x77, 0x30, 0x75, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f, + 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x27, 0x30, + 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x47, 0x54, 0x45, 0x20, + 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, + 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x1a, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x82, 0x02, 0x01, 0xa5, 0x30, 0x45, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x3e, 0x30, 0x3c, 0x30, 0x3a, 0xa0, 0x38, 0xa0, 0x36, + 0x86, 0x34, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x67, 0x69, 0x2d, 0x62, 0x69, + 0x6e, 0x2f, 0x43, 0x52, 0x4c, 0x2f, 0x32, 0x30, 0x31, 0x38, 0x2f, 0x63, + 0x64, 0x70, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe5, 0x9d, 0x59, 0x30, 0x82, 0x47, 0x58, + 0xcc, 0xac, 0xfa, 0x08, 0x54, 0x36, 0x86, 0x7b, 0x3a, 0xb5, 0x04, 0x4d, + 0xf0, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x16, 0xb4, 0x2c, 0xc9, + 0xf1, 0x5e, 0xe1, 0xa2, 0x7b, 0x9b, 0x78, 0x20, 0x7a, 0x4a, 0x70, 0x70, + 0x86, 0x19, 0x00, 0xb7, 0x05, 0x2a, 0xe8, 0xc9, 0x25, 0x39, 0x0f, 0xc3, + 0x64, 0x3c, 0x75, 0x09, 0xd9, 0x89, 0x15, 0x80, 0x07, 0xc2, 0x8d, 0xbc, + 0x29, 0xa5, 0x64, 0x50, 0xcf, 0x71, 0x75, 0x47, 0x23, 0xbd, 0x4d, 0xd8, + 0x7f, 0x77, 0x9a, 0x51, 0x10, 0x6e, 0x4e, 0x1f, 0x20, 0x3c, 0x47, 0x9c, + 0x43, 0x74, 0x7f, 0x96, 0x84, 0x10, 0x4c, 0x13, 0x43, 0xbe, 0xf8, 0xe0, + 0x72, 0x2e, 0xff, 0xbf, 0xae, 0x3c, 0x0a, 0x03, 0x60, 0x82, 0x4b, 0x6f, + 0xf9, 0x9a, 0xc5, 0x1e, 0xf6, 0xaf, 0x90, 0x3b, 0x9f, 0x61, 0x3b, 0x3e, + 0xde, 0x9b, 0x05, 0x1a, 0xc6, 0x2c, 0x3c, 0x57, 0x21, 0x08, 0x0f, 0x54, + 0xfa, 0x28, 0x63, 0x6c, 0xe8, 0x1b, 0x9c, 0x0f, 0xcf, 0xdd, 0x30, 0x44, + 0x13, 0xb9, 0x57, 0xfe, +} + +var certSet2Cert9 = []byte{ + 0x30, 0x82, 0x04, 0x44, 0x30, 0x82, 0x03, 0x2c, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x78, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, + 0x38, 0x32, 0x39, 0x32, 0x32, 0x32, 0x34, 0x35, 0x38, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x32, 0x32, 0x34, 0x35, 0x38, + 0x5a, 0x30, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x14, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x53, 0x53, 0x4c, 0x31, + 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x44, 0x56, 0x20, 0x53, 0x53, + 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdf, 0x41, 0x94, 0x7a, 0xda, 0xf7, + 0xe4, 0x31, 0x43, 0xb6, 0xea, 0x01, 0x1b, 0x5c, 0xce, 0x63, 0xea, 0xfa, + 0x6d, 0xa3, 0xd9, 0x6a, 0xee, 0x2d, 0x9a, 0x75, 0xf9, 0xd5, 0x9c, 0x5b, + 0xbd, 0x34, 0xdf, 0xd8, 0x1c, 0xc9, 0x6d, 0xd8, 0x04, 0x88, 0xda, 0x6e, + 0xb5, 0xb7, 0xb5, 0xf0, 0x30, 0xae, 0x40, 0xd6, 0x5d, 0xfa, 0xc4, 0x53, + 0xc1, 0xd4, 0x22, 0x9d, 0x04, 0x4e, 0x11, 0xa6, 0x95, 0xd5, 0x45, 0x7c, + 0x41, 0x05, 0x58, 0xe0, 0x4c, 0xdd, 0xf9, 0xee, 0x55, 0xbd, 0x5f, 0x46, + 0xdc, 0xad, 0x13, 0x08, 0x9d, 0x2c, 0xe4, 0xf7, 0x82, 0xe6, 0x07, 0x2b, + 0x9e, 0x0e, 0x8c, 0x34, 0xa1, 0xce, 0xc4, 0xa1, 0xe0, 0x81, 0x70, 0x86, + 0x00, 0x06, 0x3f, 0x2d, 0xea, 0x7c, 0x9b, 0x28, 0xae, 0x1b, 0x28, 0x8b, + 0x39, 0x09, 0xd3, 0xe7, 0xf0, 0x45, 0xa4, 0xb1, 0xba, 0x11, 0x67, 0x90, + 0x55, 0x7b, 0x8f, 0xde, 0xed, 0x38, 0x5c, 0xa1, 0xe1, 0xe3, 0x83, 0xc4, + 0xc3, 0x72, 0x91, 0x4f, 0x98, 0xee, 0x1c, 0xc2, 0x80, 0xaa, 0x64, 0xa5, + 0x3e, 0x83, 0x62, 0x1c, 0xcc, 0xe0, 0x9e, 0xf8, 0x5a, 0xc0, 0x13, 0x12, + 0x7d, 0xa2, 0xa7, 0x8b, 0xa3, 0xe7, 0x9f, 0x2a, 0xd7, 0x9b, 0xca, 0xcb, + 0xed, 0x97, 0x01, 0x9c, 0x28, 0x84, 0x51, 0x04, 0x50, 0x41, 0xbc, 0xb4, + 0xfc, 0x78, 0xe9, 0x1b, 0xcf, 0x14, 0xea, 0x1f, 0x0f, 0xfc, 0x2e, 0x01, + 0x32, 0x8d, 0xb6, 0x35, 0xcb, 0x0a, 0x18, 0x3b, 0xec, 0x5a, 0x3e, 0x3c, + 0x1b, 0xd3, 0x99, 0x43, 0x1e, 0x2f, 0xf7, 0xbd, 0xf3, 0x5b, 0x12, 0xb9, + 0x07, 0x5e, 0xed, 0x3e, 0xd1, 0xa9, 0x87, 0xcc, 0x77, 0x72, 0x27, 0xd4, + 0xd9, 0x75, 0xa2, 0x63, 0x4b, 0x93, 0x36, 0xbd, 0xe5, 0x5c, 0xd7, 0xbf, + 0x5f, 0x79, 0x0d, 0xb3, 0x32, 0xa7, 0x0b, 0xb2, 0x63, 0x23, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, 0x19, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, + 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x0b, 0x50, 0xec, 0x77, 0xef, + 0x2a, 0x9b, 0xff, 0xec, 0x03, 0xa1, 0x0a, 0xff, 0xad, 0xc6, 0xe4, 0x2a, + 0x18, 0xc7, 0x3e, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2e, + 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x2e, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, + 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, + 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4c, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, + 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, + 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x33, 0x24, 0xd5, 0x90, 0xaa, 0x29, 0x0c, 0x35, 0xb9, 0x2f, 0xc3, 0xc7, + 0x42, 0x93, 0xc0, 0xc6, 0x10, 0x4b, 0x03, 0x08, 0x76, 0x84, 0x10, 0xa2, + 0xe0, 0xe7, 0x53, 0x12, 0x27, 0xf2, 0x0a, 0xda, 0x7f, 0x3a, 0xdc, 0xfd, + 0x5c, 0x79, 0x5a, 0x8f, 0x17, 0x74, 0x43, 0x53, 0xb1, 0xd5, 0xd1, 0x5d, + 0x59, 0xb9, 0xa6, 0x84, 0x64, 0xca, 0xf1, 0x3a, 0x0a, 0x59, 0x96, 0x10, + 0xbf, 0xa9, 0x81, 0x57, 0x8b, 0x5c, 0x87, 0xdc, 0x7f, 0xe3, 0xe4, 0xbb, + 0x05, 0x7a, 0xa0, 0x32, 0x09, 0x13, 0x4e, 0x10, 0x81, 0x28, 0x1f, 0x9c, + 0x03, 0x62, 0xbc, 0xf4, 0x01, 0xb5, 0x29, 0x83, 0x46, 0x07, 0xb9, 0xe7, + 0xb8, 0x5d, 0xc8, 0xe9, 0xd1, 0xdd, 0xad, 0x3b, 0xf8, 0x34, 0xdb, 0xc1, + 0xd1, 0x95, 0xa9, 0x91, 0x18, 0xed, 0x3c, 0x2c, 0x37, 0x11, 0x4d, 0xcc, + 0xfe, 0x53, 0x3e, 0x50, 0x43, 0xf9, 0xc3, 0x56, 0x41, 0xac, 0x53, 0x9b, + 0x6c, 0x05, 0xb2, 0x9a, 0xe2, 0xe0, 0x59, 0x57, 0x30, 0x32, 0xb6, 0x26, + 0x4e, 0x13, 0x25, 0xcd, 0xfa, 0x48, 0x70, 0x0f, 0x75, 0x55, 0x60, 0x11, + 0xf5, 0x3b, 0xd5, 0x5e, 0x5a, 0x3c, 0x8b, 0x5b, 0x0f, 0x0f, 0x62, 0x42, + 0x48, 0x61, 0x85, 0x8b, 0x10, 0xf4, 0xc1, 0x88, 0xbf, 0x7f, 0x5f, 0x8a, + 0xc2, 0xd7, 0xcd, 0x2b, 0x94, 0x5c, 0x1f, 0x34, 0x4a, 0x08, 0xaf, 0xeb, + 0xae, 0x89, 0xa8, 0x48, 0x75, 0x55, 0x95, 0x1d, 0xbb, 0xc0, 0x9a, 0x01, + 0xb9, 0xf4, 0x03, 0x22, 0x3e, 0xd4, 0xe6, 0x52, 0x30, 0x0d, 0x67, 0xb9, + 0xc0, 0x91, 0xfd, 0x2d, 0x4c, 0x30, 0x8e, 0xbd, 0x8c, 0xa5, 0x04, 0x91, + 0xbb, 0xa4, 0xab, 0x7f, 0x0f, 0xd8, 0x6f, 0xf0, 0x66, 0x00, 0xc9, 0xa3, + 0x5c, 0xf5, 0xb0, 0x8f, 0x83, 0xe6, 0x9c, 0x5a, 0xe6, 0xb6, 0xb9, 0xc5, + 0xbc, 0xbe, 0xe4, 0x02, +} + +var certSet2Cert10 = []byte{ + 0x30, 0x82, 0x04, 0x45, 0x30, 0x82, 0x03, 0xae, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x33, 0x65, 0x50, 0x08, 0x79, 0xad, 0x73, 0xe2, 0x30, + 0xb9, 0xe0, 0x1d, 0x0d, 0x7f, 0xac, 0x91, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xce, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x5a, 0x41, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, + 0x0c, 0x57, 0x65, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x43, 0x61, 0x70, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, + 0x43, 0x61, 0x70, 0x65, 0x20, 0x54, 0x6f, 0x77, 0x6e, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x54, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, + 0x67, 0x20, 0x63, 0x63, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x1f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x21, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x54, 0x68, 0x61, + 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x31, 0x28, 0x30, + 0x26, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, + 0x16, 0x19, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x2d, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x40, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x31, + 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, + 0x31, 0x32, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, + 0x81, 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x1f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, + 0x30, 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xac, 0xa0, 0xf0, 0xfb, 0x80, 0x59, 0xd4, 0x9c, 0xc7, 0xa4, 0xcf, 0x9d, + 0xa1, 0x59, 0x73, 0x09, 0x10, 0x45, 0x0c, 0x0d, 0x2c, 0x6e, 0x68, 0xf1, + 0x6c, 0x5b, 0x48, 0x68, 0x49, 0x59, 0x37, 0xfc, 0x0b, 0x33, 0x19, 0xc2, + 0x77, 0x7f, 0xcc, 0x10, 0x2d, 0x95, 0x34, 0x1c, 0xe6, 0xeb, 0x4d, 0x09, + 0xa7, 0x1c, 0xd2, 0xb8, 0xc9, 0x97, 0x36, 0x02, 0xb7, 0x89, 0xd4, 0x24, + 0x5f, 0x06, 0xc0, 0xcc, 0x44, 0x94, 0x94, 0x8d, 0x02, 0x62, 0x6f, 0xeb, + 0x5a, 0xdd, 0x11, 0x8d, 0x28, 0x9a, 0x5c, 0x84, 0x90, 0x10, 0x7a, 0x0d, + 0xbd, 0x74, 0x66, 0x2f, 0x6a, 0x38, 0xa0, 0xe2, 0xd5, 0x54, 0x44, 0xeb, + 0x1d, 0x07, 0x9f, 0x07, 0xba, 0x6f, 0xee, 0xe9, 0xfd, 0x4e, 0x0b, 0x29, + 0xf5, 0x3e, 0x84, 0xa0, 0x01, 0xf1, 0x9c, 0xab, 0xf8, 0x1c, 0x7e, 0x89, + 0xa4, 0xe8, 0xa1, 0xd8, 0x71, 0x65, 0x0d, 0xa3, 0x51, 0x7b, 0xee, 0xbc, + 0xd2, 0x22, 0x60, 0x0d, 0xb9, 0x5b, 0x9d, 0xdf, 0xba, 0xfc, 0x51, 0x5b, + 0x0b, 0xaf, 0x98, 0xb2, 0xe9, 0x2e, 0xe9, 0x04, 0xe8, 0x62, 0x87, 0xde, + 0x2b, 0xc8, 0xd7, 0x4e, 0xc1, 0x4c, 0x64, 0x1e, 0xdd, 0xcf, 0x87, 0x58, + 0xba, 0x4a, 0x4f, 0xca, 0x68, 0x07, 0x1d, 0x1c, 0x9d, 0x4a, 0xc6, 0xd5, + 0x2f, 0x91, 0xcc, 0x7c, 0x71, 0x72, 0x1c, 0xc5, 0xc0, 0x67, 0xeb, 0x32, + 0xfd, 0xc9, 0x92, 0x5c, 0x94, 0xda, 0x85, 0xc0, 0x9b, 0xbf, 0x53, 0x7d, + 0x2b, 0x09, 0xf4, 0x8c, 0x9d, 0x91, 0x1f, 0x97, 0x6a, 0x52, 0xcb, 0xde, + 0x09, 0x36, 0xa4, 0x77, 0xd8, 0x7b, 0x87, 0x50, 0x44, 0xd5, 0x3e, 0x6e, + 0x29, 0x69, 0xfb, 0x39, 0x49, 0x26, 0x1e, 0x09, 0xa5, 0x80, 0x7b, 0x40, + 0x2d, 0xeb, 0xe8, 0x27, 0x85, 0xc9, 0xfe, 0x61, 0xfd, 0x7e, 0xe6, 0x7c, + 0x97, 0x1d, 0xd5, 0x9d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xc2, + 0x30, 0x81, 0xbf, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x3b, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, 0x04, 0x55, + 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x7b, 0x5b, 0x45, 0xcf, 0xaf, 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, + 0x6a, 0xb6, 0xf3, 0x46, 0xeb, 0x57, 0x48, 0x50, 0x30, 0x40, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x39, 0x30, 0x37, 0x30, 0x35, 0xa0, 0x33, 0xa0, + 0x31, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x72, 0x65, 0x6d, 0x69, + 0x75, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x84, 0xa8, 0x4c, + 0xc9, 0x3e, 0x2a, 0xbc, 0x9a, 0xe2, 0xcc, 0x8f, 0x0b, 0xb2, 0x25, 0x77, + 0xc4, 0x61, 0x89, 0x89, 0x63, 0x5a, 0xd4, 0xa3, 0x15, 0x40, 0xd4, 0xfb, + 0x5e, 0x3f, 0xb4, 0x43, 0xea, 0x63, 0x17, 0x2b, 0x6b, 0x99, 0x74, 0x9e, + 0x09, 0xa8, 0xdd, 0xd4, 0x56, 0x15, 0x2e, 0x7a, 0x79, 0x31, 0x5f, 0x63, + 0x96, 0x53, 0x1b, 0x34, 0xd9, 0x15, 0xea, 0x4f, 0x6d, 0x70, 0xca, 0xbe, + 0xf6, 0x82, 0xa9, 0xed, 0xda, 0x85, 0x77, 0xcc, 0x76, 0x1c, 0x6a, 0x81, + 0x0a, 0x21, 0xd8, 0x41, 0x99, 0x7f, 0x5e, 0x2e, 0x82, 0xc1, 0xe8, 0xaa, + 0xf7, 0x93, 0x81, 0x05, 0xaa, 0x92, 0xb4, 0x1f, 0xb7, 0x9a, 0xc0, 0x07, + 0x17, 0xf5, 0xcb, 0xc6, 0xb4, 0x4c, 0x0e, 0xd7, 0x56, 0xdc, 0x71, 0x20, + 0x74, 0x38, 0xd6, 0x74, 0xc6, 0xd6, 0x8f, 0x6b, 0xaf, 0x8b, 0x8d, 0xa0, + 0x6c, 0x29, 0x0b, 0x61, 0xe0, +} + +var certSet2Cert11 = []byte{ + 0x30, 0x82, 0x04, 0x4d, 0x30, 0x82, 0x03, 0x35, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x44, 0x4e, 0xf0, + 0x36, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4c, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, + 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, + 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41, + 0x6c, 0x70, 0x68, 0x61, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, 0x47, 0x32, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0x01, 0xec, + 0xe4, 0xec, 0x73, 0x60, 0xfb, 0x7e, 0x8f, 0x6a, 0xb7, 0xc6, 0x17, 0xe3, + 0x92, 0x64, 0x32, 0xd4, 0xac, 0x00, 0xd9, 0xa2, 0x0f, 0xb9, 0xed, 0xee, + 0x6b, 0x8a, 0x86, 0xca, 0x92, 0x67, 0xd9, 0x74, 0xd7, 0x5d, 0x47, 0x02, + 0x3c, 0x8f, 0x40, 0xd6, 0x9e, 0x6d, 0x14, 0xcd, 0xc3, 0xda, 0x29, 0x39, + 0xa7, 0x0f, 0x05, 0x0a, 0x68, 0xa2, 0x66, 0x1a, 0x1e, 0xc4, 0xb2, 0x8b, + 0x76, 0x58, 0xe5, 0xab, 0x5d, 0x1d, 0x8f, 0x40, 0xb3, 0x39, 0x8b, 0xef, + 0x1e, 0x83, 0x7d, 0x22, 0xd0, 0xe3, 0xa9, 0x00, 0x2e, 0xec, 0x53, 0xcf, + 0x62, 0x19, 0x85, 0x44, 0x28, 0x4c, 0xc0, 0x27, 0xcb, 0x7b, 0x0e, 0xec, + 0x10, 0x64, 0x00, 0x10, 0xa4, 0x05, 0xcc, 0xa0, 0x72, 0xbe, 0x41, 0x6c, + 0x31, 0x5b, 0x48, 0xe4, 0xb1, 0xec, 0xb9, 0x23, 0xeb, 0x55, 0x4d, 0xd0, + 0x7d, 0x62, 0x4a, 0xa5, 0xb4, 0xa5, 0xa4, 0x59, 0x85, 0xc5, 0x25, 0x91, + 0xa6, 0xfe, 0xa6, 0x09, 0x9f, 0x06, 0x10, 0x6d, 0x8f, 0x81, 0x0c, 0x64, + 0x40, 0x5e, 0x73, 0x00, 0x9a, 0xe0, 0x2e, 0x65, 0x98, 0x54, 0x10, 0x00, + 0x70, 0x98, 0xc8, 0xe1, 0xed, 0x34, 0x5f, 0xd8, 0x9c, 0xc7, 0x0d, 0xc0, + 0xd6, 0x23, 0x59, 0x45, 0xfc, 0xfe, 0x55, 0x7a, 0x86, 0xee, 0x94, 0x60, + 0x22, 0xf1, 0xae, 0xd1, 0xe6, 0x55, 0x46, 0xf6, 0x99, 0xc5, 0x1b, 0x08, + 0x74, 0x5f, 0xac, 0xb0, 0x64, 0x84, 0x8f, 0x89, 0x38, 0x1c, 0xa1, 0xa7, + 0x90, 0x21, 0x4f, 0x02, 0x6e, 0xbd, 0xe0, 0x61, 0x67, 0xd4, 0xf8, 0x42, + 0x87, 0x0f, 0x0a, 0xf7, 0xc9, 0x04, 0x6d, 0x2a, 0xa9, 0x2f, 0xef, 0x42, + 0xa5, 0xdf, 0xdd, 0xa3, 0x53, 0xdb, 0x98, 0x1e, 0x81, 0xf9, 0x9a, 0x72, + 0x7b, 0x5a, 0xde, 0x4f, 0x3e, 0x7f, 0xa2, 0x58, 0xa0, 0xe2, 0x17, 0xad, + 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x23, 0x30, 0x82, + 0x01, 0x1f, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0xf5, 0xcd, 0xd5, 0x3c, 0x08, 0x50, 0xf9, 0x6a, 0x4f, 0x3a, 0xb7, + 0x97, 0xda, 0x56, 0x83, 0xe6, 0x69, 0xd2, 0x68, 0xf7, 0x30, 0x45, 0x06, + 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3e, 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x04, + 0x55, 0x1d, 0x20, 0x00, 0x30, 0x32, 0x30, 0x30, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x24, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x30, 0x33, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, + 0x24, 0x86, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, + 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, + 0x6c, 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, + 0x6f, 0x74, 0x72, 0x31, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0x60, 0x7b, 0x66, 0x1a, 0x45, 0x0d, 0x97, + 0xca, 0x89, 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, 0xa8, 0xff, 0xfc, 0xfd, + 0x4b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x60, 0x40, 0x68, + 0x16, 0x47, 0xe7, 0x16, 0x8d, 0xdb, 0x5c, 0xa1, 0x56, 0x2a, 0xcb, 0xf4, + 0x5c, 0x9b, 0xb0, 0x1e, 0xa2, 0x4b, 0xf5, 0xcb, 0x02, 0x3f, 0xf8, 0x0b, + 0xa1, 0xf2, 0xa7, 0x42, 0xd4, 0xb7, 0x4c, 0xeb, 0xe3, 0x66, 0x80, 0xf3, + 0x25, 0x43, 0x78, 0x2e, 0x1b, 0x17, 0x56, 0x07, 0x52, 0x18, 0xcb, 0xd1, + 0xa8, 0xec, 0xe6, 0xfb, 0x73, 0x3e, 0xa4, 0x62, 0x8c, 0x80, 0xb4, 0xd2, + 0xc5, 0x12, 0x73, 0xa3, 0xd3, 0xfa, 0x02, 0x38, 0xbe, 0x63, 0x3d, 0x84, + 0xb8, 0x99, 0xc1, 0xf1, 0xba, 0xf7, 0x9f, 0xc3, 0x40, 0xd1, 0x58, 0x18, + 0x53, 0xc1, 0x62, 0xdd, 0xaf, 0x18, 0x42, 0x7f, 0x34, 0x4e, 0xc5, 0x43, + 0xd5, 0x71, 0xb0, 0x30, 0x00, 0xc7, 0xe3, 0x90, 0xae, 0x3f, 0x57, 0x86, + 0x97, 0xce, 0xea, 0x0c, 0x12, 0x8e, 0x22, 0x70, 0xe3, 0x66, 0xa7, 0x54, + 0x7f, 0x2e, 0x28, 0xcb, 0xd4, 0x54, 0xd0, 0xb3, 0x1e, 0x62, 0x67, 0x08, + 0xf9, 0x27, 0xe1, 0xcb, 0xe3, 0x66, 0xb8, 0x24, 0x1b, 0x89, 0x6a, 0x89, + 0x44, 0x65, 0xf2, 0xd9, 0x4c, 0xd2, 0x58, 0x1c, 0x8c, 0x4e, 0xc0, 0x95, + 0xa1, 0xd4, 0xef, 0x67, 0x2f, 0x38, 0x20, 0xe8, 0x2e, 0xff, 0x96, 0x51, + 0xf0, 0xba, 0xd8, 0x3d, 0x92, 0x70, 0x47, 0x65, 0x1c, 0x9e, 0x73, 0x72, + 0xb4, 0x60, 0x0c, 0x5c, 0xe2, 0xd1, 0x73, 0x76, 0xe0, 0xaf, 0x4e, 0xe2, + 0xe5, 0x37, 0xa5, 0x45, 0x2f, 0x8a, 0x23, 0x3e, 0x87, 0xc7, 0x30, 0xe6, + 0x31, 0x38, 0x7c, 0xf4, 0xdd, 0x52, 0xca, 0xf3, 0x53, 0x04, 0x25, 0x57, + 0x56, 0x66, 0x94, 0xe8, 0x0b, 0xee, 0xe6, 0x03, 0x14, 0x4e, 0xee, 0xfd, + 0x6d, 0x94, 0x64, 0x9e, 0x5e, 0xce, 0x79, 0xd4, 0xb2, 0xa6, 0xcf, 0x40, + 0xb1, 0x44, 0xa8, 0x3e, 0x87, 0x19, 0x5e, 0xe9, 0xf8, 0x21, 0x16, 0x59, + 0x53, +} + +var certSet2Cert12 = []byte{ + 0x30, 0x82, 0x04, 0x4f, 0x30, 0x82, 0x03, 0x37, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x6f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, + 0x31, 0x30, 0x35, 0x32, 0x31, 0x33, 0x36, 0x35, 0x30, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x31, 0x33, 0x36, 0x35, 0x30, + 0x5a, 0x30, 0x44, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x14, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe3, 0xbe, 0x7e, 0x0a, + 0x86, 0xa3, 0xcf, 0x6b, 0x6d, 0x3d, 0x2b, 0xa1, 0x97, 0xad, 0x49, 0x24, + 0x4d, 0xd7, 0x77, 0xb9, 0x34, 0x79, 0x08, 0xa5, 0x9e, 0xa2, 0x9e, 0xde, + 0x47, 0x12, 0x92, 0x3d, 0x7e, 0xea, 0x19, 0x86, 0xb1, 0xe8, 0x4f, 0x3d, + 0x5f, 0xf7, 0xd0, 0xa7, 0x77, 0x9a, 0x5b, 0x1f, 0x0a, 0x03, 0xb5, 0x19, + 0x53, 0xdb, 0xa5, 0x21, 0x94, 0x69, 0x63, 0x9d, 0x6a, 0x4c, 0x91, 0x0c, + 0x10, 0x47, 0xbe, 0x11, 0xfa, 0x6c, 0x86, 0x25, 0xb7, 0xab, 0x04, 0x68, + 0x42, 0x38, 0x09, 0x65, 0xf0, 0x14, 0xda, 0x19, 0x9e, 0xfa, 0x6b, 0x0b, + 0xab, 0x62, 0xef, 0x8d, 0xa7, 0xef, 0x63, 0x70, 0x23, 0xa8, 0xaf, 0x81, + 0xf3, 0xd1, 0x6e, 0x88, 0x67, 0x53, 0xec, 0x12, 0xa4, 0x29, 0x75, 0x8a, + 0xa7, 0xf2, 0x57, 0x3d, 0xa2, 0x83, 0x98, 0x97, 0xf2, 0x0a, 0x7d, 0xd4, + 0xe7, 0x43, 0x6e, 0x30, 0x78, 0x62, 0x22, 0x59, 0x59, 0xb8, 0x71, 0x27, + 0x45, 0xaa, 0x0f, 0x66, 0xc6, 0x55, 0x3f, 0xfa, 0x32, 0x17, 0x2b, 0x31, + 0x8f, 0x46, 0xa0, 0xfa, 0x69, 0x14, 0x7c, 0x9d, 0x9f, 0x5a, 0xe2, 0xeb, + 0x33, 0x4e, 0x10, 0xa6, 0xb3, 0xed, 0x77, 0x63, 0xd8, 0xc3, 0x9e, 0xf4, + 0xdd, 0xdf, 0x79, 0x9a, 0x7a, 0xd4, 0xee, 0xde, 0xdd, 0x9a, 0xcc, 0xc3, + 0xb7, 0xa9, 0x5d, 0xcc, 0x11, 0x3a, 0x07, 0xbb, 0x6f, 0x97, 0xa4, 0x01, + 0x23, 0x47, 0x95, 0x1f, 0xa3, 0x77, 0xfa, 0x58, 0x92, 0xc6, 0xc7, 0xd0, + 0xbd, 0xcf, 0x93, 0x18, 0x42, 0xb7, 0x7e, 0xf7, 0x9e, 0x65, 0xea, 0xd5, + 0x3b, 0xca, 0xed, 0xac, 0xc5, 0x70, 0xa1, 0xfe, 0xd4, 0x10, 0x9a, 0xf0, + 0x12, 0x04, 0x44, 0xac, 0x1a, 0x5b, 0x78, 0x50, 0x45, 0x57, 0x4c, 0x6f, + 0xbd, 0x80, 0xcb, 0x81, 0x5c, 0x2d, 0xb3, 0xbc, 0x76, 0xa1, 0x1e, 0x65, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x4a, 0x30, 0x82, 0x01, + 0x46, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, + 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd2, 0x6f, 0xf7, + 0x96, 0xf4, 0x85, 0x3f, 0x72, 0x3c, 0x30, 0x7d, 0x23, 0xda, 0x85, 0x78, + 0x9b, 0xa3, 0x7c, 0x5a, 0x7c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x31, 0x2e, 0x73, 0x79, + 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, + 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, + 0x6c, 0x30, 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x67, 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, + 0x43, 0x30, 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, + 0x01, 0x07, 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x29, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, + 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, + 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, + 0x35, 0x33, 0x39, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa0, + 0xd4, 0xf7, 0x2c, 0xfb, 0x74, 0x0b, 0x7f, 0x64, 0xf1, 0xcd, 0x43, 0x6a, + 0x9f, 0x62, 0x53, 0x1c, 0x02, 0x7c, 0x98, 0x90, 0xa2, 0xee, 0x4f, 0x68, + 0xd4, 0x20, 0x1a, 0x73, 0x12, 0x3e, 0x77, 0xb3, 0x50, 0xeb, 0x72, 0xbc, + 0xee, 0x88, 0xbe, 0x7f, 0x17, 0xea, 0x77, 0x8f, 0x83, 0x61, 0x95, 0x4f, + 0x84, 0xa1, 0xcb, 0x32, 0x4f, 0x6c, 0x21, 0xbe, 0xd2, 0x69, 0x96, 0x7d, + 0x63, 0xbd, 0xdc, 0x2b, 0xa8, 0x1f, 0xd0, 0x13, 0x84, 0x70, 0xfe, 0xf6, + 0x35, 0x95, 0x89, 0xf9, 0xa6, 0x77, 0xb0, 0x46, 0xc8, 0xbb, 0xb7, 0x13, + 0xf5, 0xc9, 0x60, 0x69, 0xd6, 0x4c, 0xfe, 0xd2, 0x8e, 0xef, 0xd3, 0x60, + 0xc1, 0x80, 0x80, 0xe1, 0xe7, 0xfb, 0x8b, 0x6f, 0x21, 0x79, 0x4a, 0xe0, + 0xdc, 0xa9, 0x1b, 0xc1, 0xb7, 0xfb, 0xc3, 0x49, 0x59, 0x5c, 0xb5, 0x77, + 0x07, 0x44, 0xd4, 0x97, 0xfc, 0x49, 0x00, 0x89, 0x6f, 0x06, 0x4e, 0x01, + 0x70, 0x19, 0xac, 0x2f, 0x11, 0xc0, 0xe2, 0xe6, 0x0f, 0x2f, 0x86, 0x4b, + 0x8d, 0x7b, 0xc3, 0xb9, 0xa7, 0x2e, 0xf4, 0xf1, 0xac, 0x16, 0x3e, 0x39, + 0x49, 0x51, 0x9e, 0x17, 0x4b, 0x4f, 0x10, 0x3a, 0x5b, 0xa5, 0xa8, 0x92, + 0x6f, 0xfd, 0xfa, 0xd6, 0x0b, 0x03, 0x4d, 0x47, 0x56, 0x57, 0x19, 0xf3, + 0xcb, 0x6b, 0xf5, 0xf3, 0xd6, 0xcf, 0xb0, 0xf5, 0xf5, 0xa3, 0x11, 0xd2, + 0x20, 0x53, 0x13, 0x34, 0x37, 0x05, 0x2c, 0x43, 0x5a, 0x63, 0xdf, 0x8d, + 0x40, 0xd6, 0x85, 0x1e, 0x51, 0xe9, 0x51, 0x17, 0x1e, 0x03, 0x56, 0xc9, + 0xf1, 0x30, 0xad, 0xe7, 0x9b, 0x11, 0xa2, 0xb9, 0xd0, 0x31, 0x81, 0x9b, + 0x68, 0xb1, 0xd9, 0xe8, 0xf3, 0xe6, 0x94, 0x7e, 0xc7, 0xae, 0x13, 0x2f, + 0x87, 0xed, 0xd0, 0x25, 0xb0, 0x68, 0xf9, 0xde, 0x08, 0x5a, 0xf3, 0x29, + 0xcc, 0xd4, 0x92, +} + +var certSet2Cert13 = []byte{ + 0x30, 0x82, 0x04, 0x59, 0x30, 0x82, 0x03, 0x41, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x63, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, + 0x38, 0x32, 0x37, 0x32, 0x30, 0x34, 0x30, 0x34, 0x30, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x30, 0x34, 0x30, 0x34, 0x30, + 0x5a, 0x30, 0x44, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x14, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb9, 0x27, 0xf9, 0x4f, + 0xd8, 0xf6, 0xb7, 0x15, 0x3f, 0x8f, 0xcd, 0xce, 0xd6, 0x8d, 0x1c, 0x6b, + 0xfd, 0x7f, 0xda, 0x54, 0x21, 0x4e, 0x03, 0xd8, 0xca, 0xd0, 0x72, 0x52, + 0x15, 0xb8, 0xc9, 0x82, 0x5b, 0x58, 0x79, 0x84, 0xff, 0x24, 0x72, 0x6f, + 0xf2, 0x69, 0x7f, 0xbc, 0x96, 0xd9, 0x9a, 0x7a, 0xc3, 0x3e, 0xa9, 0xcf, + 0x50, 0x22, 0x13, 0x0e, 0x86, 0x19, 0xdb, 0xe8, 0x49, 0xef, 0x8b, 0xe6, + 0xd6, 0x47, 0xf2, 0xfd, 0x73, 0x45, 0x08, 0xae, 0x8f, 0xac, 0x5e, 0xb6, + 0xf8, 0x9e, 0x7c, 0xf7, 0x10, 0xff, 0x92, 0x43, 0x66, 0xef, 0x1c, 0xd4, + 0xee, 0xa1, 0x46, 0x88, 0x11, 0x89, 0x49, 0x79, 0x7a, 0x25, 0xce, 0x4b, + 0x6a, 0xf0, 0xd7, 0x1c, 0x76, 0x1a, 0x29, 0x3c, 0xc9, 0xe4, 0xfd, 0x1e, + 0x85, 0xdc, 0xe0, 0x31, 0x65, 0x05, 0x47, 0x16, 0xac, 0x0a, 0x07, 0x4b, + 0x2e, 0x70, 0x5e, 0x6b, 0x06, 0xa7, 0x6b, 0x3a, 0x6c, 0xaf, 0x05, 0x12, + 0xc4, 0xb2, 0x11, 0x25, 0xd6, 0x3e, 0x97, 0x29, 0xf0, 0x83, 0x6c, 0x57, + 0x1c, 0xd8, 0xa5, 0xef, 0xcc, 0xec, 0xfd, 0xd6, 0x12, 0xf1, 0x3f, 0xdb, + 0x40, 0xb4, 0xae, 0x0f, 0x18, 0xd3, 0xc5, 0xaf, 0x40, 0x92, 0x5d, 0x07, + 0x5e, 0x4e, 0xfe, 0x62, 0x17, 0x37, 0x89, 0xe9, 0x8b, 0x74, 0x26, 0xa2, + 0xed, 0xb8, 0x0a, 0xe7, 0x6c, 0x15, 0x5b, 0x35, 0x90, 0x72, 0xdd, 0xd8, + 0x4d, 0x21, 0xd4, 0x40, 0x23, 0x5c, 0x8f, 0xee, 0x80, 0x31, 0x16, 0xab, + 0x68, 0x55, 0xf4, 0x0e, 0x3b, 0x54, 0xe9, 0x04, 0x4d, 0xf0, 0xcc, 0x4e, + 0x81, 0x5e, 0xe9, 0x6f, 0x52, 0x69, 0x4e, 0xbe, 0xa6, 0x16, 0x6d, 0x42, + 0xf5, 0x51, 0xff, 0xe0, 0x0b, 0x56, 0x3c, 0x98, 0x4f, 0x73, 0x8f, 0x0e, + 0x6f, 0x1a, 0x23, 0xf1, 0xc9, 0xc8, 0xd9, 0xdf, 0xbc, 0xec, 0x52, 0xd7, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x54, 0x30, 0x82, 0x01, + 0x50, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, + 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x11, 0x4a, 0xd0, + 0x73, 0x39, 0xd5, 0x5b, 0x69, 0x08, 0x5c, 0xba, 0x3d, 0xbf, 0x64, 0x9a, + 0xa8, 0x8b, 0x1c, 0x55, 0xbc, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, + 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, + 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, + 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, + 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x1d, 0x11, + 0x04, 0x23, 0x30, 0x21, 0xa4, 0x1f, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x56, 0x65, 0x72, 0x69, 0x53, + 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, 0x2d, 0x32, 0x2d, 0x32, 0x35, + 0x34, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3c, 0xe5, 0x3d, + 0x5a, 0x1b, 0xa2, 0x37, 0x2a, 0xe3, 0x46, 0xcf, 0x36, 0x96, 0x18, 0x3c, + 0x7b, 0xf1, 0x84, 0xc5, 0x57, 0x86, 0x77, 0x40, 0x9d, 0x35, 0xf0, 0x12, + 0xf0, 0x78, 0x18, 0xfb, 0x22, 0xa4, 0xde, 0x98, 0x4b, 0x78, 0x81, 0xe6, + 0x4d, 0x86, 0xe3, 0x91, 0x0f, 0x42, 0xe3, 0xb9, 0xdc, 0xa0, 0xd6, 0xff, + 0xa9, 0xf8, 0xb1, 0x79, 0x97, 0x99, 0xd1, 0xc3, 0x6c, 0x42, 0xa5, 0x92, + 0x94, 0xe0, 0x5d, 0x0c, 0x33, 0x18, 0x25, 0xc9, 0x2b, 0x95, 0x53, 0xe0, + 0xe5, 0xa9, 0x0c, 0x7d, 0x47, 0xfe, 0x7f, 0x51, 0x31, 0x44, 0x5e, 0xf7, + 0x2a, 0x1e, 0x35, 0xa2, 0x94, 0x32, 0xf7, 0xc9, 0xee, 0xc0, 0xb6, 0xc6, + 0x9a, 0xac, 0xde, 0x99, 0x21, 0x6a, 0x23, 0xa0, 0x38, 0x64, 0xee, 0xa3, + 0xc4, 0x88, 0x73, 0x32, 0x3b, 0x50, 0xce, 0xbf, 0xad, 0xd3, 0x75, 0x1e, + 0xa6, 0xf4, 0xe9, 0xf9, 0x42, 0x6b, 0x60, 0xb2, 0xdd, 0x45, 0xfd, 0x5d, + 0x57, 0x08, 0xce, 0x2d, 0x50, 0xe6, 0x12, 0x32, 0x16, 0x13, 0x8a, 0xf2, + 0x94, 0xa2, 0x9b, 0x47, 0xa8, 0x86, 0x7f, 0xd9, 0x98, 0xe5, 0xf7, 0xe5, + 0x76, 0x74, 0x64, 0xd8, 0x91, 0xbc, 0x84, 0x16, 0x28, 0xd8, 0x25, 0x44, + 0x30, 0x7e, 0x82, 0xd8, 0xac, 0xb1, 0xe4, 0xc0, 0xe4, 0x15, 0x6c, 0xdb, + 0xb6, 0x24, 0x27, 0x02, 0x2a, 0x01, 0x12, 0x85, 0xba, 0x31, 0x88, 0x58, + 0x47, 0x74, 0xe3, 0xb8, 0xd2, 0x64, 0xa6, 0xc3, 0x32, 0x59, 0x2e, 0x29, + 0x4b, 0x45, 0xf1, 0x5b, 0x89, 0x49, 0x2e, 0x82, 0x9a, 0xc6, 0x18, 0x15, + 0x44, 0xd0, 0x2e, 0x64, 0x01, 0x15, 0x68, 0x38, 0xf9, 0xf6, 0xf9, 0x66, + 0x03, 0x0c, 0x55, 0x1b, 0x9d, 0xbf, 0x00, 0x40, 0xae, 0xf0, 0x48, 0x27, + 0x4c, 0xe0, 0x80, 0x5e, 0x2d, 0xb9, 0x2a, 0x15, 0x7a, 0xbc, 0x66, 0xf8, + 0x35, +} + +var certSet2Cert14 = []byte{ + 0x30, 0x82, 0x04, 0x63, 0x30, 0x82, 0x03, 0x4b, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x44, 0x4e, 0xf0, + 0x3e, 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x60, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, + 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, + 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xa9, 0xdd, 0xcc, 0x0e, 0xb3, 0xe2, 0x32, + 0x39, 0xdd, 0x49, 0x22, 0xa8, 0x13, 0x69, 0x93, 0x87, 0x88, 0xe1, 0x0c, + 0xee, 0x71, 0x7d, 0xbd, 0x90, 0x87, 0x96, 0x5d, 0x59, 0xf2, 0xcc, 0xb3, + 0xd2, 0x58, 0x57, 0x57, 0xf9, 0x46, 0xef, 0x6c, 0x26, 0xd8, 0x36, 0x42, + 0x8e, 0x7e, 0x30, 0xb3, 0x2f, 0x9a, 0x3e, 0x53, 0x7b, 0x1f, 0x6e, 0xb6, + 0xa2, 0x4c, 0x45, 0x1f, 0x3c, 0xd3, 0x15, 0x93, 0x1c, 0x89, 0xed, 0x3c, + 0xf4, 0x57, 0xde, 0xca, 0xbd, 0xec, 0x06, 0x9a, 0x6a, 0x2a, 0xa0, 0x19, + 0x52, 0x7f, 0x51, 0xd1, 0x74, 0x39, 0x08, 0x9f, 0xab, 0xeb, 0xd7, 0x86, + 0x13, 0x15, 0x97, 0xae, 0x36, 0xc3, 0x54, 0x66, 0x0e, 0x5a, 0xf2, 0xa0, + 0x73, 0x85, 0x31, 0xe3, 0xb2, 0x64, 0x14, 0x6a, 0xff, 0xa5, 0xa2, 0x8e, + 0x24, 0xbb, 0xbd, 0x85, 0x52, 0x15, 0xa2, 0x79, 0xee, 0xf0, 0xb5, 0xee, + 0x3d, 0xb8, 0xf4, 0x7d, 0x80, 0xbc, 0xd9, 0x90, 0x35, 0x65, 0xb8, 0x17, + 0xa9, 0xad, 0xb3, 0x98, 0x9f, 0xa0, 0x7e, 0x7d, 0x6e, 0xfb, 0x3f, 0xad, + 0x7c, 0xc2, 0x1b, 0x59, 0x36, 0x96, 0xda, 0x37, 0x32, 0x4b, 0x4b, 0x5d, + 0x35, 0x02, 0x63, 0x8e, 0xdb, 0xa7, 0xcf, 0x62, 0xee, 0xcc, 0x2e, 0xd4, + 0x8d, 0xc9, 0xbd, 0x3c, 0x6a, 0x91, 0x72, 0xa2, 0x22, 0xa7, 0x72, 0x2d, + 0x20, 0xd1, 0xfa, 0xca, 0x37, 0xda, 0x18, 0x98, 0xe6, 0x16, 0x24, 0x71, + 0x25, 0x4b, 0xc4, 0xe5, 0x7b, 0x89, 0x52, 0x09, 0x02, 0xfd, 0x59, 0x2b, + 0x04, 0x6e, 0xca, 0x07, 0x81, 0xd4, 0xb3, 0xda, 0xda, 0xdb, 0xe3, 0xcc, + 0x80, 0xa8, 0x56, 0x07, 0x06, 0x7c, 0x96, 0x08, 0x37, 0x9d, 0xdb, 0x38, + 0xb6, 0x62, 0x34, 0x91, 0x62, 0x07, 0x74, 0x01, 0x38, 0xd8, 0x72, 0x30, + 0xe2, 0xeb, 0x90, 0x71, 0x26, 0x62, 0xc0, 0x57, 0xf3, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x25, 0x30, 0x82, 0x01, 0x21, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xea, 0x4e, 0x7c, + 0xd4, 0x80, 0x2d, 0xe5, 0x15, 0x81, 0x86, 0x26, 0x8c, 0x82, 0x6d, 0xc0, + 0x98, 0xa4, 0xcf, 0x97, 0x0f, 0x30, 0x47, 0x06, 0x03, 0x55, 0x1d, 0x20, + 0x04, 0x40, 0x30, 0x3e, 0x30, 0x3c, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, + 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, + 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x6e, + 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, + 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, + 0x72, 0x31, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x60, 0x7b, 0x66, 0x1a, 0x45, 0x0d, 0x97, 0xca, 0x89, + 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, 0xa8, 0xff, 0xfc, 0xfd, 0x4b, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xd7, 0x45, 0x9e, 0xa0, 0xdc, + 0xe0, 0xe3, 0x61, 0x5a, 0x0b, 0x7d, 0x77, 0x84, 0x17, 0x2d, 0x65, 0x5a, + 0x82, 0x9a, 0x8d, 0xa3, 0x27, 0x2a, 0x85, 0xf7, 0xc9, 0xef, 0xe9, 0x86, + 0xfd, 0xd4, 0x47, 0xcd, 0x01, 0x52, 0x96, 0xc5, 0x43, 0xbd, 0x37, 0xb1, + 0xe1, 0xb8, 0xf2, 0xa9, 0xd2, 0x8a, 0x11, 0x84, 0x71, 0x91, 0x15, 0x89, + 0xdc, 0x02, 0x9d, 0x0b, 0xcb, 0x6c, 0x33, 0x85, 0x34, 0x28, 0x9e, 0x20, + 0xb2, 0xb1, 0x97, 0xdc, 0x6d, 0x0b, 0x10, 0xc1, 0x3c, 0xcd, 0x5f, 0xea, + 0x5d, 0xd7, 0x98, 0x31, 0xc5, 0x34, 0x99, 0x5c, 0x00, 0x61, 0x55, 0xc4, + 0x1b, 0x02, 0x5b, 0xc5, 0xe3, 0x89, 0xc8, 0xb4, 0xb8, 0x6f, 0x1e, 0x38, + 0xf2, 0x56, 0x26, 0xe9, 0x41, 0xef, 0x3d, 0xcd, 0xac, 0x99, 0x4f, 0x59, + 0x4a, 0x57, 0x2d, 0x4b, 0x7d, 0xae, 0xc7, 0x88, 0xfb, 0xd6, 0x98, 0x3b, + 0xf5, 0xe5, 0xf0, 0xe8, 0x89, 0x89, 0xb9, 0x8b, 0x03, 0xcb, 0x5a, 0x23, + 0x1f, 0xa4, 0xfd, 0xb8, 0xea, 0xfb, 0x2e, 0x9d, 0xae, 0x6a, 0x73, 0x09, + 0xbc, 0xfc, 0xd5, 0xa0, 0xb5, 0x44, 0x82, 0xab, 0x44, 0x91, 0x2e, 0x50, + 0x2e, 0x57, 0xc1, 0x43, 0xd8, 0x91, 0x04, 0x8b, 0xe9, 0x11, 0x2e, 0x5f, + 0xb4, 0x3f, 0x79, 0xdf, 0x1e, 0xfb, 0x3f, 0x30, 0x00, 0x8b, 0x53, 0xe3, + 0xb7, 0x2c, 0x1d, 0x3b, 0x4d, 0x8b, 0xdc, 0xe4, 0x64, 0x1d, 0x04, 0x58, + 0x33, 0xaf, 0x1b, 0x55, 0xe7, 0xab, 0x0c, 0xbf, 0x30, 0x04, 0x74, 0xe4, + 0xf3, 0x0e, 0x2f, 0x30, 0x39, 0x8d, 0x4b, 0x04, 0x8c, 0x1e, 0x75, 0x66, + 0x66, 0x49, 0xe0, 0xbe, 0x40, 0x34, 0xc7, 0x5c, 0x5a, 0x51, 0x92, 0xba, + 0x12, 0x3c, 0x52, 0xd5, 0x04, 0x82, 0x55, 0x2d, 0x67, 0xa5, 0xdf, 0xb7, + 0x95, 0x7c, 0xee, 0x3f, 0xc3, 0x08, 0xba, 0x04, 0xbe, 0xc0, 0x46, +} + +var certSet2Cert15 = []byte{ + 0x30, 0x82, 0x04, 0x69, 0x30, 0x82, 0x03, 0x51, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x44, 0x4e, 0xf0, + 0x42, 0x47, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x66, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, + 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, + 0x31, 0x3c, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x33, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, + 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc7, + 0x0e, 0x6c, 0x3f, 0x23, 0x93, 0x7f, 0xcc, 0x70, 0xa5, 0x9d, 0x20, 0xc3, + 0x0e, 0x53, 0x3f, 0x7e, 0xc0, 0x4e, 0xc2, 0x98, 0x49, 0xca, 0x47, 0xd5, + 0x23, 0xef, 0x03, 0x34, 0x85, 0x74, 0xc8, 0xa3, 0x02, 0x2e, 0x46, 0x5c, + 0x0b, 0x7d, 0xc9, 0x88, 0x9d, 0x4f, 0x8b, 0xf0, 0xf8, 0x9c, 0x6c, 0x8c, + 0x55, 0x35, 0xdb, 0xbf, 0xf2, 0xb3, 0xea, 0xfb, 0xe3, 0x56, 0xe7, 0x4a, + 0x46, 0xd9, 0x13, 0x22, 0xca, 0x36, 0xd5, 0x9b, 0xc1, 0xa8, 0xe3, 0x96, + 0x43, 0x93, 0xf2, 0x0c, 0xbc, 0xe6, 0xf9, 0xe6, 0xe8, 0x99, 0xc8, 0x63, + 0x48, 0x78, 0x7f, 0x57, 0x36, 0x69, 0x1a, 0x19, 0x1d, 0x5a, 0xd1, 0xd4, + 0x7d, 0xc2, 0x9c, 0xd4, 0x7f, 0xe1, 0x80, 0x12, 0xae, 0x7a, 0xea, 0x88, + 0xea, 0x57, 0xd8, 0xca, 0x0a, 0x0a, 0x3a, 0x12, 0x49, 0xa2, 0x62, 0x19, + 0x7a, 0x0d, 0x24, 0xf7, 0x37, 0xeb, 0xb4, 0x73, 0x92, 0x7b, 0x05, 0x23, + 0x9b, 0x12, 0xb5, 0xce, 0xeb, 0x29, 0xdf, 0xa4, 0x14, 0x02, 0xb9, 0x01, + 0xa5, 0xd4, 0xa6, 0x9c, 0x43, 0x64, 0x88, 0xde, 0xf8, 0x7e, 0xfe, 0xe3, + 0xf5, 0x1e, 0xe5, 0xfe, 0xdc, 0xa3, 0xa8, 0xe4, 0x66, 0x31, 0xd9, 0x4c, + 0x25, 0xe9, 0x18, 0xb9, 0x89, 0x59, 0x09, 0xae, 0xe9, 0x9d, 0x1c, 0x6d, + 0x37, 0x0f, 0x4a, 0x1e, 0x35, 0x20, 0x28, 0xe2, 0xaf, 0xd4, 0x21, 0x8b, + 0x01, 0xc4, 0x45, 0xad, 0x6e, 0x2b, 0x63, 0xab, 0x92, 0x6b, 0x61, 0x0a, + 0x4d, 0x20, 0xed, 0x73, 0xba, 0x7c, 0xce, 0xfe, 0x16, 0xb5, 0xdb, 0x9f, + 0x80, 0xf0, 0xd6, 0x8b, 0x6c, 0xd9, 0x08, 0x79, 0x4a, 0x4f, 0x78, 0x65, + 0xda, 0x92, 0xbc, 0xbe, 0x35, 0xf9, 0xb3, 0xc4, 0xf9, 0x27, 0x80, 0x4e, + 0xff, 0x96, 0x52, 0xe6, 0x02, 0x20, 0xe1, 0x07, 0x73, 0xe9, 0x5d, 0x2b, + 0xbd, 0xb2, 0xf1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x25, + 0x30, 0x82, 0x01, 0x21, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x96, 0xde, 0x61, 0xf1, 0xbd, 0x1c, 0x16, 0x29, 0x53, + 0x1c, 0xc0, 0xcc, 0x7d, 0x3b, 0x83, 0x00, 0x40, 0xe6, 0x1a, 0x7c, 0x30, + 0x47, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x40, 0x30, 0x3e, 0x30, 0x3c, + 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, + 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, + 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x72, 0x31, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x60, 0x7b, 0x66, + 0x1a, 0x45, 0x0d, 0x97, 0xca, 0x89, 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, + 0xa8, 0xff, 0xfc, 0xfd, 0x4b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, + 0x00, 0x46, 0x2a, 0xee, 0x5e, 0xbd, 0xae, 0x01, 0x60, 0x37, 0x31, 0x11, + 0x86, 0x71, 0x74, 0xb6, 0x46, 0x49, 0xc8, 0x10, 0x16, 0xfe, 0x2f, 0x62, + 0x23, 0x17, 0xab, 0x1f, 0x87, 0xf8, 0x82, 0xed, 0xca, 0xdf, 0x0e, 0x2c, + 0xdf, 0x64, 0x75, 0x8e, 0xe5, 0x18, 0x72, 0xa7, 0x8c, 0x3a, 0x8b, 0xc9, + 0xac, 0xa5, 0x77, 0x50, 0xf7, 0xef, 0x9e, 0xa4, 0xe0, 0xa0, 0x8f, 0x14, + 0x57, 0xa3, 0x2a, 0x5f, 0xec, 0x7e, 0x6d, 0x10, 0xe6, 0xba, 0x8d, 0xb0, + 0x08, 0x87, 0x76, 0x0e, 0x4c, 0xb2, 0xd9, 0x51, 0xbb, 0x11, 0x02, 0xf2, + 0x5c, 0xdd, 0x1c, 0xbd, 0xf3, 0x55, 0x96, 0x0f, 0xd4, 0x06, 0xc0, 0xfc, + 0xe2, 0x23, 0x8a, 0x24, 0x70, 0xd3, 0xbb, 0xf0, 0x79, 0x1a, 0xa7, 0x61, + 0x70, 0x83, 0x8a, 0xaf, 0x06, 0xc5, 0x20, 0xd8, 0xa1, 0x63, 0xd0, 0x6c, + 0xae, 0x4f, 0x32, 0xd7, 0xae, 0x7c, 0x18, 0x45, 0x75, 0x05, 0x29, 0x77, + 0xdf, 0x42, 0x40, 0x64, 0x64, 0x86, 0xbe, 0x2a, 0x76, 0x09, 0x31, 0x6f, + 0x1d, 0x24, 0xf4, 0x99, 0xd0, 0x85, 0xfe, 0xf2, 0x21, 0x08, 0xf9, 0xc6, + 0xf6, 0xf1, 0xd0, 0x59, 0xed, 0xd6, 0x56, 0x3c, 0x08, 0x28, 0x03, 0x67, + 0xba, 0xf0, 0xf9, 0xf1, 0x90, 0x16, 0x47, 0xae, 0x67, 0xe6, 0xbc, 0x80, + 0x48, 0xe9, 0x42, 0x76, 0x34, 0x97, 0x55, 0x69, 0x24, 0x0e, 0x83, 0xd6, + 0xa0, 0x2d, 0xb4, 0xf5, 0xf3, 0x79, 0x8a, 0x49, 0x28, 0x74, 0x1a, 0x41, + 0xa1, 0xc2, 0xd3, 0x24, 0x88, 0x35, 0x30, 0x60, 0x94, 0x17, 0xb4, 0xe1, + 0x04, 0x22, 0x31, 0x3d, 0x3b, 0x2f, 0x17, 0x06, 0xb2, 0xb8, 0x9d, 0x86, + 0x2b, 0x5a, 0x69, 0xef, 0x83, 0xf5, 0x4b, 0xc4, 0xaa, 0xb4, 0x2a, 0xf8, + 0x7c, 0xa1, 0xb1, 0x85, 0x94, 0x8c, 0xf4, 0x0c, 0x87, 0x0c, 0xf4, 0xac, + 0x40, 0xf8, 0x59, 0x49, 0x98, +} + +var certSet2Cert16 = []byte{ + 0x30, 0x82, 0x04, 0x6c, 0x30, 0x82, 0x03, 0x54, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x4d, 0x5f, 0x2c, 0x34, 0x08, 0xb2, 0x4c, 0x20, 0xcd, + 0x6d, 0x50, 0x7e, 0x24, 0x4d, 0xc9, 0xec, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x32, 0x30, 0x38, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, 0x30, + 0x32, 0x30, 0x37, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x3c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x54, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x99, 0xe4, 0x85, + 0x5b, 0x76, 0x49, 0x7d, 0x2f, 0x05, 0xd8, 0xc5, 0xac, 0xc8, 0xc8, 0xa9, + 0xd3, 0xdc, 0x98, 0xe6, 0xd7, 0x34, 0xa6, 0x2f, 0x0c, 0xf2, 0x22, 0x26, + 0xd8, 0xa3, 0xc9, 0x14, 0x4c, 0x8f, 0x05, 0xa4, 0x45, 0xe8, 0x14, 0x0c, + 0x58, 0x90, 0x05, 0x1a, 0xb7, 0xc5, 0xc1, 0x06, 0xa5, 0x80, 0xaf, 0xbb, + 0x1d, 0x49, 0x6b, 0x52, 0x34, 0x88, 0xc3, 0x59, 0xe7, 0xef, 0x6b, 0xc4, + 0x27, 0x41, 0x8c, 0x2b, 0x66, 0x1d, 0xd0, 0xe0, 0xa3, 0x97, 0x98, 0x19, + 0x34, 0x4b, 0x41, 0xd5, 0x98, 0xd5, 0xc7, 0x05, 0xad, 0xa2, 0xe4, 0xd7, + 0xed, 0x0c, 0xad, 0x4f, 0xc1, 0xb5, 0xb0, 0x21, 0xfd, 0x3e, 0x50, 0x53, + 0xb2, 0xc4, 0x90, 0xd0, 0xd4, 0x30, 0x67, 0x6c, 0x9a, 0xf1, 0x0e, 0x74, + 0xc4, 0xc2, 0xdc, 0x8a, 0xe8, 0x97, 0xff, 0xc9, 0x92, 0xae, 0x01, 0x8a, + 0x56, 0x0a, 0x98, 0x32, 0xb0, 0x00, 0x23, 0xec, 0x90, 0x1a, 0x60, 0xc3, + 0xed, 0xbb, 0x3a, 0xcb, 0x0f, 0x63, 0x9f, 0x0d, 0x44, 0xc9, 0x52, 0xe1, + 0x25, 0x96, 0xbf, 0xed, 0x50, 0x95, 0x89, 0x7f, 0x56, 0x14, 0xb1, 0xb7, + 0x61, 0x1d, 0x1c, 0x07, 0x8c, 0x3a, 0x2c, 0xf7, 0xff, 0x80, 0xde, 0x39, + 0x45, 0xd5, 0xaf, 0x1a, 0xd1, 0x78, 0xd8, 0xc7, 0x71, 0x6a, 0xa3, 0x19, + 0xa7, 0x32, 0x50, 0x21, 0xe9, 0xf2, 0x0e, 0xa1, 0xc6, 0x13, 0x03, 0x44, + 0x48, 0xd1, 0x66, 0xa8, 0x52, 0x57, 0xd7, 0x11, 0xb4, 0x93, 0x8b, 0xe5, + 0x99, 0x9f, 0x5d, 0xe7, 0x78, 0x51, 0xe5, 0x4d, 0xf6, 0xb7, 0x59, 0xb4, + 0x76, 0xb5, 0x09, 0x37, 0x4d, 0x06, 0x38, 0x13, 0x7a, 0x1c, 0x08, 0x98, + 0x5c, 0xc4, 0x48, 0x4a, 0xcb, 0x52, 0xa0, 0xa9, 0xf8, 0xb1, 0x9d, 0x8e, + 0x7b, 0x79, 0xb0, 0x20, 0x2f, 0x3c, 0x96, 0xa8, 0x11, 0x62, 0x47, 0xbb, + 0x11, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xfb, 0x30, 0x81, 0xf8, + 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2d, 0x30, 0x2b, 0x30, + 0x29, 0xa0, 0x27, 0xa0, 0x25, 0x86, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, + 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x28, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x21, 0x30, 0x1f, 0xa4, 0x1d, 0x30, + 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, + 0x2d, 0x32, 0x2d, 0x39, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0xa7, 0xa2, 0x83, 0xbb, 0x34, 0x45, 0x40, 0x3d, 0xfc, + 0xd5, 0x30, 0x4f, 0x12, 0xb9, 0x3e, 0xa1, 0x01, 0x9f, 0xf6, 0xdb, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x7b, 0x5b, 0x45, 0xcf, 0xaf, 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, + 0x6a, 0xb6, 0xf3, 0x46, 0xeb, 0x57, 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x80, 0x22, 0x80, 0xe0, 0x6c, 0xc8, 0x95, 0x16, + 0xd7, 0x57, 0x26, 0x87, 0xf3, 0x72, 0x34, 0xdb, 0xc6, 0x72, 0x56, 0x27, + 0x3e, 0xd3, 0x96, 0xf6, 0x2e, 0x25, 0x91, 0xa5, 0x3e, 0x33, 0x97, 0xa7, + 0x4b, 0xe5, 0x2f, 0xfb, 0x25, 0x7d, 0x2f, 0x07, 0x61, 0xfa, 0x6f, 0x83, + 0x74, 0x4c, 0x4c, 0x53, 0x72, 0x20, 0xa4, 0x7a, 0xcf, 0x51, 0x51, 0x56, + 0x81, 0x88, 0xb0, 0x6d, 0x1f, 0x36, 0x2c, 0xc8, 0x2b, 0xb1, 0x88, 0x99, + 0xc1, 0xfe, 0x44, 0xab, 0x48, 0x51, 0x7c, 0xd8, 0xf2, 0x44, 0x64, 0x2a, + 0xd8, 0x71, 0xa7, 0xfb, 0x1a, 0x2f, 0xf9, 0x19, 0x8d, 0x34, 0xb2, 0x23, + 0xbf, 0xc4, 0x4c, 0x55, 0x1d, 0x8e, 0x44, 0xe8, 0xaa, 0x5d, 0x9a, 0xdd, + 0x9f, 0xfd, 0x03, 0xc7, 0xba, 0x24, 0x43, 0x8d, 0x2d, 0x47, 0x44, 0xdb, + 0xf6, 0xd8, 0x98, 0xc8, 0xb2, 0xf9, 0xda, 0xef, 0xed, 0x29, 0x5c, 0x69, + 0x12, 0xfa, 0xd1, 0x23, 0x96, 0x0f, 0xbf, 0x9c, 0x0d, 0xf2, 0x79, 0x45, + 0x53, 0x37, 0x9a, 0x56, 0x2f, 0xe8, 0x57, 0x10, 0x70, 0xf6, 0xee, 0x89, + 0x0c, 0x49, 0x89, 0x9a, 0xc1, 0x23, 0xf5, 0xc2, 0x2a, 0xcc, 0x41, 0xcf, + 0x22, 0xab, 0x65, 0x6e, 0xb7, 0x94, 0x82, 0x6d, 0x2f, 0x40, 0x5f, 0x58, + 0xde, 0xeb, 0x95, 0x2b, 0xa6, 0x72, 0x68, 0x52, 0x19, 0x91, 0x2a, 0xae, + 0x75, 0x9d, 0x4e, 0x92, 0xe6, 0xca, 0xde, 0x54, 0xea, 0x18, 0xab, 0x25, + 0x3c, 0xe6, 0x64, 0xa6, 0x79, 0x1f, 0x26, 0x7d, 0x61, 0xed, 0x7d, 0xd2, + 0xe5, 0x71, 0x55, 0xd8, 0x93, 0x17, 0x7c, 0x14, 0x38, 0x30, 0x3c, 0xdf, + 0x86, 0xe3, 0x4c, 0xad, 0x49, 0xe3, 0x97, 0x59, 0xce, 0x1b, 0x9b, 0x2b, + 0xce, 0xdc, 0x65, 0xd4, 0x0b, 0x28, 0x6b, 0x4e, 0x84, 0x46, 0x51, 0x44, + 0xf7, 0x33, 0x08, 0x2d, 0x58, 0x97, 0x21, 0xae, +} + +var certSet2Cert17 = []byte{ + 0x30, 0x82, 0x04, 0x6e, 0x30, 0x82, 0x03, 0x56, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x6e, 0x8a, 0x90, 0xeb, 0xcf, 0xf0, 0x44, 0x8a, 0x72, + 0x0d, 0x08, 0x05, 0xd0, 0x82, 0xa5, 0x44, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x58, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, + 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, + 0x33, 0x31, 0x30, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, + 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x17, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, + 0x56, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, + 0x34, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, + 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd9, 0xb4, + 0x05, 0xf2, 0x38, 0x67, 0x0f, 0x09, 0xe7, 0x7c, 0xf5, 0x63, 0x2a, 0xe5, + 0xb9, 0x5e, 0xa8, 0x11, 0xae, 0x75, 0x71, 0xd9, 0x4c, 0x84, 0x67, 0xad, + 0x89, 0x5d, 0xfc, 0x28, 0x3d, 0x2a, 0xb0, 0xa5, 0xd5, 0xd4, 0xe6, 0x30, + 0x0a, 0x84, 0xd4, 0xe4, 0x18, 0xcb, 0x85, 0x37, 0xc5, 0x46, 0x71, 0xeb, + 0x1c, 0x7b, 0x69, 0xdb, 0x65, 0x69, 0x8c, 0x30, 0x05, 0x3e, 0x07, 0xe1, + 0x6f, 0x3c, 0xc1, 0x0b, 0x61, 0xe6, 0x38, 0x44, 0xfc, 0xbc, 0x8c, 0x2f, + 0x4e, 0x75, 0x57, 0xf5, 0x96, 0x99, 0x7c, 0x3e, 0x87, 0x1f, 0x0f, 0x90, + 0x4b, 0x70, 0xc3, 0x3f, 0x39, 0x45, 0x3b, 0x3a, 0x6b, 0xcb, 0xbb, 0x7b, + 0x40, 0x54, 0xd1, 0x8b, 0x4b, 0xa1, 0x72, 0xd2, 0x04, 0xe9, 0xe0, 0x72, + 0x1a, 0x93, 0x11, 0x7a, 0x2f, 0xf1, 0xab, 0x9d, 0x9c, 0x98, 0x58, 0xae, + 0x2c, 0xea, 0x77, 0x5f, 0x2f, 0x2e, 0x87, 0xaf, 0xb8, 0x6b, 0xe3, 0xe2, + 0xe2, 0x3f, 0xd6, 0x3d, 0xe0, 0x96, 0x44, 0xdf, 0x11, 0x55, 0x63, 0x52, + 0x2f, 0xf4, 0x26, 0x78, 0xc4, 0x0f, 0x20, 0x4d, 0x0a, 0xc0, 0x68, 0x70, + 0x15, 0x86, 0x38, 0xee, 0xb7, 0x76, 0x88, 0xab, 0x18, 0x8f, 0x4f, 0x35, + 0x1e, 0xd4, 0x8c, 0xc9, 0xdb, 0x7e, 0x3d, 0x44, 0xd4, 0x36, 0x8c, 0xc1, + 0x37, 0xb5, 0x59, 0x5b, 0x87, 0xf9, 0xe9, 0xf1, 0xd4, 0xc5, 0x28, 0xbd, + 0x1d, 0xdc, 0xcc, 0x96, 0x72, 0xd1, 0x7a, 0xa1, 0xa7, 0x20, 0xb5, 0xb8, + 0xaf, 0xf8, 0x6e, 0xa5, 0x60, 0x7b, 0x2b, 0x8d, 0x1f, 0xee, 0xf4, 0x2b, + 0xd6, 0x69, 0xcd, 0xaf, 0xca, 0x80, 0x58, 0x29, 0xe8, 0x4c, 0x00, 0x20, + 0x8a, 0x49, 0x0a, 0x6e, 0x8e, 0x8c, 0xa8, 0xd1, 0x00, 0x12, 0x84, 0xb6, + 0xc5, 0xe2, 0x95, 0xa2, 0xc0, 0x3b, 0xa4, 0x6b, 0xf0, 0x82, 0xd0, 0x96, + 0x5d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x43, 0x30, + 0x82, 0x01, 0x3f, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x47, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x40, 0x30, 0x3e, 0x30, 0x3c, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, + 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2d, 0x30, 0x2b, 0x30, 0x29, 0xa0, 0x27, 0xa0, 0x25, 0x86, 0x23, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x31, 0x2e, 0x73, 0x79, + 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x65, 0x6f, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x50, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x29, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, + 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x11, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, + 0x2d, 0x31, 0x2d, 0x35, 0x33, 0x38, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0xde, 0xcf, 0x5c, 0x50, 0xb7, 0xae, 0x02, + 0x1f, 0x15, 0x17, 0xaa, 0x16, 0xe8, 0x0d, 0xb5, 0x28, 0x9d, 0x6a, 0x5a, + 0xf3, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x2c, 0xd5, 0x50, 0x41, 0x97, 0x15, 0x8b, 0xf0, 0x8f, 0x36, + 0x61, 0x5b, 0x4a, 0xfb, 0x6b, 0xd9, 0x99, 0xc9, 0x33, 0x92, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xb4, 0x8e, 0xbd, 0x07, 0xb9, 0x9a, + 0x85, 0xec, 0x3b, 0x67, 0xbd, 0x07, 0x60, 0x61, 0xe6, 0x84, 0xd1, 0xd4, + 0xef, 0xeb, 0x1b, 0xba, 0x0b, 0x82, 0x4b, 0x95, 0x64, 0xb6, 0x66, 0x53, + 0x23, 0xbd, 0xb7, 0x84, 0xdd, 0xe4, 0x7b, 0x8d, 0x09, 0xda, 0xcf, 0xb2, + 0xf5, 0xf1, 0xc3, 0xbf, 0x87, 0x84, 0xbe, 0x4e, 0xa6, 0xa8, 0xc2, 0xe7, + 0x12, 0x39, 0x28, 0x34, 0xe0, 0xa4, 0x56, 0x44, 0x40, 0x0c, 0x9f, 0x88, + 0xa3, 0x15, 0xd3, 0xe8, 0xd3, 0x5e, 0xe3, 0x1c, 0x04, 0x60, 0xfb, 0x69, + 0x36, 0x4f, 0x6a, 0x7e, 0x0c, 0x2a, 0x28, 0xc1, 0xf3, 0xaa, 0x58, 0x0e, + 0x6c, 0xce, 0x1d, 0x07, 0xc3, 0x4a, 0xc0, 0x9c, 0x8d, 0xc3, 0x74, 0xb1, + 0xae, 0x82, 0xf0, 0x1a, 0xe1, 0xf9, 0x4e, 0x29, 0xbd, 0x46, 0xde, 0xb7, + 0x1d, 0xf9, 0x7d, 0xdb, 0xd9, 0x0f, 0x84, 0xcb, 0x92, 0x45, 0xcc, 0x1c, + 0xb3, 0x18, 0xf6, 0xa0, 0xcf, 0x71, 0x6f, 0x0c, 0x2e, 0x9b, 0xd2, 0x2d, + 0xb3, 0x99, 0x93, 0x83, 0x44, 0xac, 0x15, 0xaa, 0x9b, 0x2e, 0x67, 0xec, + 0x4f, 0x88, 0x69, 0x05, 0x56, 0x7b, 0x8b, 0xb2, 0x43, 0xa9, 0x3a, 0x6c, + 0x1c, 0x13, 0x33, 0x25, 0x1b, 0xfd, 0xa8, 0xc8, 0x57, 0x02, 0xfb, 0x1c, + 0xe0, 0xd1, 0xbd, 0x3b, 0x56, 0x44, 0x65, 0xc3, 0x63, 0xf5, 0x1b, 0xef, + 0xec, 0x30, 0xd9, 0xe3, 0x6e, 0x2e, 0x13, 0xe9, 0x39, 0x08, 0x2a, 0x0c, + 0x72, 0xf3, 0x9a, 0xcc, 0xf6, 0x27, 0x29, 0x84, 0xd3, 0xef, 0x4c, 0xc7, + 0x84, 0x11, 0x65, 0x1f, 0xc6, 0xe3, 0x81, 0x03, 0xdb, 0x87, 0xcc, 0x78, + 0xf7, 0xb5, 0x9d, 0x96, 0x3e, 0x6a, 0x7f, 0xbc, 0x11, 0x85, 0x7a, 0x75, + 0xe6, 0x41, 0x7d, 0x0d, 0xcf, 0xf9, 0xe5, 0x85, 0x69, 0x25, 0x8f, 0xc7, + 0x8d, 0x07, 0x2d, 0xf8, 0x69, 0x0f, 0xcb, 0x41, 0x53, 0x00, +} + +var certSet2Cert18 = []byte{ + 0x30, 0x82, 0x04, 0x7d, 0x30, 0x82, 0x03, 0x65, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x1b, 0xe7, 0x15, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x63, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54, + 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, + 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x47, 0x6f, + 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, + 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x30, 0x31, + 0x30, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, + 0x35, 0x33, 0x30, 0x30, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x81, + 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, + 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, + 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, + 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, 0x47, 0x6f, 0x20, 0x44, + 0x61, 0x64, 0x64, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x71, 0x62, + 0x08, 0xf1, 0xfa, 0x59, 0x34, 0xf7, 0x1b, 0xc9, 0x18, 0xa3, 0xf7, 0x80, + 0x49, 0x58, 0xe9, 0x22, 0x83, 0x13, 0xa6, 0xc5, 0x20, 0x43, 0x01, 0x3b, + 0x84, 0xf1, 0xe6, 0x85, 0x49, 0x9f, 0x27, 0xea, 0xf6, 0x84, 0x1b, 0x4e, + 0xa0, 0xb4, 0xdb, 0x70, 0x98, 0xc7, 0x32, 0x01, 0xb1, 0x05, 0x3e, 0x07, + 0x4e, 0xee, 0xf4, 0xfa, 0x4f, 0x2f, 0x59, 0x30, 0x22, 0xe7, 0xab, 0x19, + 0x56, 0x6b, 0xe2, 0x80, 0x07, 0xfc, 0xf3, 0x16, 0x75, 0x80, 0x39, 0x51, + 0x7b, 0xe5, 0xf9, 0x35, 0xb6, 0x74, 0x4e, 0xa9, 0x8d, 0x82, 0x13, 0xe4, + 0xb6, 0x3f, 0xa9, 0x03, 0x83, 0xfa, 0xa2, 0xbe, 0x8a, 0x15, 0x6a, 0x7f, + 0xde, 0x0b, 0xc3, 0xb6, 0x19, 0x14, 0x05, 0xca, 0xea, 0xc3, 0xa8, 0x04, + 0x94, 0x3b, 0x46, 0x7c, 0x32, 0x0d, 0xf3, 0x00, 0x66, 0x22, 0xc8, 0x8d, + 0x69, 0x6d, 0x36, 0x8c, 0x11, 0x18, 0xb7, 0xd3, 0xb2, 0x1c, 0x60, 0xb4, + 0x38, 0xfa, 0x02, 0x8c, 0xce, 0xd3, 0xdd, 0x46, 0x07, 0xde, 0x0a, 0x3e, + 0xeb, 0x5d, 0x7c, 0xc8, 0x7c, 0xfb, 0xb0, 0x2b, 0x53, 0xa4, 0x92, 0x62, + 0x69, 0x51, 0x25, 0x05, 0x61, 0x1a, 0x44, 0x81, 0x8c, 0x2c, 0xa9, 0x43, + 0x96, 0x23, 0xdf, 0xac, 0x3a, 0x81, 0x9a, 0x0e, 0x29, 0xc5, 0x1c, 0xa9, + 0xe9, 0x5d, 0x1e, 0xb6, 0x9e, 0x9e, 0x30, 0x0a, 0x39, 0xce, 0xf1, 0x88, + 0x80, 0xfb, 0x4b, 0x5d, 0xcc, 0x32, 0xec, 0x85, 0x62, 0x43, 0x25, 0x34, + 0x02, 0x56, 0x27, 0x01, 0x91, 0xb4, 0x3b, 0x70, 0x2a, 0x3f, 0x6e, 0xb1, + 0xe8, 0x9c, 0x88, 0x01, 0x7d, 0x9f, 0xd4, 0xf9, 0xdb, 0x53, 0x6d, 0x60, + 0x9d, 0xbf, 0x2c, 0xe7, 0x58, 0xab, 0xb8, 0x5f, 0x46, 0xfc, 0xce, 0xc4, + 0x1b, 0x03, 0x3c, 0x09, 0xeb, 0x49, 0x31, 0x5c, 0x69, 0x46, 0xb3, 0xe0, + 0x47, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x17, 0x30, 0x82, + 0x01, 0x13, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3a, 0x9a, + 0x85, 0x07, 0x10, 0x67, 0x28, 0xb6, 0xef, 0xf6, 0xbd, 0x05, 0x41, 0x6e, + 0x20, 0xc1, 0x94, 0xda, 0x0f, 0xde, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd2, 0xc4, 0xb0, 0xd2, 0x91, + 0xd4, 0x4c, 0x11, 0x71, 0xb3, 0x61, 0xcb, 0x3d, 0xa1, 0xfe, 0xdd, 0xa8, + 0x6a, 0xd4, 0xe3, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, + 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x32, 0x06, + 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, 0x30, 0x27, 0xa0, 0x25, + 0xa0, 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x64, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, + 0x6c, 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, + 0x30, 0x3b, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x33, 0x30, 0x31, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, + 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x59, 0x0b, 0x53, + 0xbd, 0x92, 0x86, 0x11, 0xa7, 0x24, 0x7b, 0xed, 0x5b, 0x31, 0xcf, 0x1d, + 0x1f, 0x6c, 0x70, 0xc5, 0xb8, 0x6e, 0xbe, 0x4e, 0xbb, 0xf6, 0xbe, 0x97, + 0x50, 0xe1, 0x30, 0x7f, 0xba, 0x28, 0x5c, 0x62, 0x94, 0xc2, 0xe3, 0x7e, + 0x33, 0xf7, 0xfb, 0x42, 0x76, 0x85, 0xdb, 0x95, 0x1c, 0x8c, 0x22, 0x58, + 0x75, 0x09, 0x0c, 0x88, 0x65, 0x67, 0x39, 0x0a, 0x16, 0x09, 0xc5, 0xa0, + 0x38, 0x97, 0xa4, 0xc5, 0x23, 0x93, 0x3f, 0xb4, 0x18, 0xa6, 0x01, 0x06, + 0x44, 0x91, 0xe3, 0xa7, 0x69, 0x27, 0xb4, 0x5a, 0x25, 0x7f, 0x3a, 0xb7, + 0x32, 0xcd, 0xdd, 0x84, 0xff, 0x2a, 0x38, 0x29, 0x33, 0xa4, 0xdd, 0x67, + 0xb2, 0x85, 0xfe, 0xa1, 0x88, 0x20, 0x1c, 0x50, 0x89, 0xc8, 0xdc, 0x2a, + 0xf6, 0x42, 0x03, 0x37, 0x4c, 0xe6, 0x88, 0xdf, 0xd5, 0xaf, 0x24, 0xf2, + 0xb1, 0xc3, 0xdf, 0xcc, 0xb5, 0xec, 0xe0, 0x99, 0x5e, 0xb7, 0x49, 0x54, + 0x20, 0x3c, 0x94, 0x18, 0x0c, 0xc7, 0x1c, 0x52, 0x18, 0x49, 0xa4, 0x6d, + 0xe1, 0xb3, 0x58, 0x0b, 0xc9, 0xd8, 0xec, 0xd9, 0xae, 0x1c, 0x32, 0x8e, + 0x28, 0x70, 0x0d, 0xe2, 0xfe, 0xa6, 0x17, 0x9e, 0x84, 0x0f, 0xbd, 0x57, + 0x70, 0xb3, 0x5a, 0xe9, 0x1f, 0xa0, 0x86, 0x53, 0xbb, 0xef, 0x7c, 0xff, + 0x69, 0x0b, 0xe0, 0x48, 0xc3, 0xb7, 0x93, 0x0b, 0xc8, 0x0a, 0x54, 0xc4, + 0xac, 0x5d, 0x14, 0x67, 0x37, 0x6c, 0xca, 0xa5, 0x2f, 0x31, 0x08, 0x37, + 0xaa, 0x6e, 0x6f, 0x8c, 0xbc, 0x9b, 0xe2, 0x57, 0x5d, 0x24, 0x81, 0xaf, + 0x97, 0x97, 0x9c, 0x84, 0xad, 0x6c, 0xac, 0x37, 0x4c, 0x66, 0xf3, 0x61, + 0x91, 0x11, 0x20, 0xe4, 0xbe, 0x30, 0x9f, 0x7a, 0xa4, 0x29, 0x09, 0xb0, + 0xe1, 0x34, 0x5f, 0x64, 0x77, 0x18, 0x40, 0x51, 0xdf, 0x8c, 0x30, 0xa6, + 0xaf, +} + +var certSet2Cert19 = []byte{ + 0x30, 0x82, 0x04, 0x8f, 0x30, 0x82, 0x03, 0x77, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x06, 0x9e, 0x1d, 0xb7, 0x7f, 0xcf, 0x1d, 0xfb, 0xa9, + 0x7a, 0xf5, 0xe5, 0xc9, 0xa2, 0x40, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x61, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x30, 0x38, 0x31, + 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x33, + 0x30, 0x38, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x48, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, + 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, + 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbb, 0x57, 0xe4, 0x21, + 0xa9, 0xd5, 0x9b, 0x60, 0x37, 0x7e, 0x8e, 0xa1, 0x61, 0x7f, 0x81, 0xe2, + 0x1a, 0xc2, 0x75, 0x64, 0xd9, 0x91, 0x50, 0x0b, 0xe4, 0x36, 0x44, 0x24, + 0x6e, 0x30, 0xd2, 0x9b, 0x7a, 0x27, 0xfa, 0xc2, 0x6a, 0xae, 0x6a, 0x70, + 0x09, 0x38, 0xb9, 0x20, 0x0a, 0xc8, 0x65, 0x10, 0x4a, 0x88, 0xac, 0x31, + 0xf2, 0xdc, 0x92, 0xf2, 0x63, 0xa1, 0x5d, 0x80, 0x63, 0x59, 0x80, 0x92, + 0x23, 0x1c, 0xe6, 0xef, 0x76, 0x4a, 0x50, 0x35, 0xc9, 0xd8, 0x71, 0x38, + 0xb9, 0xed, 0xf0, 0xe6, 0x42, 0xae, 0xd3, 0x38, 0x26, 0x79, 0x30, 0xf9, + 0x22, 0x94, 0xc6, 0xdb, 0xa6, 0x3f, 0x41, 0x78, 0x90, 0xd8, 0xde, 0x5c, + 0x7e, 0x69, 0x7d, 0xf8, 0x90, 0x15, 0x3a, 0xd0, 0xa1, 0xa0, 0xbe, 0xfa, + 0xb2, 0xb2, 0x19, 0xa1, 0xd8, 0x2b, 0xd1, 0xce, 0xbf, 0x6b, 0xdd, 0x49, + 0xab, 0xa3, 0x92, 0xfe, 0xb5, 0xab, 0xc8, 0xc1, 0x3e, 0xee, 0x01, 0x00, + 0xd8, 0xa9, 0x44, 0xb8, 0x42, 0x73, 0x88, 0xc3, 0x61, 0xf5, 0xab, 0x4a, + 0x83, 0x28, 0x0a, 0xd2, 0xd4, 0x49, 0xfa, 0x6a, 0xb1, 0xcd, 0xdf, 0x57, + 0x2c, 0x94, 0xe5, 0xe2, 0xca, 0x83, 0x5f, 0xb7, 0xba, 0x62, 0x5c, 0x2f, + 0x68, 0xa5, 0xf0, 0xc0, 0xb9, 0xfd, 0x2b, 0xd1, 0xe9, 0x1f, 0xd8, 0x1a, + 0x62, 0x15, 0xbd, 0xff, 0x3d, 0xa6, 0xf7, 0xcb, 0xef, 0xe6, 0xdb, 0x65, + 0x2f, 0x25, 0x38, 0xec, 0xfb, 0xe6, 0x20, 0x66, 0x58, 0x96, 0x34, 0x19, + 0xd2, 0x15, 0xce, 0x21, 0xd3, 0x24, 0xcc, 0xd9, 0x14, 0x6f, 0xd8, 0xfe, + 0x55, 0xc7, 0xe7, 0x6f, 0xb6, 0x0f, 0x1a, 0x8c, 0x49, 0xbe, 0x29, 0xf2, + 0xba, 0x5a, 0x9a, 0x81, 0x26, 0x37, 0x24, 0x6f, 0xd7, 0x48, 0x12, 0x6c, + 0x2e, 0x59, 0xf5, 0x9c, 0x18, 0xbb, 0xd9, 0xf6, 0x68, 0xe2, 0xdf, 0x45, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x5a, 0x30, 0x82, 0x01, + 0x56, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x86, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x7b, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33, + 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x34, 0x2e, 0x64, + 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, + 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x64, + 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0x90, 0x71, 0xdb, 0x37, 0xeb, 0x73, 0xc8, 0xef, 0xdc, 0xd5, + 0x1e, 0x12, 0xb6, 0x34, 0xba, 0x2b, 0x5a, 0xa0, 0xa6, 0x92, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x03, + 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0, 0xa3, 0xe2, 0x1b, + 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x01, 0x00, 0x30, 0xce, 0xd1, 0x95, 0x51, 0x00, 0xae, 0x06, 0x0b, + 0xa1, 0x0e, 0x02, 0xc0, 0x17, 0xac, 0xb6, 0x7f, 0x8f, 0x20, 0xf6, 0x40, + 0x75, 0x74, 0x1c, 0xcc, 0x78, 0xb1, 0xa4, 0x4f, 0xea, 0xf4, 0xd0, 0xc4, + 0x9d, 0xa2, 0xde, 0x81, 0x07, 0x26, 0x1f, 0x40, 0x88, 0x51, 0xf0, 0x1f, + 0xcf, 0xb7, 0x4c, 0x40, 0x99, 0xd0, 0xf4, 0x3c, 0x71, 0x98, 0x73, 0x88, + 0x97, 0x2c, 0x19, 0xd7, 0x6e, 0x84, 0x8f, 0xa4, 0x1f, 0x9c, 0x5a, 0x20, + 0xe3, 0x51, 0x5c, 0xb0, 0xc5, 0x9e, 0x99, 0x6a, 0x4f, 0xc8, 0x69, 0xf7, + 0x10, 0xff, 0x4e, 0xad, 0x19, 0xd9, 0xc9, 0x58, 0xb3, 0x33, 0xae, 0x0c, + 0xd9, 0x96, 0x29, 0x9e, 0x71, 0xb2, 0x70, 0x63, 0xa3, 0xb6, 0x99, 0x16, + 0x42, 0x1d, 0x65, 0xf3, 0xf7, 0xa0, 0x1e, 0x7d, 0xc5, 0xd4, 0x65, 0x14, + 0xb2, 0x62, 0x84, 0xd4, 0x6c, 0x5c, 0x08, 0x0c, 0xd8, 0x6c, 0x93, 0x2b, + 0xb4, 0x76, 0x59, 0x8a, 0xd1, 0x7f, 0xff, 0x03, 0xd8, 0xc2, 0x5d, 0xb8, + 0x2f, 0x22, 0xd6, 0x38, 0xf0, 0xf6, 0x9c, 0x6b, 0x7d, 0x46, 0xeb, 0x99, + 0x74, 0xf7, 0xeb, 0x4a, 0x0e, 0xa9, 0xa6, 0x04, 0xeb, 0x7b, 0xce, 0xf0, + 0x5c, 0x6b, 0x98, 0x31, 0x5a, 0x98, 0x40, 0xeb, 0x69, 0xc4, 0x05, 0xf4, + 0x20, 0xa8, 0xca, 0x08, 0x3a, 0x65, 0x6c, 0x38, 0x15, 0xf5, 0x5c, 0x2c, + 0xb2, 0x55, 0xe4, 0x2c, 0x6b, 0x41, 0xf0, 0xbe, 0x5c, 0x46, 0xca, 0x4a, + 0x29, 0xa0, 0x48, 0x5e, 0x20, 0xd2, 0x45, 0xff, 0x05, 0xde, 0x34, 0xaf, + 0x70, 0x4b, 0x81, 0x39, 0xe2, 0xca, 0x07, 0x57, 0x7c, 0xb6, 0x31, 0xdc, + 0x21, 0x29, 0xe2, 0xbe, 0x97, 0x0e, 0x77, 0x90, 0x14, 0x51, 0x40, 0xe1, + 0xbf, 0xe3, 0xcc, 0x1b, 0x19, 0x9c, 0x25, 0xca, 0xa7, 0x06, 0xb2, 0x53, + 0xdf, 0x23, 0xb2, 0xcf, 0x12, 0x19, 0xa3, +} + +var certSet2Cert20 = []byte{ + 0x30, 0x82, 0x04, 0x90, 0x30, 0x82, 0x03, 0xf9, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x1b, 0x09, 0x3b, 0x78, 0x60, 0x96, 0xda, 0x37, 0xbb, + 0xa4, 0x51, 0x94, 0x46, 0xc8, 0x96, 0x78, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xca, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3a, 0x30, + 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, 0x63, 0x29, 0x20, + 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, + 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, + 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x45, 0x30, + 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, 0x24, 0x08, 0x08, 0x29, 0x7a, 0x35, + 0x9e, 0x60, 0x0c, 0xaa, 0xe7, 0x4b, 0x3b, 0x4e, 0xdc, 0x7c, 0xbc, 0x3c, + 0x45, 0x1c, 0xbb, 0x2b, 0xe0, 0xfe, 0x29, 0x02, 0xf9, 0x57, 0x08, 0xa3, + 0x64, 0x85, 0x15, 0x27, 0xf5, 0xf1, 0xad, 0xc8, 0x31, 0x89, 0x5d, 0x22, + 0xe8, 0x2a, 0xaa, 0xa6, 0x42, 0xb3, 0x8f, 0xf8, 0xb9, 0x55, 0xb7, 0xb1, + 0xb7, 0x4b, 0xb3, 0xfe, 0x8f, 0x7e, 0x07, 0x57, 0xec, 0xef, 0x43, 0xdb, + 0x66, 0x62, 0x15, 0x61, 0xcf, 0x60, 0x0d, 0xa4, 0xd8, 0xde, 0xf8, 0xe0, + 0xc3, 0x62, 0x08, 0x3d, 0x54, 0x13, 0xeb, 0x49, 0xca, 0x59, 0x54, 0x85, + 0x26, 0xe5, 0x2b, 0x8f, 0x1b, 0x9f, 0xeb, 0xf5, 0xa1, 0x91, 0xc2, 0x33, + 0x49, 0xd8, 0x43, 0x63, 0x6a, 0x52, 0x4b, 0xd2, 0x8f, 0xe8, 0x70, 0x51, + 0x4d, 0xd1, 0x89, 0x69, 0x7b, 0xc7, 0x70, 0xf6, 0xb3, 0xdc, 0x12, 0x74, + 0xdb, 0x7b, 0x5d, 0x4b, 0x56, 0xd3, 0x96, 0xbf, 0x15, 0x77, 0xa1, 0xb0, + 0xf4, 0xa2, 0x25, 0xf2, 0xaf, 0x1c, 0x92, 0x67, 0x18, 0xe5, 0xf4, 0x06, + 0x04, 0xef, 0x90, 0xb9, 0xe4, 0x00, 0xe4, 0xdd, 0x3a, 0xb5, 0x19, 0xff, + 0x02, 0xba, 0xf4, 0x3c, 0xee, 0xe0, 0x8b, 0xeb, 0x37, 0x8b, 0xec, 0xf4, + 0xd7, 0xac, 0xf2, 0xf6, 0xf0, 0x3d, 0xaf, 0xdd, 0x75, 0x91, 0x33, 0x19, + 0x1d, 0x1c, 0x40, 0xcb, 0x74, 0x24, 0x19, 0x21, 0x93, 0xd9, 0x14, 0xfe, + 0xac, 0x2a, 0x52, 0xc7, 0x8f, 0xd5, 0x04, 0x49, 0xe4, 0x8d, 0x63, 0x47, + 0x88, 0x3c, 0x69, 0x83, 0xcb, 0xfe, 0x47, 0xbd, 0x2b, 0x7e, 0x4f, 0xc5, + 0x95, 0xae, 0x0e, 0x9d, 0xd4, 0xd1, 0x43, 0xc0, 0x67, 0x73, 0xe3, 0x14, + 0x08, 0x7e, 0xe5, 0x3f, 0x9f, 0x73, 0xb8, 0x33, 0x0a, 0xcf, 0x5d, 0x3f, + 0x34, 0x87, 0x96, 0x8a, 0xee, 0x53, 0xe8, 0x25, 0x15, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x5b, 0x30, 0x82, 0x01, 0x57, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, + 0x30, 0x28, 0x30, 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, + 0x61, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, + 0x73, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x6d, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, + 0xa1, 0x5d, 0xa0, 0x5b, 0x30, 0x59, 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, + 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, + 0x8f, 0xe5, 0xd3, 0x1a, 0x86, 0xac, 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, + 0x6a, 0xd4, 0x48, 0x18, 0x2c, 0x7b, 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x76, 0x73, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, + 0xa3, 0xcd, 0x7d, 0x1e, 0xf7, 0xc7, 0x75, 0x8d, 0x48, 0xe7, 0x56, 0x34, + 0x4c, 0x00, 0x90, 0x75, 0xa9, 0x51, 0xa5, 0x56, 0xc1, 0x6d, 0xbc, 0xfe, + 0xf5, 0x53, 0x22, 0xe9, 0x98, 0xa2, 0xac, 0x9a, 0x7e, 0x70, 0x1e, 0xb3, + 0x8e, 0x3b, 0x45, 0xe3, 0x86, 0x95, 0x31, 0xda, 0x6d, 0x4c, 0xfb, 0x34, + 0x50, 0x80, 0x96, 0xcd, 0x24, 0xf2, 0x40, 0xdf, 0x04, 0x3f, 0xe2, 0x65, + 0xce, 0x34, 0x22, 0x61, 0x15, 0xea, 0x66, 0x70, 0x64, 0xd2, 0xf1, 0x6e, + 0xf3, 0xca, 0x18, 0x59, 0x6a, 0x41, 0x46, 0x7e, 0x82, 0xde, 0x19, 0xb0, + 0x70, 0x31, 0x56, 0x69, 0x0d, 0x0c, 0xe6, 0x1d, 0x9d, 0x71, 0x58, 0xdc, + 0xcc, 0xde, 0x62, 0xf5, 0xe1, 0x7a, 0x10, 0x02, 0xd8, 0x7a, 0xdc, 0x3b, + 0xfa, 0x57, 0xbd, 0xc9, 0xe9, 0x8f, 0x46, 0x21, 0x39, 0x9f, 0x51, 0x65, + 0x4c, 0x8e, 0x3a, 0xbe, 0x28, 0x41, 0x70, 0x1d, +} + +var certSet2Cert21 = []byte{ + 0x30, 0x82, 0x04, 0x94, 0x30, 0x82, 0x03, 0x7c, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x01, 0xfd, 0xa3, 0xeb, 0x6e, 0xca, 0x75, 0xc8, 0x88, + 0x43, 0x8b, 0x72, 0x4b, 0xcf, 0xbc, 0x91, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x61, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x30, 0x38, 0x31, + 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x33, + 0x30, 0x38, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4d, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, + 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, + 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x48, 0x41, 0x32, 0x20, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xdc, 0xae, 0x58, 0x90, 0x4d, 0xc1, 0xc4, 0x30, 0x15, 0x90, 0x35, + 0x5b, 0x6e, 0x3c, 0x82, 0x15, 0xf5, 0x2c, 0x5c, 0xbd, 0xe3, 0xdb, 0xff, + 0x71, 0x43, 0xfa, 0x64, 0x25, 0x80, 0xd4, 0xee, 0x18, 0xa2, 0x4d, 0xf0, + 0x66, 0xd0, 0x0a, 0x73, 0x6e, 0x11, 0x98, 0x36, 0x17, 0x64, 0xaf, 0x37, + 0x9d, 0xfd, 0xfa, 0x41, 0x84, 0xaf, 0xc7, 0xaf, 0x8c, 0xfe, 0x1a, 0x73, + 0x4d, 0xcf, 0x33, 0x97, 0x90, 0xa2, 0x96, 0x87, 0x53, 0x83, 0x2b, 0xb9, + 0xa6, 0x75, 0x48, 0x2d, 0x1d, 0x56, 0x37, 0x7b, 0xda, 0x31, 0x32, 0x1a, + 0xd7, 0xac, 0xab, 0x06, 0xf4, 0xaa, 0x5d, 0x4b, 0xb7, 0x47, 0x46, 0xdd, + 0x2a, 0x93, 0xc3, 0x90, 0x2e, 0x79, 0x80, 0x80, 0xef, 0x13, 0x04, 0x6a, + 0x14, 0x3b, 0xb5, 0x9b, 0x92, 0xbe, 0xc2, 0x07, 0x65, 0x4e, 0xfc, 0xda, + 0xfc, 0xff, 0x7a, 0xae, 0xdc, 0x5c, 0x7e, 0x55, 0x31, 0x0c, 0xe8, 0x39, + 0x07, 0xa4, 0xd7, 0xbe, 0x2f, 0xd3, 0x0b, 0x6a, 0xd2, 0xb1, 0xdf, 0x5f, + 0xfe, 0x57, 0x74, 0x53, 0x3b, 0x35, 0x80, 0xdd, 0xae, 0x8e, 0x44, 0x98, + 0xb3, 0x9f, 0x0e, 0xd3, 0xda, 0xe0, 0xd7, 0xf4, 0x6b, 0x29, 0xab, 0x44, + 0xa7, 0x4b, 0x58, 0x84, 0x6d, 0x92, 0x4b, 0x81, 0xc3, 0xda, 0x73, 0x8b, + 0x12, 0x97, 0x48, 0x90, 0x04, 0x45, 0x75, 0x1a, 0xdd, 0x37, 0x31, 0x97, + 0x92, 0xe8, 0xcd, 0x54, 0x0d, 0x3b, 0xe4, 0xc1, 0x3f, 0x39, 0x5e, 0x2e, + 0xb8, 0xf3, 0x5c, 0x7e, 0x10, 0x8e, 0x86, 0x41, 0x00, 0x8d, 0x45, 0x66, + 0x47, 0xb0, 0xa1, 0x65, 0xce, 0xa0, 0xaa, 0x29, 0x09, 0x4e, 0xf3, 0x97, + 0xeb, 0xe8, 0x2e, 0xab, 0x0f, 0x72, 0xa7, 0x30, 0x0e, 0xfa, 0xc7, 0xf4, + 0xfd, 0x14, 0x77, 0xc3, 0xa4, 0x5b, 0x28, 0x57, 0xc2, 0xb3, 0xf9, 0x82, + 0xfd, 0xb7, 0x45, 0x58, 0x9b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x5a, 0x30, 0x82, 0x01, 0x56, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, + 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x7b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, + 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, + 0x43, 0x65, 0x72, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, + 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x37, 0xa0, 0x35, + 0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, + 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43, + 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, + 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, + 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x0f, 0x80, 0x61, 0x1c, 0x82, + 0x31, 0x61, 0xd5, 0x2f, 0x28, 0xe7, 0x8d, 0x46, 0x38, 0xb4, 0x2c, 0xe1, + 0xc6, 0xd9, 0xe2, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, + 0x30, 0x16, 0x80, 0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, + 0x66, 0xf0, 0xa3, 0xe2, 0x1b, 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x23, 0x3e, 0xdf, 0x4b, + 0xd2, 0x31, 0x42, 0xa5, 0xb6, 0x7e, 0x42, 0x5c, 0x1a, 0x44, 0xcc, 0x69, + 0xd1, 0x68, 0xb4, 0x5d, 0x4b, 0xe0, 0x04, 0x21, 0x6c, 0x4b, 0xe2, 0x6d, + 0xcc, 0xb1, 0xe0, 0x97, 0x8f, 0xa6, 0x53, 0x09, 0xcd, 0xaa, 0x2a, 0x65, + 0xe5, 0x39, 0x4f, 0x1e, 0x83, 0xa5, 0x6e, 0x5c, 0x98, 0xa2, 0x24, 0x26, + 0xe6, 0xfb, 0xa1, 0xed, 0x93, 0xc7, 0x2e, 0x02, 0xc6, 0x4d, 0x4a, 0xbf, + 0xb0, 0x42, 0xdf, 0x78, 0xda, 0xb3, 0xa8, 0xf9, 0x6d, 0xff, 0x21, 0x85, + 0x53, 0x36, 0x60, 0x4c, 0x76, 0xce, 0xec, 0x38, 0xdc, 0xd6, 0x51, 0x80, + 0xf0, 0xc5, 0xd6, 0xe5, 0xd4, 0x4d, 0x27, 0x64, 0xab, 0x9b, 0xc7, 0x3e, + 0x71, 0xfb, 0x48, 0x97, 0xb8, 0x33, 0x6d, 0xc9, 0x13, 0x07, 0xee, 0x96, + 0xa2, 0x1b, 0x18, 0x15, 0xf6, 0x5c, 0x4c, 0x40, 0xed, 0xb3, 0xc2, 0xec, + 0xff, 0x71, 0xc1, 0xe3, 0x47, 0xff, 0xd4, 0xb9, 0x00, 0xb4, 0x37, 0x42, + 0xda, 0x20, 0xc9, 0xea, 0x6e, 0x8a, 0xee, 0x14, 0x06, 0xae, 0x7d, 0xa2, + 0x59, 0x98, 0x88, 0xa8, 0x1b, 0x6f, 0x2d, 0xf4, 0xf2, 0xc9, 0x14, 0x5f, + 0x26, 0xcf, 0x2c, 0x8d, 0x7e, 0xed, 0x37, 0xc0, 0xa9, 0xd5, 0x39, 0xb9, + 0x82, 0xbf, 0x19, 0x0c, 0xea, 0x34, 0xaf, 0x00, 0x21, 0x68, 0xf8, 0xad, + 0x73, 0xe2, 0xc9, 0x32, 0xda, 0x38, 0x25, 0x0b, 0x55, 0xd3, 0x9a, 0x1d, + 0xf0, 0x68, 0x86, 0xed, 0x2e, 0x41, 0x34, 0xef, 0x7c, 0xa5, 0x50, 0x1d, + 0xbf, 0x3a, 0xf9, 0xd3, 0xc1, 0x08, 0x0c, 0xe6, 0xed, 0x1e, 0x8a, 0x58, + 0x25, 0xe4, 0xb8, 0x77, 0xad, 0x2d, 0x6e, 0xf5, 0x52, 0xdd, 0xb4, 0x74, + 0x8f, 0xab, 0x49, 0x2e, 0x9d, 0x3b, 0x93, 0x34, 0x28, 0x1f, 0x78, 0xce, + 0x94, 0xea, 0xc7, 0xbd, 0xd3, 0xc9, 0x6d, 0x1c, 0xde, 0x5c, 0x32, 0xf3, +} + +var certSet2Cert22 = []byte{ + 0x30, 0x82, 0x04, 0x9a, 0x30, 0x82, 0x03, 0x82, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x0b, 0x1d, 0xb1, 0xa9, 0x19, 0xf2, 0x4c, 0x3c, 0x4e, + 0xfc, 0xb5, 0x7a, 0x6a, 0x4e, 0x6c, 0xbf, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x58, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x38, + 0x32, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, + 0x32, 0x30, 0x38, 0x32, 0x32, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, + 0x30, 0x58, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x28, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0x9e, 0xc6, 0x21, 0xcd, 0x2e, 0x3d, 0xd0, 0xbb, 0x2a, + 0x4d, 0xa4, 0x7b, 0x1f, 0xa8, 0x1a, 0xc2, 0x03, 0xa6, 0xff, 0x43, 0x62, + 0x5b, 0xbf, 0x91, 0xd1, 0x66, 0x52, 0xa9, 0x81, 0x90, 0x68, 0x31, 0x86, + 0x16, 0xbb, 0x1d, 0x85, 0x58, 0xa9, 0x7e, 0x91, 0x6a, 0x1e, 0x4c, 0x31, + 0xca, 0x21, 0xc4, 0xbe, 0x70, 0x1b, 0x9f, 0x8c, 0xe4, 0x05, 0x2d, 0x9c, + 0xed, 0x11, 0x79, 0xad, 0x8f, 0x9c, 0x25, 0x86, 0x4c, 0xba, 0xf2, 0xe5, + 0x62, 0x79, 0x8e, 0x22, 0x5f, 0x85, 0x7c, 0x22, 0x35, 0x38, 0x23, 0x8d, + 0x80, 0x3c, 0xac, 0xcc, 0x2d, 0xfc, 0x58, 0xf2, 0x35, 0xbf, 0x66, 0x5b, + 0xeb, 0xc1, 0x24, 0xf8, 0x70, 0x80, 0x74, 0x32, 0xf9, 0x46, 0xde, 0x32, + 0x19, 0x80, 0x8c, 0xb7, 0xe7, 0x1a, 0xa1, 0xaa, 0x64, 0x98, 0x8d, 0xca, + 0xce, 0x0e, 0xdc, 0x6b, 0xf7, 0xe2, 0x90, 0x0a, 0x6c, 0x1c, 0xa5, 0xf4, + 0x90, 0x32, 0x52, 0xe5, 0xf1, 0x00, 0x42, 0x31, 0x91, 0x48, 0x42, 0x89, + 0xa8, 0x5d, 0x7f, 0x63, 0x8d, 0x31, 0xb2, 0xd6, 0x48, 0x5c, 0x45, 0x45, + 0x22, 0xc9, 0xc5, 0x59, 0x12, 0xab, 0x41, 0x94, 0xea, 0xfe, 0x9c, 0x46, + 0x4d, 0x9a, 0xbc, 0x9c, 0xe0, 0xe2, 0xc6, 0x46, 0xb3, 0xe6, 0x7f, 0xdc, + 0xf5, 0x0f, 0xa3, 0x13, 0x45, 0x86, 0x6d, 0x79, 0x78, 0xfc, 0xe1, 0x50, + 0xcf, 0x09, 0x86, 0xe5, 0x9f, 0xbf, 0xcb, 0x3a, 0xd4, 0xe0, 0xb1, 0xd4, + 0xff, 0xa8, 0x3f, 0x7d, 0x62, 0x1f, 0xc0, 0x6d, 0x78, 0x48, 0xc3, 0xd7, + 0xa3, 0xa5, 0x23, 0x61, 0xc5, 0x3e, 0x35, 0x4d, 0xb2, 0xe5, 0xf8, 0xfd, + 0x94, 0x4b, 0xbc, 0x73, 0x53, 0xaf, 0xe3, 0x9a, 0x69, 0x55, 0xbe, 0xcb, + 0x67, 0xab, 0xe1, 0xbe, 0xef, 0x1b, 0xc2, 0x4d, 0xac, 0xcb, 0x29, 0x5c, + 0xbc, 0xed, 0xb8, 0x62, 0x9d, 0x10, 0xe9, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x5e, 0x30, 0x82, 0x01, 0x5a, 0x30, 0x3d, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x31, 0x30, 0x2f, + 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x45, 0x56, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, + 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x46, 0x06, 0x03, 0x55, + 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x04, 0x55, 0x1d, + 0x20, 0x00, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x41, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x3a, 0x30, 0x38, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32, + 0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x45, 0x56, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x65, + 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x50, 0x43, 0x41, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x1d, + 0x11, 0x04, 0x23, 0x30, 0x21, 0xa4, 0x1f, 0x30, 0x1d, 0x31, 0x1b, 0x30, + 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, 0x2d, 0x32, 0x2d, 0x32, + 0x35, 0x33, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x6f, 0x26, 0x56, 0xd9, 0x5c, 0xe7, 0xf7, 0xc9, 0x04, 0x20, 0xf8, + 0x1e, 0xba, 0x7c, 0x91, 0x27, 0x2f, 0x8c, 0xfa, 0x07, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x2c, 0xd5, + 0x50, 0x41, 0x97, 0x15, 0x8b, 0xf0, 0x8f, 0x36, 0x61, 0x5b, 0x4a, 0xfb, + 0x6b, 0xd9, 0x99, 0xc9, 0x33, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x92, 0x77, 0xe9, 0x57, 0xc9, 0xeb, 0xc4, 0x45, 0x6f, 0xc9, + 0x4c, 0x6e, 0x7d, 0x00, 0x12, 0x71, 0xa5, 0xe3, 0x39, 0xfe, 0x13, 0x84, + 0x49, 0x6c, 0xe7, 0x49, 0x71, 0xf5, 0x2c, 0xc7, 0xc0, 0x36, 0xc2, 0x08, + 0x58, 0xf3, 0x83, 0x75, 0xc5, 0x72, 0xd8, 0x8d, 0x78, 0xf4, 0x65, 0xea, + 0x8c, 0xd5, 0xe3, 0xa5, 0x0e, 0xa9, 0xad, 0xeb, 0xe3, 0xa1, 0x23, 0xae, + 0x93, 0xb7, 0xd8, 0x75, 0x75, 0x4a, 0x59, 0xcb, 0xf2, 0x9e, 0xdb, 0x40, + 0xbf, 0x4e, 0x89, 0xfe, 0x95, 0x42, 0x29, 0x34, 0x7b, 0xf4, 0xdd, 0x6a, + 0x0d, 0x74, 0x5f, 0xc7, 0x11, 0x13, 0x2e, 0xdd, 0x11, 0x6e, 0xc6, 0xe3, + 0x5b, 0xb3, 0xcf, 0xa6, 0x8d, 0xe5, 0xf7, 0x67, 0x7b, 0xba, 0xb3, 0xb3, + 0x69, 0x70, 0x14, 0xb0, 0xc2, 0x99, 0xb4, 0xd2, 0x76, 0x5b, 0x38, 0x17, + 0x39, 0x45, 0x1b, 0x82, 0xf1, 0x53, 0xb8, 0x3d, 0x55, 0x39, 0x0b, 0x7f, + 0xff, 0x98, 0xad, 0x6e, 0x96, 0x9a, 0xb6, 0x6a, 0x4c, 0x7a, 0x5e, 0xbd, + 0xb1, 0x86, 0x12, 0x9d, 0x7c, 0x2c, 0x62, 0xbb, 0x09, 0x93, 0x5f, 0x3f, + 0xd8, 0xb5, 0x8a, 0xc3, 0x49, 0x28, 0x0f, 0x0b, 0xf9, 0x39, 0x22, 0x1a, + 0xfe, 0x5d, 0xd3, 0xe8, 0x18, 0x5f, 0x9d, 0x5f, 0xb4, 0xc0, 0x20, 0xc6, + 0xa9, 0x49, 0x0d, 0x55, 0x73, 0x6a, 0x09, 0x7a, 0xff, 0xa2, 0x99, 0xbf, + 0xd8, 0xbb, 0x91, 0xdc, 0x30, 0x39, 0xae, 0x28, 0x4b, 0xf6, 0xc5, 0x77, + 0x24, 0xe8, 0xd6, 0xc6, 0xa7, 0xa0, 0x4e, 0xf2, 0xa6, 0x99, 0x75, 0xcd, + 0xdd, 0x57, 0xdd, 0x0a, 0x47, 0x92, 0xcb, 0xbb, 0xb7, 0x48, 0xfa, 0x21, + 0xf0, 0x69, 0x21, 0xff, 0xe5, 0x0c, 0xaa, 0x0c, 0xb1, 0xea, 0xdd, 0x05, + 0x1c, 0x19, 0x8e, 0xd1, 0x2a, 0x79, 0x68, 0x02, 0x5e, 0xcc, 0x38, 0xe6, + 0x29, 0xc4, 0x77, 0xf5, 0x19, 0x1c, +} + +var certSet2Cert23 = []byte{ + 0x30, 0x82, 0x04, 0xa0, 0x30, 0x82, 0x03, 0x88, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x39, 0x14, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x68, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, + 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x34, 0x30, 0x31, 0x30, 0x31, 0x30, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x17, 0x0d, 0x33, 0x31, 0x30, 0x35, 0x33, 0x30, 0x30, 0x37, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x30, 0x81, 0x8f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, + 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, + 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, + 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, + 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, + 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, + 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xbd, 0xed, 0xc1, 0x03, 0xfc, 0xf6, 0x8f, 0xfc, 0x02, 0xb1, + 0x6f, 0x5b, 0x9f, 0x48, 0xd9, 0x9d, 0x79, 0xe2, 0xa2, 0xb7, 0x03, 0x61, + 0x56, 0x18, 0xc3, 0x47, 0xb6, 0xd7, 0xca, 0x3d, 0x35, 0x2e, 0x89, 0x43, + 0xf7, 0xa1, 0x69, 0x9b, 0xde, 0x8a, 0x1a, 0xfd, 0x13, 0x20, 0x9c, 0xb4, + 0x49, 0x77, 0x32, 0x29, 0x56, 0xfd, 0xb9, 0xec, 0x8c, 0xdd, 0x22, 0xfa, + 0x72, 0xdc, 0x27, 0x61, 0x97, 0xee, 0xf6, 0x5a, 0x84, 0xec, 0x6e, 0x19, + 0xb9, 0x89, 0x2c, 0xdc, 0x84, 0x5b, 0xd5, 0x74, 0xfb, 0x6b, 0x5f, 0xc5, + 0x89, 0xa5, 0x10, 0x52, 0x89, 0x46, 0x55, 0xf4, 0xb8, 0x75, 0x1c, 0xe6, + 0x7f, 0xe4, 0x54, 0xae, 0x4b, 0xf8, 0x55, 0x72, 0x57, 0x02, 0x19, 0xf8, + 0x17, 0x71, 0x59, 0xeb, 0x1e, 0x28, 0x07, 0x74, 0xc5, 0x9d, 0x48, 0xbe, + 0x6c, 0xb4, 0xf4, 0xa4, 0xb0, 0xf3, 0x64, 0x37, 0x79, 0x92, 0xc0, 0xec, + 0x46, 0x5e, 0x7f, 0xe1, 0x6d, 0x53, 0x4c, 0x62, 0xaf, 0xcd, 0x1f, 0x0b, + 0x63, 0xbb, 0x3a, 0x9d, 0xfb, 0xfc, 0x79, 0x00, 0x98, 0x61, 0x74, 0xcf, + 0x26, 0x82, 0x40, 0x63, 0xf3, 0xb2, 0x72, 0x6a, 0x19, 0x0d, 0x99, 0xca, + 0xd4, 0x0e, 0x75, 0xcc, 0x37, 0xfb, 0x8b, 0x89, 0xc1, 0x59, 0xf1, 0x62, + 0x7f, 0x5f, 0xb3, 0x5f, 0x65, 0x30, 0xf8, 0xa7, 0xb7, 0x4d, 0x76, 0x5a, + 0x1e, 0x76, 0x5e, 0x34, 0xc0, 0xe8, 0x96, 0x56, 0x99, 0x8a, 0xb3, 0xf0, + 0x7f, 0xa4, 0xcd, 0xbd, 0xdc, 0x32, 0x31, 0x7c, 0x91, 0xcf, 0xe0, 0x5f, + 0x11, 0xf8, 0x6b, 0xaa, 0x49, 0x5c, 0xd1, 0x99, 0x94, 0xd1, 0xa2, 0xe3, + 0x63, 0x5b, 0x09, 0x76, 0xb5, 0x56, 0x62, 0xe1, 0x4b, 0x74, 0x1d, 0x96, + 0xd4, 0x26, 0xd4, 0x08, 0x04, 0x59, 0xd0, 0x98, 0x0e, 0x0e, 0xe6, 0xde, + 0xfc, 0xc3, 0xec, 0x1f, 0x90, 0xf1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x82, 0x01, 0x29, 0x30, 0x82, 0x01, 0x25, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x7c, 0x0c, 0x32, 0x1f, 0xa7, 0xd9, 0x30, 0x7f, 0xc4, + 0x7d, 0x68, 0xa3, 0x62, 0xa8, 0xa1, 0xce, 0xab, 0x07, 0x5b, 0x27, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0xbf, 0x5f, 0xb7, 0xd1, 0xce, 0xdd, 0x1f, 0x86, 0xf4, 0x5b, 0x55, 0xac, + 0xdc, 0xd7, 0x10, 0xc2, 0x0e, 0xa9, 0x88, 0xe7, 0x30, 0x3a, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2e, 0x30, 0x2c, + 0x30, 0x2a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, + 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x38, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0xa0, 0x2b, 0xa0, + 0x29, 0x86, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, + 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x72, 0x6f, + 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, 0x04, 0x55, 0x1d, 0x20, + 0x00, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x63, 0xc1, 0xd9, + 0xdd, 0xb9, 0xff, 0xa9, 0xbd, 0xa6, 0x19, 0xdc, 0xbf, 0x13, 0x3a, 0x11, + 0x38, 0x22, 0x54, 0xb1, 0xac, 0x05, 0x10, 0xfb, 0x7c, 0xb3, 0x96, 0x3f, + 0x31, 0x8b, 0x66, 0xff, 0x88, 0xf3, 0xe1, 0xbf, 0xfb, 0xc7, 0x1f, 0x00, + 0xff, 0x46, 0x6a, 0x8b, 0x61, 0x32, 0xc9, 0x01, 0x51, 0x76, 0xfb, 0x9a, + 0xc6, 0xfa, 0x20, 0x51, 0xc8, 0x46, 0xc4, 0x98, 0xd7, 0x79, 0xa3, 0xe3, + 0x04, 0x72, 0x3f, 0x8b, 0x4d, 0x34, 0x53, 0x67, 0xec, 0x33, 0x2c, 0x7b, + 0xe8, 0x94, 0x01, 0x28, 0x7c, 0x3a, 0x34, 0x5b, 0x02, 0x77, 0x16, 0x8d, + 0x40, 0x25, 0x33, 0xb0, 0xbc, 0x6c, 0x97, 0xd7, 0x05, 0x7a, 0xff, 0x8c, + 0x85, 0xce, 0x6f, 0xa0, 0x53, 0x00, 0x17, 0x6e, 0x1e, 0x6c, 0xbd, 0x22, + 0xd7, 0x0a, 0x88, 0x37, 0xf6, 0x7d, 0xeb, 0x99, 0x41, 0xef, 0x27, 0xcb, + 0x8c, 0x60, 0x6b, 0x4c, 0x01, 0x7e, 0x65, 0x50, 0x0b, 0x4f, 0xb8, 0x95, + 0x9a, 0x9a, 0x6e, 0x34, 0xfd, 0x73, 0x3a, 0x33, 0xf1, 0x91, 0xd5, 0xf3, + 0x4e, 0x2d, 0x74, 0xe8, 0xef, 0xd3, 0x90, 0x35, 0xf1, 0x06, 0x68, 0x64, + 0xd4, 0xd0, 0x13, 0xfd, 0x52, 0xd3, 0xc6, 0x6d, 0xc1, 0x3a, 0x8a, 0x31, + 0xdd, 0x05, 0x26, 0x35, 0x4a, 0x8c, 0x65, 0xb8, 0x52, 0x6b, 0x81, 0xec, + 0xd2, 0x9c, 0xb5, 0x34, 0x10, 0x97, 0x9c, 0x3e, 0xc6, 0x2f, 0xed, 0x8e, + 0x42, 0x42, 0x24, 0x2e, 0xe9, 0x73, 0x9a, 0x25, 0xf9, 0x11, 0xf1, 0xf2, + 0x23, 0x69, 0xcb, 0xe5, 0x94, 0x69, 0xa0, 0xd2, 0xdc, 0xb0, 0xfc, 0x44, + 0x89, 0xac, 0x17, 0xa8, 0xcc, 0xd5, 0x37, 0x77, 0x16, 0xc5, 0x80, 0xb9, + 0x0c, 0x8f, 0x57, 0x02, 0x55, 0x99, 0x85, 0x7b, 0x49, 0xf0, 0x2e, 0x5b, + 0xa0, 0xc2, 0x57, 0x53, 0x5d, 0xa2, 0xe8, 0xa6, 0x37, 0xc3, 0x01, 0xfa, +} + +var certSet2Cert24 = []byte{ + 0x30, 0x82, 0x04, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x28, 0x1c, 0x89, 0x29, 0x66, 0x14, 0x43, 0x80, 0x42, + 0x63, 0x55, 0x3a, 0x32, 0x40, 0xae, 0xb3, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x35, 0x30, 0x36, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x36, 0x32, 0x39, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, 0x69, 0x64, + 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xc0, 0x9e, 0x3a, 0x0f, 0x9a, 0xb2, 0xba, 0xd3, 0xd2, + 0xdc, 0x15, 0xec, 0xd0, 0x30, 0x54, 0x59, 0x30, 0x4d, 0x40, 0x51, 0xae, + 0x42, 0x71, 0x71, 0xd2, 0x8d, 0x53, 0x73, 0x81, 0xfe, 0xb8, 0xe0, 0xc4, + 0x96, 0xc5, 0x8e, 0x7e, 0xc2, 0xf1, 0xb7, 0x63, 0x4a, 0xcf, 0xa7, 0x1e, + 0x3f, 0xa8, 0xe7, 0xce, 0x53, 0xa0, 0xfa, 0x2d, 0xf7, 0xd6, 0xe6, 0xce, + 0x70, 0x11, 0xa6, 0xee, 0xe1, 0x03, 0x52, 0xd2, 0x68, 0xde, 0x3d, 0x08, + 0x0d, 0x87, 0xfd, 0x1c, 0xd7, 0x0b, 0x97, 0x62, 0x6d, 0x82, 0x30, 0x76, + 0x1b, 0x47, 0x3a, 0xc4, 0xf7, 0xce, 0xed, 0x1d, 0x7c, 0x8c, 0xb7, 0x17, + 0x8e, 0x53, 0x80, 0x1e, 0x1d, 0x0f, 0x5d, 0x8c, 0xf9, 0x90, 0xe4, 0x04, + 0x1e, 0x02, 0x7e, 0xcb, 0xb0, 0x49, 0xef, 0xda, 0x52, 0x25, 0xfb, 0xfb, + 0x67, 0xed, 0xdd, 0x84, 0x74, 0x59, 0x84, 0x0e, 0xf3, 0xde, 0x70, 0x66, + 0x8d, 0xe4, 0x52, 0x38, 0xf7, 0x53, 0x5a, 0x37, 0x13, 0x67, 0x0b, 0x3e, + 0xbb, 0xa8, 0x58, 0xb7, 0x2e, 0xed, 0xff, 0xb7, 0x5e, 0x11, 0x73, 0xb9, + 0x77, 0x45, 0x52, 0x67, 0x46, 0xae, 0xc4, 0xdc, 0x24, 0x81, 0x89, 0x76, + 0x0a, 0xca, 0xa1, 0x6c, 0x66, 0x73, 0x04, 0x82, 0xaa, 0xf5, 0x70, 0x6c, + 0x5f, 0x1b, 0x9a, 0x00, 0x79, 0x46, 0xd6, 0x7f, 0x7a, 0x26, 0x17, 0x30, + 0xcf, 0x39, 0x4b, 0x2c, 0x74, 0xd9, 0x89, 0x44, 0x76, 0x10, 0xd0, 0xed, + 0xf7, 0x8b, 0xbb, 0x89, 0x05, 0x75, 0x4d, 0x0b, 0x0d, 0xb3, 0xda, 0xe9, + 0xbf, 0xf1, 0x6a, 0x7d, 0x2a, 0x11, 0xdb, 0x1e, 0x9f, 0x8c, 0xe3, 0xc4, + 0x06, 0x69, 0xe1, 0x1d, 0x88, 0x45, 0x39, 0xd1, 0x6e, 0x55, 0xd8, 0xaa, + 0xb7, 0x9b, 0x6f, 0xea, 0xf4, 0xde, 0xac, 0x17, 0x11, 0x92, 0x5d, 0x40, + 0x9b, 0x83, 0x7b, 0x9a, 0xe2, 0xf7, 0xa9, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x3a, 0x30, 0x82, 0x01, 0x36, 0x30, 0x2e, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, + 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x49, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x42, 0x30, 0x40, 0x30, 0x3e, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, + 0x01, 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x36, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, + 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x50, 0x43, 0x41, 0x2d, 0x47, 0x33, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0xf3, 0xb5, 0x56, 0x0c, 0xc4, 0x09, 0xb0, 0xb4, 0xcf, 0x1f, 0xaa, + 0xf9, 0xdd, 0x23, 0x56, 0xf0, 0x77, 0xe8, 0xa1, 0xf9, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc4, 0x79, + 0xca, 0x8e, 0xa1, 0x4e, 0x03, 0x1d, 0x1c, 0xdc, 0x6b, 0xdb, 0x31, 0x5b, + 0x94, 0x3e, 0x3f, 0x30, 0x7f, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0xc3, 0x7e, 0xd8, 0x83, 0x4b, 0x04, 0x4c, 0x55, 0x29, 0x2a, + 0x4f, 0x14, 0x9d, 0x9a, 0x6e, 0xde, 0x90, 0x70, 0xc1, 0xa4, 0x26, 0x4c, + 0x88, 0x8e, 0x78, 0x48, 0xef, 0xbd, 0x9c, 0xb0, 0xa0, 0xf5, 0xf0, 0x66, + 0xfc, 0xfe, 0x59, 0x26, 0xe1, 0x79, 0xef, 0xc8, 0xb7, 0x60, 0x64, 0xa8, + 0x8b, 0x47, 0xea, 0x2f, 0xe0, 0x83, 0x99, 0xda, 0x41, 0x19, 0xd7, 0xc5, + 0xbe, 0x05, 0xfa, 0xf2, 0x90, 0x11, 0xf0, 0x0a, 0xff, 0x6c, 0xdc, 0x05, + 0xb4, 0xd8, 0x06, 0x6f, 0xa4, 0x6f, 0x8d, 0xbe, 0x20, 0x2b, 0x54, 0xdb, + 0xf9, 0xa2, 0x45, 0x83, 0x9a, 0x1e, 0xa5, 0x21, 0x89, 0x35, 0x1d, 0x7c, + 0x20, 0x5c, 0x17, 0xfd, 0x04, 0x2e, 0x45, 0xd8, 0xb2, 0xc6, 0xf8, 0x42, + 0x99, 0xfc, 0x54, 0x08, 0x4e, 0x4b, 0x80, 0x5f, 0x39, 0x37, 0xba, 0x95, + 0x4e, 0xa6, 0x37, 0x0a, 0x9e, 0x93, 0x5e, 0x87, 0x5b, 0xe9, 0x90, 0xd6, + 0xa8, 0xb6, 0x65, 0x08, 0x8d, 0x61, 0x49, 0xeb, 0x83, 0x20, 0xa9, 0x5d, + 0x1b, 0x16, 0x60, 0x62, 0x6b, 0x2f, 0x54, 0xfb, 0x5a, 0x02, 0x0d, 0x7a, + 0x27, 0xe2, 0x4b, 0xe1, 0x05, 0x14, 0xc2, 0xe4, 0xe9, 0xf9, 0x70, 0xc0, + 0xd9, 0xf7, 0x34, 0x65, 0x0e, 0xa2, 0x91, 0x4b, 0xac, 0x28, 0xf2, 0xb7, + 0x08, 0x0f, 0x98, 0xca, 0xd7, 0x3e, 0x70, 0xb6, 0xc8, 0x0b, 0xf1, 0x8b, + 0x9c, 0x51, 0xf8, 0xc6, 0x10, 0x6c, 0xd2, 0x53, 0x4f, 0x62, 0x8c, 0x11, + 0x00, 0x3e, 0x88, 0xdf, 0xbf, 0xe6, 0xd2, 0xcc, 0x70, 0xbd, 0xed, 0x25, + 0x9c, 0xfb, 0xdd, 0x24, 0x0a, 0xbd, 0x59, 0x91, 0x4a, 0x42, 0x03, 0x38, + 0x12, 0x71, 0x32, 0x88, 0x76, 0xa0, 0x8e, 0x7c, 0xbb, 0x32, 0xef, 0x88, + 0x2a, 0x1b, 0xd4, 0x6a, 0x6f, 0x50, 0xb9, 0x52, 0x67, 0x8b, 0xab, 0x30, + 0xfa, 0x1f, 0xfd, 0xe3, 0x24, 0x9a, +} + +var certSet2Cert25 = []byte{ + 0x30, 0x82, 0x04, 0xaf, 0x30, 0x82, 0x03, 0x97, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x5d, 0x72, 0xfb, 0x33, 0x76, 0x20, 0xf6, 0x4c, 0x72, + 0x80, 0xdb, 0xe9, 0x12, 0x81, 0xff, 0x6a, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, + 0x30, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x44, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x45, 0x56, 0x20, 0x53, 0x53, 0x4c, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0xdd, 0xda, 0x94, 0x1e, 0x32, 0xb2, + 0x2e, 0xa0, 0x83, 0xc0, 0xa6, 0x7d, 0x5f, 0x65, 0x2d, 0xfd, 0x27, 0xb8, + 0x73, 0x0e, 0xf8, 0x0b, 0xa9, 0xd4, 0x56, 0x26, 0x69, 0x98, 0x67, 0x35, + 0x39, 0x64, 0x58, 0xce, 0x82, 0x6f, 0x98, 0x94, 0xd1, 0x8f, 0xe0, 0x90, + 0xd6, 0xed, 0x55, 0x4b, 0x98, 0x4b, 0xd7, 0x10, 0x59, 0x34, 0x02, 0x1b, + 0xe7, 0x51, 0x31, 0x51, 0xc4, 0x38, 0xc2, 0xbc, 0xdb, 0x03, 0x5c, 0xca, + 0xe1, 0x7c, 0xdc, 0x4f, 0x59, 0x97, 0xea, 0x07, 0x7f, 0x0f, 0x85, 0x3e, + 0x92, 0xea, 0xaa, 0xa7, 0xd9, 0xbe, 0x01, 0x41, 0xe4, 0x62, 0x56, 0x47, + 0x36, 0xbd, 0x57, 0x91, 0xe6, 0x21, 0xd3, 0xf8, 0x41, 0x0b, 0xd8, 0xba, + 0xe8, 0xed, 0x81, 0xad, 0x70, 0xc0, 0x8b, 0x6e, 0xf3, 0x89, 0x6e, 0x27, + 0x9e, 0xa6, 0xa6, 0x73, 0x59, 0xbb, 0x71, 0x00, 0xd4, 0x4f, 0x4b, 0x48, + 0xe9, 0xd5, 0xc9, 0x27, 0x36, 0x9c, 0x7c, 0x1c, 0x02, 0xaa, 0xac, 0xbd, + 0x3b, 0xd1, 0x53, 0x83, 0x6a, 0x1f, 0xe6, 0x08, 0x47, 0x33, 0xa7, 0xb1, + 0x9f, 0x02, 0xbe, 0x9b, 0x47, 0xed, 0x33, 0x04, 0xdc, 0x1c, 0x80, 0x27, + 0xd1, 0x4a, 0x33, 0xa0, 0x8c, 0xeb, 0x01, 0x47, 0xa1, 0x32, 0x90, 0x64, + 0x7b, 0xc4, 0xe0, 0x84, 0xc9, 0x32, 0xe9, 0xdd, 0x34, 0x1f, 0x8a, 0x68, + 0x67, 0xf3, 0xad, 0x10, 0x63, 0xeb, 0xee, 0x8a, 0x9a, 0xb1, 0x2a, 0x1b, + 0x26, 0x74, 0xa1, 0x2a, 0xb0, 0x8f, 0xfe, 0x52, 0x98, 0x46, 0x97, 0xcf, + 0xa3, 0x56, 0x1c, 0x6f, 0x6e, 0x99, 0x97, 0x8d, 0x26, 0x0e, 0xa9, 0xec, + 0xc2, 0x53, 0x70, 0xfc, 0x7a, 0xa5, 0x19, 0x49, 0xbd, 0xb5, 0x17, 0x82, + 0x55, 0xde, 0x97, 0xe0, 0x5d, 0x62, 0x84, 0x81, 0xf0, 0x70, 0xa8, 0x34, + 0x53, 0x4f, 0x14, 0xfd, 0x3d, 0x5d, 0x3d, 0x6f, 0xb9, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x35, 0x30, 0x82, 0x01, 0x31, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, + 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2f, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x23, + 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x74, + 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, + 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, + 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, + 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, 0x30, + 0x27, 0xa0, 0x25, 0xa0, 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x74, 0x31, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x29, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, + 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, + 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x35, 0x33, 0x36, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf0, 0x70, + 0x51, 0xda, 0xd3, 0x2a, 0x91, 0x4f, 0x52, 0x77, 0xd7, 0x86, 0x77, 0x74, + 0x0f, 0xce, 0x71, 0x1a, 0x6c, 0x22, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7b, 0x5b, 0x45, 0xcf, 0xaf, + 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, 0x6a, 0xb6, 0xf3, 0x46, 0xeb, + 0x57, 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa1, + 0x2e, 0x94, 0x3e, 0x9b, 0x16, 0xf4, 0x58, 0x1a, 0x6f, 0xc1, 0xfa, 0xc1, + 0x7e, 0x43, 0x93, 0xb2, 0xc3, 0xf7, 0x89, 0xeb, 0x13, 0x62, 0x5d, 0xdd, + 0xcc, 0x61, 0x13, 0x2b, 0x1d, 0x4e, 0x88, 0x79, 0x11, 0x62, 0x14, 0x37, + 0x30, 0x46, 0xff, 0x89, 0x62, 0x10, 0x85, 0x2a, 0x87, 0x1e, 0xf8, 0xe2, + 0xaf, 0xfe, 0x93, 0x02, 0x93, 0xca, 0xf2, 0xe9, 0x46, 0x03, 0x6b, 0xa1, + 0x1a, 0xac, 0xd5, 0xf0, 0x80, 0x1b, 0x98, 0x6f, 0xb8, 0x3a, 0x50, 0xf8, + 0x54, 0x71, 0x06, 0x03, 0xe7, 0x84, 0xcc, 0x8e, 0x61, 0xd2, 0x5f, 0x4d, + 0x0c, 0x97, 0x02, 0x65, 0xb5, 0x8c, 0x26, 0xbc, 0x05, 0x98, 0xf4, 0xdc, + 0xc6, 0xaf, 0xe4, 0x57, 0x7f, 0xe3, 0xdc, 0xa1, 0xd7, 0x27, 0x47, 0x2a, + 0xe0, 0x2c, 0x3f, 0x09, 0x74, 0xdc, 0x5a, 0xe5, 0xb5, 0x7c, 0xfa, 0x82, + 0x9a, 0x15, 0xfa, 0x74, 0x2b, 0x84, 0x2e, 0x6b, 0xac, 0xef, 0x35, 0xa6, + 0x30, 0xfa, 0x47, 0x4a, 0xaa, 0x36, 0x44, 0xf6, 0x5a, 0x91, 0x07, 0xd3, + 0xe4, 0x4e, 0x97, 0x3f, 0xa6, 0x53, 0xd8, 0x29, 0x33, 0x32, 0x6f, 0x8b, + 0x3d, 0xb5, 0xa5, 0x0d, 0xe5, 0xe4, 0x8a, 0xe8, 0xf5, 0xc0, 0xfa, 0xaf, + 0xd8, 0x37, 0x28, 0x27, 0xc3, 0xed, 0x34, 0x31, 0xd9, 0x7c, 0xa6, 0xaf, + 0x4d, 0x12, 0x4f, 0xd0, 0x2b, 0x92, 0x9c, 0x69, 0x95, 0xf2, 0x28, 0xa6, + 0xfe, 0xa8, 0xc6, 0xe0, 0x2c, 0x4d, 0x36, 0xeb, 0x11, 0x34, 0xd6, 0xe1, + 0x81, 0x99, 0x9d, 0x41, 0xf2, 0xe7, 0xc5, 0x57, 0x05, 0x0e, 0x19, 0xca, + 0xaf, 0x42, 0x39, 0x1f, 0xa7, 0x27, 0x5e, 0xe0, 0x0a, 0x17, 0xb8, 0xae, + 0x47, 0xab, 0x92, 0xf1, 0x8a, 0x04, 0xdf, 0x30, 0xe0, 0xbb, 0x4f, 0x8a, + 0xf9, 0x1b, 0x88, 0x4f, 0x03, 0xb4, 0x25, 0x7a, 0x78, 0xde, 0x2e, 0x7d, + 0x29, 0xd1, 0x31, +} + +var certSet2Cert26 = []byte{ + 0x30, 0x82, 0x04, 0xb1, 0x30, 0x82, 0x03, 0x99, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x04, 0xe1, 0xe7, 0xa4, 0xdc, 0x5c, 0xf2, 0xf3, 0x6d, + 0xc0, 0x2b, 0x42, 0xb8, 0x5d, 0x15, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x6c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, + 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, + 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x32, 0x32, 0x31, 0x32, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x30, 0x32, + 0x32, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x70, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, + 0x61, 0x6e, 0x63, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, + 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb6, + 0xe0, 0x2f, 0xc2, 0x24, 0x06, 0xc8, 0x6d, 0x04, 0x5f, 0xd7, 0xef, 0x0a, + 0x64, 0x06, 0xb2, 0x7d, 0x22, 0x26, 0x65, 0x16, 0xae, 0x42, 0x40, 0x9b, + 0xce, 0xdc, 0x9f, 0x9f, 0x76, 0x07, 0x3e, 0xc3, 0x30, 0x55, 0x87, 0x19, + 0xb9, 0x4f, 0x94, 0x0e, 0x5a, 0x94, 0x1f, 0x55, 0x56, 0xb4, 0xc2, 0x02, + 0x2a, 0xaf, 0xd0, 0x98, 0xee, 0x0b, 0x40, 0xd7, 0xc4, 0xd0, 0x3b, 0x72, + 0xc8, 0x14, 0x9e, 0xef, 0x90, 0xb1, 0x11, 0xa9, 0xae, 0xd2, 0xc8, 0xb8, + 0x43, 0x3a, 0xd9, 0x0b, 0x0b, 0xd5, 0xd5, 0x95, 0xf5, 0x40, 0xaf, 0xc8, + 0x1d, 0xed, 0x4d, 0x9c, 0x5f, 0x57, 0xb7, 0x86, 0x50, 0x68, 0x99, 0xf5, + 0x8a, 0xda, 0xd2, 0xc7, 0x05, 0x1f, 0xa8, 0x97, 0xc9, 0xdc, 0xa4, 0xb1, + 0x82, 0x84, 0x2d, 0xc6, 0xad, 0xa5, 0x9c, 0xc7, 0x19, 0x82, 0xa6, 0x85, + 0x0f, 0x5e, 0x44, 0x58, 0x2a, 0x37, 0x8f, 0xfd, 0x35, 0xf1, 0x0b, 0x08, + 0x27, 0x32, 0x5a, 0xf5, 0xbb, 0x8b, 0x9e, 0xa4, 0xbd, 0x51, 0xd0, 0x27, + 0xe2, 0xdd, 0x3b, 0x42, 0x33, 0xa3, 0x05, 0x28, 0xc4, 0xbb, 0x28, 0xcc, + 0x9a, 0xac, 0x2b, 0x23, 0x0d, 0x78, 0xc6, 0x7b, 0xe6, 0x5e, 0x71, 0xb7, + 0x4a, 0x3e, 0x08, 0xfb, 0x81, 0xb7, 0x16, 0x16, 0xa1, 0x9d, 0x23, 0x12, + 0x4d, 0xe5, 0xd7, 0x92, 0x08, 0xac, 0x75, 0xa4, 0x9c, 0xba, 0xcd, 0x17, + 0xb2, 0x1e, 0x44, 0x35, 0x65, 0x7f, 0x53, 0x25, 0x39, 0xd1, 0x1c, 0x0a, + 0x9a, 0x63, 0x1b, 0x19, 0x92, 0x74, 0x68, 0x0a, 0x37, 0xc2, 0xc2, 0x52, + 0x48, 0xcb, 0x39, 0x5a, 0xa2, 0xb6, 0xe1, 0x5d, 0xc1, 0xdd, 0xa0, 0x20, + 0xb8, 0x21, 0xa2, 0x93, 0x26, 0x6f, 0x14, 0x4a, 0x21, 0x41, 0xc7, 0xed, + 0x6d, 0x9b, 0xf2, 0x48, 0x2f, 0xf3, 0x03, 0xf5, 0xa2, 0x68, 0x92, 0x53, + 0x2f, 0x5e, 0xe3, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x49, + 0x30, 0x82, 0x01, 0x45, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, + 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4b, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x44, 0x30, 0x42, 0x30, 0x40, 0xa0, 0x3e, 0xa0, 0x3c, 0x86, 0x3a, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x34, 0x2e, + 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x48, 0x69, 0x67, + 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x56, + 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, + 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, + 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x51, 0x68, 0xff, 0x90, 0xaf, 0x02, 0x07, 0x75, 0x3c, 0xcc, 0xd9, 0x65, + 0x64, 0x62, 0xa2, 0x12, 0xb8, 0x59, 0x72, 0x3b, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb1, 0x3e, 0xc3, + 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, 0x02, + 0xef, 0x63, 0x64, 0x2b, 0xc3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, + 0x00, 0x18, 0x8a, 0x95, 0x89, 0x03, 0xe6, 0x6d, 0xdf, 0x5c, 0xfc, 0x1d, + 0x68, 0xea, 0x4a, 0x8f, 0x83, 0xd6, 0x51, 0x2f, 0x8d, 0x6b, 0x44, 0x16, + 0x9e, 0xac, 0x63, 0xf5, 0xd2, 0x6e, 0x6c, 0x84, 0x99, 0x8b, 0xaa, 0x81, + 0x71, 0x84, 0x5b, 0xed, 0x34, 0x4e, 0xb0, 0xb7, 0x79, 0x92, 0x29, 0xcc, + 0x2d, 0x80, 0x6a, 0xf0, 0x8e, 0x20, 0xe1, 0x79, 0xa4, 0xfe, 0x03, 0x47, + 0x13, 0xea, 0xf5, 0x86, 0xca, 0x59, 0x71, 0x7d, 0xf4, 0x04, 0x96, 0x6b, + 0xd3, 0x59, 0x58, 0x3d, 0xfe, 0xd3, 0x31, 0x25, 0x5c, 0x18, 0x38, 0x84, + 0xa3, 0xe6, 0x9f, 0x82, 0xfd, 0x8c, 0x5b, 0x98, 0x31, 0x4e, 0xcd, 0x78, + 0x9e, 0x1a, 0xfd, 0x85, 0xcb, 0x49, 0xaa, 0xf2, 0x27, 0x8b, 0x99, 0x72, + 0xfc, 0x3e, 0xaa, 0xd5, 0x41, 0x0b, 0xda, 0xd5, 0x36, 0xa1, 0xbf, 0x1c, + 0x6e, 0x47, 0x49, 0x7f, 0x5e, 0xd9, 0x48, 0x7c, 0x03, 0xd9, 0xfd, 0x8b, + 0x49, 0xa0, 0x98, 0x26, 0x42, 0x40, 0xeb, 0xd6, 0x92, 0x11, 0xa4, 0x64, + 0x0a, 0x57, 0x54, 0xc4, 0xf5, 0x1d, 0xd6, 0x02, 0x5e, 0x6b, 0xac, 0xee, + 0xc4, 0x80, 0x9a, 0x12, 0x72, 0xfa, 0x56, 0x93, 0xd7, 0xff, 0xbf, 0x30, + 0x85, 0x06, 0x30, 0xbf, 0x0b, 0x7f, 0x4e, 0xff, 0x57, 0x05, 0x9d, 0x24, + 0xed, 0x85, 0xc3, 0x2b, 0xfb, 0xa6, 0x75, 0xa8, 0xac, 0x2d, 0x16, 0xef, + 0x7d, 0x79, 0x27, 0xb2, 0xeb, 0xc2, 0x9d, 0x0b, 0x07, 0xea, 0xaa, 0x85, + 0xd3, 0x01, 0xa3, 0x20, 0x28, 0x41, 0x59, 0x43, 0x28, 0xd2, 0x81, 0xe3, + 0xaa, 0xf6, 0xec, 0x7b, 0x3b, 0x77, 0xb6, 0x40, 0x62, 0x80, 0x05, 0x41, + 0x45, 0x01, 0xef, 0x17, 0x06, 0x3e, 0xde, 0xc0, 0x33, 0x9b, 0x67, 0xd3, + 0x61, 0x2e, 0x72, 0x87, 0xe4, 0x69, 0xfc, 0x12, 0x00, 0x57, 0x40, 0x1e, + 0x70, 0xf5, 0x1e, 0xc9, 0xb4, +} + +var certSet2Cert27 = []byte{ + 0x30, 0x82, 0x04, 0xb2, 0x30, 0x82, 0x03, 0x9a, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x16, 0x87, 0xd6, 0x88, 0x6d, 0xe2, 0x30, 0x06, 0x85, + 0x23, 0x3d, 0xbf, 0x11, 0xbf, 0x65, 0x97, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, + 0x30, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x41, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xb2, 0xfc, 0x06, 0xfb, 0x04, 0x93, 0xd2, 0xea, 0x59, 0x20, + 0x3b, 0x44, 0x85, 0x97, 0x52, 0x39, 0xe7, 0x10, 0xf0, 0x7a, 0xe0, 0xb0, + 0x94, 0x40, 0xda, 0x46, 0xf8, 0x0c, 0x28, 0xbb, 0xb9, 0xce, 0x60, 0x38, + 0x3f, 0xd2, 0xd8, 0x11, 0x42, 0x1b, 0x91, 0xad, 0x49, 0xee, 0x8f, 0xc7, + 0xde, 0x6c, 0xde, 0x37, 0x6f, 0xfd, 0x8b, 0x20, 0x3c, 0x6d, 0xe7, 0x74, + 0xd3, 0xdc, 0xd5, 0x24, 0x88, 0x41, 0x80, 0x89, 0xee, 0x36, 0xbe, 0xc4, + 0xd5, 0xbe, 0x8d, 0x53, 0x13, 0xaa, 0xe4, 0xa5, 0xb8, 0x93, 0x0a, 0xbe, + 0xec, 0xda, 0xcd, 0x3c, 0xd4, 0x32, 0x56, 0xef, 0xd0, 0x4e, 0xa0, 0xb8, + 0x97, 0xbb, 0x39, 0x50, 0x1e, 0x6e, 0x65, 0xc3, 0xfd, 0xb2, 0xce, 0xe0, + 0x59, 0xa9, 0x48, 0x09, 0xc6, 0xfe, 0xbe, 0xae, 0xfc, 0x3e, 0x3b, 0x81, + 0x20, 0x97, 0x8b, 0x8f, 0x46, 0xdf, 0x60, 0x64, 0x07, 0x75, 0xbb, 0x1b, + 0x86, 0x38, 0x9f, 0x47, 0x7b, 0x34, 0xce, 0xa1, 0xd1, 0x97, 0xad, 0x76, + 0xd8, 0x9f, 0xb7, 0x26, 0xdb, 0x79, 0x80, 0x36, 0x48, 0xf2, 0xc5, 0x37, + 0xf8, 0xd9, 0x32, 0xae, 0x7c, 0xa4, 0x53, 0x81, 0xc7, 0x99, 0xa1, 0x54, + 0x38, 0x2f, 0x4f, 0x75, 0xa0, 0xbb, 0x5a, 0xa5, 0xbb, 0xcd, 0xac, 0x02, + 0x5b, 0x19, 0x02, 0xd5, 0x13, 0x18, 0xa7, 0xce, 0xac, 0x74, 0x55, 0x12, + 0x05, 0x8b, 0x9b, 0xa2, 0x95, 0x46, 0x64, 0x72, 0x38, 0xcd, 0x5a, 0x1b, + 0x3a, 0x16, 0xa7, 0xbe, 0x71, 0x99, 0x8c, 0x54, 0x03, 0xb8, 0x96, 0x6c, + 0x01, 0xd3, 0x3e, 0x06, 0x98, 0x3f, 0x21, 0x81, 0x3b, 0x02, 0x7e, 0x00, + 0x47, 0x53, 0x01, 0x1e, 0x0e, 0x46, 0x43, 0xfb, 0x4b, 0x2d, 0xdc, 0x0b, + 0x1a, 0xe8, 0x2f, 0x98, 0xf8, 0x7e, 0xd1, 0x99, 0xab, 0x13, 0x6c, 0xa4, + 0x17, 0xde, 0x6f, 0xf6, 0x15, 0xf5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x82, 0x01, 0x3b, 0x30, 0x82, 0x01, 0x37, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x32, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, 0x30, 0x27, 0xa0, 0x25, 0xa0, 0x23, + 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x74, 0x31, 0x2e, + 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, + 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x74, 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x41, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3a, 0x30, 0x38, 0x30, + 0x36, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, + 0x36, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x29, 0x06, 0x03, 0x55, + 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, + 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, + 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x35, + 0x33, 0x37, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0xc2, 0x4f, 0x48, 0x57, 0xfc, 0xd1, 0x4f, 0x9a, 0xc0, 0x5d, 0x38, + 0x7d, 0x0e, 0x05, 0xdb, 0xd9, 0x2e, 0xb5, 0x52, 0x60, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7b, 0x5b, + 0x45, 0xcf, 0xaf, 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, 0x6a, 0xb6, + 0xf3, 0x46, 0xeb, 0x57, 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x8d, 0x06, 0xde, 0x43, 0xc9, 0x76, 0x02, 0xca, 0xd9, 0x23, + 0x97, 0x5e, 0xf3, 0x63, 0xd7, 0x7d, 0x44, 0xc2, 0x0f, 0x6b, 0x0a, 0xf5, + 0x07, 0xe5, 0x8b, 0xb8, 0xfa, 0xe0, 0xa3, 0xfa, 0x6b, 0x80, 0x92, 0xb5, + 0x03, 0x2c, 0xc5, 0x37, 0xe0, 0xc2, 0xe5, 0x95, 0xb5, 0x92, 0x70, 0x18, + 0x28, 0x42, 0x94, 0xee, 0x4b, 0x77, 0x6a, 0x01, 0x0f, 0x8b, 0x23, 0xec, + 0x56, 0x4d, 0xf4, 0x00, 0x69, 0xe5, 0x84, 0xc8, 0xe2, 0xea, 0xde, 0x5b, + 0x3e, 0xf6, 0x3c, 0x07, 0x3a, 0x94, 0xca, 0x6c, 0x27, 0xb1, 0xcc, 0x83, + 0x1a, 0x60, 0x71, 0x27, 0xd2, 0xbf, 0x02, 0xf5, 0x1e, 0x44, 0xd3, 0x48, + 0xd5, 0xa6, 0xd3, 0x76, 0x21, 0x00, 0x9c, 0xfa, 0x98, 0x64, 0xeb, 0x17, + 0x36, 0x3f, 0xeb, 0x1b, 0x3c, 0x3e, 0xa6, 0xb1, 0xd9, 0x58, 0x06, 0x0e, + 0x72, 0xd9, 0x68, 0xbe, 0xf1, 0xa7, 0x20, 0xd7, 0x52, 0xe4, 0xa4, 0x77, + 0x1f, 0x71, 0x70, 0x9d, 0x55, 0x35, 0x85, 0x37, 0xe1, 0x1d, 0x4d, 0x94, + 0xc2, 0x70, 0x7f, 0x95, 0x40, 0x6e, 0x4b, 0x7d, 0xb2, 0xb4, 0x29, 0x2a, + 0x03, 0x79, 0xc8, 0xb9, 0x4c, 0x67, 0x61, 0x04, 0xa0, 0x8b, 0x27, 0xff, + 0x59, 0x00, 0xeb, 0x55, 0x7f, 0xc6, 0xb7, 0x33, 0x35, 0x2d, 0x5e, 0x4e, + 0xac, 0xb8, 0xea, 0x12, 0xc5, 0xe8, 0xf7, 0xb9, 0xab, 0xbe, 0x74, 0x92, + 0x2c, 0xb7, 0xd9, 0x4d, 0xca, 0x84, 0x2f, 0x1c, 0xc2, 0xf0, 0x72, 0x7c, + 0xb2, 0x31, 0x6e, 0xcf, 0x80, 0xe5, 0x88, 0x07, 0x36, 0x51, 0x7b, 0xba, + 0x61, 0xaf, 0x6d, 0x8d, 0x23, 0x5b, 0x34, 0xa3, 0x95, 0xbc, 0xa2, 0x31, + 0x7f, 0xf2, 0xf5, 0xe7, 0xb7, 0xe8, 0xef, 0xc4, 0xb5, 0x27, 0x32, 0xe9, + 0xf7, 0x9e, 0x69, 0xc7, 0x2b, 0xe8, 0xbe, 0xbb, 0x0c, 0xaa, 0xe7, 0xea, + 0x60, 0x12, 0xea, 0x26, 0x8a, 0x78, +} + +var certSet2Cert28 = []byte{ + 0x30, 0x82, 0x04, 0xb6, 0x30, 0x82, 0x03, 0x9e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x0c, 0x79, 0xa9, 0x44, 0xb0, 0x8c, 0x11, 0x95, 0x20, + 0x92, 0x61, 0x5f, 0xe2, 0x6b, 0x1d, 0x83, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x6c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, + 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, + 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x32, 0x32, 0x31, 0x32, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x30, 0x32, + 0x32, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x75, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2b, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xd7, 0x53, 0xa4, 0x04, 0x51, 0xf8, 0x99, 0xa6, + 0x16, 0x48, 0x4b, 0x67, 0x27, 0xaa, 0x93, 0x49, 0xd0, 0x39, 0xed, 0x0c, + 0xb0, 0xb0, 0x00, 0x87, 0xf1, 0x67, 0x28, 0x86, 0x85, 0x8c, 0x8e, 0x63, + 0xda, 0xbc, 0xb1, 0x40, 0x38, 0xe2, 0xd3, 0xf5, 0xec, 0xa5, 0x05, 0x18, + 0xb8, 0x3d, 0x3e, 0xc5, 0x99, 0x17, 0x32, 0xec, 0x18, 0x8c, 0xfa, 0xf1, + 0x0c, 0xa6, 0x64, 0x21, 0x85, 0xcb, 0x07, 0x10, 0x34, 0xb0, 0x52, 0x88, + 0x2b, 0x1f, 0x68, 0x9b, 0xd2, 0xb1, 0x8f, 0x12, 0xb0, 0xb3, 0xd2, 0xe7, + 0x88, 0x1f, 0x1f, 0xef, 0x38, 0x77, 0x54, 0x53, 0x5f, 0x80, 0x79, 0x3f, + 0x2e, 0x1a, 0xaa, 0xa8, 0x1e, 0x4b, 0x2b, 0x0d, 0xab, 0xb7, 0x63, 0xb9, + 0x35, 0xb7, 0x7d, 0x14, 0xbc, 0x59, 0x4b, 0xdf, 0x51, 0x4a, 0xd2, 0xa1, + 0xe2, 0x0c, 0xe2, 0x90, 0x82, 0x87, 0x6a, 0xae, 0xea, 0xd7, 0x64, 0xd6, + 0x98, 0x55, 0xe8, 0xfd, 0xaf, 0x1a, 0x50, 0x6c, 0x54, 0xbc, 0x11, 0xf2, + 0xfd, 0x4a, 0xf2, 0x9d, 0xbb, 0x7f, 0x0e, 0xf4, 0xd5, 0xbe, 0x8e, 0x16, + 0x89, 0x12, 0x55, 0xd8, 0xc0, 0x71, 0x34, 0xee, 0xf6, 0xdc, 0x2d, 0xec, + 0xc4, 0x87, 0x25, 0x86, 0x8d, 0xd8, 0x21, 0xe4, 0xb0, 0x4d, 0x0c, 0x89, + 0xdc, 0x39, 0x26, 0x17, 0xdd, 0xf6, 0xd7, 0x94, 0x85, 0xd8, 0x04, 0x21, + 0x70, 0x9d, 0x6f, 0x6f, 0xff, 0x5c, 0xba, 0x19, 0xe1, 0x45, 0xcb, 0x56, + 0x57, 0x28, 0x7e, 0x1c, 0x0d, 0x41, 0x57, 0xaa, 0xb7, 0xb8, 0x27, 0xbb, + 0xb1, 0xe4, 0xfa, 0x2a, 0xef, 0x21, 0x23, 0x75, 0x1a, 0xad, 0x2d, 0x9b, + 0x86, 0x35, 0x8c, 0x9c, 0x77, 0xb5, 0x73, 0xad, 0xd8, 0x94, 0x2d, 0xe4, + 0xf3, 0x0c, 0x9d, 0xee, 0xc1, 0x4e, 0x62, 0x7e, 0x17, 0xc0, 0x71, 0x9e, + 0x2c, 0xde, 0xf1, 0xf9, 0x10, 0x28, 0x19, 0x33, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0x49, 0x30, 0x82, 0x01, 0x45, 0x30, 0x12, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, + 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, + 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, + 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4b, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x44, 0x30, 0x42, 0x30, 0x40, 0xa0, + 0x3e, 0xa0, 0x3c, 0x86, 0x3a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, + 0x72, 0x74, 0x48, 0x69, 0x67, 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, + 0x6e, 0x63, 0x65, 0x45, 0x56, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, + 0x30, 0x34, 0x30, 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, + 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, + 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3d, 0xd3, 0x50, 0xa5, 0xd6, 0xa0, 0xad, + 0xee, 0xf3, 0x4a, 0x60, 0x0a, 0x65, 0xd3, 0x21, 0xd4, 0xf8, 0xf8, 0xd6, + 0x0f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xb1, 0x3e, 0xc3, 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, + 0x98, 0x26, 0x1a, 0x08, 0x02, 0xef, 0x63, 0x64, 0x2b, 0xc3, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9d, 0xb6, 0xd0, 0x90, 0x86, 0xe1, + 0x86, 0x02, 0xed, 0xc5, 0xa0, 0xf0, 0x34, 0x1c, 0x74, 0xc1, 0x8d, 0x76, + 0xcc, 0x86, 0x0a, 0xa8, 0xf0, 0x4a, 0x8a, 0x42, 0xd6, 0x3f, 0xc8, 0xa9, + 0x4d, 0xad, 0x7c, 0x08, 0xad, 0xe6, 0xb6, 0x50, 0xb8, 0xa2, 0x1a, 0x4d, + 0x88, 0x07, 0xb1, 0x29, 0x21, 0xdc, 0xe7, 0xda, 0xc6, 0x3c, 0x21, 0xe0, + 0xe3, 0x11, 0x49, 0x70, 0xac, 0x7a, 0x1d, 0x01, 0xa4, 0xca, 0x11, 0x3a, + 0x57, 0xab, 0x7d, 0x57, 0x2a, 0x40, 0x74, 0xfd, 0xd3, 0x1d, 0x85, 0x18, + 0x50, 0xdf, 0x57, 0x47, 0x75, 0xa1, 0x7d, 0x55, 0x20, 0x2e, 0x47, 0x37, + 0x50, 0x72, 0x8c, 0x7f, 0x82, 0x1b, 0xd2, 0x62, 0x8f, 0x2d, 0x03, 0x5a, + 0xda, 0xc3, 0xc8, 0xa1, 0xce, 0x2c, 0x52, 0xa2, 0x00, 0x63, 0xeb, 0x73, + 0xba, 0x71, 0xc8, 0x49, 0x27, 0x23, 0x97, 0x64, 0x85, 0x9e, 0x38, 0x0e, + 0xad, 0x63, 0x68, 0x3c, 0xba, 0x52, 0x81, 0x58, 0x79, 0xa3, 0x2c, 0x0c, + 0xdf, 0xde, 0x6d, 0xeb, 0x31, 0xf2, 0xba, 0xa0, 0x7c, 0x6c, 0xf1, 0x2c, + 0xd4, 0xe1, 0xbd, 0x77, 0x84, 0x37, 0x03, 0xce, 0x32, 0xb5, 0xc8, 0x9a, + 0x81, 0x1a, 0x4a, 0x92, 0x4e, 0x3b, 0x46, 0x9a, 0x85, 0xfe, 0x83, 0xa2, + 0xf9, 0x9e, 0x8c, 0xa3, 0xcc, 0x0d, 0x5e, 0xb3, 0x3d, 0xcf, 0x04, 0x78, + 0x8f, 0x14, 0x14, 0x7b, 0x32, 0x9c, 0xc7, 0x00, 0xa6, 0x5c, 0xc4, 0xb5, + 0xa1, 0x55, 0x8d, 0x5a, 0x56, 0x68, 0xa4, 0x22, 0x70, 0xaa, 0x3c, 0x81, + 0x71, 0xd9, 0x9d, 0xa8, 0x45, 0x3b, 0xf4, 0xe5, 0xf6, 0xa2, 0x51, 0xdd, + 0xc7, 0x7b, 0x62, 0xe8, 0x6f, 0x0c, 0x74, 0xeb, 0xb8, 0xda, 0xf8, 0xbf, + 0x87, 0x0d, 0x79, 0x50, 0x91, 0x90, 0x9b, 0x18, 0x3b, 0x91, 0x59, 0x27, + 0xf1, 0x35, 0x28, 0x13, 0xab, 0x26, 0x7e, 0xd5, 0xf7, 0x7a, +} + +var certSet2Cert29 = []byte{ + 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x03, 0xaa, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x36, 0x34, 0x9e, 0x18, 0xc9, 0x9c, 0x26, 0x69, 0xb6, + 0x56, 0x2e, 0x6c, 0xe5, 0xad, 0x71, 0x32, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xae, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x38, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1b, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x33, 0x30, 0x35, 0x32, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x17, 0x0d, 0x32, 0x33, 0x30, 0x35, 0x32, 0x32, 0x32, 0x33, 0x35, 0x39, + 0x35, 0x39, 0x5a, 0x30, 0x43, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x14, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x63, 0x2b, + 0xd4, 0xba, 0x5d, 0x38, 0xae, 0xb0, 0xcf, 0xb9, 0x4c, 0x38, 0xdf, 0x20, + 0x7d, 0xf1, 0x2b, 0x47, 0x71, 0x1d, 0x8b, 0x68, 0xf3, 0x56, 0xf9, 0x9c, + 0xda, 0xaa, 0xe5, 0x84, 0x26, 0xde, 0xa5, 0x71, 0x30, 0xbc, 0xf3, 0x31, + 0x23, 0x9d, 0xe8, 0x3b, 0x80, 0xc8, 0x66, 0x57, 0x75, 0xb6, 0x57, 0x0e, + 0xdb, 0x93, 0xf5, 0x26, 0x8e, 0x70, 0xba, 0x64, 0x52, 0x66, 0x8a, 0x2a, + 0x88, 0x5c, 0x44, 0x18, 0x4d, 0xa8, 0xa2, 0x7c, 0xbd, 0x56, 0x61, 0x32, + 0x90, 0x12, 0xf9, 0x35, 0x87, 0x48, 0x60, 0xb0, 0x6e, 0x90, 0x67, 0x44, + 0x01, 0x8d, 0xe7, 0xc9, 0x0d, 0x63, 0x68, 0x72, 0x72, 0xab, 0x63, 0x3c, + 0x86, 0xb8, 0x1f, 0x7d, 0xad, 0x88, 0x25, 0xa7, 0x6a, 0x88, 0x29, 0xfb, + 0x59, 0xc6, 0x78, 0x71, 0x5f, 0x2c, 0xba, 0x89, 0xe6, 0xd3, 0x80, 0xfd, + 0x57, 0xec, 0xb9, 0x51, 0x5f, 0x43, 0x33, 0x2e, 0x7e, 0x25, 0x3b, 0xa4, + 0x04, 0xd1, 0x60, 0x8c, 0xb3, 0x44, 0x33, 0x93, 0x0c, 0xad, 0x2a, 0xb6, + 0x44, 0xa2, 0x19, 0x3b, 0xaf, 0xc4, 0x90, 0x6f, 0x7b, 0x05, 0x87, 0x86, + 0x9b, 0x2c, 0x6a, 0x9d, 0x2b, 0x6c, 0x77, 0xc9, 0x00, 0x9f, 0xc9, 0xcf, + 0xac, 0xed, 0x3e, 0x1b, 0xf7, 0xc3, 0xf3, 0xd9, 0xf8, 0x6c, 0xd4, 0xa0, + 0x57, 0xc4, 0xfb, 0x28, 0x32, 0xaa, 0x33, 0xf0, 0xe6, 0xba, 0x98, 0xdf, + 0xe5, 0xc2, 0x4e, 0x9c, 0x74, 0xbf, 0x8a, 0x48, 0xc2, 0xf2, 0x1b, 0xf0, + 0x77, 0x40, 0x41, 0x07, 0x04, 0xb2, 0x3a, 0xd5, 0x4c, 0xc4, 0x29, 0xa9, + 0x11, 0x40, 0x3f, 0x02, 0x46, 0xf0, 0x91, 0xd5, 0xd2, 0x81, 0x83, 0x86, + 0x13, 0xb3, 0x31, 0xed, 0x46, 0xab, 0xa8, 0x87, 0x76, 0xa9, 0x99, 0x7d, + 0xbc, 0xcd, 0x31, 0x50, 0xf4, 0xa5, 0xb5, 0xdc, 0xa5, 0x32, 0xb3, 0x8b, + 0x8b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x44, 0x30, 0x82, + 0x01, 0x40, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x41, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3a, 0x30, + 0x38, 0x30, 0x36, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, + 0x01, 0x07, 0x36, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x37, 0x06, + 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x30, 0x30, 0x2e, 0x30, 0x2c, 0xa0, 0x2a, + 0xa0, 0x28, 0x86, 0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, 0x2d, + 0x47, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2a, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x23, 0x30, 0x21, 0xa4, 0x1f, 0x30, + 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, + 0x2d, 0x32, 0x2d, 0x34, 0x31, 0x35, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2b, 0x9a, 0x35, 0xae, 0x01, 0x18, 0x38, + 0x30, 0xe1, 0x70, 0x7a, 0x05, 0xe0, 0x11, 0x76, 0xa3, 0xce, 0xbd, 0x90, + 0x14, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xad, 0x6c, 0xaa, 0x94, 0x60, 0x9c, 0xed, 0xe4, 0xff, 0xfa, + 0x3e, 0x0a, 0x74, 0x2b, 0x63, 0x03, 0xf7, 0xb6, 0x59, 0xbf, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x74, 0xa6, 0x56, 0xe8, 0xaf, 0x93, + 0x96, 0x19, 0xfb, 0x26, 0xf9, 0x0d, 0xb0, 0x44, 0xa5, 0xcd, 0xe9, 0x7a, + 0x48, 0x03, 0x74, 0x01, 0x6c, 0x13, 0x71, 0xb7, 0xe0, 0x82, 0x90, 0x99, + 0x62, 0x23, 0xe3, 0xd6, 0x99, 0xaf, 0xf0, 0xc7, 0x1e, 0x9e, 0xa8, 0x18, + 0x21, 0xdb, 0xb4, 0x94, 0x3f, 0x34, 0x56, 0x1b, 0x99, 0x55, 0x2f, 0x8e, + 0xf0, 0x45, 0x33, 0x32, 0xb7, 0x72, 0xc1, 0x13, 0x5b, 0x34, 0xd3, 0xf5, + 0x60, 0xe5, 0x2e, 0x18, 0xd1, 0x5c, 0xc5, 0x6a, 0xc1, 0xaa, 0x87, 0x50, + 0x0c, 0x1c, 0x9d, 0x64, 0x2b, 0xff, 0x1b, 0xdc, 0xd5, 0x2e, 0x61, 0x0b, + 0xe7, 0xb9, 0xb6, 0x91, 0x53, 0x86, 0xd9, 0x03, 0x2a, 0xd1, 0x3d, 0x7b, + 0x4a, 0xda, 0x2b, 0x07, 0xbe, 0x29, 0xf2, 0x60, 0x42, 0xa9, 0x91, 0x1a, + 0x0e, 0x2e, 0x3c, 0xd1, 0x7d, 0xa5, 0x13, 0x14, 0x02, 0xfa, 0xee, 0x8b, + 0x8d, 0xb6, 0xc8, 0xb8, 0x3e, 0x56, 0x81, 0x57, 0x21, 0x24, 0x3f, 0x65, + 0xc3, 0xb4, 0xc9, 0xce, 0x5c, 0x8d, 0x46, 0xac, 0x53, 0xf3, 0xf9, 0x55, + 0x74, 0xc8, 0x2b, 0xfd, 0xd2, 0x78, 0x70, 0xf5, 0xf8, 0x11, 0xe5, 0xf4, + 0xa7, 0xad, 0x20, 0xf5, 0x9d, 0xf1, 0xec, 0x70, 0xf6, 0x13, 0xac, 0xe6, + 0x8c, 0x8d, 0xdb, 0x3f, 0xc6, 0xf2, 0x79, 0x0e, 0xab, 0x52, 0xf2, 0xcc, + 0x1b, 0x79, 0x27, 0xcf, 0x16, 0xb3, 0xd6, 0xf3, 0xc6, 0x36, 0x80, 0x43, + 0xec, 0xc5, 0x94, 0xf0, 0xdd, 0x90, 0x8d, 0xf8, 0xc6, 0x52, 0x46, 0x56, + 0xeb, 0x74, 0x47, 0xbe, 0xa6, 0xf3, 0x19, 0xae, 0x71, 0x4c, 0xc0, 0xe1, + 0xe7, 0xd4, 0xcf, 0xed, 0xd4, 0x06, 0x28, 0x2a, 0x11, 0x3c, 0xba, 0xd9, + 0x41, 0x6e, 0x00, 0xe7, 0x81, 0x37, 0x93, 0xe4, 0xda, 0x62, 0xc6, 0x1d, + 0x67, 0x6f, 0x63, 0xb4, 0x14, 0x86, 0xd9, 0xa6, 0x62, 0xf0, +} + +var certSet2Cert30 = []byte{ + 0x30, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0x2f, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x35, 0x97, 0x31, 0x87, 0xf3, 0x87, 0x3a, 0x07, 0x32, + 0x7e, 0xce, 0x58, 0x0c, 0x9b, 0x7e, 0xda, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xca, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3a, 0x30, + 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, 0x63, 0x29, 0x20, + 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, + 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, + 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x45, 0x30, + 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, 0x24, 0x08, 0x08, 0x29, 0x7a, 0x35, + 0x9e, 0x60, 0x0c, 0xaa, 0xe7, 0x4b, 0x3b, 0x4e, 0xdc, 0x7c, 0xbc, 0x3c, + 0x45, 0x1c, 0xbb, 0x2b, 0xe0, 0xfe, 0x29, 0x02, 0xf9, 0x57, 0x08, 0xa3, + 0x64, 0x85, 0x15, 0x27, 0xf5, 0xf1, 0xad, 0xc8, 0x31, 0x89, 0x5d, 0x22, + 0xe8, 0x2a, 0xaa, 0xa6, 0x42, 0xb3, 0x8f, 0xf8, 0xb9, 0x55, 0xb7, 0xb1, + 0xb7, 0x4b, 0xb3, 0xfe, 0x8f, 0x7e, 0x07, 0x57, 0xec, 0xef, 0x43, 0xdb, + 0x66, 0x62, 0x15, 0x61, 0xcf, 0x60, 0x0d, 0xa4, 0xd8, 0xde, 0xf8, 0xe0, + 0xc3, 0x62, 0x08, 0x3d, 0x54, 0x13, 0xeb, 0x49, 0xca, 0x59, 0x54, 0x85, + 0x26, 0xe5, 0x2b, 0x8f, 0x1b, 0x9f, 0xeb, 0xf5, 0xa1, 0x91, 0xc2, 0x33, + 0x49, 0xd8, 0x43, 0x63, 0x6a, 0x52, 0x4b, 0xd2, 0x8f, 0xe8, 0x70, 0x51, + 0x4d, 0xd1, 0x89, 0x69, 0x7b, 0xc7, 0x70, 0xf6, 0xb3, 0xdc, 0x12, 0x74, + 0xdb, 0x7b, 0x5d, 0x4b, 0x56, 0xd3, 0x96, 0xbf, 0x15, 0x77, 0xa1, 0xb0, + 0xf4, 0xa2, 0x25, 0xf2, 0xaf, 0x1c, 0x92, 0x67, 0x18, 0xe5, 0xf4, 0x06, + 0x04, 0xef, 0x90, 0xb9, 0xe4, 0x00, 0xe4, 0xdd, 0x3a, 0xb5, 0x19, 0xff, + 0x02, 0xba, 0xf4, 0x3c, 0xee, 0xe0, 0x8b, 0xeb, 0x37, 0x8b, 0xec, 0xf4, + 0xd7, 0xac, 0xf2, 0xf6, 0xf0, 0x3d, 0xaf, 0xdd, 0x75, 0x91, 0x33, 0x19, + 0x1d, 0x1c, 0x40, 0xcb, 0x74, 0x24, 0x19, 0x21, 0x93, 0xd9, 0x14, 0xfe, + 0xac, 0x2a, 0x52, 0xc7, 0x8f, 0xd5, 0x04, 0x49, 0xe4, 0x8d, 0x63, 0x47, + 0x88, 0x3c, 0x69, 0x83, 0xcb, 0xfe, 0x47, 0xbd, 0x2b, 0x7e, 0x4f, 0xc5, + 0x95, 0xae, 0x0e, 0x9d, 0xd4, 0xd1, 0x43, 0xc0, 0x67, 0x73, 0xe3, 0x14, + 0x08, 0x7e, 0xe5, 0x3f, 0x9f, 0x73, 0xb8, 0x33, 0x0a, 0xcf, 0x5d, 0x3f, + 0x34, 0x87, 0x96, 0x8a, 0xee, 0x53, 0xe8, 0x25, 0x15, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x91, 0x30, 0x82, 0x01, 0x8d, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, + 0x30, 0x28, 0x30, 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, + 0x61, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, + 0x73, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x34, 0x06, 0x03, + 0x55, 0x1d, 0x25, 0x04, 0x2d, 0x30, 0x2b, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, + 0x86, 0xf8, 0x45, 0x01, 0x08, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x02, 0x30, 0x6d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, 0xa1, 0x5d, 0xa0, 0x5b, 0x30, 0x59, + 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, + 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, + 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x8f, 0xe5, 0xd3, 0x1a, 0x86, 0xac, + 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, 0x6a, 0xd4, 0x48, 0x18, 0x2c, 0x7b, + 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, + 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x73, 0x6c, 0x6f, 0x67, + 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, + 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x0f, 0x25, 0xae, 0x48, 0xed, 0x1b, + 0x33, 0x85, 0x4c, 0x0c, 0xb5, 0xc2, 0xd7, 0xfe, 0x4d, 0xd6, 0x83, 0x28, + 0x4c, 0x41, 0x65, 0x60, 0x00, 0x0b, 0x77, 0x48, 0x71, 0x82, 0xfe, 0x7f, + 0xdb, 0x5a, 0x0e, 0x20, 0xcc, 0xd2, 0xea, 0x47, 0xbc, 0x64, 0x42, 0x61, + 0x44, 0x34, 0x74, 0x30, 0x81, 0x81, 0x26, 0x8a, 0x4a, 0xf7, 0x44, 0x5d, + 0x7e, 0x34, 0x80, 0xa8, 0xb8, 0x83, 0xe2, 0x09, 0xd7, 0x6d, 0x23, 0xdd, + 0x89, 0xed, 0x28, 0x08, 0xbd, 0x63, 0x5a, 0x11, 0x57, 0x08, 0xc4, 0x9e, + 0xda, 0xe2, 0x68, 0x28, 0xaf, 0xdd, 0x50, 0x3c, 0xec, 0x82, 0x21, 0xd8, + 0x00, 0xc2, 0x55, 0x44, 0x50, 0x70, 0x41, 0xad, 0x83, 0x17, 0x79, 0xba, + 0x08, 0xf3, 0x2b, 0xde, 0xed, 0x34, 0x1d, 0x44, 0x9e, 0xd2, 0x04, 0x93, + 0xf4, 0xcb, 0x05, 0x17, 0x2d, 0x09, 0x2d, 0x2d, 0x63, 0xef, 0xf6, 0x26, + 0x0b, 0x7b, +} + +var certSet2Cert31 = []byte{ + 0x30, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x03, 0xb8, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x83, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, + 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, + 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x28, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, + 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x81, 0xb4, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, + 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, + 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, + 0x72, 0x74, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x2f, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x2a, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xb9, 0xe0, 0xcb, 0x10, 0xd4, 0xaf, 0x76, + 0xbd, 0xd4, 0x93, 0x62, 0xeb, 0x30, 0x64, 0xb8, 0x81, 0x08, 0x6c, 0xc3, + 0x04, 0xd9, 0x62, 0x17, 0x8e, 0x2f, 0xff, 0x3e, 0x65, 0xcf, 0x8f, 0xce, + 0x62, 0xe6, 0x3c, 0x52, 0x1c, 0xda, 0x16, 0x45, 0x4b, 0x55, 0xab, 0x78, + 0x6b, 0x63, 0x83, 0x62, 0x90, 0xce, 0x0f, 0x69, 0x6c, 0x99, 0xc8, 0x1a, + 0x14, 0x8b, 0x4c, 0xcc, 0x45, 0x33, 0xea, 0x88, 0xdc, 0x9e, 0xa3, 0xaf, + 0x2b, 0xfe, 0x80, 0x61, 0x9d, 0x79, 0x57, 0xc4, 0xcf, 0x2e, 0xf4, 0x3f, + 0x30, 0x3c, 0x5d, 0x47, 0xfc, 0x9a, 0x16, 0xbc, 0xc3, 0x37, 0x96, 0x41, + 0x51, 0x8e, 0x11, 0x4b, 0x54, 0xf8, 0x28, 0xbe, 0xd0, 0x8c, 0xbe, 0xf0, + 0x30, 0x38, 0x1e, 0xf3, 0xb0, 0x26, 0xf8, 0x66, 0x47, 0x63, 0x6d, 0xde, + 0x71, 0x26, 0x47, 0x8f, 0x38, 0x47, 0x53, 0xd1, 0x46, 0x1d, 0xb4, 0xe3, + 0xdc, 0x00, 0xea, 0x45, 0xac, 0xbd, 0xbc, 0x71, 0xd9, 0xaa, 0x6f, 0x00, + 0xdb, 0xdb, 0xcd, 0x30, 0x3a, 0x79, 0x4f, 0x5f, 0x4c, 0x47, 0xf8, 0x1d, + 0xef, 0x5b, 0xc2, 0xc4, 0x9d, 0x60, 0x3b, 0xb1, 0xb2, 0x43, 0x91, 0xd8, + 0xa4, 0x33, 0x4e, 0xea, 0xb3, 0xd6, 0x27, 0x4f, 0xad, 0x25, 0x8a, 0xa5, + 0xc6, 0xf4, 0xd5, 0xd0, 0xa6, 0xae, 0x74, 0x05, 0x64, 0x57, 0x88, 0xb5, + 0x44, 0x55, 0xd4, 0x2d, 0x2a, 0x3a, 0x3e, 0xf8, 0xb8, 0xbd, 0xe9, 0x32, + 0x0a, 0x02, 0x94, 0x64, 0xc4, 0x16, 0x3a, 0x50, 0xf1, 0x4a, 0xae, 0xe7, + 0x79, 0x33, 0xaf, 0x0c, 0x20, 0x07, 0x7f, 0xe8, 0xdf, 0x04, 0x39, 0xc2, + 0x69, 0x02, 0x6c, 0x63, 0x52, 0xfa, 0x77, 0xc1, 0x1b, 0xc8, 0x74, 0x87, + 0xc8, 0xb9, 0x93, 0x18, 0x50, 0x54, 0x35, 0x4b, 0x69, 0x4e, 0xbc, 0x3b, + 0xd3, 0x49, 0x2e, 0x1f, 0xdc, 0xc1, 0xd2, 0x52, 0xfb, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1a, 0x30, 0x82, 0x01, 0x16, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x40, 0xc2, 0xbd, 0x27, 0x8e, 0xcc, + 0x34, 0x83, 0x30, 0xa2, 0x33, 0xd7, 0xfb, 0x6c, 0xb3, 0xf0, 0xb4, 0x2c, + 0x80, 0xce, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x3a, 0x9a, 0x85, 0x07, 0x10, 0x67, 0x28, 0xb6, 0xef, + 0xf6, 0xbd, 0x05, 0x41, 0x6e, 0x20, 0xc1, 0x94, 0xda, 0x0f, 0xde, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, + 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, + 0x64, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x67, 0x32, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, + 0x3b, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x33, 0x30, 0x31, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, + 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x08, 0x7e, 0x6c, 0x93, + 0x10, 0xc8, 0x38, 0xb8, 0x96, 0xa9, 0x90, 0x4b, 0xff, 0xa1, 0x5f, 0x4f, + 0x04, 0xef, 0x6c, 0x3e, 0x9c, 0x88, 0x06, 0xc9, 0x50, 0x8f, 0xa6, 0x73, + 0xf7, 0x57, 0x31, 0x1b, 0xbe, 0xbc, 0xe4, 0x2f, 0xdb, 0xf8, 0xba, 0xd3, + 0x5b, 0xe0, 0xb4, 0xe7, 0xe6, 0x79, 0x62, 0x0e, 0x0c, 0xa2, 0xd7, 0x6a, + 0x63, 0x73, 0x31, 0xb5, 0xf5, 0xa8, 0x48, 0xa4, 0x3b, 0x08, 0x2d, 0xa2, + 0x5d, 0x90, 0xd7, 0xb4, 0x7c, 0x25, 0x4f, 0x11, 0x56, 0x30, 0xc4, 0xb6, + 0x44, 0x9d, 0x7b, 0x2c, 0x9d, 0xe5, 0x5e, 0xe6, 0xef, 0x0c, 0x61, 0xaa, + 0xbf, 0xe4, 0x2a, 0x1b, 0xee, 0x84, 0x9e, 0xb8, 0x83, 0x7d, 0xc1, 0x43, + 0xce, 0x44, 0xa7, 0x13, 0x70, 0x0d, 0x91, 0x1f, 0xf4, 0xc8, 0x13, 0xad, + 0x83, 0x60, 0xd9, 0xd8, 0x72, 0xa8, 0x73, 0x24, 0x1e, 0xb5, 0xac, 0x22, + 0x0e, 0xca, 0x17, 0x89, 0x62, 0x58, 0x44, 0x1b, 0xab, 0x89, 0x25, 0x01, + 0x00, 0x0f, 0xcd, 0xc4, 0x1b, 0x62, 0xdb, 0x51, 0xb4, 0xd3, 0x0f, 0x51, + 0x2a, 0x9b, 0xf4, 0xbc, 0x73, 0xfc, 0x76, 0xce, 0x36, 0xa4, 0xcd, 0xd9, + 0xd8, 0x2c, 0xea, 0xae, 0x9b, 0xf5, 0x2a, 0xb2, 0x90, 0xd1, 0x4d, 0x75, + 0x18, 0x8a, 0x3f, 0x8a, 0x41, 0x90, 0x23, 0x7d, 0x5b, 0x4b, 0xfe, 0xa4, + 0x03, 0x58, 0x9b, 0x46, 0xb2, 0xc3, 0x60, 0x60, 0x83, 0xf8, 0x7d, 0x50, + 0x41, 0xce, 0xc2, 0xa1, 0x90, 0xc3, 0xbb, 0xef, 0x02, 0x2f, 0xd2, 0x15, + 0x54, 0xee, 0x44, 0x15, 0xd9, 0x0a, 0xae, 0xa7, 0x8a, 0x33, 0xed, 0xb1, + 0x2d, 0x76, 0x36, 0x26, 0xdc, 0x04, 0xeb, 0x9f, 0xf7, 0x61, 0x1f, 0x15, + 0xdc, 0x87, 0x6f, 0xee, 0x46, 0x96, 0x28, 0xad, 0xa1, 0x26, 0x7d, 0x0a, + 0x09, 0xa7, 0x2e, 0x04, 0xa3, 0x8d, 0xbc, 0xf8, 0xbc, 0x04, 0x30, 0x01, +} + +var certSet2Cert32 = []byte{ + 0x30, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x03, 0xb8, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x0a, 0x48, 0x9e, 0x88, 0x53, 0x7e, 0x8a, 0xa6, 0x45, + 0x4d, 0x6e, 0x2c, 0x4b, 0x2a, 0xeb, 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xae, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x38, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1b, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x33, 0x30, 0x34, 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x17, 0x0d, 0x32, 0x33, 0x30, 0x34, 0x30, 0x38, 0x32, 0x33, 0x35, 0x39, + 0x35, 0x39, 0x5a, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x28, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xf2, 0xc4, 0xbc, 0x74, 0xe8, 0x25, 0xf6, + 0x00, 0x62, 0x28, 0xe3, 0x4c, 0xe8, 0xb8, 0xdf, 0x13, 0x9f, 0x8b, 0x07, + 0x37, 0xef, 0x62, 0x4a, 0xf1, 0x57, 0x09, 0xf6, 0x82, 0xe8, 0x75, 0xf0, + 0x0a, 0xa9, 0x27, 0xcf, 0x93, 0x3b, 0xec, 0x36, 0x89, 0xa5, 0x6e, 0x1d, + 0xd6, 0x54, 0xf3, 0xb8, 0x04, 0x97, 0x72, 0xb4, 0x69, 0x25, 0xcc, 0xd1, + 0x42, 0x0e, 0x5b, 0xd5, 0x1c, 0x7f, 0xa2, 0x60, 0x6e, 0xb1, 0x52, 0x1a, + 0xdb, 0x93, 0x2f, 0xbb, 0x0b, 0x0d, 0x64, 0x53, 0x16, 0xcb, 0x1c, 0x09, + 0x24, 0x95, 0x29, 0x22, 0xb4, 0x8a, 0x18, 0x00, 0x89, 0xfe, 0xf7, 0x1f, + 0x72, 0xc8, 0xe8, 0x5c, 0x2f, 0x1a, 0x1b, 0xa2, 0x18, 0xb8, 0xef, 0x18, + 0x5c, 0xcb, 0xb5, 0xdb, 0x3a, 0x4e, 0xdb, 0x0f, 0xae, 0xdf, 0xc4, 0x79, + 0xe3, 0x1e, 0xaa, 0x5c, 0xa3, 0xa4, 0xe5, 0xac, 0x61, 0x9b, 0x37, 0x85, + 0x8f, 0x48, 0x75, 0x1b, 0xb9, 0xd5, 0x68, 0x96, 0xe9, 0x27, 0x79, 0x70, + 0x57, 0x23, 0x1a, 0xbb, 0x6c, 0x93, 0x90, 0xc7, 0x45, 0xd7, 0x17, 0xd2, + 0x37, 0x2a, 0x76, 0xb3, 0xcd, 0x82, 0xa9, 0x4f, 0xc0, 0x03, 0x7b, 0xe1, + 0x3d, 0x7a, 0x7e, 0x5b, 0xb8, 0x85, 0xf2, 0xf5, 0x15, 0xfb, 0x70, 0xa9, + 0xbd, 0xf5, 0x50, 0x65, 0x16, 0x9d, 0xe3, 0xb6, 0x6b, 0x61, 0x6e, 0xa1, + 0x7a, 0x9e, 0xe8, 0x0d, 0x1c, 0xf7, 0x2a, 0x8e, 0x69, 0x7e, 0x43, 0x30, + 0x8e, 0x78, 0xce, 0xee, 0x65, 0x1e, 0x3b, 0x9b, 0x87, 0x1e, 0x49, 0x1c, + 0xf8, 0x32, 0x46, 0x5d, 0x28, 0x46, 0x79, 0x2a, 0x4e, 0x27, 0x5d, 0x17, + 0x58, 0xa8, 0x37, 0xfe, 0xa8, 0x13, 0xa9, 0x69, 0x15, 0xdf, 0x36, 0x22, + 0x89, 0x75, 0xba, 0xca, 0x01, 0x40, 0x2e, 0xed, 0x9d, 0xd7, 0x0c, 0xaa, + 0x31, 0xce, 0x27, 0xae, 0x57, 0xd5, 0xd2, 0x51, 0xfb, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x3e, 0x30, 0x82, 0x01, 0x3a, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, + 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x32, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x26, + 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, + 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, + 0x32, 0x30, 0x30, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, + 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, + 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x70, 0x73, 0x30, 0x37, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x30, + 0x30, 0x2e, 0x30, 0x2c, 0xa0, 0x2a, 0xa0, 0x28, 0x86, 0x26, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, + 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x50, 0x43, 0x41, 0x2d, 0x47, 0x33, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x2a, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x23, 0x30, 0x21, 0xa4, + 0x1f, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x12, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, + 0x4b, 0x49, 0x2d, 0x32, 0x2d, 0x33, 0x37, 0x34, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3b, 0x24, 0xc8, 0x31, 0xa0, + 0xb7, 0x5a, 0xd0, 0x6a, 0xb8, 0xd2, 0xca, 0x07, 0x74, 0xcc, 0x1e, 0x24, + 0xd4, 0xc4, 0xdc, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, + 0x30, 0x16, 0x80, 0x14, 0xad, 0x6c, 0xaa, 0x94, 0x60, 0x9c, 0xed, 0xe4, + 0xff, 0xfa, 0x3e, 0x0a, 0x74, 0x2b, 0x63, 0x03, 0xf7, 0xb6, 0x59, 0xbf, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x68, 0x98, 0x26, 0xaa, + 0xd4, 0x33, 0xc9, 0xba, 0x75, 0x70, 0xd4, 0x9f, 0x49, 0xad, 0xd6, 0xc1, + 0x54, 0xdc, 0xee, 0xaa, 0x56, 0x1f, 0x78, 0xa7, 0xf0, 0xa1, 0xa4, 0xee, + 0x0b, 0xf9, 0x12, 0xaf, 0xdf, 0xa6, 0xb8, 0xee, 0xc3, 0xcb, 0x35, 0x13, + 0x6a, 0x59, 0x2a, 0xf8, 0xc9, 0xe9, 0x4c, 0x2f, 0xbc, 0xb1, 0xbc, 0x2b, + 0xc2, 0x02, 0x30, 0xe1, 0xc3, 0xbe, 0xc2, 0xf0, 0x81, 0x8c, 0x99, 0x77, + 0x89, 0x58, 0x00, 0xa3, 0xcc, 0x7f, 0xa3, 0x02, 0x4c, 0x53, 0xb2, 0x6e, + 0x36, 0x4f, 0xfe, 0xdf, 0x87, 0x76, 0xb3, 0x3f, 0xec, 0x5a, 0x62, 0x50, + 0xb6, 0x00, 0x45, 0x58, 0xf2, 0x87, 0xac, 0x77, 0xe6, 0xd0, 0x20, 0x50, + 0x63, 0xc5, 0xe4, 0xb2, 0x70, 0x15, 0x18, 0x90, 0x05, 0x7b, 0x7b, 0xaf, + 0x2b, 0x46, 0xbe, 0x6b, 0x4e, 0x1f, 0x53, 0xfc, 0x84, 0x27, 0xae, 0x83, + 0xd2, 0x8d, 0x47, 0x53, 0xa7, 0x0e, 0x1f, 0x63, 0xb5, 0xba, 0xdb, 0x16, + 0xd8, 0x6a, 0x09, 0x25, 0x55, 0x7d, 0x8f, 0x3d, 0x4a, 0xc1, 0x83, 0xf9, + 0xb3, 0xb9, 0xa7, 0x04, 0x5a, 0xc8, 0xf3, 0x11, 0x04, 0x91, 0x53, 0x30, + 0xd9, 0x52, 0x87, 0xcb, 0x39, 0x00, 0x9c, 0xec, 0x53, 0xc3, 0x02, 0x09, + 0x7e, 0xa7, 0x36, 0x8e, 0x72, 0x21, 0x2f, 0x23, 0xbb, 0x4c, 0xc6, 0x47, + 0xa5, 0xa1, 0xee, 0x67, 0xc4, 0x2f, 0x5c, 0x3a, 0x47, 0x38, 0x61, 0xe2, + 0xc3, 0x1e, 0x37, 0x92, 0x9e, 0xc8, 0x2f, 0x6b, 0xfa, 0xef, 0xd2, 0xc3, + 0xcd, 0x29, 0x8d, 0x98, 0xf8, 0x52, 0x17, 0xed, 0xb5, 0x53, 0x3c, 0xdf, + 0xaf, 0xc9, 0x1b, 0x62, 0xad, 0xdf, 0x02, 0xee, 0x5d, 0x34, 0xf6, 0x41, + 0x4b, 0xcb, 0xc3, 0x55, 0xaf, 0xb1, 0xcb, 0xda, 0x9c, 0x73, 0xd5, 0x02, + 0xa8, 0x2d, 0xa7, 0xac, 0xfc, 0xe1, 0xe5, 0x07, 0xd0, 0x51, 0xe8, 0x35, +} + +var certSet2Cert33 = []byte{ + 0x30, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x04, 0x39, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x25, 0x0c, 0xe8, 0xe0, 0x30, 0x61, 0x2e, 0x9f, 0x2b, + 0x89, 0xf7, 0x05, 0x4d, 0x7c, 0xf8, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xca, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3a, 0x30, + 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, 0x63, 0x29, 0x20, + 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, + 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, + 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x45, 0x30, + 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, 0x24, 0x08, 0x08, 0x29, 0x7a, 0x35, + 0x9e, 0x60, 0x0c, 0xaa, 0xe7, 0x4b, 0x3b, 0x4e, 0xdc, 0x7c, 0xbc, 0x3c, + 0x45, 0x1c, 0xbb, 0x2b, 0xe0, 0xfe, 0x29, 0x02, 0xf9, 0x57, 0x08, 0xa3, + 0x64, 0x85, 0x15, 0x27, 0xf5, 0xf1, 0xad, 0xc8, 0x31, 0x89, 0x5d, 0x22, + 0xe8, 0x2a, 0xaa, 0xa6, 0x42, 0xb3, 0x8f, 0xf8, 0xb9, 0x55, 0xb7, 0xb1, + 0xb7, 0x4b, 0xb3, 0xfe, 0x8f, 0x7e, 0x07, 0x57, 0xec, 0xef, 0x43, 0xdb, + 0x66, 0x62, 0x15, 0x61, 0xcf, 0x60, 0x0d, 0xa4, 0xd8, 0xde, 0xf8, 0xe0, + 0xc3, 0x62, 0x08, 0x3d, 0x54, 0x13, 0xeb, 0x49, 0xca, 0x59, 0x54, 0x85, + 0x26, 0xe5, 0x2b, 0x8f, 0x1b, 0x9f, 0xeb, 0xf5, 0xa1, 0x91, 0xc2, 0x33, + 0x49, 0xd8, 0x43, 0x63, 0x6a, 0x52, 0x4b, 0xd2, 0x8f, 0xe8, 0x70, 0x51, + 0x4d, 0xd1, 0x89, 0x69, 0x7b, 0xc7, 0x70, 0xf6, 0xb3, 0xdc, 0x12, 0x74, + 0xdb, 0x7b, 0x5d, 0x4b, 0x56, 0xd3, 0x96, 0xbf, 0x15, 0x77, 0xa1, 0xb0, + 0xf4, 0xa2, 0x25, 0xf2, 0xaf, 0x1c, 0x92, 0x67, 0x18, 0xe5, 0xf4, 0x06, + 0x04, 0xef, 0x90, 0xb9, 0xe4, 0x00, 0xe4, 0xdd, 0x3a, 0xb5, 0x19, 0xff, + 0x02, 0xba, 0xf4, 0x3c, 0xee, 0xe0, 0x8b, 0xeb, 0x37, 0x8b, 0xec, 0xf4, + 0xd7, 0xac, 0xf2, 0xf6, 0xf0, 0x3d, 0xaf, 0xdd, 0x75, 0x91, 0x33, 0x19, + 0x1d, 0x1c, 0x40, 0xcb, 0x74, 0x24, 0x19, 0x21, 0x93, 0xd9, 0x14, 0xfe, + 0xac, 0x2a, 0x52, 0xc7, 0x8f, 0xd5, 0x04, 0x49, 0xe4, 0x8d, 0x63, 0x47, + 0x88, 0x3c, 0x69, 0x83, 0xcb, 0xfe, 0x47, 0xbd, 0x2b, 0x7e, 0x4f, 0xc5, + 0x95, 0xae, 0x0e, 0x9d, 0xd4, 0xd1, 0x43, 0xc0, 0x67, 0x73, 0xe3, 0x14, + 0x08, 0x7e, 0xe5, 0x3f, 0x9f, 0x73, 0xb8, 0x33, 0x0a, 0xcf, 0x5d, 0x3f, + 0x34, 0x87, 0x96, 0x8a, 0xee, 0x53, 0xe8, 0x25, 0x15, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x9b, 0x30, 0x82, 0x01, 0x97, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, + 0x30, 0x28, 0x30, 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, + 0x61, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, + 0x73, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x6d, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, + 0xa1, 0x5d, 0xa0, 0x5b, 0x30, 0x59, 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, + 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, + 0x8f, 0xe5, 0xd3, 0x1a, 0x86, 0xac, 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, + 0x6a, 0xd4, 0x48, 0x18, 0x2c, 0x7b, 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x76, 0x73, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x1d, 0x25, + 0x04, 0x37, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, 0x06, 0x0a, 0x60, + 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x08, 0x01, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x13, 0x02, 0xdd, 0xf8, 0xe8, 0x86, 0x00, 0xf2, + 0x5a, 0xf8, 0xf8, 0x20, 0x0c, 0x59, 0x88, 0x62, 0x07, 0xce, 0xce, 0xf7, + 0x4e, 0xf9, 0xbb, 0x59, 0xa1, 0x98, 0xe5, 0xe1, 0x38, 0xdd, 0x4e, 0xbc, + 0x66, 0x18, 0xd3, 0xad, 0xeb, 0x18, 0xf2, 0x0d, 0xc9, 0x6d, 0x3e, 0x4a, + 0x94, 0x20, 0xc3, 0x3c, 0xba, 0xbd, 0x65, 0x54, 0xc6, 0xaf, 0x44, 0xb3, + 0x10, 0xad, 0x2c, 0x6b, 0x3e, 0xab, 0xd7, 0x07, 0xb6, 0xb8, 0x81, 0x63, + 0xc5, 0xf9, 0x5e, 0x2e, 0xe5, 0x2a, 0x67, 0xce, 0xcd, 0x33, 0x0c, 0x2a, + 0xd7, 0x89, 0x56, 0x03, 0x23, 0x1f, 0xb3, 0xbe, 0xe8, 0x3a, 0x08, 0x59, + 0xb4, 0xec, 0x45, 0x35, 0xf7, 0x8a, 0x5b, 0xff, 0x66, 0xcf, 0x50, 0xaf, + 0xc6, 0x6d, 0x57, 0x8d, 0x19, 0x78, 0xb7, 0xb9, 0xa2, 0xd1, 0x57, 0xea, + 0x1f, 0x9a, 0x4b, 0xaf, 0xba, 0xc9, 0x8e, 0x12, 0x7e, 0xc6, 0xbd, 0xff, +} + +var certSet2Cert34 = []byte{ + 0x30, 0x82, 0x04, 0xd2, 0x30, 0x82, 0x03, 0xba, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x2c, 0x69, 0xe1, 0x2f, 0x6a, 0x67, 0x0b, 0xd9, 0x9d, + 0xd2, 0x0f, 0x91, 0x9e, 0xf0, 0x9e, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, + 0x36, 0x30, 0x39, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x63, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x14, 0x44, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x20, 0x53, 0x53, 0x4c, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x20, 0x44, 0x56, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xea, 0x94, 0x07, 0x85, 0xc8, 0x41, 0x2c, 0xf6, 0x83, 0x12, 0x6c, 0x92, + 0x5f, 0xab, 0x1f, 0x00, 0xd4, 0x96, 0x6f, 0x74, 0xcd, 0x2e, 0x11, 0xe9, + 0x6c, 0x0f, 0x39, 0x01, 0xb9, 0x48, 0x90, 0x40, 0x39, 0x4d, 0xc4, 0xa2, + 0xc8, 0x79, 0x6a, 0xa5, 0x9a, 0xbd, 0x91, 0x44, 0x65, 0x77, 0x54, 0xad, + 0xff, 0x25, 0x5f, 0xee, 0x42, 0xfb, 0xb3, 0x02, 0x0f, 0xea, 0x5d, 0x7a, + 0xdd, 0x1a, 0x54, 0x9e, 0xd7, 0x73, 0x42, 0x9b, 0xcc, 0x79, 0x5f, 0xc5, + 0x4d, 0xf4, 0xb7, 0x0b, 0x18, 0x39, 0x20, 0x7a, 0xdd, 0x50, 0x01, 0x5d, + 0x34, 0x45, 0x5f, 0x4c, 0x11, 0x0e, 0xf5, 0x87, 0x26, 0x26, 0xb4, 0xb0, + 0xf3, 0x7e, 0x71, 0xa0, 0x31, 0x71, 0x50, 0x89, 0x68, 0x5a, 0x63, 0x8a, + 0x14, 0x62, 0xe5, 0x8c, 0x3a, 0x16, 0x55, 0x0d, 0x3e, 0xeb, 0xaa, 0x80, + 0x1d, 0x71, 0x7a, 0xe3, 0x87, 0x07, 0xab, 0xbd, 0xa2, 0x74, 0xcd, 0xda, + 0x08, 0x01, 0x9d, 0x1b, 0xcc, 0x27, 0x88, 0x8c, 0x47, 0xd4, 0x69, 0x25, + 0x42, 0xd6, 0xbb, 0x50, 0x6d, 0x85, 0x50, 0xd0, 0x48, 0x82, 0x0d, 0x08, + 0x9f, 0xe9, 0x23, 0xe3, 0x42, 0xc6, 0x3c, 0x98, 0xb8, 0xbb, 0x6e, 0xc5, + 0x70, 0x13, 0xdf, 0x19, 0x1d, 0x01, 0xfd, 0xd2, 0xb5, 0x4e, 0xe6, 0x62, + 0xf4, 0x07, 0xfa, 0x6b, 0x7d, 0x11, 0x77, 0xc4, 0x62, 0x4f, 0x40, 0x4e, + 0xa5, 0x78, 0x97, 0xab, 0x2c, 0x4d, 0x0c, 0xa7, 0x7c, 0xc3, 0xc4, 0x50, + 0x32, 0x9f, 0xd0, 0x70, 0x9b, 0x0f, 0xff, 0xff, 0x75, 0x59, 0x34, 0x85, + 0xad, 0x49, 0xd5, 0x35, 0xee, 0x4f, 0x5b, 0xd4, 0xd4, 0x36, 0x95, 0xa0, + 0x7e, 0xe8, 0xc5, 0xa1, 0x1c, 0xbd, 0x13, 0x4e, 0x7d, 0xee, 0x63, 0x6a, + 0x96, 0x19, 0x99, 0xc8, 0xa7, 0x2a, 0x00, 0xe6, 0x51, 0x8d, 0x46, 0xeb, + 0x30, 0x58, 0xe8, 0x2d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x39, 0x30, 0x82, 0x01, 0x35, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x41, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3a, 0x30, 0x38, + 0x30, 0x36, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, + 0x07, 0x36, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, + 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x74, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, 0x30, 0x28, 0x30, + 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x74, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x29, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, + 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, + 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x36, 0x39, 0x38, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9f, 0xb8, 0xc1, + 0xa9, 0x6c, 0xf2, 0xf5, 0xc0, 0x22, 0x2a, 0x94, 0xed, 0x5c, 0x99, 0xac, + 0xd4, 0xec, 0xd7, 0xc6, 0x07, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7b, 0x5b, 0x45, 0xcf, 0xaf, 0xce, + 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, 0x6a, 0xb6, 0xf3, 0x46, 0xeb, 0x57, + 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x53, 0x54, + 0xf2, 0x47, 0xa8, 0x02, 0xd7, 0xef, 0xaa, 0x35, 0x78, 0xbe, 0x4a, 0x08, + 0x0d, 0x90, 0x18, 0x4b, 0x6d, 0x9e, 0x2a, 0x53, 0x2b, 0xe9, 0x54, 0x17, + 0x77, 0x74, 0x29, 0x7e, 0xd0, 0x37, 0x07, 0x05, 0xb8, 0xe4, 0xfa, 0xb8, + 0xb4, 0x63, 0x98, 0x44, 0xdc, 0xc6, 0x4f, 0x81, 0x06, 0x8c, 0x3a, 0xbe, + 0xc7, 0x30, 0x57, 0xc6, 0x70, 0xfc, 0xd6, 0x93, 0x19, 0x9f, 0xc3, 0x55, + 0xd7, 0x3e, 0x1f, 0x72, 0x8a, 0x9d, 0x30, 0x5a, 0x35, 0x97, 0x32, 0xcb, + 0x63, 0xe4, 0xc6, 0x72, 0xdf, 0xfb, 0x68, 0xca, 0x69, 0x2f, 0xdb, 0xcd, + 0x50, 0x38, 0x3e, 0x2b, 0xbb, 0xab, 0x3b, 0x82, 0xc7, 0xfd, 0x4b, 0x9b, + 0xbd, 0x7c, 0x41, 0x98, 0xef, 0x01, 0x53, 0xd8, 0x35, 0x8f, 0x25, 0xc9, + 0x03, 0x06, 0xe6, 0x9c, 0x57, 0xc1, 0x51, 0x0f, 0x9e, 0xf6, 0x7d, 0x93, + 0x4d, 0xf8, 0x76, 0xc8, 0x3a, 0x6b, 0xf4, 0xc4, 0x8f, 0x33, 0x32, 0x7f, + 0x9d, 0x21, 0x84, 0x34, 0xd9, 0xa7, 0xf9, 0x92, 0xfa, 0x41, 0x91, 0x61, + 0x84, 0x05, 0x9d, 0xa3, 0x79, 0x46, 0xce, 0x67, 0xe7, 0x81, 0xf2, 0x5e, + 0xac, 0x4c, 0xbc, 0xa8, 0xab, 0x6a, 0x6d, 0x15, 0xe2, 0x9c, 0x4e, 0x5a, + 0xd9, 0x63, 0x80, 0xbc, 0xf7, 0x42, 0xeb, 0x9a, 0x44, 0xc6, 0x8c, 0x6b, + 0x06, 0x36, 0xb4, 0x8b, 0x32, 0x89, 0xde, 0xc2, 0xf1, 0xa8, 0x26, 0xaa, + 0xa9, 0xac, 0xff, 0xea, 0x71, 0xa6, 0xe7, 0x8c, 0x41, 0xfa, 0x17, 0x35, + 0xbb, 0xb3, 0x87, 0x31, 0xa9, 0x93, 0xc2, 0xc8, 0x58, 0xe1, 0x0a, 0x4e, + 0x95, 0x83, 0x9c, 0xb9, 0xed, 0x3b, 0xa5, 0xef, 0x08, 0xe0, 0x74, 0xf9, + 0xc3, 0x1b, 0xe6, 0x07, 0xa3, 0xee, 0x07, 0xd7, 0x42, 0x22, 0x79, 0x21, + 0xa0, 0xa1, 0xd4, 0x1d, 0x26, 0xd3, 0xd0, 0xd6, 0xa6, 0x5d, 0x2b, 0x41, + 0xc0, 0x79, +} + +var certSet2Cert35 = []byte{ + 0x30, 0x82, 0x04, 0xe4, 0x30, 0x82, 0x03, 0xcc, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x4f, 0xe3, 0xe2, 0x65, 0x21, 0x07, 0xab, 0x20, 0x37, + 0x41, 0x6e, 0x48, 0x70, 0xce, 0xd2, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x6f, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x53, + 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x31, + 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, 0x41, 0x64, + 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x35, 0x32, + 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, + 0x30, 0x35, 0x33, 0x30, 0x31, 0x30, 0x34, 0x38, 0x33, 0x38, 0x5a, 0x30, + 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x24, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x80, 0x0b, 0x42, + 0xc6, 0x06, 0x6c, 0xcf, 0x22, 0xb3, 0x1a, 0x9e, 0x11, 0x2e, 0x42, 0x6e, + 0x39, 0xbf, 0xe8, 0x12, 0xaf, 0x3c, 0x42, 0x21, 0x12, 0x95, 0x40, 0x5d, + 0x32, 0xb1, 0x6d, 0x1c, 0x21, 0xd1, 0x34, 0xe5, 0x4f, 0xa8, 0xd1, 0x43, + 0xa2, 0x26, 0x4e, 0x30, 0x7d, 0x73, 0x44, 0x2c, 0x73, 0xaa, 0xc5, 0x4d, + 0x66, 0x01, 0x19, 0xd2, 0xea, 0x50, 0x59, 0x65, 0xd0, 0x68, 0x9d, 0x05, + 0xa0, 0x7c, 0xa1, 0x79, 0x53, 0xd0, 0x21, 0x90, 0x59, 0x0e, 0x37, 0xdb, + 0x1e, 0xdc, 0x92, 0xa7, 0x8b, 0x0d, 0xc4, 0xf5, 0xf8, 0xe6, 0xff, 0xb5, + 0x35, 0x1a, 0xda, 0xa8, 0xb6, 0x9b, 0x20, 0x85, 0x65, 0xc4, 0xa2, 0x4d, + 0xdf, 0xf3, 0x94, 0x4d, 0x63, 0x7e, 0xee, 0x89, 0x07, 0xaf, 0xfe, 0xe1, + 0xba, 0x00, 0x15, 0x2d, 0xc6, 0x77, 0x8e, 0xa3, 0xfe, 0xad, 0xcf, 0x26, + 0x54, 0x5a, 0xdf, 0xfc, 0xd2, 0xde, 0xc2, 0xad, 0xf6, 0xb2, 0x23, 0xfd, + 0xa8, 0x83, 0xe5, 0x65, 0xbd, 0x27, 0xf7, 0x27, 0x1a, 0x18, 0x59, 0x6a, + 0x9e, 0x14, 0xf6, 0xb4, 0x86, 0xff, 0x1c, 0x58, 0x14, 0x43, 0x73, 0x96, + 0x24, 0xbf, 0x10, 0x43, 0xd5, 0x5c, 0x89, 0xf0, 0xce, 0xf7, 0xe1, 0x96, + 0x16, 0x5e, 0x18, 0x4a, 0x27, 0x28, 0x90, 0x80, 0x18, 0xfc, 0x32, 0xfe, + 0xf4, 0xc7, 0xb8, 0xd6, 0x82, 0x3d, 0x35, 0xaf, 0xbb, 0x4a, 0x1c, 0x5b, + 0x05, 0x78, 0xf6, 0xfd, 0x55, 0x3e, 0x82, 0x74, 0xb2, 0x73, 0xb8, 0x89, + 0x4e, 0xf7, 0x1b, 0x85, 0x9a, 0xd8, 0xca, 0xb1, 0x5a, 0xb1, 0x00, 0x20, + 0x41, 0x14, 0x30, 0x2b, 0x14, 0x24, 0xed, 0x37, 0x0e, 0x32, 0x3e, 0x23, + 0x88, 0x39, 0x7e, 0xb9, 0xd9, 0x38, 0x03, 0xe2, 0x4c, 0xd9, 0x0d, 0x43, + 0x41, 0x33, 0x10, 0xeb, 0x30, 0x72, 0x53, 0x88, 0xf7, 0x52, 0x9b, 0x4f, + 0x81, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x7e, 0x30, 0x82, + 0x01, 0x7a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0xad, 0xbd, 0x98, 0x7a, 0x34, 0xb4, 0x26, 0xf7, 0xfa, + 0xc4, 0x26, 0x54, 0xef, 0x03, 0xbd, 0xe0, 0x24, 0xcb, 0x54, 0x1a, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcc, 0x03, + 0x5b, 0x96, 0x5a, 0x9e, 0x16, 0xcc, 0x26, 0x1e, 0xbd, 0xa3, 0x70, 0xfb, + 0xe3, 0xcb, 0x79, 0x19, 0xfc, 0x4d, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, + 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x18, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x11, 0x30, 0x0f, 0x30, 0x0d, 0x06, 0x0b, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x02, 0x08, 0x30, 0x44, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x3d, 0x30, 0x3b, 0x30, 0x39, 0xa0, 0x37, 0xa0, + 0x35, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x41, 0x52, 0x6f, + 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0xb3, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0xa6, 0x30, 0x81, + 0xa3, 0x30, 0x3f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x02, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x41, 0x52, 0x6f, + 0x6f, 0x74, 0x2e, 0x70, 0x37, 0x63, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x64, 0x64, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x55, 0x54, 0x4e, 0x53, 0x47, 0x43, 0x43, + 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x25, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x19, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x7b, 0xf0, 0xfc, 0xa1, 0x28, 0x47, 0xbc, 0x2b, + 0xb4, 0x04, 0x73, 0x3f, 0x4b, 0xdd, 0x1e, 0xd1, 0xb9, 0xcd, 0x1c, 0xed, + 0x7d, 0xe5, 0xe8, 0xcb, 0x51, 0xf4, 0x92, 0xbf, 0xdd, 0x9c, 0x0d, 0x5c, + 0x6e, 0x1d, 0x95, 0xed, 0x5b, 0x70, 0x50, 0x89, 0xd4, 0x67, 0x9a, 0x15, + 0x54, 0xd1, 0x90, 0x0a, 0xfa, 0x09, 0x68, 0x06, 0x18, 0xbb, 0xd7, 0x27, + 0xe4, 0x93, 0xff, 0x43, 0x48, 0x81, 0x3b, 0xc8, 0x59, 0x49, 0x35, 0xea, + 0xac, 0xb6, 0xae, 0x46, 0xb5, 0xd4, 0xf3, 0xb8, 0xc3, 0xc6, 0xe4, 0x91, + 0xbf, 0xc9, 0x34, 0xfd, 0x7e, 0xd0, 0x59, 0x6e, 0x61, 0xa1, 0x1f, 0x48, + 0x63, 0x54, 0xb2, 0x7d, 0x46, 0xbf, 0xc8, 0xfa, 0xc3, 0xbf, 0x48, 0x58, + 0x98, 0xf6, 0x69, 0x84, 0xa7, 0x16, 0x69, 0x08, 0x27, 0xa4, 0x22, 0xcb, + 0xa2, 0x2c, 0xc8, 0xdf, 0x6e, 0xa9, 0xee, 0xf8, 0x41, 0xdf, 0x1b, 0xa8, + 0xb7, 0xf3, 0xe3, 0xae, 0xce, 0xa3, 0xfe, 0xd9, 0x27, 0x60, 0x50, 0x3f, + 0x04, 0x7d, 0x7a, 0x44, 0xea, 0x76, 0x42, 0x5c, 0xd3, 0x55, 0x46, 0xef, + 0x27, 0xc5, 0x6a, 0x4a, 0x80, 0xe7, 0x35, 0xa0, 0x91, 0xc6, 0x1b, 0xa6, + 0x86, 0x9c, 0x5a, 0x3b, 0x04, 0x83, 0x54, 0x34, 0xd7, 0xd1, 0x88, 0xa6, + 0x36, 0xe9, 0x7f, 0x40, 0x27, 0xda, 0x56, 0x0a, 0x50, 0x21, 0x9d, 0x29, + 0x8b, 0xa0, 0x84, 0xec, 0xfe, 0x71, 0x23, 0x53, 0x04, 0x18, 0x19, 0x70, + 0x67, 0x86, 0x44, 0x95, 0x72, 0x40, 0x55, 0xf6, 0xdd, 0xa3, 0xb4, 0x3d, + 0x2d, 0x09, 0x60, 0xa5, 0xe7, 0x5f, 0xfc, 0xac, 0x3b, 0xec, 0x0c, 0x91, + 0x9f, 0xf8, 0xee, 0x6a, 0xba, 0xb2, 0x3c, 0xfd, 0x95, 0x7d, 0x9a, 0x07, + 0xf4, 0xb0, 0x65, 0x43, 0xa2, 0xf6, 0xdf, 0x7d, 0xb8, 0x21, 0x49, 0x84, + 0x04, 0xee, 0xbd, 0xce, 0x53, 0x8f, 0x0f, 0x29, +} + +var certSet2Cert36 = []byte{ + 0x30, 0x82, 0x04, 0xf2, 0x30, 0x82, 0x03, 0xda, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x38, 0x63, 0xe9, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xb4, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, + 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x31, + 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x14, 0x37, 0x77, 0x77, + 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x20, 0x69, + 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, + 0x66, 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x6c, + 0x69, 0x61, 0x62, 0x2e, 0x29, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x1c, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, + 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, + 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x33, 0x30, 0x31, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x45, 0x6e, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x28, 0x32, 0x30, 0x34, 0x38, + 0x29, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x31, 0x32, 0x31, 0x30, 0x32, + 0x30, 0x34, 0x33, 0x35, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, + 0x31, 0x30, 0x32, 0x31, 0x31, 0x33, 0x35, 0x34, 0x5a, 0x30, 0x81, 0xb1, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, + 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x30, + 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x70, 0x61, 0x20, 0x69, 0x73, 0x20, 0x69, + 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2e, 0x30, + 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x45, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x4c, 0x31, 0x43, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x97, 0xa3, 0x2d, 0x3c, 0x9e, 0xde, + 0x05, 0xda, 0x13, 0xc2, 0x11, 0x8d, 0x9d, 0x8e, 0xe3, 0x7f, 0xc7, 0x4b, + 0x7e, 0x5a, 0x9f, 0xb3, 0xff, 0x62, 0xab, 0x73, 0xc8, 0x28, 0x6b, 0xba, + 0x10, 0x64, 0x82, 0x87, 0x13, 0xcd, 0x57, 0x18, 0xff, 0x28, 0xce, 0xc0, + 0xe6, 0x0e, 0x06, 0x91, 0x50, 0x29, 0x83, 0xd1, 0xf2, 0xc3, 0x2a, 0xdb, + 0xd8, 0xdb, 0x4e, 0x04, 0xcc, 0x00, 0xeb, 0x8b, 0xb6, 0x96, 0xdc, 0xbc, + 0xaa, 0xfa, 0x52, 0x77, 0x04, 0xc1, 0xdb, 0x19, 0xe4, 0xae, 0x9c, 0xfd, + 0x3c, 0x8b, 0x03, 0xef, 0x4d, 0xbc, 0x1a, 0x03, 0x65, 0xf9, 0xc1, 0xb1, + 0x3f, 0x72, 0x86, 0xf2, 0x38, 0xaa, 0x19, 0xae, 0x10, 0x88, 0x78, 0x28, + 0xda, 0x75, 0xc3, 0x3d, 0x02, 0x82, 0x02, 0x9c, 0xb9, 0xc1, 0x65, 0x77, + 0x76, 0x24, 0x4c, 0x98, 0xf7, 0x6d, 0x31, 0x38, 0xfb, 0xdb, 0xfe, 0xdb, + 0x37, 0x02, 0x76, 0xa1, 0x18, 0x97, 0xa6, 0xcc, 0xde, 0x20, 0x09, 0x49, + 0x36, 0x24, 0x69, 0x42, 0xf6, 0xe4, 0x37, 0x62, 0xf1, 0x59, 0x6d, 0xa9, + 0x3c, 0xed, 0x34, 0x9c, 0xa3, 0x8e, 0xdb, 0xdc, 0x3a, 0xd7, 0xf7, 0x0a, + 0x6f, 0xef, 0x2e, 0xd8, 0xd5, 0x93, 0x5a, 0x7a, 0xed, 0x08, 0x49, 0x68, + 0xe2, 0x41, 0xe3, 0x5a, 0x90, 0xc1, 0x86, 0x55, 0xfc, 0x51, 0x43, 0x9d, + 0xe0, 0xb2, 0xc4, 0x67, 0xb4, 0xcb, 0x32, 0x31, 0x25, 0xf0, 0x54, 0x9f, + 0x4b, 0xd1, 0x6f, 0xdb, 0xd4, 0xdd, 0xfc, 0xaf, 0x5e, 0x6c, 0x78, 0x90, + 0x95, 0xde, 0xca, 0x3a, 0x48, 0xb9, 0x79, 0x3c, 0x9b, 0x19, 0xd6, 0x75, + 0x05, 0xa0, 0xf9, 0x88, 0xd7, 0xc1, 0xe8, 0xa5, 0x09, 0xe4, 0x1a, 0x15, + 0xdc, 0x87, 0x23, 0xaa, 0xb2, 0x75, 0x8c, 0x63, 0x25, 0x87, 0xd8, 0xf8, + 0x3d, 0xa6, 0xc2, 0xcc, 0x66, 0xff, 0xa5, 0x66, 0x68, 0x55, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x0b, 0x30, 0x82, 0x01, 0x07, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x33, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x27, 0x30, 0x25, + 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, + 0x30, 0x27, 0xa0, 0x25, 0xa0, 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x32, 0x30, 0x34, 0x38, 0x63, + 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x20, + 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, + 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, + 0x65, 0x74, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x1e, 0xf1, 0xab, 0x89, 0x06, 0xf8, 0x49, + 0x0f, 0x01, 0x33, 0x77, 0xee, 0x14, 0x7a, 0xee, 0x19, 0x7c, 0x93, 0x28, + 0x4d, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x55, 0xe4, 0x81, 0xd1, 0x11, 0x80, 0xbe, 0xd8, 0x89, 0xb9, + 0x08, 0xa3, 0x31, 0xf9, 0xa1, 0x24, 0x09, 0x16, 0xb9, 0x70, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x07, 0xf6, 0x5f, 0x82, 0x84, 0x7f, + 0x80, 0x40, 0xc7, 0x90, 0x34, 0x46, 0x42, 0x24, 0x03, 0xce, 0x2f, 0xab, + 0xba, 0x83, 0x9e, 0x25, 0x73, 0x0d, 0xed, 0xac, 0x05, 0x69, 0xc6, 0x87, + 0xed, 0xa3, 0x5c, 0xf2, 0x57, 0xc1, 0xb1, 0x49, 0x76, 0x9a, 0x4d, 0xf2, + 0x3f, 0xdd, 0xe4, 0x0e, 0xfe, 0x0b, 0x3e, 0xb9, 0x98, 0xd9, 0x32, 0x95, + 0x1d, 0x32, 0xf4, 0x01, 0xee, 0x9c, 0xc8, 0xc8, 0xe5, 0x3f, 0xe0, 0x53, + 0x76, 0x62, 0xfc, 0xdd, 0xab, 0x6d, 0x3d, 0x94, 0x90, 0xf2, 0xc0, 0xb3, + 0x3c, 0x98, 0x27, 0x36, 0x5e, 0x28, 0x97, 0x22, 0xfc, 0x1b, 0x40, 0xd3, + 0x2b, 0x0d, 0xad, 0xb5, 0x57, 0x6d, 0xdf, 0x0f, 0xe3, 0x4b, 0xef, 0x73, + 0x02, 0x10, 0x65, 0xfa, 0x1b, 0xd0, 0xac, 0x31, 0xd5, 0xe3, 0x0f, 0xe8, + 0xba, 0x32, 0x30, 0x83, 0xee, 0x4a, 0xd0, 0xbf, 0xdf, 0x22, 0x90, 0x7a, + 0xbe, 0xec, 0x3a, 0x1b, 0xc4, 0x49, 0x04, 0x1d, 0xf1, 0xae, 0x80, 0x77, + 0x3c, 0x42, 0x08, 0xdb, 0xa7, 0x3b, 0x28, 0xa6, 0x80, 0x01, 0x03, 0xe6, + 0x39, 0xa3, 0xeb, 0xdf, 0x80, 0x59, 0x1b, 0xf3, 0x2c, 0xbe, 0xdc, 0x72, + 0x44, 0x79, 0xa0, 0x6c, 0x07, 0xa5, 0x6d, 0x4d, 0x44, 0x8e, 0x42, 0x68, + 0xca, 0x94, 0x7c, 0x2e, 0x36, 0xba, 0x85, 0x9e, 0xcd, 0xaa, 0xc4, 0x5e, + 0x3c, 0x54, 0xbe, 0xfe, 0x2f, 0xea, 0x69, 0x9d, 0x1c, 0x1e, 0x29, 0x9b, + 0x96, 0xd8, 0xc8, 0xfe, 0x51, 0x90, 0xf1, 0x24, 0xa6, 0x90, 0x06, 0xb3, + 0xf0, 0x29, 0xa2, 0xff, 0x78, 0x2e, 0x77, 0x5c, 0x45, 0x21, 0xd9, 0x44, + 0x00, 0x31, 0xf3, 0xbe, 0x32, 0x4f, 0xf5, 0x0a, 0x32, 0x0d, 0xfc, 0xfc, + 0xba, 0x16, 0x76, 0x56, 0xb2, 0xd6, 0x48, 0x92, 0xf2, 0x8b, 0xa6, 0x3e, + 0xb7, 0xac, 0x5c, 0x69, 0xea, 0x0b, 0x3f, 0x66, 0x45, 0xb9, +} + +var certSet2Cert37 = []byte{ + 0x30, 0x82, 0x04, 0xfc, 0x30, 0x82, 0x03, 0xe4, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x16, 0x90, 0xc3, 0x29, 0xb6, 0x78, 0x06, 0x07, 0x51, + 0x1f, 0x05, 0xb0, 0x34, 0x48, 0x46, 0xcb, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x6f, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x53, + 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x31, + 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, 0x41, 0x64, + 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x34, 0x31, + 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, + 0x30, 0x35, 0x33, 0x30, 0x31, 0x30, 0x34, 0x38, 0x33, 0x38, 0x5a, 0x30, + 0x81, 0x89, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x4d, 0x61, + 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, 0x66, 0x6f, + 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x26, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, + 0x48, 0x69, 0x67, 0x68, 0x2d, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, + 0x63, 0x65, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xe7, 0x87, 0xda, 0xc0, 0x77, 0xe4, 0xbb, 0x3a, + 0xfa, 0x6a, 0x24, 0xc8, 0x80, 0x41, 0xac, 0xd2, 0x16, 0x13, 0x15, 0x3d, + 0xfa, 0xf7, 0xf8, 0x2a, 0x76, 0xdc, 0xa8, 0x2d, 0x39, 0x08, 0xce, 0x48, + 0x4a, 0xbe, 0x0f, 0x7d, 0xf0, 0xde, 0xba, 0xbb, 0x47, 0xd5, 0xbd, 0x2d, + 0xd7, 0x1b, 0xab, 0x0f, 0x20, 0x81, 0x23, 0x08, 0x72, 0xb1, 0xc0, 0x11, + 0x95, 0x0d, 0xe6, 0xea, 0xa9, 0x87, 0xff, 0xc7, 0x6e, 0x1e, 0x4f, 0x66, + 0x32, 0xba, 0x53, 0xbc, 0x05, 0xaa, 0x1c, 0x2c, 0x0c, 0xef, 0x4d, 0x37, + 0x47, 0x6b, 0x10, 0x0c, 0xdb, 0xc5, 0xa0, 0x98, 0x7e, 0x58, 0xdb, 0x37, + 0xd6, 0xae, 0xe9, 0x06, 0xbd, 0xd7, 0xa8, 0x65, 0xf3, 0x37, 0xb9, 0xc7, + 0x6d, 0xce, 0x77, 0xc7, 0x26, 0xe0, 0xd7, 0x74, 0x1f, 0xa6, 0x98, 0x16, + 0xbb, 0x0c, 0x6b, 0xc8, 0xbe, 0x77, 0xd0, 0xef, 0x58, 0xa7, 0x29, 0xa0, + 0xb9, 0xb8, 0x69, 0x05, 0x36, 0xcb, 0xb2, 0xda, 0x58, 0xa3, 0x0b, 0x75, + 0xad, 0x3d, 0x8b, 0x22, 0x82, 0x20, 0x3e, 0x70, 0x86, 0x99, 0x1c, 0xb9, + 0x4f, 0xcf, 0x77, 0xa4, 0x07, 0x1a, 0x23, 0x63, 0xd1, 0x38, 0x56, 0x84, + 0xec, 0xbf, 0x8f, 0xc5, 0x4e, 0xf4, 0x18, 0x96, 0x9b, 0x1a, 0xe8, 0x93, + 0xec, 0x8d, 0xaf, 0x15, 0x9c, 0x24, 0xf0, 0x5a, 0x3b, 0xe8, 0x0f, 0xb9, + 0xa8, 0x5a, 0x01, 0xd3, 0xb2, 0x1c, 0x60, 0xc9, 0x9c, 0x52, 0x04, 0xdd, + 0x92, 0xa7, 0xfe, 0x0c, 0xac, 0xe2, 0x45, 0x8d, 0x03, 0x61, 0xbc, 0x79, + 0xe0, 0x77, 0x2e, 0x87, 0x41, 0x3c, 0x58, 0x5f, 0xcb, 0xf5, 0xc5, 0x77, + 0xf2, 0x58, 0xc8, 0x4d, 0x28, 0xd0, 0x9a, 0xfa, 0xf3, 0x73, 0x09, 0x24, + 0x68, 0x74, 0xbc, 0x20, 0x4c, 0xd8, 0x2c, 0xb0, 0xaa, 0xe8, 0xd9, 0x4e, + 0x6d, 0xf2, 0x8c, 0x24, 0xd3, 0x93, 0x5d, 0x91, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0x77, 0x30, 0x82, 0x01, 0x73, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xad, 0xbd, + 0x98, 0x7a, 0x34, 0xb4, 0x26, 0xf7, 0xfa, 0xc4, 0x26, 0x54, 0xef, 0x03, + 0xbd, 0xe0, 0x24, 0xcb, 0x54, 0x1a, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3f, 0xd5, 0xb5, 0xd0, 0xd6, 0x44, 0x79, + 0x50, 0x4a, 0x17, 0xa3, 0x9b, 0x8c, 0x4a, 0xdc, 0xb8, 0xb0, 0x22, 0x64, + 0x6b, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x11, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x0a, 0x30, 0x08, + 0x30, 0x06, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x44, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x3d, 0x30, 0x3b, 0x30, 0x39, 0xa0, 0x37, 0xa0, + 0x35, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x41, 0x52, 0x6f, + 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0xb3, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0xa6, 0x30, 0x81, + 0xa3, 0x30, 0x3f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x02, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x41, 0x52, 0x6f, + 0x6f, 0x74, 0x2e, 0x70, 0x37, 0x63, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x64, 0x64, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x55, 0x54, 0x4e, 0x53, 0x47, 0x43, 0x43, + 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x25, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x19, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x13, 0x85, 0x1f, 0x52, 0x80, 0x18, 0xc9, 0x53, + 0xf7, 0xfe, 0x2e, 0x1a, 0xaf, 0xcc, 0xd9, 0x0b, 0x3c, 0xc2, 0xd3, 0x85, + 0x81, 0x10, 0xf0, 0x28, 0x8d, 0xb9, 0x40, 0x7e, 0x2c, 0x9e, 0x8f, 0xd6, + 0x36, 0x86, 0x0a, 0x4c, 0x14, 0x2d, 0xd6, 0x97, 0x43, 0x92, 0x41, 0x19, + 0x37, 0x4b, 0x96, 0x9e, 0xeb, 0xa9, 0x30, 0x79, 0x12, 0x95, 0xb3, 0x02, + 0x36, 0x57, 0xed, 0x2b, 0xb9, 0x1d, 0x98, 0x1a, 0xa3, 0x18, 0x0a, 0x3f, + 0x9b, 0x39, 0x8b, 0xcd, 0xa1, 0x49, 0x29, 0x4c, 0x2f, 0xf9, 0xd0, 0x95, + 0x8c, 0xc8, 0x4d, 0x95, 0xba, 0xa8, 0x43, 0xcf, 0x33, 0xaa, 0x25, 0x2a, + 0x5a, 0x0e, 0xaa, 0x27, 0xc9, 0x4e, 0x6b, 0xb1, 0xe6, 0x73, 0x1f, 0xb3, + 0x74, 0x04, 0xc3, 0xf3, 0x4c, 0xe2, 0xa8, 0xeb, 0x67, 0xb7, 0x5d, 0xb8, + 0x08, 0x05, 0x1a, 0x56, 0x9a, 0x54, 0x29, 0x85, 0xf5, 0x29, 0x4e, 0x80, + 0x3b, 0x95, 0xd0, 0x7b, 0x53, 0x96, 0x11, 0x56, 0xc1, 0x02, 0xd3, 0xea, + 0xb2, 0x7f, 0xca, 0x8f, 0x9c, 0x70, 0x4a, 0x14, 0x8d, 0x5a, 0xb9, 0x16, + 0x60, 0x75, 0xd6, 0xcd, 0x27, 0x1e, 0x16, 0xcd, 0x5b, 0x33, 0x8e, 0x79, + 0x40, 0xcf, 0x28, 0x48, 0xe7, 0xdc, 0x71, 0x16, 0x4e, 0x74, 0x91, 0x75, + 0xb9, 0x2a, 0x8c, 0xf1, 0x70, 0xac, 0x26, 0xdd, 0x04, 0xb9, 0x40, 0xc2, + 0x85, 0xde, 0x1c, 0x93, 0x40, 0xd0, 0xcc, 0x6e, 0xc3, 0x9b, 0xaa, 0xef, + 0x60, 0x65, 0xdf, 0x60, 0x22, 0xf0, 0x5a, 0xa5, 0x7a, 0xa2, 0x2f, 0xe4, + 0x70, 0x73, 0xee, 0x3c, 0xd4, 0x26, 0x2b, 0x68, 0x07, 0xc1, 0x20, 0x7a, + 0xe8, 0x98, 0x5a, 0x3e, 0x7b, 0x9f, 0x02, 0x8b, 0x62, 0xc0, 0x85, 0x81, + 0x80, 0x60, 0x35, 0x7e, 0xa5, 0x1d, 0x0c, 0xd2, 0x9c, 0xdf, 0x62, 0x45, + 0x0d, 0xdb, 0xfc, 0x37, 0xfb, 0xf5, 0x25, 0x22, +} + +var certSet2Cert38 = []byte{ + 0x30, 0x82, 0x04, 0xff, 0x30, 0x82, 0x03, 0xe7, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x51, 0xd3, 0x40, 0x44, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xb0, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x30, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, 0x73, 0x20, + 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, + 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x45, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2d, + 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x45, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x34, 0x30, 0x39, 0x32, 0x32, 0x31, 0x37, 0x31, 0x34, 0x35, + 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x39, 0x32, 0x33, 0x30, 0x31, + 0x33, 0x31, 0x35, 0x33, 0x5a, 0x30, 0x81, 0xbe, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, + 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, 0x30, + 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, + 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, + 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x29, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xba, 0x84, 0xb6, 0x72, 0xdb, 0x9e, 0x0c, 0x6b, 0xe2, + 0x99, 0xe9, 0x30, 0x01, 0xa7, 0x76, 0xea, 0x32, 0xb8, 0x95, 0x41, 0x1a, + 0xc9, 0xda, 0x61, 0x4e, 0x58, 0x72, 0xcf, 0xfe, 0xf6, 0x82, 0x79, 0xbf, + 0x73, 0x61, 0x06, 0x0a, 0xa5, 0x27, 0xd8, 0xb3, 0x5f, 0xd3, 0x45, 0x4e, + 0x1c, 0x72, 0xd6, 0x4e, 0x32, 0xf2, 0x72, 0x8a, 0x0f, 0xf7, 0x83, 0x19, + 0xd0, 0x6a, 0x80, 0x80, 0x00, 0x45, 0x1e, 0xb0, 0xc7, 0xe7, 0x9a, 0xbf, + 0x12, 0x57, 0x27, 0x1c, 0xa3, 0x68, 0x2f, 0x0a, 0x87, 0xbd, 0x6a, 0x6b, + 0x0e, 0x5e, 0x65, 0xf3, 0x1c, 0x77, 0xd5, 0xd4, 0x85, 0x8d, 0x70, 0x21, + 0xb4, 0xb3, 0x32, 0xe7, 0x8b, 0xa2, 0xd5, 0x86, 0x39, 0x02, 0xb1, 0xb8, + 0xd2, 0x47, 0xce, 0xe4, 0xc9, 0x49, 0xc4, 0x3b, 0xa7, 0xde, 0xfb, 0x54, + 0x7d, 0x57, 0xbe, 0xf0, 0xe8, 0x6e, 0xc2, 0x79, 0xb2, 0x3a, 0x0b, 0x55, + 0xe2, 0x50, 0x98, 0x16, 0x32, 0x13, 0x5c, 0x2f, 0x78, 0x56, 0xc1, 0xc2, + 0x94, 0xb3, 0xf2, 0x5a, 0xe4, 0x27, 0x9a, 0x9f, 0x24, 0xd7, 0xc6, 0xec, + 0xd0, 0x9b, 0x25, 0x82, 0xe3, 0xcc, 0xc2, 0xc4, 0x45, 0xc5, 0x8c, 0x97, + 0x7a, 0x06, 0x6b, 0x2a, 0x11, 0x9f, 0xa9, 0x0a, 0x6e, 0x48, 0x3b, 0x6f, + 0xdb, 0xd4, 0x11, 0x19, 0x42, 0xf7, 0x8f, 0x07, 0xbf, 0xf5, 0x53, 0x5f, + 0x9c, 0x3e, 0xf4, 0x17, 0x2c, 0xe6, 0x69, 0xac, 0x4e, 0x32, 0x4c, 0x62, + 0x77, 0xea, 0xb7, 0xe8, 0xe5, 0xbb, 0x34, 0xbc, 0x19, 0x8b, 0xae, 0x9c, + 0x51, 0xe7, 0xb7, 0x7e, 0xb5, 0x53, 0xb1, 0x33, 0x22, 0xe5, 0x6d, 0xcf, + 0x70, 0x3c, 0x1a, 0xfa, 0xe2, 0x9b, 0x67, 0xb6, 0x83, 0xf4, 0x8d, 0xa5, + 0xaf, 0x62, 0x4c, 0x4d, 0xe0, 0x58, 0xac, 0x64, 0x34, 0x12, 0x03, 0xf8, + 0xb6, 0x8d, 0x94, 0x63, 0x24, 0xa4, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x0f, 0x30, 0x82, 0x01, 0x0b, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, + 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x33, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x27, 0x30, 0x25, + 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2c, 0x30, 0x2a, + 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x63, + 0x61, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, 0x04, 0x55, 0x1d, 0x20, + 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6a, 0x72, 0x26, 0x7a, 0xd0, 0x1e, + 0xef, 0x7d, 0xe7, 0x3b, 0x69, 0x51, 0xd4, 0x6c, 0x8d, 0x9f, 0x90, 0x12, + 0x66, 0xab, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x68, 0x90, 0xe4, 0x67, 0xa4, 0xa6, 0x53, 0x80, 0xc7, + 0x86, 0x66, 0xa4, 0xf1, 0xf7, 0x4b, 0x43, 0xfb, 0x84, 0xbd, 0x6d, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x69, 0x33, 0x83, 0xfc, 0x28, + 0x7a, 0x6f, 0x7d, 0xef, 0x9d, 0x55, 0xeb, 0xc5, 0x3e, 0x7a, 0x9d, 0x75, + 0xb3, 0xcc, 0xc3, 0x38, 0x36, 0xd9, 0x34, 0xa2, 0x28, 0x68, 0x18, 0xea, + 0x1e, 0x69, 0xd3, 0xbd, 0xe7, 0xd0, 0x77, 0xda, 0xb8, 0x00, 0x83, 0x4e, + 0x4a, 0xcf, 0x6f, 0xd1, 0xf1, 0xc1, 0x22, 0x3f, 0x74, 0xe4, 0xf7, 0x98, + 0x49, 0x9e, 0x9b, 0xb6, 0x9e, 0xe1, 0xdb, 0x98, 0x77, 0x2d, 0x56, 0x34, + 0xb1, 0xa8, 0x3c, 0xd9, 0xfd, 0xc0, 0xcd, 0xc7, 0xbf, 0x05, 0x03, 0xd4, + 0x02, 0xc5, 0xf1, 0xe5, 0xc6, 0xda, 0x08, 0xa5, 0x13, 0xc7, 0x62, 0x23, + 0x11, 0xd1, 0x61, 0x30, 0x1d, 0x60, 0x84, 0x45, 0xef, 0x79, 0xa8, 0xc6, + 0x26, 0x93, 0xa4, 0xb7, 0xcd, 0x34, 0xb8, 0x69, 0xc5, 0x13, 0xf6, 0x91, + 0xb3, 0xc9, 0x45, 0x73, 0x76, 0xb6, 0x92, 0xf6, 0x76, 0x0a, 0x5b, 0xe1, + 0x03, 0x47, 0xb7, 0xe9, 0x29, 0x4c, 0x91, 0x32, 0x23, 0x37, 0x4a, 0x9c, + 0x35, 0xd8, 0x78, 0xfd, 0x1d, 0x1f, 0xe4, 0x83, 0x89, 0x24, 0x80, 0xad, + 0xb7, 0xf9, 0xcf, 0xe4, 0x5d, 0xa5, 0xd4, 0x71, 0xc4, 0x85, 0x5b, 0x70, + 0x1f, 0xdb, 0x3f, 0x1c, 0x01, 0xeb, 0x1a, 0x45, 0x26, 0x31, 0x14, 0xcc, + 0x65, 0xbf, 0x67, 0xde, 0xca, 0xcc, 0x33, 0x65, 0xe5, 0x41, 0x91, 0xd7, + 0x37, 0xbe, 0x41, 0x1a, 0x96, 0x9d, 0xe6, 0x8a, 0x97, 0x9d, 0xa7, 0xce, + 0xac, 0x4e, 0x9a, 0x3d, 0xbd, 0x01, 0xa0, 0x6a, 0xd9, 0x4f, 0x22, 0x00, + 0x8b, 0x44, 0xd5, 0x69, 0x62, 0x7b, 0x2e, 0xeb, 0xcc, 0xba, 0xe7, 0x92, + 0x7d, 0x69, 0x67, 0x3d, 0xfc, 0xb8, 0x7c, 0xde, 0x41, 0x87, 0xd0, 0x69, + 0xea, 0xba, 0x0a, 0x18, 0x7a, 0x1a, 0x95, 0x43, 0xb3, 0x79, 0x71, 0x28, + 0x76, 0x6d, 0xa1, 0xfb, 0x57, 0x4a, 0xec, 0x4d, 0xc8, 0x0e, 0x10, +} + +var certSet2Cert39 = []byte{ + 0x30, 0x82, 0x05, 0x00, 0x30, 0x82, 0x03, 0xe8, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x8f, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, + 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, + 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, + 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x81, 0xc6, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, + 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, + 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, + 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, + 0x74, 0x73, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x74, 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x31, 0x34, 0x30, 0x32, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2b, 0x53, 0x74, 0x61, 0x72, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, + 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe5, + 0x90, 0x66, 0x4b, 0xec, 0xf9, 0x46, 0x71, 0xa9, 0x20, 0x83, 0xbe, 0xe9, + 0x6c, 0xbf, 0x4a, 0xc9, 0x48, 0x69, 0x81, 0x75, 0x4e, 0x6d, 0x24, 0xf6, + 0xcb, 0x17, 0x13, 0xf8, 0xb0, 0x71, 0x59, 0x84, 0x7a, 0x6b, 0x2b, 0x85, + 0xa4, 0x34, 0xb5, 0x16, 0xe5, 0xcb, 0xcc, 0xe9, 0x41, 0x70, 0x2c, 0xa4, + 0x2e, 0xd6, 0xfa, 0x32, 0x7d, 0xe1, 0xa8, 0xde, 0x94, 0x10, 0xac, 0x31, + 0xc1, 0xc0, 0xd8, 0x6a, 0xff, 0x59, 0x27, 0xab, 0x76, 0xd6, 0xfc, 0x0b, + 0x74, 0x6b, 0xb8, 0xa7, 0xae, 0x3f, 0xc4, 0x54, 0xf4, 0xb4, 0x31, 0x44, + 0xdd, 0x93, 0x56, 0x8c, 0xa4, 0x4c, 0x5e, 0x9b, 0x89, 0xcb, 0x24, 0x83, + 0x9b, 0xe2, 0x57, 0x7d, 0xb7, 0xd8, 0x12, 0x1f, 0xc9, 0x85, 0x6d, 0xf4, + 0xd1, 0x80, 0xf1, 0x50, 0x9b, 0x87, 0xae, 0xd4, 0x0b, 0x10, 0x05, 0xfb, + 0x27, 0xba, 0x28, 0x6d, 0x17, 0xe9, 0x0e, 0xd6, 0x4d, 0xb9, 0x39, 0x55, + 0x06, 0xff, 0x0a, 0x24, 0x05, 0x7e, 0x2f, 0xc6, 0x1d, 0x72, 0x6c, 0xd4, + 0x8b, 0x29, 0x8c, 0x57, 0x7d, 0xda, 0xd9, 0xeb, 0x66, 0x1a, 0xd3, 0x4f, + 0xa7, 0xdf, 0x7f, 0x52, 0xc4, 0x30, 0xc5, 0xa5, 0xc9, 0x0e, 0x02, 0xc5, + 0x53, 0xbf, 0x77, 0x38, 0x68, 0x06, 0x24, 0xc3, 0x66, 0xc8, 0x37, 0x7e, + 0x30, 0x1e, 0x45, 0x71, 0x23, 0x35, 0xff, 0x90, 0xd8, 0x2a, 0x9d, 0x8d, + 0xe7, 0xb0, 0x92, 0x4d, 0x3c, 0x7f, 0x2a, 0x0a, 0x93, 0xdc, 0xcd, 0x16, + 0x46, 0x65, 0xf7, 0x60, 0x84, 0x8b, 0x76, 0x4b, 0x91, 0x27, 0x73, 0x14, + 0x92, 0xe0, 0xea, 0xee, 0x8f, 0x16, 0xea, 0x8d, 0x0e, 0x3e, 0x76, 0x17, + 0xbf, 0x7d, 0x89, 0x80, 0x80, 0x44, 0x43, 0xe7, 0x2d, 0xe0, 0x43, 0x09, + 0x75, 0xda, 0x36, 0xe8, 0xad, 0xdb, 0x89, 0x3a, 0xf5, 0x5d, 0x12, 0x8e, + 0x23, 0x04, 0x83, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x2c, + 0x30, 0x82, 0x01, 0x28, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x25, 0x45, 0x81, 0x68, 0x50, 0x26, 0x38, 0x3d, 0x3b, 0x2d, 0x2c, 0xbe, + 0xcd, 0x6a, 0xd9, 0xb6, 0x3d, 0xb3, 0x66, 0x63, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7c, 0x0c, 0x32, + 0x1f, 0xa7, 0xd9, 0x30, 0x7f, 0xc4, 0x7d, 0x68, 0xa3, 0x62, 0xa8, 0xa1, + 0xce, 0xab, 0x07, 0x5b, 0x27, 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1e, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0xa0, 0x2e, 0xa0, 0x2c, 0x86, 0x2a, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x72, 0x6f, 0x6f, 0x74, 0x2d, + 0x67, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, 0x04, 0x55, 0x1d, 0x20, + 0x00, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x56, 0x65, 0xca, 0xfe, + 0xf3, 0x3f, 0x0a, 0xa8, 0x93, 0x8b, 0x18, 0xc7, 0xde, 0x43, 0x69, 0x13, + 0x34, 0x20, 0xbe, 0x4e, 0x5f, 0x78, 0xa8, 0x6b, 0x9c, 0xdb, 0x6a, 0x4d, + 0x41, 0xdb, 0xc1, 0x13, 0xec, 0xdc, 0x31, 0x00, 0x22, 0x5e, 0xf7, 0x00, + 0x9e, 0x0c, 0xe0, 0x34, 0x65, 0x34, 0xf9, 0xb1, 0x3a, 0x4e, 0x48, 0xc8, + 0x12, 0x81, 0x88, 0x5c, 0x5b, 0x3e, 0x08, 0x53, 0x7a, 0xf7, 0x1a, 0x64, + 0xdf, 0xb8, 0x50, 0x61, 0xcc, 0x53, 0x51, 0x40, 0x29, 0x4b, 0xc2, 0xf4, + 0xae, 0x3a, 0x5f, 0xe4, 0xca, 0xad, 0x26, 0xcc, 0x4e, 0x61, 0x43, 0xe5, + 0xfd, 0x57, 0xa6, 0x37, 0x70, 0xce, 0x43, 0x2b, 0xb0, 0x94, 0xc3, 0x92, + 0xe9, 0xe1, 0x5f, 0xaa, 0x10, 0x49, 0xb7, 0x69, 0xe4, 0xe0, 0xd0, 0x1f, + 0x64, 0xa4, 0x2b, 0xcd, 0x1f, 0x6f, 0xa0, 0xf8, 0x84, 0x24, 0x18, 0xce, + 0x79, 0x3d, 0xa9, 0x91, 0xbf, 0x54, 0x18, 0x13, 0x89, 0x99, 0x54, 0x11, + 0x0d, 0x55, 0xc5, 0x26, 0x0b, 0x79, 0x4f, 0x5a, 0x1c, 0x6e, 0xf9, 0x63, + 0xdb, 0x14, 0x80, 0xa4, 0x07, 0xab, 0xfa, 0xb2, 0xa5, 0xb9, 0x88, 0xdd, + 0x91, 0xfe, 0x65, 0x3b, 0xa4, 0xa3, 0x79, 0xbe, 0x89, 0x4d, 0xe1, 0xd0, + 0xb0, 0xf4, 0xc8, 0x17, 0x0c, 0x0a, 0x96, 0x14, 0x7c, 0x09, 0xb7, 0x6c, + 0xe1, 0xc2, 0xd8, 0x55, 0xd4, 0x18, 0xa0, 0xaa, 0x41, 0x69, 0x70, 0x24, + 0xa3, 0xb9, 0xef, 0xe9, 0x5a, 0xdc, 0x3e, 0xeb, 0x94, 0x4a, 0xf0, 0xb7, + 0xde, 0x5f, 0x0e, 0x76, 0xfa, 0xfb, 0xfb, 0x69, 0x03, 0x45, 0x40, 0x50, + 0xee, 0x72, 0x0c, 0xa4, 0x12, 0x86, 0x81, 0xcd, 0x13, 0xd1, 0x4e, 0xc4, + 0x3c, 0xca, 0x4e, 0x0d, 0xd2, 0x26, 0xf1, 0x00, 0xb7, 0xb4, 0xa6, 0xa2, + 0xe1, 0x6e, 0x7a, 0x81, 0xfd, 0x30, 0xac, 0x7a, 0x1f, 0xc7, 0x59, 0x7b, +} + +var certSet2Cert40 = []byte{ + 0x30, 0x82, 0x05, 0x03, 0x30, 0x82, 0x03, 0xeb, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x51, 0xd3, 0x60, 0xee, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xbe, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, + 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, + 0x30, 0x30, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x32, 0x32, 0x31, 0x37, 0x30, + 0x35, 0x31, 0x34, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x31, 0x30, 0x32, 0x33, + 0x30, 0x37, 0x33, 0x33, 0x32, 0x32, 0x5a, 0x30, 0x81, 0xba, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, + 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, + 0x65, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, + 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x32, + 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x25, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, + 0x20, 0x4c, 0x31, 0x4b, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xda, 0x3f, 0x96, 0xd0, 0x4d, 0xb9, 0x2f, 0x44, 0xe7, 0xdb, 0x39, + 0x5e, 0x9b, 0x50, 0xee, 0x5c, 0xa5, 0x61, 0xda, 0x41, 0x67, 0x53, 0x09, + 0xaa, 0x00, 0x9a, 0x8e, 0x57, 0x7f, 0x29, 0x6b, 0xdb, 0xc7, 0xe1, 0x21, + 0x24, 0xaa, 0x3a, 0xd0, 0x8d, 0x47, 0x23, 0xd2, 0xed, 0x72, 0x16, 0xf0, + 0x91, 0x21, 0xd2, 0x5d, 0xb7, 0xb8, 0x4b, 0xa8, 0x83, 0x8f, 0xb7, 0x91, + 0x32, 0x68, 0xcf, 0xce, 0x25, 0x93, 0x2c, 0xb2, 0x7d, 0x97, 0xc8, 0xfe, + 0xc1, 0xb4, 0x17, 0xba, 0x09, 0x9e, 0x03, 0x90, 0x93, 0x7b, 0x7c, 0x49, + 0x83, 0x22, 0x68, 0x8a, 0x9b, 0xde, 0x47, 0xc3, 0x31, 0x98, 0x7a, 0x2e, + 0x7d, 0x40, 0x0b, 0xd2, 0xef, 0x3e, 0xd3, 0xb2, 0x8c, 0xaa, 0x8f, 0x48, + 0xa9, 0xff, 0x00, 0xe8, 0x29, 0x58, 0x06, 0xf7, 0xb6, 0x93, 0x5a, 0x94, + 0x73, 0x26, 0x26, 0xad, 0x58, 0x0e, 0xe5, 0x42, 0xb8, 0xd5, 0xea, 0x73, + 0x79, 0x64, 0x68, 0x53, 0x25, 0xb8, 0x84, 0xcf, 0x94, 0x7a, 0xae, 0x06, + 0x45, 0x0c, 0xa3, 0x6b, 0x4d, 0xd0, 0xc6, 0xbe, 0xea, 0x18, 0xa4, 0x36, + 0xf0, 0x92, 0xb2, 0xba, 0x1c, 0x88, 0x8f, 0x3a, 0x52, 0x7f, 0xf7, 0x5e, + 0x6d, 0x83, 0x1c, 0x9d, 0xf0, 0x1f, 0xe5, 0xc3, 0xd6, 0xdd, 0xa5, 0x78, + 0x92, 0x3d, 0xb0, 0x6d, 0x2c, 0xea, 0xc9, 0xcf, 0x94, 0x41, 0x19, 0x71, + 0x44, 0x68, 0xba, 0x47, 0x3c, 0x04, 0xe9, 0x5d, 0xba, 0x3e, 0xf0, 0x35, + 0xf7, 0x15, 0xb6, 0x9e, 0xf2, 0x2e, 0x15, 0x1e, 0x3f, 0x47, 0xc8, 0xc8, + 0x38, 0xa7, 0x73, 0x45, 0x5d, 0x4d, 0xb0, 0x3b, 0xb1, 0x8e, 0x17, 0x29, + 0x37, 0xea, 0xdd, 0x05, 0x01, 0x22, 0xbb, 0x94, 0x36, 0x2a, 0x8d, 0x5b, + 0x35, 0xfe, 0x53, 0x19, 0x2f, 0x08, 0x46, 0xc1, 0x2a, 0xb3, 0x1a, 0x62, + 0x1d, 0x4e, 0x2b, 0xd9, 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x09, 0x30, 0x82, 0x01, 0x05, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x33, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x27, 0x30, 0x25, 0x30, 0x23, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x65, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x30, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, + 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x2f, 0x67, 0x32, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3b, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x70, 0x61, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x82, 0xa2, + 0x70, 0x74, 0xdd, 0xbc, 0x53, 0x3f, 0xcf, 0x7b, 0xd4, 0xf7, 0xcd, 0x7f, + 0xa7, 0x60, 0xc6, 0x0a, 0x4c, 0xbf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x6a, 0x72, 0x26, 0x7a, 0xd0, + 0x1e, 0xef, 0x7d, 0xe7, 0x3b, 0x69, 0x51, 0xd4, 0x6c, 0x8d, 0x9f, 0x90, + 0x12, 0x66, 0xab, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3f, + 0x1c, 0x1a, 0x5b, 0xff, 0x40, 0x22, 0x1d, 0x8f, 0x35, 0x0c, 0x2d, 0xaa, + 0x99, 0x27, 0xab, 0xc0, 0x11, 0x32, 0x70, 0xd7, 0x36, 0x28, 0x69, 0xa5, + 0x8d, 0xb1, 0x27, 0x99, 0x42, 0xbe, 0xc4, 0x93, 0xeb, 0x48, 0x57, 0x43, + 0x71, 0x23, 0xc4, 0xe5, 0x4e, 0xad, 0xae, 0x43, 0x6f, 0x92, 0x76, 0xc5, + 0x19, 0xef, 0xca, 0xbc, 0x6f, 0x42, 0x4c, 0x16, 0x9a, 0x86, 0xa9, 0x04, + 0x38, 0xc7, 0x65, 0xf0, 0xf5, 0x0c, 0xe0, 0x4a, 0xdf, 0xa2, 0xfa, 0xce, + 0x1a, 0x11, 0xa8, 0x9c, 0x69, 0x2f, 0x1b, 0xdf, 0xea, 0xe2, 0x32, 0xf3, + 0xce, 0x4c, 0xbc, 0x46, 0x0c, 0xc0, 0x89, 0x80, 0xd1, 0x87, 0x6b, 0xa2, + 0xcf, 0x6b, 0xd4, 0x7f, 0xfd, 0xf5, 0x60, 0x52, 0x67, 0x57, 0xa0, 0x6d, + 0xd1, 0x64, 0x41, 0x14, 0x6d, 0x34, 0x62, 0xed, 0x06, 0x6c, 0x24, 0xf2, + 0x06, 0xbc, 0x28, 0x02, 0xaf, 0x03, 0x2d, 0xc2, 0x33, 0x05, 0xfb, 0xcb, + 0xaa, 0x16, 0xe8, 0x65, 0x10, 0x43, 0xf5, 0x69, 0x5c, 0xe3, 0x81, 0x58, + 0x99, 0xcd, 0x6b, 0xd3, 0xb8, 0xc7, 0x7b, 0x19, 0x55, 0xc9, 0x40, 0xce, + 0x79, 0x55, 0xb8, 0x73, 0x89, 0xe9, 0x5c, 0x40, 0x66, 0x43, 0x12, 0x7f, + 0x07, 0xb8, 0x65, 0x56, 0xd5, 0x8d, 0xc3, 0xa7, 0xf5, 0xb1, 0xb6, 0x65, + 0x9e, 0xc0, 0x83, 0x36, 0x7f, 0x16, 0x45, 0x3c, 0x74, 0x4b, 0x93, 0x8a, + 0x3c, 0xf1, 0x2b, 0xf5, 0x35, 0x70, 0x73, 0x7b, 0xe7, 0x82, 0x04, 0xb1, + 0x18, 0x98, 0x0e, 0xd4, 0x9c, 0x6f, 0x1a, 0xfc, 0xfc, 0xa7, 0x33, 0xa5, + 0xbb, 0xbb, 0x18, 0xf3, 0x6b, 0x7a, 0x5d, 0x32, 0x87, 0xf7, 0x6d, 0x25, + 0xe4, 0xe2, 0x76, 0x86, 0x21, 0x1e, 0x11, 0x46, 0xcd, 0x76, 0x0e, 0x6f, + 0x4f, 0xa4, 0x21, 0x71, 0x0a, 0x84, 0xa7, 0x2d, 0x36, 0xa9, 0x48, 0x22, + 0x51, 0x7e, 0x82, +} + +var certSet2Cert41 = []byte{ + 0x30, 0x82, 0x05, 0x1f, 0x30, 0x82, 0x04, 0x07, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0xa4, 0x6b, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, + 0x30, 0x34, 0x30, 0x32, 0x31, 0x34, 0x33, 0x36, 0x31, 0x30, 0x5a, 0x17, + 0x0d, 0x32, 0x31, 0x30, 0x34, 0x30, 0x32, 0x31, 0x34, 0x33, 0x35, 0x35, + 0x32, 0x5a, 0x30, 0x81, 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x13, 0x09, 0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, + 0x61, 0x6d, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x1c, 0x56, 0x65, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x20, 0x45, 0x6e, 0x74, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x53, 0x6f, 0x6c, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x25, 0x56, 0x65, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x20, 0x41, 0x6b, 0x61, + 0x6d, 0x61, 0x69, 0x20, 0x53, 0x75, 0x72, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x47, 0x31, 0x34, 0x2d, 0x53, 0x48, + 0x41, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdd, + 0x6e, 0x9e, 0x02, 0x69, 0x02, 0xb5, 0xa3, 0x99, 0x2e, 0x08, 0x64, 0x32, + 0x6a, 0x59, 0xf3, 0xc6, 0x9e, 0xa6, 0x20, 0x07, 0xd2, 0x48, 0xd1, 0xa8, + 0x93, 0xc7, 0xea, 0x47, 0x8f, 0x83, 0x39, 0x40, 0xd7, 0x20, 0x5d, 0x8d, + 0x9a, 0xba, 0xab, 0xd8, 0x70, 0xec, 0x9d, 0x88, 0xd1, 0xbd, 0x62, 0xf6, + 0xdb, 0xec, 0x9d, 0x5e, 0x35, 0x01, 0x76, 0x03, 0x23, 0xe5, 0x6f, 0xd2, + 0xaf, 0x46, 0x35, 0x59, 0x5a, 0x5c, 0xd1, 0xa8, 0x23, 0xc1, 0xeb, 0xe9, + 0x20, 0xd4, 0x49, 0xd6, 0x3f, 0x00, 0xd8, 0xa8, 0x22, 0xde, 0x43, 0x79, + 0x81, 0xac, 0xe9, 0xa4, 0x92, 0xf5, 0x77, 0x70, 0x05, 0x1e, 0x5c, 0xb6, + 0xa0, 0xf7, 0x90, 0xa4, 0xcd, 0xab, 0x28, 0x2c, 0x90, 0xc2, 0xe7, 0x0f, + 0xc3, 0xaf, 0x1c, 0x47, 0x59, 0xd5, 0x84, 0x2e, 0xdf, 0x26, 0x07, 0x45, + 0x23, 0x5a, 0xc6, 0xe8, 0x90, 0xc8, 0x85, 0x4b, 0x8c, 0x16, 0x1e, 0x60, + 0xf9, 0x01, 0x13, 0xf1, 0x14, 0x1f, 0xe6, 0xe8, 0x14, 0xed, 0xc5, 0xd2, + 0x6f, 0x63, 0x28, 0x6e, 0x72, 0x8c, 0x49, 0xae, 0x08, 0x72, 0xc7, 0x93, + 0x95, 0xb4, 0x0b, 0x0c, 0xae, 0x8f, 0x9a, 0x67, 0x84, 0xf5, 0x57, 0x1b, + 0xdb, 0x81, 0xd7, 0x17, 0x9d, 0x41, 0x11, 0x43, 0x19, 0xbd, 0x6d, 0x4a, + 0x85, 0xed, 0x8f, 0x70, 0x25, 0xab, 0x66, 0xab, 0xf6, 0xfa, 0x6d, 0x1c, + 0x3c, 0xab, 0xed, 0x17, 0xbd, 0x56, 0x84, 0xe1, 0xdb, 0x75, 0x33, 0xb2, + 0x28, 0x4b, 0x99, 0x8e, 0xf9, 0x4b, 0x82, 0x33, 0x50, 0x9f, 0x92, 0x53, + 0xed, 0xfa, 0xad, 0x0f, 0x95, 0x9c, 0xa3, 0xf2, 0xcb, 0x60, 0xf0, 0x77, + 0x1d, 0xc9, 0x01, 0x8b, 0x5f, 0x2d, 0x86, 0xbe, 0xbf, 0x36, 0xb8, 0x24, + 0x96, 0x13, 0x7c, 0xc1, 0x86, 0x5a, 0x6c, 0xc1, 0x48, 0x2a, 0x7f, 0x3e, + 0x93, 0x60, 0xc5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xb7, + 0x30, 0x82, 0x01, 0xb3, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x02, + 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, + 0x41, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb1, 0x3e, 0x01, 0x32, + 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, + 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30, 0x81, 0xba, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0xad, 0x30, 0x81, + 0xaa, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x86, 0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, + 0x73, 0x70, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, + 0x65, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x6d, + 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, + 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x72, 0x6f, 0x6f, 0x74, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x6d, 0x6e, + 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, + 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x72, 0x6f, 0x6f, 0x74, 0x2e, + 0x64, 0x65, 0x72, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0xc6, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe5, 0x9d, 0x59, 0x30, + 0x82, 0x47, 0x58, 0xcc, 0xac, 0xfa, 0x08, 0x54, 0x36, 0x86, 0x7b, 0x3a, + 0xb5, 0x04, 0x4d, 0xf0, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, + 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x64, 0x70, 0x31, 0x2e, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x52, 0x4c, 0x2f, 0x4f, 0x6d, 0x6e, 0x69, + 0x72, 0x6f, 0x6f, 0x74, 0x32, 0x30, 0x32, 0x35, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf8, + 0xbd, 0xfa, 0xaf, 0x73, 0x77, 0xc6, 0xc7, 0x1b, 0xf9, 0x4b, 0x4d, 0x11, + 0xa7, 0xd1, 0x33, 0xaf, 0xaf, 0x72, 0x11, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x01, 0x00, 0x80, 0xd9, 0x7a, 0xed, 0x72, 0x05, 0x37, 0x8f, 0x61, + 0xaa, 0x73, 0x7c, 0x9a, 0x6a, 0xfc, 0xfe, 0x01, 0xe2, 0x19, 0x81, 0x70, + 0x07, 0x25, 0x32, 0xb0, 0xf0, 0x6f, 0x3b, 0xc7, 0x6a, 0x28, 0x3d, 0xe4, + 0x51, 0x87, 0xe6, 0x7e, 0x82, 0xec, 0xae, 0x48, 0xa7, 0xb1, 0x77, 0x38, + 0xc2, 0xd6, 0x56, 0xaf, 0x8f, 0xf2, 0x01, 0xfc, 0x65, 0x65, 0x10, 0x09, + 0xf7, 0x74, 0x29, 0xb5, 0x0e, 0x92, 0xee, 0x90, 0x98, 0xd1, 0x88, 0xa2, + 0x65, 0xb7, 0xcd, 0x9c, 0x0e, 0xa7, 0x86, 0x98, 0x28, 0xbc, 0xae, 0x15, + 0x83, 0xb6, 0x1a, 0xd7, 0x1d, 0xec, 0x19, 0xda, 0x7a, 0x8e, 0x40, 0xf9, + 0x99, 0x15, 0xd5, 0x7d, 0xa5, 0xba, 0xab, 0xfd, 0x26, 0x98, 0x6e, 0x9c, + 0x41, 0x3b, 0xb6, 0x81, 0x18, 0xec, 0x70, 0x48, 0xd7, 0x6e, 0x7f, 0xa6, + 0xe1, 0x77, 0x25, 0xd6, 0xdd, 0x62, 0xe8, 0x52, 0xf3, 0x8c, 0x16, 0x39, + 0x67, 0xe2, 0x22, 0x0d, 0x77, 0x2e, 0xfb, 0x11, 0x6c, 0xe4, 0xdd, 0x38, + 0xb4, 0x27, 0x5f, 0x03, 0xa8, 0x3d, 0x44, 0xe2, 0xf2, 0x84, 0x4b, 0x84, + 0xfd, 0x56, 0xa6, 0x9e, 0x4d, 0x7b, 0xa2, 0x16, 0x4f, 0x07, 0xf5, 0x34, + 0x24, 0x72, 0xa5, 0xa2, 0xfa, 0x16, 0x66, 0x2a, 0xa4, 0x4a, 0x0e, 0xc8, + 0x0d, 0x27, 0x44, 0x9c, 0x77, 0xd4, 0x12, 0x10, 0x87, 0xd2, 0x00, 0x2c, + 0x7a, 0xbb, 0x8e, 0x88, 0x22, 0x91, 0x15, 0xbe, 0xa2, 0x59, 0xca, 0x34, + 0xe0, 0x1c, 0x61, 0x94, 0x86, 0x20, 0x33, 0xcd, 0xe7, 0x4c, 0x5d, 0x3b, + 0x92, 0x3e, 0xcb, 0xd6, 0x2d, 0xea, 0x54, 0xfa, 0xfb, 0xaf, 0x54, 0xf5, + 0xa8, 0xc5, 0x0b, 0xca, 0x8b, 0x87, 0x00, 0xe6, 0x9f, 0xe6, 0x95, 0xbf, + 0xb7, 0xc4, 0xa3, 0x59, 0xf5, 0x16, 0x6c, 0x5f, 0x3e, 0x69, 0x55, 0x80, + 0x39, 0xf6, 0x75, 0x50, 0x14, 0x3e, 0x32, +} + +var certSet2Cert42 = []byte{ + 0x30, 0x82, 0x05, 0x2b, 0x30, 0x82, 0x04, 0x13, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x7e, 0xe1, 0x4a, 0x6f, 0x6f, 0xef, 0xf2, 0xd3, 0x7f, + 0x3f, 0xad, 0x65, 0x4d, 0x3a, 0xda, 0xb4, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, 0x30, 0x33, 0x30, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x77, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1d, + 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x53, 0x79, 0x6d, + 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x16, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x1f, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x56, 0x20, 0x53, 0x53, 0x4c, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xd8, 0xa1, 0x65, 0x74, 0x23, 0xe8, 0x2b, + 0x64, 0xe2, 0x32, 0xd7, 0x33, 0x37, 0x3d, 0x8e, 0xf5, 0x34, 0x16, 0x48, + 0xdd, 0x4f, 0x7f, 0x87, 0x1c, 0xf8, 0x44, 0x23, 0x13, 0x8e, 0xfb, 0x11, + 0xd8, 0x44, 0x5a, 0x18, 0x71, 0x8e, 0x60, 0x16, 0x26, 0x92, 0x9b, 0xfd, + 0x17, 0x0b, 0xe1, 0x71, 0x70, 0x42, 0xfe, 0xbf, 0xfa, 0x1c, 0xc0, 0xaa, + 0xa3, 0xa7, 0xb5, 0x71, 0xe8, 0xff, 0x18, 0x83, 0xf6, 0xdf, 0x10, 0x0a, + 0x13, 0x62, 0xc8, 0x3d, 0x9c, 0xa7, 0xde, 0x2e, 0x3f, 0x0c, 0xd9, 0x1d, + 0xe7, 0x2e, 0xfb, 0x2a, 0xce, 0xc8, 0x9a, 0x7f, 0x87, 0xbf, 0xd8, 0x4c, + 0x04, 0x15, 0x32, 0xc9, 0xd1, 0xcc, 0x95, 0x71, 0xa0, 0x4e, 0x28, 0x4f, + 0x84, 0xd9, 0x35, 0xfb, 0xe3, 0x86, 0x6f, 0x94, 0x53, 0xe6, 0x72, 0x8a, + 0x63, 0x67, 0x2e, 0xbe, 0x69, 0xf6, 0xf7, 0x6e, 0x8e, 0x9c, 0x60, 0x04, + 0xeb, 0x29, 0xfa, 0xc4, 0x47, 0x42, 0xd2, 0x78, 0x98, 0xe3, 0xec, 0x0b, + 0xa5, 0x92, 0xdc, 0xb7, 0x9a, 0xbd, 0x80, 0x64, 0x2b, 0x38, 0x7c, 0x38, + 0x09, 0x5b, 0x66, 0xf6, 0x2d, 0x95, 0x7a, 0x86, 0xb2, 0x34, 0x2e, 0x85, + 0x9e, 0x90, 0x0e, 0x5f, 0xb7, 0x5d, 0xa4, 0x51, 0x72, 0x46, 0x70, 0x13, + 0xbf, 0x67, 0xf2, 0xb6, 0xa7, 0x4d, 0x14, 0x1e, 0x6c, 0xb9, 0x53, 0xee, + 0x23, 0x1a, 0x4e, 0x8d, 0x48, 0x55, 0x43, 0x41, 0xb1, 0x89, 0x75, 0x6a, + 0x40, 0x28, 0xc5, 0x7d, 0xdd, 0xd2, 0x6e, 0xd2, 0x02, 0x19, 0x2f, 0x7b, + 0x24, 0x94, 0x4b, 0xeb, 0xf1, 0x1a, 0xa9, 0x9b, 0xe3, 0x23, 0x9a, 0xea, + 0xfa, 0x33, 0xab, 0x0a, 0x2c, 0xb7, 0xf4, 0x60, 0x08, 0xdd, 0x9f, 0x1c, + 0xcd, 0xdd, 0x2d, 0x01, 0x66, 0x80, 0xaf, 0xb3, 0x2f, 0x29, 0x1d, 0x23, + 0xb8, 0x8a, 0xe1, 0xa1, 0x70, 0x07, 0x0c, 0x34, 0x0f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x5d, 0x30, 0x82, 0x01, 0x59, 0x30, 0x2f, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x23, + 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, + 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x65, 0x06, 0x03, 0x55, + 0x1d, 0x20, 0x04, 0x5e, 0x30, 0x5c, 0x30, 0x5a, 0x06, 0x04, 0x55, 0x1d, + 0x20, 0x00, 0x30, 0x52, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x28, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x1c, 0x1a, 0x1a, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, + 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, + 0x70, 0x61, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, + 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x31, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33, 0x2d, 0x67, 0x35, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x29, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, + 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, + 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, + 0x35, 0x33, 0x33, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0x01, 0x59, 0xab, 0xe7, 0xdd, 0x3a, 0x0b, 0x59, 0xa6, 0x64, + 0x63, 0xd6, 0xcf, 0x20, 0x07, 0x57, 0xd5, 0x91, 0xe7, 0x6a, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7f, + 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, 0x43, + 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x01, 0x00, 0x42, 0x01, 0x55, 0x7b, 0xd0, 0x16, 0x1a, 0x5d, 0x58, + 0xe8, 0xbb, 0x9b, 0xa8, 0x4d, 0xd7, 0xf3, 0xd7, 0xeb, 0x13, 0x94, 0x86, + 0xd6, 0x7f, 0x21, 0x0b, 0x47, 0xbc, 0x57, 0x9b, 0x92, 0x5d, 0x4f, 0x05, + 0x9f, 0x38, 0xa4, 0x10, 0x7c, 0xcf, 0x83, 0xbe, 0x06, 0x43, 0x46, 0x8d, + 0x08, 0xbc, 0x6a, 0xd7, 0x10, 0xa6, 0xfa, 0xab, 0xaf, 0x2f, 0x61, 0xa8, + 0x63, 0xf2, 0x65, 0xdf, 0x7f, 0x4c, 0x88, 0x12, 0x88, 0x4f, 0xb3, 0x69, + 0xd9, 0xff, 0x27, 0xc0, 0x0a, 0x97, 0x91, 0x8f, 0x56, 0xfb, 0x89, 0xc4, + 0xa8, 0xbb, 0x92, 0x2d, 0x1b, 0x73, 0xb0, 0xc6, 0xab, 0x36, 0xf4, 0x96, + 0x6c, 0x20, 0x08, 0xef, 0x0a, 0x1e, 0x66, 0x24, 0x45, 0x4f, 0x67, 0x00, + 0x40, 0xc8, 0x07, 0x54, 0x74, 0x33, 0x3b, 0xa6, 0xad, 0xbb, 0x23, 0x9f, + 0x66, 0xed, 0xa2, 0x44, 0x70, 0x34, 0xfb, 0x0e, 0xea, 0x01, 0xfd, 0xcf, + 0x78, 0x74, 0xdf, 0xa7, 0xad, 0x55, 0xb7, 0x5f, 0x4d, 0xf6, 0xd6, 0x3f, + 0xe0, 0x86, 0xce, 0x24, 0xc7, 0x42, 0xa9, 0x13, 0x14, 0x44, 0x35, 0x4b, + 0xb6, 0xdf, 0xc9, 0x60, 0xac, 0x0c, 0x7f, 0xd9, 0x93, 0x21, 0x4b, 0xee, + 0x9c, 0xe4, 0x49, 0x02, 0x98, 0xd3, 0x60, 0x7b, 0x5c, 0xbc, 0xd5, 0x30, + 0x2f, 0x07, 0xce, 0x44, 0x42, 0xc4, 0x0b, 0x99, 0xfe, 0xe6, 0x9f, 0xfc, + 0xb0, 0x78, 0x86, 0x51, 0x6d, 0xd1, 0x2c, 0x9d, 0xc6, 0x96, 0xfb, 0x85, + 0x82, 0xbb, 0x04, 0x2f, 0xf7, 0x62, 0x80, 0xef, 0x62, 0xda, 0x7f, 0xf6, + 0x0e, 0xac, 0x90, 0xb8, 0x56, 0xbd, 0x79, 0x3f, 0xf2, 0x80, 0x6e, 0xa3, + 0xd9, 0xb9, 0x0f, 0x5d, 0x3a, 0x07, 0x1d, 0x91, 0x93, 0x86, 0x4b, 0x29, + 0x4c, 0xe1, 0xdc, 0xb5, 0xe1, 0xe0, 0x33, 0x9d, 0xb3, 0xcb, 0x36, 0x91, + 0x4b, 0xfe, 0xa1, 0xb4, 0xee, 0xf0, 0xf9, +} + +var certSet2Cert43 = []byte{ + 0x30, 0x82, 0x05, 0x38, 0x30, 0x82, 0x04, 0x20, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x51, 0x3f, 0xb9, 0x74, 0x38, 0x70, 0xb7, 0x34, 0x40, + 0x41, 0x8d, 0x30, 0x93, 0x06, 0x99, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, 0x30, 0x33, 0x30, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x7e, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1d, + 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x53, 0x79, 0x6d, + 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x16, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x26, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x47, 0x34, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xb2, 0xd8, 0x05, 0xca, 0x1c, 0x74, 0x2d, 0xb5, 0x17, 0x56, 0x39, 0xc5, + 0x4a, 0x52, 0x09, 0x96, 0xe8, 0x4b, 0xd8, 0x0c, 0xf1, 0x68, 0x9f, 0x9a, + 0x42, 0x28, 0x62, 0xc3, 0xa5, 0x30, 0x53, 0x7e, 0x55, 0x11, 0x82, 0x5b, + 0x03, 0x7a, 0x0d, 0x2f, 0xe1, 0x79, 0x04, 0xc9, 0xb4, 0x96, 0x77, 0x19, + 0x81, 0x01, 0x94, 0x59, 0xf9, 0xbc, 0xf7, 0x7a, 0x99, 0x27, 0x82, 0x2d, + 0xb7, 0x83, 0xdd, 0x5a, 0x27, 0x7f, 0xb2, 0x03, 0x7a, 0x9c, 0x53, 0x25, + 0xe9, 0x48, 0x1f, 0x46, 0x4f, 0xc8, 0x9d, 0x29, 0xf8, 0xbe, 0x79, 0x56, + 0xf6, 0xf7, 0xfd, 0xd9, 0x3a, 0x68, 0xda, 0x8b, 0x4b, 0x82, 0x33, 0x41, + 0x12, 0xc3, 0xc8, 0x3c, 0xcc, 0xd6, 0x96, 0x7a, 0x84, 0x21, 0x1a, 0x22, + 0x04, 0x03, 0x27, 0x17, 0x8b, 0x1c, 0x68, 0x61, 0x93, 0x0f, 0x0e, 0x51, + 0x80, 0x33, 0x1d, 0xb4, 0xb5, 0xce, 0xeb, 0x7e, 0xd0, 0x62, 0xac, 0xee, + 0xb3, 0x7b, 0x01, 0x74, 0xef, 0x69, 0x35, 0xeb, 0xca, 0xd5, 0x3d, 0xa9, + 0xee, 0x97, 0x98, 0xca, 0x8d, 0xaa, 0x44, 0x0e, 0x25, 0x99, 0x4a, 0x15, + 0x96, 0xa4, 0xce, 0x6d, 0x02, 0x54, 0x1f, 0x2a, 0x6a, 0x26, 0xe2, 0x06, + 0x3a, 0x63, 0x48, 0xac, 0xb4, 0x4c, 0xd1, 0x75, 0x93, 0x50, 0xff, 0x13, + 0x2f, 0xd6, 0xda, 0xe1, 0xc6, 0x18, 0xf5, 0x9f, 0xc9, 0x25, 0x5d, 0xf3, + 0x00, 0x3a, 0xde, 0x26, 0x4d, 0xb4, 0x29, 0x09, 0xcd, 0x0f, 0x3d, 0x23, + 0x6f, 0x16, 0x4a, 0x81, 0x16, 0xfb, 0xf2, 0x83, 0x10, 0xc3, 0xb8, 0xd6, + 0xd8, 0x55, 0x32, 0x3d, 0xf1, 0xbd, 0x0f, 0xbd, 0x8c, 0x52, 0x95, 0x4a, + 0x16, 0x97, 0x7a, 0x52, 0x21, 0x63, 0x75, 0x2f, 0x16, 0xf9, 0xc4, 0x66, + 0xbe, 0xf5, 0xb5, 0x09, 0xd8, 0xff, 0x27, 0x00, 0xcd, 0x44, 0x7c, 0x6f, + 0x4b, 0x3f, 0xb0, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x63, 0x30, 0x82, 0x01, 0x5f, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, 0x27, + 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x73, 0x31, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33, 0x2d, 0x67, 0x35, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2f, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x23, 0x30, 0x21, 0x30, + 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, + 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x32, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x6b, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x64, 0x30, 0x62, 0x30, 0x60, 0x06, 0x0a, 0x60, + 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, 0x52, 0x30, + 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, + 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x70, 0x73, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x02, 0x30, 0x1c, 0x1a, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, + 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x29, 0x06, + 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, + 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, + 0x2d, 0x35, 0x33, 0x34, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x5f, 0x60, 0xcf, 0x61, 0x90, 0x55, 0xdf, 0x84, 0x43, + 0x14, 0x8a, 0x60, 0x2a, 0xb2, 0xf5, 0x7a, 0xf4, 0x43, 0x18, 0xef, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x5e, 0x94, 0x56, 0x49, 0xdd, 0x8e, 0x2d, 0x65, + 0xf5, 0xc1, 0x36, 0x51, 0xb6, 0x03, 0xe3, 0xda, 0x9e, 0x73, 0x19, 0xf2, + 0x1f, 0x59, 0xab, 0x58, 0x7e, 0x6c, 0x26, 0x05, 0x2c, 0xfa, 0x81, 0xd7, + 0x5c, 0x23, 0x17, 0x22, 0x2c, 0x37, 0x93, 0xf7, 0x86, 0xec, 0x85, 0xe6, + 0xb0, 0xa3, 0xfd, 0x1f, 0xe2, 0x32, 0xa8, 0x45, 0x6f, 0xe1, 0xd9, 0xfb, + 0xb9, 0xaf, 0xd2, 0x70, 0xa0, 0x32, 0x42, 0x65, 0xbf, 0x84, 0xfe, 0x16, + 0x2a, 0x8f, 0x3f, 0xc5, 0xa6, 0xd6, 0xa3, 0x93, 0x7d, 0x43, 0xe9, 0x74, + 0x21, 0x91, 0x35, 0x28, 0xf4, 0x63, 0xe9, 0x2e, 0xed, 0xf7, 0xf5, 0x5c, + 0x7f, 0x4b, 0x9a, 0xb5, 0x20, 0xe9, 0x0a, 0xbd, 0xe0, 0x45, 0x10, 0x0c, + 0x14, 0x94, 0x9a, 0x5d, 0xa5, 0xe3, 0x4b, 0x91, 0xe8, 0x24, 0x9b, 0x46, + 0x40, 0x65, 0xf4, 0x22, 0x72, 0xcd, 0x99, 0xf8, 0x88, 0x11, 0xf5, 0xf3, + 0x7f, 0xe6, 0x33, 0x82, 0xe6, 0xa8, 0xc5, 0x7e, 0xfe, 0xd0, 0x08, 0xe2, + 0x25, 0x58, 0x08, 0x71, 0x68, 0xe6, 0xcd, 0xa2, 0xe6, 0x14, 0xde, 0x4e, + 0x52, 0x24, 0x2d, 0xfd, 0xe5, 0x79, 0x13, 0x53, 0xe7, 0x5e, 0x2f, 0x2d, + 0x4d, 0x1b, 0x6d, 0x40, 0x15, 0x52, 0x2b, 0xf7, 0x87, 0x89, 0x78, 0x12, + 0x81, 0x6e, 0xd9, 0x4d, 0xaa, 0x2d, 0x78, 0xd4, 0xc2, 0x2c, 0x3d, 0x08, + 0x5f, 0x87, 0x91, 0x9e, 0x1f, 0x0e, 0xb0, 0xde, 0x30, 0x52, 0x64, 0x86, + 0x89, 0xaa, 0x9d, 0x66, 0x9c, 0x0e, 0x76, 0x0c, 0x80, 0xf2, 0x74, 0xd8, + 0x2a, 0xf8, 0xb8, 0x3a, 0xce, 0xd7, 0xd6, 0x0f, 0x11, 0xbe, 0x6b, 0xab, + 0x14, 0xf5, 0xbd, 0x41, 0xa0, 0x22, 0x63, 0x89, 0xf1, 0xba, 0x0f, 0x6f, + 0x29, 0x63, 0x66, 0x2d, 0x3f, 0xac, 0x8c, 0x72, 0xc5, 0xfb, 0xc7, 0xe4, + 0xd4, 0x0f, 0xf2, 0x3b, 0x4f, 0x8c, 0x29, 0xc7, +} + +var certSet2Cert44 = []byte{ + 0x30, 0x82, 0x05, 0x86, 0x30, 0x82, 0x04, 0x6e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0x9a, 0xa9, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, + 0x31, 0x32, 0x31, 0x39, 0x32, 0x30, 0x30, 0x37, 0x33, 0x32, 0x5a, 0x17, + 0x0d, 0x31, 0x37, 0x31, 0x32, 0x31, 0x39, 0x32, 0x30, 0x30, 0x36, 0x35, + 0x35, 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, + 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, + 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x0c, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, + 0x74, 0x20, 0x49, 0x54, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x20, 0x49, 0x54, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, + 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xd1, 0xe8, 0x37, + 0xa7, 0x76, 0x8a, 0x70, 0x4b, 0x19, 0xf0, 0x20, 0x37, 0x09, 0x24, 0x37, + 0x7f, 0xea, 0xfb, 0x78, 0xe6, 0x05, 0xba, 0x6a, 0xad, 0x4e, 0x27, 0x0d, + 0xfc, 0x72, 0x6a, 0xd9, 0x6c, 0x21, 0xc4, 0x64, 0x11, 0x95, 0x73, 0x10, + 0x0a, 0x5c, 0x25, 0x7b, 0x88, 0x6c, 0x94, 0x04, 0xfd, 0xc7, 0xdb, 0xae, + 0x7b, 0xdc, 0x4a, 0x08, 0xb3, 0x3e, 0x16, 0xf1, 0xd0, 0xad, 0xdb, 0x30, + 0x6d, 0xd7, 0x1a, 0x1e, 0x52, 0xb5, 0x3d, 0xf0, 0x47, 0x19, 0x03, 0xe2, + 0x7d, 0xa6, 0xbd, 0x57, 0x13, 0x3f, 0x54, 0xea, 0x3a, 0xa3, 0xb1, 0x77, + 0xfc, 0x42, 0xf0, 0x63, 0x49, 0x6a, 0x91, 0x80, 0x2e, 0x30, 0x49, 0xc0, + 0x8a, 0xeb, 0x2b, 0xaf, 0xfe, 0x3a, 0xeb, 0x07, 0x5d, 0x06, 0xf7, 0xe9, + 0xfd, 0x84, 0x0e, 0x91, 0xbd, 0x09, 0x20, 0x29, 0xe8, 0x6e, 0x5d, 0x09, + 0xce, 0x15, 0xd3, 0xe7, 0xef, 0xdb, 0x50, 0xeb, 0x44, 0xef, 0x18, 0x57, + 0xab, 0x04, 0x1d, 0xbc, 0x31, 0xf9, 0xf7, 0x7b, 0x2a, 0x13, 0xcf, 0xd1, + 0x3d, 0x51, 0xaf, 0x1b, 0xc5, 0xb5, 0x7b, 0xe7, 0xb0, 0xfc, 0x53, 0xbb, + 0x9a, 0xe7, 0x63, 0xde, 0x41, 0x33, 0xb6, 0x47, 0x24, 0x69, 0x5d, 0xb8, + 0x46, 0xa7, 0xff, 0xad, 0xab, 0xdf, 0x4f, 0x7a, 0x78, 0x25, 0x27, 0x21, + 0x26, 0x34, 0xca, 0x02, 0x6e, 0x37, 0x51, 0xf0, 0xed, 0x58, 0x1a, 0x60, + 0x94, 0xf6, 0xc4, 0x93, 0xd8, 0xdd, 0x30, 0x24, 0x25, 0xd7, 0x1c, 0xeb, + 0x19, 0x94, 0x35, 0x5d, 0x93, 0xb2, 0xae, 0xaa, 0x29, 0x83, 0x73, 0xc4, + 0x74, 0x59, 0x05, 0x52, 0x67, 0x9d, 0xda, 0x67, 0x51, 0x39, 0x05, 0x3a, + 0x36, 0xea, 0xf2, 0x1e, 0x76, 0x2b, 0x14, 0xae, 0xec, 0x3d, 0xf9, 0x14, + 0x99, 0x8b, 0x07, 0x6e, 0xbc, 0xe7, 0x0c, 0x56, 0xde, 0xac, 0xbe, 0xae, + 0xdb, 0x75, 0x32, 0x90, 0x9e, 0x63, 0xbd, 0x74, 0xbf, 0xe0, 0x0a, 0xca, + 0xf8, 0x34, 0x96, 0x67, 0x84, 0xcd, 0xd1, 0x42, 0x38, 0x78, 0xc7, 0x99, + 0xb6, 0x0c, 0xce, 0xb6, 0x0f, 0xe9, 0x1b, 0xcb, 0xf4, 0x59, 0xbe, 0x11, + 0x0e, 0xcb, 0x2c, 0x32, 0xc8, 0xfa, 0x83, 0x29, 0x64, 0x79, 0x3c, 0x8b, + 0x4b, 0xf0, 0x32, 0x74, 0x6c, 0xf3, 0x93, 0xb8, 0x96, 0x6b, 0x5d, 0x57, + 0x5a, 0x68, 0xc1, 0xcc, 0x0c, 0x79, 0x8a, 0x19, 0xde, 0xf5, 0x49, 0x02, + 0x5e, 0x08, 0x80, 0x01, 0x89, 0x0c, 0x32, 0xcd, 0xd2, 0xd6, 0x96, 0xd5, + 0x4b, 0xa0, 0xf3, 0xec, 0xbf, 0xab, 0xf4, 0x7d, 0xb3, 0xa1, 0xb9, 0x7c, + 0xda, 0x4e, 0xd7, 0xe5, 0xb7, 0xac, 0xb9, 0xf2, 0x25, 0x5f, 0x01, 0xcb, + 0x8c, 0x96, 0xa8, 0x28, 0xae, 0xc1, 0x33, 0x5a, 0xf6, 0x3f, 0x08, 0x90, + 0xdc, 0xeb, 0xff, 0x39, 0xd8, 0x26, 0xc8, 0x12, 0x9d, 0x1c, 0x9a, 0xaa, + 0xa9, 0xc0, 0x16, 0x8e, 0x86, 0xed, 0x67, 0x52, 0x96, 0x00, 0x7f, 0x0d, + 0x92, 0x3d, 0x3d, 0xd9, 0x70, 0x36, 0xe5, 0xea, 0x42, 0x6f, 0x1f, 0xae, + 0x95, 0xe5, 0x5b, 0x5d, 0xf8, 0xd0, 0x3a, 0xc7, 0xd4, 0xde, 0x77, 0x86, + 0xd0, 0xfc, 0x9e, 0x4e, 0xe2, 0xe2, 0xb8, 0xa9, 0x68, 0x37, 0x09, 0xc4, + 0x39, 0xe3, 0x85, 0xb8, 0x89, 0xf3, 0x1f, 0x6e, 0xb7, 0x6d, 0x1f, 0x4a, + 0x2f, 0x18, 0x09, 0x6f, 0xde, 0x4a, 0x01, 0x8f, 0x14, 0xc9, 0xb7, 0xa6, + 0xee, 0xa7, 0x63, 0x9f, 0x33, 0xa4, 0x54, 0x7c, 0x42, 0x83, 0x68, 0xb8, + 0xa5, 0xdf, 0xbf, 0xec, 0xb9, 0x1a, 0x5d, 0x13, 0x3b, 0xd9, 0xad, 0x68, + 0xfd, 0x20, 0x0a, 0x55, 0x91, 0x21, 0x64, 0xf9, 0xd7, 0x13, 0x01, 0xa0, + 0x08, 0x5d, 0x59, 0x89, 0x1b, 0x44, 0xaf, 0xa4, 0xac, 0xc7, 0x05, 0x10, + 0xfa, 0x41, 0x4a, 0xa8, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x20, 0x30, 0x82, 0x01, 0x1c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x53, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4c, 0x30, + 0x4a, 0x30, 0x48, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb1, 0x3e, + 0x01, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, + 0x63, 0x66, 0x6d, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x02, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0xe5, 0x9d, 0x59, 0x30, 0x82, 0x47, 0x58, 0xcc, 0xac, + 0xfa, 0x08, 0x54, 0x36, 0x86, 0x7b, 0x3a, 0xb5, 0x04, 0x4d, 0xf0, 0x30, + 0x42, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, + 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x64, 0x70, 0x31, 0x2e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, + 0x52, 0x4c, 0x2f, 0x4f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x32, + 0x30, 0x32, 0x35, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x51, 0xaf, 0x24, 0x26, 0x9c, 0xf4, + 0x68, 0x22, 0x57, 0x80, 0x26, 0x2b, 0x3b, 0x46, 0x62, 0x15, 0x7b, 0x1e, + 0xcc, 0xa5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x76, 0x85, + 0xc5, 0x23, 0x31, 0x1f, 0xb4, 0x73, 0xea, 0xa0, 0xbc, 0xa5, 0xed, 0xdf, + 0x45, 0x43, 0x6a, 0x7f, 0x69, 0x20, 0x1b, 0x80, 0xb2, 0xfb, 0x1c, 0xdd, + 0xaa, 0x7f, 0x88, 0xd3, 0x31, 0x41, 0x36, 0xf7, 0xfb, 0xfb, 0x6b, 0xad, + 0x98, 0x8c, 0x78, 0x1f, 0x9d, 0x11, 0x67, 0x3a, 0xcd, 0x4b, 0xec, 0xa8, + 0xbc, 0x9d, 0x15, 0x19, 0xc4, 0x3b, 0x0b, 0xa7, 0x93, 0xce, 0xe8, 0xfc, + 0x9d, 0x5b, 0xe8, 0x1f, 0xcb, 0x56, 0xae, 0x76, 0x43, 0x2b, 0xc7, 0x13, + 0x51, 0x77, 0x41, 0xa8, 0x66, 0x4c, 0x5f, 0xa7, 0xd1, 0xd7, 0xaa, 0x75, + 0xc5, 0x1b, 0x29, 0x4c, 0xc9, 0xf4, 0x6d, 0xa1, 0x5e, 0xa1, 0x85, 0x93, + 0x16, 0xc2, 0xcb, 0x3b, 0xab, 0x14, 0x7d, 0x44, 0xfd, 0xda, 0x25, 0x29, + 0x86, 0x2a, 0xfe, 0x63, 0x20, 0xca, 0xd2, 0x0b, 0xc2, 0x34, 0x15, 0xbb, + 0xaf, 0x5b, 0x7f, 0x8a, 0xe0, 0xaa, 0xed, 0x45, 0xa6, 0xea, 0x79, 0xdb, + 0xd8, 0x35, 0x66, 0x54, 0x43, 0xde, 0x37, 0x33, 0xd1, 0xe4, 0xe0, 0xcd, + 0x57, 0xca, 0x71, 0xb0, 0x7d, 0xe9, 0x16, 0x77, 0x64, 0xe8, 0x59, 0x97, + 0xb9, 0xd5, 0x2e, 0xd1, 0xb4, 0x91, 0xda, 0x77, 0x71, 0xf3, 0x4a, 0x0f, + 0x48, 0xd2, 0x34, 0x99, 0x60, 0x95, 0x37, 0xac, 0x1f, 0x01, 0xcd, 0x10, + 0x9d, 0xe8, 0x2a, 0xa5, 0x20, 0xc7, 0x50, 0x9b, 0xb3, 0x6c, 0x49, 0x78, + 0x2b, 0x58, 0x92, 0x64, 0x89, 0xb8, 0x95, 0x36, 0xa8, 0x34, 0xaa, 0xf0, + 0x41, 0xd2, 0x95, 0x5a, 0x24, 0x54, 0x97, 0x4d, 0x6e, 0x05, 0xc4, 0x95, + 0xad, 0xc4, 0x7a, 0xa3, 0x39, 0xfb, 0x79, 0x06, 0x8a, 0x9b, 0xa6, 0x4f, + 0xd9, 0x22, 0xfa, 0x44, 0x4e, 0x36, 0xf3, 0xc9, 0x0f, 0xa6, 0x39, 0xe7, + 0x80, 0xb2, 0x5e, 0xbf, 0xbd, 0x39, 0xd1, 0x46, 0xe5, 0x55, 0x47, 0xdb, + 0xbc, 0x6e, +} + +var certSet2Cert45 = []byte{ + 0x30, 0x82, 0x05, 0xa3, 0x30, 0x82, 0x03, 0x8b, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x67, 0x3f, 0x33, 0x4f, 0x21, 0x53, 0x36, 0x52, 0xc3, + 0x5e, 0x15, 0xd2, 0xfd, 0xb3, 0x02, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x55, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, + 0x4e, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, + 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x21, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x57, 0x6f, 0x53, 0x69, 0x67, + 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x38, 0x30, 0x38, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x35, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x38, + 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x35, 0x5a, 0x30, 0x4f, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x57, + 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x65, 0x64, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x1b, 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x4f, 0x56, 0x20, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xbc, 0x89, 0xbe, 0x61, 0x51, 0x53, 0xc8, 0x2b, 0x96, + 0x75, 0xb3, 0x5a, 0xd3, 0x0e, 0x34, 0xfe, 0x4a, 0xc2, 0x9f, 0xa3, 0x18, + 0x83, 0xa2, 0xac, 0xe3, 0x2e, 0x5e, 0x93, 0x79, 0x0b, 0x13, 0x49, 0x5e, + 0x93, 0xb2, 0x8f, 0x84, 0x10, 0xed, 0x91, 0x8f, 0x82, 0xba, 0xad, 0x67, + 0xdf, 0x33, 0x1b, 0xae, 0x84, 0xf2, 0x55, 0xb0, 0x5b, 0xf4, 0xb3, 0x9e, + 0xbc, 0xe6, 0x04, 0x0f, 0x1d, 0xef, 0x04, 0x5a, 0xa8, 0x0b, 0xec, 0x12, + 0x6d, 0x56, 0x19, 0x64, 0x70, 0x49, 0x0f, 0x57, 0x92, 0xf3, 0x5f, 0x21, + 0xa6, 0x4d, 0xb4, 0xd2, 0x96, 0x2b, 0x3c, 0x32, 0xb3, 0xef, 0x8f, 0x59, + 0x0b, 0x14, 0xba, 0x6e, 0xa2, 0x9e, 0x71, 0xdb, 0xf2, 0x88, 0x3f, 0x28, + 0x3b, 0xec, 0xce, 0xbe, 0x47, 0xac, 0x45, 0xc7, 0x8a, 0x9e, 0xfa, 0x61, + 0x93, 0xc5, 0x49, 0x17, 0xb6, 0x46, 0xb6, 0xf7, 0x99, 0x16, 0x8c, 0x1c, + 0x6e, 0x31, 0xae, 0x69, 0xce, 0xed, 0xc6, 0x24, 0x92, 0x70, 0xa1, 0xcb, + 0x96, 0xc3, 0x6c, 0x16, 0xd0, 0xee, 0xcc, 0x4f, 0x86, 0x33, 0xb3, 0x41, + 0xe6, 0x3d, 0x3d, 0xdb, 0x0e, 0x8c, 0x33, 0x74, 0xbb, 0xc3, 0xfc, 0x0b, + 0xa7, 0xfc, 0xd1, 0x71, 0xe2, 0xc1, 0x0c, 0xd4, 0xf7, 0xba, 0x3e, 0x80, + 0x90, 0xd4, 0x48, 0xeb, 0xa2, 0x83, 0x70, 0xd8, 0xdb, 0x30, 0x07, 0x29, + 0x89, 0xf9, 0x81, 0x21, 0x2c, 0xff, 0xeb, 0x47, 0xf6, 0x7a, 0x6d, 0x43, + 0x96, 0x67, 0x17, 0x3e, 0xf3, 0xe2, 0x73, 0x51, 0xc7, 0x76, 0x1e, 0xe9, + 0x1c, 0xa0, 0xec, 0x11, 0x1a, 0xb1, 0xcf, 0x1e, 0x2d, 0x9c, 0x55, 0xee, + 0x3b, 0xc6, 0x2d, 0xae, 0xdc, 0x66, 0x65, 0x91, 0xa2, 0x66, 0x9c, 0xac, + 0x82, 0xf1, 0xa4, 0x17, 0xb5, 0xd7, 0x43, 0x83, 0xc3, 0x88, 0xa0, 0x64, + 0xde, 0xca, 0x72, 0x45, 0xdc, 0x38, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x73, 0x30, 0x82, 0x01, 0x6f, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x29, + 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x31, 0x2e, 0x77, + 0x6f, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x61, + 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x27, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x31, 0x2e, + 0x77, 0x6f, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x61, 0x31, 0x30, 0x38, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x61, + 0x69, 0x61, 0x31, 0x2e, 0x77, 0x6f, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x61, 0x31, 0x2d, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x33, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x63, 0x65, 0x72, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x62, + 0x2e, 0x81, 0xd9, 0xe3, 0x42, 0x79, 0x14, 0xa3, 0xcd, 0xd9, 0x54, 0x8a, + 0x6e, 0xf8, 0xde, 0x95, 0xaa, 0x8f, 0x98, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe1, 0x66, 0xcf, 0x0e, + 0xd1, 0xf1, 0xb3, 0x4b, 0xb7, 0x06, 0x20, 0x14, 0xfe, 0x87, 0x12, 0xd5, + 0xf6, 0xfe, 0xfb, 0x3e, 0x30, 0x45, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x3e, 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, + 0x82, 0x9b, 0x51, 0x01, 0x03, 0x02, 0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x73, + 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0xab, + 0x70, 0xaa, 0x64, 0xc4, 0x0b, 0x34, 0x91, 0xb9, 0x63, 0x20, 0x5e, 0xb0, + 0x9c, 0x21, 0xff, 0x25, 0x79, 0x6c, 0x57, 0x4e, 0x56, 0x44, 0x58, 0x83, + 0xb9, 0x00, 0xce, 0x2d, 0x65, 0xa8, 0x6d, 0x95, 0x38, 0xea, 0x82, 0x2d, + 0x55, 0x18, 0x60, 0x12, 0x7e, 0x1a, 0x1d, 0x6b, 0x62, 0x34, 0x2c, 0xd9, + 0xcd, 0x17, 0x00, 0x43, 0x84, 0x3e, 0xad, 0xbc, 0xff, 0x26, 0x85, 0x1f, + 0x4a, 0xa7, 0x46, 0x13, 0xb0, 0x7d, 0x3b, 0x0b, 0xd9, 0x4b, 0x9d, 0xb0, + 0xcf, 0x8d, 0xf4, 0x05, 0xcb, 0x12, 0x29, 0xfe, 0xe1, 0x97, 0xc7, 0xb7, + 0xc7, 0xaa, 0x53, 0x7e, 0x39, 0x2d, 0x9d, 0xf6, 0xd4, 0x5e, 0xb7, 0x8c, + 0x15, 0x6a, 0x81, 0xd2, 0x37, 0x1a, 0x43, 0x0e, 0xcb, 0xe6, 0x30, 0x21, + 0x43, 0x83, 0x69, 0x0f, 0xef, 0x6b, 0xcd, 0x10, 0xf9, 0x84, 0x60, 0xcf, + 0x89, 0xe9, 0x88, 0x10, 0x01, 0xaf, 0x09, 0xf3, 0x48, 0xbb, 0x07, 0x09, + 0x75, 0x01, 0x84, 0xfa, 0xb1, 0x1e, 0x51, 0x19, 0x8f, 0xc6, 0xc9, 0x85, + 0x65, 0x16, 0x5f, 0xe0, 0x56, 0x7e, 0xb7, 0xbf, 0x40, 0xc2, 0xd4, 0xd0, + 0x05, 0x1f, 0x93, 0x63, 0xc9, 0x24, 0x08, 0x3b, 0x91, 0xb2, 0x35, 0xe1, + 0xa4, 0x8f, 0x35, 0xdb, 0x24, 0x58, 0x75, 0x39, 0xe4, 0xdd, 0x10, 0x1a, + 0xb0, 0xdf, 0x13, 0x12, 0x73, 0x9e, 0x6d, 0xe7, 0x67, 0x3c, 0xdb, 0x1c, + 0x1c, 0xdd, 0x10, 0xdd, 0xcc, 0xf4, 0x07, 0x09, 0xb9, 0x2e, 0xe5, 0x75, + 0x6d, 0x97, 0xb7, 0x60, 0x5b, 0x89, 0x70, 0x81, 0xd2, 0x26, 0xd8, 0xc6, + 0x09, 0x2b, 0xb2, 0x05, 0x7f, 0xc4, 0xb8, 0x14, 0x41, 0x1e, 0x07, 0xf0, + 0x48, 0x41, 0x63, 0xcb, 0x0c, 0xaa, 0x45, 0x7e, 0x84, 0xf9, 0x33, 0xb3, + 0x58, 0x87, 0xbc, 0xb1, 0xd6, 0xc2, 0x65, 0xc7, 0x57, 0xc6, 0x95, 0xe8, + 0x85, 0x90, 0xb0, 0x62, 0x50, 0xf5, 0xee, 0x12, 0xf1, 0xd8, 0x7e, 0x73, + 0xcb, 0xc0, 0xc3, 0xa0, 0x25, 0x17, 0x23, 0x37, 0x91, 0xba, 0x63, 0xbd, + 0x84, 0xaf, 0xf3, 0x89, 0xe0, 0x51, 0xc2, 0x73, 0x35, 0x6d, 0x63, 0x86, + 0x21, 0xf2, 0x73, 0xbd, 0xc2, 0x47, 0xe0, 0x4d, 0x7e, 0x46, 0x37, 0x4b, + 0xd0, 0xf7, 0x61, 0x2a, 0xc7, 0x94, 0x50, 0x25, 0x36, 0xe8, 0xae, 0xda, + 0x2e, 0x1f, 0xb8, 0x08, 0xb2, 0x55, 0x7c, 0x6b, 0x66, 0x43, 0x8f, 0x02, + 0x1d, 0xdd, 0xa7, 0xeb, 0x98, 0x00, 0xa7, 0x25, 0x74, 0xf5, 0x93, 0x1b, + 0x6d, 0x26, 0xbb, 0x1d, 0xe5, 0xb7, 0xfc, 0x21, 0x25, 0x26, 0xd1, 0x77, + 0x1b, 0xa8, 0x6e, 0xaa, 0xc3, 0x4b, 0x64, 0x51, 0x7f, 0x91, 0x0e, 0x41, + 0x5c, 0x19, 0x83, 0xa1, 0xa8, 0x1f, 0x94, 0x99, 0x43, 0x0f, 0x99, 0xdb, + 0x18, 0xdc, 0x21, 0x6f, 0x76, 0xd1, 0x9e, 0xea, 0xa3, 0x76, 0xe0, 0xf0, + 0x09, 0xbc, 0xb9, 0xb4, 0xf7, 0x43, 0x6c, 0x1f, 0xd3, 0x2a, 0x86, 0x6a, + 0x2f, 0xe0, 0x6c, 0xf1, 0x83, 0x39, 0xd7, 0x70, 0xdb, 0xa2, 0x91, 0xab, + 0x54, 0xbe, 0xf4, 0x47, 0x88, 0x8c, 0xf0, 0x10, 0xd2, 0xe4, 0xad, 0xeb, + 0x7e, 0xb1, 0xba, 0x08, 0x4b, 0x67, 0x04, 0xa3, 0xf2, 0xe9, 0x90, 0x2b, + 0x81, 0xe3, 0x74, 0x76, 0x3d, 0x00, 0x9d, 0xd2, 0xbb, 0xfc, 0xa5, 0xa0, + 0x15, 0x1c, 0x28, 0xdf, 0x10, 0x4f, 0x47, 0xd7, 0x33, 0x46, 0x9d, 0xb2, + 0x57, 0xd2, 0xc6, 0x1f, 0xfb, 0xe4, 0x59, 0x4a, 0x2b, 0x28, 0xa9, 0x13, + 0xdd, 0xb9, 0xe9, 0x93, 0xb4, 0x88, 0xee, 0xe2, 0x5b, 0xa0, 0x07, 0x25, + 0xfe, 0x8a, 0x2e, 0x78, 0xe4, 0xb4, 0xe1, 0xd5, 0x1d, 0xf6, 0x1a, 0x3a, + 0xe3, 0x1c, 0x01, 0x2a, 0x1e, 0xa1, 0x86, 0x54, 0x9e, 0x49, 0xdc, 0xc9, + 0x59, 0xe3, 0x0d, 0x6d, 0x5a, 0x13, 0x36, +} + +var certSet2Cert46 = []byte{ + 0x30, 0x82, 0x05, 0xe1, 0x30, 0x82, 0x04, 0xc9, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0xaa, 0x47, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, + 0x30, 0x35, 0x30, 0x37, 0x31, 0x37, 0x30, 0x34, 0x30, 0x39, 0x5a, 0x17, + 0x0d, 0x31, 0x38, 0x30, 0x35, 0x30, 0x37, 0x31, 0x37, 0x30, 0x33, 0x33, + 0x30, 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, + 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, + 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x0c, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, + 0x74, 0x20, 0x49, 0x54, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x20, 0x49, 0x54, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, + 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xd1, 0xe8, 0x37, + 0xa7, 0x76, 0x8a, 0x70, 0x4b, 0x19, 0xf0, 0x20, 0x37, 0x09, 0x24, 0x37, + 0x7f, 0xea, 0xfb, 0x78, 0xe6, 0x05, 0xba, 0x6a, 0xad, 0x4e, 0x27, 0x0d, + 0xfc, 0x72, 0x6a, 0xd9, 0x6c, 0x21, 0xc4, 0x64, 0x11, 0x95, 0x73, 0x10, + 0x0a, 0x5c, 0x25, 0x7b, 0x88, 0x6c, 0x94, 0x04, 0xfd, 0xc7, 0xdb, 0xae, + 0x7b, 0xdc, 0x4a, 0x08, 0xb3, 0x3e, 0x16, 0xf1, 0xd0, 0xad, 0xdb, 0x30, + 0x6d, 0xd7, 0x1a, 0x1e, 0x52, 0xb5, 0x3d, 0xf0, 0x47, 0x19, 0x03, 0xe2, + 0x7d, 0xa6, 0xbd, 0x57, 0x13, 0x3f, 0x54, 0xea, 0x3a, 0xa3, 0xb1, 0x77, + 0xfc, 0x42, 0xf0, 0x63, 0x49, 0x6a, 0x91, 0x80, 0x2e, 0x30, 0x49, 0xc0, + 0x8a, 0xeb, 0x2b, 0xaf, 0xfe, 0x3a, 0xeb, 0x07, 0x5d, 0x06, 0xf7, 0xe9, + 0xfd, 0x84, 0x0e, 0x91, 0xbd, 0x09, 0x20, 0x29, 0xe8, 0x6e, 0x5d, 0x09, + 0xce, 0x15, 0xd3, 0xe7, 0xef, 0xdb, 0x50, 0xeb, 0x44, 0xef, 0x18, 0x57, + 0xab, 0x04, 0x1d, 0xbc, 0x31, 0xf9, 0xf7, 0x7b, 0x2a, 0x13, 0xcf, 0xd1, + 0x3d, 0x51, 0xaf, 0x1b, 0xc5, 0xb5, 0x7b, 0xe7, 0xb0, 0xfc, 0x53, 0xbb, + 0x9a, 0xe7, 0x63, 0xde, 0x41, 0x33, 0xb6, 0x47, 0x24, 0x69, 0x5d, 0xb8, + 0x46, 0xa7, 0xff, 0xad, 0xab, 0xdf, 0x4f, 0x7a, 0x78, 0x25, 0x27, 0x21, + 0x26, 0x34, 0xca, 0x02, 0x6e, 0x37, 0x51, 0xf0, 0xed, 0x58, 0x1a, 0x60, + 0x94, 0xf6, 0xc4, 0x93, 0xd8, 0xdd, 0x30, 0x24, 0x25, 0xd7, 0x1c, 0xeb, + 0x19, 0x94, 0x35, 0x5d, 0x93, 0xb2, 0xae, 0xaa, 0x29, 0x83, 0x73, 0xc4, + 0x74, 0x59, 0x05, 0x52, 0x67, 0x9d, 0xda, 0x67, 0x51, 0x39, 0x05, 0x3a, + 0x36, 0xea, 0xf2, 0x1e, 0x76, 0x2b, 0x14, 0xae, 0xec, 0x3d, 0xf9, 0x14, + 0x99, 0x8b, 0x07, 0x6e, 0xbc, 0xe7, 0x0c, 0x56, 0xde, 0xac, 0xbe, 0xae, + 0xdb, 0x75, 0x32, 0x90, 0x9e, 0x63, 0xbd, 0x74, 0xbf, 0xe0, 0x0a, 0xca, + 0xf8, 0x34, 0x96, 0x67, 0x84, 0xcd, 0xd1, 0x42, 0x38, 0x78, 0xc7, 0x99, + 0xb6, 0x0c, 0xce, 0xb6, 0x0f, 0xe9, 0x1b, 0xcb, 0xf4, 0x59, 0xbe, 0x11, + 0x0e, 0xcb, 0x2c, 0x32, 0xc8, 0xfa, 0x83, 0x29, 0x64, 0x79, 0x3c, 0x8b, + 0x4b, 0xf0, 0x32, 0x74, 0x6c, 0xf3, 0x93, 0xb8, 0x96, 0x6b, 0x5d, 0x57, + 0x5a, 0x68, 0xc1, 0xcc, 0x0c, 0x79, 0x8a, 0x19, 0xde, 0xf5, 0x49, 0x02, + 0x5e, 0x08, 0x80, 0x01, 0x89, 0x0c, 0x32, 0xcd, 0xd2, 0xd6, 0x96, 0xd5, + 0x4b, 0xa0, 0xf3, 0xec, 0xbf, 0xab, 0xf4, 0x7d, 0xb3, 0xa1, 0xb9, 0x7c, + 0xda, 0x4e, 0xd7, 0xe5, 0xb7, 0xac, 0xb9, 0xf2, 0x25, 0x5f, 0x01, 0xcb, + 0x8c, 0x96, 0xa8, 0x28, 0xae, 0xc1, 0x33, 0x5a, 0xf6, 0x3f, 0x08, 0x90, + 0xdc, 0xeb, 0xff, 0x39, 0xd8, 0x26, 0xc8, 0x12, 0x9d, 0x1c, 0x9a, 0xaa, + 0xa9, 0xc0, 0x16, 0x8e, 0x86, 0xed, 0x67, 0x52, 0x96, 0x00, 0x7f, 0x0d, + 0x92, 0x3d, 0x3d, 0xd9, 0x70, 0x36, 0xe5, 0xea, 0x42, 0x6f, 0x1f, 0xae, + 0x95, 0xe5, 0x5b, 0x5d, 0xf8, 0xd0, 0x3a, 0xc7, 0xd4, 0xde, 0x77, 0x86, + 0xd0, 0xfc, 0x9e, 0x4e, 0xe2, 0xe2, 0xb8, 0xa9, 0x68, 0x37, 0x09, 0xc4, + 0x39, 0xe3, 0x85, 0xb8, 0x89, 0xf3, 0x1f, 0x6e, 0xb7, 0x6d, 0x1f, 0x4a, + 0x2f, 0x18, 0x09, 0x6f, 0xde, 0x4a, 0x01, 0x8f, 0x14, 0xc9, 0xb7, 0xa6, + 0xee, 0xa7, 0x63, 0x9f, 0x33, 0xa4, 0x54, 0x7c, 0x42, 0x83, 0x68, 0xb8, + 0xa5, 0xdf, 0xbf, 0xec, 0xb9, 0x1a, 0x5d, 0x13, 0x3b, 0xd9, 0xad, 0x68, + 0xfd, 0x20, 0x0a, 0x55, 0x91, 0x21, 0x64, 0xf9, 0xd7, 0x13, 0x01, 0xa0, + 0x08, 0x5d, 0x59, 0x89, 0x1b, 0x44, 0xaf, 0xa4, 0xac, 0xc7, 0x05, 0x10, + 0xfa, 0x41, 0x4a, 0xa8, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x7b, 0x30, 0x82, 0x01, 0x77, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x60, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x59, 0x30, + 0x57, 0x30, 0x48, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb1, 0x3e, + 0x01, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, + 0x63, 0x66, 0x6d, 0x30, 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, + 0x82, 0x37, 0x2a, 0x01, 0x30, 0x42, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x01, 0x01, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x26, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x6f, 0x6d, + 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, + 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x72, 0x6f, 0x6f, 0x74, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x01, 0x86, 0x30, 0x27, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, + 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe5, 0x9d, + 0x59, 0x30, 0x82, 0x47, 0x58, 0xcc, 0xac, 0xfa, 0x08, 0x54, 0x36, 0x86, + 0x7b, 0x3a, 0xb5, 0x04, 0x4d, 0xf0, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, + 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x64, 0x70, 0x31, + 0x2e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x52, 0x4c, 0x2f, 0x4f, 0x6d, + 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x32, 0x30, 0x32, 0x35, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x51, 0xaf, 0x24, 0x26, 0x9c, 0xf4, 0x68, 0x22, 0x57, 0x80, 0x26, + 0x2b, 0x3b, 0x46, 0x62, 0x15, 0x7b, 0x1e, 0xcc, 0xa5, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0x69, 0x62, 0xf6, 0x84, 0x91, 0x00, 0xc4, + 0x6f, 0x82, 0x7b, 0x24, 0xe1, 0x42, 0xa2, 0xa5, 0x8b, 0x82, 0x5c, 0xa7, + 0xc5, 0x44, 0xcb, 0xe7, 0x52, 0x76, 0x63, 0xd3, 0x76, 0x9e, 0x78, 0xe2, + 0x69, 0x35, 0xb1, 0x38, 0xba, 0xb0, 0x96, 0xc6, 0x1f, 0xac, 0x7b, 0xc6, + 0xb2, 0x65, 0x77, 0x8b, 0x7d, 0x8d, 0xae, 0x64, 0xb9, 0xa5, 0x8c, 0x17, + 0xca, 0x58, 0x65, 0xc3, 0xad, 0x82, 0xf5, 0xc5, 0xa2, 0xf5, 0x01, 0x13, + 0x93, 0xc6, 0x7e, 0x44, 0xe5, 0xc4, 0x61, 0xfa, 0x03, 0xb6, 0x56, 0xc1, + 0x72, 0xe1, 0xc8, 0x28, 0xc5, 0x69, 0x21, 0x8f, 0xac, 0x6e, 0xfd, 0x7f, + 0x43, 0x83, 0x36, 0xb8, 0xc0, 0xd6, 0xa0, 0x28, 0xfe, 0x1a, 0x45, 0xbe, + 0xfd, 0x93, 0x8c, 0x8d, 0xa4, 0x64, 0x79, 0x1f, 0x14, 0xdb, 0xa1, 0x9f, + 0x21, 0xdc, 0xc0, 0x4e, 0x7b, 0x17, 0x22, 0x17, 0xb1, 0xb6, 0x3c, 0xd3, + 0x9b, 0xe2, 0x0a, 0xa3, 0x7e, 0x99, 0xb0, 0xc1, 0xac, 0xd8, 0xf4, 0x86, + 0xdf, 0x3c, 0xda, 0x7d, 0x14, 0x9c, 0x40, 0xc1, 0x7c, 0xd2, 0x18, 0x6f, + 0xf1, 0x4f, 0x26, 0x45, 0x09, 0x95, 0x94, 0x5c, 0xda, 0xd0, 0x98, 0xf8, + 0xf4, 0x4c, 0x82, 0x96, 0x10, 0xde, 0xac, 0x30, 0xcb, 0x2b, 0xae, 0xf9, + 0x92, 0xea, 0xbf, 0x79, 0x03, 0xfc, 0x1e, 0x3f, 0xac, 0x09, 0xa4, 0x3f, + 0x65, 0xfd, 0x91, 0x4f, 0x96, 0x24, 0xa7, 0xce, 0xb4, 0x4e, 0x6a, 0x96, + 0x29, 0x17, 0xae, 0xc0, 0xa8, 0xdf, 0x17, 0x22, 0xf4, 0x17, 0xe3, 0xdc, + 0x1c, 0x39, 0x06, 0x56, 0x10, 0xea, 0xea, 0xb5, 0x74, 0x17, 0x3c, 0x4e, + 0xdd, 0x7e, 0x91, 0x0a, 0xa8, 0x0b, 0x78, 0x07, 0xa7, 0x31, 0x44, 0x08, + 0x31, 0xab, 0x18, 0x84, 0x0f, 0x12, 0x9c, 0xe7, 0xde, 0x84, 0x2c, 0xe9, + 0x6d, 0x93, 0x45, 0xbf, 0xa8, 0xc1, 0x3f, 0x34, 0xdc, +} + +var certSet2Cert47 = []byte{ + 0x30, 0x82, 0x05, 0xec, 0x30, 0x82, 0x04, 0xd4, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x6e, 0xcc, 0x7a, 0xa5, 0xa7, 0x03, 0x20, 0x09, 0xb8, + 0xce, 0xbc, 0xf4, 0xe9, 0x52, 0xd4, 0x91, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x32, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x32, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xb5, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, + 0x39, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x31, 0x30, 0x31, 0x2f, + 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x56, 0x65, 0x72, + 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x33, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb1, 0x87, 0x84, 0x1f, + 0xc2, 0x0c, 0x45, 0xf5, 0xbc, 0xab, 0x25, 0x97, 0xa7, 0xad, 0xa2, 0x3e, + 0x9c, 0xba, 0xf6, 0xc1, 0x39, 0xb8, 0x8b, 0xca, 0xc2, 0xac, 0x56, 0xc6, + 0xe5, 0xbb, 0x65, 0x8e, 0x44, 0x4f, 0x4d, 0xce, 0x6f, 0xed, 0x09, 0x4a, + 0xd4, 0xaf, 0x4e, 0x10, 0x9c, 0x68, 0x8b, 0x2e, 0x95, 0x7b, 0x89, 0x9b, + 0x13, 0xca, 0xe2, 0x34, 0x34, 0xc1, 0xf3, 0x5b, 0xf3, 0x49, 0x7b, 0x62, + 0x83, 0x48, 0x81, 0x74, 0xd1, 0x88, 0x78, 0x6c, 0x02, 0x53, 0xf9, 0xbc, + 0x7f, 0x43, 0x26, 0x57, 0x58, 0x33, 0x83, 0x3b, 0x33, 0x0a, 0x17, 0xb0, + 0xd0, 0x4e, 0x91, 0x24, 0xad, 0x86, 0x7d, 0x64, 0x12, 0xdc, 0x74, 0x4a, + 0x34, 0xa1, 0x1d, 0x0a, 0xea, 0x96, 0x1d, 0x0b, 0x15, 0xfc, 0xa3, 0x4b, + 0x3b, 0xce, 0x63, 0x88, 0xd0, 0xf8, 0x2d, 0x0c, 0x94, 0x86, 0x10, 0xca, + 0xb6, 0x9a, 0x3d, 0xca, 0xeb, 0x37, 0x9c, 0x00, 0x48, 0x35, 0x86, 0x29, + 0x50, 0x78, 0xe8, 0x45, 0x63, 0xcd, 0x19, 0x41, 0x4f, 0xf5, 0x95, 0xec, + 0x7b, 0x98, 0xd4, 0xc4, 0x71, 0xb3, 0x50, 0xbe, 0x28, 0xb3, 0x8f, 0xa0, + 0xb9, 0x53, 0x9c, 0xf5, 0xca, 0x2c, 0x23, 0xa9, 0xfd, 0x14, 0x06, 0xe8, + 0x18, 0xb4, 0x9a, 0xe8, 0x3c, 0x6e, 0x81, 0xfd, 0xe4, 0xcd, 0x35, 0x36, + 0xb3, 0x51, 0xd3, 0x69, 0xec, 0x12, 0xba, 0x56, 0x6e, 0x6f, 0x9b, 0x57, + 0xc5, 0x8b, 0x14, 0xe7, 0x0e, 0xc7, 0x9c, 0xed, 0x4a, 0x54, 0x6a, 0xc9, + 0x4d, 0xc5, 0xbf, 0x11, 0xb1, 0xae, 0x1c, 0x67, 0x81, 0xcb, 0x44, 0x55, + 0x33, 0x99, 0x7f, 0x24, 0x9b, 0x3f, 0x53, 0x45, 0x7f, 0x86, 0x1a, 0xf3, + 0x3c, 0xfa, 0x6d, 0x7f, 0x81, 0xf5, 0xb8, 0x4a, 0xd3, 0xf5, 0x85, 0x37, + 0x1c, 0xb5, 0xa6, 0xd0, 0x09, 0xe4, 0x18, 0x7b, 0x38, 0x4e, 0xfa, 0x0f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xdf, 0x30, 0x82, 0x01, + 0xdb, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, + 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x70, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x69, + 0x30, 0x67, 0x30, 0x65, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, + 0x45, 0x01, 0x07, 0x17, 0x03, 0x30, 0x56, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, + 0x73, 0x30, 0x2a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x02, 0x30, 0x1e, 0x1a, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x34, 0x06, + 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2d, 0x30, 0x2b, 0x30, 0x29, 0xa0, 0x27, + 0xa0, 0x25, 0x86, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33, 0x2d, 0x67, 0x35, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x6d, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, 0xa1, + 0x5d, 0xa0, 0x5b, 0x30, 0x59, 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, 0x1f, + 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x8f, + 0xe5, 0xd3, 0x1a, 0x86, 0xac, 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, 0x6a, + 0xd4, 0x48, 0x18, 0x2c, 0x7b, 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x76, + 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x76, 0x73, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, 0x28, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x21, 0x30, 0x1f, 0xa4, 0x1d, 0x30, + 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, + 0x2d, 0x32, 0x2d, 0x36, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x0d, 0x44, 0x5c, 0x16, 0x53, 0x44, 0xc1, 0x82, 0x7e, + 0x1d, 0x20, 0xab, 0x25, 0xf4, 0x01, 0x63, 0xd8, 0xbe, 0x79, 0xa5, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x0c, 0x83, 0x24, 0xef, 0xdd, 0xc3, 0x0c, 0xd9, + 0x58, 0x9c, 0xfe, 0x36, 0xb6, 0xeb, 0x8a, 0x80, 0x4b, 0xd1, 0xa3, 0xf7, + 0x9d, 0xf3, 0xcc, 0x53, 0xef, 0x82, 0x9e, 0xa3, 0xa1, 0xe6, 0x97, 0xc1, + 0x58, 0x9d, 0x75, 0x6c, 0xe0, 0x1d, 0x1b, 0x4c, 0xfa, 0xd1, 0xc1, 0x2d, + 0x05, 0xc0, 0xea, 0x6e, 0xb2, 0x22, 0x70, 0x55, 0xd9, 0x20, 0x33, 0x40, + 0x33, 0x07, 0xc2, 0x65, 0x83, 0xfa, 0x8f, 0x43, 0x37, 0x9b, 0xea, 0x0e, + 0x9a, 0x6c, 0x70, 0xee, 0xf6, 0x9c, 0x80, 0x3b, 0xd9, 0x37, 0xf4, 0x7a, + 0x6d, 0xec, 0xd0, 0x18, 0x7d, 0x49, 0x4a, 0xca, 0x99, 0xc7, 0x19, 0x28, + 0xa2, 0xbe, 0xd8, 0x77, 0x24, 0xf7, 0x85, 0x26, 0x86, 0x6d, 0x87, 0x05, + 0x40, 0x41, 0x67, 0xd1, 0x27, 0x3a, 0xed, 0xdc, 0x48, 0x1d, 0x22, 0xcd, + 0x0b, 0x0b, 0x8b, 0xbc, 0xf4, 0xb1, 0x7b, 0xfd, 0xb4, 0x99, 0xa8, 0xe9, + 0x76, 0x2a, 0xe1, 0x1a, 0x2d, 0x87, 0x6e, 0x74, 0xd3, 0x88, 0xdd, 0x1e, + 0x22, 0xc6, 0xdf, 0x16, 0xb6, 0x2b, 0x82, 0x14, 0x0a, 0x94, 0x5c, 0xf2, + 0x50, 0xec, 0xaf, 0xce, 0xff, 0x62, 0x37, 0x0d, 0xad, 0x65, 0xd3, 0x06, + 0x41, 0x53, 0xed, 0x02, 0x14, 0xc8, 0xb5, 0x58, 0x28, 0xa1, 0xac, 0xe0, + 0x5b, 0xec, 0xb3, 0x7f, 0x95, 0x4a, 0xfb, 0x03, 0xc8, 0xad, 0x26, 0xdb, + 0xe6, 0x66, 0x78, 0x12, 0x4a, 0xd9, 0x9f, 0x42, 0xfb, 0xe1, 0x98, 0xe6, + 0x42, 0x83, 0x9b, 0x8f, 0x8f, 0x67, 0x24, 0xe8, 0x61, 0x19, 0xb5, 0xdd, + 0xcd, 0xb5, 0x0b, 0x26, 0x05, 0x8e, 0xc3, 0x6e, 0xc4, 0xc8, 0x75, 0xb8, + 0x46, 0xcf, 0xe2, 0x18, 0x06, 0x5e, 0xa9, 0xae, 0xa8, 0x81, 0x9a, 0x47, + 0x16, 0xde, 0x0c, 0x28, 0x6c, 0x25, 0x27, 0xb9, 0xde, 0xb7, 0x84, 0x58, + 0xc6, 0x1f, 0x38, 0x1e, 0xa4, 0xc4, 0xcb, 0x66, +} + +var certSet2Cert48 = []byte{ + 0x30, 0x82, 0x06, 0x1e, 0x30, 0x82, 0x05, 0x06, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x2c, 0x48, 0xdd, 0x93, 0x0d, 0xf5, 0x59, 0x8e, 0xf9, + 0x3c, 0x99, 0x54, 0x7a, 0x60, 0xed, 0x43, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xbe, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, + 0x39, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x36, 0x31, 0x38, + 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2f, 0x56, 0x65, 0x72, + 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x53, + 0x4c, 0x20, 0x53, 0x47, 0x43, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0x56, 0x88, 0xba, 0x88, 0x34, 0x64, + 0x64, 0xcf, 0xcd, 0xca, 0xb0, 0xee, 0xe7, 0x19, 0x73, 0xc5, 0x72, 0xd9, + 0xbb, 0x45, 0xbc, 0xb5, 0xa8, 0xff, 0x83, 0xbe, 0x1c, 0x03, 0xdb, 0xed, + 0x89, 0xb7, 0x2e, 0x10, 0x1a, 0x25, 0xbc, 0x55, 0xca, 0x41, 0xa1, 0x9f, + 0x0b, 0xcf, 0x19, 0x5e, 0x70, 0xb9, 0x5e, 0x39, 0x4b, 0x9e, 0x31, 0x1c, + 0x5f, 0x87, 0xae, 0x2a, 0xaa, 0xa8, 0x2b, 0xa2, 0x1b, 0x3b, 0x10, 0x23, + 0x5f, 0x13, 0xb1, 0xdd, 0x08, 0x8c, 0x4e, 0x14, 0xda, 0x83, 0x81, 0xe3, + 0xb5, 0x8c, 0xe3, 0x68, 0xed, 0x24, 0x67, 0xce, 0x56, 0xb6, 0xac, 0x9b, + 0x73, 0x96, 0x44, 0xdb, 0x8a, 0x8c, 0xb3, 0xd6, 0xf0, 0x71, 0x93, 0x8e, + 0xdb, 0x71, 0x54, 0x4a, 0xeb, 0x73, 0x59, 0x6a, 0x8f, 0x70, 0x51, 0x2c, + 0x03, 0x9f, 0x97, 0xd1, 0xcc, 0x11, 0x7a, 0xbc, 0x62, 0x0d, 0x95, 0x2a, + 0xc9, 0x1c, 0x75, 0x57, 0xe9, 0xf5, 0xc7, 0xea, 0xba, 0x84, 0x35, 0xcb, + 0xc7, 0x85, 0x5a, 0x7e, 0xe4, 0x4d, 0xe1, 0x11, 0x97, 0x7d, 0x0e, 0x20, + 0x34, 0x45, 0xdb, 0xf1, 0xa2, 0x09, 0xeb, 0xeb, 0x3d, 0x9e, 0xb8, 0x96, + 0x43, 0x5e, 0x34, 0x4b, 0x08, 0x25, 0x1e, 0x43, 0x1a, 0xa2, 0xd9, 0xb7, + 0x8a, 0x01, 0x34, 0x3d, 0xc3, 0xf8, 0xe5, 0xaf, 0x4f, 0x8c, 0xff, 0xcd, + 0x65, 0xf0, 0x23, 0x4e, 0xc5, 0x97, 0xb3, 0x5c, 0xda, 0x90, 0x1c, 0x82, + 0x85, 0x0d, 0x06, 0x0d, 0xc1, 0x22, 0xb6, 0x7b, 0x28, 0xa4, 0x03, 0xc3, + 0x4c, 0x53, 0xd1, 0x58, 0xbc, 0x72, 0xbc, 0x08, 0x39, 0xfc, 0xa0, 0x76, + 0xa8, 0xa8, 0xe9, 0x4b, 0x6e, 0x88, 0x3d, 0xe3, 0xb3, 0x31, 0x25, 0x8c, + 0x73, 0x29, 0x48, 0x0e, 0x32, 0x79, 0x06, 0xed, 0x3d, 0x43, 0xf4, 0xf6, + 0xe4, 0xe9, 0xfc, 0x7d, 0xbe, 0x8e, 0x08, 0xd5, 0x1f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x02, 0x08, 0x30, 0x82, 0x02, 0x04, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x4e, 0x43, 0xc8, + 0x1d, 0x76, 0xef, 0x37, 0x53, 0x7a, 0x4f, 0xf2, 0x58, 0x6f, 0x94, 0xf3, + 0x38, 0xe2, 0xd5, 0xbd, 0xdf, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, + 0x30, 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x63, 0x70, 0x73, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, + 0x36, 0x30, 0x34, 0x30, 0x32, 0xa0, 0x30, 0xa0, 0x2e, 0x86, 0x2c, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x45, 0x56, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, + 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33, + 0x2d, 0x67, 0x35, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, + 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x6d, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, 0xa1, 0x5d, + 0xa0, 0x5b, 0x30, 0x59, 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, 0x1f, 0x30, + 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x8f, 0xe5, + 0xd3, 0x1a, 0x86, 0xac, 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, 0x6a, 0xd4, + 0x48, 0x18, 0x2c, 0x7b, 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x76, 0x65, + 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, + 0x73, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, 0x29, 0x06, + 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x33, 0x43, 0x41, 0x32, 0x30, 0x34, 0x38, 0x2d, + 0x31, 0x2d, 0x34, 0x38, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, + 0xbb, 0xf0, 0x30, 0x09, 0xf3, 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, + 0x33, 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x45, 0x56, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d, 0x6f, + 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x2d, 0x30, 0x2b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, + 0x04, 0x01, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, + 0x08, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x27, 0x74, 0xa6, 0x34, 0xea, 0x1d, + 0x9d, 0xe1, 0x53, 0xd6, 0x1c, 0x9d, 0x0c, 0xa7, 0x5b, 0x4c, 0xa9, 0x67, + 0xf2, 0xf0, 0x32, 0xb7, 0x01, 0x0f, 0xfb, 0x42, 0x18, 0x38, 0xde, 0xe4, + 0xee, 0x49, 0xc8, 0x13, 0xc9, 0x0b, 0xec, 0x04, 0xc3, 0x40, 0x71, 0x18, + 0x72, 0x76, 0x43, 0x02, 0x23, 0x5d, 0xab, 0x7b, 0xc8, 0x48, 0x14, 0x1a, + 0xc8, 0x7b, 0x1d, 0xfc, 0xf6, 0x0a, 0x9f, 0x36, 0xa1, 0xd2, 0x09, 0x73, + 0x71, 0x66, 0x96, 0x75, 0x51, 0x34, 0xbf, 0x99, 0x30, 0x51, 0x67, 0x9d, + 0x54, 0xb7, 0x26, 0x45, 0xac, 0x73, 0x08, 0x23, 0x86, 0x26, 0x99, 0x71, + 0xf4, 0x8e, 0xd7, 0xea, 0x39, 0x9b, 0x06, 0x09, 0x23, 0xbf, 0x62, 0xdd, + 0xa8, 0xc4, 0xb6, 0x7d, 0xa4, 0x89, 0x07, 0x3e, 0xf3, 0x6d, 0xae, 0x40, + 0x59, 0x50, 0x79, 0x97, 0x37, 0x3d, 0x32, 0x78, 0x7d, 0xb2, 0x63, 0x4b, + 0xf9, 0xea, 0x08, 0x69, 0x0e, 0x13, 0xed, 0xe8, 0xcf, 0xbb, 0xac, 0x05, + 0x86, 0xca, 0x22, 0xcf, 0x88, 0x62, 0x5d, 0x3c, 0x22, 0x49, 0xd8, 0x63, + 0xd5, 0x24, 0xa6, 0xbd, 0xef, 0x5c, 0xe3, 0xcc, 0x20, 0x3b, 0x22, 0xea, + 0xfc, 0x44, 0xc6, 0xa8, 0xe5, 0x1f, 0xe1, 0x86, 0xcd, 0x0c, 0x4d, 0x8f, + 0x93, 0x53, 0xd9, 0x7f, 0xee, 0xa1, 0x08, 0xa7, 0xb3, 0x30, 0x96, 0x49, + 0x70, 0x6e, 0xa3, 0x6c, 0x3d, 0xd0, 0x63, 0xef, 0x25, 0x66, 0x63, 0xcc, + 0xaa, 0xb7, 0x18, 0x17, 0x4e, 0xea, 0x70, 0x76, 0xf6, 0xba, 0x42, 0xa6, + 0x80, 0x37, 0x09, 0x4e, 0x9f, 0x66, 0x88, 0x2e, 0x6b, 0x33, 0x66, 0xc8, + 0xc0, 0x71, 0xa4, 0x41, 0xeb, 0x5a, 0xe3, 0xfc, 0x14, 0x2e, 0x4b, 0x88, + 0xfd, 0xae, 0x6e, 0x5b, 0x65, 0xe9, 0x27, 0xe4, 0xbf, 0xe4, 0xb0, 0x23, + 0xc1, 0xb2, 0x7d, 0x5b, 0x62, 0x25, 0xd7, 0x3e, 0x10, 0xd4, +} + +var certSet2Cert49 = []byte{ + 0x30, 0x82, 0x06, 0x29, 0x30, 0x82, 0x05, 0x11, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x64, 0x1b, 0xe8, 0x20, 0xce, 0x02, 0x08, 0x13, 0xf3, + 0x2d, 0x4d, 0x2d, 0x95, 0xd6, 0x7e, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x32, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x32, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xbc, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, + 0x39, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x31, 0x30, 0x31, 0x36, + 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x56, 0x65, 0x72, + 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x33, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0x99, 0xd6, 0x9c, 0x62, 0xf0, 0x15, 0xf4, 0x81, 0x9a, + 0x41, 0x08, 0x59, 0x8f, 0x13, 0x9d, 0x17, 0xc9, 0x9f, 0x51, 0xdc, 0xda, + 0xb1, 0x52, 0xef, 0xff, 0xe3, 0x41, 0xdd, 0xe0, 0xdf, 0xc4, 0x28, 0xc6, + 0xe3, 0xad, 0x79, 0x1f, 0x27, 0x10, 0x98, 0xb8, 0xbb, 0x20, 0x97, 0xc1, + 0x28, 0x44, 0x41, 0x0f, 0xea, 0xa9, 0xa8, 0x52, 0xcf, 0x4d, 0x4e, 0x1b, + 0x8b, 0xbb, 0xb5, 0xc4, 0x76, 0xd9, 0xcc, 0x56, 0x06, 0xee, 0xb3, 0x55, + 0x20, 0x2a, 0xde, 0x15, 0x8d, 0x71, 0xcb, 0x54, 0xc8, 0x6f, 0x17, 0xcd, + 0x89, 0x00, 0xe4, 0xdc, 0xff, 0xe1, 0xc0, 0x1f, 0x68, 0x71, 0xe9, 0xc7, + 0x29, 0x2e, 0x7e, 0xbc, 0x3b, 0xfc, 0xe5, 0xbb, 0xab, 0x26, 0x54, 0x8b, + 0x66, 0x90, 0xcd, 0xf6, 0x92, 0xb9, 0x31, 0x24, 0x80, 0xbc, 0x9e, 0x6c, + 0xd5, 0xfc, 0x7e, 0xd2, 0xe1, 0x4b, 0x8c, 0xdc, 0x42, 0xfa, 0x44, 0x4b, + 0x5f, 0xf8, 0x18, 0xb5, 0x2e, 0x30, 0xf4, 0x3d, 0x12, 0x98, 0xd3, 0x62, + 0x05, 0x73, 0x54, 0xa6, 0x9c, 0xa2, 0x1d, 0xbe, 0x52, 0x83, 0x3a, 0x07, + 0x46, 0xc4, 0x3b, 0x02, 0x56, 0x21, 0xbf, 0xf2, 0x51, 0x4f, 0xd0, 0xa6, + 0x99, 0x39, 0xe9, 0xae, 0xa5, 0x3f, 0x89, 0x9b, 0x9c, 0x7d, 0xfe, 0x4d, + 0x60, 0x07, 0x25, 0x20, 0xf7, 0xbb, 0xd7, 0x69, 0x83, 0x2b, 0x82, 0x93, + 0x43, 0x37, 0xd9, 0x83, 0x41, 0x1b, 0x6b, 0x0b, 0xab, 0x4a, 0x66, 0x84, + 0x4f, 0x4a, 0x8e, 0xde, 0x7e, 0x34, 0x99, 0x8e, 0x68, 0xd6, 0xca, 0x39, + 0x06, 0x9b, 0x4c, 0xb3, 0x9a, 0x48, 0x4d, 0x13, 0x46, 0xb4, 0x58, 0x21, + 0x04, 0xc4, 0xfb, 0xa0, 0x4d, 0xac, 0x2e, 0x4b, 0x62, 0x12, 0xe3, 0xfb, + 0x4d, 0xf6, 0xc9, 0x51, 0x00, 0x01, 0x1f, 0xfc, 0x1e, 0x6a, 0x81, 0x2a, + 0x38, 0xe0, 0xb9, 0x4f, 0xd6, 0x2d, 0x45, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x02, 0x15, 0x30, 0x82, 0x02, 0x11, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x70, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x69, 0x30, 0x67, 0x30, 0x65, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, + 0xf8, 0x45, 0x01, 0x07, 0x17, 0x03, 0x30, 0x56, 0x30, 0x28, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, + 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x70, 0x73, 0x30, 0x2a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x02, 0x30, 0x1e, 0x1a, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, + 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x01, 0x06, 0x30, 0x6d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, 0xa1, 0x5d, 0xa0, 0x5b, 0x30, 0x59, + 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, + 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, + 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x8f, 0xe5, 0xd3, 0x1a, 0x86, 0xac, + 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, 0x6a, 0xd4, 0x48, 0x18, 0x2c, 0x7b, + 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, + 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x73, 0x6c, 0x6f, 0x67, + 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x25, + 0x04, 0x2d, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, 0x06, + 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x08, 0x01, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2d, 0x30, 0x2b, 0x30, 0x29, 0xa0, 0x27, 0xa0, 0x25, 0x86, 0x23, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, + 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x70, 0x63, 0x61, 0x33, 0x2d, 0x67, 0x35, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x28, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x21, 0x30, 0x1f, 0xa4, 0x1d, + 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x10, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, + 0x49, 0x2d, 0x32, 0x2d, 0x37, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xd7, 0x9b, 0x7c, 0xd8, 0x22, 0xa0, 0x15, 0xf7, + 0xdd, 0xad, 0x5f, 0xce, 0x29, 0x9b, 0x58, 0xc3, 0xbc, 0x46, 0x00, 0xb5, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, + 0xf3, 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0x71, 0xb5, 0x7d, 0x73, 0x52, 0x4a, 0xdd, + 0xd7, 0x4d, 0x34, 0x2b, 0x2e, 0xaf, 0x94, 0x46, 0xa5, 0x49, 0x50, 0x02, + 0x4f, 0xf8, 0x2f, 0x17, 0x70, 0xf2, 0x13, 0xdc, 0x1f, 0x21, 0x86, 0xaa, + 0xc2, 0x4f, 0x7c, 0x37, 0x3c, 0xd4, 0x46, 0x78, 0xae, 0x5d, 0x78, 0x6f, + 0xd1, 0xba, 0x5a, 0xbc, 0x10, 0xab, 0x58, 0x36, 0xc5, 0x8c, 0x62, 0x15, + 0x45, 0x60, 0x17, 0x21, 0xe2, 0xd5, 0x42, 0xa8, 0x77, 0xa1, 0x55, 0xd8, + 0x43, 0x04, 0x51, 0xf6, 0x6e, 0xba, 0x48, 0xe6, 0x5d, 0x4c, 0xb7, 0x44, + 0xd3, 0x3e, 0xa4, 0xd5, 0xd6, 0x33, 0x9a, 0x9f, 0x0d, 0xe6, 0xd7, 0x4e, + 0x96, 0x44, 0x95, 0x5a, 0x6c, 0xd6, 0xa3, 0x16, 0x53, 0x0e, 0x98, 0x43, + 0xce, 0xa4, 0xb8, 0xc3, 0x66, 0x7a, 0x05, 0x5c, 0x62, 0x10, 0xe8, 0x1b, + 0x12, 0xdb, 0x7d, 0x2e, 0x76, 0x50, 0xff, 0xdf, 0xd7, 0x6b, 0x1b, 0xcc, + 0x8a, 0xcc, 0x71, 0xfa, 0xb3, 0x40, 0x56, 0x7c, 0x33, 0x7a, 0x77, 0x94, + 0x5b, 0xf5, 0x0b, 0x53, 0xfb, 0x0e, 0x5f, 0xbc, 0x68, 0xfb, 0xaf, 0x2a, + 0xee, 0x30, 0x37, 0x79, 0x16, 0x93, 0x25, 0x7f, 0x4d, 0x10, 0xff, 0x57, + 0xfb, 0xbf, 0x6e, 0x3b, 0x33, 0x21, 0xde, 0x79, 0xdc, 0x86, 0x17, 0x59, + 0x2d, 0x43, 0x64, 0xb7, 0xa6, 0x66, 0x87, 0xea, 0xbc, 0x96, 0x46, 0x19, + 0x1a, 0x86, 0x8b, 0x6f, 0xd7, 0xb7, 0x49, 0x00, 0x5b, 0xdb, 0xa3, 0xbf, + 0x29, 0x9a, 0xee, 0xf7, 0xd3, 0x33, 0xae, 0xa3, 0xf4, 0x9e, 0x4c, 0xca, + 0x5e, 0x69, 0xd4, 0x1b, 0xad, 0xb7, 0x90, 0x77, 0x6a, 0xd8, 0x59, 0x6f, + 0x79, 0xab, 0x01, 0xfa, 0x55, 0xf0, 0x8a, 0x21, 0x66, 0xe5, 0x65, 0x6e, + 0xfd, 0x7c, 0xd3, 0xdf, 0x1e, 0xeb, 0x7e, 0x3f, 0x06, 0x90, 0xfb, 0x19, + 0x0b, 0xd3, 0x06, 0x02, 0x1b, 0x78, 0x43, 0x99, 0xa8, +} + +var certSet2Cert50 = []byte{ + 0x30, 0x82, 0x06, 0x34, 0x30, 0x82, 0x04, 0x1c, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x1a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x7d, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x16, + 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x2b, + 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x22, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, 0x29, 0x30, 0x27, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, + 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x37, 0x31, 0x30, 0x32, 0x34, + 0x32, 0x30, 0x35, 0x37, 0x30, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x31, + 0x30, 0x32, 0x34, 0x32, 0x30, 0x35, 0x37, 0x30, 0x39, 0x5a, 0x30, 0x81, + 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, + 0x64, 0x2e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, 0x67, 0x69, + 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, + 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2f, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, + 0x20, 0x32, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe2, 0x4f, 0x39, 0x2f, 0xa1, 0x8c, + 0x9a, 0x85, 0xad, 0x08, 0x0e, 0x08, 0x3e, 0x57, 0xf2, 0x88, 0x01, 0x21, + 0x1b, 0x94, 0xa9, 0x6c, 0xe2, 0xb8, 0xdb, 0xaa, 0x19, 0x18, 0x46, 0x3a, + 0x52, 0xa1, 0xf5, 0x0f, 0xf4, 0x6e, 0x8c, 0xea, 0x96, 0x8c, 0x96, 0x87, + 0x79, 0x13, 0x40, 0x51, 0x2f, 0x22, 0xf2, 0x0c, 0x8b, 0x87, 0x0f, 0x65, + 0xdf, 0x71, 0x74, 0x34, 0x43, 0x55, 0xb1, 0x35, 0x09, 0x9b, 0xd9, 0xbc, + 0x1f, 0xfa, 0xeb, 0x42, 0xd0, 0x97, 0x40, 0x72, 0xb7, 0x43, 0x96, 0x3d, + 0xba, 0x96, 0x9d, 0x5d, 0x50, 0x02, 0x1c, 0x9b, 0x91, 0x8d, 0x9c, 0xc0, + 0xac, 0xd7, 0xbb, 0x2f, 0x17, 0xd7, 0xcb, 0x3e, 0x82, 0x9d, 0x73, 0xeb, + 0x07, 0x42, 0x92, 0xb2, 0xcd, 0x64, 0xb3, 0x74, 0x55, 0x1b, 0xb4, 0x4b, + 0x86, 0x21, 0x2c, 0xf7, 0x78, 0x87, 0x32, 0xe0, 0x16, 0xe4, 0xda, 0xbd, + 0x4c, 0x95, 0xea, 0xa4, 0x0a, 0x7e, 0xb6, 0x0a, 0x0d, 0x2e, 0x8a, 0xcf, + 0x55, 0xab, 0xc3, 0xe5, 0xdd, 0x41, 0x8a, 0x4e, 0xe6, 0x6f, 0x65, 0x6c, + 0xb2, 0x40, 0xcf, 0x17, 0x5d, 0xb9, 0xc3, 0x6a, 0x0b, 0x27, 0x11, 0x84, + 0x77, 0x61, 0xf6, 0xc2, 0x7c, 0xed, 0xc0, 0x8d, 0x78, 0x14, 0x18, 0x99, + 0x81, 0x99, 0x75, 0x63, 0xb7, 0xe8, 0x53, 0xd3, 0xba, 0x61, 0xe9, 0x0e, + 0xfa, 0xa2, 0x30, 0xf3, 0x46, 0xa2, 0xb9, 0xc9, 0x1f, 0x6c, 0x80, 0x5a, + 0x40, 0xac, 0x27, 0xed, 0x48, 0x47, 0x33, 0xb0, 0x54, 0xc6, 0x46, 0x1a, + 0xf3, 0x35, 0x61, 0xc1, 0x02, 0x29, 0x90, 0x54, 0x7e, 0x64, 0x4d, 0xc4, + 0x30, 0x52, 0x02, 0x82, 0xd7, 0xdf, 0xce, 0x21, 0x6e, 0x18, 0x91, 0xd7, + 0xb8, 0xab, 0x8c, 0x27, 0x17, 0xb5, 0xf0, 0xa3, 0x01, 0x2f, 0x8e, 0xd2, + 0x2e, 0x87, 0x3a, 0x3d, 0xb4, 0x29, 0x67, 0x8a, 0xc4, 0x03, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xad, 0x30, 0x82, 0x01, 0xa9, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, + 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x11, 0xdb, 0x23, 0x45, 0xfd, + 0x54, 0xcc, 0x6a, 0x71, 0x6f, 0x84, 0x8a, 0x03, 0xd7, 0xbe, 0xf7, 0x01, + 0x2f, 0x26, 0x86, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, + 0x30, 0x16, 0x80, 0x14, 0x4e, 0x0b, 0xef, 0x1a, 0xa4, 0x40, 0x5b, 0xa5, + 0x17, 0x69, 0x87, 0x30, 0xca, 0x34, 0x68, 0x43, 0xd0, 0x41, 0xae, 0xf2, + 0x30, 0x66, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x5a, 0x30, 0x58, 0x30, 0x27, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, + 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x61, 0x30, 0x2d, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x21, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, + 0x66, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x5b, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x54, 0x30, 0x52, 0x30, 0x27, 0xa0, 0x25, 0xa0, + 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x27, 0xa0, 0x25, 0xa0, 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x73, 0x63, + 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0x80, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x79, 0x30, 0x77, 0x30, 0x75, 0x06, 0x0b, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0x81, 0xb5, 0x37, 0x01, 0x02, 0x01, 0x30, 0x66, 0x30, 0x2e, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x64, 0x66, 0x30, 0x34, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x28, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x64, 0x66, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, + 0x9d, 0x07, 0xe1, 0xee, 0x90, 0x76, 0x31, 0x67, 0x16, 0x45, 0x70, 0x8c, + 0xcb, 0x84, 0x8b, 0x4b, 0x57, 0x68, 0x44, 0xa5, 0x89, 0xc1, 0xf2, 0x7e, + 0xcb, 0x28, 0x8b, 0xf5, 0xe7, 0x70, 0x77, 0xd5, 0xb6, 0xf4, 0x0b, 0x21, + 0x60, 0xa5, 0xa1, 0x74, 0x73, 0x24, 0x22, 0x80, 0xd6, 0xd8, 0xba, 0x8d, + 0xa2, 0x62, 0x5d, 0x09, 0x35, 0x42, 0x29, 0xfb, 0x39, 0x63, 0x45, 0x0b, + 0xa4, 0xb0, 0x38, 0x1a, 0x68, 0xf4, 0x95, 0x13, 0xcc, 0xe0, 0x43, 0x94, + 0xec, 0xeb, 0x39, 0x1a, 0xec, 0x57, 0x29, 0xd9, 0x99, 0x6d, 0xf5, 0x84, + 0xcd, 0x8e, 0x73, 0xae, 0xc9, 0xdc, 0x6a, 0xfa, 0x9e, 0x9d, 0x16, 0x64, + 0x93, 0x08, 0xc7, 0x1c, 0xc2, 0x89, 0x54, 0x9e, 0x77, 0x80, 0x90, 0xf6, + 0xb9, 0x29, 0x76, 0xeb, 0x13, 0x67, 0x48, 0x59, 0xf8, 0x2e, 0x3a, 0x31, + 0xb8, 0xc9, 0xd3, 0x88, 0xe5, 0x5f, 0x4e, 0xd2, 0x19, 0x3d, 0x43, 0x8e, + 0xd7, 0x92, 0xff, 0xcf, 0x38, 0xb6, 0xe1, 0x5b, 0x8a, 0x53, 0x1d, 0xce, + 0xac, 0xb4, 0x76, 0x2f, 0xd8, 0xf7, 0x40, 0x63, 0xd5, 0xee, 0x69, 0xf3, + 0x45, 0x7d, 0xa0, 0x62, 0xc1, 0x61, 0xc3, 0x75, 0xed, 0xb2, 0x7b, 0x4d, + 0xac, 0x21, 0x27, 0x30, 0x4e, 0x59, 0x46, 0x6a, 0x93, 0x17, 0xca, 0xc8, + 0x39, 0x2d, 0x01, 0x73, 0x65, 0x5b, 0xe9, 0x41, 0x9b, 0x11, 0x17, 0x9c, + 0xc8, 0xc8, 0x4a, 0xef, 0xa1, 0x76, 0x60, 0x2d, 0xae, 0x93, 0xff, 0x0c, + 0xd5, 0x33, 0x13, 0x9f, 0x4f, 0x13, 0xce, 0xdd, 0x86, 0xf1, 0xfc, 0xf8, + 0x35, 0x54, 0x15, 0xa8, 0x5b, 0xe7, 0x85, 0x7e, 0xfa, 0x37, 0x09, 0xff, + 0x8b, 0xb8, 0x31, 0x49, 0x9e, 0x0d, 0x6e, 0xde, 0xb4, 0xd2, 0x12, 0x2d, + 0xb8, 0xed, 0xc8, 0xc3, 0xf1, 0xb6, 0x42, 0xa0, 0x4c, 0x97, 0x79, 0xdf, + 0xfe, 0xc3, 0xa3, 0x9f, 0xa1, 0xf4, 0x6d, 0x2c, 0x84, 0x77, 0xa4, 0xa2, + 0x05, 0xe1, 0x17, 0xff, 0x31, 0xdd, 0x9a, 0xf3, 0xb8, 0x7a, 0xc3, 0x52, + 0xc2, 0x11, 0x11, 0xb7, 0x50, 0x31, 0x8a, 0x7f, 0xcc, 0xe7, 0x5a, 0x89, + 0xcc, 0xf7, 0x86, 0x9a, 0x61, 0x92, 0x4f, 0x2f, 0x94, 0xb6, 0x98, 0xc7, + 0x78, 0xe0, 0x62, 0x4b, 0x43, 0x7d, 0x3c, 0xde, 0xd6, 0x9a, 0xb4, 0x10, + 0xa1, 0x40, 0x9c, 0x4b, 0x2a, 0xdc, 0xb8, 0xd0, 0xd4, 0x9e, 0xfd, 0xf1, + 0x84, 0x78, 0x1b, 0x0e, 0x57, 0x8f, 0x69, 0x54, 0x42, 0x68, 0x7b, 0xea, + 0xa0, 0xef, 0x75, 0x0f, 0x07, 0xa2, 0x8c, 0x73, 0x99, 0xab, 0x55, 0xf5, + 0x07, 0x09, 0xd2, 0xaf, 0x38, 0x03, 0x6a, 0x90, 0x03, 0x0c, 0x2f, 0x8f, + 0xe2, 0xe8, 0x43, 0xc2, 0x31, 0xe9, 0x6f, 0xad, 0x87, 0xe5, 0x8d, 0xbd, + 0x4e, 0x2c, 0x89, 0x4b, 0x51, 0xe6, 0x9c, 0x4c, 0x54, 0x76, 0xc0, 0x12, + 0x81, 0x53, 0x9b, 0xec, 0xa0, 0xfc, 0x2c, 0x9c, 0xda, 0x18, 0x95, 0x6e, + 0x1e, 0x38, 0x26, 0x42, 0x27, 0x78, 0x60, 0x08, 0xdf, 0x7f, 0x6d, 0x32, + 0xe8, 0xd8, 0xc0, 0x6f, 0x1f, 0xeb, 0x26, 0x75, 0x9f, 0x93, 0xfc, 0x7b, + 0x1b, 0xfe, 0x35, 0x90, 0xdc, 0x53, 0xa3, 0x07, 0xa6, 0x3f, 0x83, 0x55, + 0x0a, 0x2b, 0x4e, 0x62, 0x82, 0x25, 0xce, 0x66, 0x30, 0x5d, 0x2c, 0xe0, + 0xf9, 0x19, 0x1b, 0x75, 0xb9, 0x9d, 0x98, 0x56, 0xa6, 0x83, 0x27, 0x7a, + 0xd1, 0x8f, 0x8d, 0x59, 0x93, 0xfc, 0x3f, 0x73, 0xd7, 0x2e, 0xb4, 0x2c, + 0x95, 0xd8, 0x8b, 0xf7, 0xc9, 0x7e, 0xc7, 0xfc, 0x9d, 0xac, 0x72, 0x04, + 0x1f, 0xd2, 0xcc, 0x17, 0xf4, 0xed, 0x34, 0x60, 0x9b, 0x9e, 0x4a, 0x97, + 0x04, 0xfe, 0xdd, 0x72, 0x0e, 0x57, 0x54, 0x51, 0x06, 0x70, 0x4d, 0xef, + 0xaa, 0x1c, 0xa4, 0x82, 0xe0, 0x33, 0xc7, 0xf4, +} + +var certSet2Cert51 = []byte{ + 0x30, 0x82, 0x06, 0x58, 0x30, 0x82, 0x05, 0x40, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x0a, 0x5f, 0x11, 0x4d, 0x03, 0x5b, 0x17, 0x91, 0x17, + 0xd2, 0xef, 0xd4, 0x03, 0x8c, 0x3f, 0x3b, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x6c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, + 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, + 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x34, 0x30, 0x32, 0x31, 0x32, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x34, 0x30, + 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x66, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, 0x69, 0x67, + 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, + 0x43, 0x41, 0x2d, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xbf, 0x61, 0x0a, 0x29, 0x10, 0x1f, 0x5e, 0xfe, 0x34, 0x37, 0x51, + 0x08, 0xf8, 0x1e, 0xfb, 0x22, 0xed, 0x61, 0xbe, 0x0b, 0x0d, 0x70, 0x4c, + 0x50, 0x63, 0x26, 0x75, 0x15, 0xb9, 0x41, 0x88, 0x97, 0xb6, 0xf0, 0xa0, + 0x15, 0xbb, 0x08, 0x60, 0xe0, 0x42, 0xe8, 0x05, 0x29, 0x10, 0x87, 0x36, + 0x8a, 0x28, 0x65, 0xa8, 0xef, 0x31, 0x07, 0x74, 0x6d, 0x36, 0x97, 0x2f, + 0x28, 0x46, 0x66, 0x04, 0xc7, 0x2a, 0x79, 0x26, 0x7a, 0x99, 0xd5, 0x8e, + 0xc3, 0x6d, 0x4f, 0xa0, 0x5e, 0xad, 0xbc, 0x3d, 0x91, 0xc2, 0x59, 0x7b, + 0x5e, 0x36, 0x6c, 0xc0, 0x53, 0xcf, 0x00, 0x08, 0x32, 0x3e, 0x10, 0x64, + 0x58, 0x10, 0x13, 0x69, 0xc7, 0x0c, 0xee, 0x9c, 0x42, 0x51, 0x00, 0xf9, + 0x05, 0x44, 0xee, 0x24, 0xce, 0x7a, 0x1f, 0xed, 0x8c, 0x11, 0xbd, 0x12, + 0xa8, 0xf3, 0x15, 0xf4, 0x1c, 0x7a, 0x31, 0x69, 0x01, 0x1b, 0xa7, 0xe6, + 0x5d, 0xc0, 0x9a, 0x6c, 0x7e, 0x09, 0x9e, 0xe7, 0x52, 0x44, 0x4a, 0x10, + 0x3a, 0x23, 0xe4, 0x9b, 0xb6, 0x03, 0xaf, 0xa8, 0x9c, 0xb4, 0x5b, 0x9f, + 0xd4, 0x4b, 0xad, 0x92, 0x8c, 0xce, 0xb5, 0x11, 0x2a, 0xaa, 0x37, 0x18, + 0x8d, 0xb4, 0xc2, 0xb8, 0xd8, 0x5c, 0x06, 0x8c, 0xf8, 0xff, 0x23, 0xbd, + 0x35, 0x5e, 0xd4, 0x7c, 0x3e, 0x7e, 0x83, 0x0e, 0x91, 0x96, 0x05, 0x98, + 0xc3, 0xb2, 0x1f, 0xe3, 0xc8, 0x65, 0xeb, 0xa9, 0x7b, 0x5d, 0xa0, 0x2c, + 0xcc, 0xfc, 0x3c, 0xd9, 0x6d, 0xed, 0xcc, 0xfa, 0x4b, 0x43, 0x8c, 0xc9, + 0xd4, 0xb8, 0xa5, 0x61, 0x1c, 0xb2, 0x40, 0xb6, 0x28, 0x12, 0xdf, 0xb9, + 0xf8, 0x5f, 0xfe, 0xd3, 0xb2, 0xc9, 0xef, 0x3d, 0xb4, 0x1e, 0x4b, 0x7c, + 0x1c, 0x4c, 0x99, 0x36, 0x9e, 0x3d, 0xeb, 0xec, 0xa7, 0x68, 0x5e, 0x1d, + 0xdf, 0x67, 0x6e, 0x5e, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x02, 0xfa, 0x30, 0x82, 0x02, 0xf6, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x82, + 0x01, 0xc6, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x82, 0x01, 0xbd, 0x30, + 0x82, 0x01, 0xb9, 0x30, 0x82, 0x01, 0xb5, 0x06, 0x0b, 0x60, 0x86, 0x48, + 0x01, 0x86, 0xfd, 0x6c, 0x01, 0x03, 0x00, 0x02, 0x30, 0x82, 0x01, 0xa4, + 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, + 0x16, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x73, 0x73, 0x6c, 0x2d, 0x63, 0x70, 0x73, 0x2d, 0x72, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x68, 0x74, 0x6d, + 0x30, 0x82, 0x01, 0x64, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x02, 0x30, 0x82, 0x01, 0x56, 0x1e, 0x82, 0x01, 0x52, 0x00, 0x41, + 0x00, 0x6e, 0x00, 0x79, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, + 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x43, 0x00, 0x65, 0x00, 0x72, + 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, + 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, + 0x00, 0x73, 0x00, 0x74, 0x00, 0x69, 0x00, 0x74, 0x00, 0x75, 0x00, 0x74, + 0x00, 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x63, 0x00, 0x63, + 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, + 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, + 0x00, 0x69, 0x00, 0x43, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x20, + 0x00, 0x43, 0x00, 0x50, 0x00, 0x2f, 0x00, 0x43, 0x00, 0x50, 0x00, 0x53, + 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x74, + 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6c, + 0x00, 0x79, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, 0x00, 0x50, + 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79, 0x00, 0x20, 0x00, 0x41, + 0x00, 0x67, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, + 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x77, 0x00, 0x68, 0x00, 0x69, + 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x6d, + 0x00, 0x69, 0x00, 0x74, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x61, + 0x00, 0x62, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, + 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x61, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x63, + 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, + 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x68, 0x00, 0x65, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x62, + 0x00, 0x79, 0x00, 0x20, 0x00, 0x72, 0x00, 0x65, 0x00, 0x66, 0x00, 0x65, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x2e, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, + 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x34, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, + 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x81, 0x8f, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, + 0x87, 0x30, 0x81, 0x84, 0x30, 0x40, 0xa0, 0x3e, 0xa0, 0x3c, 0x86, 0x3a, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e, + 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x48, 0x69, 0x67, + 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x56, + 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x40, + 0xa0, 0x3e, 0xa0, 0x3c, 0x86, 0x3a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, + 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, + 0x65, 0x72, 0x74, 0x48, 0x69, 0x67, 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, + 0x61, 0x6e, 0x63, 0x65, 0x45, 0x56, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0xb1, 0x3e, 0xc3, 0x69, 0x03, 0xf8, 0xbf, + 0x47, 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, 0x02, 0xef, 0x63, 0x64, 0x2b, + 0xc3, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x50, 0xea, 0x73, 0x89, 0xdb, 0x29, 0xfb, 0x10, 0x8f, 0x9e, 0xe5, 0x01, + 0x20, 0xd4, 0xde, 0x79, 0x99, 0x48, 0x83, 0xf7, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x1e, 0xe2, 0xa5, 0x48, 0x9e, 0x6c, 0xdb, 0x53, + 0x38, 0x0f, 0xef, 0xa6, 0x1a, 0x2a, 0xac, 0xe2, 0x03, 0x43, 0xed, 0x9a, + 0xbc, 0x3e, 0x8e, 0x75, 0x1b, 0xf0, 0xfd, 0x2e, 0x22, 0x59, 0xac, 0x13, + 0xc0, 0x61, 0xe2, 0xe7, 0xfa, 0xe9, 0x99, 0xcd, 0x87, 0x09, 0x75, 0x54, + 0x28, 0xbf, 0x46, 0x60, 0xdc, 0xbe, 0x51, 0x2c, 0x92, 0xf3, 0x1b, 0x91, + 0x7c, 0x31, 0x08, 0x70, 0xe2, 0x37, 0xb9, 0xc1, 0x5b, 0xa8, 0xbd, 0xa3, + 0x0b, 0x00, 0xfb, 0x1a, 0x15, 0xfd, 0x03, 0xad, 0x58, 0x6a, 0xc5, 0xc7, + 0x24, 0x99, 0x48, 0x47, 0x46, 0x31, 0x1e, 0x92, 0xef, 0xb4, 0x5f, 0x4e, + 0x34, 0xc7, 0x90, 0xbf, 0x31, 0xc1, 0xf8, 0xb1, 0x84, 0x86, 0xd0, 0x9c, + 0x01, 0xaa, 0xdf, 0x8a, 0x56, 0x06, 0xce, 0x3a, 0xe9, 0x0e, 0xae, 0x97, + 0x74, 0x5d, 0xd7, 0x71, 0x9a, 0x42, 0x74, 0x5f, 0xde, 0x8d, 0x43, 0x7c, + 0xde, 0xe9, 0x55, 0xed, 0x69, 0x00, 0xcb, 0x05, 0xe0, 0x7a, 0x61, 0x61, + 0x33, 0xd1, 0x19, 0x4d, 0xf9, 0x08, 0xee, 0xa0, 0x39, 0xc5, 0x25, 0x35, + 0xb7, 0x2b, 0xc4, 0x0f, 0xb2, 0xdd, 0xf1, 0xa5, 0xb7, 0x0e, 0x24, 0xc4, + 0x26, 0x28, 0x8d, 0x79, 0x77, 0xf5, 0x2f, 0xf0, 0x57, 0xba, 0x7c, 0x07, + 0xd4, 0xe1, 0xfc, 0xcd, 0x5a, 0x30, 0x57, 0x7e, 0x86, 0x10, 0x47, 0xdd, + 0x31, 0x1f, 0xd7, 0xfc, 0xa2, 0xc2, 0xbf, 0x30, 0x7c, 0x5d, 0x24, 0xaa, + 0xe8, 0xf9, 0xae, 0x5f, 0x6a, 0x74, 0xc2, 0xce, 0x6b, 0xb3, 0x46, 0xd8, + 0x21, 0xbe, 0x29, 0xd4, 0x8e, 0x5e, 0x15, 0xd6, 0x42, 0x4a, 0xe7, 0x32, + 0x6f, 0xa4, 0xb1, 0x6b, 0x51, 0x83, 0x58, 0xbe, 0x3f, 0x6d, 0xc7, 0xfb, + 0xda, 0x03, 0x21, 0xcb, 0x6a, 0x16, 0x19, 0x4e, 0x0a, 0xf0, 0xad, 0x84, + 0xca, 0x5d, 0x94, 0xb3, 0x5a, 0x76, 0xf7, 0x61, +} + +var certSet2Cert52 = []byte{ + 0x30, 0x82, 0x06, 0x5c, 0x30, 0x82, 0x04, 0x44, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x07, 0x19, 0xc2, 0x85, 0x30, 0xe9, 0x3b, 0x36, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, + 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, + 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, + 0x67, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, + 0x30, 0x36, 0x30, 0x39, 0x31, 0x37, 0x32, 0x32, 0x34, 0x36, 0x33, 0x36, + 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, + 0x39, 0x35, 0x39, 0x5a, 0x30, 0x55, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x1a, 0x30, 0x18, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, + 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x21, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x66, + 0x20, 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x82, 0x02, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, + 0x82, 0x02, 0x01, 0x00, 0xbd, 0xca, 0x8d, 0xac, 0xb8, 0x91, 0x15, 0x56, + 0x97, 0x7b, 0x6b, 0x5c, 0x7a, 0xc2, 0xde, 0x6b, 0xd9, 0xa1, 0xb0, 0xc3, + 0x10, 0x23, 0xfa, 0xa7, 0xa1, 0xb2, 0xcc, 0x31, 0xfa, 0x3e, 0xd9, 0xa6, + 0x29, 0x6f, 0x16, 0x3d, 0xe0, 0x6b, 0xf8, 0xb8, 0x40, 0x5f, 0xdb, 0x39, + 0xa8, 0x00, 0x7a, 0x8b, 0xa0, 0x4d, 0x54, 0x7d, 0xc2, 0x22, 0x78, 0xfc, + 0x8e, 0x09, 0xb8, 0xa8, 0x85, 0xd7, 0xcc, 0x95, 0x97, 0x4b, 0x74, 0xd8, + 0x9e, 0x7e, 0xf0, 0x00, 0xe4, 0x0e, 0x89, 0xae, 0x49, 0x28, 0x44, 0x1a, + 0x10, 0x99, 0x32, 0x0f, 0x25, 0x88, 0x53, 0xa4, 0x0d, 0xb3, 0x0f, 0x12, + 0x08, 0x16, 0x0b, 0x03, 0x71, 0x27, 0x1c, 0x7f, 0xe1, 0xdb, 0xd2, 0xfd, + 0x67, 0x68, 0xc4, 0x05, 0x5d, 0x0a, 0x0e, 0x5d, 0x70, 0xd7, 0xd8, 0x97, + 0xa0, 0xbc, 0x53, 0x41, 0x9a, 0x91, 0x8d, 0xf4, 0x9e, 0x36, 0x66, 0x7a, + 0x7e, 0x56, 0xc1, 0x90, 0x5f, 0xe6, 0xb1, 0x68, 0x20, 0x36, 0xa4, 0x8c, + 0x24, 0x2c, 0x2c, 0x47, 0x0b, 0x59, 0x76, 0x66, 0x30, 0xb5, 0xbe, 0xde, + 0xed, 0x8f, 0xf8, 0x9d, 0xd3, 0xbb, 0x01, 0x30, 0xe6, 0xf2, 0xf3, 0x0e, + 0xe0, 0x2c, 0x92, 0x80, 0xf3, 0x85, 0xf9, 0x28, 0x8a, 0xb4, 0x54, 0x2e, + 0x9a, 0xed, 0xf7, 0x76, 0xfc, 0x15, 0x68, 0x16, 0xeb, 0x4a, 0x6c, 0xeb, + 0x2e, 0x12, 0x8f, 0xd4, 0xcf, 0xfe, 0x0c, 0xc7, 0x5c, 0x1d, 0x0b, 0x7e, + 0x05, 0x32, 0xbe, 0x5e, 0xb0, 0x09, 0x2a, 0x42, 0xd5, 0xc9, 0x4e, 0x90, + 0xb3, 0x59, 0x0d, 0xbb, 0x7a, 0x7e, 0xcd, 0xd5, 0x08, 0x5a, 0xb4, 0x7f, + 0xd8, 0x1c, 0x69, 0x11, 0xf9, 0x27, 0x0f, 0x7b, 0x06, 0xaf, 0x54, 0x83, + 0x18, 0x7b, 0xe1, 0xdd, 0x54, 0x7a, 0x51, 0x68, 0x6e, 0x77, 0xfc, 0xc6, + 0xbf, 0x52, 0x4a, 0x66, 0x46, 0xa1, 0xb2, 0x67, 0x1a, 0xbb, 0xa3, 0x4f, + 0x77, 0xa0, 0xbe, 0x5d, 0xff, 0xfc, 0x56, 0x0b, 0x43, 0x72, 0x77, 0x90, + 0xca, 0x9e, 0xf9, 0xf2, 0x39, 0xf5, 0x0d, 0xa9, 0xf4, 0xea, 0xd7, 0xe7, + 0xb3, 0x10, 0x2f, 0x30, 0x42, 0x37, 0x21, 0xcc, 0x30, 0x70, 0xc9, 0x86, + 0x98, 0x0f, 0xcc, 0x58, 0x4d, 0x83, 0xbb, 0x7d, 0xe5, 0x1a, 0xa5, 0x37, + 0x8d, 0xb6, 0xac, 0x32, 0x97, 0x00, 0x3a, 0x63, 0x71, 0x24, 0x1e, 0x9e, + 0x37, 0xc4, 0xff, 0x74, 0xd4, 0x37, 0xc0, 0xe2, 0xfe, 0x88, 0x46, 0x60, + 0x11, 0xdd, 0x08, 0x3f, 0x50, 0x36, 0xab, 0xb8, 0x7a, 0xa4, 0x95, 0x62, + 0x6a, 0x6e, 0xb0, 0xca, 0x6a, 0x21, 0x5a, 0x69, 0xf3, 0xf3, 0xfb, 0x1d, + 0x70, 0x39, 0x95, 0xf3, 0xa7, 0x6e, 0xa6, 0x81, 0x89, 0xa1, 0x88, 0xc5, + 0x3b, 0x71, 0xca, 0xa3, 0x52, 0xee, 0x83, 0xbb, 0xfd, 0xa0, 0x77, 0xf4, + 0xe4, 0x6f, 0xe7, 0x42, 0xdb, 0x6d, 0x4a, 0x99, 0x8a, 0x34, 0x48, 0xbc, + 0x17, 0xdc, 0xe4, 0x80, 0x08, 0x22, 0xb6, 0xf2, 0x31, 0xc0, 0x3f, 0x04, + 0x3e, 0xeb, 0x9f, 0x20, 0x79, 0xd6, 0xb8, 0x06, 0x64, 0x64, 0x02, 0x31, + 0xd7, 0xa9, 0xcd, 0x52, 0xfb, 0x84, 0x45, 0x69, 0x09, 0x00, 0x2a, 0xdc, + 0x55, 0x8b, 0xc4, 0x06, 0x46, 0x4b, 0xc0, 0x4a, 0x1d, 0x09, 0x5b, 0x39, + 0x28, 0xfd, 0xa9, 0xab, 0xce, 0x00, 0xf9, 0x2e, 0x48, 0x4b, 0x26, 0xe6, + 0x30, 0x4c, 0xa5, 0x58, 0xca, 0xb4, 0x44, 0x82, 0x4f, 0xe7, 0x91, 0x1e, + 0x33, 0xc3, 0xb0, 0x93, 0xff, 0x11, 0xfc, 0x81, 0xd2, 0xca, 0x1f, 0x71, + 0x29, 0xdd, 0x76, 0x4f, 0x92, 0x25, 0xaf, 0x1d, 0x81, 0xb7, 0x0f, 0x2f, + 0x8c, 0xc3, 0x06, 0xcc, 0x2f, 0x27, 0xa3, 0x4a, 0xe4, 0x0e, 0x99, 0xba, + 0x7c, 0x1e, 0x45, 0x1f, 0x7f, 0xaa, 0x19, 0x45, 0x96, 0xfd, 0xfc, 0x3d, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x07, 0x30, 0x82, 0x01, + 0x03, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x02, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xe1, 0x66, 0xcf, 0x0e, 0xd1, 0xf1, 0xb3, 0x4b, 0xb7, 0x06, 0x20, 0x14, + 0xfe, 0x87, 0x12, 0xd5, 0xf6, 0xfe, 0xfb, 0x3e, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x4e, 0x0b, 0xef, + 0x1a, 0xa4, 0x40, 0x5b, 0xa5, 0x17, 0x69, 0x87, 0x30, 0xca, 0x34, 0x68, + 0x43, 0xd0, 0x41, 0xae, 0xf2, 0x30, 0x69, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5d, 0x30, 0x5b, 0x30, 0x27, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x61, 0x30, 0x30, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x61, + 0x69, 0x61, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x63, 0x61, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, + 0x2b, 0x30, 0x29, 0x30, 0x27, 0xa0, 0x25, 0xa0, 0x23, 0x86, 0x21, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, + 0x66, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x02, 0x01, 0x00, 0xb6, 0x6d, 0xf8, 0x70, 0xfb, 0xe2, 0x0d, 0x4c, + 0x98, 0xb3, 0x07, 0x49, 0x15, 0xf5, 0x04, 0xc4, 0x6c, 0xca, 0xca, 0xf5, + 0x68, 0xa0, 0x08, 0xfe, 0x12, 0x6d, 0x9c, 0x04, 0x06, 0xc9, 0xad, 0x9a, + 0x91, 0x52, 0x3e, 0x78, 0xc4, 0x5c, 0xee, 0x9f, 0x54, 0x1d, 0xee, 0xe3, + 0xf1, 0x5e, 0x30, 0xc9, 0x49, 0xe1, 0x39, 0xe0, 0xa6, 0x9d, 0x36, 0x6c, + 0x57, 0xfa, 0xe6, 0x34, 0x4f, 0x55, 0xe8, 0x87, 0xa8, 0x2c, 0xdd, 0x05, + 0xf1, 0x58, 0x12, 0x91, 0xe8, 0xca, 0xce, 0x28, 0x78, 0x8f, 0xdf, 0x07, + 0x85, 0x01, 0xa5, 0xdc, 0x45, 0x96, 0x05, 0xd4, 0x80, 0xb2, 0x2b, 0x05, + 0x9a, 0xcb, 0x9a, 0xa5, 0x8b, 0xe0, 0x3a, 0x67, 0xe6, 0x73, 0x47, 0xbe, + 0x4a, 0xfd, 0x27, 0xb1, 0x88, 0xef, 0xe6, 0xca, 0xcf, 0x8d, 0x0e, 0x26, + 0x9f, 0xfa, 0x5f, 0x57, 0x78, 0xad, 0x6d, 0xfe, 0xae, 0x9b, 0x35, 0x08, + 0xb1, 0xc3, 0xba, 0xc1, 0x00, 0x4a, 0x4b, 0x7d, 0x14, 0xbd, 0xf7, 0xf1, + 0xd3, 0x55, 0x18, 0xac, 0xd0, 0x33, 0x70, 0x88, 0x6d, 0xc4, 0x09, 0x71, + 0x14, 0xa6, 0x2b, 0x4f, 0x88, 0x81, 0xe7, 0x0b, 0x00, 0x37, 0xa9, 0x15, + 0x7d, 0x7e, 0xd7, 0x01, 0x96, 0x3f, 0x2f, 0xaf, 0x7b, 0x62, 0xae, 0x0a, + 0x4a, 0xbf, 0x4b, 0x39, 0x2e, 0x35, 0x10, 0x8b, 0xfe, 0x04, 0x39, 0xe4, + 0x3c, 0x3a, 0x0c, 0x09, 0x56, 0x40, 0x3a, 0xb5, 0xf4, 0xc2, 0x68, 0x0c, + 0xb5, 0xf9, 0x52, 0xcd, 0xee, 0x9d, 0xf8, 0x98, 0xfc, 0x78, 0xe7, 0x58, + 0x47, 0x8f, 0x1c, 0x73, 0x58, 0x69, 0x33, 0xab, 0xff, 0xdd, 0xdf, 0x8e, + 0x24, 0x01, 0x77, 0x98, 0x19, 0x3a, 0xb0, 0x66, 0x79, 0xbc, 0xe1, 0x08, + 0xa3, 0x0e, 0x4f, 0xc1, 0x04, 0xb3, 0xf3, 0x01, 0xc8, 0xeb, 0xd3, 0x59, + 0x1c, 0x35, 0xd2, 0x93, 0x1e, 0x70, 0x65, 0x82, 0x7f, 0xdb, 0xcf, 0xfb, + 0xc8, 0x99, 0x12, 0x60, 0xc3, 0x44, 0x6f, 0x3a, 0x80, 0x4b, 0xd7, 0xbe, + 0x21, 0xaa, 0x14, 0x7a, 0x64, 0xcb, 0xdd, 0x37, 0x43, 0x45, 0x5b, 0x32, + 0x2e, 0x45, 0xf0, 0xd9, 0x59, 0x1f, 0x6b, 0x18, 0xf0, 0x7c, 0xe9, 0x55, + 0x36, 0x19, 0x61, 0x5f, 0xb5, 0x7d, 0xf1, 0x8d, 0xbd, 0x88, 0xe4, 0x75, + 0x4b, 0x98, 0xdd, 0x27, 0xb0, 0xe4, 0x84, 0x44, 0x2a, 0x61, 0x84, 0x57, + 0x05, 0x82, 0x11, 0x1f, 0xaa, 0x35, 0x58, 0xf3, 0x20, 0x0e, 0xaf, 0x59, + 0xef, 0xfa, 0x55, 0x72, 0x72, 0x0d, 0x26, 0xd0, 0x9b, 0x53, 0x49, 0xac, + 0xce, 0x37, 0x2e, 0x65, 0x61, 0xff, 0xf6, 0xec, 0x1b, 0xea, 0xf6, 0xf1, + 0xa6, 0xd3, 0xd1, 0xb5, 0x7b, 0xbe, 0x35, 0xf4, 0x22, 0xc1, 0xbc, 0x8d, + 0x01, 0xbd, 0x68, 0x5e, 0x83, 0x0d, 0x2f, 0xec, 0xd6, 0xda, 0x63, 0x0c, + 0x27, 0xd1, 0x54, 0x3e, 0xe4, 0xa8, 0xd3, 0xce, 0x4b, 0x32, 0xb8, 0x91, + 0x94, 0xff, 0xfb, 0x5b, 0x49, 0x2d, 0x75, 0x18, 0xa8, 0xba, 0x71, 0x9a, + 0x3b, 0xae, 0xd9, 0xc0, 0xa9, 0x4f, 0x87, 0x91, 0xed, 0x8b, 0x7b, 0x6b, + 0x20, 0x98, 0x89, 0x39, 0x83, 0x4f, 0x80, 0xc4, 0x69, 0xcc, 0x17, 0xc9, + 0xc8, 0x4e, 0xbe, 0xe4, 0xa9, 0xa5, 0x81, 0x76, 0x70, 0x06, 0x04, 0x32, + 0xcd, 0x83, 0x65, 0xf4, 0xbc, 0x7d, 0x3e, 0x13, 0xbc, 0xd2, 0xe8, 0x6f, + 0x63, 0xaa, 0xb5, 0x3b, 0xda, 0x8d, 0x86, 0x32, 0x82, 0x78, 0x9d, 0xd9, + 0xcc, 0xff, 0xbf, 0x57, 0x64, 0x74, 0xed, 0x28, 0x3d, 0x44, 0x62, 0x15, + 0x61, 0x4b, 0xf7, 0x94, 0xb0, 0x0d, 0x2a, 0x67, 0x1c, 0xf0, 0xcb, 0x9b, + 0xa5, 0x92, 0xbf, 0xf8, 0x41, 0x5a, 0xc1, 0x3d, 0x60, 0xed, 0x9f, 0xbb, + 0xb8, 0x6d, 0x9b, 0xce, 0xa9, 0x6a, 0x16, 0x3f, 0x7e, 0xea, 0x06, 0xf1, +} + +var certSet2Cert53 = []byte{ + 0x30, 0x82, 0x06, 0xe6, 0x30, 0x82, 0x05, 0xce, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x03, 0x37, 0xb9, 0x28, 0x34, 0x7c, 0x60, 0xa6, 0xae, + 0xc5, 0xad, 0xb1, 0x21, 0x7f, 0x38, 0x60, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x6c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, + 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, + 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x37, 0x31, 0x31, 0x30, 0x39, 0x31, 0x32, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x69, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1f, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, 0x69, 0x67, + 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, + 0x45, 0x56, 0x20, 0x43, 0x41, 0x2d, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xf3, 0x96, 0x62, 0xd8, 0x75, 0x6e, 0x19, 0xff, + 0x3f, 0x34, 0x7c, 0x49, 0x4f, 0x31, 0x7e, 0x0d, 0x04, 0x4e, 0x99, 0x81, + 0xe2, 0xb3, 0x85, 0x55, 0x91, 0x30, 0xb1, 0xc0, 0xaf, 0x70, 0xbb, 0x2c, + 0xa8, 0xe7, 0x18, 0xaa, 0x3f, 0x78, 0xf7, 0x90, 0x68, 0x52, 0x86, 0x01, + 0x88, 0x97, 0xe2, 0x3b, 0x06, 0x65, 0x90, 0xaa, 0xbd, 0x65, 0x76, 0xc2, + 0xec, 0xbe, 0x10, 0x5b, 0x37, 0x78, 0x83, 0x60, 0x75, 0x45, 0xc6, 0xbd, + 0x74, 0xaa, 0xb6, 0x9f, 0xa4, 0x3a, 0x01, 0x50, 0x17, 0xc4, 0x39, 0x69, + 0xb9, 0xf1, 0x4f, 0xef, 0x82, 0xc1, 0xca, 0xf3, 0x4a, 0xdb, 0xcc, 0x9e, + 0x50, 0x4f, 0x4d, 0x40, 0xa3, 0x3a, 0x90, 0xe7, 0x86, 0x66, 0xbc, 0xf0, + 0x3e, 0x76, 0x28, 0x4c, 0xd1, 0x75, 0x80, 0x9e, 0x6a, 0x35, 0x14, 0x35, + 0x03, 0x9e, 0xdb, 0x0c, 0x8c, 0xc2, 0x28, 0xad, 0x50, 0xb2, 0xce, 0xf6, + 0x91, 0xa3, 0xc3, 0xa5, 0x0a, 0x58, 0x49, 0xf6, 0x75, 0x44, 0x6c, 0xba, + 0xf9, 0xce, 0xe9, 0xab, 0x3a, 0x02, 0xe0, 0x4d, 0xf3, 0xac, 0xe2, 0x7a, + 0xe0, 0x60, 0x22, 0x05, 0x3c, 0x82, 0xd3, 0x52, 0xe2, 0xf3, 0x9c, 0x47, + 0xf8, 0x3b, 0xd8, 0xb2, 0x4b, 0x93, 0x56, 0x4a, 0xbf, 0x70, 0xab, 0x3e, + 0xe9, 0x68, 0xc8, 0x1d, 0x8f, 0x58, 0x1d, 0x2a, 0x4d, 0x5e, 0x27, 0x3d, + 0xad, 0x0a, 0x59, 0x2f, 0x5a, 0x11, 0x20, 0x40, 0xd9, 0x68, 0x04, 0x68, + 0x2d, 0xf4, 0xc0, 0x84, 0x0b, 0x0a, 0x1b, 0x78, 0xdf, 0xed, 0x1a, 0x58, + 0xdc, 0xfb, 0x41, 0x5a, 0x6d, 0x6b, 0xf2, 0xed, 0x1c, 0xee, 0x5c, 0x32, + 0xb6, 0x5c, 0xec, 0xd7, 0xa6, 0x03, 0x32, 0xa6, 0xe8, 0xde, 0xb7, 0x28, + 0x27, 0x59, 0x88, 0x80, 0xff, 0x7b, 0xad, 0x89, 0x58, 0xd5, 0x1e, 0x14, + 0xa4, 0xf2, 0xb0, 0x70, 0xd4, 0xa0, 0x3e, 0xa7, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x03, 0x85, 0x30, 0x82, 0x03, 0x81, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x86, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x34, 0x30, 0x32, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x04, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x08, 0x30, 0x82, 0x01, 0xc4, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x82, 0x01, 0xbb, 0x30, 0x82, 0x01, 0xb7, 0x30, 0x82, 0x01, 0xb3, 0x06, + 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6c, 0x02, 0x01, 0x30, 0x82, + 0x01, 0xa4, 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x73, 0x6c, 0x2d, 0x63, 0x70, 0x73, 0x2d, + 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x68, + 0x74, 0x6d, 0x30, 0x82, 0x01, 0x64, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x02, 0x30, 0x82, 0x01, 0x56, 0x1e, 0x82, 0x01, 0x52, + 0x00, 0x41, 0x00, 0x6e, 0x00, 0x79, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, + 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x43, 0x00, 0x65, + 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, + 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, + 0x00, 0x6e, 0x00, 0x73, 0x00, 0x74, 0x00, 0x69, 0x00, 0x74, 0x00, 0x75, + 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x63, + 0x00, 0x63, 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, + 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, + 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x44, 0x00, 0x69, + 0x00, 0x67, 0x00, 0x69, 0x00, 0x43, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, + 0x00, 0x20, 0x00, 0x45, 0x00, 0x56, 0x00, 0x20, 0x00, 0x43, 0x00, 0x50, + 0x00, 0x53, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, + 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x52, 0x00, 0x65, + 0x00, 0x6c, 0x00, 0x79, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, + 0x00, 0x50, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79, 0x00, 0x20, + 0x00, 0x41, 0x00, 0x67, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x6d, + 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x77, 0x00, 0x68, + 0x00, 0x69, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x69, + 0x00, 0x6d, 0x00, 0x69, 0x00, 0x74, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x69, + 0x00, 0x61, 0x00, 0x62, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x74, + 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, + 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x6e, + 0x00, 0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, + 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x68, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x20, + 0x00, 0x62, 0x00, 0x79, 0x00, 0x20, 0x00, 0x72, 0x00, 0x65, 0x00, 0x66, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, + 0x00, 0x2e, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x81, + 0x83, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x77, 0x30, 0x75, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4d, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x41, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, + 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x41, 0x43, 0x65, 0x72, + 0x74, 0x73, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x48, + 0x69, 0x67, 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, + 0x45, 0x56, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, + 0x30, 0x81, 0x8f, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0x87, 0x30, + 0x81, 0x84, 0x30, 0x40, 0xa0, 0x3e, 0xa0, 0x3c, 0x86, 0x3a, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e, 0x64, 0x69, + 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, + 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x48, 0x69, 0x67, 0x68, 0x41, + 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x56, 0x52, 0x6f, + 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x40, 0xa0, 0x3e, + 0xa0, 0x3c, 0x86, 0x3a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, + 0x74, 0x48, 0x69, 0x67, 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, + 0x63, 0x65, 0x45, 0x56, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x4c, 0x58, 0xcb, 0x25, 0xf0, 0x41, 0x4f, 0x52, 0xf4, 0x28, 0xc8, + 0x81, 0x43, 0x9b, 0xa6, 0xa8, 0xa0, 0xe6, 0x92, 0xe5, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb1, 0x3e, + 0xc3, 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, + 0x02, 0xef, 0x63, 0x64, 0x2b, 0xc3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x4c, 0x7a, 0x17, 0x87, 0x28, 0x5d, 0x17, 0xbc, 0xb2, 0x32, + 0x73, 0xbf, 0xcd, 0x2e, 0xf5, 0x58, 0x31, 0x1d, 0xf0, 0xb1, 0x71, 0x54, + 0x9c, 0xd6, 0x9b, 0x67, 0x93, 0xdb, 0x2f, 0x03, 0x3e, 0x16, 0x6f, 0x1e, + 0x03, 0xc9, 0x53, 0x84, 0xa3, 0x56, 0x60, 0x1e, 0x78, 0x94, 0x1b, 0xa2, + 0xa8, 0x6f, 0xa3, 0xa4, 0x8b, 0x52, 0x91, 0xd7, 0xdd, 0x5c, 0x95, 0xbb, + 0xef, 0xb5, 0x16, 0x49, 0xe9, 0xa5, 0x42, 0x4f, 0x34, 0xf2, 0x47, 0xff, + 0xae, 0x81, 0x7f, 0x13, 0x54, 0xb7, 0x20, 0xc4, 0x70, 0x15, 0xcb, 0x81, + 0x0a, 0x81, 0xcb, 0x74, 0x57, 0xdc, 0x9c, 0xdf, 0x24, 0xa4, 0x29, 0x0c, + 0x18, 0xf0, 0x1c, 0xe4, 0xae, 0x07, 0x33, 0xec, 0xf1, 0x49, 0x3e, 0x55, + 0xcf, 0x6e, 0x4f, 0x0d, 0x54, 0x7b, 0xd3, 0xc9, 0xe8, 0x15, 0x48, 0xd4, + 0xc5, 0xbb, 0xdc, 0x35, 0x1c, 0x77, 0x45, 0x07, 0x48, 0x45, 0x85, 0xbd, + 0xd7, 0x7e, 0x53, 0xb8, 0xc0, 0x16, 0xd9, 0x95, 0xcd, 0x8b, 0x8d, 0x7d, + 0xc9, 0x60, 0x4f, 0xd1, 0xa2, 0x9b, 0xe3, 0xd0, 0x30, 0xd6, 0xb4, 0x73, + 0x36, 0xe6, 0xd2, 0xf9, 0x03, 0xb2, 0xe3, 0xa4, 0xf5, 0xe5, 0xb8, 0x3e, + 0x04, 0x49, 0x00, 0xba, 0x2e, 0xa6, 0x4a, 0x72, 0x83, 0x72, 0x9d, 0xf7, + 0x0b, 0x8c, 0xa9, 0x89, 0xe7, 0xb3, 0xd7, 0x64, 0x1f, 0xd6, 0xe3, 0x60, + 0xcb, 0x03, 0xc4, 0xdc, 0x88, 0xe9, 0x9d, 0x25, 0x01, 0x00, 0x71, 0xcb, + 0x03, 0xb4, 0x29, 0x60, 0x25, 0x8f, 0xf9, 0x46, 0xd1, 0x7b, 0x71, 0xae, + 0xcd, 0x53, 0x12, 0x5b, 0x84, 0x8e, 0xc2, 0x0f, 0xc7, 0xed, 0x93, 0x19, + 0xd9, 0xc9, 0xfa, 0x8f, 0x58, 0x34, 0x76, 0x32, 0x2f, 0xae, 0xe1, 0x50, + 0x14, 0x61, 0xd4, 0xa8, 0x58, 0xa3, 0xc8, 0x30, 0x13, 0x23, 0xef, 0xc6, + 0x25, 0x8c, 0x36, 0x8f, 0x1c, 0x80, +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_3.go b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_3.go new file mode 100644 index 00000000..e3dfed9c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/cert_set_3.go @@ -0,0 +1,5456 @@ +package certsets + +var CertSet3 = [][]byte{ + certSet3Cert0, + certSet3Cert1, + certSet3Cert2, + certSet3Cert3, + certSet3Cert4, + certSet3Cert5, + certSet3Cert6, + certSet3Cert7, + certSet3Cert8, + certSet3Cert9, + certSet3Cert10, + certSet3Cert11, + certSet3Cert12, + certSet3Cert13, + certSet3Cert14, + certSet3Cert15, + certSet3Cert16, + certSet3Cert17, + certSet3Cert18, + certSet3Cert19, + certSet3Cert20, + certSet3Cert21, + certSet3Cert22, + certSet3Cert23, + certSet3Cert24, + certSet3Cert25, + certSet3Cert26, + certSet3Cert27, + certSet3Cert28, + certSet3Cert29, + certSet3Cert30, + certSet3Cert31, + certSet3Cert32, + certSet3Cert33, + certSet3Cert34, + certSet3Cert35, + certSet3Cert36, + certSet3Cert37, + certSet3Cert38, + certSet3Cert39, + certSet3Cert40, + certSet3Cert41, + certSet3Cert42, + certSet3Cert43, + certSet3Cert44, + certSet3Cert45, + certSet3Cert46, + certSet3Cert47, + certSet3Cert48, + certSet3Cert49, + certSet3Cert50, + certSet3Cert51, +} + +const CertSet3Hash uint64 = (0x918215a28680ed7e) + +var certSet3Cert0 = []byte{ + 0x30, 0x82, 0x03, 0x7d, 0x30, 0x82, 0x02, 0xe6, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x12, 0xbb, 0xe6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x45, + 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, + 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x32, 0x30, + 0x35, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x31, 0x38, 0x30, 0x38, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, + 0x5a, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0xcc, 0x18, 0x63, 0x30, 0xfd, + 0xf4, 0x17, 0x23, 0x1a, 0x56, 0x7e, 0x5b, 0xdf, 0x3c, 0x6c, 0x38, 0xe4, + 0x71, 0xb7, 0x78, 0x91, 0xd4, 0xbc, 0xa1, 0xd8, 0x4c, 0xf8, 0xa8, 0x43, + 0xb6, 0x03, 0xe9, 0x4d, 0x21, 0x07, 0x08, 0x88, 0xda, 0x58, 0x2f, 0x66, + 0x39, 0x29, 0xbd, 0x05, 0x78, 0x8b, 0x9d, 0x38, 0xe8, 0x05, 0xb7, 0x6a, + 0x7e, 0x71, 0xa4, 0xe6, 0xc4, 0x60, 0xa6, 0xb0, 0xef, 0x80, 0xe4, 0x89, + 0x28, 0x0f, 0x9e, 0x25, 0xd6, 0xed, 0x83, 0xf3, 0xad, 0xa6, 0x91, 0xc7, + 0x98, 0xc9, 0x42, 0x18, 0x35, 0x14, 0x9d, 0xad, 0x98, 0x46, 0x92, 0x2e, + 0x4f, 0xca, 0xf1, 0x87, 0x43, 0xc1, 0x16, 0x95, 0x57, 0x2d, 0x50, 0xef, + 0x89, 0x2d, 0x80, 0x7a, 0x57, 0xad, 0xf2, 0xee, 0x5f, 0x6b, 0xd2, 0x00, + 0x8d, 0xb9, 0x14, 0xf8, 0x14, 0x15, 0x35, 0xd9, 0xc0, 0x46, 0xa3, 0x7b, + 0x72, 0xc8, 0x91, 0xbf, 0xc9, 0x55, 0x2b, 0xcd, 0xd0, 0x97, 0x3e, 0x9c, + 0x26, 0x64, 0xcc, 0xdf, 0xce, 0x83, 0x19, 0x71, 0xca, 0x4e, 0xe6, 0xd4, + 0xd5, 0x7b, 0xa9, 0x19, 0xcd, 0x55, 0xde, 0xc8, 0xec, 0xd2, 0x5e, 0x38, + 0x53, 0xe5, 0x5c, 0x4f, 0x8c, 0x2d, 0xfe, 0x50, 0x23, 0x36, 0xfc, 0x66, + 0xe6, 0xcb, 0x8e, 0xa4, 0x39, 0x19, 0x00, 0xb7, 0x95, 0x02, 0x39, 0x91, + 0x0b, 0x0e, 0xfe, 0x38, 0x2e, 0xd1, 0x1d, 0x05, 0x9a, 0xf6, 0x4d, 0x3e, + 0x6f, 0x0f, 0x07, 0x1d, 0xaf, 0x2c, 0x1e, 0x8f, 0x60, 0x39, 0xe2, 0xfa, + 0x36, 0x53, 0x13, 0x39, 0xd4, 0x5e, 0x26, 0x2b, 0xdb, 0x3d, 0xa8, 0x14, + 0xbd, 0x32, 0xeb, 0x18, 0x03, 0x28, 0x52, 0x04, 0x71, 0xe5, 0xab, 0x33, + 0x3d, 0xe1, 0x38, 0xbb, 0x07, 0x36, 0x84, 0x62, 0x9c, 0x79, 0xea, 0x16, + 0x30, 0xf4, 0x5f, 0xc0, 0x2b, 0xe8, 0x71, 0x6b, 0xe4, 0xf9, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x81, 0xf0, 0x30, 0x81, 0xed, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x48, 0xe6, + 0x68, 0xf9, 0x2b, 0xd2, 0xb2, 0x95, 0xd7, 0x47, 0xd8, 0x23, 0x20, 0x10, + 0x4f, 0x33, 0x98, 0x90, 0x9f, 0xd4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, + 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, + 0x4e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3a, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, + 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x65, + 0x63, 0x75, 0x72, 0x65, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4e, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x47, 0x30, 0x45, 0x30, 0x43, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, + 0x00, 0x76, 0xe1, 0x12, 0x6e, 0x4e, 0x4b, 0x16, 0x12, 0x86, 0x30, 0x06, + 0xb2, 0x81, 0x08, 0xcf, 0xf0, 0x08, 0xc7, 0xc7, 0x71, 0x7e, 0x66, 0xee, + 0xc2, 0xed, 0xd4, 0x3b, 0x1f, 0xff, 0xf0, 0xf0, 0xc8, 0x4e, 0xd6, 0x43, + 0x38, 0xb0, 0xb9, 0x30, 0x7d, 0x18, 0xd0, 0x55, 0x83, 0xa2, 0x6a, 0xcb, + 0x36, 0x11, 0x9c, 0xe8, 0x48, 0x66, 0xa3, 0x6d, 0x7f, 0xb8, 0x13, 0xd4, + 0x47, 0xfe, 0x8b, 0x5a, 0x5c, 0x73, 0xfc, 0xae, 0xd9, 0x1b, 0x32, 0x19, + 0x38, 0xab, 0x97, 0x34, 0x14, 0xaa, 0x96, 0xd2, 0xeb, 0xa3, 0x1c, 0x14, + 0x08, 0x49, 0xb6, 0xbb, 0xe5, 0x91, 0xef, 0x83, 0x36, 0xeb, 0x1d, 0x56, + 0x6f, 0xca, 0xda, 0xbc, 0x73, 0x63, 0x90, 0xe4, 0x7f, 0x7b, 0x3e, 0x22, + 0xcb, 0x3d, 0x07, 0xed, 0x5f, 0x38, 0x74, 0x9c, 0xe3, 0x03, 0x50, 0x4e, + 0xa1, 0xaf, 0x98, 0xee, 0x61, 0xf2, 0x84, 0x3f, 0x12, +} + +var certSet3Cert1 = []byte{ + 0x30, 0x82, 0x03, 0x8b, 0x30, 0x82, 0x02, 0xf4, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x0d, 0x6e, 0x62, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x45, + 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, + 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, + 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x31, 0x38, 0x30, 0x38, 0x32, 0x31, 0x31, 0x36, 0x31, 0x35, 0x30, 0x30, + 0x5a, 0x30, 0x58, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x28, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xbe, 0xb8, 0x15, 0x7b, 0xff, 0xd4, 0x7c, 0x7d, + 0x67, 0xad, 0x83, 0x64, 0x7b, 0xc8, 0x42, 0x53, 0x2d, 0xdf, 0xf6, 0x84, + 0x08, 0x20, 0x61, 0xd6, 0x01, 0x59, 0x6a, 0x9c, 0x44, 0x11, 0xaf, 0xef, + 0x76, 0xfd, 0x95, 0x7e, 0xce, 0x61, 0x30, 0xbb, 0x7a, 0x83, 0x5f, 0x02, + 0xbd, 0x01, 0x66, 0xca, 0xee, 0x15, 0x8d, 0x6f, 0xa1, 0x30, 0x9c, 0xbd, + 0xa1, 0x85, 0x9e, 0x94, 0x3a, 0xf3, 0x56, 0x88, 0x00, 0x31, 0xcf, 0xd8, + 0xee, 0x6a, 0x96, 0x02, 0xd9, 0xed, 0x03, 0x8c, 0xfb, 0x75, 0x6d, 0xe7, + 0xea, 0xb8, 0x55, 0x16, 0x05, 0x16, 0x9a, 0xf4, 0xe0, 0x5e, 0xb1, 0x88, + 0xc0, 0x64, 0x85, 0x5c, 0x15, 0x4d, 0x88, 0xc7, 0xb7, 0xba, 0xe0, 0x75, + 0xe9, 0xad, 0x05, 0x3d, 0x9d, 0xc7, 0x89, 0x48, 0xe0, 0xbb, 0x28, 0xc8, + 0x03, 0xe1, 0x30, 0x93, 0x64, 0x5e, 0x52, 0xc0, 0x59, 0x70, 0x22, 0x35, + 0x57, 0x88, 0x8a, 0xf1, 0x95, 0x0a, 0x83, 0xd7, 0xbc, 0x31, 0x73, 0x01, + 0x34, 0xed, 0xef, 0x46, 0x71, 0xe0, 0x6b, 0x02, 0xa8, 0x35, 0x72, 0x6b, + 0x97, 0x9b, 0x66, 0xe0, 0xcb, 0x1c, 0x79, 0x5f, 0xd8, 0x1a, 0x04, 0x68, + 0x1e, 0x47, 0x02, 0xe6, 0x9d, 0x60, 0xe2, 0x36, 0x97, 0x01, 0xdf, 0xce, + 0x35, 0x92, 0xdf, 0xbe, 0x67, 0xc7, 0x6d, 0x77, 0x59, 0x3b, 0x8f, 0x9d, + 0xd6, 0x90, 0x15, 0x94, 0xbc, 0x42, 0x34, 0x10, 0xc1, 0x39, 0xf9, 0xb1, + 0x27, 0x3e, 0x7e, 0xd6, 0x8a, 0x75, 0xc5, 0xb2, 0xaf, 0x96, 0xd3, 0xa2, + 0xde, 0x9b, 0xe4, 0x98, 0xbe, 0x7d, 0xe1, 0xe9, 0x81, 0xad, 0xb6, 0x6f, + 0xfc, 0xd7, 0x0e, 0xda, 0xe0, 0x34, 0xb0, 0x0d, 0x1a, 0x77, 0xe7, 0xe3, + 0x08, 0x98, 0xef, 0x58, 0xfa, 0x9c, 0x84, 0xb7, 0x36, 0xaf, 0xc2, 0xdf, + 0xac, 0xd2, 0xf4, 0x10, 0x06, 0x70, 0x71, 0x35, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x81, 0xe8, 0x30, 0x81, 0xe5, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2c, 0xd5, + 0x50, 0x41, 0x97, 0x15, 0x8b, 0xf0, 0x8f, 0x36, 0x61, 0x5b, 0x4a, 0xfb, + 0x6b, 0xd9, 0x99, 0xc9, 0x33, 0x92, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x48, 0xe6, 0x68, 0xf9, 0x2b, + 0xd2, 0xb2, 0x95, 0xd7, 0x47, 0xd8, 0x23, 0x20, 0x10, 0x4f, 0x33, 0x98, + 0x90, 0x9f, 0xd4, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x3a, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, + 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x46, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x04, 0x55, + 0x1d, 0x20, 0x00, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0xaf, 0xf3, 0x0e, 0xd6, 0x72, 0xab, 0xc7, 0xa9, 0x97, + 0xca, 0x2a, 0x6b, 0x84, 0x39, 0xde, 0x79, 0xa9, 0xf0, 0x81, 0xe5, 0x08, + 0x67, 0xab, 0xd7, 0x2f, 0x20, 0x02, 0x01, 0x71, 0x0c, 0x04, 0x22, 0xc9, + 0x1e, 0x88, 0x95, 0x03, 0xc9, 0x49, 0x3a, 0xaf, 0x67, 0x08, 0x49, 0xb0, + 0xd5, 0x08, 0xf5, 0x20, 0x3d, 0x80, 0x91, 0xa0, 0xc5, 0x87, 0xa3, 0xfb, + 0xc9, 0xa3, 0x17, 0x91, 0xf9, 0xa8, 0x2f, 0xae, 0xe9, 0x0f, 0xdf, 0x96, + 0x72, 0x0f, 0x75, 0x17, 0x80, 0x5d, 0x78, 0x01, 0x4d, 0x9f, 0x1f, 0x6d, + 0x7b, 0xd8, 0xf5, 0x42, 0x38, 0x23, 0x1a, 0x99, 0x93, 0xf4, 0x83, 0xbe, + 0x3b, 0x35, 0x74, 0xe7, 0x37, 0x13, 0x35, 0x7a, 0xac, 0xb4, 0xb6, 0x90, + 0x82, 0x6c, 0x27, 0xa4, 0xe0, 0xec, 0x9e, 0x35, 0xbd, 0xbf, 0xe5, 0x29, + 0xa1, 0x47, 0x9f, 0x5b, 0x32, 0xfc, 0xe9, 0x99, 0x7d, 0x2b, 0x39, +} + +var certSet3Cert2 = []byte{ + 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, + 0x34, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x31, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, + 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3, + 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a, + 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a, + 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f, + 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1, + 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4, + 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53, + 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f, + 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73, + 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b, + 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb, + 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4, + 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19, + 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65, + 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80, + 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99, + 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75, + 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e, + 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf, + 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2, + 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37, + 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, + 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, + 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, + 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, + 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, + 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, + 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, + 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, + 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10, + 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, + 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x08, 0x4e, 0x04, 0xa7, 0x80, 0x7f, 0x10, 0x16, 0x43, 0x5e, 0x02, 0xad, + 0xd7, 0x42, 0x80, 0xf4, 0xb0, 0x8e, 0xd2, 0xae, 0xb3, 0xeb, 0x11, 0x7d, + 0x90, 0x84, 0x18, 0x7d, 0xe7, 0x90, 0x15, 0xfb, 0x49, 0x7f, 0xa8, 0x99, + 0x05, 0x91, 0xbb, 0x7a, 0xc9, 0xd6, 0x3c, 0x37, 0x18, 0x09, 0x9a, 0xb6, + 0xc7, 0x92, 0x20, 0x07, 0x35, 0x33, 0x09, 0xe4, 0x28, 0x63, 0x72, 0x0d, + 0xb4, 0xe0, 0x32, 0x9c, 0x87, 0x98, 0xc4, 0x1b, 0x76, 0x89, 0x67, 0xc1, + 0x50, 0x58, 0xb0, 0x13, 0xaa, 0x13, 0x1a, 0x1b, 0x32, 0xa5, 0xbe, 0xea, + 0x11, 0x95, 0x4c, 0x48, 0x63, 0x49, 0xe9, 0x99, 0x5d, 0x20, 0x37, 0xcc, + 0xfe, 0x2a, 0x69, 0x51, 0x16, 0x95, 0x4b, 0xa9, 0xde, 0x49, 0x82, 0xc0, + 0x10, 0x70, 0xf4, 0x2c, 0xf3, 0xec, 0xbc, 0x24, 0x24, 0xd0, 0x4e, 0xac, + 0xa5, 0xd9, 0x5e, 0x1e, 0x6d, 0x92, 0xc1, 0xa7, 0xac, 0x48, 0x35, 0x81, + 0xf9, 0xe5, 0xe4, 0x9c, 0x65, 0x69, 0xcd, 0x87, 0xa4, 0x41, 0x50, 0x3f, + 0x2e, 0x57, 0xa5, 0x91, 0x51, 0x12, 0x58, 0x0e, 0x8c, 0x09, 0xa1, 0xac, + 0x7a, 0xa4, 0x12, 0xa5, 0x27, 0xf3, 0x9a, 0x10, 0x97, 0x7d, 0x55, 0x03, + 0x06, 0xf7, 0x66, 0x58, 0x5f, 0x5f, 0x64, 0xe1, 0xab, 0x5d, 0x6d, 0xa5, + 0x39, 0x48, 0x75, 0x98, 0x4c, 0x29, 0x5a, 0x3a, 0x8d, 0xd3, 0x2b, 0xca, + 0x9c, 0x55, 0x04, 0xbf, 0xf4, 0xe6, 0x14, 0xd5, 0x80, 0xac, 0x26, 0xed, + 0x17, 0x89, 0xa6, 0x93, 0x6c, 0x5c, 0xa4, 0xcc, 0xb8, 0xf0, 0x66, 0x8e, + 0x64, 0xe3, 0x7d, 0x9a, 0xe2, 0x00, 0xb3, 0x49, 0xc7, 0xe4, 0x0a, 0xaa, + 0xdd, 0x5b, 0x83, 0xc7, 0x70, 0x90, 0x46, 0x4e, 0xbe, 0xd0, 0xdb, 0x59, + 0x96, 0x6c, 0x2e, 0xf5, 0x16, 0x36, 0xde, 0x71, 0xcc, 0x01, 0xc2, 0x12, + 0xc1, 0x21, 0xc6, 0x16, +} + +var certSet3Cert3 = []byte{ + 0x30, 0x82, 0x04, 0x15, 0x30, 0x82, 0x03, 0x7e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0x8e, 0xed, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, + 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x1e, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x23, 0x30, 0x21, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x47, 0x54, 0x45, 0x20, 0x43, + 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x32, 0x30, 0x34, 0x31, 0x38, 0x31, 0x36, 0x33, 0x36, 0x31, + 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x38, 0x31, 0x33, 0x31, 0x36, + 0x33, 0x35, 0x31, 0x37, 0x5a, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x45, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x42, 0x61, 0x6c, 0x74, 0x69, + 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, + 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, + 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x04, + 0xbb, 0x22, 0xab, 0x98, 0x3d, 0x57, 0xe8, 0x26, 0x72, 0x9a, 0xb5, 0x79, + 0xd4, 0x29, 0xe2, 0xe1, 0xe8, 0x95, 0x80, 0xb1, 0xb0, 0xe3, 0x5b, 0x8e, + 0x2b, 0x29, 0x9a, 0x64, 0xdf, 0xa1, 0x5d, 0xed, 0xb0, 0x09, 0x05, 0x6d, + 0xdb, 0x28, 0x2e, 0xce, 0x62, 0xa2, 0x62, 0xfe, 0xb4, 0x88, 0xda, 0x12, + 0xeb, 0x38, 0xeb, 0x21, 0x9d, 0xc0, 0x41, 0x2b, 0x01, 0x52, 0x7b, 0x88, + 0x77, 0xd3, 0x1c, 0x8f, 0xc7, 0xba, 0xb9, 0x88, 0xb5, 0x6a, 0x09, 0xe7, + 0x73, 0xe8, 0x11, 0x40, 0xa7, 0xd1, 0xcc, 0xca, 0x62, 0x8d, 0x2d, 0xe5, + 0x8f, 0x0b, 0xa6, 0x50, 0xd2, 0xa8, 0x50, 0xc3, 0x28, 0xea, 0xf5, 0xab, + 0x25, 0x87, 0x8a, 0x9a, 0x96, 0x1c, 0xa9, 0x67, 0xb8, 0x3f, 0x0c, 0xd5, + 0xf7, 0xf9, 0x52, 0x13, 0x2f, 0xc2, 0x1b, 0xd5, 0x70, 0x70, 0xf0, 0x8f, + 0xc0, 0x12, 0xca, 0x06, 0xcb, 0x9a, 0xe1, 0xd9, 0xca, 0x33, 0x7a, 0x77, + 0xd6, 0xf8, 0xec, 0xb9, 0xf1, 0x68, 0x44, 0x42, 0x48, 0x13, 0xd2, 0xc0, + 0xc2, 0xa4, 0xae, 0x5e, 0x60, 0xfe, 0xb6, 0xa6, 0x05, 0xfc, 0xb4, 0xdd, + 0x07, 0x59, 0x02, 0xd4, 0x59, 0x18, 0x98, 0x63, 0xf5, 0xa5, 0x63, 0xe0, + 0x90, 0x0c, 0x7d, 0x5d, 0xb2, 0x06, 0x7a, 0xf3, 0x85, 0xea, 0xeb, 0xd4, + 0x03, 0xae, 0x5e, 0x84, 0x3e, 0x5f, 0xff, 0x15, 0xed, 0x69, 0xbc, 0xf9, + 0x39, 0x36, 0x72, 0x75, 0xcf, 0x77, 0x52, 0x4d, 0xf3, 0xc9, 0x90, 0x2c, + 0xb9, 0x3d, 0xe5, 0xc9, 0x23, 0x53, 0x3f, 0x1f, 0x24, 0x98, 0x21, 0x5c, + 0x07, 0x99, 0x29, 0xbd, 0xc6, 0x3a, 0xec, 0xe7, 0x6e, 0x86, 0x3a, 0x6b, + 0x97, 0x74, 0x63, 0x33, 0xbd, 0x68, 0x18, 0x31, 0xf0, 0x78, 0x8d, 0x76, + 0xbf, 0xfc, 0x9e, 0x8e, 0x5d, 0x2a, 0x86, 0xa7, 0x4d, 0x90, 0xdc, 0x27, + 0x1a, 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x47, 0x30, + 0x82, 0x01, 0x43, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x03, 0x30, + 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x43, 0x30, 0x41, 0x30, 0x3f, + 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x37, 0x30, 0x35, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x29, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x81, 0x89, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x81, 0x81, 0x30, 0x7f, 0xa1, 0x79, 0xa4, 0x77, + 0x30, 0x75, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0f, 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x1e, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x23, + 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x47, 0x54, 0x45, + 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x82, + 0x02, 0x01, 0xa5, 0x30, 0x45, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x3e, + 0x30, 0x3c, 0x30, 0x3a, 0xa0, 0x38, 0xa0, 0x36, 0x86, 0x34, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x67, 0x69, 0x2d, 0x62, 0x69, 0x6e, 0x2f, 0x43, 0x52, + 0x4c, 0x2f, 0x32, 0x30, 0x31, 0x38, 0x2f, 0x63, 0x64, 0x70, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x93, 0x1d, 0xfe, + 0x8b, 0xae, 0x46, 0xec, 0xcb, 0xa9, 0x0f, 0xab, 0xe5, 0xef, 0xca, 0xb2, + 0x68, 0x16, 0x68, 0xd8, 0x8f, 0xfa, 0x13, 0xa9, 0xaf, 0xb3, 0xcb, 0x2d, + 0xe7, 0x4b, 0x6e, 0x8e, 0x69, 0x2a, 0xc2, 0x2b, 0x10, 0x0a, 0x8d, 0xf6, + 0xae, 0x73, 0xb6, 0xb9, 0xfb, 0x14, 0xfd, 0x5f, 0x6d, 0xb8, 0x50, 0xb6, + 0xc4, 0x8a, 0xd6, 0x40, 0x7e, 0xd7, 0xc3, 0xcb, 0x73, 0xdc, 0xc9, 0x5d, + 0x5b, 0xaf, 0xb0, 0x41, 0xb5, 0x37, 0xeb, 0xea, 0xdc, 0x20, 0x91, 0xc4, + 0x34, 0x6a, 0xf4, 0xa1, 0xf3, 0x96, 0x9d, 0x37, 0x86, 0x97, 0xe1, 0x71, + 0xa4, 0xdd, 0x7d, 0xfa, 0x44, 0x84, 0x94, 0xae, 0xd7, 0x09, 0x04, 0x22, + 0x76, 0x0f, 0x64, 0x51, 0x35, 0xa9, 0x24, 0x0f, 0xf9, 0x0b, 0xdb, 0x32, + 0xda, 0xc2, 0xfe, 0xc1, 0xb9, 0x2a, 0x5c, 0x7a, 0x27, 0x13, 0xca, 0xb1, + 0x48, 0x3a, 0x71, 0xd0, 0x43, +} + +var certSet3Cert4 = []byte{ + 0x30, 0x82, 0x04, 0x25, 0x30, 0x82, 0x03, 0x0d, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x77, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, + 0x38, 0x32, 0x39, 0x32, 0x31, 0x33, 0x39, 0x33, 0x32, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x31, 0x33, 0x39, 0x33, 0x32, + 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, + 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, + 0x54, 0x9b, 0xd9, 0x58, 0x5d, 0x1e, 0x2c, 0x56, 0xc6, 0xd5, 0xe8, 0x7f, + 0xf4, 0x7d, 0x16, 0x03, 0xff, 0xd0, 0x8b, 0x5a, 0xe4, 0x8e, 0xa7, 0xdd, + 0x54, 0x2e, 0xd4, 0x04, 0xc0, 0x5d, 0x98, 0x9c, 0x8d, 0x90, 0x0f, 0xbc, + 0x10, 0x65, 0x5f, 0xda, 0x9a, 0xd6, 0x44, 0x7c, 0xc0, 0x9f, 0xb5, 0xe9, + 0x4a, 0x8c, 0x0b, 0x06, 0x43, 0x04, 0xbb, 0xf4, 0x96, 0xe2, 0x26, 0xf6, + 0x61, 0x01, 0x91, 0x66, 0x31, 0x22, 0xc3, 0x34, 0x34, 0x5f, 0x3f, 0x3f, + 0x91, 0x2f, 0x44, 0x5f, 0xdc, 0xc7, 0x14, 0xb6, 0x03, 0x9f, 0x86, 0x4b, + 0x0e, 0xa3, 0xff, 0xa0, 0x80, 0x02, 0x83, 0xc3, 0xd3, 0x1f, 0x69, 0x52, + 0xd6, 0x9d, 0x64, 0x0f, 0xc9, 0x83, 0xe7, 0x1b, 0xc4, 0x70, 0xac, 0x94, + 0xe7, 0xc3, 0xa4, 0x6a, 0x2c, 0xbd, 0xb8, 0x9e, 0x69, 0xd8, 0xbe, 0x0a, + 0x8f, 0x16, 0x63, 0x5a, 0x68, 0x71, 0x80, 0x7b, 0x30, 0xde, 0x15, 0x04, + 0xbf, 0xcc, 0xd3, 0xbf, 0x3e, 0x48, 0x05, 0x55, 0x7a, 0xb3, 0xd7, 0x10, + 0x0c, 0x03, 0xfc, 0x9b, 0xfd, 0x08, 0xa7, 0x8c, 0x8c, 0xdb, 0xa7, 0x8e, + 0xf1, 0x1e, 0x63, 0xdc, 0xb3, 0x01, 0x2f, 0x7f, 0xaf, 0x57, 0xc3, 0x3c, + 0x48, 0xa7, 0x83, 0x68, 0x21, 0xa7, 0x2f, 0xe7, 0xa7, 0x3f, 0xf0, 0xb5, + 0x0c, 0xfc, 0xf5, 0x84, 0xd1, 0x53, 0xbc, 0x0e, 0x72, 0x4f, 0x60, 0x0c, + 0x42, 0xb8, 0x98, 0xad, 0x19, 0x88, 0x57, 0xd7, 0x04, 0xec, 0x87, 0xbf, + 0x7e, 0x87, 0x4e, 0xa3, 0x21, 0xf9, 0x53, 0xfd, 0x36, 0x98, 0x48, 0x8d, + 0xd6, 0xf8, 0xbb, 0x48, 0xf2, 0x29, 0xc8, 0x64, 0xd1, 0xcc, 0x54, 0x48, + 0x53, 0x8b, 0xaf, 0xb7, 0x65, 0x1e, 0xbf, 0x29, 0x33, 0x29, 0xd9, 0x29, + 0x60, 0x48, 0xf8, 0xff, 0x91, 0xbc, 0x57, 0x58, 0xe5, 0x35, 0x2e, 0xbb, + 0x69, 0xb6, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1d, + 0x30, 0x82, 0x01, 0x19, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, + 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xc3, 0x9c, 0xf3, 0xfc, 0xd3, 0x46, 0x08, 0x34, 0xbb, 0xce, 0x46, 0x7f, + 0xa0, 0x7c, 0x5b, 0xf3, 0xe2, 0x08, 0xcb, 0x59, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x35, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, + 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, + 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, + 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, + 0x30, 0x43, 0x30, 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, + 0x45, 0x01, 0x07, 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x58, 0x1e, 0xc6, 0x43, 0x32, 0xac, + 0xac, 0x2f, 0x93, 0x78, 0xb7, 0xea, 0xae, 0x54, 0x40, 0x47, 0x2d, 0x7e, + 0x78, 0x8d, 0x50, 0xf6, 0xf8, 0x66, 0xac, 0xd6, 0x4f, 0x73, 0xd6, 0x44, + 0xef, 0xaf, 0x0b, 0xcc, 0x5b, 0xc1, 0xf4, 0x4f, 0x9a, 0x8f, 0x49, 0x7e, + 0x60, 0xaf, 0xc2, 0x27, 0xc7, 0x16, 0xf1, 0xfb, 0x93, 0x81, 0x90, 0xa9, + 0x7c, 0xef, 0x6f, 0x7e, 0x6e, 0x45, 0x94, 0x16, 0x84, 0xbd, 0xec, 0x49, + 0xf1, 0xc4, 0x0e, 0xf4, 0xaf, 0x04, 0x59, 0x83, 0x87, 0x0f, 0x2c, 0x3b, + 0x97, 0xc3, 0x5a, 0x12, 0x9b, 0x7b, 0x04, 0x35, 0x7b, 0xa3, 0x95, 0x33, + 0x08, 0x7b, 0x93, 0x71, 0x22, 0x42, 0xb3, 0xa9, 0xd9, 0x6f, 0x4f, 0x81, + 0x92, 0xfc, 0x07, 0xb6, 0x79, 0xbc, 0x84, 0x4a, 0x9d, 0x77, 0x09, 0xf1, + 0xc5, 0x89, 0xf2, 0xf0, 0xb4, 0x9c, 0x54, 0xaa, 0x12, 0x7b, 0x0d, 0xba, + 0x4f, 0xef, 0x93, 0x19, 0xec, 0xef, 0x7d, 0x4e, 0x61, 0xa3, 0x8e, 0x76, + 0x9c, 0x59, 0xcf, 0x8c, 0x94, 0xb1, 0x84, 0x97, 0xf7, 0x1a, 0xb9, 0x07, + 0xb8, 0xb2, 0xc6, 0x4f, 0x13, 0x79, 0xdb, 0xbf, 0x4f, 0x51, 0x1b, 0x7f, + 0x69, 0x0d, 0x51, 0x2a, 0xc1, 0xd6, 0x15, 0xff, 0x37, 0x51, 0x34, 0x65, + 0x51, 0xf4, 0x1e, 0xbe, 0x38, 0x6a, 0xec, 0x0e, 0xab, 0xbf, 0x3d, 0x7b, + 0x39, 0x05, 0x7b, 0xf4, 0xf3, 0xfb, 0x1a, 0xa1, 0xd0, 0xc8, 0x7e, 0x4e, + 0x64, 0x8d, 0xcd, 0x8c, 0x61, 0x55, 0x90, 0xfe, 0x3a, 0xca, 0x5d, 0x25, + 0x0f, 0xf8, 0x1d, 0xa3, 0x4a, 0x74, 0x56, 0x4f, 0x1a, 0x55, 0x40, 0x70, + 0x75, 0x25, 0xa6, 0x33, 0x2e, 0xba, 0x4b, 0xa5, 0x5d, 0x53, 0x9a, 0x0d, + 0x30, 0xe1, 0x8d, 0x5f, 0x61, 0x2c, 0xaf, 0xcc, 0xef, 0xb0, 0x99, 0xa1, + 0x80, 0xff, 0x0b, 0xf2, 0x62, 0x4c, 0x70, 0x26, 0x98, +} + +var certSet3Cert5 = []byte{ + 0x30, 0x82, 0x04, 0x44, 0x30, 0x82, 0x03, 0x2c, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x78, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, + 0x38, 0x32, 0x39, 0x32, 0x32, 0x32, 0x34, 0x35, 0x38, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x32, 0x32, 0x34, 0x35, 0x38, + 0x5a, 0x30, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x14, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x53, 0x53, 0x4c, 0x31, + 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x44, 0x56, 0x20, 0x53, 0x53, + 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdf, 0x41, 0x94, 0x7a, 0xda, 0xf7, + 0xe4, 0x31, 0x43, 0xb6, 0xea, 0x01, 0x1b, 0x5c, 0xce, 0x63, 0xea, 0xfa, + 0x6d, 0xa3, 0xd9, 0x6a, 0xee, 0x2d, 0x9a, 0x75, 0xf9, 0xd5, 0x9c, 0x5b, + 0xbd, 0x34, 0xdf, 0xd8, 0x1c, 0xc9, 0x6d, 0xd8, 0x04, 0x88, 0xda, 0x6e, + 0xb5, 0xb7, 0xb5, 0xf0, 0x30, 0xae, 0x40, 0xd6, 0x5d, 0xfa, 0xc4, 0x53, + 0xc1, 0xd4, 0x22, 0x9d, 0x04, 0x4e, 0x11, 0xa6, 0x95, 0xd5, 0x45, 0x7c, + 0x41, 0x05, 0x58, 0xe0, 0x4c, 0xdd, 0xf9, 0xee, 0x55, 0xbd, 0x5f, 0x46, + 0xdc, 0xad, 0x13, 0x08, 0x9d, 0x2c, 0xe4, 0xf7, 0x82, 0xe6, 0x07, 0x2b, + 0x9e, 0x0e, 0x8c, 0x34, 0xa1, 0xce, 0xc4, 0xa1, 0xe0, 0x81, 0x70, 0x86, + 0x00, 0x06, 0x3f, 0x2d, 0xea, 0x7c, 0x9b, 0x28, 0xae, 0x1b, 0x28, 0x8b, + 0x39, 0x09, 0xd3, 0xe7, 0xf0, 0x45, 0xa4, 0xb1, 0xba, 0x11, 0x67, 0x90, + 0x55, 0x7b, 0x8f, 0xde, 0xed, 0x38, 0x5c, 0xa1, 0xe1, 0xe3, 0x83, 0xc4, + 0xc3, 0x72, 0x91, 0x4f, 0x98, 0xee, 0x1c, 0xc2, 0x80, 0xaa, 0x64, 0xa5, + 0x3e, 0x83, 0x62, 0x1c, 0xcc, 0xe0, 0x9e, 0xf8, 0x5a, 0xc0, 0x13, 0x12, + 0x7d, 0xa2, 0xa7, 0x8b, 0xa3, 0xe7, 0x9f, 0x2a, 0xd7, 0x9b, 0xca, 0xcb, + 0xed, 0x97, 0x01, 0x9c, 0x28, 0x84, 0x51, 0x04, 0x50, 0x41, 0xbc, 0xb4, + 0xfc, 0x78, 0xe9, 0x1b, 0xcf, 0x14, 0xea, 0x1f, 0x0f, 0xfc, 0x2e, 0x01, + 0x32, 0x8d, 0xb6, 0x35, 0xcb, 0x0a, 0x18, 0x3b, 0xec, 0x5a, 0x3e, 0x3c, + 0x1b, 0xd3, 0x99, 0x43, 0x1e, 0x2f, 0xf7, 0xbd, 0xf3, 0x5b, 0x12, 0xb9, + 0x07, 0x5e, 0xed, 0x3e, 0xd1, 0xa9, 0x87, 0xcc, 0x77, 0x72, 0x27, 0xd4, + 0xd9, 0x75, 0xa2, 0x63, 0x4b, 0x93, 0x36, 0xbd, 0xe5, 0x5c, 0xd7, 0xbf, + 0x5f, 0x79, 0x0d, 0xb3, 0x32, 0xa7, 0x0b, 0xb2, 0x63, 0x23, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, 0x19, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, + 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x0b, 0x50, 0xec, 0x77, 0xef, + 0x2a, 0x9b, 0xff, 0xec, 0x03, 0xa1, 0x0a, 0xff, 0xad, 0xc6, 0xe4, 0x2a, + 0x18, 0xc7, 0x3e, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2e, + 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x2e, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, + 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, + 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4c, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, + 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, + 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x33, 0x24, 0xd5, 0x90, 0xaa, 0x29, 0x0c, 0x35, 0xb9, 0x2f, 0xc3, 0xc7, + 0x42, 0x93, 0xc0, 0xc6, 0x10, 0x4b, 0x03, 0x08, 0x76, 0x84, 0x10, 0xa2, + 0xe0, 0xe7, 0x53, 0x12, 0x27, 0xf2, 0x0a, 0xda, 0x7f, 0x3a, 0xdc, 0xfd, + 0x5c, 0x79, 0x5a, 0x8f, 0x17, 0x74, 0x43, 0x53, 0xb1, 0xd5, 0xd1, 0x5d, + 0x59, 0xb9, 0xa6, 0x84, 0x64, 0xca, 0xf1, 0x3a, 0x0a, 0x59, 0x96, 0x10, + 0xbf, 0xa9, 0x81, 0x57, 0x8b, 0x5c, 0x87, 0xdc, 0x7f, 0xe3, 0xe4, 0xbb, + 0x05, 0x7a, 0xa0, 0x32, 0x09, 0x13, 0x4e, 0x10, 0x81, 0x28, 0x1f, 0x9c, + 0x03, 0x62, 0xbc, 0xf4, 0x01, 0xb5, 0x29, 0x83, 0x46, 0x07, 0xb9, 0xe7, + 0xb8, 0x5d, 0xc8, 0xe9, 0xd1, 0xdd, 0xad, 0x3b, 0xf8, 0x34, 0xdb, 0xc1, + 0xd1, 0x95, 0xa9, 0x91, 0x18, 0xed, 0x3c, 0x2c, 0x37, 0x11, 0x4d, 0xcc, + 0xfe, 0x53, 0x3e, 0x50, 0x43, 0xf9, 0xc3, 0x56, 0x41, 0xac, 0x53, 0x9b, + 0x6c, 0x05, 0xb2, 0x9a, 0xe2, 0xe0, 0x59, 0x57, 0x30, 0x32, 0xb6, 0x26, + 0x4e, 0x13, 0x25, 0xcd, 0xfa, 0x48, 0x70, 0x0f, 0x75, 0x55, 0x60, 0x11, + 0xf5, 0x3b, 0xd5, 0x5e, 0x5a, 0x3c, 0x8b, 0x5b, 0x0f, 0x0f, 0x62, 0x42, + 0x48, 0x61, 0x85, 0x8b, 0x10, 0xf4, 0xc1, 0x88, 0xbf, 0x7f, 0x5f, 0x8a, + 0xc2, 0xd7, 0xcd, 0x2b, 0x94, 0x5c, 0x1f, 0x34, 0x4a, 0x08, 0xaf, 0xeb, + 0xae, 0x89, 0xa8, 0x48, 0x75, 0x55, 0x95, 0x1d, 0xbb, 0xc0, 0x9a, 0x01, + 0xb9, 0xf4, 0x03, 0x22, 0x3e, 0xd4, 0xe6, 0x52, 0x30, 0x0d, 0x67, 0xb9, + 0xc0, 0x91, 0xfd, 0x2d, 0x4c, 0x30, 0x8e, 0xbd, 0x8c, 0xa5, 0x04, 0x91, + 0xbb, 0xa4, 0xab, 0x7f, 0x0f, 0xd8, 0x6f, 0xf0, 0x66, 0x00, 0xc9, 0xa3, + 0x5c, 0xf5, 0xb0, 0x8f, 0x83, 0xe6, 0x9c, 0x5a, 0xe6, 0xb6, 0xb9, 0xc5, + 0xbc, 0xbe, 0xe4, 0x02, +} + +var certSet3Cert6 = []byte{ + 0x30, 0x82, 0x04, 0x45, 0x30, 0x82, 0x03, 0xae, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x33, 0x65, 0x50, 0x08, 0x79, 0xad, 0x73, 0xe2, 0x30, + 0xb9, 0xe0, 0x1d, 0x0d, 0x7f, 0xac, 0x91, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xce, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x5a, 0x41, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, + 0x0c, 0x57, 0x65, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x43, 0x61, 0x70, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, + 0x43, 0x61, 0x70, 0x65, 0x20, 0x54, 0x6f, 0x77, 0x6e, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x54, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, + 0x67, 0x20, 0x63, 0x63, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x1f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x21, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x54, 0x68, 0x61, + 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x31, 0x28, 0x30, + 0x26, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, + 0x16, 0x19, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x2d, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x40, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x31, + 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, + 0x31, 0x32, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, + 0x81, 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x1f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, + 0x30, 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, + 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xac, 0xa0, 0xf0, 0xfb, 0x80, 0x59, 0xd4, 0x9c, 0xc7, 0xa4, 0xcf, 0x9d, + 0xa1, 0x59, 0x73, 0x09, 0x10, 0x45, 0x0c, 0x0d, 0x2c, 0x6e, 0x68, 0xf1, + 0x6c, 0x5b, 0x48, 0x68, 0x49, 0x59, 0x37, 0xfc, 0x0b, 0x33, 0x19, 0xc2, + 0x77, 0x7f, 0xcc, 0x10, 0x2d, 0x95, 0x34, 0x1c, 0xe6, 0xeb, 0x4d, 0x09, + 0xa7, 0x1c, 0xd2, 0xb8, 0xc9, 0x97, 0x36, 0x02, 0xb7, 0x89, 0xd4, 0x24, + 0x5f, 0x06, 0xc0, 0xcc, 0x44, 0x94, 0x94, 0x8d, 0x02, 0x62, 0x6f, 0xeb, + 0x5a, 0xdd, 0x11, 0x8d, 0x28, 0x9a, 0x5c, 0x84, 0x90, 0x10, 0x7a, 0x0d, + 0xbd, 0x74, 0x66, 0x2f, 0x6a, 0x38, 0xa0, 0xe2, 0xd5, 0x54, 0x44, 0xeb, + 0x1d, 0x07, 0x9f, 0x07, 0xba, 0x6f, 0xee, 0xe9, 0xfd, 0x4e, 0x0b, 0x29, + 0xf5, 0x3e, 0x84, 0xa0, 0x01, 0xf1, 0x9c, 0xab, 0xf8, 0x1c, 0x7e, 0x89, + 0xa4, 0xe8, 0xa1, 0xd8, 0x71, 0x65, 0x0d, 0xa3, 0x51, 0x7b, 0xee, 0xbc, + 0xd2, 0x22, 0x60, 0x0d, 0xb9, 0x5b, 0x9d, 0xdf, 0xba, 0xfc, 0x51, 0x5b, + 0x0b, 0xaf, 0x98, 0xb2, 0xe9, 0x2e, 0xe9, 0x04, 0xe8, 0x62, 0x87, 0xde, + 0x2b, 0xc8, 0xd7, 0x4e, 0xc1, 0x4c, 0x64, 0x1e, 0xdd, 0xcf, 0x87, 0x58, + 0xba, 0x4a, 0x4f, 0xca, 0x68, 0x07, 0x1d, 0x1c, 0x9d, 0x4a, 0xc6, 0xd5, + 0x2f, 0x91, 0xcc, 0x7c, 0x71, 0x72, 0x1c, 0xc5, 0xc0, 0x67, 0xeb, 0x32, + 0xfd, 0xc9, 0x92, 0x5c, 0x94, 0xda, 0x85, 0xc0, 0x9b, 0xbf, 0x53, 0x7d, + 0x2b, 0x09, 0xf4, 0x8c, 0x9d, 0x91, 0x1f, 0x97, 0x6a, 0x52, 0xcb, 0xde, + 0x09, 0x36, 0xa4, 0x77, 0xd8, 0x7b, 0x87, 0x50, 0x44, 0xd5, 0x3e, 0x6e, + 0x29, 0x69, 0xfb, 0x39, 0x49, 0x26, 0x1e, 0x09, 0xa5, 0x80, 0x7b, 0x40, + 0x2d, 0xeb, 0xe8, 0x27, 0x85, 0xc9, 0xfe, 0x61, 0xfd, 0x7e, 0xe6, 0x7c, + 0x97, 0x1d, 0xd5, 0x9d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xc2, + 0x30, 0x81, 0xbf, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x3b, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, 0x04, 0x55, + 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x7b, 0x5b, 0x45, 0xcf, 0xaf, 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, + 0x6a, 0xb6, 0xf3, 0x46, 0xeb, 0x57, 0x48, 0x50, 0x30, 0x40, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x39, 0x30, 0x37, 0x30, 0x35, 0xa0, 0x33, 0xa0, + 0x31, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x72, 0x65, 0x6d, 0x69, + 0x75, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x84, 0xa8, 0x4c, + 0xc9, 0x3e, 0x2a, 0xbc, 0x9a, 0xe2, 0xcc, 0x8f, 0x0b, 0xb2, 0x25, 0x77, + 0xc4, 0x61, 0x89, 0x89, 0x63, 0x5a, 0xd4, 0xa3, 0x15, 0x40, 0xd4, 0xfb, + 0x5e, 0x3f, 0xb4, 0x43, 0xea, 0x63, 0x17, 0x2b, 0x6b, 0x99, 0x74, 0x9e, + 0x09, 0xa8, 0xdd, 0xd4, 0x56, 0x15, 0x2e, 0x7a, 0x79, 0x31, 0x5f, 0x63, + 0x96, 0x53, 0x1b, 0x34, 0xd9, 0x15, 0xea, 0x4f, 0x6d, 0x70, 0xca, 0xbe, + 0xf6, 0x82, 0xa9, 0xed, 0xda, 0x85, 0x77, 0xcc, 0x76, 0x1c, 0x6a, 0x81, + 0x0a, 0x21, 0xd8, 0x41, 0x99, 0x7f, 0x5e, 0x2e, 0x82, 0xc1, 0xe8, 0xaa, + 0xf7, 0x93, 0x81, 0x05, 0xaa, 0x92, 0xb4, 0x1f, 0xb7, 0x9a, 0xc0, 0x07, + 0x17, 0xf5, 0xcb, 0xc6, 0xb4, 0x4c, 0x0e, 0xd7, 0x56, 0xdc, 0x71, 0x20, + 0x74, 0x38, 0xd6, 0x74, 0xc6, 0xd6, 0x8f, 0x6b, 0xaf, 0x8b, 0x8d, 0xa0, + 0x6c, 0x29, 0x0b, 0x61, 0xe0, +} + +var certSet3Cert7 = []byte{ + 0x30, 0x82, 0x04, 0x49, 0x30, 0x82, 0x03, 0x31, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x13, 0x06, 0x7f, 0x94, 0x57, 0x85, 0x87, 0xe8, 0xac, 0x77, + 0xde, 0xb2, 0x53, 0x32, 0x5b, 0xbc, 0x99, 0x8b, 0x56, 0x0d, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19, 0x30, + 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, + 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x31, 0x30, 0x32, 0x32, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x30, 0x31, + 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x46, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d, + 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, + 0x20, 0x31, 0x42, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xc2, 0x4e, 0x16, 0x67, 0xdd, 0xce, 0xbc, + 0x6a, 0xc8, 0x37, 0x5a, 0xec, 0x3a, 0x30, 0xb0, 0x1d, 0xe6, 0xd1, 0x12, + 0xe8, 0x12, 0x28, 0x48, 0xcc, 0xe8, 0x29, 0xc1, 0xb9, 0x6e, 0x53, 0xd5, + 0xa3, 0xeb, 0x03, 0x39, 0x1a, 0xcc, 0x77, 0x87, 0xf6, 0x01, 0xb9, 0xd9, + 0x70, 0xcc, 0xcf, 0x6b, 0x8d, 0xe3, 0xe3, 0x03, 0x71, 0x86, 0x99, 0x6d, + 0xcb, 0xa6, 0x94, 0x2a, 0x4e, 0x13, 0xd6, 0xa7, 0xbd, 0x04, 0xec, 0x0a, + 0x16, 0x3c, 0x0a, 0xeb, 0x39, 0xb1, 0xc4, 0xb5, 0x58, 0xa3, 0xb6, 0xc7, + 0x56, 0x25, 0xec, 0x3e, 0x52, 0x7a, 0xa8, 0xe3, 0x29, 0x16, 0x07, 0xb9, + 0x6e, 0x50, 0xcf, 0xfb, 0x5f, 0x31, 0xf8, 0x1d, 0xba, 0x03, 0x4a, 0x62, + 0x89, 0x03, 0xae, 0x3e, 0x47, 0xf2, 0x0f, 0x27, 0x91, 0xe3, 0x14, 0x20, + 0x85, 0xf8, 0xfa, 0xe9, 0x8a, 0x35, 0xf5, 0x5f, 0x9e, 0x99, 0x4d, 0xe7, + 0x6b, 0x37, 0xef, 0xa4, 0x50, 0x3e, 0x44, 0xec, 0xfa, 0x5a, 0x85, 0x66, + 0x07, 0x9c, 0x7e, 0x17, 0x6a, 0x55, 0xf3, 0x17, 0x8a, 0x35, 0x1e, 0xee, + 0xe9, 0xac, 0xc3, 0x75, 0x4e, 0x58, 0x55, 0x7d, 0x53, 0x6b, 0x0a, 0x6b, + 0x9b, 0x14, 0x42, 0xd7, 0xe5, 0xac, 0x01, 0x89, 0xb3, 0xea, 0xa3, 0xfe, + 0xcf, 0xc0, 0x2b, 0x0c, 0x84, 0xc2, 0xd8, 0x53, 0x15, 0xcb, 0x67, 0xf0, + 0xd0, 0x88, 0xca, 0x3a, 0xd1, 0x17, 0x73, 0xf5, 0x5f, 0x9a, 0xd4, 0xc5, + 0x72, 0x1e, 0x7e, 0x01, 0xf1, 0x98, 0x30, 0x63, 0x2a, 0xaa, 0xf2, 0x7a, + 0x2d, 0xc5, 0xe2, 0x02, 0x1a, 0x86, 0xe5, 0x32, 0x3e, 0x0e, 0xbd, 0x11, + 0xb4, 0xcf, 0x3c, 0x93, 0xef, 0x17, 0x50, 0x10, 0x9e, 0x43, 0xc2, 0x06, + 0x2a, 0xe0, 0x0d, 0x68, 0xbe, 0xd3, 0x88, 0x8b, 0x4a, 0x65, 0x8c, 0x4a, + 0xd4, 0xc3, 0x2e, 0x4c, 0x9b, 0x55, 0xf4, 0x86, 0xe5, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x3b, 0x30, 0x82, 0x01, 0x37, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, + 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x59, 0xa4, 0x66, + 0x06, 0x52, 0xa0, 0x7b, 0x95, 0x92, 0x3c, 0xa3, 0x94, 0x07, 0x27, 0x96, + 0x74, 0x5b, 0xf9, 0x3d, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x84, 0x18, 0xcc, 0x85, 0x34, 0xec, + 0xbc, 0x0c, 0x94, 0x94, 0x2e, 0x08, 0x59, 0x9c, 0xc7, 0xb2, 0x10, 0x4e, + 0x0a, 0x08, 0x30, 0x7b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x6f, 0x30, 0x6d, 0x30, 0x2f, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x23, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x74, + 0x63, 0x61, 0x31, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3a, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2e, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x72, 0x6f, 0x6f, 0x74, + 0x63, 0x61, 0x31, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, + 0x63, 0x61, 0x31, 0x2e, 0x63, 0x65, 0x72, 0x30, 0x3f, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x38, 0x30, 0x36, 0x30, 0x34, 0xa0, 0x32, 0xa0, 0x30, + 0x86, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x2e, 0x72, 0x6f, 0x6f, 0x74, 0x63, 0x61, 0x31, 0x2e, 0x61, 0x6d, 0x61, + 0x7a, 0x6f, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x63, 0x61, 0x31, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x0c, 0x30, 0x0a, 0x30, + 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x01, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x92, 0xbe, 0x35, 0xbb, 0x79, 0xcf, + 0xa3, 0x81, 0x42, 0x1c, 0xe4, 0xe3, 0x63, 0x73, 0x53, 0x39, 0x52, 0x35, + 0xe7, 0xd1, 0xad, 0xfd, 0xae, 0x99, 0x8a, 0xac, 0x89, 0x12, 0x2f, 0xbb, + 0xe7, 0x6f, 0x9a, 0xd5, 0x4e, 0x72, 0xea, 0x20, 0x30, 0x61, 0xf9, 0x97, + 0xb2, 0xcd, 0xa5, 0x27, 0x02, 0x45, 0xa8, 0xca, 0x76, 0x3e, 0x98, 0x4a, + 0x83, 0x9e, 0xb6, 0xe6, 0x45, 0xe0, 0xf2, 0x43, 0xf6, 0x08, 0xde, 0x6d, + 0xe8, 0x6e, 0xdb, 0x31, 0x07, 0x13, 0xf0, 0x2f, 0x31, 0x0d, 0x93, 0x6d, + 0x61, 0x37, 0x7b, 0x58, 0xf0, 0xfc, 0x51, 0x98, 0x91, 0x28, 0x02, 0x4f, + 0x05, 0x76, 0xb7, 0xd3, 0xf0, 0x1b, 0xc2, 0xe6, 0x5e, 0xd0, 0x66, 0x85, + 0x11, 0x0f, 0x2e, 0x81, 0xc6, 0x10, 0x81, 0x29, 0xfe, 0x20, 0x60, 0x48, + 0xf3, 0xf2, 0xf0, 0x84, 0x13, 0x53, 0x65, 0x35, 0x15, 0x11, 0x6b, 0x82, + 0x51, 0x40, 0x55, 0x57, 0x5f, 0x18, 0xb5, 0xb0, 0x22, 0x3e, 0xad, 0xf2, + 0x5e, 0xa3, 0x01, 0xe3, 0xc3, 0xb3, 0xf9, 0xcb, 0x41, 0x5a, 0xe6, 0x52, + 0x91, 0xbb, 0xe4, 0x36, 0x87, 0x4f, 0x2d, 0xa9, 0xa4, 0x07, 0x68, 0x35, + 0xba, 0x94, 0x72, 0xcd, 0x0e, 0xea, 0x0e, 0x7d, 0x57, 0xf2, 0x79, 0xfc, + 0x37, 0xc5, 0x7b, 0x60, 0x9e, 0xb2, 0xeb, 0xc0, 0x2d, 0x90, 0x77, 0x0d, + 0x49, 0x10, 0x27, 0xa5, 0x38, 0xad, 0xc4, 0x12, 0xa3, 0xb4, 0xa3, 0xc8, + 0x48, 0xb3, 0x15, 0x0b, 0x1e, 0xe2, 0xe2, 0x19, 0xdc, 0xc4, 0x76, 0x52, + 0xc8, 0xbc, 0x8a, 0x41, 0x78, 0x70, 0xd9, 0x6d, 0x97, 0xb3, 0x4a, 0x8b, + 0x78, 0x2d, 0x5e, 0xb4, 0x0f, 0xa3, 0x4c, 0x60, 0xca, 0xe1, 0x47, 0xcb, + 0x78, 0x2d, 0x12, 0x17, 0xb1, 0x52, 0x8b, 0xca, 0x39, 0x2c, 0xbd, 0xb5, + 0x2f, 0xc2, 0x33, 0x02, 0x96, 0xab, 0xda, 0x94, 0x7f, +} + +var certSet3Cert8 = []byte{ + 0x30, 0x82, 0x04, 0x4d, 0x30, 0x82, 0x03, 0x35, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x71, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, + 0x32, 0x31, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x31, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x33, 0x34, 0x35, 0x35, 0x31, + 0x5a, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x12, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbb, 0x58, 0xc1, 0x12, 0x01, 0x2e, + 0x97, 0xd8, 0x7d, 0x18, 0xaa, 0xc8, 0xc2, 0xe5, 0x85, 0xe2, 0x17, 0x6c, + 0x60, 0x2e, 0xc9, 0x8d, 0x31, 0x05, 0x39, 0x1a, 0x06, 0x98, 0x56, 0xdd, + 0x54, 0xd7, 0x11, 0x8c, 0x59, 0x5b, 0x3d, 0xb1, 0x54, 0xae, 0x4b, 0x21, + 0x85, 0x32, 0x16, 0x5f, 0x54, 0x86, 0xe6, 0xd9, 0xb1, 0xd8, 0x60, 0x89, + 0x6b, 0x58, 0xbe, 0x72, 0xda, 0xa0, 0x00, 0x42, 0x76, 0xb1, 0x27, 0x59, + 0x4c, 0xcd, 0xe3, 0xba, 0xd4, 0x5c, 0xd9, 0xa6, 0x7f, 0xbb, 0x2b, 0x75, + 0xd5, 0x46, 0x44, 0xbd, 0xec, 0x40, 0x5c, 0x59, 0xb7, 0xdd, 0x59, 0x9f, + 0xf1, 0x6a, 0xf7, 0x06, 0xfc, 0xd6, 0x2f, 0x19, 0x8a, 0x95, 0x12, 0xba, + 0x9a, 0xca, 0xd5, 0x30, 0xd2, 0x38, 0xfc, 0x19, 0x3b, 0x5b, 0x15, 0x3b, + 0x36, 0xd0, 0x43, 0x4d, 0xd1, 0x65, 0xa1, 0xd4, 0x8b, 0xc1, 0x60, 0x41, + 0xb3, 0xd6, 0x70, 0x17, 0xcc, 0x39, 0xc0, 0x9c, 0x0c, 0xa0, 0x3d, 0xb7, + 0x11, 0x22, 0x4e, 0xce, 0xd9, 0xa9, 0x7a, 0xd2, 0x2a, 0x62, 0x9c, 0xa0, + 0x0b, 0x4e, 0x2a, 0xd7, 0xc3, 0x61, 0x5a, 0x85, 0xdd, 0x5c, 0x10, 0xb9, + 0x54, 0x3d, 0x2d, 0x03, 0xf8, 0x49, 0xf0, 0xbc, 0x92, 0xb7, 0xb7, 0x9c, + 0x31, 0xc7, 0xe9, 0xb8, 0xaa, 0x82, 0x0b, 0x05, 0xb9, 0x31, 0xcd, 0x08, + 0x5b, 0xbb, 0x22, 0x0b, 0xf6, 0x9c, 0x8e, 0x8a, 0x55, 0x1c, 0x76, 0x43, + 0x76, 0xf0, 0xe2, 0x6e, 0xf0, 0xdf, 0xa8, 0x29, 0x75, 0xe7, 0xc8, 0xa4, + 0x87, 0x8b, 0x6a, 0xf1, 0xbb, 0x08, 0xc9, 0x36, 0x18, 0x65, 0xee, 0x50, + 0x43, 0xb8, 0x5d, 0x72, 0xd5, 0x28, 0x39, 0xe1, 0x53, 0x3e, 0x25, 0x2c, + 0xda, 0x2b, 0x4f, 0xdd, 0x8a, 0x9e, 0x50, 0x50, 0xe0, 0x6f, 0x9a, 0xc4, + 0xd5, 0x19, 0x26, 0x89, 0x01, 0x75, 0x73, 0x09, 0x9b, 0x3b, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x4a, 0x30, 0x82, 0x01, 0x46, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, + 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x97, 0xc2, 0x27, 0x50, 0x9e, + 0xc2, 0xc9, 0xec, 0x0c, 0x88, 0x32, 0xc8, 0x7c, 0xad, 0xe2, 0xa6, 0x01, + 0x4f, 0xda, 0x6f, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2f, + 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x31, 0x2e, 0x73, 0x79, 0x6d, 0x63, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, + 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x67, 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, + 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, + 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x29, 0x06, 0x03, 0x55, 0x1d, + 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, 0x30, + 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, 0x61, + 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x35, 0x36, + 0x39, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x35, 0xeb, 0xe1, + 0x8b, 0x20, 0x56, 0x94, 0xba, 0x7a, 0xbd, 0x79, 0xa9, 0xf6, 0xe3, 0xfe, + 0x6e, 0x38, 0xb4, 0x32, 0xc1, 0xa3, 0xdb, 0x58, 0x56, 0x20, 0x3e, 0x7d, + 0xc7, 0x3a, 0xb1, 0x67, 0x69, 0xd5, 0x79, 0x14, 0x1b, 0xf6, 0xfa, 0xec, + 0x60, 0xf2, 0x79, 0xcd, 0x0a, 0x0c, 0x60, 0x8a, 0x74, 0x4c, 0xa3, 0x93, + 0x2a, 0xa0, 0xf0, 0x51, 0x7f, 0xcd, 0xe9, 0xf9, 0x92, 0xfd, 0x96, 0xab, + 0x45, 0xf5, 0x62, 0x3d, 0x3f, 0x60, 0x46, 0x50, 0x13, 0x3d, 0x20, 0x13, + 0x18, 0x2e, 0x94, 0x46, 0xae, 0xd5, 0x21, 0xfe, 0x43, 0xa1, 0xc9, 0x23, + 0xfe, 0x53, 0xc4, 0xbf, 0x1a, 0xd8, 0xac, 0x3a, 0xca, 0xde, 0x66, 0x97, + 0x23, 0xae, 0xd3, 0xdf, 0x4a, 0x4d, 0x73, 0x1f, 0x6f, 0x31, 0xa2, 0x51, + 0x04, 0x16, 0x6a, 0x00, 0xeb, 0xf9, 0x8d, 0x43, 0x81, 0xf0, 0x50, 0xa1, + 0x1f, 0xa6, 0xca, 0x3a, 0xf3, 0x28, 0x3c, 0x5f, 0x51, 0xac, 0xd7, 0x0a, + 0x45, 0x77, 0x4b, 0x0e, 0x52, 0x62, 0x1b, 0xd8, 0x38, 0x51, 0xa0, 0x92, + 0x2d, 0x3f, 0x90, 0x6e, 0xc8, 0x7e, 0x40, 0x9f, 0x20, 0x46, 0x15, 0x5d, + 0xe0, 0x50, 0x7c, 0xe1, 0x76, 0xaf, 0x5e, 0xed, 0x11, 0xd3, 0x2f, 0x13, + 0xb9, 0xb8, 0x25, 0xa4, 0xaf, 0x58, 0x09, 0xaf, 0x35, 0xb4, 0x62, 0x54, + 0x85, 0xe3, 0x48, 0xde, 0xbc, 0xd2, 0x90, 0x7a, 0x7a, 0xa4, 0x84, 0x0d, + 0xa3, 0x42, 0xf2, 0x51, 0xc0, 0xd4, 0xad, 0x53, 0x65, 0x5d, 0x6c, 0xf8, + 0x3f, 0x1f, 0x06, 0xf2, 0x4f, 0xcb, 0x97, 0xa0, 0x4a, 0x59, 0xc6, 0x78, + 0xd1, 0xe8, 0x03, 0xb9, 0x85, 0x6d, 0x2c, 0xba, 0xe1, 0x5f, 0xb6, 0xad, + 0x2b, 0x3e, 0x25, 0x79, 0xc5, 0x8b, 0x56, 0xd5, 0xe3, 0x09, 0x80, 0xea, + 0xc1, 0x27, 0xc2, 0xd9, 0x0e, 0xec, 0x47, 0x0a, 0xe9, 0xd0, 0xca, 0xfc, + 0xd8, +} + +var certSet3Cert9 = []byte{ + 0x30, 0x82, 0x04, 0x4d, 0x30, 0x82, 0x03, 0x35, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x44, 0x4e, 0xf0, + 0x36, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4c, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, + 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, + 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41, + 0x6c, 0x70, 0x68, 0x61, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, 0x47, 0x32, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0x01, 0xec, + 0xe4, 0xec, 0x73, 0x60, 0xfb, 0x7e, 0x8f, 0x6a, 0xb7, 0xc6, 0x17, 0xe3, + 0x92, 0x64, 0x32, 0xd4, 0xac, 0x00, 0xd9, 0xa2, 0x0f, 0xb9, 0xed, 0xee, + 0x6b, 0x8a, 0x86, 0xca, 0x92, 0x67, 0xd9, 0x74, 0xd7, 0x5d, 0x47, 0x02, + 0x3c, 0x8f, 0x40, 0xd6, 0x9e, 0x6d, 0x14, 0xcd, 0xc3, 0xda, 0x29, 0x39, + 0xa7, 0x0f, 0x05, 0x0a, 0x68, 0xa2, 0x66, 0x1a, 0x1e, 0xc4, 0xb2, 0x8b, + 0x76, 0x58, 0xe5, 0xab, 0x5d, 0x1d, 0x8f, 0x40, 0xb3, 0x39, 0x8b, 0xef, + 0x1e, 0x83, 0x7d, 0x22, 0xd0, 0xe3, 0xa9, 0x00, 0x2e, 0xec, 0x53, 0xcf, + 0x62, 0x19, 0x85, 0x44, 0x28, 0x4c, 0xc0, 0x27, 0xcb, 0x7b, 0x0e, 0xec, + 0x10, 0x64, 0x00, 0x10, 0xa4, 0x05, 0xcc, 0xa0, 0x72, 0xbe, 0x41, 0x6c, + 0x31, 0x5b, 0x48, 0xe4, 0xb1, 0xec, 0xb9, 0x23, 0xeb, 0x55, 0x4d, 0xd0, + 0x7d, 0x62, 0x4a, 0xa5, 0xb4, 0xa5, 0xa4, 0x59, 0x85, 0xc5, 0x25, 0x91, + 0xa6, 0xfe, 0xa6, 0x09, 0x9f, 0x06, 0x10, 0x6d, 0x8f, 0x81, 0x0c, 0x64, + 0x40, 0x5e, 0x73, 0x00, 0x9a, 0xe0, 0x2e, 0x65, 0x98, 0x54, 0x10, 0x00, + 0x70, 0x98, 0xc8, 0xe1, 0xed, 0x34, 0x5f, 0xd8, 0x9c, 0xc7, 0x0d, 0xc0, + 0xd6, 0x23, 0x59, 0x45, 0xfc, 0xfe, 0x55, 0x7a, 0x86, 0xee, 0x94, 0x60, + 0x22, 0xf1, 0xae, 0xd1, 0xe6, 0x55, 0x46, 0xf6, 0x99, 0xc5, 0x1b, 0x08, + 0x74, 0x5f, 0xac, 0xb0, 0x64, 0x84, 0x8f, 0x89, 0x38, 0x1c, 0xa1, 0xa7, + 0x90, 0x21, 0x4f, 0x02, 0x6e, 0xbd, 0xe0, 0x61, 0x67, 0xd4, 0xf8, 0x42, + 0x87, 0x0f, 0x0a, 0xf7, 0xc9, 0x04, 0x6d, 0x2a, 0xa9, 0x2f, 0xef, 0x42, + 0xa5, 0xdf, 0xdd, 0xa3, 0x53, 0xdb, 0x98, 0x1e, 0x81, 0xf9, 0x9a, 0x72, + 0x7b, 0x5a, 0xde, 0x4f, 0x3e, 0x7f, 0xa2, 0x58, 0xa0, 0xe2, 0x17, 0xad, + 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x23, 0x30, 0x82, + 0x01, 0x1f, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0xf5, 0xcd, 0xd5, 0x3c, 0x08, 0x50, 0xf9, 0x6a, 0x4f, 0x3a, 0xb7, + 0x97, 0xda, 0x56, 0x83, 0xe6, 0x69, 0xd2, 0x68, 0xf7, 0x30, 0x45, 0x06, + 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3e, 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x04, + 0x55, 0x1d, 0x20, 0x00, 0x30, 0x32, 0x30, 0x30, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x24, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x30, 0x33, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, + 0x24, 0x86, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, + 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, + 0x6c, 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, + 0x6f, 0x74, 0x72, 0x31, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0x60, 0x7b, 0x66, 0x1a, 0x45, 0x0d, 0x97, + 0xca, 0x89, 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, 0xa8, 0xff, 0xfc, 0xfd, + 0x4b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x60, 0x40, 0x68, + 0x16, 0x47, 0xe7, 0x16, 0x8d, 0xdb, 0x5c, 0xa1, 0x56, 0x2a, 0xcb, 0xf4, + 0x5c, 0x9b, 0xb0, 0x1e, 0xa2, 0x4b, 0xf5, 0xcb, 0x02, 0x3f, 0xf8, 0x0b, + 0xa1, 0xf2, 0xa7, 0x42, 0xd4, 0xb7, 0x4c, 0xeb, 0xe3, 0x66, 0x80, 0xf3, + 0x25, 0x43, 0x78, 0x2e, 0x1b, 0x17, 0x56, 0x07, 0x52, 0x18, 0xcb, 0xd1, + 0xa8, 0xec, 0xe6, 0xfb, 0x73, 0x3e, 0xa4, 0x62, 0x8c, 0x80, 0xb4, 0xd2, + 0xc5, 0x12, 0x73, 0xa3, 0xd3, 0xfa, 0x02, 0x38, 0xbe, 0x63, 0x3d, 0x84, + 0xb8, 0x99, 0xc1, 0xf1, 0xba, 0xf7, 0x9f, 0xc3, 0x40, 0xd1, 0x58, 0x18, + 0x53, 0xc1, 0x62, 0xdd, 0xaf, 0x18, 0x42, 0x7f, 0x34, 0x4e, 0xc5, 0x43, + 0xd5, 0x71, 0xb0, 0x30, 0x00, 0xc7, 0xe3, 0x90, 0xae, 0x3f, 0x57, 0x86, + 0x97, 0xce, 0xea, 0x0c, 0x12, 0x8e, 0x22, 0x70, 0xe3, 0x66, 0xa7, 0x54, + 0x7f, 0x2e, 0x28, 0xcb, 0xd4, 0x54, 0xd0, 0xb3, 0x1e, 0x62, 0x67, 0x08, + 0xf9, 0x27, 0xe1, 0xcb, 0xe3, 0x66, 0xb8, 0x24, 0x1b, 0x89, 0x6a, 0x89, + 0x44, 0x65, 0xf2, 0xd9, 0x4c, 0xd2, 0x58, 0x1c, 0x8c, 0x4e, 0xc0, 0x95, + 0xa1, 0xd4, 0xef, 0x67, 0x2f, 0x38, 0x20, 0xe8, 0x2e, 0xff, 0x96, 0x51, + 0xf0, 0xba, 0xd8, 0x3d, 0x92, 0x70, 0x47, 0x65, 0x1c, 0x9e, 0x73, 0x72, + 0xb4, 0x60, 0x0c, 0x5c, 0xe2, 0xd1, 0x73, 0x76, 0xe0, 0xaf, 0x4e, 0xe2, + 0xe5, 0x37, 0xa5, 0x45, 0x2f, 0x8a, 0x23, 0x3e, 0x87, 0xc7, 0x30, 0xe6, + 0x31, 0x38, 0x7c, 0xf4, 0xdd, 0x52, 0xca, 0xf3, 0x53, 0x04, 0x25, 0x57, + 0x56, 0x66, 0x94, 0xe8, 0x0b, 0xee, 0xe6, 0x03, 0x14, 0x4e, 0xee, 0xfd, + 0x6d, 0x94, 0x64, 0x9e, 0x5e, 0xce, 0x79, 0xd4, 0xb2, 0xa6, 0xcf, 0x40, + 0xb1, 0x44, 0xa8, 0x3e, 0x87, 0x19, 0x5e, 0xe9, 0xf8, 0x21, 0x16, 0x59, + 0x53, +} + +var certSet3Cert10 = []byte{ + 0x30, 0x82, 0x04, 0x4f, 0x30, 0x82, 0x03, 0x37, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x6f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, + 0x31, 0x30, 0x35, 0x32, 0x31, 0x33, 0x36, 0x35, 0x30, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x31, 0x33, 0x36, 0x35, 0x30, + 0x5a, 0x30, 0x44, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x14, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe3, 0xbe, 0x7e, 0x0a, + 0x86, 0xa3, 0xcf, 0x6b, 0x6d, 0x3d, 0x2b, 0xa1, 0x97, 0xad, 0x49, 0x24, + 0x4d, 0xd7, 0x77, 0xb9, 0x34, 0x79, 0x08, 0xa5, 0x9e, 0xa2, 0x9e, 0xde, + 0x47, 0x12, 0x92, 0x3d, 0x7e, 0xea, 0x19, 0x86, 0xb1, 0xe8, 0x4f, 0x3d, + 0x5f, 0xf7, 0xd0, 0xa7, 0x77, 0x9a, 0x5b, 0x1f, 0x0a, 0x03, 0xb5, 0x19, + 0x53, 0xdb, 0xa5, 0x21, 0x94, 0x69, 0x63, 0x9d, 0x6a, 0x4c, 0x91, 0x0c, + 0x10, 0x47, 0xbe, 0x11, 0xfa, 0x6c, 0x86, 0x25, 0xb7, 0xab, 0x04, 0x68, + 0x42, 0x38, 0x09, 0x65, 0xf0, 0x14, 0xda, 0x19, 0x9e, 0xfa, 0x6b, 0x0b, + 0xab, 0x62, 0xef, 0x8d, 0xa7, 0xef, 0x63, 0x70, 0x23, 0xa8, 0xaf, 0x81, + 0xf3, 0xd1, 0x6e, 0x88, 0x67, 0x53, 0xec, 0x12, 0xa4, 0x29, 0x75, 0x8a, + 0xa7, 0xf2, 0x57, 0x3d, 0xa2, 0x83, 0x98, 0x97, 0xf2, 0x0a, 0x7d, 0xd4, + 0xe7, 0x43, 0x6e, 0x30, 0x78, 0x62, 0x22, 0x59, 0x59, 0xb8, 0x71, 0x27, + 0x45, 0xaa, 0x0f, 0x66, 0xc6, 0x55, 0x3f, 0xfa, 0x32, 0x17, 0x2b, 0x31, + 0x8f, 0x46, 0xa0, 0xfa, 0x69, 0x14, 0x7c, 0x9d, 0x9f, 0x5a, 0xe2, 0xeb, + 0x33, 0x4e, 0x10, 0xa6, 0xb3, 0xed, 0x77, 0x63, 0xd8, 0xc3, 0x9e, 0xf4, + 0xdd, 0xdf, 0x79, 0x9a, 0x7a, 0xd4, 0xee, 0xde, 0xdd, 0x9a, 0xcc, 0xc3, + 0xb7, 0xa9, 0x5d, 0xcc, 0x11, 0x3a, 0x07, 0xbb, 0x6f, 0x97, 0xa4, 0x01, + 0x23, 0x47, 0x95, 0x1f, 0xa3, 0x77, 0xfa, 0x58, 0x92, 0xc6, 0xc7, 0xd0, + 0xbd, 0xcf, 0x93, 0x18, 0x42, 0xb7, 0x7e, 0xf7, 0x9e, 0x65, 0xea, 0xd5, + 0x3b, 0xca, 0xed, 0xac, 0xc5, 0x70, 0xa1, 0xfe, 0xd4, 0x10, 0x9a, 0xf0, + 0x12, 0x04, 0x44, 0xac, 0x1a, 0x5b, 0x78, 0x50, 0x45, 0x57, 0x4c, 0x6f, + 0xbd, 0x80, 0xcb, 0x81, 0x5c, 0x2d, 0xb3, 0xbc, 0x76, 0xa1, 0x1e, 0x65, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x4a, 0x30, 0x82, 0x01, + 0x46, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, + 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd2, 0x6f, 0xf7, + 0x96, 0xf4, 0x85, 0x3f, 0x72, 0x3c, 0x30, 0x7d, 0x23, 0xda, 0x85, 0x78, + 0x9b, 0xa3, 0x7c, 0x5a, 0x7c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x31, 0x2e, 0x73, 0x79, + 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, + 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, + 0x6c, 0x30, 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x67, 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, + 0x43, 0x30, 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, + 0x01, 0x07, 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x29, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, + 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, + 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, + 0x35, 0x33, 0x39, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa0, + 0xd4, 0xf7, 0x2c, 0xfb, 0x74, 0x0b, 0x7f, 0x64, 0xf1, 0xcd, 0x43, 0x6a, + 0x9f, 0x62, 0x53, 0x1c, 0x02, 0x7c, 0x98, 0x90, 0xa2, 0xee, 0x4f, 0x68, + 0xd4, 0x20, 0x1a, 0x73, 0x12, 0x3e, 0x77, 0xb3, 0x50, 0xeb, 0x72, 0xbc, + 0xee, 0x88, 0xbe, 0x7f, 0x17, 0xea, 0x77, 0x8f, 0x83, 0x61, 0x95, 0x4f, + 0x84, 0xa1, 0xcb, 0x32, 0x4f, 0x6c, 0x21, 0xbe, 0xd2, 0x69, 0x96, 0x7d, + 0x63, 0xbd, 0xdc, 0x2b, 0xa8, 0x1f, 0xd0, 0x13, 0x84, 0x70, 0xfe, 0xf6, + 0x35, 0x95, 0x89, 0xf9, 0xa6, 0x77, 0xb0, 0x46, 0xc8, 0xbb, 0xb7, 0x13, + 0xf5, 0xc9, 0x60, 0x69, 0xd6, 0x4c, 0xfe, 0xd2, 0x8e, 0xef, 0xd3, 0x60, + 0xc1, 0x80, 0x80, 0xe1, 0xe7, 0xfb, 0x8b, 0x6f, 0x21, 0x79, 0x4a, 0xe0, + 0xdc, 0xa9, 0x1b, 0xc1, 0xb7, 0xfb, 0xc3, 0x49, 0x59, 0x5c, 0xb5, 0x77, + 0x07, 0x44, 0xd4, 0x97, 0xfc, 0x49, 0x00, 0x89, 0x6f, 0x06, 0x4e, 0x01, + 0x70, 0x19, 0xac, 0x2f, 0x11, 0xc0, 0xe2, 0xe6, 0x0f, 0x2f, 0x86, 0x4b, + 0x8d, 0x7b, 0xc3, 0xb9, 0xa7, 0x2e, 0xf4, 0xf1, 0xac, 0x16, 0x3e, 0x39, + 0x49, 0x51, 0x9e, 0x17, 0x4b, 0x4f, 0x10, 0x3a, 0x5b, 0xa5, 0xa8, 0x92, + 0x6f, 0xfd, 0xfa, 0xd6, 0x0b, 0x03, 0x4d, 0x47, 0x56, 0x57, 0x19, 0xf3, + 0xcb, 0x6b, 0xf5, 0xf3, 0xd6, 0xcf, 0xb0, 0xf5, 0xf5, 0xa3, 0x11, 0xd2, + 0x20, 0x53, 0x13, 0x34, 0x37, 0x05, 0x2c, 0x43, 0x5a, 0x63, 0xdf, 0x8d, + 0x40, 0xd6, 0x85, 0x1e, 0x51, 0xe9, 0x51, 0x17, 0x1e, 0x03, 0x56, 0xc9, + 0xf1, 0x30, 0xad, 0xe7, 0x9b, 0x11, 0xa2, 0xb9, 0xd0, 0x31, 0x81, 0x9b, + 0x68, 0xb1, 0xd9, 0xe8, 0xf3, 0xe6, 0x94, 0x7e, 0xc7, 0xae, 0x13, 0x2f, + 0x87, 0xed, 0xd0, 0x25, 0xb0, 0x68, 0xf9, 0xde, 0x08, 0x5a, 0xf3, 0x29, + 0xcc, 0xd4, 0x92, +} + +var certSet3Cert11 = []byte{ + 0x30, 0x82, 0x04, 0x59, 0x30, 0x82, 0x03, 0x41, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x63, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, + 0x38, 0x32, 0x37, 0x32, 0x30, 0x34, 0x30, 0x34, 0x30, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x30, 0x34, 0x30, 0x34, 0x30, + 0x5a, 0x30, 0x44, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x14, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb9, 0x27, 0xf9, 0x4f, + 0xd8, 0xf6, 0xb7, 0x15, 0x3f, 0x8f, 0xcd, 0xce, 0xd6, 0x8d, 0x1c, 0x6b, + 0xfd, 0x7f, 0xda, 0x54, 0x21, 0x4e, 0x03, 0xd8, 0xca, 0xd0, 0x72, 0x52, + 0x15, 0xb8, 0xc9, 0x82, 0x5b, 0x58, 0x79, 0x84, 0xff, 0x24, 0x72, 0x6f, + 0xf2, 0x69, 0x7f, 0xbc, 0x96, 0xd9, 0x9a, 0x7a, 0xc3, 0x3e, 0xa9, 0xcf, + 0x50, 0x22, 0x13, 0x0e, 0x86, 0x19, 0xdb, 0xe8, 0x49, 0xef, 0x8b, 0xe6, + 0xd6, 0x47, 0xf2, 0xfd, 0x73, 0x45, 0x08, 0xae, 0x8f, 0xac, 0x5e, 0xb6, + 0xf8, 0x9e, 0x7c, 0xf7, 0x10, 0xff, 0x92, 0x43, 0x66, 0xef, 0x1c, 0xd4, + 0xee, 0xa1, 0x46, 0x88, 0x11, 0x89, 0x49, 0x79, 0x7a, 0x25, 0xce, 0x4b, + 0x6a, 0xf0, 0xd7, 0x1c, 0x76, 0x1a, 0x29, 0x3c, 0xc9, 0xe4, 0xfd, 0x1e, + 0x85, 0xdc, 0xe0, 0x31, 0x65, 0x05, 0x47, 0x16, 0xac, 0x0a, 0x07, 0x4b, + 0x2e, 0x70, 0x5e, 0x6b, 0x06, 0xa7, 0x6b, 0x3a, 0x6c, 0xaf, 0x05, 0x12, + 0xc4, 0xb2, 0x11, 0x25, 0xd6, 0x3e, 0x97, 0x29, 0xf0, 0x83, 0x6c, 0x57, + 0x1c, 0xd8, 0xa5, 0xef, 0xcc, 0xec, 0xfd, 0xd6, 0x12, 0xf1, 0x3f, 0xdb, + 0x40, 0xb4, 0xae, 0x0f, 0x18, 0xd3, 0xc5, 0xaf, 0x40, 0x92, 0x5d, 0x07, + 0x5e, 0x4e, 0xfe, 0x62, 0x17, 0x37, 0x89, 0xe9, 0x8b, 0x74, 0x26, 0xa2, + 0xed, 0xb8, 0x0a, 0xe7, 0x6c, 0x15, 0x5b, 0x35, 0x90, 0x72, 0xdd, 0xd8, + 0x4d, 0x21, 0xd4, 0x40, 0x23, 0x5c, 0x8f, 0xee, 0x80, 0x31, 0x16, 0xab, + 0x68, 0x55, 0xf4, 0x0e, 0x3b, 0x54, 0xe9, 0x04, 0x4d, 0xf0, 0xcc, 0x4e, + 0x81, 0x5e, 0xe9, 0x6f, 0x52, 0x69, 0x4e, 0xbe, 0xa6, 0x16, 0x6d, 0x42, + 0xf5, 0x51, 0xff, 0xe0, 0x0b, 0x56, 0x3c, 0x98, 0x4f, 0x73, 0x8f, 0x0e, + 0x6f, 0x1a, 0x23, 0xf1, 0xc9, 0xc8, 0xd9, 0xdf, 0xbc, 0xec, 0x52, 0xd7, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x54, 0x30, 0x82, 0x01, + 0x50, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, + 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x11, 0x4a, 0xd0, + 0x73, 0x39, 0xd5, 0x5b, 0x69, 0x08, 0x5c, 0xba, 0x3d, 0xbf, 0x64, 0x9a, + 0xa8, 0x8b, 0x1c, 0x55, 0xbc, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, + 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, + 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, + 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, + 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x1d, 0x11, + 0x04, 0x23, 0x30, 0x21, 0xa4, 0x1f, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x56, 0x65, 0x72, 0x69, 0x53, + 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, 0x2d, 0x32, 0x2d, 0x32, 0x35, + 0x34, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3c, 0xe5, 0x3d, + 0x5a, 0x1b, 0xa2, 0x37, 0x2a, 0xe3, 0x46, 0xcf, 0x36, 0x96, 0x18, 0x3c, + 0x7b, 0xf1, 0x84, 0xc5, 0x57, 0x86, 0x77, 0x40, 0x9d, 0x35, 0xf0, 0x12, + 0xf0, 0x78, 0x18, 0xfb, 0x22, 0xa4, 0xde, 0x98, 0x4b, 0x78, 0x81, 0xe6, + 0x4d, 0x86, 0xe3, 0x91, 0x0f, 0x42, 0xe3, 0xb9, 0xdc, 0xa0, 0xd6, 0xff, + 0xa9, 0xf8, 0xb1, 0x79, 0x97, 0x99, 0xd1, 0xc3, 0x6c, 0x42, 0xa5, 0x92, + 0x94, 0xe0, 0x5d, 0x0c, 0x33, 0x18, 0x25, 0xc9, 0x2b, 0x95, 0x53, 0xe0, + 0xe5, 0xa9, 0x0c, 0x7d, 0x47, 0xfe, 0x7f, 0x51, 0x31, 0x44, 0x5e, 0xf7, + 0x2a, 0x1e, 0x35, 0xa2, 0x94, 0x32, 0xf7, 0xc9, 0xee, 0xc0, 0xb6, 0xc6, + 0x9a, 0xac, 0xde, 0x99, 0x21, 0x6a, 0x23, 0xa0, 0x38, 0x64, 0xee, 0xa3, + 0xc4, 0x88, 0x73, 0x32, 0x3b, 0x50, 0xce, 0xbf, 0xad, 0xd3, 0x75, 0x1e, + 0xa6, 0xf4, 0xe9, 0xf9, 0x42, 0x6b, 0x60, 0xb2, 0xdd, 0x45, 0xfd, 0x5d, + 0x57, 0x08, 0xce, 0x2d, 0x50, 0xe6, 0x12, 0x32, 0x16, 0x13, 0x8a, 0xf2, + 0x94, 0xa2, 0x9b, 0x47, 0xa8, 0x86, 0x7f, 0xd9, 0x98, 0xe5, 0xf7, 0xe5, + 0x76, 0x74, 0x64, 0xd8, 0x91, 0xbc, 0x84, 0x16, 0x28, 0xd8, 0x25, 0x44, + 0x30, 0x7e, 0x82, 0xd8, 0xac, 0xb1, 0xe4, 0xc0, 0xe4, 0x15, 0x6c, 0xdb, + 0xb6, 0x24, 0x27, 0x02, 0x2a, 0x01, 0x12, 0x85, 0xba, 0x31, 0x88, 0x58, + 0x47, 0x74, 0xe3, 0xb8, 0xd2, 0x64, 0xa6, 0xc3, 0x32, 0x59, 0x2e, 0x29, + 0x4b, 0x45, 0xf1, 0x5b, 0x89, 0x49, 0x2e, 0x82, 0x9a, 0xc6, 0x18, 0x15, + 0x44, 0xd0, 0x2e, 0x64, 0x01, 0x15, 0x68, 0x38, 0xf9, 0xf6, 0xf9, 0x66, + 0x03, 0x0c, 0x55, 0x1b, 0x9d, 0xbf, 0x00, 0x40, 0xae, 0xf0, 0x48, 0x27, + 0x4c, 0xe0, 0x80, 0x5e, 0x2d, 0xb9, 0x2a, 0x15, 0x7a, 0xbc, 0x66, 0xf8, + 0x35, +} + +var certSet3Cert12 = []byte{ + 0x30, 0x82, 0x04, 0x63, 0x30, 0x82, 0x03, 0x4b, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x44, 0x4e, 0xf0, + 0x3e, 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x60, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, + 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, + 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xa9, 0xdd, 0xcc, 0x0e, 0xb3, 0xe2, 0x32, + 0x39, 0xdd, 0x49, 0x22, 0xa8, 0x13, 0x69, 0x93, 0x87, 0x88, 0xe1, 0x0c, + 0xee, 0x71, 0x7d, 0xbd, 0x90, 0x87, 0x96, 0x5d, 0x59, 0xf2, 0xcc, 0xb3, + 0xd2, 0x58, 0x57, 0x57, 0xf9, 0x46, 0xef, 0x6c, 0x26, 0xd8, 0x36, 0x42, + 0x8e, 0x7e, 0x30, 0xb3, 0x2f, 0x9a, 0x3e, 0x53, 0x7b, 0x1f, 0x6e, 0xb6, + 0xa2, 0x4c, 0x45, 0x1f, 0x3c, 0xd3, 0x15, 0x93, 0x1c, 0x89, 0xed, 0x3c, + 0xf4, 0x57, 0xde, 0xca, 0xbd, 0xec, 0x06, 0x9a, 0x6a, 0x2a, 0xa0, 0x19, + 0x52, 0x7f, 0x51, 0xd1, 0x74, 0x39, 0x08, 0x9f, 0xab, 0xeb, 0xd7, 0x86, + 0x13, 0x15, 0x97, 0xae, 0x36, 0xc3, 0x54, 0x66, 0x0e, 0x5a, 0xf2, 0xa0, + 0x73, 0x85, 0x31, 0xe3, 0xb2, 0x64, 0x14, 0x6a, 0xff, 0xa5, 0xa2, 0x8e, + 0x24, 0xbb, 0xbd, 0x85, 0x52, 0x15, 0xa2, 0x79, 0xee, 0xf0, 0xb5, 0xee, + 0x3d, 0xb8, 0xf4, 0x7d, 0x80, 0xbc, 0xd9, 0x90, 0x35, 0x65, 0xb8, 0x17, + 0xa9, 0xad, 0xb3, 0x98, 0x9f, 0xa0, 0x7e, 0x7d, 0x6e, 0xfb, 0x3f, 0xad, + 0x7c, 0xc2, 0x1b, 0x59, 0x36, 0x96, 0xda, 0x37, 0x32, 0x4b, 0x4b, 0x5d, + 0x35, 0x02, 0x63, 0x8e, 0xdb, 0xa7, 0xcf, 0x62, 0xee, 0xcc, 0x2e, 0xd4, + 0x8d, 0xc9, 0xbd, 0x3c, 0x6a, 0x91, 0x72, 0xa2, 0x22, 0xa7, 0x72, 0x2d, + 0x20, 0xd1, 0xfa, 0xca, 0x37, 0xda, 0x18, 0x98, 0xe6, 0x16, 0x24, 0x71, + 0x25, 0x4b, 0xc4, 0xe5, 0x7b, 0x89, 0x52, 0x09, 0x02, 0xfd, 0x59, 0x2b, + 0x04, 0x6e, 0xca, 0x07, 0x81, 0xd4, 0xb3, 0xda, 0xda, 0xdb, 0xe3, 0xcc, + 0x80, 0xa8, 0x56, 0x07, 0x06, 0x7c, 0x96, 0x08, 0x37, 0x9d, 0xdb, 0x38, + 0xb6, 0x62, 0x34, 0x91, 0x62, 0x07, 0x74, 0x01, 0x38, 0xd8, 0x72, 0x30, + 0xe2, 0xeb, 0x90, 0x71, 0x26, 0x62, 0xc0, 0x57, 0xf3, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x25, 0x30, 0x82, 0x01, 0x21, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xea, 0x4e, 0x7c, + 0xd4, 0x80, 0x2d, 0xe5, 0x15, 0x81, 0x86, 0x26, 0x8c, 0x82, 0x6d, 0xc0, + 0x98, 0xa4, 0xcf, 0x97, 0x0f, 0x30, 0x47, 0x06, 0x03, 0x55, 0x1d, 0x20, + 0x04, 0x40, 0x30, 0x3e, 0x30, 0x3c, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, + 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, + 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x6e, + 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, + 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, + 0x72, 0x31, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x60, 0x7b, 0x66, 0x1a, 0x45, 0x0d, 0x97, 0xca, 0x89, + 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, 0xa8, 0xff, 0xfc, 0xfd, 0x4b, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xd7, 0x45, 0x9e, 0xa0, 0xdc, + 0xe0, 0xe3, 0x61, 0x5a, 0x0b, 0x7d, 0x77, 0x84, 0x17, 0x2d, 0x65, 0x5a, + 0x82, 0x9a, 0x8d, 0xa3, 0x27, 0x2a, 0x85, 0xf7, 0xc9, 0xef, 0xe9, 0x86, + 0xfd, 0xd4, 0x47, 0xcd, 0x01, 0x52, 0x96, 0xc5, 0x43, 0xbd, 0x37, 0xb1, + 0xe1, 0xb8, 0xf2, 0xa9, 0xd2, 0x8a, 0x11, 0x84, 0x71, 0x91, 0x15, 0x89, + 0xdc, 0x02, 0x9d, 0x0b, 0xcb, 0x6c, 0x33, 0x85, 0x34, 0x28, 0x9e, 0x20, + 0xb2, 0xb1, 0x97, 0xdc, 0x6d, 0x0b, 0x10, 0xc1, 0x3c, 0xcd, 0x5f, 0xea, + 0x5d, 0xd7, 0x98, 0x31, 0xc5, 0x34, 0x99, 0x5c, 0x00, 0x61, 0x55, 0xc4, + 0x1b, 0x02, 0x5b, 0xc5, 0xe3, 0x89, 0xc8, 0xb4, 0xb8, 0x6f, 0x1e, 0x38, + 0xf2, 0x56, 0x26, 0xe9, 0x41, 0xef, 0x3d, 0xcd, 0xac, 0x99, 0x4f, 0x59, + 0x4a, 0x57, 0x2d, 0x4b, 0x7d, 0xae, 0xc7, 0x88, 0xfb, 0xd6, 0x98, 0x3b, + 0xf5, 0xe5, 0xf0, 0xe8, 0x89, 0x89, 0xb9, 0x8b, 0x03, 0xcb, 0x5a, 0x23, + 0x1f, 0xa4, 0xfd, 0xb8, 0xea, 0xfb, 0x2e, 0x9d, 0xae, 0x6a, 0x73, 0x09, + 0xbc, 0xfc, 0xd5, 0xa0, 0xb5, 0x44, 0x82, 0xab, 0x44, 0x91, 0x2e, 0x50, + 0x2e, 0x57, 0xc1, 0x43, 0xd8, 0x91, 0x04, 0x8b, 0xe9, 0x11, 0x2e, 0x5f, + 0xb4, 0x3f, 0x79, 0xdf, 0x1e, 0xfb, 0x3f, 0x30, 0x00, 0x8b, 0x53, 0xe3, + 0xb7, 0x2c, 0x1d, 0x3b, 0x4d, 0x8b, 0xdc, 0xe4, 0x64, 0x1d, 0x04, 0x58, + 0x33, 0xaf, 0x1b, 0x55, 0xe7, 0xab, 0x0c, 0xbf, 0x30, 0x04, 0x74, 0xe4, + 0xf3, 0x0e, 0x2f, 0x30, 0x39, 0x8d, 0x4b, 0x04, 0x8c, 0x1e, 0x75, 0x66, + 0x66, 0x49, 0xe0, 0xbe, 0x40, 0x34, 0xc7, 0x5c, 0x5a, 0x51, 0x92, 0xba, + 0x12, 0x3c, 0x52, 0xd5, 0x04, 0x82, 0x55, 0x2d, 0x67, 0xa5, 0xdf, 0xb7, + 0x95, 0x7c, 0xee, 0x3f, 0xc3, 0x08, 0xba, 0x04, 0xbe, 0xc0, 0x46, +} + +var certSet3Cert13 = []byte{ + 0x30, 0x82, 0x04, 0x69, 0x30, 0x82, 0x03, 0x51, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x44, 0x4e, 0xf0, + 0x42, 0x47, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x32, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x66, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, + 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, + 0x31, 0x3c, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x33, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, + 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc7, + 0x0e, 0x6c, 0x3f, 0x23, 0x93, 0x7f, 0xcc, 0x70, 0xa5, 0x9d, 0x20, 0xc3, + 0x0e, 0x53, 0x3f, 0x7e, 0xc0, 0x4e, 0xc2, 0x98, 0x49, 0xca, 0x47, 0xd5, + 0x23, 0xef, 0x03, 0x34, 0x85, 0x74, 0xc8, 0xa3, 0x02, 0x2e, 0x46, 0x5c, + 0x0b, 0x7d, 0xc9, 0x88, 0x9d, 0x4f, 0x8b, 0xf0, 0xf8, 0x9c, 0x6c, 0x8c, + 0x55, 0x35, 0xdb, 0xbf, 0xf2, 0xb3, 0xea, 0xfb, 0xe3, 0x56, 0xe7, 0x4a, + 0x46, 0xd9, 0x13, 0x22, 0xca, 0x36, 0xd5, 0x9b, 0xc1, 0xa8, 0xe3, 0x96, + 0x43, 0x93, 0xf2, 0x0c, 0xbc, 0xe6, 0xf9, 0xe6, 0xe8, 0x99, 0xc8, 0x63, + 0x48, 0x78, 0x7f, 0x57, 0x36, 0x69, 0x1a, 0x19, 0x1d, 0x5a, 0xd1, 0xd4, + 0x7d, 0xc2, 0x9c, 0xd4, 0x7f, 0xe1, 0x80, 0x12, 0xae, 0x7a, 0xea, 0x88, + 0xea, 0x57, 0xd8, 0xca, 0x0a, 0x0a, 0x3a, 0x12, 0x49, 0xa2, 0x62, 0x19, + 0x7a, 0x0d, 0x24, 0xf7, 0x37, 0xeb, 0xb4, 0x73, 0x92, 0x7b, 0x05, 0x23, + 0x9b, 0x12, 0xb5, 0xce, 0xeb, 0x29, 0xdf, 0xa4, 0x14, 0x02, 0xb9, 0x01, + 0xa5, 0xd4, 0xa6, 0x9c, 0x43, 0x64, 0x88, 0xde, 0xf8, 0x7e, 0xfe, 0xe3, + 0xf5, 0x1e, 0xe5, 0xfe, 0xdc, 0xa3, 0xa8, 0xe4, 0x66, 0x31, 0xd9, 0x4c, + 0x25, 0xe9, 0x18, 0xb9, 0x89, 0x59, 0x09, 0xae, 0xe9, 0x9d, 0x1c, 0x6d, + 0x37, 0x0f, 0x4a, 0x1e, 0x35, 0x20, 0x28, 0xe2, 0xaf, 0xd4, 0x21, 0x8b, + 0x01, 0xc4, 0x45, 0xad, 0x6e, 0x2b, 0x63, 0xab, 0x92, 0x6b, 0x61, 0x0a, + 0x4d, 0x20, 0xed, 0x73, 0xba, 0x7c, 0xce, 0xfe, 0x16, 0xb5, 0xdb, 0x9f, + 0x80, 0xf0, 0xd6, 0x8b, 0x6c, 0xd9, 0x08, 0x79, 0x4a, 0x4f, 0x78, 0x65, + 0xda, 0x92, 0xbc, 0xbe, 0x35, 0xf9, 0xb3, 0xc4, 0xf9, 0x27, 0x80, 0x4e, + 0xff, 0x96, 0x52, 0xe6, 0x02, 0x20, 0xe1, 0x07, 0x73, 0xe9, 0x5d, 0x2b, + 0xbd, 0xb2, 0xf1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x25, + 0x30, 0x82, 0x01, 0x21, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x96, 0xde, 0x61, 0xf1, 0xbd, 0x1c, 0x16, 0x29, 0x53, + 0x1c, 0xc0, 0xcc, 0x7d, 0x3b, 0x83, 0x00, 0x40, 0xe6, 0x1a, 0x7c, 0x30, + 0x47, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x40, 0x30, 0x3e, 0x30, 0x3c, + 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, + 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, + 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x72, 0x31, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x60, 0x7b, 0x66, + 0x1a, 0x45, 0x0d, 0x97, 0xca, 0x89, 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, + 0xa8, 0xff, 0xfc, 0xfd, 0x4b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, + 0x00, 0x46, 0x2a, 0xee, 0x5e, 0xbd, 0xae, 0x01, 0x60, 0x37, 0x31, 0x11, + 0x86, 0x71, 0x74, 0xb6, 0x46, 0x49, 0xc8, 0x10, 0x16, 0xfe, 0x2f, 0x62, + 0x23, 0x17, 0xab, 0x1f, 0x87, 0xf8, 0x82, 0xed, 0xca, 0xdf, 0x0e, 0x2c, + 0xdf, 0x64, 0x75, 0x8e, 0xe5, 0x18, 0x72, 0xa7, 0x8c, 0x3a, 0x8b, 0xc9, + 0xac, 0xa5, 0x77, 0x50, 0xf7, 0xef, 0x9e, 0xa4, 0xe0, 0xa0, 0x8f, 0x14, + 0x57, 0xa3, 0x2a, 0x5f, 0xec, 0x7e, 0x6d, 0x10, 0xe6, 0xba, 0x8d, 0xb0, + 0x08, 0x87, 0x76, 0x0e, 0x4c, 0xb2, 0xd9, 0x51, 0xbb, 0x11, 0x02, 0xf2, + 0x5c, 0xdd, 0x1c, 0xbd, 0xf3, 0x55, 0x96, 0x0f, 0xd4, 0x06, 0xc0, 0xfc, + 0xe2, 0x23, 0x8a, 0x24, 0x70, 0xd3, 0xbb, 0xf0, 0x79, 0x1a, 0xa7, 0x61, + 0x70, 0x83, 0x8a, 0xaf, 0x06, 0xc5, 0x20, 0xd8, 0xa1, 0x63, 0xd0, 0x6c, + 0xae, 0x4f, 0x32, 0xd7, 0xae, 0x7c, 0x18, 0x45, 0x75, 0x05, 0x29, 0x77, + 0xdf, 0x42, 0x40, 0x64, 0x64, 0x86, 0xbe, 0x2a, 0x76, 0x09, 0x31, 0x6f, + 0x1d, 0x24, 0xf4, 0x99, 0xd0, 0x85, 0xfe, 0xf2, 0x21, 0x08, 0xf9, 0xc6, + 0xf6, 0xf1, 0xd0, 0x59, 0xed, 0xd6, 0x56, 0x3c, 0x08, 0x28, 0x03, 0x67, + 0xba, 0xf0, 0xf9, 0xf1, 0x90, 0x16, 0x47, 0xae, 0x67, 0xe6, 0xbc, 0x80, + 0x48, 0xe9, 0x42, 0x76, 0x34, 0x97, 0x55, 0x69, 0x24, 0x0e, 0x83, 0xd6, + 0xa0, 0x2d, 0xb4, 0xf5, 0xf3, 0x79, 0x8a, 0x49, 0x28, 0x74, 0x1a, 0x41, + 0xa1, 0xc2, 0xd3, 0x24, 0x88, 0x35, 0x30, 0x60, 0x94, 0x17, 0xb4, 0xe1, + 0x04, 0x22, 0x31, 0x3d, 0x3b, 0x2f, 0x17, 0x06, 0xb2, 0xb8, 0x9d, 0x86, + 0x2b, 0x5a, 0x69, 0xef, 0x83, 0xf5, 0x4b, 0xc4, 0xaa, 0xb4, 0x2a, 0xf8, + 0x7c, 0xa1, 0xb1, 0x85, 0x94, 0x8c, 0xf4, 0x0c, 0x87, 0x0c, 0xf4, 0xac, + 0x40, 0xf8, 0x59, 0x49, 0x98, +} + +var certSet3Cert14 = []byte{ + 0x30, 0x82, 0x04, 0x6c, 0x30, 0x82, 0x03, 0x54, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x4d, 0x5f, 0x2c, 0x34, 0x08, 0xb2, 0x4c, 0x20, 0xcd, + 0x6d, 0x50, 0x7e, 0x24, 0x4d, 0xc9, 0xec, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x32, 0x30, 0x38, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, 0x30, + 0x32, 0x30, 0x37, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x3c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x54, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x99, 0xe4, 0x85, + 0x5b, 0x76, 0x49, 0x7d, 0x2f, 0x05, 0xd8, 0xc5, 0xac, 0xc8, 0xc8, 0xa9, + 0xd3, 0xdc, 0x98, 0xe6, 0xd7, 0x34, 0xa6, 0x2f, 0x0c, 0xf2, 0x22, 0x26, + 0xd8, 0xa3, 0xc9, 0x14, 0x4c, 0x8f, 0x05, 0xa4, 0x45, 0xe8, 0x14, 0x0c, + 0x58, 0x90, 0x05, 0x1a, 0xb7, 0xc5, 0xc1, 0x06, 0xa5, 0x80, 0xaf, 0xbb, + 0x1d, 0x49, 0x6b, 0x52, 0x34, 0x88, 0xc3, 0x59, 0xe7, 0xef, 0x6b, 0xc4, + 0x27, 0x41, 0x8c, 0x2b, 0x66, 0x1d, 0xd0, 0xe0, 0xa3, 0x97, 0x98, 0x19, + 0x34, 0x4b, 0x41, 0xd5, 0x98, 0xd5, 0xc7, 0x05, 0xad, 0xa2, 0xe4, 0xd7, + 0xed, 0x0c, 0xad, 0x4f, 0xc1, 0xb5, 0xb0, 0x21, 0xfd, 0x3e, 0x50, 0x53, + 0xb2, 0xc4, 0x90, 0xd0, 0xd4, 0x30, 0x67, 0x6c, 0x9a, 0xf1, 0x0e, 0x74, + 0xc4, 0xc2, 0xdc, 0x8a, 0xe8, 0x97, 0xff, 0xc9, 0x92, 0xae, 0x01, 0x8a, + 0x56, 0x0a, 0x98, 0x32, 0xb0, 0x00, 0x23, 0xec, 0x90, 0x1a, 0x60, 0xc3, + 0xed, 0xbb, 0x3a, 0xcb, 0x0f, 0x63, 0x9f, 0x0d, 0x44, 0xc9, 0x52, 0xe1, + 0x25, 0x96, 0xbf, 0xed, 0x50, 0x95, 0x89, 0x7f, 0x56, 0x14, 0xb1, 0xb7, + 0x61, 0x1d, 0x1c, 0x07, 0x8c, 0x3a, 0x2c, 0xf7, 0xff, 0x80, 0xde, 0x39, + 0x45, 0xd5, 0xaf, 0x1a, 0xd1, 0x78, 0xd8, 0xc7, 0x71, 0x6a, 0xa3, 0x19, + 0xa7, 0x32, 0x50, 0x21, 0xe9, 0xf2, 0x0e, 0xa1, 0xc6, 0x13, 0x03, 0x44, + 0x48, 0xd1, 0x66, 0xa8, 0x52, 0x57, 0xd7, 0x11, 0xb4, 0x93, 0x8b, 0xe5, + 0x99, 0x9f, 0x5d, 0xe7, 0x78, 0x51, 0xe5, 0x4d, 0xf6, 0xb7, 0x59, 0xb4, + 0x76, 0xb5, 0x09, 0x37, 0x4d, 0x06, 0x38, 0x13, 0x7a, 0x1c, 0x08, 0x98, + 0x5c, 0xc4, 0x48, 0x4a, 0xcb, 0x52, 0xa0, 0xa9, 0xf8, 0xb1, 0x9d, 0x8e, + 0x7b, 0x79, 0xb0, 0x20, 0x2f, 0x3c, 0x96, 0xa8, 0x11, 0x62, 0x47, 0xbb, + 0x11, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xfb, 0x30, 0x81, 0xf8, + 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2d, 0x30, 0x2b, 0x30, + 0x29, 0xa0, 0x27, 0xa0, 0x25, 0x86, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, + 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x28, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x21, 0x30, 0x1f, 0xa4, 0x1d, 0x30, + 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, + 0x2d, 0x32, 0x2d, 0x39, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0xa7, 0xa2, 0x83, 0xbb, 0x34, 0x45, 0x40, 0x3d, 0xfc, + 0xd5, 0x30, 0x4f, 0x12, 0xb9, 0x3e, 0xa1, 0x01, 0x9f, 0xf6, 0xdb, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x7b, 0x5b, 0x45, 0xcf, 0xaf, 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, + 0x6a, 0xb6, 0xf3, 0x46, 0xeb, 0x57, 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x80, 0x22, 0x80, 0xe0, 0x6c, 0xc8, 0x95, 0x16, + 0xd7, 0x57, 0x26, 0x87, 0xf3, 0x72, 0x34, 0xdb, 0xc6, 0x72, 0x56, 0x27, + 0x3e, 0xd3, 0x96, 0xf6, 0x2e, 0x25, 0x91, 0xa5, 0x3e, 0x33, 0x97, 0xa7, + 0x4b, 0xe5, 0x2f, 0xfb, 0x25, 0x7d, 0x2f, 0x07, 0x61, 0xfa, 0x6f, 0x83, + 0x74, 0x4c, 0x4c, 0x53, 0x72, 0x20, 0xa4, 0x7a, 0xcf, 0x51, 0x51, 0x56, + 0x81, 0x88, 0xb0, 0x6d, 0x1f, 0x36, 0x2c, 0xc8, 0x2b, 0xb1, 0x88, 0x99, + 0xc1, 0xfe, 0x44, 0xab, 0x48, 0x51, 0x7c, 0xd8, 0xf2, 0x44, 0x64, 0x2a, + 0xd8, 0x71, 0xa7, 0xfb, 0x1a, 0x2f, 0xf9, 0x19, 0x8d, 0x34, 0xb2, 0x23, + 0xbf, 0xc4, 0x4c, 0x55, 0x1d, 0x8e, 0x44, 0xe8, 0xaa, 0x5d, 0x9a, 0xdd, + 0x9f, 0xfd, 0x03, 0xc7, 0xba, 0x24, 0x43, 0x8d, 0x2d, 0x47, 0x44, 0xdb, + 0xf6, 0xd8, 0x98, 0xc8, 0xb2, 0xf9, 0xda, 0xef, 0xed, 0x29, 0x5c, 0x69, + 0x12, 0xfa, 0xd1, 0x23, 0x96, 0x0f, 0xbf, 0x9c, 0x0d, 0xf2, 0x79, 0x45, + 0x53, 0x37, 0x9a, 0x56, 0x2f, 0xe8, 0x57, 0x10, 0x70, 0xf6, 0xee, 0x89, + 0x0c, 0x49, 0x89, 0x9a, 0xc1, 0x23, 0xf5, 0xc2, 0x2a, 0xcc, 0x41, 0xcf, + 0x22, 0xab, 0x65, 0x6e, 0xb7, 0x94, 0x82, 0x6d, 0x2f, 0x40, 0x5f, 0x58, + 0xde, 0xeb, 0x95, 0x2b, 0xa6, 0x72, 0x68, 0x52, 0x19, 0x91, 0x2a, 0xae, + 0x75, 0x9d, 0x4e, 0x92, 0xe6, 0xca, 0xde, 0x54, 0xea, 0x18, 0xab, 0x25, + 0x3c, 0xe6, 0x64, 0xa6, 0x79, 0x1f, 0x26, 0x7d, 0x61, 0xed, 0x7d, 0xd2, + 0xe5, 0x71, 0x55, 0xd8, 0x93, 0x17, 0x7c, 0x14, 0x38, 0x30, 0x3c, 0xdf, + 0x86, 0xe3, 0x4c, 0xad, 0x49, 0xe3, 0x97, 0x59, 0xce, 0x1b, 0x9b, 0x2b, + 0xce, 0xdc, 0x65, 0xd4, 0x0b, 0x28, 0x6b, 0x4e, 0x84, 0x46, 0x51, 0x44, + 0xf7, 0x33, 0x08, 0x2d, 0x58, 0x97, 0x21, 0xae, +} + +var certSet3Cert15 = []byte{ + 0x30, 0x82, 0x04, 0x6e, 0x30, 0x82, 0x03, 0x56, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x6e, 0x8a, 0x90, 0xeb, 0xcf, 0xf0, 0x44, 0x8a, 0x72, + 0x0d, 0x08, 0x05, 0xd0, 0x82, 0xa5, 0x44, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x58, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, + 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, + 0x33, 0x31, 0x30, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, + 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x17, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, + 0x56, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, + 0x34, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, + 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd9, 0xb4, + 0x05, 0xf2, 0x38, 0x67, 0x0f, 0x09, 0xe7, 0x7c, 0xf5, 0x63, 0x2a, 0xe5, + 0xb9, 0x5e, 0xa8, 0x11, 0xae, 0x75, 0x71, 0xd9, 0x4c, 0x84, 0x67, 0xad, + 0x89, 0x5d, 0xfc, 0x28, 0x3d, 0x2a, 0xb0, 0xa5, 0xd5, 0xd4, 0xe6, 0x30, + 0x0a, 0x84, 0xd4, 0xe4, 0x18, 0xcb, 0x85, 0x37, 0xc5, 0x46, 0x71, 0xeb, + 0x1c, 0x7b, 0x69, 0xdb, 0x65, 0x69, 0x8c, 0x30, 0x05, 0x3e, 0x07, 0xe1, + 0x6f, 0x3c, 0xc1, 0x0b, 0x61, 0xe6, 0x38, 0x44, 0xfc, 0xbc, 0x8c, 0x2f, + 0x4e, 0x75, 0x57, 0xf5, 0x96, 0x99, 0x7c, 0x3e, 0x87, 0x1f, 0x0f, 0x90, + 0x4b, 0x70, 0xc3, 0x3f, 0x39, 0x45, 0x3b, 0x3a, 0x6b, 0xcb, 0xbb, 0x7b, + 0x40, 0x54, 0xd1, 0x8b, 0x4b, 0xa1, 0x72, 0xd2, 0x04, 0xe9, 0xe0, 0x72, + 0x1a, 0x93, 0x11, 0x7a, 0x2f, 0xf1, 0xab, 0x9d, 0x9c, 0x98, 0x58, 0xae, + 0x2c, 0xea, 0x77, 0x5f, 0x2f, 0x2e, 0x87, 0xaf, 0xb8, 0x6b, 0xe3, 0xe2, + 0xe2, 0x3f, 0xd6, 0x3d, 0xe0, 0x96, 0x44, 0xdf, 0x11, 0x55, 0x63, 0x52, + 0x2f, 0xf4, 0x26, 0x78, 0xc4, 0x0f, 0x20, 0x4d, 0x0a, 0xc0, 0x68, 0x70, + 0x15, 0x86, 0x38, 0xee, 0xb7, 0x76, 0x88, 0xab, 0x18, 0x8f, 0x4f, 0x35, + 0x1e, 0xd4, 0x8c, 0xc9, 0xdb, 0x7e, 0x3d, 0x44, 0xd4, 0x36, 0x8c, 0xc1, + 0x37, 0xb5, 0x59, 0x5b, 0x87, 0xf9, 0xe9, 0xf1, 0xd4, 0xc5, 0x28, 0xbd, + 0x1d, 0xdc, 0xcc, 0x96, 0x72, 0xd1, 0x7a, 0xa1, 0xa7, 0x20, 0xb5, 0xb8, + 0xaf, 0xf8, 0x6e, 0xa5, 0x60, 0x7b, 0x2b, 0x8d, 0x1f, 0xee, 0xf4, 0x2b, + 0xd6, 0x69, 0xcd, 0xaf, 0xca, 0x80, 0x58, 0x29, 0xe8, 0x4c, 0x00, 0x20, + 0x8a, 0x49, 0x0a, 0x6e, 0x8e, 0x8c, 0xa8, 0xd1, 0x00, 0x12, 0x84, 0xb6, + 0xc5, 0xe2, 0x95, 0xa2, 0xc0, 0x3b, 0xa4, 0x6b, 0xf0, 0x82, 0xd0, 0x96, + 0x5d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x43, 0x30, + 0x82, 0x01, 0x3f, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x47, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x40, 0x30, 0x3e, 0x30, 0x3c, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, + 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2d, 0x30, 0x2b, 0x30, 0x29, 0xa0, 0x27, 0xa0, 0x25, 0x86, 0x23, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x31, 0x2e, 0x73, 0x79, + 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x65, 0x6f, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x50, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x29, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, + 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x11, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, + 0x2d, 0x31, 0x2d, 0x35, 0x33, 0x38, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0xde, 0xcf, 0x5c, 0x50, 0xb7, 0xae, 0x02, + 0x1f, 0x15, 0x17, 0xaa, 0x16, 0xe8, 0x0d, 0xb5, 0x28, 0x9d, 0x6a, 0x5a, + 0xf3, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x2c, 0xd5, 0x50, 0x41, 0x97, 0x15, 0x8b, 0xf0, 0x8f, 0x36, + 0x61, 0x5b, 0x4a, 0xfb, 0x6b, 0xd9, 0x99, 0xc9, 0x33, 0x92, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xb4, 0x8e, 0xbd, 0x07, 0xb9, 0x9a, + 0x85, 0xec, 0x3b, 0x67, 0xbd, 0x07, 0x60, 0x61, 0xe6, 0x84, 0xd1, 0xd4, + 0xef, 0xeb, 0x1b, 0xba, 0x0b, 0x82, 0x4b, 0x95, 0x64, 0xb6, 0x66, 0x53, + 0x23, 0xbd, 0xb7, 0x84, 0xdd, 0xe4, 0x7b, 0x8d, 0x09, 0xda, 0xcf, 0xb2, + 0xf5, 0xf1, 0xc3, 0xbf, 0x87, 0x84, 0xbe, 0x4e, 0xa6, 0xa8, 0xc2, 0xe7, + 0x12, 0x39, 0x28, 0x34, 0xe0, 0xa4, 0x56, 0x44, 0x40, 0x0c, 0x9f, 0x88, + 0xa3, 0x15, 0xd3, 0xe8, 0xd3, 0x5e, 0xe3, 0x1c, 0x04, 0x60, 0xfb, 0x69, + 0x36, 0x4f, 0x6a, 0x7e, 0x0c, 0x2a, 0x28, 0xc1, 0xf3, 0xaa, 0x58, 0x0e, + 0x6c, 0xce, 0x1d, 0x07, 0xc3, 0x4a, 0xc0, 0x9c, 0x8d, 0xc3, 0x74, 0xb1, + 0xae, 0x82, 0xf0, 0x1a, 0xe1, 0xf9, 0x4e, 0x29, 0xbd, 0x46, 0xde, 0xb7, + 0x1d, 0xf9, 0x7d, 0xdb, 0xd9, 0x0f, 0x84, 0xcb, 0x92, 0x45, 0xcc, 0x1c, + 0xb3, 0x18, 0xf6, 0xa0, 0xcf, 0x71, 0x6f, 0x0c, 0x2e, 0x9b, 0xd2, 0x2d, + 0xb3, 0x99, 0x93, 0x83, 0x44, 0xac, 0x15, 0xaa, 0x9b, 0x2e, 0x67, 0xec, + 0x4f, 0x88, 0x69, 0x05, 0x56, 0x7b, 0x8b, 0xb2, 0x43, 0xa9, 0x3a, 0x6c, + 0x1c, 0x13, 0x33, 0x25, 0x1b, 0xfd, 0xa8, 0xc8, 0x57, 0x02, 0xfb, 0x1c, + 0xe0, 0xd1, 0xbd, 0x3b, 0x56, 0x44, 0x65, 0xc3, 0x63, 0xf5, 0x1b, 0xef, + 0xec, 0x30, 0xd9, 0xe3, 0x6e, 0x2e, 0x13, 0xe9, 0x39, 0x08, 0x2a, 0x0c, + 0x72, 0xf3, 0x9a, 0xcc, 0xf6, 0x27, 0x29, 0x84, 0xd3, 0xef, 0x4c, 0xc7, + 0x84, 0x11, 0x65, 0x1f, 0xc6, 0xe3, 0x81, 0x03, 0xdb, 0x87, 0xcc, 0x78, + 0xf7, 0xb5, 0x9d, 0x96, 0x3e, 0x6a, 0x7f, 0xbc, 0x11, 0x85, 0x7a, 0x75, + 0xe6, 0x41, 0x7d, 0x0d, 0xcf, 0xf9, 0xe5, 0x85, 0x69, 0x25, 0x8f, 0xc7, + 0x8d, 0x07, 0x2d, 0xf8, 0x69, 0x0f, 0xcb, 0x41, 0x53, 0x00, +} + +var certSet3Cert16 = []byte{ + 0x30, 0x82, 0x04, 0x6f, 0x30, 0x82, 0x03, 0x57, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x02, 0x3a, 0x73, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, + 0x36, 0x31, 0x31, 0x32, 0x32, 0x30, 0x32, 0x35, 0x39, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x32, 0x30, 0x32, 0x35, 0x39, + 0x5a, 0x30, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x14, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x53, 0x53, 0x4c, 0x31, + 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x44, 0x56, 0x20, 0x53, 0x53, + 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb3, 0x44, 0x3a, 0x6c, 0xb0, 0xae, + 0xcb, 0x14, 0xf9, 0x8c, 0x19, 0x74, 0x34, 0x5c, 0xa9, 0x69, 0xe3, 0x88, + 0x53, 0x77, 0xa5, 0xa7, 0xff, 0xbd, 0xd1, 0x3c, 0x0d, 0x27, 0xe4, 0xde, + 0xad, 0x7f, 0xbc, 0xd1, 0x90, 0x58, 0x93, 0xd6, 0xa6, 0xda, 0x39, 0x9c, + 0xad, 0xe1, 0x0e, 0x56, 0x46, 0xee, 0x95, 0x9e, 0x10, 0x68, 0x4c, 0x9c, + 0x2b, 0xf6, 0x6a, 0x3a, 0x8b, 0x80, 0x81, 0x87, 0x06, 0x57, 0x25, 0x1a, + 0x56, 0x52, 0x94, 0xdd, 0x90, 0xeb, 0x67, 0x3b, 0xde, 0xfa, 0xae, 0x36, + 0x68, 0xd3, 0x62, 0x69, 0xf6, 0x6c, 0x82, 0x24, 0x44, 0x4f, 0x87, 0x5c, + 0x98, 0x11, 0x95, 0x64, 0x6b, 0xe8, 0x0c, 0xd1, 0xdd, 0xe6, 0x27, 0x97, + 0xae, 0xcc, 0xe2, 0x91, 0x6a, 0x41, 0x12, 0xb6, 0xab, 0xe5, 0xcc, 0x6e, + 0xcc, 0x23, 0xb8, 0x63, 0x8a, 0x1f, 0x31, 0x93, 0x2d, 0x06, 0xc4, 0xf7, + 0xe8, 0x3d, 0x58, 0xcd, 0x97, 0x08, 0x46, 0x6c, 0x7b, 0x74, 0xc0, 0xf8, + 0xfc, 0x31, 0x3b, 0xa7, 0x7f, 0xd7, 0x8f, 0xb0, 0xc9, 0x15, 0x63, 0x50, + 0x7a, 0x12, 0x4d, 0xf5, 0x12, 0x1e, 0xa3, 0x7e, 0x55, 0xe3, 0x75, 0xb7, + 0xea, 0x1e, 0xea, 0x31, 0x2c, 0x08, 0x4e, 0xd8, 0xcb, 0x43, 0x74, 0x89, + 0x24, 0xbc, 0xd2, 0x0e, 0x1e, 0xf0, 0xdb, 0x05, 0x24, 0xf6, 0x8a, 0xbf, + 0x10, 0x27, 0x84, 0x41, 0x1a, 0xf6, 0x18, 0x53, 0xee, 0x91, 0xd0, 0x54, + 0x17, 0xd3, 0x7d, 0x3e, 0x7e, 0xb2, 0x7d, 0xa8, 0xbf, 0xdb, 0xb9, 0x21, + 0x2a, 0xf0, 0x89, 0xb9, 0x08, 0x6e, 0x5a, 0xb3, 0x5e, 0xea, 0x82, 0xb8, + 0x7e, 0x27, 0x0b, 0xcc, 0x56, 0x73, 0x81, 0x05, 0x4f, 0xe3, 0x96, 0x2d, + 0x71, 0xd5, 0x78, 0xa7, 0x60, 0xc3, 0xd7, 0xec, 0xaa, 0x39, 0x1a, 0x05, + 0x39, 0x82, 0x81, 0xe0, 0x15, 0x2c, 0x35, 0xd1, 0xee, 0x25, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x48, 0x30, 0x82, 0x01, 0x44, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, + 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xad, 0x65, 0x22, 0x85, 0x90, + 0xd0, 0x3b, 0xe3, 0xa1, 0x49, 0x8b, 0x37, 0xf9, 0xf1, 0x0b, 0x1d, 0x5f, + 0x17, 0xa0, 0x77, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2e, + 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x2e, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, + 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, + 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4c, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, + 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, + 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x2f, 0x63, 0x70, 0x73, 0x30, 0x29, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, + 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, + 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x36, 0x39, 0x39, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4e, 0x27, 0xb8, 0x1a, 0xc7, + 0x3b, 0xdc, 0x5d, 0xbb, 0x9e, 0x1a, 0x35, 0x23, 0x1e, 0x88, 0x55, 0x90, + 0xd1, 0xec, 0x86, 0x9c, 0x88, 0xb7, 0xe0, 0x1f, 0x67, 0x87, 0xe2, 0x7c, + 0xb5, 0x43, 0x03, 0x0e, 0xb6, 0x02, 0xe8, 0xe0, 0xff, 0x86, 0x84, 0x19, + 0x71, 0xe9, 0xf2, 0x4b, 0xf5, 0x9e, 0x2e, 0x2e, 0x5e, 0xdb, 0xab, 0xd6, + 0x1c, 0x4e, 0xc4, 0x3e, 0xb8, 0x2c, 0x78, 0x86, 0x71, 0x10, 0xae, 0x8d, + 0xc5, 0x70, 0xbf, 0xa4, 0xf9, 0x89, 0xe6, 0xb4, 0xed, 0xe8, 0x4b, 0xed, + 0x7c, 0x09, 0x2a, 0x09, 0x08, 0x06, 0x3e, 0xd4, 0xe1, 0xde, 0x82, 0x92, + 0x0c, 0x34, 0x30, 0x35, 0x0a, 0xc1, 0x60, 0x75, 0xca, 0xb6, 0x55, 0x6b, + 0xaa, 0x00, 0x42, 0xcb, 0x3f, 0xfb, 0x10, 0xe1, 0xfb, 0x85, 0xc1, 0x21, + 0x90, 0x72, 0x2b, 0x6e, 0xc0, 0xe8, 0x9d, 0xd9, 0xb5, 0x5a, 0x50, 0x8e, + 0x34, 0x1e, 0xbb, 0x38, 0xa7, 0x3c, 0x31, 0xbd, 0x7a, 0xf2, 0x43, 0x8b, + 0xeb, 0x16, 0xca, 0xad, 0x9b, 0xde, 0x6b, 0x1e, 0xf8, 0x4f, 0xb6, 0x5e, + 0x4a, 0x29, 0x1f, 0x7a, 0x14, 0xee, 0x91, 0xf4, 0x94, 0x4f, 0xa4, 0xbd, + 0x9b, 0x76, 0x7a, 0xbc, 0xf1, 0x51, 0x7a, 0x96, 0xa8, 0x81, 0x0e, 0x83, + 0x87, 0x3f, 0x8b, 0xae, 0x5e, 0x32, 0x9b, 0x34, 0x9e, 0xb2, 0xe7, 0xdb, + 0x2f, 0xec, 0x02, 0xa0, 0xe1, 0xfd, 0x51, 0x52, 0xfe, 0x2c, 0xdb, 0x36, + 0xba, 0xc1, 0xd6, 0x5e, 0x4b, 0x58, 0x6d, 0xde, 0xc6, 0xe1, 0xe1, 0xfa, + 0x9a, 0x03, 0x2c, 0x5b, 0xa2, 0xe1, 0xb3, 0x9b, 0xf9, 0x36, 0xec, 0xc1, + 0x73, 0xfa, 0x33, 0x12, 0x66, 0x95, 0xe3, 0x69, 0x10, 0xb6, 0xd7, 0xaa, + 0x33, 0xfa, 0xf6, 0x9d, 0x41, 0x6d, 0x96, 0x2a, 0xba, 0xbe, 0x83, 0x31, + 0x41, 0x7f, 0x0c, 0x0a, 0xd2, 0x69, 0xd6, 0xfc, 0x35, 0x4c, 0xc3, +} + +var certSet3Cert17 = []byte{ + 0x30, 0x82, 0x04, 0x75, 0x30, 0x82, 0x03, 0x5d, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x09, 0x00, 0xa7, 0x0e, 0x4a, 0x4c, 0x34, 0x82, 0xb7, 0x7f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, + 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, + 0x30, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x39, 0x30, 0x32, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x36, + 0x32, 0x38, 0x31, 0x37, 0x33, 0x39, 0x31, 0x36, 0x5a, 0x30, 0x81, 0x98, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, + 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, + 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, + 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x3b, 0x30, 0x39, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x32, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xd5, 0x0c, 0x3a, 0xc4, 0x2a, 0xf9, 0x4e, + 0xe2, 0xf5, 0xbe, 0x19, 0x97, 0x5f, 0x8e, 0x88, 0x53, 0xb1, 0x1f, 0x3f, + 0xcb, 0xcf, 0x9f, 0x20, 0x13, 0x6d, 0x29, 0x3a, 0xc8, 0x0f, 0x7d, 0x3c, + 0xf7, 0x6b, 0x76, 0x38, 0x63, 0xd9, 0x36, 0x60, 0xa8, 0x9b, 0x5e, 0x5c, + 0x00, 0x80, 0xb2, 0x2f, 0x59, 0x7f, 0xf6, 0x87, 0xf9, 0x25, 0x43, 0x86, + 0xe7, 0x69, 0x1b, 0x52, 0x9a, 0x90, 0xe1, 0x71, 0xe3, 0xd8, 0x2d, 0x0d, + 0x4e, 0x6f, 0xf6, 0xc8, 0x49, 0xd9, 0xb6, 0xf3, 0x1a, 0x56, 0xae, 0x2b, + 0xb6, 0x74, 0x14, 0xeb, 0xcf, 0xfb, 0x26, 0xe3, 0x1a, 0xba, 0x1d, 0x96, + 0x2e, 0x6a, 0x3b, 0x58, 0x94, 0x89, 0x47, 0x56, 0xff, 0x25, 0xa0, 0x93, + 0x70, 0x53, 0x83, 0xda, 0x84, 0x74, 0x14, 0xc3, 0x67, 0x9e, 0x04, 0x68, + 0x3a, 0xdf, 0x8e, 0x40, 0x5a, 0x1d, 0x4a, 0x4e, 0xcf, 0x43, 0x91, 0x3b, + 0xe7, 0x56, 0xd6, 0x00, 0x70, 0xcb, 0x52, 0xee, 0x7b, 0x7d, 0xae, 0x3a, + 0xe7, 0xbc, 0x31, 0xf9, 0x45, 0xf6, 0xc2, 0x60, 0xcf, 0x13, 0x59, 0x02, + 0x2b, 0x80, 0xcc, 0x34, 0x47, 0xdf, 0xb9, 0xde, 0x90, 0x65, 0x6d, 0x02, + 0xcf, 0x2c, 0x91, 0xa6, 0xa6, 0xe7, 0xde, 0x85, 0x18, 0x49, 0x7c, 0x66, + 0x4e, 0xa3, 0x3a, 0x6d, 0xa9, 0xb5, 0xee, 0x34, 0x2e, 0xba, 0x0d, 0x03, + 0xb8, 0x33, 0xdf, 0x47, 0xeb, 0xb1, 0x6b, 0x8d, 0x25, 0xd9, 0x9b, 0xce, + 0x81, 0xd1, 0x45, 0x46, 0x32, 0x96, 0x70, 0x87, 0xde, 0x02, 0x0e, 0x49, + 0x43, 0x85, 0xb6, 0x6c, 0x73, 0xbb, 0x64, 0xea, 0x61, 0x41, 0xac, 0xc9, + 0xd4, 0x54, 0xdf, 0x87, 0x2f, 0xc7, 0x22, 0xb2, 0x26, 0xcc, 0x9f, 0x59, + 0x54, 0x68, 0x9f, 0xfc, 0xbe, 0x2a, 0x2f, 0xc4, 0x55, 0x1c, 0x75, 0x40, + 0x60, 0x17, 0x85, 0x02, 0x55, 0x39, 0x8b, 0x7f, 0x05, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x81, 0xf0, 0x30, 0x81, 0xed, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, + 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0x9c, 0x5f, 0x00, 0xdf, 0xaa, 0x01, 0xd7, 0x30, + 0x2b, 0x38, 0x88, 0xa2, 0xb8, 0x6d, 0x4a, 0x9c, 0xf2, 0x11, 0x91, 0x83, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0xbf, 0x5f, 0xb7, 0xd1, 0xce, 0xdd, 0x1f, 0x86, 0xf4, 0x5b, 0x55, + 0xac, 0xdc, 0xd7, 0x10, 0xc2, 0x0e, 0xa9, 0x88, 0xe7, 0x30, 0x4f, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x43, 0x30, + 0x41, 0x30, 0x1c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x86, 0x10, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x2e, + 0x73, 0x73, 0x32, 0x2e, 0x75, 0x73, 0x2f, 0x30, 0x21, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x15, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x78, 0x2e, 0x73, 0x73, 0x32, 0x2e, 0x75, 0x73, + 0x2f, 0x78, 0x2e, 0x63, 0x65, 0x72, 0x30, 0x26, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x1f, 0x30, 0x1d, 0x30, 0x1b, 0xa0, 0x19, 0xa0, 0x17, 0x86, + 0x15, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x2e, 0x73, 0x73, + 0x32, 0x2e, 0x75, 0x73, 0x2f, 0x72, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x0a, 0x30, 0x08, 0x30, 0x06, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, + 0x00, 0x23, 0x1d, 0xe3, 0x8a, 0x57, 0xca, 0x7d, 0xe9, 0x17, 0x79, 0x4c, + 0xf1, 0x1e, 0x55, 0xfd, 0xcc, 0x53, 0x6e, 0x3e, 0x47, 0x0f, 0xdf, 0xc6, + 0x55, 0xf2, 0xb2, 0x04, 0x36, 0xed, 0x80, 0x1f, 0x53, 0xc4, 0x5d, 0x34, + 0x28, 0x6b, 0xbe, 0xc7, 0x55, 0xfc, 0x67, 0xea, 0xcb, 0x3f, 0x7f, 0x90, + 0xb2, 0x33, 0xcd, 0x1b, 0x58, 0x10, 0x82, 0x02, 0xf8, 0xf8, 0x2f, 0xf5, + 0x13, 0x60, 0xd4, 0x05, 0xce, 0xf1, 0x81, 0x08, 0xc1, 0xdd, 0xa7, 0x75, + 0x97, 0x4f, 0x18, 0xb9, 0x6d, 0xde, 0xf7, 0x93, 0x91, 0x08, 0xba, 0x7e, + 0x40, 0x2c, 0xed, 0xc1, 0xea, 0xbb, 0x76, 0x9e, 0x33, 0x06, 0x77, 0x1d, + 0x0d, 0x08, 0x7f, 0x53, 0xdd, 0x1b, 0x64, 0xab, 0x82, 0x27, 0xf1, 0x69, + 0xd5, 0x4d, 0x5e, 0xae, 0xf4, 0xa1, 0xc3, 0x75, 0xa7, 0x58, 0x44, 0x2d, + 0xf2, 0x3c, 0x70, 0x98, 0xac, 0xba, 0x69, 0xb6, 0x95, 0x77, 0x7f, 0x0f, + 0x31, 0x5e, 0x2c, 0xfc, 0xa0, 0x87, 0x3a, 0x47, 0x69, 0xf0, 0x79, 0x5f, + 0xf4, 0x14, 0x54, 0xa4, 0x95, 0x5e, 0x11, 0x78, 0x12, 0x60, 0x27, 0xce, + 0x9f, 0xc2, 0x77, 0xff, 0x23, 0x53, 0x77, 0x5d, 0xba, 0xff, 0xea, 0x59, + 0xe7, 0xdb, 0xcf, 0xaf, 0x92, 0x96, 0xef, 0x24, 0x9a, 0x35, 0x10, 0x7a, + 0x9c, 0x91, 0xc6, 0x0e, 0x7d, 0x99, 0xf6, 0x3f, 0x19, 0xdf, 0xf5, 0x72, + 0x54, 0xe1, 0x15, 0xa9, 0x07, 0x59, 0x7b, 0x83, 0xbf, 0x52, 0x2e, 0x46, + 0x8c, 0xb2, 0x00, 0x64, 0x76, 0x1c, 0x48, 0xd3, 0xd8, 0x79, 0xe8, 0x6e, + 0x56, 0xcc, 0xae, 0x2c, 0x03, 0x90, 0xd7, 0x19, 0x38, 0x99, 0xe4, 0xca, + 0x09, 0x19, 0x5b, 0xff, 0x07, 0x96, 0xb0, 0xa8, 0x7f, 0x34, 0x49, 0xdf, + 0x56, 0xa9, 0xf7, 0xb0, 0x5f, 0xed, 0x33, 0xed, 0x8c, 0x47, 0xb7, 0x30, + 0x03, 0x5d, 0xf4, 0x03, 0x8c, +} + +var certSet3Cert18 = []byte{ + 0x30, 0x82, 0x04, 0x79, 0x30, 0x82, 0x03, 0x61, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0xa2, 0x76, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, + 0x30, 0x32, 0x32, 0x37, 0x31, 0x38, 0x30, 0x39, 0x32, 0x37, 0x5a, 0x17, + 0x0d, 0x32, 0x30, 0x30, 0x36, 0x30, 0x39, 0x31, 0x37, 0x30, 0x37, 0x32, + 0x39, 0x5a, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x1a, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x20, 0x43, 0x6f, 0x2e, + 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x1d, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x20, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x20, 0x43, 0x41, 0x20, 0x47, 0x33, 0x30, 0x82, + 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x94, 0x56, 0xa3, 0x45, 0x44, + 0x54, 0xaa, 0x60, 0x64, 0xbf, 0xb8, 0x57, 0x9f, 0x4e, 0xdb, 0xd4, 0x79, + 0x68, 0x5f, 0x13, 0x05, 0xf4, 0x3f, 0xcd, 0x25, 0xdd, 0x3c, 0x5e, 0x58, + 0x77, 0x1c, 0x9d, 0xe6, 0x9f, 0xe3, 0x32, 0x49, 0xef, 0x02, 0x3a, 0x34, + 0x53, 0x8d, 0x52, 0xe5, 0xe3, 0x39, 0x66, 0x1f, 0xe7, 0x33, 0x61, 0xb6, + 0x27, 0xc6, 0x24, 0x55, 0x50, 0x27, 0x02, 0x65, 0xf0, 0xb0, 0x8c, 0x41, + 0x8d, 0x30, 0x5e, 0x47, 0x5b, 0x82, 0x6f, 0xc7, 0x9c, 0xa3, 0x28, 0x43, + 0x6d, 0x58, 0x7b, 0xc8, 0x15, 0x98, 0x4e, 0x25, 0x6f, 0xcb, 0x76, 0x27, + 0x5b, 0x0b, 0x2c, 0x2c, 0xb5, 0x98, 0x23, 0xe7, 0x8b, 0x7c, 0xfd, 0x77, + 0x1a, 0xc4, 0x52, 0xba, 0x5d, 0x19, 0xee, 0x78, 0x21, 0x4d, 0x21, 0x9a, + 0xd9, 0x12, 0x7c, 0x33, 0x15, 0x6b, 0x1a, 0xc9, 0x81, 0xea, 0xda, 0xda, + 0x57, 0xb7, 0xd5, 0x2f, 0xce, 0x1f, 0x4b, 0xfc, 0xb4, 0x33, 0xe0, 0xa0, + 0xc9, 0x94, 0x27, 0xbb, 0x27, 0x40, 0xb6, 0x90, 0xdb, 0xac, 0x9e, 0x75, + 0xa6, 0x11, 0x2b, 0x49, 0x19, 0x2d, 0xc3, 0xc2, 0x43, 0x07, 0x09, 0xbb, + 0x3d, 0x6e, 0x88, 0xa3, 0xe3, 0x8a, 0xc5, 0xd2, 0x86, 0xf6, 0x65, 0x5b, + 0x34, 0xc3, 0x9f, 0x4c, 0x02, 0xe5, 0x09, 0xba, 0x2c, 0xc6, 0x76, 0x66, + 0xeb, 0xd1, 0x76, 0x25, 0xf4, 0x30, 0x13, 0xfb, 0x58, 0x60, 0xa8, 0x58, + 0xe3, 0x51, 0x6f, 0x4b, 0x08, 0x04, 0x61, 0x8d, 0xac, 0xa9, 0x30, 0x2f, + 0x52, 0x41, 0xa3, 0x22, 0xc1, 0x33, 0x59, 0xab, 0x7b, 0x59, 0xf9, 0x93, + 0x67, 0x4b, 0xc9, 0x89, 0x75, 0x52, 0xef, 0x29, 0x49, 0x34, 0x93, 0x1c, + 0x9c, 0x93, 0x73, 0x9c, 0x19, 0xce, 0x5c, 0x18, 0xcd, 0x4c, 0x09, 0x27, + 0xc1, 0x3f, 0xf5, 0x49, 0xec, 0xf4, 0xe2, 0xdf, 0x4b, 0xaf, 0x8f, 0x02, + 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x45, 0x30, 0x82, 0x01, 0x41, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, + 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x53, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x4c, 0x30, 0x4a, 0x30, 0x48, 0x06, 0x09, 0x2b, + 0x06, 0x01, 0x04, 0x01, 0xb1, 0x3e, 0x01, 0x00, 0x30, 0x3b, 0x30, 0x39, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, + 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x66, 0x6d, 0x30, 0x42, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x36, 0x30, + 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x86, 0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, + 0x73, 0x70, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, + 0x65, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, + 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe5, 0x9d, + 0x59, 0x30, 0x82, 0x47, 0x58, 0xcc, 0xac, 0xfa, 0x08, 0x54, 0x36, 0x86, + 0x7b, 0x3a, 0xb5, 0x04, 0x4d, 0xf0, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, + 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x64, 0x70, 0x31, + 0x2e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x52, 0x4c, 0x2f, 0x4f, 0x6d, + 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x32, 0x30, 0x32, 0x35, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x73, 0xa8, 0x08, 0x53, 0x29, 0xb8, 0x15, 0xfb, 0x99, 0x80, 0xe5, + 0xc5, 0x37, 0xd8, 0xf8, 0x39, 0x7b, 0xa4, 0x13, 0x06, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0x68, 0xdf, 0xfe, 0x72, 0x54, 0x4e, 0x1b, + 0xfb, 0x5c, 0x6e, 0x5a, 0x45, 0x46, 0xcf, 0x42, 0xbe, 0xb2, 0x02, 0x9c, + 0x9d, 0x90, 0x6a, 0x09, 0x2e, 0xb7, 0x36, 0x64, 0x24, 0xb6, 0xb1, 0xe2, + 0x48, 0x67, 0xce, 0x17, 0x46, 0x9b, 0x23, 0x75, 0x78, 0x11, 0xf6, 0xc6, + 0x09, 0x38, 0x42, 0x62, 0x96, 0x97, 0x30, 0x7b, 0x51, 0x77, 0xdf, 0x33, + 0xb5, 0x00, 0x51, 0x29, 0xd5, 0x24, 0xfe, 0xb7, 0x98, 0xa2, 0xac, 0x6c, + 0xa1, 0x13, 0x7f, 0xca, 0xf3, 0xb7, 0xa6, 0x52, 0xc2, 0x16, 0x0d, 0xec, + 0x3a, 0xbf, 0xa3, 0x37, 0x77, 0x4f, 0xae, 0x7b, 0x55, 0x1d, 0x46, 0xe9, + 0x10, 0xda, 0xc3, 0xb4, 0x05, 0x5c, 0x5b, 0xf6, 0x48, 0x21, 0x00, 0x89, + 0xf4, 0xbb, 0x38, 0x8e, 0x1e, 0x33, 0xf3, 0x49, 0x97, 0x81, 0x31, 0x6c, + 0x16, 0x74, 0x08, 0x91, 0x17, 0xc0, 0xd3, 0x25, 0xb3, 0xbc, 0xc1, 0x15, + 0xb5, 0xa4, 0xcd, 0x84, 0x4d, 0xb9, 0xc8, 0xeb, 0xc5, 0x59, 0x42, 0x10, + 0x14, 0x25, 0x79, 0xf8, 0xdb, 0xb6, 0xd0, 0xe6, 0xd3, 0xa0, 0x14, 0x7c, + 0x17, 0x1c, 0x20, 0x1e, 0xed, 0x99, 0x90, 0x65, 0xc0, 0x41, 0x71, 0xc3, + 0xab, 0x3f, 0x29, 0x41, 0x67, 0xf9, 0xe2, 0xd1, 0x98, 0xe3, 0xf8, 0xdf, + 0x3a, 0xb8, 0xca, 0xa3, 0x6f, 0x68, 0x8b, 0x6c, 0x9f, 0x6e, 0x88, 0x7c, + 0x9d, 0x41, 0x5c, 0xba, 0xcb, 0x19, 0x05, 0x83, 0x9c, 0x99, 0xf4, 0x1a, + 0xd2, 0x24, 0x69, 0x57, 0x0a, 0x0f, 0x7a, 0xc3, 0x1b, 0x2c, 0x4b, 0x06, + 0xd3, 0x2a, 0x97, 0x7e, 0x07, 0xb0, 0xf9, 0x20, 0x5a, 0xb5, 0x92, 0x4b, + 0x5b, 0xa8, 0xeb, 0xeb, 0x36, 0x33, 0x47, 0x36, 0xda, 0x72, 0x9c, 0xbf, + 0x68, 0x45, 0x81, 0x31, 0xbe, 0xd2, 0xfd, 0x3b, 0xe9, 0x72, 0xd5, 0x70, + 0xdd, 0xa6, 0xde, 0x5f, 0x0d, 0xb6, 0x5e, 0x00, 0x49, +} + +var certSet3Cert19 = []byte{ + 0x30, 0x82, 0x04, 0x7d, 0x30, 0x82, 0x03, 0x65, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x1b, 0xe7, 0x15, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x63, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54, + 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, + 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x47, 0x6f, + 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, + 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x30, 0x31, + 0x30, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, + 0x35, 0x33, 0x30, 0x30, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x81, + 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, + 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, + 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, + 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, 0x47, 0x6f, 0x20, 0x44, + 0x61, 0x64, 0x64, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x71, 0x62, + 0x08, 0xf1, 0xfa, 0x59, 0x34, 0xf7, 0x1b, 0xc9, 0x18, 0xa3, 0xf7, 0x80, + 0x49, 0x58, 0xe9, 0x22, 0x83, 0x13, 0xa6, 0xc5, 0x20, 0x43, 0x01, 0x3b, + 0x84, 0xf1, 0xe6, 0x85, 0x49, 0x9f, 0x27, 0xea, 0xf6, 0x84, 0x1b, 0x4e, + 0xa0, 0xb4, 0xdb, 0x70, 0x98, 0xc7, 0x32, 0x01, 0xb1, 0x05, 0x3e, 0x07, + 0x4e, 0xee, 0xf4, 0xfa, 0x4f, 0x2f, 0x59, 0x30, 0x22, 0xe7, 0xab, 0x19, + 0x56, 0x6b, 0xe2, 0x80, 0x07, 0xfc, 0xf3, 0x16, 0x75, 0x80, 0x39, 0x51, + 0x7b, 0xe5, 0xf9, 0x35, 0xb6, 0x74, 0x4e, 0xa9, 0x8d, 0x82, 0x13, 0xe4, + 0xb6, 0x3f, 0xa9, 0x03, 0x83, 0xfa, 0xa2, 0xbe, 0x8a, 0x15, 0x6a, 0x7f, + 0xde, 0x0b, 0xc3, 0xb6, 0x19, 0x14, 0x05, 0xca, 0xea, 0xc3, 0xa8, 0x04, + 0x94, 0x3b, 0x46, 0x7c, 0x32, 0x0d, 0xf3, 0x00, 0x66, 0x22, 0xc8, 0x8d, + 0x69, 0x6d, 0x36, 0x8c, 0x11, 0x18, 0xb7, 0xd3, 0xb2, 0x1c, 0x60, 0xb4, + 0x38, 0xfa, 0x02, 0x8c, 0xce, 0xd3, 0xdd, 0x46, 0x07, 0xde, 0x0a, 0x3e, + 0xeb, 0x5d, 0x7c, 0xc8, 0x7c, 0xfb, 0xb0, 0x2b, 0x53, 0xa4, 0x92, 0x62, + 0x69, 0x51, 0x25, 0x05, 0x61, 0x1a, 0x44, 0x81, 0x8c, 0x2c, 0xa9, 0x43, + 0x96, 0x23, 0xdf, 0xac, 0x3a, 0x81, 0x9a, 0x0e, 0x29, 0xc5, 0x1c, 0xa9, + 0xe9, 0x5d, 0x1e, 0xb6, 0x9e, 0x9e, 0x30, 0x0a, 0x39, 0xce, 0xf1, 0x88, + 0x80, 0xfb, 0x4b, 0x5d, 0xcc, 0x32, 0xec, 0x85, 0x62, 0x43, 0x25, 0x34, + 0x02, 0x56, 0x27, 0x01, 0x91, 0xb4, 0x3b, 0x70, 0x2a, 0x3f, 0x6e, 0xb1, + 0xe8, 0x9c, 0x88, 0x01, 0x7d, 0x9f, 0xd4, 0xf9, 0xdb, 0x53, 0x6d, 0x60, + 0x9d, 0xbf, 0x2c, 0xe7, 0x58, 0xab, 0xb8, 0x5f, 0x46, 0xfc, 0xce, 0xc4, + 0x1b, 0x03, 0x3c, 0x09, 0xeb, 0x49, 0x31, 0x5c, 0x69, 0x46, 0xb3, 0xe0, + 0x47, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x17, 0x30, 0x82, + 0x01, 0x13, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3a, 0x9a, + 0x85, 0x07, 0x10, 0x67, 0x28, 0xb6, 0xef, 0xf6, 0xbd, 0x05, 0x41, 0x6e, + 0x20, 0xc1, 0x94, 0xda, 0x0f, 0xde, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd2, 0xc4, 0xb0, 0xd2, 0x91, + 0xd4, 0x4c, 0x11, 0x71, 0xb3, 0x61, 0xcb, 0x3d, 0xa1, 0xfe, 0xdd, 0xa8, + 0x6a, 0xd4, 0xe3, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, + 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x32, 0x06, + 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, 0x30, 0x27, 0xa0, 0x25, + 0xa0, 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x64, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, + 0x6c, 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, + 0x30, 0x3b, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x33, 0x30, 0x31, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, + 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x59, 0x0b, 0x53, + 0xbd, 0x92, 0x86, 0x11, 0xa7, 0x24, 0x7b, 0xed, 0x5b, 0x31, 0xcf, 0x1d, + 0x1f, 0x6c, 0x70, 0xc5, 0xb8, 0x6e, 0xbe, 0x4e, 0xbb, 0xf6, 0xbe, 0x97, + 0x50, 0xe1, 0x30, 0x7f, 0xba, 0x28, 0x5c, 0x62, 0x94, 0xc2, 0xe3, 0x7e, + 0x33, 0xf7, 0xfb, 0x42, 0x76, 0x85, 0xdb, 0x95, 0x1c, 0x8c, 0x22, 0x58, + 0x75, 0x09, 0x0c, 0x88, 0x65, 0x67, 0x39, 0x0a, 0x16, 0x09, 0xc5, 0xa0, + 0x38, 0x97, 0xa4, 0xc5, 0x23, 0x93, 0x3f, 0xb4, 0x18, 0xa6, 0x01, 0x06, + 0x44, 0x91, 0xe3, 0xa7, 0x69, 0x27, 0xb4, 0x5a, 0x25, 0x7f, 0x3a, 0xb7, + 0x32, 0xcd, 0xdd, 0x84, 0xff, 0x2a, 0x38, 0x29, 0x33, 0xa4, 0xdd, 0x67, + 0xb2, 0x85, 0xfe, 0xa1, 0x88, 0x20, 0x1c, 0x50, 0x89, 0xc8, 0xdc, 0x2a, + 0xf6, 0x42, 0x03, 0x37, 0x4c, 0xe6, 0x88, 0xdf, 0xd5, 0xaf, 0x24, 0xf2, + 0xb1, 0xc3, 0xdf, 0xcc, 0xb5, 0xec, 0xe0, 0x99, 0x5e, 0xb7, 0x49, 0x54, + 0x20, 0x3c, 0x94, 0x18, 0x0c, 0xc7, 0x1c, 0x52, 0x18, 0x49, 0xa4, 0x6d, + 0xe1, 0xb3, 0x58, 0x0b, 0xc9, 0xd8, 0xec, 0xd9, 0xae, 0x1c, 0x32, 0x8e, + 0x28, 0x70, 0x0d, 0xe2, 0xfe, 0xa6, 0x17, 0x9e, 0x84, 0x0f, 0xbd, 0x57, + 0x70, 0xb3, 0x5a, 0xe9, 0x1f, 0xa0, 0x86, 0x53, 0xbb, 0xef, 0x7c, 0xff, + 0x69, 0x0b, 0xe0, 0x48, 0xc3, 0xb7, 0x93, 0x0b, 0xc8, 0x0a, 0x54, 0xc4, + 0xac, 0x5d, 0x14, 0x67, 0x37, 0x6c, 0xca, 0xa5, 0x2f, 0x31, 0x08, 0x37, + 0xaa, 0x6e, 0x6f, 0x8c, 0xbc, 0x9b, 0xe2, 0x57, 0x5d, 0x24, 0x81, 0xaf, + 0x97, 0x97, 0x9c, 0x84, 0xad, 0x6c, 0xac, 0x37, 0x4c, 0x66, 0xf3, 0x61, + 0x91, 0x11, 0x20, 0xe4, 0xbe, 0x30, 0x9f, 0x7a, 0xa4, 0x29, 0x09, 0xb0, + 0xe1, 0x34, 0x5f, 0x64, 0x77, 0x18, 0x40, 0x51, 0xdf, 0x8c, 0x30, 0xa6, + 0xaf, +} + +var certSet3Cert20 = []byte{ + 0x30, 0x82, 0x04, 0x8b, 0x30, 0x82, 0x03, 0x73, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0e, 0x46, 0xf0, 0x8c, 0xdb, 0xcf, 0x2c, 0x54, 0x66, 0xef, + 0x33, 0x01, 0xdd, 0x5f, 0x34, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, + 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, + 0x73, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x38, 0x31, 0x39, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x38, + 0x31, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x57, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, + 0x2d, 0x73, 0x61, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x24, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, + 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, + 0xc0, 0x75, 0xe1, 0x32, 0x98, 0xe5, 0xd9, 0xae, 0x84, 0x7c, 0x8d, 0xe8, + 0x23, 0x5f, 0x46, 0x95, 0x5b, 0x4c, 0xa2, 0x25, 0x70, 0xd7, 0x90, 0x04, + 0x85, 0x80, 0xc9, 0xb5, 0xf4, 0x8a, 0x65, 0x4d, 0x92, 0xcb, 0xa5, 0xc4, + 0x42, 0xa0, 0xb6, 0x79, 0x25, 0x31, 0xed, 0xf1, 0x85, 0x20, 0xcd, 0x13, + 0x51, 0x3d, 0x67, 0xac, 0x97, 0x4d, 0x68, 0x9b, 0x33, 0x86, 0x5c, 0xb3, + 0x7b, 0x2d, 0xaa, 0xdf, 0x77, 0xa0, 0x61, 0xd1, 0xf5, 0x3c, 0xfb, 0x9a, + 0xfc, 0xd3, 0xd5, 0x94, 0xca, 0xc9, 0x1e, 0x80, 0x1b, 0x90, 0x90, 0xc8, + 0xac, 0x8d, 0xf6, 0x60, 0x17, 0x9c, 0x31, 0xb8, 0xc5, 0x61, 0xa2, 0xe2, + 0x6e, 0x57, 0x25, 0x08, 0x6f, 0x24, 0x99, 0x99, 0xcf, 0x94, 0xbf, 0xc7, + 0x8b, 0x6b, 0xb0, 0x1f, 0xca, 0x14, 0xfa, 0x18, 0x9b, 0x6c, 0x10, 0x7c, + 0x99, 0x2b, 0xda, 0x4a, 0x63, 0xe5, 0xb2, 0x4e, 0xc2, 0xfd, 0x3e, 0x10, + 0x0b, 0x48, 0xf4, 0x77, 0x0b, 0x2f, 0xf0, 0x96, 0x4b, 0x3a, 0xee, 0xbd, + 0x35, 0xde, 0x85, 0x8d, 0xda, 0x13, 0x0e, 0xce, 0x01, 0xc4, 0x71, 0xd3, + 0xd3, 0x77, 0xc5, 0x08, 0xa6, 0x60, 0x39, 0x25, 0xa7, 0x27, 0x69, 0x5c, + 0x83, 0xd1, 0x6f, 0x76, 0x78, 0xee, 0xc5, 0x44, 0x5b, 0x45, 0xbd, 0x29, + 0x3b, 0xe2, 0xc6, 0x09, 0x0f, 0xa2, 0xbe, 0x2b, 0xdc, 0xe3, 0x5c, 0xda, + 0x5a, 0x6f, 0x8e, 0xe7, 0xc9, 0x07, 0x6b, 0x7e, 0xa1, 0xc0, 0x53, 0x95, + 0x82, 0x89, 0xe0, 0x78, 0x5c, 0x72, 0xa8, 0x6c, 0xbe, 0x67, 0x6b, 0xab, + 0xe7, 0x33, 0xd9, 0x87, 0xf2, 0xf8, 0x5c, 0x27, 0xf4, 0xf6, 0x2a, 0x3b, + 0x87, 0xef, 0xda, 0xc2, 0x47, 0xda, 0xbf, 0xac, 0xeb, 0x27, 0x64, 0x7b, + 0x4c, 0x53, 0xeb, 0x34, 0xe1, 0x2f, 0x9b, 0x20, 0x4d, 0x54, 0x12, 0x6b, + 0x7d, 0x28, 0xbd, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x53, + 0x30, 0x82, 0x01, 0x4f, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x03, 0x02, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa9, 0x2b, + 0x87, 0xe1, 0xce, 0x24, 0x47, 0x3b, 0x1b, 0xbf, 0xcf, 0x85, 0x37, 0x02, + 0x55, 0x9d, 0x0d, 0x94, 0x58, 0xe6, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x60, 0x7b, 0x66, 0x1a, 0x45, + 0x0d, 0x97, 0xca, 0x89, 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, 0xa8, 0xff, + 0xfc, 0xfd, 0x4b, 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x72, 0x6f, 0x6f, 0x74, 0x72, 0x31, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x56, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4f, 0x30, 0x4d, 0x30, 0x0b, + 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xa0, 0x32, 0x01, 0x14, 0x30, + 0x3e, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x02, 0x30, 0x34, 0x30, + 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, + 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa2, + 0x1d, 0x69, 0x8a, 0x0a, 0x8e, 0xc4, 0x14, 0x83, 0x2a, 0x2a, 0x12, 0x4d, + 0x39, 0x27, 0x90, 0x4e, 0xf0, 0x8d, 0xac, 0xd2, 0x96, 0x62, 0x47, 0x36, + 0x5e, 0x92, 0xd1, 0xfa, 0xc5, 0x93, 0xb5, 0x37, 0x07, 0x65, 0x29, 0xd2, + 0xf4, 0x53, 0x50, 0x6b, 0xc9, 0xf4, 0xfe, 0x34, 0xf5, 0xdd, 0xb8, 0x1d, + 0xfa, 0xfc, 0xdc, 0x14, 0xac, 0x56, 0x94, 0x27, 0x9c, 0x42, 0xaa, 0x04, + 0x4d, 0xb7, 0xed, 0x58, 0xd9, 0x99, 0xd2, 0x49, 0xe6, 0x20, 0x2f, 0xd3, + 0xa7, 0x77, 0xb8, 0x2a, 0x89, 0x1a, 0xef, 0xa7, 0xcf, 0x86, 0x2d, 0xd6, + 0x53, 0xe9, 0x0b, 0x93, 0x9c, 0x4e, 0xab, 0xd9, 0x45, 0xee, 0xa4, 0x84, + 0x85, 0xff, 0x34, 0xe4, 0x0e, 0xc0, 0xbb, 0xa5, 0xce, 0x5f, 0x95, 0x89, + 0x85, 0x70, 0xaa, 0xc1, 0x5d, 0xec, 0xcf, 0x2b, 0xd3, 0xd9, 0x83, 0xdf, + 0x03, 0xca, 0x81, 0xa7, 0x02, 0x32, 0xb7, 0x77, 0x61, 0x10, 0x25, 0x4e, + 0xd9, 0x74, 0xf3, 0xd9, 0x79, 0x82, 0xb5, 0x26, 0x70, 0xb4, 0x52, 0xbc, + 0x8f, 0x33, 0xd7, 0x8a, 0xae, 0x19, 0xd0, 0xfc, 0x92, 0xad, 0x2f, 0xba, + 0x3c, 0xa0, 0x48, 0x58, 0x47, 0x5e, 0xfd, 0x20, 0x56, 0x95, 0x20, 0xc1, + 0x72, 0x1d, 0xab, 0x66, 0x99, 0xa4, 0xd5, 0x78, 0x37, 0x48, 0x1b, 0x9f, + 0xb2, 0x4c, 0x37, 0x67, 0x7a, 0xfd, 0x42, 0xd2, 0xd3, 0x56, 0x9e, 0xd3, + 0x1d, 0x8e, 0xc4, 0x0c, 0x68, 0x96, 0xb6, 0x47, 0x51, 0x10, 0xf7, 0x7b, + 0xeb, 0x15, 0x09, 0x64, 0xf5, 0xf9, 0xf0, 0x63, 0x16, 0x2d, 0x3d, 0xdf, + 0x23, 0x42, 0x3a, 0x93, 0x63, 0xcc, 0xab, 0xaf, 0x4f, 0x57, 0x06, 0xc7, + 0xfe, 0x14, 0x55, 0x62, 0xce, 0x27, 0x11, 0x19, 0xe1, 0xf4, 0x42, 0xed, + 0x22, 0x30, 0x6b, 0x35, 0x1a, 0x4a, 0x05, 0x80, 0xa4, 0x65, 0xdf, 0xcc, + 0xcb, 0x6f, 0xd0, +} + +var certSet3Cert21 = []byte{ + 0x30, 0x82, 0x04, 0x90, 0x30, 0x82, 0x03, 0xf9, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x1b, 0x09, 0x3b, 0x78, 0x60, 0x96, 0xda, 0x37, 0xbb, + 0xa4, 0x51, 0x94, 0x46, 0xc8, 0x96, 0x78, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xca, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3a, 0x30, + 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, 0x63, 0x29, 0x20, + 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, + 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, + 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x45, 0x30, + 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, 0x24, 0x08, 0x08, 0x29, 0x7a, 0x35, + 0x9e, 0x60, 0x0c, 0xaa, 0xe7, 0x4b, 0x3b, 0x4e, 0xdc, 0x7c, 0xbc, 0x3c, + 0x45, 0x1c, 0xbb, 0x2b, 0xe0, 0xfe, 0x29, 0x02, 0xf9, 0x57, 0x08, 0xa3, + 0x64, 0x85, 0x15, 0x27, 0xf5, 0xf1, 0xad, 0xc8, 0x31, 0x89, 0x5d, 0x22, + 0xe8, 0x2a, 0xaa, 0xa6, 0x42, 0xb3, 0x8f, 0xf8, 0xb9, 0x55, 0xb7, 0xb1, + 0xb7, 0x4b, 0xb3, 0xfe, 0x8f, 0x7e, 0x07, 0x57, 0xec, 0xef, 0x43, 0xdb, + 0x66, 0x62, 0x15, 0x61, 0xcf, 0x60, 0x0d, 0xa4, 0xd8, 0xde, 0xf8, 0xe0, + 0xc3, 0x62, 0x08, 0x3d, 0x54, 0x13, 0xeb, 0x49, 0xca, 0x59, 0x54, 0x85, + 0x26, 0xe5, 0x2b, 0x8f, 0x1b, 0x9f, 0xeb, 0xf5, 0xa1, 0x91, 0xc2, 0x33, + 0x49, 0xd8, 0x43, 0x63, 0x6a, 0x52, 0x4b, 0xd2, 0x8f, 0xe8, 0x70, 0x51, + 0x4d, 0xd1, 0x89, 0x69, 0x7b, 0xc7, 0x70, 0xf6, 0xb3, 0xdc, 0x12, 0x74, + 0xdb, 0x7b, 0x5d, 0x4b, 0x56, 0xd3, 0x96, 0xbf, 0x15, 0x77, 0xa1, 0xb0, + 0xf4, 0xa2, 0x25, 0xf2, 0xaf, 0x1c, 0x92, 0x67, 0x18, 0xe5, 0xf4, 0x06, + 0x04, 0xef, 0x90, 0xb9, 0xe4, 0x00, 0xe4, 0xdd, 0x3a, 0xb5, 0x19, 0xff, + 0x02, 0xba, 0xf4, 0x3c, 0xee, 0xe0, 0x8b, 0xeb, 0x37, 0x8b, 0xec, 0xf4, + 0xd7, 0xac, 0xf2, 0xf6, 0xf0, 0x3d, 0xaf, 0xdd, 0x75, 0x91, 0x33, 0x19, + 0x1d, 0x1c, 0x40, 0xcb, 0x74, 0x24, 0x19, 0x21, 0x93, 0xd9, 0x14, 0xfe, + 0xac, 0x2a, 0x52, 0xc7, 0x8f, 0xd5, 0x04, 0x49, 0xe4, 0x8d, 0x63, 0x47, + 0x88, 0x3c, 0x69, 0x83, 0xcb, 0xfe, 0x47, 0xbd, 0x2b, 0x7e, 0x4f, 0xc5, + 0x95, 0xae, 0x0e, 0x9d, 0xd4, 0xd1, 0x43, 0xc0, 0x67, 0x73, 0xe3, 0x14, + 0x08, 0x7e, 0xe5, 0x3f, 0x9f, 0x73, 0xb8, 0x33, 0x0a, 0xcf, 0x5d, 0x3f, + 0x34, 0x87, 0x96, 0x8a, 0xee, 0x53, 0xe8, 0x25, 0x15, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x5b, 0x30, 0x82, 0x01, 0x57, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, + 0x30, 0x28, 0x30, 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, + 0x61, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, + 0x73, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x6d, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, + 0xa1, 0x5d, 0xa0, 0x5b, 0x30, 0x59, 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, + 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, + 0x8f, 0xe5, 0xd3, 0x1a, 0x86, 0xac, 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, + 0x6a, 0xd4, 0x48, 0x18, 0x2c, 0x7b, 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x76, 0x73, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, + 0xa3, 0xcd, 0x7d, 0x1e, 0xf7, 0xc7, 0x75, 0x8d, 0x48, 0xe7, 0x56, 0x34, + 0x4c, 0x00, 0x90, 0x75, 0xa9, 0x51, 0xa5, 0x56, 0xc1, 0x6d, 0xbc, 0xfe, + 0xf5, 0x53, 0x22, 0xe9, 0x98, 0xa2, 0xac, 0x9a, 0x7e, 0x70, 0x1e, 0xb3, + 0x8e, 0x3b, 0x45, 0xe3, 0x86, 0x95, 0x31, 0xda, 0x6d, 0x4c, 0xfb, 0x34, + 0x50, 0x80, 0x96, 0xcd, 0x24, 0xf2, 0x40, 0xdf, 0x04, 0x3f, 0xe2, 0x65, + 0xce, 0x34, 0x22, 0x61, 0x15, 0xea, 0x66, 0x70, 0x64, 0xd2, 0xf1, 0x6e, + 0xf3, 0xca, 0x18, 0x59, 0x6a, 0x41, 0x46, 0x7e, 0x82, 0xde, 0x19, 0xb0, + 0x70, 0x31, 0x56, 0x69, 0x0d, 0x0c, 0xe6, 0x1d, 0x9d, 0x71, 0x58, 0xdc, + 0xcc, 0xde, 0x62, 0xf5, 0xe1, 0x7a, 0x10, 0x02, 0xd8, 0x7a, 0xdc, 0x3b, + 0xfa, 0x57, 0xbd, 0xc9, 0xe9, 0x8f, 0x46, 0x21, 0x39, 0x9f, 0x51, 0x65, + 0x4c, 0x8e, 0x3a, 0xbe, 0x28, 0x41, 0x70, 0x1d, +} + +var certSet3Cert22 = []byte{ + 0x30, 0x82, 0x04, 0x92, 0x30, 0x82, 0x03, 0x7a, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x0a, 0x01, 0x41, 0x42, 0x00, 0x00, 0x01, 0x53, 0x85, + 0x73, 0x6a, 0x0b, 0x85, 0xec, 0xa7, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3f, + 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, 0x44, + 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, + 0x6f, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0e, 0x44, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x58, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x33, 0x31, + 0x37, 0x31, 0x36, 0x34, 0x30, 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x32, 0x31, + 0x30, 0x33, 0x31, 0x37, 0x31, 0x36, 0x34, 0x30, 0x34, 0x36, 0x5a, 0x30, + 0x4a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x4c, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x1a, 0x4c, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x58, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0x9c, 0xd3, 0x0c, 0xf0, 0x5a, 0xe5, 0x2e, 0x47, 0xb7, 0x72, 0x5d, 0x37, + 0x83, 0xb3, 0x68, 0x63, 0x30, 0xea, 0xd7, 0x35, 0x26, 0x19, 0x25, 0xe1, + 0xbd, 0xbe, 0x35, 0xf1, 0x70, 0x92, 0x2f, 0xb7, 0xb8, 0x4b, 0x41, 0x05, + 0xab, 0xa9, 0x9e, 0x35, 0x08, 0x58, 0xec, 0xb1, 0x2a, 0xc4, 0x68, 0x87, + 0x0b, 0xa3, 0xe3, 0x75, 0xe4, 0xe6, 0xf3, 0xa7, 0x62, 0x71, 0xba, 0x79, + 0x81, 0x60, 0x1f, 0xd7, 0x91, 0x9a, 0x9f, 0xf3, 0xd0, 0x78, 0x67, 0x71, + 0xc8, 0x69, 0x0e, 0x95, 0x91, 0xcf, 0xfe, 0xe6, 0x99, 0xe9, 0x60, 0x3c, + 0x48, 0xcc, 0x7e, 0xca, 0x4d, 0x77, 0x12, 0x24, 0x9d, 0x47, 0x1b, 0x5a, + 0xeb, 0xb9, 0xec, 0x1e, 0x37, 0x00, 0x1c, 0x9c, 0xac, 0x7b, 0xa7, 0x05, + 0xea, 0xce, 0x4a, 0xeb, 0xbd, 0x41, 0xe5, 0x36, 0x98, 0xb9, 0xcb, 0xfd, + 0x6d, 0x3c, 0x96, 0x68, 0xdf, 0x23, 0x2a, 0x42, 0x90, 0x0c, 0x86, 0x74, + 0x67, 0xc8, 0x7f, 0xa5, 0x9a, 0xb8, 0x52, 0x61, 0x14, 0x13, 0x3f, 0x65, + 0xe9, 0x82, 0x87, 0xcb, 0xdb, 0xfa, 0x0e, 0x56, 0xf6, 0x86, 0x89, 0xf3, + 0x85, 0x3f, 0x97, 0x86, 0xaf, 0xb0, 0xdc, 0x1a, 0xef, 0x6b, 0x0d, 0x95, + 0x16, 0x7d, 0xc4, 0x2b, 0xa0, 0x65, 0xb2, 0x99, 0x04, 0x36, 0x75, 0x80, + 0x6b, 0xac, 0x4a, 0xf3, 0x1b, 0x90, 0x49, 0x78, 0x2f, 0xa2, 0x96, 0x4f, + 0x2a, 0x20, 0x25, 0x29, 0x04, 0xc6, 0x74, 0xc0, 0xd0, 0x31, 0xcd, 0x8f, + 0x31, 0x38, 0x95, 0x16, 0xba, 0xa8, 0x33, 0xb8, 0x43, 0xf1, 0xb1, 0x1f, + 0xc3, 0x30, 0x7f, 0xa2, 0x79, 0x31, 0x13, 0x3d, 0x2d, 0x36, 0xf8, 0xe3, + 0xfc, 0xf2, 0x33, 0x6a, 0xb9, 0x39, 0x31, 0xc5, 0xaf, 0xc4, 0x8d, 0x0d, + 0x1d, 0x64, 0x16, 0x33, 0xaa, 0xfa, 0x84, 0x29, 0xb6, 0xd4, 0x0b, 0xc0, + 0xd8, 0x7d, 0xc3, 0x93, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x7d, 0x30, 0x82, 0x01, 0x79, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x32, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x26, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x73, 0x72, 0x67, 0x2e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x69, 0x64, 0x2e, 0x6f, 0x63, 0x73, 0x70, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x61, 0x70, + 0x70, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x2f, 0x64, + 0x73, 0x74, 0x72, 0x6f, 0x6f, 0x74, 0x63, 0x61, 0x78, 0x33, 0x2e, 0x70, + 0x37, 0x63, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0xc4, 0xa7, 0xb1, 0xa4, 0x7b, 0x2c, 0x71, 0xfa, 0xdb, + 0xe1, 0x4b, 0x90, 0x75, 0xff, 0xc4, 0x15, 0x60, 0x85, 0x89, 0x10, 0x30, + 0x54, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4d, 0x30, 0x4b, 0x30, 0x08, + 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x01, 0x30, 0x3f, 0x06, 0x0b, + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xdf, 0x13, 0x01, 0x01, 0x01, 0x30, + 0x30, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x01, 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x70, + 0x73, 0x2e, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x78, 0x31, 0x2e, 0x6c, 0x65, + 0x74, 0x73, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2e, 0x6f, 0x72, + 0x67, 0x30, 0x3c, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x35, 0x30, 0x33, + 0x30, 0x31, 0xa0, 0x2f, 0xa0, 0x2d, 0x86, 0x2b, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x53, 0x54, + 0x52, 0x4f, 0x4f, 0x54, 0x43, 0x41, 0x58, 0x33, 0x43, 0x52, 0x4c, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0xa8, 0x4a, 0x6a, 0x63, 0x04, 0x7d, 0xdd, 0xba, 0xe6, 0xd1, + 0x39, 0xb7, 0xa6, 0x45, 0x65, 0xef, 0xf3, 0xa8, 0xec, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xdd, 0x33, 0xd7, 0x11, 0xf3, 0x63, + 0x58, 0x38, 0xdd, 0x18, 0x15, 0xfb, 0x09, 0x55, 0xbe, 0x76, 0x56, 0xb9, + 0x70, 0x48, 0xa5, 0x69, 0x47, 0x27, 0x7b, 0xc2, 0x24, 0x08, 0x92, 0xf1, + 0x5a, 0x1f, 0x4a, 0x12, 0x29, 0x37, 0x24, 0x74, 0x51, 0x1c, 0x62, 0x68, + 0xb8, 0xcd, 0x95, 0x70, 0x67, 0xe5, 0xf7, 0xa4, 0xbc, 0x4e, 0x28, 0x51, + 0xcd, 0x9b, 0xe8, 0xae, 0x87, 0x9d, 0xea, 0xd8, 0xba, 0x5a, 0xa1, 0x01, + 0x9a, 0xdc, 0xf0, 0xdd, 0x6a, 0x1d, 0x6a, 0xd8, 0x3e, 0x57, 0x23, 0x9e, + 0xa6, 0x1e, 0x04, 0x62, 0x9a, 0xff, 0xd7, 0x05, 0xca, 0xb7, 0x1f, 0x3f, + 0xc0, 0x0a, 0x48, 0xbc, 0x94, 0xb0, 0xb6, 0x65, 0x62, 0xe0, 0xc1, 0x54, + 0xe5, 0xa3, 0x2a, 0xad, 0x20, 0xc4, 0xe9, 0xe6, 0xbb, 0xdc, 0xc8, 0xf6, + 0xb5, 0xc3, 0x32, 0xa3, 0x98, 0xcc, 0x77, 0xa8, 0xe6, 0x79, 0x65, 0x07, + 0x2b, 0xcb, 0x28, 0xfe, 0x3a, 0x16, 0x52, 0x81, 0xce, 0x52, 0x0c, 0x2e, + 0x5f, 0x83, 0xe8, 0xd5, 0x06, 0x33, 0xfb, 0x77, 0x6c, 0xce, 0x40, 0xea, + 0x32, 0x9e, 0x1f, 0x92, 0x5c, 0x41, 0xc1, 0x74, 0x6c, 0x5b, 0x5d, 0x0a, + 0x5f, 0x33, 0xcc, 0x4d, 0x9f, 0xac, 0x38, 0xf0, 0x2f, 0x7b, 0x2c, 0x62, + 0x9d, 0xd9, 0xa3, 0x91, 0x6f, 0x25, 0x1b, 0x2f, 0x90, 0xb1, 0x19, 0x46, + 0x3d, 0xf6, 0x7e, 0x1b, 0xa6, 0x7a, 0x87, 0xb9, 0xa3, 0x7a, 0x6d, 0x18, + 0xfa, 0x25, 0xa5, 0x91, 0x87, 0x15, 0xe0, 0xf2, 0x16, 0x2f, 0x58, 0xb0, + 0x06, 0x2f, 0x2c, 0x68, 0x26, 0xc6, 0x4b, 0x98, 0xcd, 0xda, 0x9f, 0x0c, + 0xf9, 0x7f, 0x90, 0xed, 0x43, 0x4a, 0x12, 0x44, 0x4e, 0x6f, 0x73, 0x7a, + 0x28, 0xea, 0xa4, 0xaa, 0x6e, 0x7b, 0x4c, 0x7d, 0x87, 0xdd, 0xe0, 0xc9, + 0x02, 0x44, 0xa7, 0x87, 0xaf, 0xc3, 0x34, 0x5b, 0xb4, 0x42, +} + +var certSet3Cert23 = []byte{ + 0x30, 0x82, 0x04, 0x92, 0x30, 0x82, 0x03, 0x7a, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x13, 0x06, 0x7f, 0x94, 0x4a, 0x2a, 0x27, 0xcd, 0xf3, 0xfa, + 0xc2, 0xae, 0x2b, 0x01, 0xf9, 0x08, 0xee, 0xb9, 0xc4, 0xc6, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, + 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, + 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, + 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x32, 0x53, 0x74, + 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x35, 0x32, 0x35, 0x31, 0x32, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x32, 0x33, + 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x39, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d, + 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xb2, 0x78, 0x80, 0x71, 0xca, 0x78, 0xd5, 0xe3, + 0x71, 0xaf, 0x47, 0x80, 0x50, 0x74, 0x7d, 0x6e, 0xd8, 0xd7, 0x88, 0x76, + 0xf4, 0x99, 0x68, 0xf7, 0x58, 0x21, 0x60, 0xf9, 0x74, 0x84, 0x01, 0x2f, + 0xac, 0x02, 0x2d, 0x86, 0xd3, 0xa0, 0x43, 0x7a, 0x4e, 0xb2, 0xa4, 0xd0, + 0x36, 0xba, 0x01, 0xbe, 0x8d, 0xdb, 0x48, 0xc8, 0x07, 0x17, 0x36, 0x4c, + 0xf4, 0xee, 0x88, 0x23, 0xc7, 0x3e, 0xeb, 0x37, 0xf5, 0xb5, 0x19, 0xf8, + 0x49, 0x68, 0xb0, 0xde, 0xd7, 0xb9, 0x76, 0x38, 0x1d, 0x61, 0x9e, 0xa4, + 0xfe, 0x82, 0x36, 0xa5, 0xe5, 0x4a, 0x56, 0xe4, 0x45, 0xe1, 0xf9, 0xfd, + 0xb4, 0x16, 0xfa, 0x74, 0xda, 0x9c, 0x9b, 0x35, 0x39, 0x2f, 0xfa, 0xb0, + 0x20, 0x50, 0x06, 0x6c, 0x7a, 0xd0, 0x80, 0xb2, 0xa6, 0xf9, 0xaf, 0xec, + 0x47, 0x19, 0x8f, 0x50, 0x38, 0x07, 0xdc, 0xa2, 0x87, 0x39, 0x58, 0xf8, + 0xba, 0xd5, 0xa9, 0xf9, 0x48, 0x67, 0x30, 0x96, 0xee, 0x94, 0x78, 0x5e, + 0x6f, 0x89, 0xa3, 0x51, 0xc0, 0x30, 0x86, 0x66, 0xa1, 0x45, 0x66, 0xba, + 0x54, 0xeb, 0xa3, 0xc3, 0x91, 0xf9, 0x48, 0xdc, 0xff, 0xd1, 0xe8, 0x30, + 0x2d, 0x7d, 0x2d, 0x74, 0x70, 0x35, 0xd7, 0x88, 0x24, 0xf7, 0x9e, 0xc4, + 0x59, 0x6e, 0xbb, 0x73, 0x87, 0x17, 0xf2, 0x32, 0x46, 0x28, 0xb8, 0x43, + 0xfa, 0xb7, 0x1d, 0xaa, 0xca, 0xb4, 0xf2, 0x9f, 0x24, 0x0e, 0x2d, 0x4b, + 0xf7, 0x71, 0x5c, 0x5e, 0x69, 0xff, 0xea, 0x95, 0x02, 0xcb, 0x38, 0x8a, + 0xae, 0x50, 0x38, 0x6f, 0xdb, 0xfb, 0x2d, 0x62, 0x1b, 0xc5, 0xc7, 0x1e, + 0x54, 0xe1, 0x77, 0xe0, 0x67, 0xc8, 0x0f, 0x9c, 0x87, 0x23, 0xd6, 0x3f, + 0x40, 0x20, 0x7f, 0x20, 0x80, 0xc4, 0x80, 0x4c, 0x3e, 0x3b, 0x24, 0x26, + 0x8e, 0x04, 0xae, 0x6c, 0x9a, 0xc8, 0xaa, 0x0d, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0x31, 0x30, 0x82, 0x01, 0x2d, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x84, 0x18, 0xcc, 0x85, 0x34, 0xec, 0xbc, + 0x0c, 0x94, 0x94, 0x2e, 0x08, 0x59, 0x9c, 0xc7, 0xb2, 0x10, 0x4e, 0x0a, + 0x08, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x9c, 0x5f, 0x00, 0xdf, 0xaa, 0x01, 0xd7, 0x30, 0x2b, 0x38, + 0x88, 0xa2, 0xb8, 0x6d, 0x4a, 0x9c, 0xf2, 0x11, 0x91, 0x83, 0x30, 0x78, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x6c, + 0x30, 0x6a, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, + 0x63, 0x73, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x74, 0x67, 0x32, 0x2e, 0x61, + 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x38, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x74, 0x2e, 0x72, 0x6f, 0x6f, 0x74, 0x67, 0x32, 0x2e, 0x61, 0x6d, + 0x61, 0x7a, 0x6f, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x67, 0x32, 0x2e, 0x63, 0x65, 0x72, + 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x36, 0x30, 0x34, 0x30, + 0x32, 0xa0, 0x30, 0xa0, 0x2e, 0x86, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x72, 0x6f, 0x6f, 0x74, 0x67, 0x32, + 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x67, 0x32, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x11, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x0a, + 0x30, 0x08, 0x30, 0x06, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x62, 0x37, 0x42, 0x5c, 0xbc, 0x10, + 0xb5, 0x3e, 0x8b, 0x2c, 0xe9, 0x0c, 0x9b, 0x6c, 0x45, 0xe2, 0x07, 0x00, + 0x7a, 0xf9, 0xc5, 0x58, 0x0b, 0xb9, 0x08, 0x8c, 0x3e, 0xed, 0xb3, 0x25, + 0x3c, 0xb5, 0x6f, 0x50, 0xe4, 0xcd, 0x35, 0x6a, 0xa7, 0x93, 0x34, 0x96, + 0x32, 0x21, 0xa9, 0x48, 0x44, 0xab, 0x9c, 0xed, 0x3d, 0xb4, 0xaa, 0x73, + 0x6d, 0xe4, 0x7f, 0x16, 0x80, 0x89, 0x6c, 0xcf, 0x28, 0x03, 0x18, 0x83, + 0x47, 0x79, 0xa3, 0x10, 0x7e, 0x30, 0x5b, 0xac, 0x3b, 0xb0, 0x60, 0xe0, + 0x77, 0xd4, 0x08, 0xa6, 0xe1, 0x1d, 0x7c, 0x5e, 0xc0, 0xbb, 0xf9, 0x9a, + 0x7b, 0x22, 0x9d, 0xa7, 0x00, 0x09, 0x7e, 0xac, 0x46, 0x17, 0x83, 0xdc, + 0x9c, 0x26, 0x57, 0x99, 0x30, 0x39, 0x62, 0x96, 0x8f, 0xed, 0xda, 0xde, + 0xaa, 0xc5, 0xcc, 0x1b, 0x3e, 0xca, 0x43, 0x68, 0x6c, 0x57, 0x16, 0xbc, + 0xd5, 0x0e, 0x20, 0x2e, 0xfe, 0xff, 0xc2, 0x6a, 0x5d, 0x2e, 0xa0, 0x4a, + 0x6d, 0x14, 0x58, 0x87, 0x94, 0xe6, 0x39, 0x31, 0x5f, 0x7c, 0x73, 0xcb, + 0x90, 0x88, 0x6a, 0x84, 0x11, 0x96, 0x27, 0xa6, 0xed, 0xd9, 0x81, 0x46, + 0xa6, 0x7e, 0xa3, 0x72, 0x00, 0x0a, 0x52, 0x3e, 0x83, 0x88, 0x07, 0x63, + 0x77, 0x89, 0x69, 0x17, 0x0f, 0x39, 0x85, 0xd2, 0xab, 0x08, 0x45, 0x4d, + 0xd0, 0x51, 0x3a, 0xfd, 0x5d, 0x5d, 0x37, 0x64, 0x4c, 0x7e, 0x30, 0xb2, + 0x55, 0x24, 0x42, 0x9d, 0x36, 0xb0, 0x5d, 0x9c, 0x17, 0x81, 0x61, 0xf1, + 0xca, 0xf9, 0x10, 0x02, 0x24, 0xab, 0xeb, 0x0d, 0x74, 0x91, 0x8d, 0x7b, + 0x45, 0x29, 0x50, 0x39, 0x88, 0xb2, 0xa6, 0x89, 0x35, 0x25, 0x1e, 0x14, + 0x6a, 0x47, 0x23, 0x31, 0x2f, 0x5c, 0x9a, 0xfa, 0xad, 0x9a, 0x0e, 0x62, + 0x51, 0xa4, 0x2a, 0xa9, 0xc4, 0xf9, 0x34, 0x9d, 0x21, 0x18, +} + +var certSet3Cert24 = []byte{ + 0x30, 0x82, 0x04, 0x94, 0x30, 0x82, 0x03, 0x7c, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x01, 0xfd, 0xa3, 0xeb, 0x6e, 0xca, 0x75, 0xc8, 0x88, + 0x43, 0x8b, 0x72, 0x4b, 0xcf, 0xbc, 0x91, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x61, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x30, 0x38, 0x31, + 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x33, + 0x30, 0x38, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4d, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, + 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, + 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x48, 0x41, 0x32, 0x20, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xdc, 0xae, 0x58, 0x90, 0x4d, 0xc1, 0xc4, 0x30, 0x15, 0x90, 0x35, + 0x5b, 0x6e, 0x3c, 0x82, 0x15, 0xf5, 0x2c, 0x5c, 0xbd, 0xe3, 0xdb, 0xff, + 0x71, 0x43, 0xfa, 0x64, 0x25, 0x80, 0xd4, 0xee, 0x18, 0xa2, 0x4d, 0xf0, + 0x66, 0xd0, 0x0a, 0x73, 0x6e, 0x11, 0x98, 0x36, 0x17, 0x64, 0xaf, 0x37, + 0x9d, 0xfd, 0xfa, 0x41, 0x84, 0xaf, 0xc7, 0xaf, 0x8c, 0xfe, 0x1a, 0x73, + 0x4d, 0xcf, 0x33, 0x97, 0x90, 0xa2, 0x96, 0x87, 0x53, 0x83, 0x2b, 0xb9, + 0xa6, 0x75, 0x48, 0x2d, 0x1d, 0x56, 0x37, 0x7b, 0xda, 0x31, 0x32, 0x1a, + 0xd7, 0xac, 0xab, 0x06, 0xf4, 0xaa, 0x5d, 0x4b, 0xb7, 0x47, 0x46, 0xdd, + 0x2a, 0x93, 0xc3, 0x90, 0x2e, 0x79, 0x80, 0x80, 0xef, 0x13, 0x04, 0x6a, + 0x14, 0x3b, 0xb5, 0x9b, 0x92, 0xbe, 0xc2, 0x07, 0x65, 0x4e, 0xfc, 0xda, + 0xfc, 0xff, 0x7a, 0xae, 0xdc, 0x5c, 0x7e, 0x55, 0x31, 0x0c, 0xe8, 0x39, + 0x07, 0xa4, 0xd7, 0xbe, 0x2f, 0xd3, 0x0b, 0x6a, 0xd2, 0xb1, 0xdf, 0x5f, + 0xfe, 0x57, 0x74, 0x53, 0x3b, 0x35, 0x80, 0xdd, 0xae, 0x8e, 0x44, 0x98, + 0xb3, 0x9f, 0x0e, 0xd3, 0xda, 0xe0, 0xd7, 0xf4, 0x6b, 0x29, 0xab, 0x44, + 0xa7, 0x4b, 0x58, 0x84, 0x6d, 0x92, 0x4b, 0x81, 0xc3, 0xda, 0x73, 0x8b, + 0x12, 0x97, 0x48, 0x90, 0x04, 0x45, 0x75, 0x1a, 0xdd, 0x37, 0x31, 0x97, + 0x92, 0xe8, 0xcd, 0x54, 0x0d, 0x3b, 0xe4, 0xc1, 0x3f, 0x39, 0x5e, 0x2e, + 0xb8, 0xf3, 0x5c, 0x7e, 0x10, 0x8e, 0x86, 0x41, 0x00, 0x8d, 0x45, 0x66, + 0x47, 0xb0, 0xa1, 0x65, 0xce, 0xa0, 0xaa, 0x29, 0x09, 0x4e, 0xf3, 0x97, + 0xeb, 0xe8, 0x2e, 0xab, 0x0f, 0x72, 0xa7, 0x30, 0x0e, 0xfa, 0xc7, 0xf4, + 0xfd, 0x14, 0x77, 0xc3, 0xa4, 0x5b, 0x28, 0x57, 0xc2, 0xb3, 0xf9, 0x82, + 0xfd, 0xb7, 0x45, 0x58, 0x9b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x5a, 0x30, 0x82, 0x01, 0x56, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, + 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x7b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, + 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, + 0x43, 0x65, 0x72, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, + 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x37, 0xa0, 0x35, + 0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, + 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43, + 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, + 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, + 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x0f, 0x80, 0x61, 0x1c, 0x82, + 0x31, 0x61, 0xd5, 0x2f, 0x28, 0xe7, 0x8d, 0x46, 0x38, 0xb4, 0x2c, 0xe1, + 0xc6, 0xd9, 0xe2, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, + 0x30, 0x16, 0x80, 0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, + 0x66, 0xf0, 0xa3, 0xe2, 0x1b, 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x23, 0x3e, 0xdf, 0x4b, + 0xd2, 0x31, 0x42, 0xa5, 0xb6, 0x7e, 0x42, 0x5c, 0x1a, 0x44, 0xcc, 0x69, + 0xd1, 0x68, 0xb4, 0x5d, 0x4b, 0xe0, 0x04, 0x21, 0x6c, 0x4b, 0xe2, 0x6d, + 0xcc, 0xb1, 0xe0, 0x97, 0x8f, 0xa6, 0x53, 0x09, 0xcd, 0xaa, 0x2a, 0x65, + 0xe5, 0x39, 0x4f, 0x1e, 0x83, 0xa5, 0x6e, 0x5c, 0x98, 0xa2, 0x24, 0x26, + 0xe6, 0xfb, 0xa1, 0xed, 0x93, 0xc7, 0x2e, 0x02, 0xc6, 0x4d, 0x4a, 0xbf, + 0xb0, 0x42, 0xdf, 0x78, 0xda, 0xb3, 0xa8, 0xf9, 0x6d, 0xff, 0x21, 0x85, + 0x53, 0x36, 0x60, 0x4c, 0x76, 0xce, 0xec, 0x38, 0xdc, 0xd6, 0x51, 0x80, + 0xf0, 0xc5, 0xd6, 0xe5, 0xd4, 0x4d, 0x27, 0x64, 0xab, 0x9b, 0xc7, 0x3e, + 0x71, 0xfb, 0x48, 0x97, 0xb8, 0x33, 0x6d, 0xc9, 0x13, 0x07, 0xee, 0x96, + 0xa2, 0x1b, 0x18, 0x15, 0xf6, 0x5c, 0x4c, 0x40, 0xed, 0xb3, 0xc2, 0xec, + 0xff, 0x71, 0xc1, 0xe3, 0x47, 0xff, 0xd4, 0xb9, 0x00, 0xb4, 0x37, 0x42, + 0xda, 0x20, 0xc9, 0xea, 0x6e, 0x8a, 0xee, 0x14, 0x06, 0xae, 0x7d, 0xa2, + 0x59, 0x98, 0x88, 0xa8, 0x1b, 0x6f, 0x2d, 0xf4, 0xf2, 0xc9, 0x14, 0x5f, + 0x26, 0xcf, 0x2c, 0x8d, 0x7e, 0xed, 0x37, 0xc0, 0xa9, 0xd5, 0x39, 0xb9, + 0x82, 0xbf, 0x19, 0x0c, 0xea, 0x34, 0xaf, 0x00, 0x21, 0x68, 0xf8, 0xad, + 0x73, 0xe2, 0xc9, 0x32, 0xda, 0x38, 0x25, 0x0b, 0x55, 0xd3, 0x9a, 0x1d, + 0xf0, 0x68, 0x86, 0xed, 0x2e, 0x41, 0x34, 0xef, 0x7c, 0xa5, 0x50, 0x1d, + 0xbf, 0x3a, 0xf9, 0xd3, 0xc1, 0x08, 0x0c, 0xe6, 0xed, 0x1e, 0x8a, 0x58, + 0x25, 0xe4, 0xb8, 0x77, 0xad, 0x2d, 0x6e, 0xf5, 0x52, 0xdd, 0xb4, 0x74, + 0x8f, 0xab, 0x49, 0x2e, 0x9d, 0x3b, 0x93, 0x34, 0x28, 0x1f, 0x78, 0xce, + 0x94, 0xea, 0xc7, 0xbd, 0xd3, 0xc9, 0x6d, 0x1c, 0xde, 0x5c, 0x32, 0xf3, +} + +var certSet3Cert25 = []byte{ + 0x30, 0x82, 0x04, 0xa0, 0x30, 0x82, 0x03, 0x88, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x03, 0x39, 0x14, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x68, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, + 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x34, 0x30, 0x31, 0x30, 0x31, 0x30, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x17, 0x0d, 0x33, 0x31, 0x30, 0x35, 0x33, 0x30, 0x30, 0x37, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x30, 0x81, 0x8f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, + 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, + 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, + 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, + 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, + 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, + 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xbd, 0xed, 0xc1, 0x03, 0xfc, 0xf6, 0x8f, 0xfc, 0x02, 0xb1, + 0x6f, 0x5b, 0x9f, 0x48, 0xd9, 0x9d, 0x79, 0xe2, 0xa2, 0xb7, 0x03, 0x61, + 0x56, 0x18, 0xc3, 0x47, 0xb6, 0xd7, 0xca, 0x3d, 0x35, 0x2e, 0x89, 0x43, + 0xf7, 0xa1, 0x69, 0x9b, 0xde, 0x8a, 0x1a, 0xfd, 0x13, 0x20, 0x9c, 0xb4, + 0x49, 0x77, 0x32, 0x29, 0x56, 0xfd, 0xb9, 0xec, 0x8c, 0xdd, 0x22, 0xfa, + 0x72, 0xdc, 0x27, 0x61, 0x97, 0xee, 0xf6, 0x5a, 0x84, 0xec, 0x6e, 0x19, + 0xb9, 0x89, 0x2c, 0xdc, 0x84, 0x5b, 0xd5, 0x74, 0xfb, 0x6b, 0x5f, 0xc5, + 0x89, 0xa5, 0x10, 0x52, 0x89, 0x46, 0x55, 0xf4, 0xb8, 0x75, 0x1c, 0xe6, + 0x7f, 0xe4, 0x54, 0xae, 0x4b, 0xf8, 0x55, 0x72, 0x57, 0x02, 0x19, 0xf8, + 0x17, 0x71, 0x59, 0xeb, 0x1e, 0x28, 0x07, 0x74, 0xc5, 0x9d, 0x48, 0xbe, + 0x6c, 0xb4, 0xf4, 0xa4, 0xb0, 0xf3, 0x64, 0x37, 0x79, 0x92, 0xc0, 0xec, + 0x46, 0x5e, 0x7f, 0xe1, 0x6d, 0x53, 0x4c, 0x62, 0xaf, 0xcd, 0x1f, 0x0b, + 0x63, 0xbb, 0x3a, 0x9d, 0xfb, 0xfc, 0x79, 0x00, 0x98, 0x61, 0x74, 0xcf, + 0x26, 0x82, 0x40, 0x63, 0xf3, 0xb2, 0x72, 0x6a, 0x19, 0x0d, 0x99, 0xca, + 0xd4, 0x0e, 0x75, 0xcc, 0x37, 0xfb, 0x8b, 0x89, 0xc1, 0x59, 0xf1, 0x62, + 0x7f, 0x5f, 0xb3, 0x5f, 0x65, 0x30, 0xf8, 0xa7, 0xb7, 0x4d, 0x76, 0x5a, + 0x1e, 0x76, 0x5e, 0x34, 0xc0, 0xe8, 0x96, 0x56, 0x99, 0x8a, 0xb3, 0xf0, + 0x7f, 0xa4, 0xcd, 0xbd, 0xdc, 0x32, 0x31, 0x7c, 0x91, 0xcf, 0xe0, 0x5f, + 0x11, 0xf8, 0x6b, 0xaa, 0x49, 0x5c, 0xd1, 0x99, 0x94, 0xd1, 0xa2, 0xe3, + 0x63, 0x5b, 0x09, 0x76, 0xb5, 0x56, 0x62, 0xe1, 0x4b, 0x74, 0x1d, 0x96, + 0xd4, 0x26, 0xd4, 0x08, 0x04, 0x59, 0xd0, 0x98, 0x0e, 0x0e, 0xe6, 0xde, + 0xfc, 0xc3, 0xec, 0x1f, 0x90, 0xf1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x82, 0x01, 0x29, 0x30, 0x82, 0x01, 0x25, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x7c, 0x0c, 0x32, 0x1f, 0xa7, 0xd9, 0x30, 0x7f, 0xc4, + 0x7d, 0x68, 0xa3, 0x62, 0xa8, 0xa1, 0xce, 0xab, 0x07, 0x5b, 0x27, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0xbf, 0x5f, 0xb7, 0xd1, 0xce, 0xdd, 0x1f, 0x86, 0xf4, 0x5b, 0x55, 0xac, + 0xdc, 0xd7, 0x10, 0xc2, 0x0e, 0xa9, 0x88, 0xe7, 0x30, 0x3a, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2e, 0x30, 0x2c, + 0x30, 0x2a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, + 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x38, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0xa0, 0x2b, 0xa0, + 0x29, 0x86, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, + 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x72, 0x6f, + 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, 0x04, 0x55, 0x1d, 0x20, + 0x00, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x63, 0xc1, 0xd9, + 0xdd, 0xb9, 0xff, 0xa9, 0xbd, 0xa6, 0x19, 0xdc, 0xbf, 0x13, 0x3a, 0x11, + 0x38, 0x22, 0x54, 0xb1, 0xac, 0x05, 0x10, 0xfb, 0x7c, 0xb3, 0x96, 0x3f, + 0x31, 0x8b, 0x66, 0xff, 0x88, 0xf3, 0xe1, 0xbf, 0xfb, 0xc7, 0x1f, 0x00, + 0xff, 0x46, 0x6a, 0x8b, 0x61, 0x32, 0xc9, 0x01, 0x51, 0x76, 0xfb, 0x9a, + 0xc6, 0xfa, 0x20, 0x51, 0xc8, 0x46, 0xc4, 0x98, 0xd7, 0x79, 0xa3, 0xe3, + 0x04, 0x72, 0x3f, 0x8b, 0x4d, 0x34, 0x53, 0x67, 0xec, 0x33, 0x2c, 0x7b, + 0xe8, 0x94, 0x01, 0x28, 0x7c, 0x3a, 0x34, 0x5b, 0x02, 0x77, 0x16, 0x8d, + 0x40, 0x25, 0x33, 0xb0, 0xbc, 0x6c, 0x97, 0xd7, 0x05, 0x7a, 0xff, 0x8c, + 0x85, 0xce, 0x6f, 0xa0, 0x53, 0x00, 0x17, 0x6e, 0x1e, 0x6c, 0xbd, 0x22, + 0xd7, 0x0a, 0x88, 0x37, 0xf6, 0x7d, 0xeb, 0x99, 0x41, 0xef, 0x27, 0xcb, + 0x8c, 0x60, 0x6b, 0x4c, 0x01, 0x7e, 0x65, 0x50, 0x0b, 0x4f, 0xb8, 0x95, + 0x9a, 0x9a, 0x6e, 0x34, 0xfd, 0x73, 0x3a, 0x33, 0xf1, 0x91, 0xd5, 0xf3, + 0x4e, 0x2d, 0x74, 0xe8, 0xef, 0xd3, 0x90, 0x35, 0xf1, 0x06, 0x68, 0x64, + 0xd4, 0xd0, 0x13, 0xfd, 0x52, 0xd3, 0xc6, 0x6d, 0xc1, 0x3a, 0x8a, 0x31, + 0xdd, 0x05, 0x26, 0x35, 0x4a, 0x8c, 0x65, 0xb8, 0x52, 0x6b, 0x81, 0xec, + 0xd2, 0x9c, 0xb5, 0x34, 0x10, 0x97, 0x9c, 0x3e, 0xc6, 0x2f, 0xed, 0x8e, + 0x42, 0x42, 0x24, 0x2e, 0xe9, 0x73, 0x9a, 0x25, 0xf9, 0x11, 0xf1, 0xf2, + 0x23, 0x69, 0xcb, 0xe5, 0x94, 0x69, 0xa0, 0xd2, 0xdc, 0xb0, 0xfc, 0x44, + 0x89, 0xac, 0x17, 0xa8, 0xcc, 0xd5, 0x37, 0x77, 0x16, 0xc5, 0x80, 0xb9, + 0x0c, 0x8f, 0x57, 0x02, 0x55, 0x99, 0x85, 0x7b, 0x49, 0xf0, 0x2e, 0x5b, + 0xa0, 0xc2, 0x57, 0x53, 0x5d, 0xa2, 0xe8, 0xa6, 0x37, 0xc3, 0x01, 0xfa, +} + +var certSet3Cert26 = []byte{ + 0x30, 0x82, 0x04, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x28, 0x1c, 0x89, 0x29, 0x66, 0x14, 0x43, 0x80, 0x42, + 0x63, 0x55, 0x3a, 0x32, 0x40, 0xae, 0xb3, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x35, 0x30, 0x36, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x36, 0x32, 0x39, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, 0x69, 0x64, + 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xc0, 0x9e, 0x3a, 0x0f, 0x9a, 0xb2, 0xba, 0xd3, 0xd2, + 0xdc, 0x15, 0xec, 0xd0, 0x30, 0x54, 0x59, 0x30, 0x4d, 0x40, 0x51, 0xae, + 0x42, 0x71, 0x71, 0xd2, 0x8d, 0x53, 0x73, 0x81, 0xfe, 0xb8, 0xe0, 0xc4, + 0x96, 0xc5, 0x8e, 0x7e, 0xc2, 0xf1, 0xb7, 0x63, 0x4a, 0xcf, 0xa7, 0x1e, + 0x3f, 0xa8, 0xe7, 0xce, 0x53, 0xa0, 0xfa, 0x2d, 0xf7, 0xd6, 0xe6, 0xce, + 0x70, 0x11, 0xa6, 0xee, 0xe1, 0x03, 0x52, 0xd2, 0x68, 0xde, 0x3d, 0x08, + 0x0d, 0x87, 0xfd, 0x1c, 0xd7, 0x0b, 0x97, 0x62, 0x6d, 0x82, 0x30, 0x76, + 0x1b, 0x47, 0x3a, 0xc4, 0xf7, 0xce, 0xed, 0x1d, 0x7c, 0x8c, 0xb7, 0x17, + 0x8e, 0x53, 0x80, 0x1e, 0x1d, 0x0f, 0x5d, 0x8c, 0xf9, 0x90, 0xe4, 0x04, + 0x1e, 0x02, 0x7e, 0xcb, 0xb0, 0x49, 0xef, 0xda, 0x52, 0x25, 0xfb, 0xfb, + 0x67, 0xed, 0xdd, 0x84, 0x74, 0x59, 0x84, 0x0e, 0xf3, 0xde, 0x70, 0x66, + 0x8d, 0xe4, 0x52, 0x38, 0xf7, 0x53, 0x5a, 0x37, 0x13, 0x67, 0x0b, 0x3e, + 0xbb, 0xa8, 0x58, 0xb7, 0x2e, 0xed, 0xff, 0xb7, 0x5e, 0x11, 0x73, 0xb9, + 0x77, 0x45, 0x52, 0x67, 0x46, 0xae, 0xc4, 0xdc, 0x24, 0x81, 0x89, 0x76, + 0x0a, 0xca, 0xa1, 0x6c, 0x66, 0x73, 0x04, 0x82, 0xaa, 0xf5, 0x70, 0x6c, + 0x5f, 0x1b, 0x9a, 0x00, 0x79, 0x46, 0xd6, 0x7f, 0x7a, 0x26, 0x17, 0x30, + 0xcf, 0x39, 0x4b, 0x2c, 0x74, 0xd9, 0x89, 0x44, 0x76, 0x10, 0xd0, 0xed, + 0xf7, 0x8b, 0xbb, 0x89, 0x05, 0x75, 0x4d, 0x0b, 0x0d, 0xb3, 0xda, 0xe9, + 0xbf, 0xf1, 0x6a, 0x7d, 0x2a, 0x11, 0xdb, 0x1e, 0x9f, 0x8c, 0xe3, 0xc4, + 0x06, 0x69, 0xe1, 0x1d, 0x88, 0x45, 0x39, 0xd1, 0x6e, 0x55, 0xd8, 0xaa, + 0xb7, 0x9b, 0x6f, 0xea, 0xf4, 0xde, 0xac, 0x17, 0x11, 0x92, 0x5d, 0x40, + 0x9b, 0x83, 0x7b, 0x9a, 0xe2, 0xf7, 0xa9, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x3a, 0x30, 0x82, 0x01, 0x36, 0x30, 0x2e, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, + 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x49, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x42, 0x30, 0x40, 0x30, 0x3e, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, + 0x01, 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x36, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, + 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x50, 0x43, 0x41, 0x2d, 0x47, 0x33, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0xf3, 0xb5, 0x56, 0x0c, 0xc4, 0x09, 0xb0, 0xb4, 0xcf, 0x1f, 0xaa, + 0xf9, 0xdd, 0x23, 0x56, 0xf0, 0x77, 0xe8, 0xa1, 0xf9, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc4, 0x79, + 0xca, 0x8e, 0xa1, 0x4e, 0x03, 0x1d, 0x1c, 0xdc, 0x6b, 0xdb, 0x31, 0x5b, + 0x94, 0x3e, 0x3f, 0x30, 0x7f, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0xc3, 0x7e, 0xd8, 0x83, 0x4b, 0x04, 0x4c, 0x55, 0x29, 0x2a, + 0x4f, 0x14, 0x9d, 0x9a, 0x6e, 0xde, 0x90, 0x70, 0xc1, 0xa4, 0x26, 0x4c, + 0x88, 0x8e, 0x78, 0x48, 0xef, 0xbd, 0x9c, 0xb0, 0xa0, 0xf5, 0xf0, 0x66, + 0xfc, 0xfe, 0x59, 0x26, 0xe1, 0x79, 0xef, 0xc8, 0xb7, 0x60, 0x64, 0xa8, + 0x8b, 0x47, 0xea, 0x2f, 0xe0, 0x83, 0x99, 0xda, 0x41, 0x19, 0xd7, 0xc5, + 0xbe, 0x05, 0xfa, 0xf2, 0x90, 0x11, 0xf0, 0x0a, 0xff, 0x6c, 0xdc, 0x05, + 0xb4, 0xd8, 0x06, 0x6f, 0xa4, 0x6f, 0x8d, 0xbe, 0x20, 0x2b, 0x54, 0xdb, + 0xf9, 0xa2, 0x45, 0x83, 0x9a, 0x1e, 0xa5, 0x21, 0x89, 0x35, 0x1d, 0x7c, + 0x20, 0x5c, 0x17, 0xfd, 0x04, 0x2e, 0x45, 0xd8, 0xb2, 0xc6, 0xf8, 0x42, + 0x99, 0xfc, 0x54, 0x08, 0x4e, 0x4b, 0x80, 0x5f, 0x39, 0x37, 0xba, 0x95, + 0x4e, 0xa6, 0x37, 0x0a, 0x9e, 0x93, 0x5e, 0x87, 0x5b, 0xe9, 0x90, 0xd6, + 0xa8, 0xb6, 0x65, 0x08, 0x8d, 0x61, 0x49, 0xeb, 0x83, 0x20, 0xa9, 0x5d, + 0x1b, 0x16, 0x60, 0x62, 0x6b, 0x2f, 0x54, 0xfb, 0x5a, 0x02, 0x0d, 0x7a, + 0x27, 0xe2, 0x4b, 0xe1, 0x05, 0x14, 0xc2, 0xe4, 0xe9, 0xf9, 0x70, 0xc0, + 0xd9, 0xf7, 0x34, 0x65, 0x0e, 0xa2, 0x91, 0x4b, 0xac, 0x28, 0xf2, 0xb7, + 0x08, 0x0f, 0x98, 0xca, 0xd7, 0x3e, 0x70, 0xb6, 0xc8, 0x0b, 0xf1, 0x8b, + 0x9c, 0x51, 0xf8, 0xc6, 0x10, 0x6c, 0xd2, 0x53, 0x4f, 0x62, 0x8c, 0x11, + 0x00, 0x3e, 0x88, 0xdf, 0xbf, 0xe6, 0xd2, 0xcc, 0x70, 0xbd, 0xed, 0x25, + 0x9c, 0xfb, 0xdd, 0x24, 0x0a, 0xbd, 0x59, 0x91, 0x4a, 0x42, 0x03, 0x38, + 0x12, 0x71, 0x32, 0x88, 0x76, 0xa0, 0x8e, 0x7c, 0xbb, 0x32, 0xef, 0x88, + 0x2a, 0x1b, 0xd4, 0x6a, 0x6f, 0x50, 0xb9, 0x52, 0x67, 0x8b, 0xab, 0x30, + 0xfa, 0x1f, 0xfd, 0xe3, 0x24, 0x9a, +} + +var certSet3Cert27 = []byte{ + 0x30, 0x82, 0x04, 0xa8, 0x30, 0x82, 0x03, 0x90, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x11, 0x00, 0xe4, 0x05, 0x47, 0x83, 0x0e, 0x0c, 0x64, 0x52, + 0x97, 0x6f, 0x7a, 0x35, 0x49, 0xc0, 0xdd, 0x48, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x50, 0x4c, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x19, 0x55, 0x6e, 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, + 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x53, 0x2e, + 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x1e, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x22, 0x30, 0x20, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x35, 0x30, 0x31, 0x32, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x17, 0x0d, 0x32, 0x35, 0x30, 0x31, 0x31, 0x38, 0x31, 0x32, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x52, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x59, 0x61, 0x6e, 0x64, 0x65, 0x78, 0x20, + 0x4c, 0x4c, 0x43, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x1e, 0x59, 0x61, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x59, 0x61, 0x6e, 0x64, 0x65, + 0x78, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xa6, 0x05, 0x24, 0x76, 0x61, 0xb9, 0x9e, 0x42, 0x60, 0x22, 0x63, + 0x85, 0x59, 0xe5, 0x9d, 0x88, 0x0d, 0xdf, 0xef, 0x21, 0x64, 0x5a, 0x26, + 0x94, 0x71, 0x3a, 0xa4, 0x7f, 0x2b, 0x53, 0xc3, 0xac, 0x7b, 0xba, 0x95, + 0x42, 0x6d, 0x6a, 0x5b, 0xd6, 0x7e, 0x78, 0x0c, 0x67, 0x40, 0x98, 0x2f, + 0x6a, 0x2d, 0xd0, 0xb7, 0x18, 0x3a, 0x7e, 0x99, 0x60, 0x01, 0xe5, 0x27, + 0xbf, 0xff, 0x49, 0xf5, 0xcd, 0xc4, 0x58, 0xc3, 0x4c, 0xe1, 0x70, 0xd5, + 0xfd, 0x08, 0xa8, 0x79, 0x95, 0x76, 0x1c, 0x0e, 0x05, 0x41, 0xfa, 0xbd, + 0x80, 0x38, 0x2a, 0x87, 0x4f, 0xc1, 0x67, 0x42, 0xaa, 0x17, 0xa6, 0xee, + 0xa7, 0x8c, 0x8e, 0xef, 0x2d, 0x7f, 0x7a, 0x1d, 0x05, 0x17, 0x8f, 0x7e, + 0x3b, 0x92, 0x35, 0xf5, 0x68, 0xed, 0x93, 0x03, 0x55, 0x23, 0x4f, 0x4b, + 0xa2, 0x00, 0x86, 0x65, 0x91, 0x0f, 0xeb, 0xf6, 0x3c, 0xd5, 0xdb, 0x6d, + 0x0e, 0xed, 0xe8, 0x7c, 0x3a, 0xc8, 0xba, 0xb7, 0x53, 0xc1, 0xa4, 0xd8, + 0x40, 0x02, 0xe5, 0xb5, 0xa2, 0xca, 0xbf, 0xda, 0x9c, 0x94, 0x0d, 0xfc, + 0xc5, 0x1c, 0x2a, 0x59, 0x88, 0x62, 0x57, 0x93, 0x2e, 0x11, 0xf0, 0x38, + 0x2c, 0x7a, 0x81, 0x2a, 0xf2, 0x25, 0x15, 0x17, 0x35, 0x70, 0x2c, 0x4b, + 0xf7, 0x23, 0x4c, 0x82, 0xef, 0x33, 0x9f, 0xc2, 0x9a, 0x0b, 0xa3, 0xe2, + 0x5d, 0x6b, 0x38, 0x77, 0xf9, 0x60, 0x33, 0xcf, 0x2e, 0x7b, 0x56, 0xb7, + 0x13, 0x93, 0x1f, 0x34, 0x97, 0x71, 0x99, 0x76, 0x02, 0x46, 0x35, 0x14, + 0x7c, 0xdc, 0xca, 0x48, 0x8a, 0x0a, 0x72, 0x4b, 0x78, 0x6d, 0x82, 0x34, + 0x96, 0x13, 0x45, 0xcf, 0x02, 0x2f, 0x50, 0x13, 0x39, 0x43, 0x89, 0xc0, + 0xe1, 0x74, 0xd7, 0x28, 0x71, 0x21, 0xe5, 0xaa, 0x97, 0x0e, 0xee, 0x46, + 0xec, 0x93, 0xf7, 0x23, 0x7d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x3e, 0x30, 0x82, 0x01, 0x3a, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x37, 0x5c, + 0xe3, 0x19, 0xe0, 0xb2, 0x8e, 0xa1, 0xa8, 0x4e, 0xd2, 0xcf, 0xab, 0xd0, + 0xdc, 0xe3, 0x0b, 0x5c, 0x35, 0x4d, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x08, 0x76, 0xcd, 0xcb, 0x07, + 0xff, 0x24, 0xf6, 0xc5, 0xcd, 0xed, 0xbb, 0x90, 0xbc, 0xe2, 0x84, 0x37, + 0x46, 0x75, 0xf7, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2f, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0xa0, 0x22, 0xa0, 0x20, + 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x2e, 0x63, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x2e, 0x70, 0x6c, 0x2f, 0x63, + 0x74, 0x6e, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x6b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5f, 0x30, 0x5d, + 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x75, 0x62, + 0x63, 0x61, 0x2e, 0x6f, 0x63, 0x73, 0x70, 0x2d, 0x63, 0x65, 0x72, 0x74, + 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x31, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x2e, 0x70, 0x6c, 0x2f, + 0x63, 0x74, 0x6e, 0x63, 0x61, 0x2e, 0x63, 0x65, 0x72, 0x30, 0x39, 0x06, + 0x03, 0x55, 0x1d, 0x20, 0x04, 0x32, 0x30, 0x30, 0x30, 0x2e, 0x06, 0x04, + 0x55, 0x1d, 0x20, 0x00, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x18, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x75, + 0x6d, 0x2e, 0x70, 0x6c, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x02, 0x5e, 0x8e, 0x7b, 0xe0, 0x66, 0xa1, 0xc6, + 0xab, 0x8b, 0x18, 0x1f, 0x0e, 0xb9, 0xc4, 0xcd, 0x71, 0xdb, 0x44, 0x5c, + 0x03, 0x7d, 0x65, 0xea, 0xb8, 0x47, 0xb5, 0x1e, 0xce, 0x24, 0x70, 0xa0, + 0x7f, 0xd3, 0xdf, 0x66, 0x4b, 0x8c, 0x90, 0xe2, 0xa5, 0xed, 0x9b, 0x94, + 0x36, 0xb4, 0xa8, 0xbe, 0xf0, 0x74, 0x8c, 0x26, 0x92, 0x75, 0x9d, 0x56, + 0x50, 0x9e, 0xad, 0xd0, 0x1a, 0xa0, 0xdf, 0xa4, 0x14, 0x56, 0x10, 0x75, + 0x93, 0x7a, 0xc1, 0xf4, 0x53, 0xa0, 0x76, 0x74, 0x2c, 0x72, 0xba, 0xb5, + 0xd1, 0xc9, 0xe2, 0xdc, 0x46, 0x86, 0x3f, 0x1d, 0xf6, 0x33, 0x87, 0x59, + 0xec, 0x9c, 0xdc, 0x2d, 0x1e, 0x4d, 0x43, 0x1a, 0xce, 0xba, 0xd9, 0x87, + 0x7e, 0xe2, 0x47, 0x45, 0x72, 0x3d, 0x28, 0x03, 0xc9, 0x0a, 0x4d, 0xe0, + 0x57, 0xa3, 0x5e, 0x6e, 0x7e, 0xcc, 0x5a, 0xc8, 0xc4, 0x78, 0x01, 0x57, + 0x68, 0x7a, 0x38, 0x3b, 0x53, 0x36, 0xe7, 0x92, 0x6d, 0x8a, 0x2c, 0x2f, + 0xd7, 0x8b, 0xb6, 0x34, 0xa8, 0xd1, 0xb6, 0xf8, 0x5e, 0x3b, 0xab, 0xed, + 0xa5, 0x8f, 0x39, 0x6f, 0x45, 0xad, 0xcb, 0x63, 0xed, 0x6a, 0x64, 0xc9, + 0x10, 0xa7, 0x03, 0x08, 0x12, 0x53, 0xb1, 0x1c, 0xaf, 0xca, 0xf7, 0x53, + 0xfc, 0xd8, 0x29, 0x4b, 0x1b, 0xfb, 0x38, 0xcd, 0xc0, 0x63, 0xff, 0x5f, + 0xe4, 0xb9, 0x8d, 0x5e, 0xaa, 0x2b, 0xd2, 0xc3, 0x22, 0x35, 0x31, 0xf6, + 0x30, 0x0e, 0x53, 0x32, 0xf4, 0x93, 0xc5, 0x43, 0xcb, 0xc8, 0xf0, 0x15, + 0x56, 0x8f, 0x00, 0x19, 0x87, 0xca, 0x78, 0x22, 0x8d, 0xa0, 0x2e, 0xdb, + 0x2f, 0xa0, 0xc3, 0x7e, 0x29, 0x5d, 0x91, 0x25, 0x84, 0x1d, 0x1d, 0x39, + 0xab, 0x1b, 0xc5, 0xd6, 0x91, 0xfe, 0x69, 0x0e, 0x46, 0x80, 0xbc, 0x45, + 0x7b, 0x35, 0x53, 0x2a, 0xdf, 0x00, 0xb6, 0x77, +} + +var certSet3Cert28 = []byte{ + 0x30, 0x82, 0x04, 0xaf, 0x30, 0x82, 0x03, 0x97, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x5d, 0x72, 0xfb, 0x33, 0x76, 0x20, 0xf6, 0x4c, 0x72, + 0x80, 0xdb, 0xe9, 0x12, 0x81, 0xff, 0x6a, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, + 0x30, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x44, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x45, 0x56, 0x20, 0x53, 0x53, 0x4c, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0xdd, 0xda, 0x94, 0x1e, 0x32, 0xb2, + 0x2e, 0xa0, 0x83, 0xc0, 0xa6, 0x7d, 0x5f, 0x65, 0x2d, 0xfd, 0x27, 0xb8, + 0x73, 0x0e, 0xf8, 0x0b, 0xa9, 0xd4, 0x56, 0x26, 0x69, 0x98, 0x67, 0x35, + 0x39, 0x64, 0x58, 0xce, 0x82, 0x6f, 0x98, 0x94, 0xd1, 0x8f, 0xe0, 0x90, + 0xd6, 0xed, 0x55, 0x4b, 0x98, 0x4b, 0xd7, 0x10, 0x59, 0x34, 0x02, 0x1b, + 0xe7, 0x51, 0x31, 0x51, 0xc4, 0x38, 0xc2, 0xbc, 0xdb, 0x03, 0x5c, 0xca, + 0xe1, 0x7c, 0xdc, 0x4f, 0x59, 0x97, 0xea, 0x07, 0x7f, 0x0f, 0x85, 0x3e, + 0x92, 0xea, 0xaa, 0xa7, 0xd9, 0xbe, 0x01, 0x41, 0xe4, 0x62, 0x56, 0x47, + 0x36, 0xbd, 0x57, 0x91, 0xe6, 0x21, 0xd3, 0xf8, 0x41, 0x0b, 0xd8, 0xba, + 0xe8, 0xed, 0x81, 0xad, 0x70, 0xc0, 0x8b, 0x6e, 0xf3, 0x89, 0x6e, 0x27, + 0x9e, 0xa6, 0xa6, 0x73, 0x59, 0xbb, 0x71, 0x00, 0xd4, 0x4f, 0x4b, 0x48, + 0xe9, 0xd5, 0xc9, 0x27, 0x36, 0x9c, 0x7c, 0x1c, 0x02, 0xaa, 0xac, 0xbd, + 0x3b, 0xd1, 0x53, 0x83, 0x6a, 0x1f, 0xe6, 0x08, 0x47, 0x33, 0xa7, 0xb1, + 0x9f, 0x02, 0xbe, 0x9b, 0x47, 0xed, 0x33, 0x04, 0xdc, 0x1c, 0x80, 0x27, + 0xd1, 0x4a, 0x33, 0xa0, 0x8c, 0xeb, 0x01, 0x47, 0xa1, 0x32, 0x90, 0x64, + 0x7b, 0xc4, 0xe0, 0x84, 0xc9, 0x32, 0xe9, 0xdd, 0x34, 0x1f, 0x8a, 0x68, + 0x67, 0xf3, 0xad, 0x10, 0x63, 0xeb, 0xee, 0x8a, 0x9a, 0xb1, 0x2a, 0x1b, + 0x26, 0x74, 0xa1, 0x2a, 0xb0, 0x8f, 0xfe, 0x52, 0x98, 0x46, 0x97, 0xcf, + 0xa3, 0x56, 0x1c, 0x6f, 0x6e, 0x99, 0x97, 0x8d, 0x26, 0x0e, 0xa9, 0xec, + 0xc2, 0x53, 0x70, 0xfc, 0x7a, 0xa5, 0x19, 0x49, 0xbd, 0xb5, 0x17, 0x82, + 0x55, 0xde, 0x97, 0xe0, 0x5d, 0x62, 0x84, 0x81, 0xf0, 0x70, 0xa8, 0x34, + 0x53, 0x4f, 0x14, 0xfd, 0x3d, 0x5d, 0x3d, 0x6f, 0xb9, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x35, 0x30, 0x82, 0x01, 0x31, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, + 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2f, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x23, + 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x74, + 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, + 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, + 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, + 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, 0x30, + 0x27, 0xa0, 0x25, 0xa0, 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x74, 0x31, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x29, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, + 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, + 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x35, 0x33, 0x36, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf0, 0x70, + 0x51, 0xda, 0xd3, 0x2a, 0x91, 0x4f, 0x52, 0x77, 0xd7, 0x86, 0x77, 0x74, + 0x0f, 0xce, 0x71, 0x1a, 0x6c, 0x22, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7b, 0x5b, 0x45, 0xcf, 0xaf, + 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, 0x6a, 0xb6, 0xf3, 0x46, 0xeb, + 0x57, 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa1, + 0x2e, 0x94, 0x3e, 0x9b, 0x16, 0xf4, 0x58, 0x1a, 0x6f, 0xc1, 0xfa, 0xc1, + 0x7e, 0x43, 0x93, 0xb2, 0xc3, 0xf7, 0x89, 0xeb, 0x13, 0x62, 0x5d, 0xdd, + 0xcc, 0x61, 0x13, 0x2b, 0x1d, 0x4e, 0x88, 0x79, 0x11, 0x62, 0x14, 0x37, + 0x30, 0x46, 0xff, 0x89, 0x62, 0x10, 0x85, 0x2a, 0x87, 0x1e, 0xf8, 0xe2, + 0xaf, 0xfe, 0x93, 0x02, 0x93, 0xca, 0xf2, 0xe9, 0x46, 0x03, 0x6b, 0xa1, + 0x1a, 0xac, 0xd5, 0xf0, 0x80, 0x1b, 0x98, 0x6f, 0xb8, 0x3a, 0x50, 0xf8, + 0x54, 0x71, 0x06, 0x03, 0xe7, 0x84, 0xcc, 0x8e, 0x61, 0xd2, 0x5f, 0x4d, + 0x0c, 0x97, 0x02, 0x65, 0xb5, 0x8c, 0x26, 0xbc, 0x05, 0x98, 0xf4, 0xdc, + 0xc6, 0xaf, 0xe4, 0x57, 0x7f, 0xe3, 0xdc, 0xa1, 0xd7, 0x27, 0x47, 0x2a, + 0xe0, 0x2c, 0x3f, 0x09, 0x74, 0xdc, 0x5a, 0xe5, 0xb5, 0x7c, 0xfa, 0x82, + 0x9a, 0x15, 0xfa, 0x74, 0x2b, 0x84, 0x2e, 0x6b, 0xac, 0xef, 0x35, 0xa6, + 0x30, 0xfa, 0x47, 0x4a, 0xaa, 0x36, 0x44, 0xf6, 0x5a, 0x91, 0x07, 0xd3, + 0xe4, 0x4e, 0x97, 0x3f, 0xa6, 0x53, 0xd8, 0x29, 0x33, 0x32, 0x6f, 0x8b, + 0x3d, 0xb5, 0xa5, 0x0d, 0xe5, 0xe4, 0x8a, 0xe8, 0xf5, 0xc0, 0xfa, 0xaf, + 0xd8, 0x37, 0x28, 0x27, 0xc3, 0xed, 0x34, 0x31, 0xd9, 0x7c, 0xa6, 0xaf, + 0x4d, 0x12, 0x4f, 0xd0, 0x2b, 0x92, 0x9c, 0x69, 0x95, 0xf2, 0x28, 0xa6, + 0xfe, 0xa8, 0xc6, 0xe0, 0x2c, 0x4d, 0x36, 0xeb, 0x11, 0x34, 0xd6, 0xe1, + 0x81, 0x99, 0x9d, 0x41, 0xf2, 0xe7, 0xc5, 0x57, 0x05, 0x0e, 0x19, 0xca, + 0xaf, 0x42, 0x39, 0x1f, 0xa7, 0x27, 0x5e, 0xe0, 0x0a, 0x17, 0xb8, 0xae, + 0x47, 0xab, 0x92, 0xf1, 0x8a, 0x04, 0xdf, 0x30, 0xe0, 0xbb, 0x4f, 0x8a, + 0xf9, 0x1b, 0x88, 0x4f, 0x03, 0xb4, 0x25, 0x7a, 0x78, 0xde, 0x2e, 0x7d, + 0x29, 0xd1, 0x31, +} + +var certSet3Cert29 = []byte{ + 0x30, 0x82, 0x04, 0xb1, 0x30, 0x82, 0x03, 0x99, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x04, 0xe1, 0xe7, 0xa4, 0xdc, 0x5c, 0xf2, 0xf3, 0x6d, + 0xc0, 0x2b, 0x42, 0xb8, 0x5d, 0x15, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x6c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, + 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, + 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x32, 0x32, 0x31, 0x32, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x30, 0x32, + 0x32, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x70, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, + 0x61, 0x6e, 0x63, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, + 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb6, + 0xe0, 0x2f, 0xc2, 0x24, 0x06, 0xc8, 0x6d, 0x04, 0x5f, 0xd7, 0xef, 0x0a, + 0x64, 0x06, 0xb2, 0x7d, 0x22, 0x26, 0x65, 0x16, 0xae, 0x42, 0x40, 0x9b, + 0xce, 0xdc, 0x9f, 0x9f, 0x76, 0x07, 0x3e, 0xc3, 0x30, 0x55, 0x87, 0x19, + 0xb9, 0x4f, 0x94, 0x0e, 0x5a, 0x94, 0x1f, 0x55, 0x56, 0xb4, 0xc2, 0x02, + 0x2a, 0xaf, 0xd0, 0x98, 0xee, 0x0b, 0x40, 0xd7, 0xc4, 0xd0, 0x3b, 0x72, + 0xc8, 0x14, 0x9e, 0xef, 0x90, 0xb1, 0x11, 0xa9, 0xae, 0xd2, 0xc8, 0xb8, + 0x43, 0x3a, 0xd9, 0x0b, 0x0b, 0xd5, 0xd5, 0x95, 0xf5, 0x40, 0xaf, 0xc8, + 0x1d, 0xed, 0x4d, 0x9c, 0x5f, 0x57, 0xb7, 0x86, 0x50, 0x68, 0x99, 0xf5, + 0x8a, 0xda, 0xd2, 0xc7, 0x05, 0x1f, 0xa8, 0x97, 0xc9, 0xdc, 0xa4, 0xb1, + 0x82, 0x84, 0x2d, 0xc6, 0xad, 0xa5, 0x9c, 0xc7, 0x19, 0x82, 0xa6, 0x85, + 0x0f, 0x5e, 0x44, 0x58, 0x2a, 0x37, 0x8f, 0xfd, 0x35, 0xf1, 0x0b, 0x08, + 0x27, 0x32, 0x5a, 0xf5, 0xbb, 0x8b, 0x9e, 0xa4, 0xbd, 0x51, 0xd0, 0x27, + 0xe2, 0xdd, 0x3b, 0x42, 0x33, 0xa3, 0x05, 0x28, 0xc4, 0xbb, 0x28, 0xcc, + 0x9a, 0xac, 0x2b, 0x23, 0x0d, 0x78, 0xc6, 0x7b, 0xe6, 0x5e, 0x71, 0xb7, + 0x4a, 0x3e, 0x08, 0xfb, 0x81, 0xb7, 0x16, 0x16, 0xa1, 0x9d, 0x23, 0x12, + 0x4d, 0xe5, 0xd7, 0x92, 0x08, 0xac, 0x75, 0xa4, 0x9c, 0xba, 0xcd, 0x17, + 0xb2, 0x1e, 0x44, 0x35, 0x65, 0x7f, 0x53, 0x25, 0x39, 0xd1, 0x1c, 0x0a, + 0x9a, 0x63, 0x1b, 0x19, 0x92, 0x74, 0x68, 0x0a, 0x37, 0xc2, 0xc2, 0x52, + 0x48, 0xcb, 0x39, 0x5a, 0xa2, 0xb6, 0xe1, 0x5d, 0xc1, 0xdd, 0xa0, 0x20, + 0xb8, 0x21, 0xa2, 0x93, 0x26, 0x6f, 0x14, 0x4a, 0x21, 0x41, 0xc7, 0xed, + 0x6d, 0x9b, 0xf2, 0x48, 0x2f, 0xf3, 0x03, 0xf5, 0xa2, 0x68, 0x92, 0x53, + 0x2f, 0x5e, 0xe3, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x49, + 0x30, 0x82, 0x01, 0x45, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, + 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4b, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x44, 0x30, 0x42, 0x30, 0x40, 0xa0, 0x3e, 0xa0, 0x3c, 0x86, 0x3a, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x34, 0x2e, + 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x48, 0x69, 0x67, + 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x56, + 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, + 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, + 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x51, 0x68, 0xff, 0x90, 0xaf, 0x02, 0x07, 0x75, 0x3c, 0xcc, 0xd9, 0x65, + 0x64, 0x62, 0xa2, 0x12, 0xb8, 0x59, 0x72, 0x3b, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb1, 0x3e, 0xc3, + 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, 0x02, + 0xef, 0x63, 0x64, 0x2b, 0xc3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, + 0x00, 0x18, 0x8a, 0x95, 0x89, 0x03, 0xe6, 0x6d, 0xdf, 0x5c, 0xfc, 0x1d, + 0x68, 0xea, 0x4a, 0x8f, 0x83, 0xd6, 0x51, 0x2f, 0x8d, 0x6b, 0x44, 0x16, + 0x9e, 0xac, 0x63, 0xf5, 0xd2, 0x6e, 0x6c, 0x84, 0x99, 0x8b, 0xaa, 0x81, + 0x71, 0x84, 0x5b, 0xed, 0x34, 0x4e, 0xb0, 0xb7, 0x79, 0x92, 0x29, 0xcc, + 0x2d, 0x80, 0x6a, 0xf0, 0x8e, 0x20, 0xe1, 0x79, 0xa4, 0xfe, 0x03, 0x47, + 0x13, 0xea, 0xf5, 0x86, 0xca, 0x59, 0x71, 0x7d, 0xf4, 0x04, 0x96, 0x6b, + 0xd3, 0x59, 0x58, 0x3d, 0xfe, 0xd3, 0x31, 0x25, 0x5c, 0x18, 0x38, 0x84, + 0xa3, 0xe6, 0x9f, 0x82, 0xfd, 0x8c, 0x5b, 0x98, 0x31, 0x4e, 0xcd, 0x78, + 0x9e, 0x1a, 0xfd, 0x85, 0xcb, 0x49, 0xaa, 0xf2, 0x27, 0x8b, 0x99, 0x72, + 0xfc, 0x3e, 0xaa, 0xd5, 0x41, 0x0b, 0xda, 0xd5, 0x36, 0xa1, 0xbf, 0x1c, + 0x6e, 0x47, 0x49, 0x7f, 0x5e, 0xd9, 0x48, 0x7c, 0x03, 0xd9, 0xfd, 0x8b, + 0x49, 0xa0, 0x98, 0x26, 0x42, 0x40, 0xeb, 0xd6, 0x92, 0x11, 0xa4, 0x64, + 0x0a, 0x57, 0x54, 0xc4, 0xf5, 0x1d, 0xd6, 0x02, 0x5e, 0x6b, 0xac, 0xee, + 0xc4, 0x80, 0x9a, 0x12, 0x72, 0xfa, 0x56, 0x93, 0xd7, 0xff, 0xbf, 0x30, + 0x85, 0x06, 0x30, 0xbf, 0x0b, 0x7f, 0x4e, 0xff, 0x57, 0x05, 0x9d, 0x24, + 0xed, 0x85, 0xc3, 0x2b, 0xfb, 0xa6, 0x75, 0xa8, 0xac, 0x2d, 0x16, 0xef, + 0x7d, 0x79, 0x27, 0xb2, 0xeb, 0xc2, 0x9d, 0x0b, 0x07, 0xea, 0xaa, 0x85, + 0xd3, 0x01, 0xa3, 0x20, 0x28, 0x41, 0x59, 0x43, 0x28, 0xd2, 0x81, 0xe3, + 0xaa, 0xf6, 0xec, 0x7b, 0x3b, 0x77, 0xb6, 0x40, 0x62, 0x80, 0x05, 0x41, + 0x45, 0x01, 0xef, 0x17, 0x06, 0x3e, 0xde, 0xc0, 0x33, 0x9b, 0x67, 0xd3, + 0x61, 0x2e, 0x72, 0x87, 0xe4, 0x69, 0xfc, 0x12, 0x00, 0x57, 0x40, 0x1e, + 0x70, 0xf5, 0x1e, 0xc9, 0xb4, +} + +var certSet3Cert30 = []byte{ + 0x30, 0x82, 0x04, 0xb2, 0x30, 0x82, 0x03, 0x9a, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x16, 0x87, 0xd6, 0x88, 0x6d, 0xe2, 0x30, 0x06, 0x85, + 0x23, 0x3d, 0xbf, 0x11, 0xbf, 0x65, 0x97, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, + 0x30, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x41, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xb2, 0xfc, 0x06, 0xfb, 0x04, 0x93, 0xd2, 0xea, 0x59, 0x20, + 0x3b, 0x44, 0x85, 0x97, 0x52, 0x39, 0xe7, 0x10, 0xf0, 0x7a, 0xe0, 0xb0, + 0x94, 0x40, 0xda, 0x46, 0xf8, 0x0c, 0x28, 0xbb, 0xb9, 0xce, 0x60, 0x38, + 0x3f, 0xd2, 0xd8, 0x11, 0x42, 0x1b, 0x91, 0xad, 0x49, 0xee, 0x8f, 0xc7, + 0xde, 0x6c, 0xde, 0x37, 0x6f, 0xfd, 0x8b, 0x20, 0x3c, 0x6d, 0xe7, 0x74, + 0xd3, 0xdc, 0xd5, 0x24, 0x88, 0x41, 0x80, 0x89, 0xee, 0x36, 0xbe, 0xc4, + 0xd5, 0xbe, 0x8d, 0x53, 0x13, 0xaa, 0xe4, 0xa5, 0xb8, 0x93, 0x0a, 0xbe, + 0xec, 0xda, 0xcd, 0x3c, 0xd4, 0x32, 0x56, 0xef, 0xd0, 0x4e, 0xa0, 0xb8, + 0x97, 0xbb, 0x39, 0x50, 0x1e, 0x6e, 0x65, 0xc3, 0xfd, 0xb2, 0xce, 0xe0, + 0x59, 0xa9, 0x48, 0x09, 0xc6, 0xfe, 0xbe, 0xae, 0xfc, 0x3e, 0x3b, 0x81, + 0x20, 0x97, 0x8b, 0x8f, 0x46, 0xdf, 0x60, 0x64, 0x07, 0x75, 0xbb, 0x1b, + 0x86, 0x38, 0x9f, 0x47, 0x7b, 0x34, 0xce, 0xa1, 0xd1, 0x97, 0xad, 0x76, + 0xd8, 0x9f, 0xb7, 0x26, 0xdb, 0x79, 0x80, 0x36, 0x48, 0xf2, 0xc5, 0x37, + 0xf8, 0xd9, 0x32, 0xae, 0x7c, 0xa4, 0x53, 0x81, 0xc7, 0x99, 0xa1, 0x54, + 0x38, 0x2f, 0x4f, 0x75, 0xa0, 0xbb, 0x5a, 0xa5, 0xbb, 0xcd, 0xac, 0x02, + 0x5b, 0x19, 0x02, 0xd5, 0x13, 0x18, 0xa7, 0xce, 0xac, 0x74, 0x55, 0x12, + 0x05, 0x8b, 0x9b, 0xa2, 0x95, 0x46, 0x64, 0x72, 0x38, 0xcd, 0x5a, 0x1b, + 0x3a, 0x16, 0xa7, 0xbe, 0x71, 0x99, 0x8c, 0x54, 0x03, 0xb8, 0x96, 0x6c, + 0x01, 0xd3, 0x3e, 0x06, 0x98, 0x3f, 0x21, 0x81, 0x3b, 0x02, 0x7e, 0x00, + 0x47, 0x53, 0x01, 0x1e, 0x0e, 0x46, 0x43, 0xfb, 0x4b, 0x2d, 0xdc, 0x0b, + 0x1a, 0xe8, 0x2f, 0x98, 0xf8, 0x7e, 0xd1, 0x99, 0xab, 0x13, 0x6c, 0xa4, + 0x17, 0xde, 0x6f, 0xf6, 0x15, 0xf5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x82, 0x01, 0x3b, 0x30, 0x82, 0x01, 0x37, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x32, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, 0x30, 0x27, 0xa0, 0x25, 0xa0, 0x23, + 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x74, 0x31, 0x2e, + 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, + 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x74, 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x41, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3a, 0x30, 0x38, 0x30, + 0x36, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, + 0x36, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x29, 0x06, 0x03, 0x55, + 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, + 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, + 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x35, + 0x33, 0x37, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0xc2, 0x4f, 0x48, 0x57, 0xfc, 0xd1, 0x4f, 0x9a, 0xc0, 0x5d, 0x38, + 0x7d, 0x0e, 0x05, 0xdb, 0xd9, 0x2e, 0xb5, 0x52, 0x60, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7b, 0x5b, + 0x45, 0xcf, 0xaf, 0xce, 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, 0x6a, 0xb6, + 0xf3, 0x46, 0xeb, 0x57, 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x8d, 0x06, 0xde, 0x43, 0xc9, 0x76, 0x02, 0xca, 0xd9, 0x23, + 0x97, 0x5e, 0xf3, 0x63, 0xd7, 0x7d, 0x44, 0xc2, 0x0f, 0x6b, 0x0a, 0xf5, + 0x07, 0xe5, 0x8b, 0xb8, 0xfa, 0xe0, 0xa3, 0xfa, 0x6b, 0x80, 0x92, 0xb5, + 0x03, 0x2c, 0xc5, 0x37, 0xe0, 0xc2, 0xe5, 0x95, 0xb5, 0x92, 0x70, 0x18, + 0x28, 0x42, 0x94, 0xee, 0x4b, 0x77, 0x6a, 0x01, 0x0f, 0x8b, 0x23, 0xec, + 0x56, 0x4d, 0xf4, 0x00, 0x69, 0xe5, 0x84, 0xc8, 0xe2, 0xea, 0xde, 0x5b, + 0x3e, 0xf6, 0x3c, 0x07, 0x3a, 0x94, 0xca, 0x6c, 0x27, 0xb1, 0xcc, 0x83, + 0x1a, 0x60, 0x71, 0x27, 0xd2, 0xbf, 0x02, 0xf5, 0x1e, 0x44, 0xd3, 0x48, + 0xd5, 0xa6, 0xd3, 0x76, 0x21, 0x00, 0x9c, 0xfa, 0x98, 0x64, 0xeb, 0x17, + 0x36, 0x3f, 0xeb, 0x1b, 0x3c, 0x3e, 0xa6, 0xb1, 0xd9, 0x58, 0x06, 0x0e, + 0x72, 0xd9, 0x68, 0xbe, 0xf1, 0xa7, 0x20, 0xd7, 0x52, 0xe4, 0xa4, 0x77, + 0x1f, 0x71, 0x70, 0x9d, 0x55, 0x35, 0x85, 0x37, 0xe1, 0x1d, 0x4d, 0x94, + 0xc2, 0x70, 0x7f, 0x95, 0x40, 0x6e, 0x4b, 0x7d, 0xb2, 0xb4, 0x29, 0x2a, + 0x03, 0x79, 0xc8, 0xb9, 0x4c, 0x67, 0x61, 0x04, 0xa0, 0x8b, 0x27, 0xff, + 0x59, 0x00, 0xeb, 0x55, 0x7f, 0xc6, 0xb7, 0x33, 0x35, 0x2d, 0x5e, 0x4e, + 0xac, 0xb8, 0xea, 0x12, 0xc5, 0xe8, 0xf7, 0xb9, 0xab, 0xbe, 0x74, 0x92, + 0x2c, 0xb7, 0xd9, 0x4d, 0xca, 0x84, 0x2f, 0x1c, 0xc2, 0xf0, 0x72, 0x7c, + 0xb2, 0x31, 0x6e, 0xcf, 0x80, 0xe5, 0x88, 0x07, 0x36, 0x51, 0x7b, 0xba, + 0x61, 0xaf, 0x6d, 0x8d, 0x23, 0x5b, 0x34, 0xa3, 0x95, 0xbc, 0xa2, 0x31, + 0x7f, 0xf2, 0xf5, 0xe7, 0xb7, 0xe8, 0xef, 0xc4, 0xb5, 0x27, 0x32, 0xe9, + 0xf7, 0x9e, 0x69, 0xc7, 0x2b, 0xe8, 0xbe, 0xbb, 0x0c, 0xaa, 0xe7, 0xea, + 0x60, 0x12, 0xea, 0x26, 0x8a, 0x78, +} + +var certSet3Cert31 = []byte{ + 0x30, 0x82, 0x04, 0xb4, 0x30, 0x82, 0x03, 0x9c, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x11, 0x00, 0x93, 0x92, 0x85, 0x40, 0x01, 0x65, 0x71, 0x5f, + 0x94, 0x7f, 0x28, 0x8f, 0xef, 0xc9, 0x9b, 0x28, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x50, 0x4c, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x12, 0x55, 0x6e, 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, 0x53, 0x70, 0x2e, + 0x20, 0x7a, 0x20, 0x6f, 0x2e, 0x6f, 0x2e, 0x31, 0x12, 0x30, 0x10, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, + 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x30, 0x32, + 0x32, 0x31, 0x32, 0x30, 0x37, 0x33, 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x37, + 0x30, 0x36, 0x31, 0x30, 0x31, 0x30, 0x34, 0x36, 0x33, 0x39, 0x5a, 0x30, + 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x50, 0x4c, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x19, 0x55, 0x6e, 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, + 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x53, 0x2e, + 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x1e, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x22, 0x30, 0x20, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xe3, 0xfb, 0x7d, 0xa3, 0x72, 0xba, 0xc2, 0xf0, + 0xc9, 0x14, 0x87, 0xf5, 0x6b, 0x01, 0x4e, 0xe1, 0x6e, 0x40, 0x07, 0xba, + 0x6d, 0x27, 0x5d, 0x7f, 0xf7, 0x5b, 0x2d, 0xb3, 0x5a, 0xc7, 0x51, 0x5f, + 0xab, 0xa4, 0x32, 0xa6, 0x61, 0x87, 0xb6, 0x6e, 0x0f, 0x86, 0xd2, 0x30, + 0x02, 0x97, 0xf8, 0xd7, 0x69, 0x57, 0xa1, 0x18, 0x39, 0x5d, 0x6a, 0x64, + 0x79, 0xc6, 0x01, 0x59, 0xac, 0x3c, 0x31, 0x4a, 0x38, 0x7c, 0xd2, 0x04, + 0xd2, 0x4b, 0x28, 0xe8, 0x20, 0x5f, 0x3b, 0x07, 0xa2, 0xcc, 0x4d, 0x73, + 0xdb, 0xf3, 0xae, 0x4f, 0xc7, 0x56, 0xd5, 0x5a, 0xa7, 0x96, 0x89, 0xfa, + 0xf3, 0xab, 0x68, 0xd4, 0x23, 0x86, 0x59, 0x27, 0xcf, 0x09, 0x27, 0xbc, + 0xac, 0x6e, 0x72, 0x83, 0x1c, 0x30, 0x72, 0xdf, 0xe0, 0xa2, 0xe9, 0xd2, + 0xe1, 0x74, 0x75, 0x19, 0xbd, 0x2a, 0x9e, 0x7b, 0x15, 0x54, 0x04, 0x1b, + 0xd7, 0x43, 0x39, 0xad, 0x55, 0x28, 0xc5, 0xe2, 0x1a, 0xbb, 0xf4, 0xc0, + 0xe4, 0xae, 0x38, 0x49, 0x33, 0xcc, 0x76, 0x85, 0x9f, 0x39, 0x45, 0xd2, + 0xa4, 0x9e, 0xf2, 0x12, 0x8c, 0x51, 0xf8, 0x7c, 0xe4, 0x2d, 0x7f, 0xf5, + 0xac, 0x5f, 0xeb, 0x16, 0x9f, 0xb1, 0x2d, 0xd1, 0xba, 0xcc, 0x91, 0x42, + 0x77, 0x4c, 0x25, 0xc9, 0x90, 0x38, 0x6f, 0xdb, 0xf0, 0xcc, 0xfb, 0x8e, + 0x1e, 0x97, 0x59, 0x3e, 0xd5, 0x60, 0x4e, 0xe6, 0x05, 0x28, 0xed, 0x49, + 0x79, 0x13, 0x4b, 0xba, 0x48, 0xdb, 0x2f, 0xf9, 0x72, 0xd3, 0x39, 0xca, + 0xfe, 0x1f, 0xd8, 0x34, 0x72, 0xf5, 0xb4, 0x40, 0xcf, 0x31, 0x01, 0xc3, + 0xec, 0xde, 0x11, 0x2d, 0x17, 0x5d, 0x1f, 0xb8, 0x50, 0xd1, 0x5e, 0x19, + 0xa7, 0x69, 0xde, 0x07, 0x33, 0x28, 0xca, 0x50, 0x95, 0xf9, 0xa7, 0x54, + 0xcb, 0x54, 0x86, 0x50, 0x45, 0xa9, 0xf9, 0x49, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0x6b, 0x30, 0x82, 0x01, 0x67, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x08, 0x76, 0xcd, 0xcb, 0x07, 0xff, 0x24, 0xf6, 0xc5, 0xcd, 0xed, + 0xbb, 0x90, 0xbc, 0xe2, 0x84, 0x37, 0x46, 0x75, 0xf7, 0x30, 0x52, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x4b, 0x30, 0x49, 0xa1, 0x42, 0xa4, 0x40, + 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x50, 0x4c, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x12, 0x55, 0x6e, 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, 0x53, 0x70, + 0x2e, 0x20, 0x7a, 0x20, 0x6f, 0x2e, 0x6f, 0x2e, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x43, 0x65, 0x72, 0x74, 0x75, + 0x6d, 0x20, 0x43, 0x41, 0x82, 0x03, 0x01, 0x00, 0x20, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x25, 0x30, 0x23, + 0x30, 0x21, 0xa0, 0x1f, 0xa0, 0x1d, 0x86, 0x1b, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x75, + 0x6d, 0x2e, 0x70, 0x6c, 0x2f, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x5c, 0x30, 0x5a, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x73, 0x75, 0x62, 0x63, 0x61, 0x2e, 0x6f, 0x63, 0x73, 0x70, 0x2d, 0x63, + 0x65, 0x72, 0x74, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x2e, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x22, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x2e, + 0x70, 0x6c, 0x2f, 0x63, 0x61, 0x2e, 0x63, 0x65, 0x72, 0x30, 0x39, 0x06, + 0x03, 0x55, 0x1d, 0x20, 0x04, 0x32, 0x30, 0x30, 0x30, 0x2e, 0x06, 0x04, + 0x55, 0x1d, 0x20, 0x00, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x18, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x75, + 0x6d, 0x2e, 0x70, 0x6c, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x8d, 0xe6, 0xfd, 0x40, 0x66, 0xa3, 0x4c, 0x9c, + 0xa7, 0xab, 0xa1, 0xda, 0x84, 0xdd, 0x1c, 0x30, 0x07, 0xe6, 0xdb, 0xc7, + 0x2d, 0xec, 0x83, 0xa1, 0x56, 0xe4, 0x1d, 0x3c, 0x26, 0xa1, 0xa5, 0x09, + 0x2b, 0xe8, 0x7d, 0x62, 0xbe, 0xb2, 0x75, 0x94, 0xdd, 0x08, 0xf2, 0x7f, + 0x28, 0x41, 0xe4, 0x80, 0x67, 0x02, 0x4e, 0x8a, 0x8f, 0xc3, 0x35, 0xd0, + 0xd5, 0xa9, 0x27, 0x28, 0xea, 0xd2, 0xf4, 0xab, 0x06, 0x86, 0x43, 0xae, + 0x8c, 0xe3, 0xf9, 0x88, 0x7d, 0xe0, 0xdb, 0xbd, 0x42, 0x81, 0x80, 0x02, + 0x12, 0x75, 0xb2, 0xe8, 0x17, 0x71, 0xab, 0x21, 0x95, 0x31, 0x46, 0x42, + 0x0d, 0x88, 0x10, 0x39, 0xd3, 0x6f, 0xec, 0x2f, 0x42, 0xea, 0x40, 0x53, + 0x62, 0xbf, 0xeb, 0xca, 0x78, 0x9e, 0xab, 0xa2, 0xd5, 0x2e, 0x05, 0xea, + 0x33, 0xab, 0xe9, 0xd6, 0x97, 0x94, 0x42, 0x5e, 0x04, 0xed, 0x2c, 0xed, + 0x6a, 0x9c, 0x7a, 0x95, 0x7d, 0x05, 0x2a, 0x05, 0x7f, 0x08, 0x5d, 0x66, + 0xad, 0x61, 0xd4, 0x76, 0xac, 0x75, 0x96, 0x97, 0x73, 0x63, 0xbd, 0x1a, + 0x41, 0x59, 0x29, 0xa5, 0x5e, 0x22, 0x83, 0xc3, 0x8b, 0x59, 0xfa, 0x9a, + 0xa2, 0xf6, 0xbd, 0x30, 0xbf, 0x72, 0x1d, 0x1c, 0x99, 0x86, 0x9c, 0xf2, + 0x85, 0x3c, 0x1d, 0xf7, 0x26, 0x96, 0x2f, 0x2e, 0xf9, 0x02, 0xb1, 0xb5, + 0xa9, 0x50, 0xe8, 0x38, 0xfa, 0x9b, 0x0a, 0x5e, 0xb4, 0x04, 0xc0, 0xce, + 0x4e, 0x39, 0x2c, 0xca, 0x0b, 0x5b, 0x62, 0xf0, 0x4d, 0x58, 0x50, 0x34, + 0x99, 0xe6, 0x9a, 0x2c, 0xd2, 0x90, 0xd7, 0x09, 0x81, 0xd6, 0xc0, 0xaa, + 0x5e, 0xce, 0xfe, 0xd2, 0xf7, 0xa1, 0xba, 0x4b, 0xd9, 0xd6, 0x86, 0x8e, + 0x19, 0x1f, 0xa6, 0x06, 0x47, 0x42, 0x72, 0xe0, 0x56, 0x0a, 0x00, 0x1c, + 0x78, 0xb9, 0x8d, 0xcc, 0x99, 0x04, 0x37, 0x49, +} + +var certSet3Cert32 = []byte{ + 0x30, 0x82, 0x04, 0xb5, 0x30, 0x82, 0x03, 0x9d, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x48, 0xe9, 0x94, 0x40, 0xd4, 0x36, 0x49, 0x1c, 0xb8, + 0xb8, 0x82, 0x3d, 0x09, 0x43, 0x94, 0xc7, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x36, 0x30, 0x39, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, 0x69, 0x64, + 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xc4, 0x95, 0x63, 0x28, 0xd0, 0x4e, 0x30, 0x45, 0xaf, + 0x8b, 0x97, 0x34, 0x14, 0x45, 0xf8, 0x5c, 0x58, 0x4a, 0xfa, 0x33, 0x8e, + 0x6e, 0x9c, 0x60, 0xab, 0xf3, 0x86, 0xff, 0x34, 0x74, 0xb2, 0x2b, 0xbe, + 0xa1, 0x8c, 0xd5, 0xa2, 0xa3, 0x60, 0x7a, 0x40, 0xb9, 0xe1, 0xfc, 0x22, + 0xca, 0x67, 0xba, 0x60, 0xaa, 0xc7, 0x9a, 0xf9, 0x06, 0x7f, 0xee, 0xf7, + 0xba, 0x85, 0x05, 0xb0, 0x03, 0xff, 0x72, 0xae, 0x15, 0x41, 0x4a, 0x98, + 0x64, 0xd7, 0x17, 0x4b, 0x54, 0xef, 0x05, 0xc6, 0x98, 0x07, 0x93, 0x27, + 0x3e, 0x4f, 0xdc, 0x0f, 0xc6, 0x7b, 0x8b, 0xe7, 0xf3, 0x06, 0x5e, 0x8d, + 0xe8, 0xb4, 0xae, 0x29, 0xb4, 0x1e, 0x1e, 0x2d, 0x16, 0x90, 0xd3, 0xea, + 0xaa, 0xe7, 0x8c, 0x3b, 0x6d, 0xaf, 0x36, 0x59, 0xff, 0xc5, 0x0a, 0xfa, + 0xc7, 0x4c, 0xbd, 0x36, 0x8b, 0x64, 0xc4, 0x4a, 0xf5, 0xce, 0x33, 0xf9, + 0x07, 0xbe, 0x7f, 0x45, 0x90, 0xa8, 0x08, 0x14, 0xb0, 0xd0, 0xa5, 0x4f, + 0xdf, 0x82, 0x80, 0xda, 0x1b, 0xee, 0xc3, 0x13, 0xb0, 0x98, 0xf5, 0x0f, + 0xf9, 0x7e, 0x76, 0xb5, 0xe6, 0xb9, 0x5d, 0x68, 0xb9, 0x5c, 0x50, 0x90, + 0x89, 0xa4, 0x36, 0xb1, 0x70, 0x16, 0xea, 0xb1, 0x10, 0xb5, 0x6a, 0x76, + 0xdf, 0xe1, 0xbb, 0xfc, 0x78, 0xf2, 0x72, 0x99, 0xcf, 0xc9, 0xa2, 0xd4, + 0x73, 0x54, 0x77, 0xbf, 0xc0, 0x39, 0x77, 0xe5, 0xae, 0x12, 0xc5, 0x78, + 0x5a, 0x19, 0x45, 0xd4, 0x41, 0x19, 0xd3, 0x7c, 0xf5, 0x6f, 0x99, 0x6b, + 0xd7, 0x8b, 0xbc, 0x2d, 0x09, 0x9d, 0x4b, 0x10, 0x61, 0xc0, 0xda, 0x52, + 0xc3, 0xaf, 0x22, 0x43, 0xc6, 0xeb, 0x37, 0x7e, 0x63, 0x74, 0x30, 0x0d, + 0x6a, 0x71, 0x8e, 0xde, 0x5d, 0x5b, 0x8a, 0xc8, 0xc5, 0xd7, 0x9b, 0x29, + 0xe8, 0xae, 0xb6, 0x25, 0x61, 0x81, 0xeb, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x49, 0x30, 0x82, 0x01, 0x45, 0x30, 0x2e, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, + 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, + 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x36, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, + 0x29, 0xa0, 0x27, 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x50, 0x43, 0x41, 0x2d, + 0x47, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x29, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, + 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, + 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, + 0x31, 0x2d, 0x36, 0x39, 0x37, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0x4c, 0xf4, 0xbf, 0xe8, 0x3b, 0xbe, 0xc2, 0x24, + 0xf3, 0x1b, 0x47, 0x3b, 0xb5, 0x6e, 0x48, 0x8e, 0x16, 0xab, 0xaf, 0x12, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0xc4, 0x79, 0xca, 0x8e, 0xa1, 0x4e, 0x03, 0x1d, 0x1c, 0xdc, 0x6b, + 0xdb, 0x31, 0x5b, 0x94, 0x3e, 0x3f, 0x30, 0x7f, 0x2d, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0x7a, 0x53, 0xb5, 0xde, 0xb6, 0xef, 0x52, + 0xa3, 0x5f, 0x8a, 0xf5, 0x89, 0xf1, 0x42, 0xcc, 0x5e, 0x46, 0x88, 0xae, + 0xa5, 0x08, 0x87, 0x51, 0xde, 0x0f, 0x0f, 0x02, 0xeb, 0x0c, 0x82, 0x78, + 0xe3, 0x73, 0x7d, 0x71, 0xbd, 0x43, 0xe9, 0xca, 0x8a, 0x3f, 0xe0, 0x25, + 0x92, 0x9b, 0x33, 0x33, 0x74, 0x49, 0x5e, 0x00, 0xd9, 0x73, 0x14, 0x1c, + 0x0b, 0x46, 0x76, 0x1c, 0x8a, 0x0d, 0x4d, 0x8c, 0x6c, 0x7e, 0x4b, 0xf7, + 0x60, 0xd8, 0x81, 0x78, 0xa0, 0x78, 0xd0, 0x25, 0x62, 0xab, 0x10, 0xca, + 0x22, 0xe8, 0x1c, 0x19, 0xdd, 0x52, 0x83, 0x64, 0x05, 0xe5, 0x87, 0x66, + 0xae, 0xe7, 0x7a, 0xa4, 0x3b, 0x3e, 0xd8, 0x70, 0x7a, 0x76, 0xa2, 0x67, + 0x39, 0xd4, 0xc9, 0xfa, 0xe5, 0xb7, 0x1e, 0x41, 0xe2, 0x09, 0x39, 0x88, + 0x1c, 0x18, 0x55, 0x0a, 0xc4, 0x41, 0xaf, 0xb2, 0xf3, 0xf3, 0x0f, 0x42, + 0x14, 0x61, 0x74, 0x81, 0xe3, 0xda, 0x87, 0x5a, 0x9a, 0x4d, 0x8b, 0xd3, + 0xc9, 0x8f, 0x89, 0x66, 0x13, 0x29, 0x11, 0xe4, 0xff, 0xe2, 0xdf, 0x8e, + 0x96, 0x0c, 0x5a, 0xa1, 0xaa, 0x6b, 0x9b, 0xfd, 0xfc, 0x03, 0x3b, 0x55, + 0x0d, 0xa6, 0xa2, 0x25, 0x48, 0x17, 0x1f, 0x42, 0xa8, 0xda, 0x6c, 0x7e, + 0x69, 0x6e, 0xa0, 0xdf, 0x67, 0xd2, 0x6d, 0xf4, 0x0e, 0x6a, 0x12, 0x79, + 0xf5, 0x7c, 0xc8, 0xa5, 0x32, 0x1c, 0xc4, 0x31, 0xb2, 0xe6, 0xbb, 0xa8, + 0x6b, 0x6a, 0xa2, 0x8a, 0x60, 0x69, 0xc0, 0x57, 0x7d, 0xb2, 0xf2, 0x31, + 0x0c, 0x98, 0x65, 0x32, 0xec, 0x08, 0x5a, 0xce, 0xc6, 0x98, 0xe9, 0x21, + 0x97, 0x3f, 0x2c, 0x79, 0x29, 0x03, 0xf5, 0xf6, 0x94, 0x2b, 0x53, 0x31, + 0xf3, 0x93, 0x68, 0x57, 0xe1, 0xd7, 0x4f, 0x3a, 0xd1, 0x61, 0xa1, 0x60, + 0xce, 0xb9, 0xab, 0x98, 0xae, 0x35, 0x54, 0x63, 0x8b, +} + +var certSet3Cert33 = []byte{ + 0x30, 0x82, 0x04, 0xb6, 0x30, 0x82, 0x03, 0x9e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x0c, 0x79, 0xa9, 0x44, 0xb0, 0x8c, 0x11, 0x95, 0x20, + 0x92, 0x61, 0x5f, 0xe2, 0x6b, 0x1d, 0x83, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x6c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, + 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, + 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x32, 0x32, 0x31, 0x32, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x30, 0x32, + 0x32, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x75, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2b, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xd7, 0x53, 0xa4, 0x04, 0x51, 0xf8, 0x99, 0xa6, + 0x16, 0x48, 0x4b, 0x67, 0x27, 0xaa, 0x93, 0x49, 0xd0, 0x39, 0xed, 0x0c, + 0xb0, 0xb0, 0x00, 0x87, 0xf1, 0x67, 0x28, 0x86, 0x85, 0x8c, 0x8e, 0x63, + 0xda, 0xbc, 0xb1, 0x40, 0x38, 0xe2, 0xd3, 0xf5, 0xec, 0xa5, 0x05, 0x18, + 0xb8, 0x3d, 0x3e, 0xc5, 0x99, 0x17, 0x32, 0xec, 0x18, 0x8c, 0xfa, 0xf1, + 0x0c, 0xa6, 0x64, 0x21, 0x85, 0xcb, 0x07, 0x10, 0x34, 0xb0, 0x52, 0x88, + 0x2b, 0x1f, 0x68, 0x9b, 0xd2, 0xb1, 0x8f, 0x12, 0xb0, 0xb3, 0xd2, 0xe7, + 0x88, 0x1f, 0x1f, 0xef, 0x38, 0x77, 0x54, 0x53, 0x5f, 0x80, 0x79, 0x3f, + 0x2e, 0x1a, 0xaa, 0xa8, 0x1e, 0x4b, 0x2b, 0x0d, 0xab, 0xb7, 0x63, 0xb9, + 0x35, 0xb7, 0x7d, 0x14, 0xbc, 0x59, 0x4b, 0xdf, 0x51, 0x4a, 0xd2, 0xa1, + 0xe2, 0x0c, 0xe2, 0x90, 0x82, 0x87, 0x6a, 0xae, 0xea, 0xd7, 0x64, 0xd6, + 0x98, 0x55, 0xe8, 0xfd, 0xaf, 0x1a, 0x50, 0x6c, 0x54, 0xbc, 0x11, 0xf2, + 0xfd, 0x4a, 0xf2, 0x9d, 0xbb, 0x7f, 0x0e, 0xf4, 0xd5, 0xbe, 0x8e, 0x16, + 0x89, 0x12, 0x55, 0xd8, 0xc0, 0x71, 0x34, 0xee, 0xf6, 0xdc, 0x2d, 0xec, + 0xc4, 0x87, 0x25, 0x86, 0x8d, 0xd8, 0x21, 0xe4, 0xb0, 0x4d, 0x0c, 0x89, + 0xdc, 0x39, 0x26, 0x17, 0xdd, 0xf6, 0xd7, 0x94, 0x85, 0xd8, 0x04, 0x21, + 0x70, 0x9d, 0x6f, 0x6f, 0xff, 0x5c, 0xba, 0x19, 0xe1, 0x45, 0xcb, 0x56, + 0x57, 0x28, 0x7e, 0x1c, 0x0d, 0x41, 0x57, 0xaa, 0xb7, 0xb8, 0x27, 0xbb, + 0xb1, 0xe4, 0xfa, 0x2a, 0xef, 0x21, 0x23, 0x75, 0x1a, 0xad, 0x2d, 0x9b, + 0x86, 0x35, 0x8c, 0x9c, 0x77, 0xb5, 0x73, 0xad, 0xd8, 0x94, 0x2d, 0xe4, + 0xf3, 0x0c, 0x9d, 0xee, 0xc1, 0x4e, 0x62, 0x7e, 0x17, 0xc0, 0x71, 0x9e, + 0x2c, 0xde, 0xf1, 0xf9, 0x10, 0x28, 0x19, 0x33, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0x49, 0x30, 0x82, 0x01, 0x45, 0x30, 0x12, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, + 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, + 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, + 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4b, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x44, 0x30, 0x42, 0x30, 0x40, 0xa0, + 0x3e, 0xa0, 0x3c, 0x86, 0x3a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, + 0x72, 0x74, 0x48, 0x69, 0x67, 0x68, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, + 0x6e, 0x63, 0x65, 0x45, 0x56, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, + 0x30, 0x34, 0x30, 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, + 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, + 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3d, 0xd3, 0x50, 0xa5, 0xd6, 0xa0, 0xad, + 0xee, 0xf3, 0x4a, 0x60, 0x0a, 0x65, 0xd3, 0x21, 0xd4, 0xf8, 0xf8, 0xd6, + 0x0f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xb1, 0x3e, 0xc3, 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, + 0x98, 0x26, 0x1a, 0x08, 0x02, 0xef, 0x63, 0x64, 0x2b, 0xc3, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9d, 0xb6, 0xd0, 0x90, 0x86, 0xe1, + 0x86, 0x02, 0xed, 0xc5, 0xa0, 0xf0, 0x34, 0x1c, 0x74, 0xc1, 0x8d, 0x76, + 0xcc, 0x86, 0x0a, 0xa8, 0xf0, 0x4a, 0x8a, 0x42, 0xd6, 0x3f, 0xc8, 0xa9, + 0x4d, 0xad, 0x7c, 0x08, 0xad, 0xe6, 0xb6, 0x50, 0xb8, 0xa2, 0x1a, 0x4d, + 0x88, 0x07, 0xb1, 0x29, 0x21, 0xdc, 0xe7, 0xda, 0xc6, 0x3c, 0x21, 0xe0, + 0xe3, 0x11, 0x49, 0x70, 0xac, 0x7a, 0x1d, 0x01, 0xa4, 0xca, 0x11, 0x3a, + 0x57, 0xab, 0x7d, 0x57, 0x2a, 0x40, 0x74, 0xfd, 0xd3, 0x1d, 0x85, 0x18, + 0x50, 0xdf, 0x57, 0x47, 0x75, 0xa1, 0x7d, 0x55, 0x20, 0x2e, 0x47, 0x37, + 0x50, 0x72, 0x8c, 0x7f, 0x82, 0x1b, 0xd2, 0x62, 0x8f, 0x2d, 0x03, 0x5a, + 0xda, 0xc3, 0xc8, 0xa1, 0xce, 0x2c, 0x52, 0xa2, 0x00, 0x63, 0xeb, 0x73, + 0xba, 0x71, 0xc8, 0x49, 0x27, 0x23, 0x97, 0x64, 0x85, 0x9e, 0x38, 0x0e, + 0xad, 0x63, 0x68, 0x3c, 0xba, 0x52, 0x81, 0x58, 0x79, 0xa3, 0x2c, 0x0c, + 0xdf, 0xde, 0x6d, 0xeb, 0x31, 0xf2, 0xba, 0xa0, 0x7c, 0x6c, 0xf1, 0x2c, + 0xd4, 0xe1, 0xbd, 0x77, 0x84, 0x37, 0x03, 0xce, 0x32, 0xb5, 0xc8, 0x9a, + 0x81, 0x1a, 0x4a, 0x92, 0x4e, 0x3b, 0x46, 0x9a, 0x85, 0xfe, 0x83, 0xa2, + 0xf9, 0x9e, 0x8c, 0xa3, 0xcc, 0x0d, 0x5e, 0xb3, 0x3d, 0xcf, 0x04, 0x78, + 0x8f, 0x14, 0x14, 0x7b, 0x32, 0x9c, 0xc7, 0x00, 0xa6, 0x5c, 0xc4, 0xb5, + 0xa1, 0x55, 0x8d, 0x5a, 0x56, 0x68, 0xa4, 0x22, 0x70, 0xaa, 0x3c, 0x81, + 0x71, 0xd9, 0x9d, 0xa8, 0x45, 0x3b, 0xf4, 0xe5, 0xf6, 0xa2, 0x51, 0xdd, + 0xc7, 0x7b, 0x62, 0xe8, 0x6f, 0x0c, 0x74, 0xeb, 0xb8, 0xda, 0xf8, 0xbf, + 0x87, 0x0d, 0x79, 0x50, 0x91, 0x90, 0x9b, 0x18, 0x3b, 0x91, 0x59, 0x27, + 0xf1, 0x35, 0x28, 0x13, 0xab, 0x26, 0x7e, 0xd5, 0xf7, 0x7a, +} + +var certSet3Cert34 = []byte{ + 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x03, 0xaa, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x36, 0x34, 0x9e, 0x18, 0xc9, 0x9c, 0x26, 0x69, 0xb6, + 0x56, 0x2e, 0x6c, 0xe5, 0xad, 0x71, 0x32, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xae, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x38, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1b, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x33, 0x30, 0x35, 0x32, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x17, 0x0d, 0x32, 0x33, 0x30, 0x35, 0x32, 0x32, 0x32, 0x33, 0x35, 0x39, + 0x35, 0x39, 0x5a, 0x30, 0x43, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x14, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x63, 0x2b, + 0xd4, 0xba, 0x5d, 0x38, 0xae, 0xb0, 0xcf, 0xb9, 0x4c, 0x38, 0xdf, 0x20, + 0x7d, 0xf1, 0x2b, 0x47, 0x71, 0x1d, 0x8b, 0x68, 0xf3, 0x56, 0xf9, 0x9c, + 0xda, 0xaa, 0xe5, 0x84, 0x26, 0xde, 0xa5, 0x71, 0x30, 0xbc, 0xf3, 0x31, + 0x23, 0x9d, 0xe8, 0x3b, 0x80, 0xc8, 0x66, 0x57, 0x75, 0xb6, 0x57, 0x0e, + 0xdb, 0x93, 0xf5, 0x26, 0x8e, 0x70, 0xba, 0x64, 0x52, 0x66, 0x8a, 0x2a, + 0x88, 0x5c, 0x44, 0x18, 0x4d, 0xa8, 0xa2, 0x7c, 0xbd, 0x56, 0x61, 0x32, + 0x90, 0x12, 0xf9, 0x35, 0x87, 0x48, 0x60, 0xb0, 0x6e, 0x90, 0x67, 0x44, + 0x01, 0x8d, 0xe7, 0xc9, 0x0d, 0x63, 0x68, 0x72, 0x72, 0xab, 0x63, 0x3c, + 0x86, 0xb8, 0x1f, 0x7d, 0xad, 0x88, 0x25, 0xa7, 0x6a, 0x88, 0x29, 0xfb, + 0x59, 0xc6, 0x78, 0x71, 0x5f, 0x2c, 0xba, 0x89, 0xe6, 0xd3, 0x80, 0xfd, + 0x57, 0xec, 0xb9, 0x51, 0x5f, 0x43, 0x33, 0x2e, 0x7e, 0x25, 0x3b, 0xa4, + 0x04, 0xd1, 0x60, 0x8c, 0xb3, 0x44, 0x33, 0x93, 0x0c, 0xad, 0x2a, 0xb6, + 0x44, 0xa2, 0x19, 0x3b, 0xaf, 0xc4, 0x90, 0x6f, 0x7b, 0x05, 0x87, 0x86, + 0x9b, 0x2c, 0x6a, 0x9d, 0x2b, 0x6c, 0x77, 0xc9, 0x00, 0x9f, 0xc9, 0xcf, + 0xac, 0xed, 0x3e, 0x1b, 0xf7, 0xc3, 0xf3, 0xd9, 0xf8, 0x6c, 0xd4, 0xa0, + 0x57, 0xc4, 0xfb, 0x28, 0x32, 0xaa, 0x33, 0xf0, 0xe6, 0xba, 0x98, 0xdf, + 0xe5, 0xc2, 0x4e, 0x9c, 0x74, 0xbf, 0x8a, 0x48, 0xc2, 0xf2, 0x1b, 0xf0, + 0x77, 0x40, 0x41, 0x07, 0x04, 0xb2, 0x3a, 0xd5, 0x4c, 0xc4, 0x29, 0xa9, + 0x11, 0x40, 0x3f, 0x02, 0x46, 0xf0, 0x91, 0xd5, 0xd2, 0x81, 0x83, 0x86, + 0x13, 0xb3, 0x31, 0xed, 0x46, 0xab, 0xa8, 0x87, 0x76, 0xa9, 0x99, 0x7d, + 0xbc, 0xcd, 0x31, 0x50, 0xf4, 0xa5, 0xb5, 0xdc, 0xa5, 0x32, 0xb3, 0x8b, + 0x8b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x44, 0x30, 0x82, + 0x01, 0x40, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x41, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3a, 0x30, + 0x38, 0x30, 0x36, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, + 0x01, 0x07, 0x36, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x37, 0x06, + 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x30, 0x30, 0x2e, 0x30, 0x2c, 0xa0, 0x2a, + 0xa0, 0x28, 0x86, 0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, 0x2d, + 0x47, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2a, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x23, 0x30, 0x21, 0xa4, 0x1f, 0x30, + 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, + 0x2d, 0x32, 0x2d, 0x34, 0x31, 0x35, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2b, 0x9a, 0x35, 0xae, 0x01, 0x18, 0x38, + 0x30, 0xe1, 0x70, 0x7a, 0x05, 0xe0, 0x11, 0x76, 0xa3, 0xce, 0xbd, 0x90, + 0x14, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0xad, 0x6c, 0xaa, 0x94, 0x60, 0x9c, 0xed, 0xe4, 0xff, 0xfa, + 0x3e, 0x0a, 0x74, 0x2b, 0x63, 0x03, 0xf7, 0xb6, 0x59, 0xbf, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x74, 0xa6, 0x56, 0xe8, 0xaf, 0x93, + 0x96, 0x19, 0xfb, 0x26, 0xf9, 0x0d, 0xb0, 0x44, 0xa5, 0xcd, 0xe9, 0x7a, + 0x48, 0x03, 0x74, 0x01, 0x6c, 0x13, 0x71, 0xb7, 0xe0, 0x82, 0x90, 0x99, + 0x62, 0x23, 0xe3, 0xd6, 0x99, 0xaf, 0xf0, 0xc7, 0x1e, 0x9e, 0xa8, 0x18, + 0x21, 0xdb, 0xb4, 0x94, 0x3f, 0x34, 0x56, 0x1b, 0x99, 0x55, 0x2f, 0x8e, + 0xf0, 0x45, 0x33, 0x32, 0xb7, 0x72, 0xc1, 0x13, 0x5b, 0x34, 0xd3, 0xf5, + 0x60, 0xe5, 0x2e, 0x18, 0xd1, 0x5c, 0xc5, 0x6a, 0xc1, 0xaa, 0x87, 0x50, + 0x0c, 0x1c, 0x9d, 0x64, 0x2b, 0xff, 0x1b, 0xdc, 0xd5, 0x2e, 0x61, 0x0b, + 0xe7, 0xb9, 0xb6, 0x91, 0x53, 0x86, 0xd9, 0x03, 0x2a, 0xd1, 0x3d, 0x7b, + 0x4a, 0xda, 0x2b, 0x07, 0xbe, 0x29, 0xf2, 0x60, 0x42, 0xa9, 0x91, 0x1a, + 0x0e, 0x2e, 0x3c, 0xd1, 0x7d, 0xa5, 0x13, 0x14, 0x02, 0xfa, 0xee, 0x8b, + 0x8d, 0xb6, 0xc8, 0xb8, 0x3e, 0x56, 0x81, 0x57, 0x21, 0x24, 0x3f, 0x65, + 0xc3, 0xb4, 0xc9, 0xce, 0x5c, 0x8d, 0x46, 0xac, 0x53, 0xf3, 0xf9, 0x55, + 0x74, 0xc8, 0x2b, 0xfd, 0xd2, 0x78, 0x70, 0xf5, 0xf8, 0x11, 0xe5, 0xf4, + 0xa7, 0xad, 0x20, 0xf5, 0x9d, 0xf1, 0xec, 0x70, 0xf6, 0x13, 0xac, 0xe6, + 0x8c, 0x8d, 0xdb, 0x3f, 0xc6, 0xf2, 0x79, 0x0e, 0xab, 0x52, 0xf2, 0xcc, + 0x1b, 0x79, 0x27, 0xcf, 0x16, 0xb3, 0xd6, 0xf3, 0xc6, 0x36, 0x80, 0x43, + 0xec, 0xc5, 0x94, 0xf0, 0xdd, 0x90, 0x8d, 0xf8, 0xc6, 0x52, 0x46, 0x56, + 0xeb, 0x74, 0x47, 0xbe, 0xa6, 0xf3, 0x19, 0xae, 0x71, 0x4c, 0xc0, 0xe1, + 0xe7, 0xd4, 0xcf, 0xed, 0xd4, 0x06, 0x28, 0x2a, 0x11, 0x3c, 0xba, 0xd9, + 0x41, 0x6e, 0x00, 0xe7, 0x81, 0x37, 0x93, 0xe4, 0xda, 0x62, 0xc6, 0x1d, + 0x67, 0x6f, 0x63, 0xb4, 0x14, 0x86, 0xd9, 0xa6, 0x62, 0xf0, +} + +var certSet3Cert35 = []byte{ + 0x30, 0x82, 0x04, 0xc7, 0x30, 0x82, 0x03, 0xaf, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x41, 0x82, 0x12, 0x7d, 0x12, 0xd9, 0xc6, 0xb3, 0x21, + 0x39, 0x43, 0x12, 0x56, 0x64, 0x00, 0xb8, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x33, 0x30, 0x35, 0x32, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x35, 0x32, 0x32, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x46, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x47, 0x65, 0x6f, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x53, + 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xc6, 0xa9, 0x0b, 0x5d, 0x17, 0xa5, 0x7d, 0xc6, 0xcf, 0x2a, + 0xef, 0xc6, 0x66, 0xd1, 0x42, 0x1e, 0x5f, 0x83, 0x78, 0x68, 0x91, 0xaf, + 0xe6, 0xa7, 0x8b, 0xf0, 0x1d, 0x44, 0x01, 0x0a, 0x19, 0xca, 0x9c, 0xd4, + 0x8b, 0x1d, 0xe1, 0xa1, 0x90, 0xa3, 0xc1, 0x5b, 0xb4, 0xd7, 0x5b, 0x6a, + 0x8b, 0xfc, 0x0e, 0x49, 0x1e, 0xc2, 0x62, 0x29, 0xfe, 0x80, 0x15, 0x39, + 0x8b, 0x81, 0x2a, 0x27, 0xb5, 0xfb, 0x12, 0xa8, 0x05, 0x22, 0x0b, 0xc5, + 0x2c, 0xf5, 0xd9, 0x98, 0xdd, 0x16, 0x2f, 0x3b, 0x66, 0xe7, 0x62, 0xa2, + 0x43, 0x32, 0xac, 0x8f, 0xb5, 0x85, 0xc8, 0x52, 0x06, 0x2c, 0x5c, 0xc0, + 0x77, 0xfa, 0x67, 0xf7, 0x83, 0xe8, 0x5e, 0x05, 0x8d, 0xc8, 0xab, 0xa1, + 0x16, 0x32, 0x8a, 0xd2, 0x40, 0xec, 0x86, 0x3a, 0x1c, 0x23, 0xa9, 0x8d, + 0xb5, 0x00, 0xde, 0x72, 0xbd, 0x85, 0x55, 0xfe, 0x06, 0x01, 0x60, 0x5d, + 0xad, 0xb3, 0xe0, 0x65, 0x73, 0xa5, 0x92, 0x14, 0x9e, 0x94, 0x56, 0x6f, + 0x93, 0xee, 0xaf, 0xa9, 0x3a, 0x30, 0x25, 0x4a, 0x8e, 0x09, 0x84, 0xef, + 0xb7, 0xd2, 0xd5, 0xd7, 0x9b, 0x49, 0xcd, 0xe9, 0xc0, 0x5e, 0x67, 0x71, + 0x22, 0xac, 0x50, 0x90, 0x43, 0x20, 0x5d, 0xa1, 0xa3, 0x15, 0x83, 0xfd, + 0xfc, 0xa7, 0x39, 0xbc, 0x6b, 0x65, 0x48, 0x12, 0x60, 0xff, 0xdd, 0x23, + 0xb3, 0x3a, 0xaa, 0xf4, 0x9f, 0x9c, 0x37, 0x53, 0x41, 0xa2, 0x47, 0x93, + 0x81, 0x33, 0x09, 0xe5, 0x22, 0xc6, 0xc8, 0x1c, 0x49, 0xa1, 0x6e, 0x8d, + 0xcc, 0x83, 0xb3, 0x9a, 0xcd, 0xea, 0x43, 0xf2, 0x19, 0xd3, 0x24, 0xcb, + 0xa8, 0x29, 0xae, 0x52, 0xcc, 0xf4, 0x08, 0x27, 0xb0, 0x84, 0xea, 0xce, + 0x27, 0xb5, 0xe1, 0x34, 0x13, 0x73, 0x92, 0x5c, 0x87, 0x86, 0x2a, 0xc6, + 0xb0, 0x68, 0x36, 0xad, 0xcb, 0x09, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x82, 0x01, 0x5c, 0x30, 0x82, 0x01, 0x58, 0x30, 0x3b, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2f, 0x30, 0x2d, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, + 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x63, 0x61, 0x2d, + 0x67, 0x33, 0x2d, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x65, 0x6f, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, + 0xff, 0x02, 0x01, 0x00, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, + 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, 0x33, 0x30, 0x31, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x3b, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0xa0, + 0x2e, 0xa0, 0x2c, 0x86, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x50, 0x43, 0x41, 0x2d, 0x47, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x23, + 0x30, 0x21, 0xa4, 0x1f, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x12, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, + 0x6e, 0x4d, 0x50, 0x4b, 0x49, 0x2d, 0x32, 0x2d, 0x34, 0x31, 0x36, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x14, 0x67, + 0x8e, 0xed, 0x83, 0x4f, 0xd6, 0x1e, 0x9d, 0x40, 0x04, 0x0c, 0x04, 0x46, + 0xa1, 0x70, 0x34, 0xb2, 0x0f, 0x72, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc4, 0x79, 0xca, 0x8e, 0xa1, + 0x4e, 0x03, 0x1d, 0x1c, 0xdc, 0x6b, 0xdb, 0x31, 0x5b, 0x94, 0x3e, 0x3f, + 0x30, 0x7f, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x10, + 0x10, 0xea, 0xf2, 0x10, 0xd6, 0x08, 0x46, 0xe2, 0xc1, 0x8f, 0x3e, 0x36, + 0x59, 0xc8, 0x2b, 0x0f, 0xfe, 0x4d, 0xec, 0xe3, 0xf8, 0xb6, 0x56, 0x31, + 0x78, 0x25, 0xd4, 0x76, 0xf2, 0x08, 0xdd, 0xef, 0x3f, 0xcd, 0x8b, 0x1c, + 0x7e, 0xaa, 0x7f, 0xfc, 0x0b, 0xa8, 0x23, 0x64, 0x51, 0xb3, 0x87, 0xd6, + 0x09, 0xfa, 0x22, 0xfa, 0xc7, 0x0a, 0x51, 0xe8, 0xce, 0xb8, 0xf6, 0x03, + 0x70, 0xe0, 0x1b, 0x5a, 0xb9, 0xb1, 0xb2, 0x93, 0x11, 0x10, 0xf9, 0x97, + 0x05, 0x07, 0x29, 0x6c, 0x6d, 0x57, 0x25, 0x54, 0xe8, 0xf9, 0x66, 0x9b, + 0x0e, 0xfb, 0xdb, 0x9f, 0xee, 0x96, 0x6f, 0x65, 0xcb, 0x1f, 0xd8, 0x55, + 0xce, 0x31, 0xfa, 0xcf, 0x02, 0xf4, 0xd0, 0x7f, 0x50, 0x66, 0xff, 0x2f, + 0x79, 0x9b, 0xa5, 0xc2, 0xdf, 0xd6, 0xcf, 0xc8, 0x15, 0x83, 0x96, 0x84, + 0x98, 0xb2, 0x46, 0xd4, 0x5f, 0x13, 0xa8, 0x3e, 0xa7, 0x34, 0x9c, 0x05, + 0x38, 0xda, 0xcf, 0xd6, 0x69, 0x95, 0xa9, 0x26, 0x87, 0x76, 0x01, 0xd7, + 0xb2, 0x51, 0x0f, 0x81, 0x69, 0x46, 0x26, 0x1c, 0x99, 0xb6, 0x83, 0x58, + 0xe3, 0x3b, 0x58, 0x8f, 0xdc, 0xb4, 0x71, 0xc0, 0xb9, 0xbf, 0x42, 0x9c, + 0x1c, 0x03, 0x9e, 0xe4, 0x46, 0xa8, 0xea, 0xb9, 0xc1, 0xcd, 0xf6, 0x5b, + 0xa9, 0x3c, 0x96, 0xfb, 0x79, 0xa4, 0x33, 0x73, 0xa7, 0x9e, 0x78, 0xb9, + 0x70, 0xdc, 0x72, 0x74, 0xc4, 0x32, 0xc8, 0x00, 0x1b, 0xc9, 0xef, 0x48, + 0xd3, 0xfb, 0x3a, 0x9b, 0xfa, 0xfe, 0x7a, 0x9a, 0x40, 0x69, 0x1c, 0xc8, + 0xda, 0x28, 0x37, 0x0b, 0xd3, 0xa3, 0xb9, 0x7e, 0x96, 0xcc, 0x2b, 0x28, + 0xc3, 0x56, 0x6c, 0x6f, 0xe9, 0xdb, 0x52, 0xb1, 0xfa, 0x9a, 0xfb, 0xe7, + 0xaf, 0xb5, 0x97, 0xa6, 0x22, 0xc3, 0xc5, 0xa8, 0x93, 0xb1, 0x00, 0xc9, + 0x07, 0xb2, 0x7d, +} + +var certSet3Cert36 = []byte{ + 0x30, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x03, 0xb8, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x83, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, + 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, + 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x28, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, + 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x81, 0xb4, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, + 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, + 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, + 0x72, 0x74, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x2f, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x2a, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xb9, 0xe0, 0xcb, 0x10, 0xd4, 0xaf, 0x76, + 0xbd, 0xd4, 0x93, 0x62, 0xeb, 0x30, 0x64, 0xb8, 0x81, 0x08, 0x6c, 0xc3, + 0x04, 0xd9, 0x62, 0x17, 0x8e, 0x2f, 0xff, 0x3e, 0x65, 0xcf, 0x8f, 0xce, + 0x62, 0xe6, 0x3c, 0x52, 0x1c, 0xda, 0x16, 0x45, 0x4b, 0x55, 0xab, 0x78, + 0x6b, 0x63, 0x83, 0x62, 0x90, 0xce, 0x0f, 0x69, 0x6c, 0x99, 0xc8, 0x1a, + 0x14, 0x8b, 0x4c, 0xcc, 0x45, 0x33, 0xea, 0x88, 0xdc, 0x9e, 0xa3, 0xaf, + 0x2b, 0xfe, 0x80, 0x61, 0x9d, 0x79, 0x57, 0xc4, 0xcf, 0x2e, 0xf4, 0x3f, + 0x30, 0x3c, 0x5d, 0x47, 0xfc, 0x9a, 0x16, 0xbc, 0xc3, 0x37, 0x96, 0x41, + 0x51, 0x8e, 0x11, 0x4b, 0x54, 0xf8, 0x28, 0xbe, 0xd0, 0x8c, 0xbe, 0xf0, + 0x30, 0x38, 0x1e, 0xf3, 0xb0, 0x26, 0xf8, 0x66, 0x47, 0x63, 0x6d, 0xde, + 0x71, 0x26, 0x47, 0x8f, 0x38, 0x47, 0x53, 0xd1, 0x46, 0x1d, 0xb4, 0xe3, + 0xdc, 0x00, 0xea, 0x45, 0xac, 0xbd, 0xbc, 0x71, 0xd9, 0xaa, 0x6f, 0x00, + 0xdb, 0xdb, 0xcd, 0x30, 0x3a, 0x79, 0x4f, 0x5f, 0x4c, 0x47, 0xf8, 0x1d, + 0xef, 0x5b, 0xc2, 0xc4, 0x9d, 0x60, 0x3b, 0xb1, 0xb2, 0x43, 0x91, 0xd8, + 0xa4, 0x33, 0x4e, 0xea, 0xb3, 0xd6, 0x27, 0x4f, 0xad, 0x25, 0x8a, 0xa5, + 0xc6, 0xf4, 0xd5, 0xd0, 0xa6, 0xae, 0x74, 0x05, 0x64, 0x57, 0x88, 0xb5, + 0x44, 0x55, 0xd4, 0x2d, 0x2a, 0x3a, 0x3e, 0xf8, 0xb8, 0xbd, 0xe9, 0x32, + 0x0a, 0x02, 0x94, 0x64, 0xc4, 0x16, 0x3a, 0x50, 0xf1, 0x4a, 0xae, 0xe7, + 0x79, 0x33, 0xaf, 0x0c, 0x20, 0x07, 0x7f, 0xe8, 0xdf, 0x04, 0x39, 0xc2, + 0x69, 0x02, 0x6c, 0x63, 0x52, 0xfa, 0x77, 0xc1, 0x1b, 0xc8, 0x74, 0x87, + 0xc8, 0xb9, 0x93, 0x18, 0x50, 0x54, 0x35, 0x4b, 0x69, 0x4e, 0xbc, 0x3b, + 0xd3, 0x49, 0x2e, 0x1f, 0xdc, 0xc1, 0xd2, 0x52, 0xfb, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1a, 0x30, 0x82, 0x01, 0x16, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x40, 0xc2, 0xbd, 0x27, 0x8e, 0xcc, + 0x34, 0x83, 0x30, 0xa2, 0x33, 0xd7, 0xfb, 0x6c, 0xb3, 0xf0, 0xb4, 0x2c, + 0x80, 0xce, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x3a, 0x9a, 0x85, 0x07, 0x10, 0x67, 0x28, 0xb6, 0xef, + 0xf6, 0xbd, 0x05, 0x41, 0x6e, 0x20, 0xc1, 0x94, 0xda, 0x0f, 0xde, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, + 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, + 0x64, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x67, 0x32, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, + 0x3b, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x33, 0x30, 0x31, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, + 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x08, 0x7e, 0x6c, 0x93, + 0x10, 0xc8, 0x38, 0xb8, 0x96, 0xa9, 0x90, 0x4b, 0xff, 0xa1, 0x5f, 0x4f, + 0x04, 0xef, 0x6c, 0x3e, 0x9c, 0x88, 0x06, 0xc9, 0x50, 0x8f, 0xa6, 0x73, + 0xf7, 0x57, 0x31, 0x1b, 0xbe, 0xbc, 0xe4, 0x2f, 0xdb, 0xf8, 0xba, 0xd3, + 0x5b, 0xe0, 0xb4, 0xe7, 0xe6, 0x79, 0x62, 0x0e, 0x0c, 0xa2, 0xd7, 0x6a, + 0x63, 0x73, 0x31, 0xb5, 0xf5, 0xa8, 0x48, 0xa4, 0x3b, 0x08, 0x2d, 0xa2, + 0x5d, 0x90, 0xd7, 0xb4, 0x7c, 0x25, 0x4f, 0x11, 0x56, 0x30, 0xc4, 0xb6, + 0x44, 0x9d, 0x7b, 0x2c, 0x9d, 0xe5, 0x5e, 0xe6, 0xef, 0x0c, 0x61, 0xaa, + 0xbf, 0xe4, 0x2a, 0x1b, 0xee, 0x84, 0x9e, 0xb8, 0x83, 0x7d, 0xc1, 0x43, + 0xce, 0x44, 0xa7, 0x13, 0x70, 0x0d, 0x91, 0x1f, 0xf4, 0xc8, 0x13, 0xad, + 0x83, 0x60, 0xd9, 0xd8, 0x72, 0xa8, 0x73, 0x24, 0x1e, 0xb5, 0xac, 0x22, + 0x0e, 0xca, 0x17, 0x89, 0x62, 0x58, 0x44, 0x1b, 0xab, 0x89, 0x25, 0x01, + 0x00, 0x0f, 0xcd, 0xc4, 0x1b, 0x62, 0xdb, 0x51, 0xb4, 0xd3, 0x0f, 0x51, + 0x2a, 0x9b, 0xf4, 0xbc, 0x73, 0xfc, 0x76, 0xce, 0x36, 0xa4, 0xcd, 0xd9, + 0xd8, 0x2c, 0xea, 0xae, 0x9b, 0xf5, 0x2a, 0xb2, 0x90, 0xd1, 0x4d, 0x75, + 0x18, 0x8a, 0x3f, 0x8a, 0x41, 0x90, 0x23, 0x7d, 0x5b, 0x4b, 0xfe, 0xa4, + 0x03, 0x58, 0x9b, 0x46, 0xb2, 0xc3, 0x60, 0x60, 0x83, 0xf8, 0x7d, 0x50, + 0x41, 0xce, 0xc2, 0xa1, 0x90, 0xc3, 0xbb, 0xef, 0x02, 0x2f, 0xd2, 0x15, + 0x54, 0xee, 0x44, 0x15, 0xd9, 0x0a, 0xae, 0xa7, 0x8a, 0x33, 0xed, 0xb1, + 0x2d, 0x76, 0x36, 0x26, 0xdc, 0x04, 0xeb, 0x9f, 0xf7, 0x61, 0x1f, 0x15, + 0xdc, 0x87, 0x6f, 0xee, 0x46, 0x96, 0x28, 0xad, 0xa1, 0x26, 0x7d, 0x0a, + 0x09, 0xa7, 0x2e, 0x04, 0xa3, 0x8d, 0xbc, 0xf8, 0xbc, 0x04, 0x30, 0x01, +} + +var certSet3Cert37 = []byte{ + 0x30, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x04, 0x39, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x25, 0x0c, 0xe8, 0xe0, 0x30, 0x61, 0x2e, 0x9f, 0x2b, + 0x89, 0xf7, 0x05, 0x4d, 0x7c, 0xf8, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x30, 0x38, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x30, 0x37, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xca, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3a, 0x30, + 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, 0x63, 0x29, 0x20, + 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, + 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, + 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x45, 0x30, + 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, 0x24, 0x08, 0x08, 0x29, 0x7a, 0x35, + 0x9e, 0x60, 0x0c, 0xaa, 0xe7, 0x4b, 0x3b, 0x4e, 0xdc, 0x7c, 0xbc, 0x3c, + 0x45, 0x1c, 0xbb, 0x2b, 0xe0, 0xfe, 0x29, 0x02, 0xf9, 0x57, 0x08, 0xa3, + 0x64, 0x85, 0x15, 0x27, 0xf5, 0xf1, 0xad, 0xc8, 0x31, 0x89, 0x5d, 0x22, + 0xe8, 0x2a, 0xaa, 0xa6, 0x42, 0xb3, 0x8f, 0xf8, 0xb9, 0x55, 0xb7, 0xb1, + 0xb7, 0x4b, 0xb3, 0xfe, 0x8f, 0x7e, 0x07, 0x57, 0xec, 0xef, 0x43, 0xdb, + 0x66, 0x62, 0x15, 0x61, 0xcf, 0x60, 0x0d, 0xa4, 0xd8, 0xde, 0xf8, 0xe0, + 0xc3, 0x62, 0x08, 0x3d, 0x54, 0x13, 0xeb, 0x49, 0xca, 0x59, 0x54, 0x85, + 0x26, 0xe5, 0x2b, 0x8f, 0x1b, 0x9f, 0xeb, 0xf5, 0xa1, 0x91, 0xc2, 0x33, + 0x49, 0xd8, 0x43, 0x63, 0x6a, 0x52, 0x4b, 0xd2, 0x8f, 0xe8, 0x70, 0x51, + 0x4d, 0xd1, 0x89, 0x69, 0x7b, 0xc7, 0x70, 0xf6, 0xb3, 0xdc, 0x12, 0x74, + 0xdb, 0x7b, 0x5d, 0x4b, 0x56, 0xd3, 0x96, 0xbf, 0x15, 0x77, 0xa1, 0xb0, + 0xf4, 0xa2, 0x25, 0xf2, 0xaf, 0x1c, 0x92, 0x67, 0x18, 0xe5, 0xf4, 0x06, + 0x04, 0xef, 0x90, 0xb9, 0xe4, 0x00, 0xe4, 0xdd, 0x3a, 0xb5, 0x19, 0xff, + 0x02, 0xba, 0xf4, 0x3c, 0xee, 0xe0, 0x8b, 0xeb, 0x37, 0x8b, 0xec, 0xf4, + 0xd7, 0xac, 0xf2, 0xf6, 0xf0, 0x3d, 0xaf, 0xdd, 0x75, 0x91, 0x33, 0x19, + 0x1d, 0x1c, 0x40, 0xcb, 0x74, 0x24, 0x19, 0x21, 0x93, 0xd9, 0x14, 0xfe, + 0xac, 0x2a, 0x52, 0xc7, 0x8f, 0xd5, 0x04, 0x49, 0xe4, 0x8d, 0x63, 0x47, + 0x88, 0x3c, 0x69, 0x83, 0xcb, 0xfe, 0x47, 0xbd, 0x2b, 0x7e, 0x4f, 0xc5, + 0x95, 0xae, 0x0e, 0x9d, 0xd4, 0xd1, 0x43, 0xc0, 0x67, 0x73, 0xe3, 0x14, + 0x08, 0x7e, 0xe5, 0x3f, 0x9f, 0x73, 0xb8, 0x33, 0x0a, 0xcf, 0x5d, 0x3f, + 0x34, 0x87, 0x96, 0x8a, 0xee, 0x53, 0xe8, 0x25, 0x15, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x9b, 0x30, 0x82, 0x01, 0x97, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xff, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, + 0x30, 0x28, 0x30, 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, + 0x61, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, + 0x73, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x6d, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c, 0x04, 0x61, 0x30, 0x5f, + 0xa1, 0x5d, 0xa0, 0x5b, 0x30, 0x59, 0x30, 0x57, 0x30, 0x55, 0x16, 0x09, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, + 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, + 0x8f, 0xe5, 0xd3, 0x1a, 0x86, 0xac, 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80, + 0x6a, 0xd4, 0x48, 0x18, 0x2c, 0x7b, 0x19, 0x2e, 0x30, 0x25, 0x16, 0x23, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x76, 0x73, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, + 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x1d, 0x25, + 0x04, 0x37, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, 0x06, 0x0a, 0x60, + 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x08, 0x01, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x13, 0x02, 0xdd, 0xf8, 0xe8, 0x86, 0x00, 0xf2, + 0x5a, 0xf8, 0xf8, 0x20, 0x0c, 0x59, 0x88, 0x62, 0x07, 0xce, 0xce, 0xf7, + 0x4e, 0xf9, 0xbb, 0x59, 0xa1, 0x98, 0xe5, 0xe1, 0x38, 0xdd, 0x4e, 0xbc, + 0x66, 0x18, 0xd3, 0xad, 0xeb, 0x18, 0xf2, 0x0d, 0xc9, 0x6d, 0x3e, 0x4a, + 0x94, 0x20, 0xc3, 0x3c, 0xba, 0xbd, 0x65, 0x54, 0xc6, 0xaf, 0x44, 0xb3, + 0x10, 0xad, 0x2c, 0x6b, 0x3e, 0xab, 0xd7, 0x07, 0xb6, 0xb8, 0x81, 0x63, + 0xc5, 0xf9, 0x5e, 0x2e, 0xe5, 0x2a, 0x67, 0xce, 0xcd, 0x33, 0x0c, 0x2a, + 0xd7, 0x89, 0x56, 0x03, 0x23, 0x1f, 0xb3, 0xbe, 0xe8, 0x3a, 0x08, 0x59, + 0xb4, 0xec, 0x45, 0x35, 0xf7, 0x8a, 0x5b, 0xff, 0x66, 0xcf, 0x50, 0xaf, + 0xc6, 0x6d, 0x57, 0x8d, 0x19, 0x78, 0xb7, 0xb9, 0xa2, 0xd1, 0x57, 0xea, + 0x1f, 0x9a, 0x4b, 0xaf, 0xba, 0xc9, 0x8e, 0x12, 0x7e, 0xc6, 0xbd, 0xff, +} + +var certSet3Cert38 = []byte{ + 0x30, 0x82, 0x04, 0xd2, 0x30, 0x82, 0x03, 0xba, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x2c, 0x69, 0xe1, 0x2f, 0x6a, 0x67, 0x0b, 0xd9, 0x9d, + 0xd2, 0x0f, 0x91, 0x9e, 0xf0, 0x9e, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, 0x38, 0x30, 0x36, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x16, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, + 0x36, 0x30, 0x39, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x63, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x14, 0x44, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x20, 0x53, 0x53, 0x4c, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x20, 0x44, 0x56, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xea, 0x94, 0x07, 0x85, 0xc8, 0x41, 0x2c, 0xf6, 0x83, 0x12, 0x6c, 0x92, + 0x5f, 0xab, 0x1f, 0x00, 0xd4, 0x96, 0x6f, 0x74, 0xcd, 0x2e, 0x11, 0xe9, + 0x6c, 0x0f, 0x39, 0x01, 0xb9, 0x48, 0x90, 0x40, 0x39, 0x4d, 0xc4, 0xa2, + 0xc8, 0x79, 0x6a, 0xa5, 0x9a, 0xbd, 0x91, 0x44, 0x65, 0x77, 0x54, 0xad, + 0xff, 0x25, 0x5f, 0xee, 0x42, 0xfb, 0xb3, 0x02, 0x0f, 0xea, 0x5d, 0x7a, + 0xdd, 0x1a, 0x54, 0x9e, 0xd7, 0x73, 0x42, 0x9b, 0xcc, 0x79, 0x5f, 0xc5, + 0x4d, 0xf4, 0xb7, 0x0b, 0x18, 0x39, 0x20, 0x7a, 0xdd, 0x50, 0x01, 0x5d, + 0x34, 0x45, 0x5f, 0x4c, 0x11, 0x0e, 0xf5, 0x87, 0x26, 0x26, 0xb4, 0xb0, + 0xf3, 0x7e, 0x71, 0xa0, 0x31, 0x71, 0x50, 0x89, 0x68, 0x5a, 0x63, 0x8a, + 0x14, 0x62, 0xe5, 0x8c, 0x3a, 0x16, 0x55, 0x0d, 0x3e, 0xeb, 0xaa, 0x80, + 0x1d, 0x71, 0x7a, 0xe3, 0x87, 0x07, 0xab, 0xbd, 0xa2, 0x74, 0xcd, 0xda, + 0x08, 0x01, 0x9d, 0x1b, 0xcc, 0x27, 0x88, 0x8c, 0x47, 0xd4, 0x69, 0x25, + 0x42, 0xd6, 0xbb, 0x50, 0x6d, 0x85, 0x50, 0xd0, 0x48, 0x82, 0x0d, 0x08, + 0x9f, 0xe9, 0x23, 0xe3, 0x42, 0xc6, 0x3c, 0x98, 0xb8, 0xbb, 0x6e, 0xc5, + 0x70, 0x13, 0xdf, 0x19, 0x1d, 0x01, 0xfd, 0xd2, 0xb5, 0x4e, 0xe6, 0x62, + 0xf4, 0x07, 0xfa, 0x6b, 0x7d, 0x11, 0x77, 0xc4, 0x62, 0x4f, 0x40, 0x4e, + 0xa5, 0x78, 0x97, 0xab, 0x2c, 0x4d, 0x0c, 0xa7, 0x7c, 0xc3, 0xc4, 0x50, + 0x32, 0x9f, 0xd0, 0x70, 0x9b, 0x0f, 0xff, 0xff, 0x75, 0x59, 0x34, 0x85, + 0xad, 0x49, 0xd5, 0x35, 0xee, 0x4f, 0x5b, 0xd4, 0xd4, 0x36, 0x95, 0xa0, + 0x7e, 0xe8, 0xc5, 0xa1, 0x1c, 0xbd, 0x13, 0x4e, 0x7d, 0xee, 0x63, 0x6a, + 0x96, 0x19, 0x99, 0xc8, 0xa7, 0x2a, 0x00, 0xe6, 0x51, 0x8d, 0x46, 0xeb, + 0x30, 0x58, 0xe8, 0x2d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x39, 0x30, 0x82, 0x01, 0x35, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x41, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3a, 0x30, 0x38, + 0x30, 0x36, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, + 0x07, 0x36, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, + 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x74, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, 0x30, 0x28, 0x30, + 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x74, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x50, 0x43, 0x41, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x29, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, + 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, + 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, 0x36, 0x39, 0x38, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9f, 0xb8, 0xc1, + 0xa9, 0x6c, 0xf2, 0xf5, 0xc0, 0x22, 0x2a, 0x94, 0xed, 0x5c, 0x99, 0xac, + 0xd4, 0xec, 0xd7, 0xc6, 0x07, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7b, 0x5b, 0x45, 0xcf, 0xaf, 0xce, + 0xcb, 0x7a, 0xfd, 0x31, 0x92, 0x1a, 0x6a, 0xb6, 0xf3, 0x46, 0xeb, 0x57, + 0x48, 0x50, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x53, 0x54, + 0xf2, 0x47, 0xa8, 0x02, 0xd7, 0xef, 0xaa, 0x35, 0x78, 0xbe, 0x4a, 0x08, + 0x0d, 0x90, 0x18, 0x4b, 0x6d, 0x9e, 0x2a, 0x53, 0x2b, 0xe9, 0x54, 0x17, + 0x77, 0x74, 0x29, 0x7e, 0xd0, 0x37, 0x07, 0x05, 0xb8, 0xe4, 0xfa, 0xb8, + 0xb4, 0x63, 0x98, 0x44, 0xdc, 0xc6, 0x4f, 0x81, 0x06, 0x8c, 0x3a, 0xbe, + 0xc7, 0x30, 0x57, 0xc6, 0x70, 0xfc, 0xd6, 0x93, 0x19, 0x9f, 0xc3, 0x55, + 0xd7, 0x3e, 0x1f, 0x72, 0x8a, 0x9d, 0x30, 0x5a, 0x35, 0x97, 0x32, 0xcb, + 0x63, 0xe4, 0xc6, 0x72, 0xdf, 0xfb, 0x68, 0xca, 0x69, 0x2f, 0xdb, 0xcd, + 0x50, 0x38, 0x3e, 0x2b, 0xbb, 0xab, 0x3b, 0x82, 0xc7, 0xfd, 0x4b, 0x9b, + 0xbd, 0x7c, 0x41, 0x98, 0xef, 0x01, 0x53, 0xd8, 0x35, 0x8f, 0x25, 0xc9, + 0x03, 0x06, 0xe6, 0x9c, 0x57, 0xc1, 0x51, 0x0f, 0x9e, 0xf6, 0x7d, 0x93, + 0x4d, 0xf8, 0x76, 0xc8, 0x3a, 0x6b, 0xf4, 0xc4, 0x8f, 0x33, 0x32, 0x7f, + 0x9d, 0x21, 0x84, 0x34, 0xd9, 0xa7, 0xf9, 0x92, 0xfa, 0x41, 0x91, 0x61, + 0x84, 0x05, 0x9d, 0xa3, 0x79, 0x46, 0xce, 0x67, 0xe7, 0x81, 0xf2, 0x5e, + 0xac, 0x4c, 0xbc, 0xa8, 0xab, 0x6a, 0x6d, 0x15, 0xe2, 0x9c, 0x4e, 0x5a, + 0xd9, 0x63, 0x80, 0xbc, 0xf7, 0x42, 0xeb, 0x9a, 0x44, 0xc6, 0x8c, 0x6b, + 0x06, 0x36, 0xb4, 0x8b, 0x32, 0x89, 0xde, 0xc2, 0xf1, 0xa8, 0x26, 0xaa, + 0xa9, 0xac, 0xff, 0xea, 0x71, 0xa6, 0xe7, 0x8c, 0x41, 0xfa, 0x17, 0x35, + 0xbb, 0xb3, 0x87, 0x31, 0xa9, 0x93, 0xc2, 0xc8, 0x58, 0xe1, 0x0a, 0x4e, + 0x95, 0x83, 0x9c, 0xb9, 0xed, 0x3b, 0xa5, 0xef, 0x08, 0xe0, 0x74, 0xf9, + 0xc3, 0x1b, 0xe6, 0x07, 0xa3, 0xee, 0x07, 0xd7, 0x42, 0x22, 0x79, 0x21, + 0xa0, 0xa1, 0xd4, 0x1d, 0x26, 0xd3, 0xd0, 0xd6, 0xa6, 0x5d, 0x2b, 0x41, + 0xc0, 0x79, +} + +var certSet3Cert39 = []byte{ + 0x30, 0x82, 0x04, 0xff, 0x30, 0x82, 0x03, 0xe7, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x51, 0xd3, 0x40, 0x44, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xb0, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x30, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, 0x73, 0x20, + 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, + 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x45, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2d, + 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x45, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x34, 0x30, 0x39, 0x32, 0x32, 0x31, 0x37, 0x31, 0x34, 0x35, + 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x39, 0x32, 0x33, 0x30, 0x31, + 0x33, 0x31, 0x35, 0x33, 0x5a, 0x30, 0x81, 0xbe, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, + 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, 0x30, + 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, + 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, + 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x29, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xba, 0x84, 0xb6, 0x72, 0xdb, 0x9e, 0x0c, 0x6b, 0xe2, + 0x99, 0xe9, 0x30, 0x01, 0xa7, 0x76, 0xea, 0x32, 0xb8, 0x95, 0x41, 0x1a, + 0xc9, 0xda, 0x61, 0x4e, 0x58, 0x72, 0xcf, 0xfe, 0xf6, 0x82, 0x79, 0xbf, + 0x73, 0x61, 0x06, 0x0a, 0xa5, 0x27, 0xd8, 0xb3, 0x5f, 0xd3, 0x45, 0x4e, + 0x1c, 0x72, 0xd6, 0x4e, 0x32, 0xf2, 0x72, 0x8a, 0x0f, 0xf7, 0x83, 0x19, + 0xd0, 0x6a, 0x80, 0x80, 0x00, 0x45, 0x1e, 0xb0, 0xc7, 0xe7, 0x9a, 0xbf, + 0x12, 0x57, 0x27, 0x1c, 0xa3, 0x68, 0x2f, 0x0a, 0x87, 0xbd, 0x6a, 0x6b, + 0x0e, 0x5e, 0x65, 0xf3, 0x1c, 0x77, 0xd5, 0xd4, 0x85, 0x8d, 0x70, 0x21, + 0xb4, 0xb3, 0x32, 0xe7, 0x8b, 0xa2, 0xd5, 0x86, 0x39, 0x02, 0xb1, 0xb8, + 0xd2, 0x47, 0xce, 0xe4, 0xc9, 0x49, 0xc4, 0x3b, 0xa7, 0xde, 0xfb, 0x54, + 0x7d, 0x57, 0xbe, 0xf0, 0xe8, 0x6e, 0xc2, 0x79, 0xb2, 0x3a, 0x0b, 0x55, + 0xe2, 0x50, 0x98, 0x16, 0x32, 0x13, 0x5c, 0x2f, 0x78, 0x56, 0xc1, 0xc2, + 0x94, 0xb3, 0xf2, 0x5a, 0xe4, 0x27, 0x9a, 0x9f, 0x24, 0xd7, 0xc6, 0xec, + 0xd0, 0x9b, 0x25, 0x82, 0xe3, 0xcc, 0xc2, 0xc4, 0x45, 0xc5, 0x8c, 0x97, + 0x7a, 0x06, 0x6b, 0x2a, 0x11, 0x9f, 0xa9, 0x0a, 0x6e, 0x48, 0x3b, 0x6f, + 0xdb, 0xd4, 0x11, 0x19, 0x42, 0xf7, 0x8f, 0x07, 0xbf, 0xf5, 0x53, 0x5f, + 0x9c, 0x3e, 0xf4, 0x17, 0x2c, 0xe6, 0x69, 0xac, 0x4e, 0x32, 0x4c, 0x62, + 0x77, 0xea, 0xb7, 0xe8, 0xe5, 0xbb, 0x34, 0xbc, 0x19, 0x8b, 0xae, 0x9c, + 0x51, 0xe7, 0xb7, 0x7e, 0xb5, 0x53, 0xb1, 0x33, 0x22, 0xe5, 0x6d, 0xcf, + 0x70, 0x3c, 0x1a, 0xfa, 0xe2, 0x9b, 0x67, 0xb6, 0x83, 0xf4, 0x8d, 0xa5, + 0xaf, 0x62, 0x4c, 0x4d, 0xe0, 0x58, 0xac, 0x64, 0x34, 0x12, 0x03, 0xf8, + 0xb6, 0x8d, 0x94, 0x63, 0x24, 0xa4, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x0f, 0x30, 0x82, 0x01, 0x0b, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, + 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x33, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x27, 0x30, 0x25, + 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2c, 0x30, 0x2a, + 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x63, + 0x61, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, 0x04, 0x55, 0x1d, 0x20, + 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6a, 0x72, 0x26, 0x7a, 0xd0, 0x1e, + 0xef, 0x7d, 0xe7, 0x3b, 0x69, 0x51, 0xd4, 0x6c, 0x8d, 0x9f, 0x90, 0x12, + 0x66, 0xab, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x68, 0x90, 0xe4, 0x67, 0xa4, 0xa6, 0x53, 0x80, 0xc7, + 0x86, 0x66, 0xa4, 0xf1, 0xf7, 0x4b, 0x43, 0xfb, 0x84, 0xbd, 0x6d, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x69, 0x33, 0x83, 0xfc, 0x28, + 0x7a, 0x6f, 0x7d, 0xef, 0x9d, 0x55, 0xeb, 0xc5, 0x3e, 0x7a, 0x9d, 0x75, + 0xb3, 0xcc, 0xc3, 0x38, 0x36, 0xd9, 0x34, 0xa2, 0x28, 0x68, 0x18, 0xea, + 0x1e, 0x69, 0xd3, 0xbd, 0xe7, 0xd0, 0x77, 0xda, 0xb8, 0x00, 0x83, 0x4e, + 0x4a, 0xcf, 0x6f, 0xd1, 0xf1, 0xc1, 0x22, 0x3f, 0x74, 0xe4, 0xf7, 0x98, + 0x49, 0x9e, 0x9b, 0xb6, 0x9e, 0xe1, 0xdb, 0x98, 0x77, 0x2d, 0x56, 0x34, + 0xb1, 0xa8, 0x3c, 0xd9, 0xfd, 0xc0, 0xcd, 0xc7, 0xbf, 0x05, 0x03, 0xd4, + 0x02, 0xc5, 0xf1, 0xe5, 0xc6, 0xda, 0x08, 0xa5, 0x13, 0xc7, 0x62, 0x23, + 0x11, 0xd1, 0x61, 0x30, 0x1d, 0x60, 0x84, 0x45, 0xef, 0x79, 0xa8, 0xc6, + 0x26, 0x93, 0xa4, 0xb7, 0xcd, 0x34, 0xb8, 0x69, 0xc5, 0x13, 0xf6, 0x91, + 0xb3, 0xc9, 0x45, 0x73, 0x76, 0xb6, 0x92, 0xf6, 0x76, 0x0a, 0x5b, 0xe1, + 0x03, 0x47, 0xb7, 0xe9, 0x29, 0x4c, 0x91, 0x32, 0x23, 0x37, 0x4a, 0x9c, + 0x35, 0xd8, 0x78, 0xfd, 0x1d, 0x1f, 0xe4, 0x83, 0x89, 0x24, 0x80, 0xad, + 0xb7, 0xf9, 0xcf, 0xe4, 0x5d, 0xa5, 0xd4, 0x71, 0xc4, 0x85, 0x5b, 0x70, + 0x1f, 0xdb, 0x3f, 0x1c, 0x01, 0xeb, 0x1a, 0x45, 0x26, 0x31, 0x14, 0xcc, + 0x65, 0xbf, 0x67, 0xde, 0xca, 0xcc, 0x33, 0x65, 0xe5, 0x41, 0x91, 0xd7, + 0x37, 0xbe, 0x41, 0x1a, 0x96, 0x9d, 0xe6, 0x8a, 0x97, 0x9d, 0xa7, 0xce, + 0xac, 0x4e, 0x9a, 0x3d, 0xbd, 0x01, 0xa0, 0x6a, 0xd9, 0x4f, 0x22, 0x00, + 0x8b, 0x44, 0xd5, 0x69, 0x62, 0x7b, 0x2e, 0xeb, 0xcc, 0xba, 0xe7, 0x92, + 0x7d, 0x69, 0x67, 0x3d, 0xfc, 0xb8, 0x7c, 0xde, 0x41, 0x87, 0xd0, 0x69, + 0xea, 0xba, 0x0a, 0x18, 0x7a, 0x1a, 0x95, 0x43, 0xb3, 0x79, 0x71, 0x28, + 0x76, 0x6d, 0xa1, 0xfb, 0x57, 0x4a, 0xec, 0x4d, 0xc8, 0x0e, 0x10, +} + +var certSet3Cert40 = []byte{ + 0x30, 0x82, 0x05, 0x00, 0x30, 0x82, 0x03, 0xe8, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x8f, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, + 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, + 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, + 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x35, 0x30, 0x33, 0x30, 0x37, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x81, 0xc6, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, + 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, + 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, + 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, + 0x74, 0x73, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x74, 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x31, 0x34, 0x30, 0x32, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2b, 0x53, 0x74, 0x61, 0x72, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, + 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe5, + 0x90, 0x66, 0x4b, 0xec, 0xf9, 0x46, 0x71, 0xa9, 0x20, 0x83, 0xbe, 0xe9, + 0x6c, 0xbf, 0x4a, 0xc9, 0x48, 0x69, 0x81, 0x75, 0x4e, 0x6d, 0x24, 0xf6, + 0xcb, 0x17, 0x13, 0xf8, 0xb0, 0x71, 0x59, 0x84, 0x7a, 0x6b, 0x2b, 0x85, + 0xa4, 0x34, 0xb5, 0x16, 0xe5, 0xcb, 0xcc, 0xe9, 0x41, 0x70, 0x2c, 0xa4, + 0x2e, 0xd6, 0xfa, 0x32, 0x7d, 0xe1, 0xa8, 0xde, 0x94, 0x10, 0xac, 0x31, + 0xc1, 0xc0, 0xd8, 0x6a, 0xff, 0x59, 0x27, 0xab, 0x76, 0xd6, 0xfc, 0x0b, + 0x74, 0x6b, 0xb8, 0xa7, 0xae, 0x3f, 0xc4, 0x54, 0xf4, 0xb4, 0x31, 0x44, + 0xdd, 0x93, 0x56, 0x8c, 0xa4, 0x4c, 0x5e, 0x9b, 0x89, 0xcb, 0x24, 0x83, + 0x9b, 0xe2, 0x57, 0x7d, 0xb7, 0xd8, 0x12, 0x1f, 0xc9, 0x85, 0x6d, 0xf4, + 0xd1, 0x80, 0xf1, 0x50, 0x9b, 0x87, 0xae, 0xd4, 0x0b, 0x10, 0x05, 0xfb, + 0x27, 0xba, 0x28, 0x6d, 0x17, 0xe9, 0x0e, 0xd6, 0x4d, 0xb9, 0x39, 0x55, + 0x06, 0xff, 0x0a, 0x24, 0x05, 0x7e, 0x2f, 0xc6, 0x1d, 0x72, 0x6c, 0xd4, + 0x8b, 0x29, 0x8c, 0x57, 0x7d, 0xda, 0xd9, 0xeb, 0x66, 0x1a, 0xd3, 0x4f, + 0xa7, 0xdf, 0x7f, 0x52, 0xc4, 0x30, 0xc5, 0xa5, 0xc9, 0x0e, 0x02, 0xc5, + 0x53, 0xbf, 0x77, 0x38, 0x68, 0x06, 0x24, 0xc3, 0x66, 0xc8, 0x37, 0x7e, + 0x30, 0x1e, 0x45, 0x71, 0x23, 0x35, 0xff, 0x90, 0xd8, 0x2a, 0x9d, 0x8d, + 0xe7, 0xb0, 0x92, 0x4d, 0x3c, 0x7f, 0x2a, 0x0a, 0x93, 0xdc, 0xcd, 0x16, + 0x46, 0x65, 0xf7, 0x60, 0x84, 0x8b, 0x76, 0x4b, 0x91, 0x27, 0x73, 0x14, + 0x92, 0xe0, 0xea, 0xee, 0x8f, 0x16, 0xea, 0x8d, 0x0e, 0x3e, 0x76, 0x17, + 0xbf, 0x7d, 0x89, 0x80, 0x80, 0x44, 0x43, 0xe7, 0x2d, 0xe0, 0x43, 0x09, + 0x75, 0xda, 0x36, 0xe8, 0xad, 0xdb, 0x89, 0x3a, 0xf5, 0x5d, 0x12, 0x8e, + 0x23, 0x04, 0x83, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x2c, + 0x30, 0x82, 0x01, 0x28, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x25, 0x45, 0x81, 0x68, 0x50, 0x26, 0x38, 0x3d, 0x3b, 0x2d, 0x2c, 0xbe, + 0xcd, 0x6a, 0xd9, 0xb6, 0x3d, 0xb3, 0x66, 0x63, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7c, 0x0c, 0x32, + 0x1f, 0xa7, 0xd9, 0x30, 0x7f, 0xc4, 0x7d, 0x68, 0xa3, 0x62, 0xa8, 0xa1, + 0xce, 0xab, 0x07, 0x5b, 0x27, 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1e, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x1f, + 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0xa0, 0x2e, 0xa0, 0x2c, 0x86, 0x2a, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x72, 0x6f, 0x6f, 0x74, 0x2d, + 0x67, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x41, 0x06, 0x04, 0x55, 0x1d, 0x20, + 0x00, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x74, 0x65, 0x63, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x56, 0x65, 0xca, 0xfe, + 0xf3, 0x3f, 0x0a, 0xa8, 0x93, 0x8b, 0x18, 0xc7, 0xde, 0x43, 0x69, 0x13, + 0x34, 0x20, 0xbe, 0x4e, 0x5f, 0x78, 0xa8, 0x6b, 0x9c, 0xdb, 0x6a, 0x4d, + 0x41, 0xdb, 0xc1, 0x13, 0xec, 0xdc, 0x31, 0x00, 0x22, 0x5e, 0xf7, 0x00, + 0x9e, 0x0c, 0xe0, 0x34, 0x65, 0x34, 0xf9, 0xb1, 0x3a, 0x4e, 0x48, 0xc8, + 0x12, 0x81, 0x88, 0x5c, 0x5b, 0x3e, 0x08, 0x53, 0x7a, 0xf7, 0x1a, 0x64, + 0xdf, 0xb8, 0x50, 0x61, 0xcc, 0x53, 0x51, 0x40, 0x29, 0x4b, 0xc2, 0xf4, + 0xae, 0x3a, 0x5f, 0xe4, 0xca, 0xad, 0x26, 0xcc, 0x4e, 0x61, 0x43, 0xe5, + 0xfd, 0x57, 0xa6, 0x37, 0x70, 0xce, 0x43, 0x2b, 0xb0, 0x94, 0xc3, 0x92, + 0xe9, 0xe1, 0x5f, 0xaa, 0x10, 0x49, 0xb7, 0x69, 0xe4, 0xe0, 0xd0, 0x1f, + 0x64, 0xa4, 0x2b, 0xcd, 0x1f, 0x6f, 0xa0, 0xf8, 0x84, 0x24, 0x18, 0xce, + 0x79, 0x3d, 0xa9, 0x91, 0xbf, 0x54, 0x18, 0x13, 0x89, 0x99, 0x54, 0x11, + 0x0d, 0x55, 0xc5, 0x26, 0x0b, 0x79, 0x4f, 0x5a, 0x1c, 0x6e, 0xf9, 0x63, + 0xdb, 0x14, 0x80, 0xa4, 0x07, 0xab, 0xfa, 0xb2, 0xa5, 0xb9, 0x88, 0xdd, + 0x91, 0xfe, 0x65, 0x3b, 0xa4, 0xa3, 0x79, 0xbe, 0x89, 0x4d, 0xe1, 0xd0, + 0xb0, 0xf4, 0xc8, 0x17, 0x0c, 0x0a, 0x96, 0x14, 0x7c, 0x09, 0xb7, 0x6c, + 0xe1, 0xc2, 0xd8, 0x55, 0xd4, 0x18, 0xa0, 0xaa, 0x41, 0x69, 0x70, 0x24, + 0xa3, 0xb9, 0xef, 0xe9, 0x5a, 0xdc, 0x3e, 0xeb, 0x94, 0x4a, 0xf0, 0xb7, + 0xde, 0x5f, 0x0e, 0x76, 0xfa, 0xfb, 0xfb, 0x69, 0x03, 0x45, 0x40, 0x50, + 0xee, 0x72, 0x0c, 0xa4, 0x12, 0x86, 0x81, 0xcd, 0x13, 0xd1, 0x4e, 0xc4, + 0x3c, 0xca, 0x4e, 0x0d, 0xd2, 0x26, 0xf1, 0x00, 0xb7, 0xb4, 0xa6, 0xa2, + 0xe1, 0x6e, 0x7a, 0x81, 0xfd, 0x30, 0xac, 0x7a, 0x1f, 0xc7, 0x59, 0x7b, +} + +var certSet3Cert41 = []byte{ + 0x30, 0x82, 0x05, 0x03, 0x30, 0x82, 0x03, 0xeb, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x51, 0xd3, 0x60, 0xee, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xbe, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, + 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, + 0x30, 0x30, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x32, 0x32, 0x31, 0x37, 0x30, + 0x35, 0x31, 0x34, 0x5a, 0x17, 0x0d, 0x32, 0x34, 0x31, 0x30, 0x32, 0x33, + 0x30, 0x37, 0x33, 0x33, 0x32, 0x32, 0x5a, 0x30, 0x81, 0xba, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, + 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, + 0x65, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, + 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x32, + 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x25, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, + 0x20, 0x4c, 0x31, 0x4b, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xda, 0x3f, 0x96, 0xd0, 0x4d, 0xb9, 0x2f, 0x44, 0xe7, 0xdb, 0x39, + 0x5e, 0x9b, 0x50, 0xee, 0x5c, 0xa5, 0x61, 0xda, 0x41, 0x67, 0x53, 0x09, + 0xaa, 0x00, 0x9a, 0x8e, 0x57, 0x7f, 0x29, 0x6b, 0xdb, 0xc7, 0xe1, 0x21, + 0x24, 0xaa, 0x3a, 0xd0, 0x8d, 0x47, 0x23, 0xd2, 0xed, 0x72, 0x16, 0xf0, + 0x91, 0x21, 0xd2, 0x5d, 0xb7, 0xb8, 0x4b, 0xa8, 0x83, 0x8f, 0xb7, 0x91, + 0x32, 0x68, 0xcf, 0xce, 0x25, 0x93, 0x2c, 0xb2, 0x7d, 0x97, 0xc8, 0xfe, + 0xc1, 0xb4, 0x17, 0xba, 0x09, 0x9e, 0x03, 0x90, 0x93, 0x7b, 0x7c, 0x49, + 0x83, 0x22, 0x68, 0x8a, 0x9b, 0xde, 0x47, 0xc3, 0x31, 0x98, 0x7a, 0x2e, + 0x7d, 0x40, 0x0b, 0xd2, 0xef, 0x3e, 0xd3, 0xb2, 0x8c, 0xaa, 0x8f, 0x48, + 0xa9, 0xff, 0x00, 0xe8, 0x29, 0x58, 0x06, 0xf7, 0xb6, 0x93, 0x5a, 0x94, + 0x73, 0x26, 0x26, 0xad, 0x58, 0x0e, 0xe5, 0x42, 0xb8, 0xd5, 0xea, 0x73, + 0x79, 0x64, 0x68, 0x53, 0x25, 0xb8, 0x84, 0xcf, 0x94, 0x7a, 0xae, 0x06, + 0x45, 0x0c, 0xa3, 0x6b, 0x4d, 0xd0, 0xc6, 0xbe, 0xea, 0x18, 0xa4, 0x36, + 0xf0, 0x92, 0xb2, 0xba, 0x1c, 0x88, 0x8f, 0x3a, 0x52, 0x7f, 0xf7, 0x5e, + 0x6d, 0x83, 0x1c, 0x9d, 0xf0, 0x1f, 0xe5, 0xc3, 0xd6, 0xdd, 0xa5, 0x78, + 0x92, 0x3d, 0xb0, 0x6d, 0x2c, 0xea, 0xc9, 0xcf, 0x94, 0x41, 0x19, 0x71, + 0x44, 0x68, 0xba, 0x47, 0x3c, 0x04, 0xe9, 0x5d, 0xba, 0x3e, 0xf0, 0x35, + 0xf7, 0x15, 0xb6, 0x9e, 0xf2, 0x2e, 0x15, 0x1e, 0x3f, 0x47, 0xc8, 0xc8, + 0x38, 0xa7, 0x73, 0x45, 0x5d, 0x4d, 0xb0, 0x3b, 0xb1, 0x8e, 0x17, 0x29, + 0x37, 0xea, 0xdd, 0x05, 0x01, 0x22, 0xbb, 0x94, 0x36, 0x2a, 0x8d, 0x5b, + 0x35, 0xfe, 0x53, 0x19, 0x2f, 0x08, 0x46, 0xc1, 0x2a, 0xb3, 0x1a, 0x62, + 0x1d, 0x4e, 0x2b, 0xd9, 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x09, 0x30, 0x82, 0x01, 0x05, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x33, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x27, 0x30, 0x25, 0x30, 0x23, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x65, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x30, 0x06, 0x03, + 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, + 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x2f, 0x67, 0x32, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3b, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x70, 0x61, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x82, 0xa2, + 0x70, 0x74, 0xdd, 0xbc, 0x53, 0x3f, 0xcf, 0x7b, 0xd4, 0xf7, 0xcd, 0x7f, + 0xa7, 0x60, 0xc6, 0x0a, 0x4c, 0xbf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x6a, 0x72, 0x26, 0x7a, 0xd0, + 0x1e, 0xef, 0x7d, 0xe7, 0x3b, 0x69, 0x51, 0xd4, 0x6c, 0x8d, 0x9f, 0x90, + 0x12, 0x66, 0xab, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3f, + 0x1c, 0x1a, 0x5b, 0xff, 0x40, 0x22, 0x1d, 0x8f, 0x35, 0x0c, 0x2d, 0xaa, + 0x99, 0x27, 0xab, 0xc0, 0x11, 0x32, 0x70, 0xd7, 0x36, 0x28, 0x69, 0xa5, + 0x8d, 0xb1, 0x27, 0x99, 0x42, 0xbe, 0xc4, 0x93, 0xeb, 0x48, 0x57, 0x43, + 0x71, 0x23, 0xc4, 0xe5, 0x4e, 0xad, 0xae, 0x43, 0x6f, 0x92, 0x76, 0xc5, + 0x19, 0xef, 0xca, 0xbc, 0x6f, 0x42, 0x4c, 0x16, 0x9a, 0x86, 0xa9, 0x04, + 0x38, 0xc7, 0x65, 0xf0, 0xf5, 0x0c, 0xe0, 0x4a, 0xdf, 0xa2, 0xfa, 0xce, + 0x1a, 0x11, 0xa8, 0x9c, 0x69, 0x2f, 0x1b, 0xdf, 0xea, 0xe2, 0x32, 0xf3, + 0xce, 0x4c, 0xbc, 0x46, 0x0c, 0xc0, 0x89, 0x80, 0xd1, 0x87, 0x6b, 0xa2, + 0xcf, 0x6b, 0xd4, 0x7f, 0xfd, 0xf5, 0x60, 0x52, 0x67, 0x57, 0xa0, 0x6d, + 0xd1, 0x64, 0x41, 0x14, 0x6d, 0x34, 0x62, 0xed, 0x06, 0x6c, 0x24, 0xf2, + 0x06, 0xbc, 0x28, 0x02, 0xaf, 0x03, 0x2d, 0xc2, 0x33, 0x05, 0xfb, 0xcb, + 0xaa, 0x16, 0xe8, 0x65, 0x10, 0x43, 0xf5, 0x69, 0x5c, 0xe3, 0x81, 0x58, + 0x99, 0xcd, 0x6b, 0xd3, 0xb8, 0xc7, 0x7b, 0x19, 0x55, 0xc9, 0x40, 0xce, + 0x79, 0x55, 0xb8, 0x73, 0x89, 0xe9, 0x5c, 0x40, 0x66, 0x43, 0x12, 0x7f, + 0x07, 0xb8, 0x65, 0x56, 0xd5, 0x8d, 0xc3, 0xa7, 0xf5, 0xb1, 0xb6, 0x65, + 0x9e, 0xc0, 0x83, 0x36, 0x7f, 0x16, 0x45, 0x3c, 0x74, 0x4b, 0x93, 0x8a, + 0x3c, 0xf1, 0x2b, 0xf5, 0x35, 0x70, 0x73, 0x7b, 0xe7, 0x82, 0x04, 0xb1, + 0x18, 0x98, 0x0e, 0xd4, 0x9c, 0x6f, 0x1a, 0xfc, 0xfc, 0xa7, 0x33, 0xa5, + 0xbb, 0xbb, 0x18, 0xf3, 0x6b, 0x7a, 0x5d, 0x32, 0x87, 0xf7, 0x6d, 0x25, + 0xe4, 0xe2, 0x76, 0x86, 0x21, 0x1e, 0x11, 0x46, 0xcd, 0x76, 0x0e, 0x6f, + 0x4f, 0xa4, 0x21, 0x71, 0x0a, 0x84, 0xa7, 0x2d, 0x36, 0xa9, 0x48, 0x22, + 0x51, 0x7e, 0x82, +} + +var certSet3Cert42 = []byte{ + 0x30, 0x82, 0x05, 0x0e, 0x30, 0x82, 0x03, 0xf6, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0c, 0x0e, 0xe9, 0x4c, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x51, + 0xd3, 0x77, 0x85, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xbe, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, + 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, + 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, + 0x20, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, + 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, + 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x29, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x35, 0x31, 0x30, 0x30, 0x35, 0x31, 0x39, 0x31, 0x33, 0x35, 0x36, 0x5a, + 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x30, 0x35, 0x31, 0x39, 0x34, 0x33, + 0x35, 0x36, 0x5a, 0x30, 0x81, 0xba, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, + 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, + 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x30, + 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x45, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x4c, 0x31, 0x4b, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0x3f, 0x96, + 0xd0, 0x4d, 0xb9, 0x2f, 0x44, 0xe7, 0xdb, 0x39, 0x5e, 0x9b, 0x50, 0xee, + 0x5c, 0xa5, 0x61, 0xda, 0x41, 0x67, 0x53, 0x09, 0xaa, 0x00, 0x9a, 0x8e, + 0x57, 0x7f, 0x29, 0x6b, 0xdb, 0xc7, 0xe1, 0x21, 0x24, 0xaa, 0x3a, 0xd0, + 0x8d, 0x47, 0x23, 0xd2, 0xed, 0x72, 0x16, 0xf0, 0x91, 0x21, 0xd2, 0x5d, + 0xb7, 0xb8, 0x4b, 0xa8, 0x83, 0x8f, 0xb7, 0x91, 0x32, 0x68, 0xcf, 0xce, + 0x25, 0x93, 0x2c, 0xb2, 0x7d, 0x97, 0xc8, 0xfe, 0xc1, 0xb4, 0x17, 0xba, + 0x09, 0x9e, 0x03, 0x90, 0x93, 0x7b, 0x7c, 0x49, 0x83, 0x22, 0x68, 0x8a, + 0x9b, 0xde, 0x47, 0xc3, 0x31, 0x98, 0x7a, 0x2e, 0x7d, 0x40, 0x0b, 0xd2, + 0xef, 0x3e, 0xd3, 0xb2, 0x8c, 0xaa, 0x8f, 0x48, 0xa9, 0xff, 0x00, 0xe8, + 0x29, 0x58, 0x06, 0xf7, 0xb6, 0x93, 0x5a, 0x94, 0x73, 0x26, 0x26, 0xad, + 0x58, 0x0e, 0xe5, 0x42, 0xb8, 0xd5, 0xea, 0x73, 0x79, 0x64, 0x68, 0x53, + 0x25, 0xb8, 0x84, 0xcf, 0x94, 0x7a, 0xae, 0x06, 0x45, 0x0c, 0xa3, 0x6b, + 0x4d, 0xd0, 0xc6, 0xbe, 0xea, 0x18, 0xa4, 0x36, 0xf0, 0x92, 0xb2, 0xba, + 0x1c, 0x88, 0x8f, 0x3a, 0x52, 0x7f, 0xf7, 0x5e, 0x6d, 0x83, 0x1c, 0x9d, + 0xf0, 0x1f, 0xe5, 0xc3, 0xd6, 0xdd, 0xa5, 0x78, 0x92, 0x3d, 0xb0, 0x6d, + 0x2c, 0xea, 0xc9, 0xcf, 0x94, 0x41, 0x19, 0x71, 0x44, 0x68, 0xba, 0x47, + 0x3c, 0x04, 0xe9, 0x5d, 0xba, 0x3e, 0xf0, 0x35, 0xf7, 0x15, 0xb6, 0x9e, + 0xf2, 0x2e, 0x15, 0x1e, 0x3f, 0x47, 0xc8, 0xc8, 0x38, 0xa7, 0x73, 0x45, + 0x5d, 0x4d, 0xb0, 0x3b, 0xb1, 0x8e, 0x17, 0x29, 0x37, 0xea, 0xdd, 0x05, + 0x01, 0x22, 0xbb, 0x94, 0x36, 0x2a, 0x8d, 0x5b, 0x35, 0xfe, 0x53, 0x19, + 0x2f, 0x08, 0x46, 0xc1, 0x2a, 0xb3, 0x1a, 0x62, 0x1d, 0x4e, 0x2b, 0xd9, + 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x0c, 0x30, 0x82, + 0x01, 0x08, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x33, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x27, 0x30, 0x25, 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x65, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x30, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, + 0x2f, 0x67, 0x32, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3b, 0x06, + 0x03, 0x55, 0x1d, 0x20, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0x06, 0x04, + 0x55, 0x1d, 0x20, 0x00, 0x30, 0x28, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x82, 0xa2, 0x70, + 0x74, 0xdd, 0xbc, 0x53, 0x3f, 0xcf, 0x7b, 0xd4, 0xf7, 0xcd, 0x7f, 0xa7, + 0x60, 0xc6, 0x0a, 0x4c, 0xbf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x6a, 0x72, 0x26, 0x7a, 0xd0, 0x1e, + 0xef, 0x7d, 0xe7, 0x3b, 0x69, 0x51, 0xd4, 0x6c, 0x8d, 0x9f, 0x90, 0x12, + 0x66, 0xab, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x39, 0xd5, + 0x8e, 0x98, 0x83, 0x61, 0xc8, 0x2c, 0x63, 0xd3, 0x70, 0x1d, 0x19, 0x30, + 0xcb, 0xf6, 0x09, 0xac, 0xcc, 0x69, 0xd5, 0xc9, 0xdc, 0x37, 0x41, 0xf2, + 0x32, 0x0f, 0xef, 0x74, 0xc3, 0x58, 0xf6, 0x78, 0x27, 0x09, 0x34, 0x08, + 0x95, 0x92, 0x2f, 0xd7, 0xdf, 0xb8, 0xa3, 0xfd, 0x0e, 0x81, 0xe9, 0xa4, + 0x9c, 0xd3, 0x3f, 0x4d, 0x68, 0x2b, 0x15, 0x31, 0x0a, 0x15, 0xcc, 0x52, + 0x04, 0x93, 0xe8, 0x93, 0x50, 0xc3, 0xd9, 0xb1, 0xe2, 0xe1, 0x68, 0xb7, + 0x3a, 0x09, 0x74, 0xf1, 0x34, 0x58, 0x0a, 0x3f, 0x77, 0x98, 0x40, 0xb8, + 0xe6, 0x68, 0xff, 0x5d, 0xe4, 0xc8, 0x46, 0xc5, 0xec, 0x81, 0xd7, 0xc9, + 0x82, 0x18, 0x5c, 0x83, 0xce, 0x71, 0xd8, 0xbc, 0xbf, 0xac, 0x99, 0x02, + 0x93, 0xdb, 0x94, 0x98, 0x84, 0xd2, 0x9c, 0xa6, 0xb5, 0xfe, 0x5c, 0xbb, + 0xf0, 0x4a, 0xaf, 0x21, 0xac, 0xc2, 0x3f, 0x49, 0x24, 0x67, 0xd6, 0x2e, + 0x8e, 0xcf, 0xac, 0xcc, 0x64, 0x15, 0x18, 0x72, 0xe5, 0x6c, 0x77, 0xd3, + 0x52, 0xa8, 0xb9, 0xdd, 0x8d, 0xac, 0x00, 0x4a, 0x35, 0x19, 0xd4, 0x6f, + 0x73, 0xa3, 0x75, 0xef, 0x6b, 0x64, 0xc3, 0xe0, 0x8d, 0x83, 0x12, 0xa1, + 0x8a, 0xe7, 0x0e, 0x86, 0x4d, 0xd8, 0xb4, 0x20, 0x1b, 0xbe, 0x6a, 0xa5, + 0x8c, 0x4b, 0x68, 0x66, 0xe3, 0x2b, 0xc7, 0x58, 0x0b, 0xfb, 0x56, 0x10, + 0xd4, 0x91, 0xfb, 0x1d, 0xd3, 0x31, 0x58, 0x10, 0x8c, 0x44, 0xe3, 0x75, + 0x7b, 0x10, 0x9d, 0xb5, 0x38, 0xb1, 0xf6, 0xaa, 0xca, 0x81, 0x64, 0x6c, + 0xe8, 0xf2, 0xe2, 0x81, 0x55, 0x97, 0x51, 0x7f, 0xe1, 0xc2, 0x27, 0x50, + 0xa2, 0xc9, 0x3c, 0x5b, 0x00, 0x43, 0xf6, 0x5b, 0xb9, 0xd5, 0xa5, 0xfc, + 0xff, 0x07, 0x50, 0x40, 0x67, 0x07, 0xb0, 0x55, 0xf0, 0xb7, 0x7e, 0x6e, + 0x2d, 0xcc, +} + +var certSet3Cert43 = []byte{ + 0x30, 0x82, 0x05, 0x1f, 0x30, 0x82, 0x04, 0x07, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0xa4, 0x6b, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, + 0x30, 0x34, 0x30, 0x32, 0x31, 0x34, 0x33, 0x36, 0x31, 0x30, 0x5a, 0x17, + 0x0d, 0x32, 0x31, 0x30, 0x34, 0x30, 0x32, 0x31, 0x34, 0x33, 0x35, 0x35, + 0x32, 0x5a, 0x30, 0x81, 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x13, 0x09, 0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, + 0x61, 0x6d, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x1c, 0x56, 0x65, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x20, 0x45, 0x6e, 0x74, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x53, 0x6f, 0x6c, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x25, 0x56, 0x65, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x20, 0x41, 0x6b, 0x61, + 0x6d, 0x61, 0x69, 0x20, 0x53, 0x75, 0x72, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x47, 0x31, 0x34, 0x2d, 0x53, 0x48, + 0x41, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdd, + 0x6e, 0x9e, 0x02, 0x69, 0x02, 0xb5, 0xa3, 0x99, 0x2e, 0x08, 0x64, 0x32, + 0x6a, 0x59, 0xf3, 0xc6, 0x9e, 0xa6, 0x20, 0x07, 0xd2, 0x48, 0xd1, 0xa8, + 0x93, 0xc7, 0xea, 0x47, 0x8f, 0x83, 0x39, 0x40, 0xd7, 0x20, 0x5d, 0x8d, + 0x9a, 0xba, 0xab, 0xd8, 0x70, 0xec, 0x9d, 0x88, 0xd1, 0xbd, 0x62, 0xf6, + 0xdb, 0xec, 0x9d, 0x5e, 0x35, 0x01, 0x76, 0x03, 0x23, 0xe5, 0x6f, 0xd2, + 0xaf, 0x46, 0x35, 0x59, 0x5a, 0x5c, 0xd1, 0xa8, 0x23, 0xc1, 0xeb, 0xe9, + 0x20, 0xd4, 0x49, 0xd6, 0x3f, 0x00, 0xd8, 0xa8, 0x22, 0xde, 0x43, 0x79, + 0x81, 0xac, 0xe9, 0xa4, 0x92, 0xf5, 0x77, 0x70, 0x05, 0x1e, 0x5c, 0xb6, + 0xa0, 0xf7, 0x90, 0xa4, 0xcd, 0xab, 0x28, 0x2c, 0x90, 0xc2, 0xe7, 0x0f, + 0xc3, 0xaf, 0x1c, 0x47, 0x59, 0xd5, 0x84, 0x2e, 0xdf, 0x26, 0x07, 0x45, + 0x23, 0x5a, 0xc6, 0xe8, 0x90, 0xc8, 0x85, 0x4b, 0x8c, 0x16, 0x1e, 0x60, + 0xf9, 0x01, 0x13, 0xf1, 0x14, 0x1f, 0xe6, 0xe8, 0x14, 0xed, 0xc5, 0xd2, + 0x6f, 0x63, 0x28, 0x6e, 0x72, 0x8c, 0x49, 0xae, 0x08, 0x72, 0xc7, 0x93, + 0x95, 0xb4, 0x0b, 0x0c, 0xae, 0x8f, 0x9a, 0x67, 0x84, 0xf5, 0x57, 0x1b, + 0xdb, 0x81, 0xd7, 0x17, 0x9d, 0x41, 0x11, 0x43, 0x19, 0xbd, 0x6d, 0x4a, + 0x85, 0xed, 0x8f, 0x70, 0x25, 0xab, 0x66, 0xab, 0xf6, 0xfa, 0x6d, 0x1c, + 0x3c, 0xab, 0xed, 0x17, 0xbd, 0x56, 0x84, 0xe1, 0xdb, 0x75, 0x33, 0xb2, + 0x28, 0x4b, 0x99, 0x8e, 0xf9, 0x4b, 0x82, 0x33, 0x50, 0x9f, 0x92, 0x53, + 0xed, 0xfa, 0xad, 0x0f, 0x95, 0x9c, 0xa3, 0xf2, 0xcb, 0x60, 0xf0, 0x77, + 0x1d, 0xc9, 0x01, 0x8b, 0x5f, 0x2d, 0x86, 0xbe, 0xbf, 0x36, 0xb8, 0x24, + 0x96, 0x13, 0x7c, 0xc1, 0x86, 0x5a, 0x6c, 0xc1, 0x48, 0x2a, 0x7f, 0x3e, + 0x93, 0x60, 0xc5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xb7, + 0x30, 0x82, 0x01, 0xb3, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x02, + 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, + 0x41, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb1, 0x3e, 0x01, 0x32, + 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x02, 0x01, 0x16, 0x26, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, + 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30, 0x81, 0xba, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0xad, 0x30, 0x81, + 0xaa, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x86, 0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, + 0x73, 0x70, 0x2e, 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, + 0x65, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x6d, + 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, + 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x72, 0x6f, 0x6f, 0x74, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x6d, 0x6e, + 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, + 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x72, 0x6f, 0x6f, 0x74, 0x2e, + 0x64, 0x65, 0x72, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0xc6, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe5, 0x9d, 0x59, 0x30, + 0x82, 0x47, 0x58, 0xcc, 0xac, 0xfa, 0x08, 0x54, 0x36, 0x86, 0x7b, 0x3a, + 0xb5, 0x04, 0x4d, 0xf0, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, + 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x64, 0x70, 0x31, 0x2e, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x52, 0x4c, 0x2f, 0x4f, 0x6d, 0x6e, 0x69, + 0x72, 0x6f, 0x6f, 0x74, 0x32, 0x30, 0x32, 0x35, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf8, + 0xbd, 0xfa, 0xaf, 0x73, 0x77, 0xc6, 0xc7, 0x1b, 0xf9, 0x4b, 0x4d, 0x11, + 0xa7, 0xd1, 0x33, 0xaf, 0xaf, 0x72, 0x11, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x01, 0x00, 0x80, 0xd9, 0x7a, 0xed, 0x72, 0x05, 0x37, 0x8f, 0x61, + 0xaa, 0x73, 0x7c, 0x9a, 0x6a, 0xfc, 0xfe, 0x01, 0xe2, 0x19, 0x81, 0x70, + 0x07, 0x25, 0x32, 0xb0, 0xf0, 0x6f, 0x3b, 0xc7, 0x6a, 0x28, 0x3d, 0xe4, + 0x51, 0x87, 0xe6, 0x7e, 0x82, 0xec, 0xae, 0x48, 0xa7, 0xb1, 0x77, 0x38, + 0xc2, 0xd6, 0x56, 0xaf, 0x8f, 0xf2, 0x01, 0xfc, 0x65, 0x65, 0x10, 0x09, + 0xf7, 0x74, 0x29, 0xb5, 0x0e, 0x92, 0xee, 0x90, 0x98, 0xd1, 0x88, 0xa2, + 0x65, 0xb7, 0xcd, 0x9c, 0x0e, 0xa7, 0x86, 0x98, 0x28, 0xbc, 0xae, 0x15, + 0x83, 0xb6, 0x1a, 0xd7, 0x1d, 0xec, 0x19, 0xda, 0x7a, 0x8e, 0x40, 0xf9, + 0x99, 0x15, 0xd5, 0x7d, 0xa5, 0xba, 0xab, 0xfd, 0x26, 0x98, 0x6e, 0x9c, + 0x41, 0x3b, 0xb6, 0x81, 0x18, 0xec, 0x70, 0x48, 0xd7, 0x6e, 0x7f, 0xa6, + 0xe1, 0x77, 0x25, 0xd6, 0xdd, 0x62, 0xe8, 0x52, 0xf3, 0x8c, 0x16, 0x39, + 0x67, 0xe2, 0x22, 0x0d, 0x77, 0x2e, 0xfb, 0x11, 0x6c, 0xe4, 0xdd, 0x38, + 0xb4, 0x27, 0x5f, 0x03, 0xa8, 0x3d, 0x44, 0xe2, 0xf2, 0x84, 0x4b, 0x84, + 0xfd, 0x56, 0xa6, 0x9e, 0x4d, 0x7b, 0xa2, 0x16, 0x4f, 0x07, 0xf5, 0x34, + 0x24, 0x72, 0xa5, 0xa2, 0xfa, 0x16, 0x66, 0x2a, 0xa4, 0x4a, 0x0e, 0xc8, + 0x0d, 0x27, 0x44, 0x9c, 0x77, 0xd4, 0x12, 0x10, 0x87, 0xd2, 0x00, 0x2c, + 0x7a, 0xbb, 0x8e, 0x88, 0x22, 0x91, 0x15, 0xbe, 0xa2, 0x59, 0xca, 0x34, + 0xe0, 0x1c, 0x61, 0x94, 0x86, 0x20, 0x33, 0xcd, 0xe7, 0x4c, 0x5d, 0x3b, + 0x92, 0x3e, 0xcb, 0xd6, 0x2d, 0xea, 0x54, 0xfa, 0xfb, 0xaf, 0x54, 0xf5, + 0xa8, 0xc5, 0x0b, 0xca, 0x8b, 0x87, 0x00, 0xe6, 0x9f, 0xe6, 0x95, 0xbf, + 0xb7, 0xc4, 0xa3, 0x59, 0xf5, 0x16, 0x6c, 0x5f, 0x3e, 0x69, 0x55, 0x80, + 0x39, 0xf6, 0x75, 0x50, 0x14, 0x3e, 0x32, +} + +var certSet3Cert44 = []byte{ + 0x30, 0x82, 0x05, 0x2b, 0x30, 0x82, 0x04, 0x13, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x7e, 0xe1, 0x4a, 0x6f, 0x6f, 0xef, 0xf2, 0xd3, 0x7f, + 0x3f, 0xad, 0x65, 0x4d, 0x3a, 0xda, 0xb4, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, 0x30, 0x33, 0x30, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x77, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1d, + 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x53, 0x79, 0x6d, + 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x16, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x1f, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x56, 0x20, 0x53, 0x53, 0x4c, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xd8, 0xa1, 0x65, 0x74, 0x23, 0xe8, 0x2b, + 0x64, 0xe2, 0x32, 0xd7, 0x33, 0x37, 0x3d, 0x8e, 0xf5, 0x34, 0x16, 0x48, + 0xdd, 0x4f, 0x7f, 0x87, 0x1c, 0xf8, 0x44, 0x23, 0x13, 0x8e, 0xfb, 0x11, + 0xd8, 0x44, 0x5a, 0x18, 0x71, 0x8e, 0x60, 0x16, 0x26, 0x92, 0x9b, 0xfd, + 0x17, 0x0b, 0xe1, 0x71, 0x70, 0x42, 0xfe, 0xbf, 0xfa, 0x1c, 0xc0, 0xaa, + 0xa3, 0xa7, 0xb5, 0x71, 0xe8, 0xff, 0x18, 0x83, 0xf6, 0xdf, 0x10, 0x0a, + 0x13, 0x62, 0xc8, 0x3d, 0x9c, 0xa7, 0xde, 0x2e, 0x3f, 0x0c, 0xd9, 0x1d, + 0xe7, 0x2e, 0xfb, 0x2a, 0xce, 0xc8, 0x9a, 0x7f, 0x87, 0xbf, 0xd8, 0x4c, + 0x04, 0x15, 0x32, 0xc9, 0xd1, 0xcc, 0x95, 0x71, 0xa0, 0x4e, 0x28, 0x4f, + 0x84, 0xd9, 0x35, 0xfb, 0xe3, 0x86, 0x6f, 0x94, 0x53, 0xe6, 0x72, 0x8a, + 0x63, 0x67, 0x2e, 0xbe, 0x69, 0xf6, 0xf7, 0x6e, 0x8e, 0x9c, 0x60, 0x04, + 0xeb, 0x29, 0xfa, 0xc4, 0x47, 0x42, 0xd2, 0x78, 0x98, 0xe3, 0xec, 0x0b, + 0xa5, 0x92, 0xdc, 0xb7, 0x9a, 0xbd, 0x80, 0x64, 0x2b, 0x38, 0x7c, 0x38, + 0x09, 0x5b, 0x66, 0xf6, 0x2d, 0x95, 0x7a, 0x86, 0xb2, 0x34, 0x2e, 0x85, + 0x9e, 0x90, 0x0e, 0x5f, 0xb7, 0x5d, 0xa4, 0x51, 0x72, 0x46, 0x70, 0x13, + 0xbf, 0x67, 0xf2, 0xb6, 0xa7, 0x4d, 0x14, 0x1e, 0x6c, 0xb9, 0x53, 0xee, + 0x23, 0x1a, 0x4e, 0x8d, 0x48, 0x55, 0x43, 0x41, 0xb1, 0x89, 0x75, 0x6a, + 0x40, 0x28, 0xc5, 0x7d, 0xdd, 0xd2, 0x6e, 0xd2, 0x02, 0x19, 0x2f, 0x7b, + 0x24, 0x94, 0x4b, 0xeb, 0xf1, 0x1a, 0xa9, 0x9b, 0xe3, 0x23, 0x9a, 0xea, + 0xfa, 0x33, 0xab, 0x0a, 0x2c, 0xb7, 0xf4, 0x60, 0x08, 0xdd, 0x9f, 0x1c, + 0xcd, 0xdd, 0x2d, 0x01, 0x66, 0x80, 0xaf, 0xb3, 0x2f, 0x29, 0x1d, 0x23, + 0xb8, 0x8a, 0xe1, 0xa1, 0x70, 0x07, 0x0c, 0x34, 0x0f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x5d, 0x30, 0x82, 0x01, 0x59, 0x30, 0x2f, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x23, + 0x30, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, + 0x32, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x65, 0x06, 0x03, 0x55, + 0x1d, 0x20, 0x04, 0x5e, 0x30, 0x5c, 0x30, 0x5a, 0x06, 0x04, 0x55, 0x1d, + 0x20, 0x00, 0x30, 0x52, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x28, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x1c, 0x1a, 0x1a, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, + 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, + 0x70, 0x61, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, + 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x31, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33, 0x2d, 0x67, 0x35, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x29, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, 0x31, + 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, 0x79, + 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, 0x2d, + 0x35, 0x33, 0x33, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0x01, 0x59, 0xab, 0xe7, 0xdd, 0x3a, 0x0b, 0x59, 0xa6, 0x64, + 0x63, 0xd6, 0xcf, 0x20, 0x07, 0x57, 0xd5, 0x91, 0xe7, 0x6a, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7f, + 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, 0x43, + 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x01, 0x00, 0x42, 0x01, 0x55, 0x7b, 0xd0, 0x16, 0x1a, 0x5d, 0x58, + 0xe8, 0xbb, 0x9b, 0xa8, 0x4d, 0xd7, 0xf3, 0xd7, 0xeb, 0x13, 0x94, 0x86, + 0xd6, 0x7f, 0x21, 0x0b, 0x47, 0xbc, 0x57, 0x9b, 0x92, 0x5d, 0x4f, 0x05, + 0x9f, 0x38, 0xa4, 0x10, 0x7c, 0xcf, 0x83, 0xbe, 0x06, 0x43, 0x46, 0x8d, + 0x08, 0xbc, 0x6a, 0xd7, 0x10, 0xa6, 0xfa, 0xab, 0xaf, 0x2f, 0x61, 0xa8, + 0x63, 0xf2, 0x65, 0xdf, 0x7f, 0x4c, 0x88, 0x12, 0x88, 0x4f, 0xb3, 0x69, + 0xd9, 0xff, 0x27, 0xc0, 0x0a, 0x97, 0x91, 0x8f, 0x56, 0xfb, 0x89, 0xc4, + 0xa8, 0xbb, 0x92, 0x2d, 0x1b, 0x73, 0xb0, 0xc6, 0xab, 0x36, 0xf4, 0x96, + 0x6c, 0x20, 0x08, 0xef, 0x0a, 0x1e, 0x66, 0x24, 0x45, 0x4f, 0x67, 0x00, + 0x40, 0xc8, 0x07, 0x54, 0x74, 0x33, 0x3b, 0xa6, 0xad, 0xbb, 0x23, 0x9f, + 0x66, 0xed, 0xa2, 0x44, 0x70, 0x34, 0xfb, 0x0e, 0xea, 0x01, 0xfd, 0xcf, + 0x78, 0x74, 0xdf, 0xa7, 0xad, 0x55, 0xb7, 0x5f, 0x4d, 0xf6, 0xd6, 0x3f, + 0xe0, 0x86, 0xce, 0x24, 0xc7, 0x42, 0xa9, 0x13, 0x14, 0x44, 0x35, 0x4b, + 0xb6, 0xdf, 0xc9, 0x60, 0xac, 0x0c, 0x7f, 0xd9, 0x93, 0x21, 0x4b, 0xee, + 0x9c, 0xe4, 0x49, 0x02, 0x98, 0xd3, 0x60, 0x7b, 0x5c, 0xbc, 0xd5, 0x30, + 0x2f, 0x07, 0xce, 0x44, 0x42, 0xc4, 0x0b, 0x99, 0xfe, 0xe6, 0x9f, 0xfc, + 0xb0, 0x78, 0x86, 0x51, 0x6d, 0xd1, 0x2c, 0x9d, 0xc6, 0x96, 0xfb, 0x85, + 0x82, 0xbb, 0x04, 0x2f, 0xf7, 0x62, 0x80, 0xef, 0x62, 0xda, 0x7f, 0xf6, + 0x0e, 0xac, 0x90, 0xb8, 0x56, 0xbd, 0x79, 0x3f, 0xf2, 0x80, 0x6e, 0xa3, + 0xd9, 0xb9, 0x0f, 0x5d, 0x3a, 0x07, 0x1d, 0x91, 0x93, 0x86, 0x4b, 0x29, + 0x4c, 0xe1, 0xdc, 0xb5, 0xe1, 0xe0, 0x33, 0x9d, 0xb3, 0xcb, 0x36, 0x91, + 0x4b, 0xfe, 0xa1, 0xb4, 0xee, 0xf0, 0xf9, +} + +var certSet3Cert45 = []byte{ + 0x30, 0x82, 0x05, 0x38, 0x30, 0x82, 0x04, 0x20, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x51, 0x3f, 0xb9, 0x74, 0x38, 0x70, 0xb7, 0x34, 0x40, + 0x41, 0x8d, 0x30, 0x93, 0x06, 0x99, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x30, 0x33, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x31, 0x30, 0x33, 0x30, + 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x7e, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1d, + 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x53, 0x79, 0x6d, + 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x16, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x26, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x47, 0x34, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xb2, 0xd8, 0x05, 0xca, 0x1c, 0x74, 0x2d, 0xb5, 0x17, 0x56, 0x39, 0xc5, + 0x4a, 0x52, 0x09, 0x96, 0xe8, 0x4b, 0xd8, 0x0c, 0xf1, 0x68, 0x9f, 0x9a, + 0x42, 0x28, 0x62, 0xc3, 0xa5, 0x30, 0x53, 0x7e, 0x55, 0x11, 0x82, 0x5b, + 0x03, 0x7a, 0x0d, 0x2f, 0xe1, 0x79, 0x04, 0xc9, 0xb4, 0x96, 0x77, 0x19, + 0x81, 0x01, 0x94, 0x59, 0xf9, 0xbc, 0xf7, 0x7a, 0x99, 0x27, 0x82, 0x2d, + 0xb7, 0x83, 0xdd, 0x5a, 0x27, 0x7f, 0xb2, 0x03, 0x7a, 0x9c, 0x53, 0x25, + 0xe9, 0x48, 0x1f, 0x46, 0x4f, 0xc8, 0x9d, 0x29, 0xf8, 0xbe, 0x79, 0x56, + 0xf6, 0xf7, 0xfd, 0xd9, 0x3a, 0x68, 0xda, 0x8b, 0x4b, 0x82, 0x33, 0x41, + 0x12, 0xc3, 0xc8, 0x3c, 0xcc, 0xd6, 0x96, 0x7a, 0x84, 0x21, 0x1a, 0x22, + 0x04, 0x03, 0x27, 0x17, 0x8b, 0x1c, 0x68, 0x61, 0x93, 0x0f, 0x0e, 0x51, + 0x80, 0x33, 0x1d, 0xb4, 0xb5, 0xce, 0xeb, 0x7e, 0xd0, 0x62, 0xac, 0xee, + 0xb3, 0x7b, 0x01, 0x74, 0xef, 0x69, 0x35, 0xeb, 0xca, 0xd5, 0x3d, 0xa9, + 0xee, 0x97, 0x98, 0xca, 0x8d, 0xaa, 0x44, 0x0e, 0x25, 0x99, 0x4a, 0x15, + 0x96, 0xa4, 0xce, 0x6d, 0x02, 0x54, 0x1f, 0x2a, 0x6a, 0x26, 0xe2, 0x06, + 0x3a, 0x63, 0x48, 0xac, 0xb4, 0x4c, 0xd1, 0x75, 0x93, 0x50, 0xff, 0x13, + 0x2f, 0xd6, 0xda, 0xe1, 0xc6, 0x18, 0xf5, 0x9f, 0xc9, 0x25, 0x5d, 0xf3, + 0x00, 0x3a, 0xde, 0x26, 0x4d, 0xb4, 0x29, 0x09, 0xcd, 0x0f, 0x3d, 0x23, + 0x6f, 0x16, 0x4a, 0x81, 0x16, 0xfb, 0xf2, 0x83, 0x10, 0xc3, 0xb8, 0xd6, + 0xd8, 0x55, 0x32, 0x3d, 0xf1, 0xbd, 0x0f, 0xbd, 0x8c, 0x52, 0x95, 0x4a, + 0x16, 0x97, 0x7a, 0x52, 0x21, 0x63, 0x75, 0x2f, 0x16, 0xf9, 0xc4, 0x66, + 0xbe, 0xf5, 0xb5, 0x09, 0xd8, 0xff, 0x27, 0x00, 0xcd, 0x44, 0x7c, 0x6f, + 0x4b, 0x3f, 0xb0, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x63, 0x30, 0x82, 0x01, 0x5f, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, 0x27, + 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x73, 0x31, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33, 0x2d, 0x67, 0x35, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2f, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x23, 0x30, 0x21, 0x30, + 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, + 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x32, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x6b, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x64, 0x30, 0x62, 0x30, 0x60, 0x06, 0x0a, 0x60, + 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, 0x52, 0x30, + 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, + 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x70, 0x73, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x02, 0x30, 0x1c, 0x1a, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, + 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x29, 0x06, + 0x03, 0x55, 0x1d, 0x11, 0x04, 0x22, 0x30, 0x20, 0xa4, 0x1e, 0x30, 0x1c, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x53, + 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x50, 0x4b, 0x49, 0x2d, 0x31, + 0x2d, 0x35, 0x33, 0x34, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x5f, 0x60, 0xcf, 0x61, 0x90, 0x55, 0xdf, 0x84, 0x43, + 0x14, 0x8a, 0x60, 0x2a, 0xb2, 0xf5, 0x7a, 0xf4, 0x43, 0x18, 0xef, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x7f, 0xd3, 0x65, 0xa7, 0xc2, 0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, + 0x43, 0x39, 0xfa, 0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x5e, 0x94, 0x56, 0x49, 0xdd, 0x8e, 0x2d, 0x65, + 0xf5, 0xc1, 0x36, 0x51, 0xb6, 0x03, 0xe3, 0xda, 0x9e, 0x73, 0x19, 0xf2, + 0x1f, 0x59, 0xab, 0x58, 0x7e, 0x6c, 0x26, 0x05, 0x2c, 0xfa, 0x81, 0xd7, + 0x5c, 0x23, 0x17, 0x22, 0x2c, 0x37, 0x93, 0xf7, 0x86, 0xec, 0x85, 0xe6, + 0xb0, 0xa3, 0xfd, 0x1f, 0xe2, 0x32, 0xa8, 0x45, 0x6f, 0xe1, 0xd9, 0xfb, + 0xb9, 0xaf, 0xd2, 0x70, 0xa0, 0x32, 0x42, 0x65, 0xbf, 0x84, 0xfe, 0x16, + 0x2a, 0x8f, 0x3f, 0xc5, 0xa6, 0xd6, 0xa3, 0x93, 0x7d, 0x43, 0xe9, 0x74, + 0x21, 0x91, 0x35, 0x28, 0xf4, 0x63, 0xe9, 0x2e, 0xed, 0xf7, 0xf5, 0x5c, + 0x7f, 0x4b, 0x9a, 0xb5, 0x20, 0xe9, 0x0a, 0xbd, 0xe0, 0x45, 0x10, 0x0c, + 0x14, 0x94, 0x9a, 0x5d, 0xa5, 0xe3, 0x4b, 0x91, 0xe8, 0x24, 0x9b, 0x46, + 0x40, 0x65, 0xf4, 0x22, 0x72, 0xcd, 0x99, 0xf8, 0x88, 0x11, 0xf5, 0xf3, + 0x7f, 0xe6, 0x33, 0x82, 0xe6, 0xa8, 0xc5, 0x7e, 0xfe, 0xd0, 0x08, 0xe2, + 0x25, 0x58, 0x08, 0x71, 0x68, 0xe6, 0xcd, 0xa2, 0xe6, 0x14, 0xde, 0x4e, + 0x52, 0x24, 0x2d, 0xfd, 0xe5, 0x79, 0x13, 0x53, 0xe7, 0x5e, 0x2f, 0x2d, + 0x4d, 0x1b, 0x6d, 0x40, 0x15, 0x52, 0x2b, 0xf7, 0x87, 0x89, 0x78, 0x12, + 0x81, 0x6e, 0xd9, 0x4d, 0xaa, 0x2d, 0x78, 0xd4, 0xc2, 0x2c, 0x3d, 0x08, + 0x5f, 0x87, 0x91, 0x9e, 0x1f, 0x0e, 0xb0, 0xde, 0x30, 0x52, 0x64, 0x86, + 0x89, 0xaa, 0x9d, 0x66, 0x9c, 0x0e, 0x76, 0x0c, 0x80, 0xf2, 0x74, 0xd8, + 0x2a, 0xf8, 0xb8, 0x3a, 0xce, 0xd7, 0xd6, 0x0f, 0x11, 0xbe, 0x6b, 0xab, + 0x14, 0xf5, 0xbd, 0x41, 0xa0, 0x22, 0x63, 0x89, 0xf1, 0xba, 0x0f, 0x6f, + 0x29, 0x63, 0x66, 0x2d, 0x3f, 0xac, 0x8c, 0x72, 0xc5, 0xfb, 0xc7, 0xe4, + 0xd4, 0x0f, 0xf2, 0x3b, 0x4f, 0x8c, 0x29, 0xc7, +} + +var certSet3Cert46 = []byte{ + 0x30, 0x82, 0x05, 0x49, 0x30, 0x82, 0x04, 0x31, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x69, 0x87, 0x94, 0x19, 0xd9, 0xe3, 0x62, 0x70, 0x74, + 0x9d, 0xbb, 0xe5, 0x9d, 0xc6, 0x68, 0x5e, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xbd, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x31, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, + 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2f, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x55, 0x6e, 0x69, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x33, 0x30, 0x34, 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x34, 0x30, 0x38, 0x32, + 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1d, + 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x53, 0x79, 0x6d, + 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x16, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x31, 0x35, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x2c, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbe, 0x38, 0x16, 0x51, 0x8b, 0x80, + 0xdb, 0xea, 0x0e, 0x4d, 0xec, 0xe8, 0x3f, 0x5c, 0xc4, 0x7c, 0xa2, 0x5d, + 0xed, 0x3b, 0xaf, 0xa5, 0xd6, 0x9e, 0x10, 0x35, 0x2c, 0xe3, 0xc5, 0xe5, + 0xa8, 0xde, 0x8c, 0x86, 0x17, 0x26, 0xe6, 0xde, 0x0b, 0x51, 0x4a, 0x2c, + 0xd0, 0xfb, 0xd1, 0x14, 0x5a, 0x72, 0xf7, 0xc9, 0xdd, 0xb8, 0x83, 0x1c, + 0xc6, 0x46, 0x8c, 0x31, 0x25, 0x91, 0x0e, 0x59, 0x17, 0xa3, 0xd0, 0x13, + 0x8c, 0x92, 0xc1, 0xaf, 0x81, 0x54, 0x4e, 0xbc, 0x62, 0x02, 0x9e, 0xaa, + 0xa7, 0x1a, 0x57, 0xd8, 0xca, 0xa6, 0x99, 0x7a, 0x70, 0x56, 0x4f, 0x98, + 0x07, 0x2e, 0x4b, 0x96, 0xd0, 0x4c, 0x39, 0x53, 0xb9, 0x61, 0x2f, 0x3b, + 0x76, 0x7c, 0x8e, 0x05, 0x9e, 0x99, 0x44, 0xd1, 0x03, 0x54, 0x77, 0x29, + 0x2b, 0x56, 0x2a, 0xaa, 0x61, 0xe4, 0x84, 0x2f, 0x12, 0x15, 0x3c, 0xbd, + 0xd7, 0x8a, 0xe8, 0x09, 0x1e, 0x56, 0xf1, 0xb5, 0x14, 0xac, 0x8a, 0x84, + 0xce, 0xae, 0x78, 0xa2, 0x60, 0x0a, 0x53, 0x7e, 0x13, 0x4c, 0x1a, 0x40, + 0x70, 0x0e, 0x52, 0x59, 0xff, 0x5a, 0x68, 0x2e, 0x4c, 0x46, 0x13, 0x3b, + 0x39, 0x09, 0x82, 0x78, 0x02, 0x35, 0x49, 0x20, 0x08, 0x82, 0xb3, 0xb1, + 0x6c, 0x89, 0x0f, 0x6e, 0x1e, 0x35, 0x25, 0xb0, 0x2c, 0x24, 0x83, 0xe3, + 0xc5, 0x50, 0x2c, 0xba, 0x46, 0x90, 0x45, 0x87, 0x0d, 0x72, 0xff, 0x5d, + 0x11, 0x38, 0xc5, 0x91, 0x76, 0xc5, 0x2c, 0xfb, 0x05, 0x2a, 0x82, 0x95, + 0xa1, 0x59, 0x63, 0xe3, 0xd0, 0x26, 0x58, 0xcd, 0x67, 0x56, 0x3a, 0xba, + 0xdf, 0x7c, 0xd2, 0xd2, 0x3b, 0xd8, 0xde, 0x1a, 0x7a, 0x77, 0xe4, 0x0c, + 0x8c, 0x0b, 0xeb, 0x2b, 0xc2, 0x22, 0xb0, 0xbd, 0x55, 0xba, 0xd9, 0xb9, + 0x55, 0xd1, 0x22, 0x7a, 0xc6, 0x02, 0x4e, 0x3f, 0xc3, 0x35, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x7a, 0x30, 0x82, 0x01, 0x76, 0x30, + 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x3e, 0x06, 0x03, 0x55, + 0x1d, 0x1f, 0x04, 0x37, 0x30, 0x35, 0x30, 0x33, 0xa0, 0x31, 0xa0, 0x2f, + 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x2e, 0x77, 0x73, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x6c, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x2b, 0x30, 0x29, 0x30, 0x27, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x77, 0x73, 0x2e, + 0x73, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x6b, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x64, 0x30, 0x62, 0x30, + 0x60, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, + 0x36, 0x30, 0x52, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x1c, 0x1a, 0x1a, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, + 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, + 0x61, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x23, 0x30, 0x21, + 0xa4, 0x1f, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x12, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x4d, + 0x50, 0x4b, 0x49, 0x2d, 0x32, 0x2d, 0x33, 0x37, 0x33, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xdb, 0x62, 0x20, 0xfb, + 0x7d, 0x02, 0x89, 0x7c, 0xd2, 0x3b, 0x6f, 0xc7, 0xe4, 0x32, 0x6c, 0x05, + 0x52, 0x1d, 0xad, 0xb1, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0xb6, 0x77, 0xfa, 0x69, 0x48, 0x47, 0x9f, + 0x53, 0x12, 0xd5, 0xc2, 0xea, 0x07, 0x32, 0x76, 0x07, 0xd1, 0x97, 0x07, + 0x19, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x19, 0xcc, 0x95, + 0xe2, 0x2f, 0x7b, 0x49, 0xd0, 0x48, 0x90, 0x53, 0xf4, 0x07, 0xb1, 0x20, + 0x44, 0x35, 0x70, 0x14, 0xd5, 0x44, 0x37, 0x31, 0xef, 0xef, 0x70, 0xd1, + 0x2d, 0x4c, 0xe9, 0x2d, 0xb0, 0x53, 0x91, 0x01, 0x4c, 0x54, 0xe7, 0x7d, + 0x9b, 0xda, 0x3a, 0xff, 0xb7, 0xcb, 0x14, 0xad, 0x30, 0x0f, 0x69, 0x1a, + 0x2a, 0xf0, 0xbc, 0xcd, 0x35, 0xeb, 0x48, 0xdc, 0xb9, 0x87, 0xfd, 0xcf, + 0xb1, 0x5a, 0xf6, 0x05, 0xda, 0x3c, 0x64, 0xe6, 0x2b, 0xe6, 0xdc, 0x73, + 0x5e, 0x9a, 0xd8, 0x0c, 0x9b, 0xd2, 0x97, 0xb3, 0xe8, 0xfa, 0x87, 0x95, + 0x53, 0xe1, 0x99, 0xad, 0x88, 0xe8, 0xfa, 0xbc, 0x09, 0x4d, 0xa2, 0xc4, + 0x6a, 0x1b, 0x28, 0x3b, 0x2d, 0xc3, 0x21, 0x15, 0xee, 0x14, 0xfa, 0x9d, + 0x98, 0x10, 0xeb, 0x9f, 0x3e, 0xe6, 0x24, 0x24, 0x5f, 0x7a, 0x1c, 0x05, + 0xbb, 0x9a, 0x31, 0x23, 0x58, 0x79, 0x4c, 0xec, 0x6d, 0x18, 0x19, 0x4d, + 0x51, 0x1f, 0x08, 0x61, 0xbd, 0x91, 0x05, 0x0c, 0x5a, 0x9c, 0x26, 0xfc, + 0x0b, 0xa5, 0x20, 0x25, 0xbf, 0x6a, 0x1b, 0x2b, 0xf7, 0x02, 0x09, 0x72, + 0x69, 0x83, 0x32, 0x14, 0xc3, 0x60, 0x5b, 0x7e, 0xfd, 0x9a, 0x32, 0xfa, + 0xb4, 0x95, 0x0e, 0x1a, 0xf9, 0x3b, 0x09, 0xa4, 0x54, 0x47, 0x9a, 0x0c, + 0xce, 0x32, 0xaf, 0xd1, 0x21, 0xcc, 0x7f, 0xd2, 0x06, 0xef, 0x60, 0x0e, + 0x62, 0x6f, 0x6f, 0x81, 0x1a, 0x17, 0x9d, 0xc8, 0xcb, 0x28, 0xcc, 0xe2, + 0x5f, 0x6e, 0x2c, 0x7a, 0xb4, 0xcb, 0x47, 0x7c, 0x74, 0x68, 0x7b, 0x48, + 0x71, 0x02, 0x9c, 0x23, 0x09, 0xf3, 0x5a, 0xae, 0x5f, 0x42, 0x2e, 0x5f, + 0x2b, 0x59, 0x2d, 0x52, 0x88, 0xe5, 0x8d, 0x0b, 0xb3, 0xa8, 0x61, 0xf9, + 0x4b, 0x9b, 0x55, 0xd6, 0xda, 0xb1, 0x92, 0x3b, 0xbf, 0xc3, 0x9b, 0xf9, + 0x2c, +} + +var certSet3Cert47 = []byte{ + 0x30, 0x82, 0x05, 0x86, 0x30, 0x82, 0x04, 0x6e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0x9a, 0xa9, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, + 0x31, 0x32, 0x31, 0x39, 0x32, 0x30, 0x30, 0x37, 0x33, 0x32, 0x5a, 0x17, + 0x0d, 0x31, 0x37, 0x31, 0x32, 0x31, 0x39, 0x32, 0x30, 0x30, 0x36, 0x35, + 0x35, 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, + 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, + 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x0c, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, + 0x74, 0x20, 0x49, 0x54, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x20, 0x49, 0x54, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, + 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xd1, 0xe8, 0x37, + 0xa7, 0x76, 0x8a, 0x70, 0x4b, 0x19, 0xf0, 0x20, 0x37, 0x09, 0x24, 0x37, + 0x7f, 0xea, 0xfb, 0x78, 0xe6, 0x05, 0xba, 0x6a, 0xad, 0x4e, 0x27, 0x0d, + 0xfc, 0x72, 0x6a, 0xd9, 0x6c, 0x21, 0xc4, 0x64, 0x11, 0x95, 0x73, 0x10, + 0x0a, 0x5c, 0x25, 0x7b, 0x88, 0x6c, 0x94, 0x04, 0xfd, 0xc7, 0xdb, 0xae, + 0x7b, 0xdc, 0x4a, 0x08, 0xb3, 0x3e, 0x16, 0xf1, 0xd0, 0xad, 0xdb, 0x30, + 0x6d, 0xd7, 0x1a, 0x1e, 0x52, 0xb5, 0x3d, 0xf0, 0x47, 0x19, 0x03, 0xe2, + 0x7d, 0xa6, 0xbd, 0x57, 0x13, 0x3f, 0x54, 0xea, 0x3a, 0xa3, 0xb1, 0x77, + 0xfc, 0x42, 0xf0, 0x63, 0x49, 0x6a, 0x91, 0x80, 0x2e, 0x30, 0x49, 0xc0, + 0x8a, 0xeb, 0x2b, 0xaf, 0xfe, 0x3a, 0xeb, 0x07, 0x5d, 0x06, 0xf7, 0xe9, + 0xfd, 0x84, 0x0e, 0x91, 0xbd, 0x09, 0x20, 0x29, 0xe8, 0x6e, 0x5d, 0x09, + 0xce, 0x15, 0xd3, 0xe7, 0xef, 0xdb, 0x50, 0xeb, 0x44, 0xef, 0x18, 0x57, + 0xab, 0x04, 0x1d, 0xbc, 0x31, 0xf9, 0xf7, 0x7b, 0x2a, 0x13, 0xcf, 0xd1, + 0x3d, 0x51, 0xaf, 0x1b, 0xc5, 0xb5, 0x7b, 0xe7, 0xb0, 0xfc, 0x53, 0xbb, + 0x9a, 0xe7, 0x63, 0xde, 0x41, 0x33, 0xb6, 0x47, 0x24, 0x69, 0x5d, 0xb8, + 0x46, 0xa7, 0xff, 0xad, 0xab, 0xdf, 0x4f, 0x7a, 0x78, 0x25, 0x27, 0x21, + 0x26, 0x34, 0xca, 0x02, 0x6e, 0x37, 0x51, 0xf0, 0xed, 0x58, 0x1a, 0x60, + 0x94, 0xf6, 0xc4, 0x93, 0xd8, 0xdd, 0x30, 0x24, 0x25, 0xd7, 0x1c, 0xeb, + 0x19, 0x94, 0x35, 0x5d, 0x93, 0xb2, 0xae, 0xaa, 0x29, 0x83, 0x73, 0xc4, + 0x74, 0x59, 0x05, 0x52, 0x67, 0x9d, 0xda, 0x67, 0x51, 0x39, 0x05, 0x3a, + 0x36, 0xea, 0xf2, 0x1e, 0x76, 0x2b, 0x14, 0xae, 0xec, 0x3d, 0xf9, 0x14, + 0x99, 0x8b, 0x07, 0x6e, 0xbc, 0xe7, 0x0c, 0x56, 0xde, 0xac, 0xbe, 0xae, + 0xdb, 0x75, 0x32, 0x90, 0x9e, 0x63, 0xbd, 0x74, 0xbf, 0xe0, 0x0a, 0xca, + 0xf8, 0x34, 0x96, 0x67, 0x84, 0xcd, 0xd1, 0x42, 0x38, 0x78, 0xc7, 0x99, + 0xb6, 0x0c, 0xce, 0xb6, 0x0f, 0xe9, 0x1b, 0xcb, 0xf4, 0x59, 0xbe, 0x11, + 0x0e, 0xcb, 0x2c, 0x32, 0xc8, 0xfa, 0x83, 0x29, 0x64, 0x79, 0x3c, 0x8b, + 0x4b, 0xf0, 0x32, 0x74, 0x6c, 0xf3, 0x93, 0xb8, 0x96, 0x6b, 0x5d, 0x57, + 0x5a, 0x68, 0xc1, 0xcc, 0x0c, 0x79, 0x8a, 0x19, 0xde, 0xf5, 0x49, 0x02, + 0x5e, 0x08, 0x80, 0x01, 0x89, 0x0c, 0x32, 0xcd, 0xd2, 0xd6, 0x96, 0xd5, + 0x4b, 0xa0, 0xf3, 0xec, 0xbf, 0xab, 0xf4, 0x7d, 0xb3, 0xa1, 0xb9, 0x7c, + 0xda, 0x4e, 0xd7, 0xe5, 0xb7, 0xac, 0xb9, 0xf2, 0x25, 0x5f, 0x01, 0xcb, + 0x8c, 0x96, 0xa8, 0x28, 0xae, 0xc1, 0x33, 0x5a, 0xf6, 0x3f, 0x08, 0x90, + 0xdc, 0xeb, 0xff, 0x39, 0xd8, 0x26, 0xc8, 0x12, 0x9d, 0x1c, 0x9a, 0xaa, + 0xa9, 0xc0, 0x16, 0x8e, 0x86, 0xed, 0x67, 0x52, 0x96, 0x00, 0x7f, 0x0d, + 0x92, 0x3d, 0x3d, 0xd9, 0x70, 0x36, 0xe5, 0xea, 0x42, 0x6f, 0x1f, 0xae, + 0x95, 0xe5, 0x5b, 0x5d, 0xf8, 0xd0, 0x3a, 0xc7, 0xd4, 0xde, 0x77, 0x86, + 0xd0, 0xfc, 0x9e, 0x4e, 0xe2, 0xe2, 0xb8, 0xa9, 0x68, 0x37, 0x09, 0xc4, + 0x39, 0xe3, 0x85, 0xb8, 0x89, 0xf3, 0x1f, 0x6e, 0xb7, 0x6d, 0x1f, 0x4a, + 0x2f, 0x18, 0x09, 0x6f, 0xde, 0x4a, 0x01, 0x8f, 0x14, 0xc9, 0xb7, 0xa6, + 0xee, 0xa7, 0x63, 0x9f, 0x33, 0xa4, 0x54, 0x7c, 0x42, 0x83, 0x68, 0xb8, + 0xa5, 0xdf, 0xbf, 0xec, 0xb9, 0x1a, 0x5d, 0x13, 0x3b, 0xd9, 0xad, 0x68, + 0xfd, 0x20, 0x0a, 0x55, 0x91, 0x21, 0x64, 0xf9, 0xd7, 0x13, 0x01, 0xa0, + 0x08, 0x5d, 0x59, 0x89, 0x1b, 0x44, 0xaf, 0xa4, 0xac, 0xc7, 0x05, 0x10, + 0xfa, 0x41, 0x4a, 0xa8, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x20, 0x30, 0x82, 0x01, 0x1c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x53, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4c, 0x30, + 0x4a, 0x30, 0x48, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb1, 0x3e, + 0x01, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, + 0x63, 0x66, 0x6d, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x02, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0xe5, 0x9d, 0x59, 0x30, 0x82, 0x47, 0x58, 0xcc, 0xac, + 0xfa, 0x08, 0x54, 0x36, 0x86, 0x7b, 0x3a, 0xb5, 0x04, 0x4d, 0xf0, 0x30, + 0x42, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, + 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x64, 0x70, 0x31, 0x2e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, + 0x52, 0x4c, 0x2f, 0x4f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x32, + 0x30, 0x32, 0x35, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x51, 0xaf, 0x24, 0x26, 0x9c, 0xf4, + 0x68, 0x22, 0x57, 0x80, 0x26, 0x2b, 0x3b, 0x46, 0x62, 0x15, 0x7b, 0x1e, + 0xcc, 0xa5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x76, 0x85, + 0xc5, 0x23, 0x31, 0x1f, 0xb4, 0x73, 0xea, 0xa0, 0xbc, 0xa5, 0xed, 0xdf, + 0x45, 0x43, 0x6a, 0x7f, 0x69, 0x20, 0x1b, 0x80, 0xb2, 0xfb, 0x1c, 0xdd, + 0xaa, 0x7f, 0x88, 0xd3, 0x31, 0x41, 0x36, 0xf7, 0xfb, 0xfb, 0x6b, 0xad, + 0x98, 0x8c, 0x78, 0x1f, 0x9d, 0x11, 0x67, 0x3a, 0xcd, 0x4b, 0xec, 0xa8, + 0xbc, 0x9d, 0x15, 0x19, 0xc4, 0x3b, 0x0b, 0xa7, 0x93, 0xce, 0xe8, 0xfc, + 0x9d, 0x5b, 0xe8, 0x1f, 0xcb, 0x56, 0xae, 0x76, 0x43, 0x2b, 0xc7, 0x13, + 0x51, 0x77, 0x41, 0xa8, 0x66, 0x4c, 0x5f, 0xa7, 0xd1, 0xd7, 0xaa, 0x75, + 0xc5, 0x1b, 0x29, 0x4c, 0xc9, 0xf4, 0x6d, 0xa1, 0x5e, 0xa1, 0x85, 0x93, + 0x16, 0xc2, 0xcb, 0x3b, 0xab, 0x14, 0x7d, 0x44, 0xfd, 0xda, 0x25, 0x29, + 0x86, 0x2a, 0xfe, 0x63, 0x20, 0xca, 0xd2, 0x0b, 0xc2, 0x34, 0x15, 0xbb, + 0xaf, 0x5b, 0x7f, 0x8a, 0xe0, 0xaa, 0xed, 0x45, 0xa6, 0xea, 0x79, 0xdb, + 0xd8, 0x35, 0x66, 0x54, 0x43, 0xde, 0x37, 0x33, 0xd1, 0xe4, 0xe0, 0xcd, + 0x57, 0xca, 0x71, 0xb0, 0x7d, 0xe9, 0x16, 0x77, 0x64, 0xe8, 0x59, 0x97, + 0xb9, 0xd5, 0x2e, 0xd1, 0xb4, 0x91, 0xda, 0x77, 0x71, 0xf3, 0x4a, 0x0f, + 0x48, 0xd2, 0x34, 0x99, 0x60, 0x95, 0x37, 0xac, 0x1f, 0x01, 0xcd, 0x10, + 0x9d, 0xe8, 0x2a, 0xa5, 0x20, 0xc7, 0x50, 0x9b, 0xb3, 0x6c, 0x49, 0x78, + 0x2b, 0x58, 0x92, 0x64, 0x89, 0xb8, 0x95, 0x36, 0xa8, 0x34, 0xaa, 0xf0, + 0x41, 0xd2, 0x95, 0x5a, 0x24, 0x54, 0x97, 0x4d, 0x6e, 0x05, 0xc4, 0x95, + 0xad, 0xc4, 0x7a, 0xa3, 0x39, 0xfb, 0x79, 0x06, 0x8a, 0x9b, 0xa6, 0x4f, + 0xd9, 0x22, 0xfa, 0x44, 0x4e, 0x36, 0xf3, 0xc9, 0x0f, 0xa6, 0x39, 0xe7, + 0x80, 0xb2, 0x5e, 0xbf, 0xbd, 0x39, 0xd1, 0x46, 0xe5, 0x55, 0x47, 0xdb, + 0xbc, 0x6e, +} + +var certSet3Cert48 = []byte{ + 0x30, 0x82, 0x05, 0xa3, 0x30, 0x82, 0x03, 0x8b, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x75, 0x96, 0xc2, 0x3e, 0xfa, 0x89, 0x59, 0x45, 0x6e, + 0x79, 0xf7, 0x17, 0xba, 0xcf, 0x64, 0xf3, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x55, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, + 0x4e, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, + 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x21, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x57, 0x6f, 0x53, 0x69, 0x67, + 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x31, 0x30, 0x38, 0x30, + 0x30, 0x35, 0x38, 0x35, 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x31, + 0x30, 0x38, 0x30, 0x30, 0x35, 0x38, 0x35, 0x38, 0x5a, 0x30, 0x52, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x57, + 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x65, 0x64, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x1e, 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x4f, 0x56, 0x20, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd6, 0x74, 0x87, 0xaf, 0x99, 0xc0, + 0x57, 0x96, 0x99, 0xc2, 0x89, 0x74, 0x3c, 0x92, 0x55, 0x99, 0xbf, 0x1f, + 0x07, 0x00, 0x35, 0x05, 0x26, 0x96, 0x16, 0x5b, 0x03, 0xc1, 0x42, 0x37, + 0x33, 0xbe, 0x3f, 0x0d, 0x4f, 0xff, 0xbb, 0x94, 0x26, 0x91, 0xd7, 0x14, + 0x16, 0x78, 0x1b, 0xf7, 0x13, 0xa2, 0x4b, 0x4c, 0xe5, 0x5c, 0xa7, 0x10, + 0x40, 0x35, 0x59, 0x30, 0xd1, 0x77, 0x99, 0xe3, 0x9d, 0x29, 0xc2, 0xbe, + 0x31, 0x95, 0xbd, 0x92, 0x61, 0x5b, 0xb0, 0x23, 0xfb, 0x67, 0x58, 0xd5, + 0x52, 0xe4, 0x7b, 0x2f, 0xf0, 0x73, 0x1c, 0x73, 0x94, 0x55, 0xba, 0xc8, + 0x68, 0x59, 0x02, 0x10, 0x10, 0xe4, 0xf7, 0x11, 0xf0, 0xc3, 0xb6, 0xd7, + 0xae, 0x56, 0x80, 0x00, 0x9e, 0x65, 0x64, 0xa6, 0x83, 0x91, 0x41, 0xe6, + 0xed, 0xa7, 0x7a, 0x65, 0xa5, 0x1f, 0x30, 0x2e, 0x13, 0x3c, 0xbf, 0xdf, + 0x63, 0x97, 0xf3, 0x96, 0xf0, 0x52, 0x32, 0xb4, 0xf4, 0x7b, 0x98, 0x57, + 0xed, 0x36, 0x4f, 0xf7, 0x21, 0x4a, 0x28, 0x9d, 0xdd, 0x1c, 0x92, 0xb3, + 0x4d, 0x8d, 0x9c, 0x58, 0x8b, 0x17, 0x21, 0xd8, 0xdc, 0xa1, 0xb7, 0xae, + 0x73, 0x78, 0x8a, 0xc4, 0xb6, 0xe9, 0x7f, 0x28, 0x8e, 0x9a, 0xd5, 0x2e, + 0x9e, 0x39, 0xe9, 0xda, 0x59, 0x74, 0xe3, 0xc8, 0x97, 0x10, 0x32, 0x94, + 0x19, 0x59, 0xd4, 0x0f, 0x89, 0x57, 0x44, 0xe6, 0xe5, 0x2b, 0x17, 0x30, + 0x62, 0x52, 0x98, 0x7f, 0xab, 0x0d, 0xa5, 0x01, 0xea, 0x04, 0x41, 0xca, + 0xfa, 0x13, 0x0e, 0x3b, 0x87, 0x06, 0xba, 0xbd, 0x47, 0x31, 0xd7, 0x63, + 0x03, 0x01, 0xf4, 0xbe, 0xa1, 0x37, 0x11, 0x9f, 0x1e, 0x01, 0x95, 0x4e, + 0x0f, 0x3f, 0x54, 0x1e, 0x92, 0xa6, 0x9f, 0x30, 0x8c, 0xfe, 0x98, 0xe8, + 0x56, 0x96, 0x66, 0x04, 0xe1, 0x35, 0xfe, 0x59, 0xac, 0x57, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x70, 0x30, 0x82, 0x01, 0x6c, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, + 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, + 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x73, + 0x31, 0x2e, 0x77, 0x6f, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x63, 0x61, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x6d, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x61, 0x30, 0x5f, + 0x30, 0x27, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x31, 0x2e, 0x77, 0x6f, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x61, 0x31, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x61, 0x69, 0x61, 0x31, 0x2e, 0x77, 0x6f, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x61, 0x31, 0x67, 0x32, 0x2d, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x33, 0x2e, 0x63, 0x65, 0x72, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf9, 0x8b, + 0xec, 0x04, 0x38, 0x6a, 0x3f, 0xaa, 0x06, 0xc6, 0x94, 0xad, 0x73, 0x95, + 0x2a, 0xb0, 0xc8, 0xe6, 0xb8, 0xfb, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe1, 0x66, 0xcf, 0x0e, 0xd1, + 0xf1, 0xb3, 0x4b, 0xb7, 0x06, 0x20, 0x14, 0xfe, 0x87, 0x12, 0xd5, 0xf6, + 0xfe, 0xfb, 0x3e, 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, + 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x0c, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, + 0x9b, 0x51, 0x06, 0x03, 0x02, 0x01, 0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x73, + 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x5e, + 0x67, 0xba, 0x78, 0x32, 0x05, 0xb6, 0xb7, 0xaf, 0xe7, 0xde, 0x6a, 0x7a, + 0x82, 0x64, 0x0e, 0xa0, 0x0b, 0xf2, 0x9e, 0x9a, 0xba, 0xc6, 0x2b, 0x6f, + 0x56, 0x3a, 0xb4, 0x62, 0x57, 0xab, 0x7c, 0xad, 0x60, 0x50, 0x96, 0x34, + 0x9c, 0xa3, 0x88, 0xcf, 0xd9, 0x8f, 0x50, 0xaf, 0xf6, 0xf0, 0x00, 0x36, + 0x1b, 0x1f, 0x1f, 0x87, 0x55, 0x3c, 0x60, 0x9a, 0xf0, 0xb0, 0x0d, 0x9a, + 0x80, 0x2d, 0x8a, 0x3b, 0xbe, 0x05, 0xb3, 0xd7, 0xa0, 0x80, 0xb6, 0xb8, + 0x19, 0xeb, 0x51, 0xdb, 0xec, 0x64, 0x54, 0xf1, 0x1a, 0x89, 0x4a, 0x48, + 0xa1, 0x4d, 0x3f, 0x31, 0x7d, 0xc4, 0x79, 0x94, 0x4b, 0xf1, 0xde, 0xab, + 0x83, 0xaf, 0x5f, 0x86, 0xbe, 0x96, 0x1c, 0xb3, 0x3e, 0x1c, 0xe7, 0xbc, + 0x96, 0xb2, 0xe8, 0x5a, 0xac, 0xb5, 0x58, 0xcb, 0x3c, 0x56, 0x6f, 0x0a, + 0xa7, 0xa5, 0xd0, 0x36, 0x89, 0x82, 0x26, 0x8c, 0xb9, 0x1f, 0xb6, 0xeb, + 0x8f, 0x7e, 0x78, 0xfc, 0x5b, 0x8b, 0x79, 0x1c, 0xd6, 0xdf, 0x47, 0xa7, + 0x56, 0xf4, 0x98, 0x4e, 0xc7, 0xa9, 0xd5, 0x0e, 0x75, 0x56, 0x06, 0x7f, + 0xb4, 0x37, 0x46, 0x08, 0xc6, 0xe9, 0x4f, 0x8b, 0x5b, 0x43, 0x1c, 0xe0, + 0x45, 0x3e, 0x95, 0x20, 0x71, 0xc0, 0x1c, 0x98, 0x16, 0xef, 0xf2, 0x78, + 0xdf, 0xac, 0x4d, 0xbb, 0xbf, 0x56, 0x0e, 0xcf, 0x85, 0xaf, 0xcf, 0xbf, + 0x04, 0xed, 0x72, 0x6b, 0xfd, 0x1f, 0x57, 0x0e, 0x58, 0x91, 0x44, 0x11, + 0x58, 0x3b, 0x62, 0x3b, 0x09, 0x78, 0xb3, 0xa4, 0x75, 0x6a, 0xec, 0xb3, + 0xc2, 0x2b, 0x32, 0xcc, 0xb3, 0x8d, 0xc3, 0xa3, 0x6e, 0xdc, 0x8a, 0xd5, + 0xe8, 0x4a, 0xc4, 0x0b, 0x7b, 0xdb, 0x30, 0x5d, 0x95, 0x33, 0xc3, 0xd1, + 0xa3, 0x69, 0x64, 0x5b, 0xa8, 0xaa, 0x96, 0x48, 0x73, 0x73, 0xe3, 0xc9, + 0xb9, 0x24, 0xdf, 0x17, 0x75, 0xaa, 0xaf, 0x07, 0x3a, 0xcf, 0xbe, 0x9b, + 0x8a, 0x80, 0xa7, 0xbf, 0x7c, 0xe2, 0xe9, 0x2a, 0xe6, 0xfd, 0xb0, 0x2c, + 0xe7, 0xe6, 0xe6, 0x7e, 0xb3, 0x35, 0x15, 0x65, 0x00, 0xf4, 0xe1, 0x39, + 0x73, 0x0e, 0x28, 0x4b, 0xf0, 0x0c, 0x98, 0x9e, 0x3a, 0xeb, 0xce, 0x7b, + 0x7a, 0x9e, 0x40, 0xc1, 0x50, 0x65, 0x96, 0x9a, 0xe7, 0x4b, 0x77, 0xcd, + 0xdd, 0xcb, 0x7d, 0x97, 0xb4, 0xea, 0x09, 0xb2, 0xe9, 0x49, 0x28, 0xc3, + 0x30, 0xe0, 0x87, 0x15, 0xf0, 0x26, 0xea, 0xd8, 0x03, 0xfd, 0xec, 0xda, + 0x08, 0x83, 0x65, 0xdc, 0x77, 0xc5, 0x6e, 0x3d, 0x34, 0xf7, 0x87, 0xc3, + 0x1c, 0x1d, 0x26, 0x33, 0xec, 0x33, 0xac, 0xc6, 0x99, 0x53, 0xab, 0x60, + 0xf4, 0xb0, 0xd9, 0xee, 0x64, 0x5a, 0x33, 0x07, 0x70, 0x13, 0x74, 0x88, + 0x07, 0xf5, 0x86, 0xf9, 0x18, 0xd3, 0xb2, 0x47, 0xc8, 0xae, 0x03, 0x4a, + 0x53, 0xde, 0x1c, 0x65, 0xd6, 0x0a, 0x2e, 0x3a, 0x51, 0x93, 0xee, 0xb7, + 0xe3, 0x6f, 0x0a, 0xfb, 0xe9, 0xfe, 0x4e, 0xe8, 0xbb, 0x1d, 0xc2, 0x97, + 0xab, 0x0a, 0xb9, 0xed, 0x36, 0x32, 0x1b, 0x4d, 0xa1, 0xcc, 0x03, 0xa6, + 0x9d, 0xb3, 0xd9, 0x1c, 0xd5, 0x67, 0xe2, 0x8f, 0x74, 0x3c, 0x92, 0x2a, + 0x74, 0xb1, 0x56, 0x50, 0xdf, 0x53, 0x15, 0xd7, 0x21, 0xd6, 0xeb, 0xf3, + 0xfb, 0x63, 0xe3, 0x20, 0x2c, 0x0a, 0x74, 0x37, 0x0b, 0xc1, 0xa1, 0x35, + 0x6a, 0x84, 0x70, 0xf4, 0x45, 0xf8, 0xb2, 0xb6, 0x81, 0x49, 0xaa, 0xfd, + 0x54, 0x45, 0x90, 0x4d, 0xe7, 0x04, 0x07, 0x5f, 0x78, 0x14, 0xdd, 0x3a, + 0xbb, 0x2b, 0xf9, 0x72, 0x50, 0xec, 0x68, 0xea, 0x3c, 0xa8, 0xd1, 0x80, + 0xbb, 0xbe, 0x35, 0x43, 0x97, 0xc3, 0x32, 0xb2, 0xf5, 0xaa, 0xad, 0xc9, + 0x7f, 0x83, 0x9f, 0x7d, 0x69, 0x1e, 0x15, +} + +var certSet3Cert49 = []byte{ + 0x30, 0x82, 0x05, 0xe1, 0x30, 0x82, 0x04, 0xc9, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x07, 0x27, 0xaa, 0x47, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, + 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, + 0x30, 0x35, 0x30, 0x37, 0x31, 0x37, 0x30, 0x34, 0x30, 0x39, 0x5a, 0x17, + 0x0d, 0x31, 0x38, 0x30, 0x35, 0x30, 0x37, 0x31, 0x37, 0x30, 0x33, 0x33, + 0x30, 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, + 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x13, 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, + 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x0c, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, + 0x74, 0x20, 0x49, 0x54, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x20, 0x49, 0x54, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, + 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xd1, 0xe8, 0x37, + 0xa7, 0x76, 0x8a, 0x70, 0x4b, 0x19, 0xf0, 0x20, 0x37, 0x09, 0x24, 0x37, + 0x7f, 0xea, 0xfb, 0x78, 0xe6, 0x05, 0xba, 0x6a, 0xad, 0x4e, 0x27, 0x0d, + 0xfc, 0x72, 0x6a, 0xd9, 0x6c, 0x21, 0xc4, 0x64, 0x11, 0x95, 0x73, 0x10, + 0x0a, 0x5c, 0x25, 0x7b, 0x88, 0x6c, 0x94, 0x04, 0xfd, 0xc7, 0xdb, 0xae, + 0x7b, 0xdc, 0x4a, 0x08, 0xb3, 0x3e, 0x16, 0xf1, 0xd0, 0xad, 0xdb, 0x30, + 0x6d, 0xd7, 0x1a, 0x1e, 0x52, 0xb5, 0x3d, 0xf0, 0x47, 0x19, 0x03, 0xe2, + 0x7d, 0xa6, 0xbd, 0x57, 0x13, 0x3f, 0x54, 0xea, 0x3a, 0xa3, 0xb1, 0x77, + 0xfc, 0x42, 0xf0, 0x63, 0x49, 0x6a, 0x91, 0x80, 0x2e, 0x30, 0x49, 0xc0, + 0x8a, 0xeb, 0x2b, 0xaf, 0xfe, 0x3a, 0xeb, 0x07, 0x5d, 0x06, 0xf7, 0xe9, + 0xfd, 0x84, 0x0e, 0x91, 0xbd, 0x09, 0x20, 0x29, 0xe8, 0x6e, 0x5d, 0x09, + 0xce, 0x15, 0xd3, 0xe7, 0xef, 0xdb, 0x50, 0xeb, 0x44, 0xef, 0x18, 0x57, + 0xab, 0x04, 0x1d, 0xbc, 0x31, 0xf9, 0xf7, 0x7b, 0x2a, 0x13, 0xcf, 0xd1, + 0x3d, 0x51, 0xaf, 0x1b, 0xc5, 0xb5, 0x7b, 0xe7, 0xb0, 0xfc, 0x53, 0xbb, + 0x9a, 0xe7, 0x63, 0xde, 0x41, 0x33, 0xb6, 0x47, 0x24, 0x69, 0x5d, 0xb8, + 0x46, 0xa7, 0xff, 0xad, 0xab, 0xdf, 0x4f, 0x7a, 0x78, 0x25, 0x27, 0x21, + 0x26, 0x34, 0xca, 0x02, 0x6e, 0x37, 0x51, 0xf0, 0xed, 0x58, 0x1a, 0x60, + 0x94, 0xf6, 0xc4, 0x93, 0xd8, 0xdd, 0x30, 0x24, 0x25, 0xd7, 0x1c, 0xeb, + 0x19, 0x94, 0x35, 0x5d, 0x93, 0xb2, 0xae, 0xaa, 0x29, 0x83, 0x73, 0xc4, + 0x74, 0x59, 0x05, 0x52, 0x67, 0x9d, 0xda, 0x67, 0x51, 0x39, 0x05, 0x3a, + 0x36, 0xea, 0xf2, 0x1e, 0x76, 0x2b, 0x14, 0xae, 0xec, 0x3d, 0xf9, 0x14, + 0x99, 0x8b, 0x07, 0x6e, 0xbc, 0xe7, 0x0c, 0x56, 0xde, 0xac, 0xbe, 0xae, + 0xdb, 0x75, 0x32, 0x90, 0x9e, 0x63, 0xbd, 0x74, 0xbf, 0xe0, 0x0a, 0xca, + 0xf8, 0x34, 0x96, 0x67, 0x84, 0xcd, 0xd1, 0x42, 0x38, 0x78, 0xc7, 0x99, + 0xb6, 0x0c, 0xce, 0xb6, 0x0f, 0xe9, 0x1b, 0xcb, 0xf4, 0x59, 0xbe, 0x11, + 0x0e, 0xcb, 0x2c, 0x32, 0xc8, 0xfa, 0x83, 0x29, 0x64, 0x79, 0x3c, 0x8b, + 0x4b, 0xf0, 0x32, 0x74, 0x6c, 0xf3, 0x93, 0xb8, 0x96, 0x6b, 0x5d, 0x57, + 0x5a, 0x68, 0xc1, 0xcc, 0x0c, 0x79, 0x8a, 0x19, 0xde, 0xf5, 0x49, 0x02, + 0x5e, 0x08, 0x80, 0x01, 0x89, 0x0c, 0x32, 0xcd, 0xd2, 0xd6, 0x96, 0xd5, + 0x4b, 0xa0, 0xf3, 0xec, 0xbf, 0xab, 0xf4, 0x7d, 0xb3, 0xa1, 0xb9, 0x7c, + 0xda, 0x4e, 0xd7, 0xe5, 0xb7, 0xac, 0xb9, 0xf2, 0x25, 0x5f, 0x01, 0xcb, + 0x8c, 0x96, 0xa8, 0x28, 0xae, 0xc1, 0x33, 0x5a, 0xf6, 0x3f, 0x08, 0x90, + 0xdc, 0xeb, 0xff, 0x39, 0xd8, 0x26, 0xc8, 0x12, 0x9d, 0x1c, 0x9a, 0xaa, + 0xa9, 0xc0, 0x16, 0x8e, 0x86, 0xed, 0x67, 0x52, 0x96, 0x00, 0x7f, 0x0d, + 0x92, 0x3d, 0x3d, 0xd9, 0x70, 0x36, 0xe5, 0xea, 0x42, 0x6f, 0x1f, 0xae, + 0x95, 0xe5, 0x5b, 0x5d, 0xf8, 0xd0, 0x3a, 0xc7, 0xd4, 0xde, 0x77, 0x86, + 0xd0, 0xfc, 0x9e, 0x4e, 0xe2, 0xe2, 0xb8, 0xa9, 0x68, 0x37, 0x09, 0xc4, + 0x39, 0xe3, 0x85, 0xb8, 0x89, 0xf3, 0x1f, 0x6e, 0xb7, 0x6d, 0x1f, 0x4a, + 0x2f, 0x18, 0x09, 0x6f, 0xde, 0x4a, 0x01, 0x8f, 0x14, 0xc9, 0xb7, 0xa6, + 0xee, 0xa7, 0x63, 0x9f, 0x33, 0xa4, 0x54, 0x7c, 0x42, 0x83, 0x68, 0xb8, + 0xa5, 0xdf, 0xbf, 0xec, 0xb9, 0x1a, 0x5d, 0x13, 0x3b, 0xd9, 0xad, 0x68, + 0xfd, 0x20, 0x0a, 0x55, 0x91, 0x21, 0x64, 0xf9, 0xd7, 0x13, 0x01, 0xa0, + 0x08, 0x5d, 0x59, 0x89, 0x1b, 0x44, 0xaf, 0xa4, 0xac, 0xc7, 0x05, 0x10, + 0xfa, 0x41, 0x4a, 0xa8, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x7b, 0x30, 0x82, 0x01, 0x77, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x60, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x59, 0x30, + 0x57, 0x30, 0x48, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb1, 0x3e, + 0x01, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6f, 0x6d, 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, + 0x63, 0x66, 0x6d, 0x30, 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, + 0x82, 0x37, 0x2a, 0x01, 0x30, 0x42, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x01, 0x01, 0x04, 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x26, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x6f, 0x6d, + 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, + 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x72, 0x6f, 0x6f, 0x74, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x01, 0x86, 0x30, 0x27, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, + 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe5, 0x9d, + 0x59, 0x30, 0x82, 0x47, 0x58, 0xcc, 0xac, 0xfa, 0x08, 0x54, 0x36, 0x86, + 0x7b, 0x3a, 0xb5, 0x04, 0x4d, 0xf0, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33, 0x86, + 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x64, 0x70, 0x31, + 0x2e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x52, 0x4c, 0x2f, 0x4f, 0x6d, + 0x6e, 0x69, 0x72, 0x6f, 0x6f, 0x74, 0x32, 0x30, 0x32, 0x35, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x51, 0xaf, 0x24, 0x26, 0x9c, 0xf4, 0x68, 0x22, 0x57, 0x80, 0x26, + 0x2b, 0x3b, 0x46, 0x62, 0x15, 0x7b, 0x1e, 0xcc, 0xa5, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0x69, 0x62, 0xf6, 0x84, 0x91, 0x00, 0xc4, + 0x6f, 0x82, 0x7b, 0x24, 0xe1, 0x42, 0xa2, 0xa5, 0x8b, 0x82, 0x5c, 0xa7, + 0xc5, 0x44, 0xcb, 0xe7, 0x52, 0x76, 0x63, 0xd3, 0x76, 0x9e, 0x78, 0xe2, + 0x69, 0x35, 0xb1, 0x38, 0xba, 0xb0, 0x96, 0xc6, 0x1f, 0xac, 0x7b, 0xc6, + 0xb2, 0x65, 0x77, 0x8b, 0x7d, 0x8d, 0xae, 0x64, 0xb9, 0xa5, 0x8c, 0x17, + 0xca, 0x58, 0x65, 0xc3, 0xad, 0x82, 0xf5, 0xc5, 0xa2, 0xf5, 0x01, 0x13, + 0x93, 0xc6, 0x7e, 0x44, 0xe5, 0xc4, 0x61, 0xfa, 0x03, 0xb6, 0x56, 0xc1, + 0x72, 0xe1, 0xc8, 0x28, 0xc5, 0x69, 0x21, 0x8f, 0xac, 0x6e, 0xfd, 0x7f, + 0x43, 0x83, 0x36, 0xb8, 0xc0, 0xd6, 0xa0, 0x28, 0xfe, 0x1a, 0x45, 0xbe, + 0xfd, 0x93, 0x8c, 0x8d, 0xa4, 0x64, 0x79, 0x1f, 0x14, 0xdb, 0xa1, 0x9f, + 0x21, 0xdc, 0xc0, 0x4e, 0x7b, 0x17, 0x22, 0x17, 0xb1, 0xb6, 0x3c, 0xd3, + 0x9b, 0xe2, 0x0a, 0xa3, 0x7e, 0x99, 0xb0, 0xc1, 0xac, 0xd8, 0xf4, 0x86, + 0xdf, 0x3c, 0xda, 0x7d, 0x14, 0x9c, 0x40, 0xc1, 0x7c, 0xd2, 0x18, 0x6f, + 0xf1, 0x4f, 0x26, 0x45, 0x09, 0x95, 0x94, 0x5c, 0xda, 0xd0, 0x98, 0xf8, + 0xf4, 0x4c, 0x82, 0x96, 0x10, 0xde, 0xac, 0x30, 0xcb, 0x2b, 0xae, 0xf9, + 0x92, 0xea, 0xbf, 0x79, 0x03, 0xfc, 0x1e, 0x3f, 0xac, 0x09, 0xa4, 0x3f, + 0x65, 0xfd, 0x91, 0x4f, 0x96, 0x24, 0xa7, 0xce, 0xb4, 0x4e, 0x6a, 0x96, + 0x29, 0x17, 0xae, 0xc0, 0xa8, 0xdf, 0x17, 0x22, 0xf4, 0x17, 0xe3, 0xdc, + 0x1c, 0x39, 0x06, 0x56, 0x10, 0xea, 0xea, 0xb5, 0x74, 0x17, 0x3c, 0x4e, + 0xdd, 0x7e, 0x91, 0x0a, 0xa8, 0x0b, 0x78, 0x07, 0xa7, 0x31, 0x44, 0x08, + 0x31, 0xab, 0x18, 0x84, 0x0f, 0x12, 0x9c, 0xe7, 0xde, 0x84, 0x2c, 0xe9, + 0x6d, 0x93, 0x45, 0xbf, 0xa8, 0xc1, 0x3f, 0x34, 0xdc, +} + +var certSet3Cert50 = []byte{ + 0x30, 0x82, 0x05, 0xe5, 0x30, 0x82, 0x03, 0xcd, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x13, 0x8b, 0xfe, 0xf3, 0x32, 0x94, 0xf9, 0xd8, 0x16, + 0xf9, 0x45, 0xc2, 0x71, 0x95, 0x29, 0x98, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7d, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, + 0x4c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, + 0x2e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x22, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, 0x67, 0x69, 0x74, + 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, 0x29, + 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x31, + 0x32, 0x31, 0x36, 0x30, 0x31, 0x30, 0x30, 0x30, 0x35, 0x5a, 0x17, 0x0d, + 0x33, 0x30, 0x31, 0x32, 0x31, 0x36, 0x30, 0x31, 0x30, 0x30, 0x30, 0x35, + 0x5a, 0x30, 0x78, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, + 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x20, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, + 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1d, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, + 0x20, 0x33, 0x20, 0x4f, 0x56, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xaf, 0x67, 0x1c, 0x6f, 0xe5, 0x45, 0xe0, 0xd7, 0x46, 0x4b, 0x75, 0x2c, + 0xb6, 0x80, 0xf2, 0x9a, 0x17, 0x4d, 0x2d, 0xff, 0xde, 0xae, 0xd2, 0xd4, + 0x00, 0x8a, 0x3a, 0xb8, 0x31, 0xfe, 0x8e, 0x37, 0x9e, 0xfa, 0xaa, 0xd5, + 0xa3, 0x5b, 0x16, 0x12, 0xc1, 0x19, 0x3e, 0x34, 0x85, 0x96, 0xc3, 0xbe, + 0xd3, 0xb3, 0x43, 0xf4, 0x8d, 0x6f, 0x16, 0xbd, 0x30, 0xba, 0x07, 0xfc, + 0xd8, 0x9a, 0xc1, 0x79, 0x89, 0x80, 0x6d, 0xa0, 0x8c, 0xbe, 0xdd, 0x37, + 0xf7, 0xeb, 0x05, 0xd3, 0x53, 0x7f, 0x57, 0x58, 0x76, 0x55, 0xb6, 0xa8, + 0xa8, 0x86, 0x44, 0xb8, 0xbb, 0xd0, 0x13, 0xda, 0xfd, 0x8f, 0xe1, 0xf2, + 0xcd, 0xa0, 0x15, 0x38, 0x55, 0x56, 0xce, 0x26, 0xcf, 0x7c, 0x93, 0x75, + 0x29, 0x7a, 0x0a, 0xab, 0xfb, 0xba, 0x09, 0x38, 0x20, 0x11, 0x57, 0x07, + 0x5d, 0x7f, 0x49, 0x9f, 0x2a, 0x4a, 0x67, 0x1e, 0x9e, 0x58, 0xe9, 0xc7, + 0x7f, 0xf9, 0xc3, 0xed, 0xfe, 0x5f, 0x4d, 0xaf, 0xb8, 0x4f, 0x9d, 0xdf, + 0x69, 0x2d, 0x69, 0x1b, 0x3a, 0x58, 0x81, 0x69, 0x63, 0x30, 0xea, 0x87, + 0x8d, 0x0f, 0x52, 0x9d, 0x5a, 0xda, 0x39, 0x44, 0xba, 0x9f, 0x89, 0x9f, + 0x36, 0xb6, 0xc2, 0x19, 0x5c, 0xd9, 0x26, 0x78, 0xd9, 0xae, 0x5e, 0xfc, + 0x95, 0x90, 0xbf, 0xe8, 0x11, 0xc0, 0x47, 0x0f, 0x77, 0x89, 0xdd, 0x6a, + 0x28, 0x4f, 0x0a, 0xbc, 0x32, 0x64, 0x57, 0x43, 0x3d, 0x08, 0x65, 0x93, + 0xe5, 0x45, 0xae, 0xdd, 0x28, 0x0c, 0x27, 0x2c, 0x8e, 0xa6, 0x2b, 0x09, + 0x03, 0x5d, 0xa1, 0x78, 0xd2, 0x8c, 0xab, 0xb6, 0x6b, 0xb9, 0x46, 0xc9, + 0x19, 0x00, 0x39, 0xb9, 0xbf, 0xc6, 0x13, 0x2b, 0x73, 0x72, 0x1f, 0xf2, + 0x3e, 0x37, 0xb8, 0xe8, 0xb9, 0x14, 0x65, 0x88, 0x4d, 0xe2, 0xf1, 0x1b, + 0xd8, 0xa5, 0x1d, 0x3b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x64, 0x30, 0x82, 0x01, 0x60, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, + 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2b, 0x30, 0x29, 0x30, + 0x27, 0xa0, 0x25, 0xa0, 0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, + 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x73, 0x63, 0x61, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x66, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x01, 0x01, 0x04, 0x5a, 0x30, 0x58, 0x30, 0x24, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x30, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x24, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x61, 0x69, 0x61, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x74, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, + 0x3f, 0x1c, 0x92, 0x7b, 0x92, 0xb0, 0x5a, 0x25, 0xb3, 0x38, 0xfb, 0x9c, + 0x07, 0xa4, 0x26, 0x50, 0x32, 0xe3, 0x51, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x4e, 0x0b, 0xef, 0x1a, + 0xa4, 0x40, 0x5b, 0xa5, 0x17, 0x69, 0x87, 0x30, 0xca, 0x34, 0x68, 0x43, + 0xd0, 0x41, 0xae, 0xf2, 0x30, 0x3f, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, + 0x38, 0x30, 0x36, 0x30, 0x34, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, + 0x2c, 0x30, 0x2a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + 0x01, 0x16, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x02, 0x01, 0x00, 0x85, 0xf2, 0xe8, 0x14, 0xd3, 0x1b, 0xc1, + 0xa1, 0x16, 0x1d, 0xa4, 0xf4, 0x4d, 0xba, 0x51, 0x8b, 0x5c, 0x52, 0xb1, + 0x54, 0x54, 0x12, 0x16, 0x17, 0x9c, 0x96, 0x78, 0x6f, 0xd3, 0xbf, 0xdf, + 0x43, 0x36, 0xf5, 0x12, 0x89, 0x61, 0x72, 0x44, 0xdf, 0x1c, 0x9b, 0x09, + 0x4f, 0x60, 0x26, 0x68, 0xc1, 0xe6, 0x66, 0x50, 0x70, 0xb3, 0x6a, 0xf1, + 0xa8, 0x6a, 0x0c, 0x1e, 0x2e, 0x93, 0xf1, 0xee, 0x07, 0x3e, 0x09, 0xdd, + 0x30, 0x45, 0xb2, 0x56, 0x8e, 0xdc, 0x2c, 0x5c, 0xab, 0x49, 0xfa, 0xb9, + 0x04, 0x03, 0x40, 0x15, 0x7a, 0xb5, 0x30, 0xe0, 0x1d, 0x91, 0x8f, 0xa6, + 0xd6, 0x6f, 0x1f, 0x99, 0xa0, 0x84, 0x95, 0x39, 0xbd, 0xac, 0x77, 0x7f, + 0x72, 0x4b, 0xdd, 0x2d, 0xae, 0xff, 0xa8, 0x58, 0x1d, 0x46, 0x27, 0xd4, + 0x83, 0xc7, 0x69, 0x64, 0x9f, 0x19, 0xbb, 0x10, 0xf8, 0x04, 0x42, 0x87, + 0x59, 0x5d, 0x02, 0xb1, 0xd6, 0xe5, 0xc8, 0xda, 0x43, 0x30, 0xa3, 0xe8, + 0x37, 0xa5, 0xd2, 0x48, 0x0b, 0xa2, 0x83, 0x4e, 0x9d, 0x4f, 0x83, 0x58, + 0x9d, 0xd7, 0x47, 0x22, 0xb1, 0x89, 0xf0, 0x89, 0x3b, 0x3d, 0x28, 0x43, + 0x2c, 0x9b, 0x17, 0x7c, 0x03, 0xee, 0x9d, 0x26, 0x25, 0xe0, 0x04, 0xb8, + 0x1d, 0x04, 0x57, 0x42, 0x47, 0xda, 0x58, 0x69, 0xf0, 0xd3, 0x29, 0xab, + 0x12, 0x02, 0x99, 0x2b, 0x2a, 0xd8, 0x9d, 0xa0, 0x1f, 0x54, 0x5e, 0x23, + 0x9a, 0x0c, 0xd2, 0x99, 0x58, 0xc4, 0xa1, 0xe5, 0x49, 0xc2, 0x25, 0xa7, + 0x64, 0x20, 0x52, 0x2e, 0xe7, 0x89, 0xf5, 0x19, 0xc0, 0x8b, 0xd0, 0x63, + 0xb1, 0x78, 0x1e, 0xbe, 0x01, 0x47, 0xbe, 0x76, 0x81, 0x46, 0xf1, 0x99, + 0x1f, 0x94, 0x9a, 0xbe, 0xfa, 0x82, 0x15, 0xb5, 0x84, 0x84, 0x79, 0x75, + 0x93, 0xba, 0x9f, 0xb5, 0xe4, 0x9b, 0xc2, 0xcb, 0x69, 0x5c, 0xbd, 0x1f, + 0x55, 0x0a, 0xa7, 0x26, 0x30, 0x05, 0x51, 0xbe, 0x65, 0xee, 0x57, 0xa9, + 0x6a, 0xdf, 0xbd, 0xf9, 0x36, 0x2f, 0xad, 0x1e, 0x46, 0x41, 0x2b, 0xb1, + 0x88, 0xd0, 0x88, 0x25, 0x85, 0x40, 0x17, 0x79, 0xbf, 0x3d, 0x8d, 0xe2, + 0xf4, 0x2d, 0xea, 0x30, 0x31, 0xdf, 0xa1, 0x40, 0xcb, 0x35, 0xff, 0x82, + 0x9f, 0xf5, 0x99, 0x3c, 0x4a, 0xfd, 0x9d, 0xa1, 0xd1, 0x55, 0xcc, 0x20, + 0xa8, 0x1c, 0xd8, 0x20, 0x05, 0xab, 0xb3, 0x14, 0x65, 0x95, 0x53, 0xd8, + 0xe8, 0x8e, 0x57, 0xc5, 0x77, 0x6b, 0x2d, 0x4d, 0x88, 0xe9, 0x5d, 0x62, + 0xd5, 0xa2, 0xf8, 0x70, 0xe1, 0x70, 0xeb, 0x45, 0x23, 0x0e, 0xf0, 0x00, + 0x46, 0xc2, 0x48, 0x31, 0xe8, 0xe7, 0x36, 0x80, 0x36, 0x2d, 0x22, 0xf2, + 0x01, 0x27, 0x53, 0xeb, 0xce, 0xa7, 0x69, 0x49, 0x82, 0xbf, 0xe7, 0x0f, + 0x9c, 0xf3, 0x20, 0x2e, 0xf5, 0xfa, 0x5d, 0xce, 0xea, 0x58, 0x3a, 0x8f, + 0xd8, 0xaa, 0x7d, 0x30, 0xb7, 0x74, 0x96, 0x7c, 0x3d, 0x6e, 0xb4, 0xec, + 0x4a, 0x3b, 0x59, 0xb6, 0xa9, 0x50, 0x0d, 0x0f, 0x05, 0x06, 0x70, 0x26, + 0xb9, 0x95, 0x91, 0xd1, 0x5e, 0x24, 0x8c, 0x8f, 0xca, 0x74, 0x57, 0x97, + 0x90, 0x8b, 0x5a, 0xb7, 0xfe, 0x8d, 0xad, 0xd8, 0xe8, 0xc2, 0x06, 0xbc, + 0x08, 0x56, 0x21, 0x02, 0x12, 0x53, 0xc6, 0x9f, 0x86, 0x04, 0x58, 0xca, + 0x2d, 0xf8, 0x03, 0x0d, 0x57, 0x0b, 0x1c, 0x37, 0xbd, 0xf0, 0x5a, 0x35, + 0xf2, 0xfe, 0x3b, 0xd6, 0xa4, 0x37, 0x15, 0xe9, 0xf8, 0x08, 0x92, 0x96, + 0x3d, 0x74, 0xc8, 0xb5, 0x5c, 0x6e, 0x65, 0x08, 0xe7, 0xdf, 0x69, 0x73, + 0x9c, 0xec, 0xe3, 0x30, 0x5a, 0xa6, 0xdf, 0x5c, 0xbe, 0xda, 0x7f, 0x00, + 0xee, 0xa5, 0xda, 0x2b, 0x5c, 0x1e, 0x2a, 0x6a, 0xc0, 0xa3, 0xae, 0x1e, + 0xf1, +} + +var certSet3Cert51 = []byte{ + 0x30, 0x82, 0x06, 0x5c, 0x30, 0x82, 0x04, 0x44, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x07, 0x19, 0xc2, 0x85, 0x30, 0xe9, 0x3b, 0x36, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, + 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, + 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, + 0x67, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, + 0x30, 0x36, 0x30, 0x39, 0x31, 0x37, 0x32, 0x32, 0x34, 0x36, 0x33, 0x36, + 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, + 0x39, 0x35, 0x39, 0x5a, 0x30, 0x55, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x1a, 0x30, 0x18, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, + 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x21, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x66, + 0x20, 0x57, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x82, 0x02, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, + 0x82, 0x02, 0x01, 0x00, 0xbd, 0xca, 0x8d, 0xac, 0xb8, 0x91, 0x15, 0x56, + 0x97, 0x7b, 0x6b, 0x5c, 0x7a, 0xc2, 0xde, 0x6b, 0xd9, 0xa1, 0xb0, 0xc3, + 0x10, 0x23, 0xfa, 0xa7, 0xa1, 0xb2, 0xcc, 0x31, 0xfa, 0x3e, 0xd9, 0xa6, + 0x29, 0x6f, 0x16, 0x3d, 0xe0, 0x6b, 0xf8, 0xb8, 0x40, 0x5f, 0xdb, 0x39, + 0xa8, 0x00, 0x7a, 0x8b, 0xa0, 0x4d, 0x54, 0x7d, 0xc2, 0x22, 0x78, 0xfc, + 0x8e, 0x09, 0xb8, 0xa8, 0x85, 0xd7, 0xcc, 0x95, 0x97, 0x4b, 0x74, 0xd8, + 0x9e, 0x7e, 0xf0, 0x00, 0xe4, 0x0e, 0x89, 0xae, 0x49, 0x28, 0x44, 0x1a, + 0x10, 0x99, 0x32, 0x0f, 0x25, 0x88, 0x53, 0xa4, 0x0d, 0xb3, 0x0f, 0x12, + 0x08, 0x16, 0x0b, 0x03, 0x71, 0x27, 0x1c, 0x7f, 0xe1, 0xdb, 0xd2, 0xfd, + 0x67, 0x68, 0xc4, 0x05, 0x5d, 0x0a, 0x0e, 0x5d, 0x70, 0xd7, 0xd8, 0x97, + 0xa0, 0xbc, 0x53, 0x41, 0x9a, 0x91, 0x8d, 0xf4, 0x9e, 0x36, 0x66, 0x7a, + 0x7e, 0x56, 0xc1, 0x90, 0x5f, 0xe6, 0xb1, 0x68, 0x20, 0x36, 0xa4, 0x8c, + 0x24, 0x2c, 0x2c, 0x47, 0x0b, 0x59, 0x76, 0x66, 0x30, 0xb5, 0xbe, 0xde, + 0xed, 0x8f, 0xf8, 0x9d, 0xd3, 0xbb, 0x01, 0x30, 0xe6, 0xf2, 0xf3, 0x0e, + 0xe0, 0x2c, 0x92, 0x80, 0xf3, 0x85, 0xf9, 0x28, 0x8a, 0xb4, 0x54, 0x2e, + 0x9a, 0xed, 0xf7, 0x76, 0xfc, 0x15, 0x68, 0x16, 0xeb, 0x4a, 0x6c, 0xeb, + 0x2e, 0x12, 0x8f, 0xd4, 0xcf, 0xfe, 0x0c, 0xc7, 0x5c, 0x1d, 0x0b, 0x7e, + 0x05, 0x32, 0xbe, 0x5e, 0xb0, 0x09, 0x2a, 0x42, 0xd5, 0xc9, 0x4e, 0x90, + 0xb3, 0x59, 0x0d, 0xbb, 0x7a, 0x7e, 0xcd, 0xd5, 0x08, 0x5a, 0xb4, 0x7f, + 0xd8, 0x1c, 0x69, 0x11, 0xf9, 0x27, 0x0f, 0x7b, 0x06, 0xaf, 0x54, 0x83, + 0x18, 0x7b, 0xe1, 0xdd, 0x54, 0x7a, 0x51, 0x68, 0x6e, 0x77, 0xfc, 0xc6, + 0xbf, 0x52, 0x4a, 0x66, 0x46, 0xa1, 0xb2, 0x67, 0x1a, 0xbb, 0xa3, 0x4f, + 0x77, 0xa0, 0xbe, 0x5d, 0xff, 0xfc, 0x56, 0x0b, 0x43, 0x72, 0x77, 0x90, + 0xca, 0x9e, 0xf9, 0xf2, 0x39, 0xf5, 0x0d, 0xa9, 0xf4, 0xea, 0xd7, 0xe7, + 0xb3, 0x10, 0x2f, 0x30, 0x42, 0x37, 0x21, 0xcc, 0x30, 0x70, 0xc9, 0x86, + 0x98, 0x0f, 0xcc, 0x58, 0x4d, 0x83, 0xbb, 0x7d, 0xe5, 0x1a, 0xa5, 0x37, + 0x8d, 0xb6, 0xac, 0x32, 0x97, 0x00, 0x3a, 0x63, 0x71, 0x24, 0x1e, 0x9e, + 0x37, 0xc4, 0xff, 0x74, 0xd4, 0x37, 0xc0, 0xe2, 0xfe, 0x88, 0x46, 0x60, + 0x11, 0xdd, 0x08, 0x3f, 0x50, 0x36, 0xab, 0xb8, 0x7a, 0xa4, 0x95, 0x62, + 0x6a, 0x6e, 0xb0, 0xca, 0x6a, 0x21, 0x5a, 0x69, 0xf3, 0xf3, 0xfb, 0x1d, + 0x70, 0x39, 0x95, 0xf3, 0xa7, 0x6e, 0xa6, 0x81, 0x89, 0xa1, 0x88, 0xc5, + 0x3b, 0x71, 0xca, 0xa3, 0x52, 0xee, 0x83, 0xbb, 0xfd, 0xa0, 0x77, 0xf4, + 0xe4, 0x6f, 0xe7, 0x42, 0xdb, 0x6d, 0x4a, 0x99, 0x8a, 0x34, 0x48, 0xbc, + 0x17, 0xdc, 0xe4, 0x80, 0x08, 0x22, 0xb6, 0xf2, 0x31, 0xc0, 0x3f, 0x04, + 0x3e, 0xeb, 0x9f, 0x20, 0x79, 0xd6, 0xb8, 0x06, 0x64, 0x64, 0x02, 0x31, + 0xd7, 0xa9, 0xcd, 0x52, 0xfb, 0x84, 0x45, 0x69, 0x09, 0x00, 0x2a, 0xdc, + 0x55, 0x8b, 0xc4, 0x06, 0x46, 0x4b, 0xc0, 0x4a, 0x1d, 0x09, 0x5b, 0x39, + 0x28, 0xfd, 0xa9, 0xab, 0xce, 0x00, 0xf9, 0x2e, 0x48, 0x4b, 0x26, 0xe6, + 0x30, 0x4c, 0xa5, 0x58, 0xca, 0xb4, 0x44, 0x82, 0x4f, 0xe7, 0x91, 0x1e, + 0x33, 0xc3, 0xb0, 0x93, 0xff, 0x11, 0xfc, 0x81, 0xd2, 0xca, 0x1f, 0x71, + 0x29, 0xdd, 0x76, 0x4f, 0x92, 0x25, 0xaf, 0x1d, 0x81, 0xb7, 0x0f, 0x2f, + 0x8c, 0xc3, 0x06, 0xcc, 0x2f, 0x27, 0xa3, 0x4a, 0xe4, 0x0e, 0x99, 0xba, + 0x7c, 0x1e, 0x45, 0x1f, 0x7f, 0xaa, 0x19, 0x45, 0x96, 0xfd, 0xfc, 0x3d, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x07, 0x30, 0x82, 0x01, + 0x03, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x02, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xe1, 0x66, 0xcf, 0x0e, 0xd1, 0xf1, 0xb3, 0x4b, 0xb7, 0x06, 0x20, 0x14, + 0xfe, 0x87, 0x12, 0xd5, 0xf6, 0xfe, 0xfb, 0x3e, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x4e, 0x0b, 0xef, + 0x1a, 0xa4, 0x40, 0x5b, 0xa5, 0x17, 0x69, 0x87, 0x30, 0xca, 0x34, 0x68, + 0x43, 0xd0, 0x41, 0xae, 0xf2, 0x30, 0x69, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5d, 0x30, 0x5b, 0x30, 0x27, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x61, 0x30, 0x30, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x61, + 0x69, 0x61, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x63, 0x61, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, + 0x2b, 0x30, 0x29, 0x30, 0x27, 0xa0, 0x25, 0xa0, 0x23, 0x86, 0x21, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, + 0x66, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x02, 0x01, 0x00, 0xb6, 0x6d, 0xf8, 0x70, 0xfb, 0xe2, 0x0d, 0x4c, + 0x98, 0xb3, 0x07, 0x49, 0x15, 0xf5, 0x04, 0xc4, 0x6c, 0xca, 0xca, 0xf5, + 0x68, 0xa0, 0x08, 0xfe, 0x12, 0x6d, 0x9c, 0x04, 0x06, 0xc9, 0xad, 0x9a, + 0x91, 0x52, 0x3e, 0x78, 0xc4, 0x5c, 0xee, 0x9f, 0x54, 0x1d, 0xee, 0xe3, + 0xf1, 0x5e, 0x30, 0xc9, 0x49, 0xe1, 0x39, 0xe0, 0xa6, 0x9d, 0x36, 0x6c, + 0x57, 0xfa, 0xe6, 0x34, 0x4f, 0x55, 0xe8, 0x87, 0xa8, 0x2c, 0xdd, 0x05, + 0xf1, 0x58, 0x12, 0x91, 0xe8, 0xca, 0xce, 0x28, 0x78, 0x8f, 0xdf, 0x07, + 0x85, 0x01, 0xa5, 0xdc, 0x45, 0x96, 0x05, 0xd4, 0x80, 0xb2, 0x2b, 0x05, + 0x9a, 0xcb, 0x9a, 0xa5, 0x8b, 0xe0, 0x3a, 0x67, 0xe6, 0x73, 0x47, 0xbe, + 0x4a, 0xfd, 0x27, 0xb1, 0x88, 0xef, 0xe6, 0xca, 0xcf, 0x8d, 0x0e, 0x26, + 0x9f, 0xfa, 0x5f, 0x57, 0x78, 0xad, 0x6d, 0xfe, 0xae, 0x9b, 0x35, 0x08, + 0xb1, 0xc3, 0xba, 0xc1, 0x00, 0x4a, 0x4b, 0x7d, 0x14, 0xbd, 0xf7, 0xf1, + 0xd3, 0x55, 0x18, 0xac, 0xd0, 0x33, 0x70, 0x88, 0x6d, 0xc4, 0x09, 0x71, + 0x14, 0xa6, 0x2b, 0x4f, 0x88, 0x81, 0xe7, 0x0b, 0x00, 0x37, 0xa9, 0x15, + 0x7d, 0x7e, 0xd7, 0x01, 0x96, 0x3f, 0x2f, 0xaf, 0x7b, 0x62, 0xae, 0x0a, + 0x4a, 0xbf, 0x4b, 0x39, 0x2e, 0x35, 0x10, 0x8b, 0xfe, 0x04, 0x39, 0xe4, + 0x3c, 0x3a, 0x0c, 0x09, 0x56, 0x40, 0x3a, 0xb5, 0xf4, 0xc2, 0x68, 0x0c, + 0xb5, 0xf9, 0x52, 0xcd, 0xee, 0x9d, 0xf8, 0x98, 0xfc, 0x78, 0xe7, 0x58, + 0x47, 0x8f, 0x1c, 0x73, 0x58, 0x69, 0x33, 0xab, 0xff, 0xdd, 0xdf, 0x8e, + 0x24, 0x01, 0x77, 0x98, 0x19, 0x3a, 0xb0, 0x66, 0x79, 0xbc, 0xe1, 0x08, + 0xa3, 0x0e, 0x4f, 0xc1, 0x04, 0xb3, 0xf3, 0x01, 0xc8, 0xeb, 0xd3, 0x59, + 0x1c, 0x35, 0xd2, 0x93, 0x1e, 0x70, 0x65, 0x82, 0x7f, 0xdb, 0xcf, 0xfb, + 0xc8, 0x99, 0x12, 0x60, 0xc3, 0x44, 0x6f, 0x3a, 0x80, 0x4b, 0xd7, 0xbe, + 0x21, 0xaa, 0x14, 0x7a, 0x64, 0xcb, 0xdd, 0x37, 0x43, 0x45, 0x5b, 0x32, + 0x2e, 0x45, 0xf0, 0xd9, 0x59, 0x1f, 0x6b, 0x18, 0xf0, 0x7c, 0xe9, 0x55, + 0x36, 0x19, 0x61, 0x5f, 0xb5, 0x7d, 0xf1, 0x8d, 0xbd, 0x88, 0xe4, 0x75, + 0x4b, 0x98, 0xdd, 0x27, 0xb0, 0xe4, 0x84, 0x44, 0x2a, 0x61, 0x84, 0x57, + 0x05, 0x82, 0x11, 0x1f, 0xaa, 0x35, 0x58, 0xf3, 0x20, 0x0e, 0xaf, 0x59, + 0xef, 0xfa, 0x55, 0x72, 0x72, 0x0d, 0x26, 0xd0, 0x9b, 0x53, 0x49, 0xac, + 0xce, 0x37, 0x2e, 0x65, 0x61, 0xff, 0xf6, 0xec, 0x1b, 0xea, 0xf6, 0xf1, + 0xa6, 0xd3, 0xd1, 0xb5, 0x7b, 0xbe, 0x35, 0xf4, 0x22, 0xc1, 0xbc, 0x8d, + 0x01, 0xbd, 0x68, 0x5e, 0x83, 0x0d, 0x2f, 0xec, 0xd6, 0xda, 0x63, 0x0c, + 0x27, 0xd1, 0x54, 0x3e, 0xe4, 0xa8, 0xd3, 0xce, 0x4b, 0x32, 0xb8, 0x91, + 0x94, 0xff, 0xfb, 0x5b, 0x49, 0x2d, 0x75, 0x18, 0xa8, 0xba, 0x71, 0x9a, + 0x3b, 0xae, 0xd9, 0xc0, 0xa9, 0x4f, 0x87, 0x91, 0xed, 0x8b, 0x7b, 0x6b, + 0x20, 0x98, 0x89, 0x39, 0x83, 0x4f, 0x80, 0xc4, 0x69, 0xcc, 0x17, 0xc9, + 0xc8, 0x4e, 0xbe, 0xe4, 0xa9, 0xa5, 0x81, 0x76, 0x70, 0x06, 0x04, 0x32, + 0xcd, 0x83, 0x65, 0xf4, 0xbc, 0x7d, 0x3e, 0x13, 0xbc, 0xd2, 0xe8, 0x6f, + 0x63, 0xaa, 0xb5, 0x3b, 0xda, 0x8d, 0x86, 0x32, 0x82, 0x78, 0x9d, 0xd9, + 0xcc, 0xff, 0xbf, 0x57, 0x64, 0x74, 0xed, 0x28, 0x3d, 0x44, 0x62, 0x15, + 0x61, 0x4b, 0xf7, 0x94, 0xb0, 0x0d, 0x2a, 0x67, 0x1c, 0xf0, 0xcb, 0x9b, + 0xa5, 0x92, 0xbf, 0xf8, 0x41, 0x5a, 0xc1, 0x3d, 0x60, 0xed, 0x9f, 0xbb, + 0xb8, 0x6d, 0x9b, 0xce, 0xa9, 0x6a, 0x16, 0x3f, 0x7e, 0xea, 0x06, 0xf1, +} diff --git a/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/createCertSets.rb b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/createCertSets.rb new file mode 100755 index 00000000..6d28e83c --- /dev/null +++ b/vendor/lucas-clemente/quic-go/vendor/github.com/lucas-clemente/quic-go-certificates/createCertSets.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +# +# Extract the common certificate sets from the chromium source to go +# +# Usage: +# createCertSets.rb 1 ~/src/chromium/src/net/quic/crypto/common_cert_set_1* +# createCertSets.rb 2 ~/src/chromium/src/net/quic/crypto/common_cert_set_2* + +n = ARGV.shift +mainFile = ARGV.shift +dataFiles = ARGV + +data = "package certsets\n" +data += File.read(mainFile) +data += (dataFiles.map{|p| File.read(p)}).join + +# Good enough +data.gsub!(/\/\*(.*?)\*\//m, '') +data.gsub!(/^#include.+/, '') +data.gsub!(/^#if 0(.*?)\n#endif/m, '') + +data.gsub!(/^static const size_t kNumCerts.+/, '') +data.gsub!(/static const size_t kLens[^}]+};/m, '') + +data.gsub!('static const unsigned char* const kCerts[] = {', "var CertSet#{n} = [][]byte{") +data.gsub!('static const uint64_t kHash = UINT64_C', "const CertSet#{n}Hash uint64 = ") + +data.gsub!(/static const unsigned char kDERCert(\d+)\[\] = /, "var kDERCert\\1 = []byte") + +data.gsub!(/kDERCert(\d+)/, "certSet#{n}Cert\\1") + +File.write("cert_set_#{n}.go", data) + +system("gofmt -w -s cert_set_#{n}.go") diff --git a/vendor/lucas-clemente/quic-go/window_update_queue.go b/vendor/lucas-clemente/quic-go/window_update_queue.go new file mode 100644 index 00000000..6cd359e5 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/window_update_queue.go @@ -0,0 +1,79 @@ +package quic + +import ( + "sync" + + "github.com/lucas-clemente/quic-go/internal/flowcontrol" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +type windowUpdateQueue struct { + mutex sync.Mutex + + queue map[protocol.StreamID]bool // used as a set + queuedConn bool // connection-level window update + + cryptoStream cryptoStream + streamGetter streamGetter + connFlowController flowcontrol.ConnectionFlowController + callback func(wire.Frame) +} + +func newWindowUpdateQueue( + streamGetter streamGetter, + cryptoStream cryptoStream, + connFC flowcontrol.ConnectionFlowController, + cb func(wire.Frame), +) *windowUpdateQueue { + return &windowUpdateQueue{ + queue: make(map[protocol.StreamID]bool), + streamGetter: streamGetter, + cryptoStream: cryptoStream, + connFlowController: connFC, + callback: cb, + } +} + +func (q *windowUpdateQueue) AddStream(id protocol.StreamID) { + q.mutex.Lock() + q.queue[id] = true + q.mutex.Unlock() +} + +func (q *windowUpdateQueue) AddConnection() { + q.mutex.Lock() + q.queuedConn = true + q.mutex.Unlock() +} + +func (q *windowUpdateQueue) QueueAll() { + q.mutex.Lock() + // queue a connection-level window update + if q.queuedConn { + q.callback(&wire.MaxDataFrame{ByteOffset: q.connFlowController.GetWindowUpdate()}) + q.queuedConn = false + } + // queue all stream-level window updates + var offset protocol.ByteCount + for id := range q.queue { + if id == q.cryptoStream.StreamID() { + offset = q.cryptoStream.getWindowUpdate() + } else { + str, err := q.streamGetter.GetOrOpenReceiveStream(id) + if err != nil || str == nil { // the stream can be nil if it was completed before dequeing the window update + continue + } + offset = str.getWindowUpdate() + } + if offset == 0 { // can happen if we received a final offset, right after queueing the window update + continue + } + q.callback(&wire.MaxStreamDataFrame{ + StreamID: id, + ByteOffset: offset, + }) + delete(q.queue, id) + } + q.mutex.Unlock() +} diff --git a/vendor/lucas-clemente/quic-go/window_update_queue_test.go b/vendor/lucas-clemente/quic-go/window_update_queue_test.go new file mode 100644 index 00000000..317b0350 --- /dev/null +++ b/vendor/lucas-clemente/quic-go/window_update_queue_test.go @@ -0,0 +1,102 @@ +package quic + +import ( + "github.com/lucas-clemente/quic-go/internal/mocks" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Window Update Queue", func() { + var ( + q *windowUpdateQueue + streamGetter *MockStreamGetter + connFC *mocks.MockConnectionFlowController + queuedFrames []wire.Frame + cryptoStream *MockCryptoStream + ) + + BeforeEach(func() { + streamGetter = NewMockStreamGetter(mockCtrl) + cryptoStream = NewMockCryptoStream(mockCtrl) + connFC = mocks.NewMockConnectionFlowController(mockCtrl) + cryptoStream.EXPECT().StreamID().Return(protocol.StreamID(0)).AnyTimes() + queuedFrames = queuedFrames[:0] + q = newWindowUpdateQueue(streamGetter, cryptoStream, connFC, func(f wire.Frame) { + queuedFrames = append(queuedFrames, f) + }) + }) + + It("adds stream offsets and gets MAX_STREAM_DATA frames", func() { + stream1 := NewMockStreamI(mockCtrl) + stream1.EXPECT().getWindowUpdate().Return(protocol.ByteCount(10)) + stream3 := NewMockStreamI(mockCtrl) + stream3.EXPECT().getWindowUpdate().Return(protocol.ByteCount(30)) + streamGetter.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(3)).Return(stream3, nil) + streamGetter.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(1)).Return(stream1, nil) + q.AddStream(3) + q.AddStream(1) + q.QueueAll() + Expect(queuedFrames).To(ContainElement(&wire.MaxStreamDataFrame{StreamID: 1, ByteOffset: 10})) + Expect(queuedFrames).To(ContainElement(&wire.MaxStreamDataFrame{StreamID: 3, ByteOffset: 30})) + }) + + It("deletes the entry after getting the MAX_STREAM_DATA frame", func() { + stream10 := NewMockStreamI(mockCtrl) + stream10.EXPECT().getWindowUpdate().Return(protocol.ByteCount(100)) + streamGetter.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(10)).Return(stream10, nil) + q.AddStream(10) + q.QueueAll() + Expect(queuedFrames).To(HaveLen(1)) + q.QueueAll() + Expect(queuedFrames).To(HaveLen(1)) + }) + + It("doesn't queue a MAX_STREAM_DATA for a closed stream", func() { + streamGetter.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(12)).Return(nil, nil) + q.AddStream(12) + q.QueueAll() + Expect(queuedFrames).To(BeEmpty()) + }) + + It("doesn't queue a MAX_STREAM_DATA if the flow controller returns an offset of 0", func() { + stream5 := NewMockStreamI(mockCtrl) + stream5.EXPECT().getWindowUpdate().Return(protocol.ByteCount(0)) + streamGetter.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(5)).Return(stream5, nil) + q.AddStream(5) + q.QueueAll() + Expect(queuedFrames).To(BeEmpty()) + }) + + It("adds MAX_STREAM_DATA frames for the crypto stream", func() { + cryptoStream.EXPECT().getWindowUpdate().Return(protocol.ByteCount(42)) + q.AddStream(0) + q.QueueAll() + Expect(queuedFrames).To(Equal([]wire.Frame{ + &wire.MaxStreamDataFrame{StreamID: 0, ByteOffset: 42}, + })) + }) + + It("queues MAX_DATA frames", func() { + connFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0x1337)) + q.AddConnection() + q.QueueAll() + Expect(queuedFrames).To(Equal([]wire.Frame{ + &wire.MaxDataFrame{ByteOffset: 0x1337}, + })) + }) + + It("deduplicates", func() { + stream10 := NewMockStreamI(mockCtrl) + stream10.EXPECT().getWindowUpdate().Return(protocol.ByteCount(200)) + streamGetter.EXPECT().GetOrOpenReceiveStream(protocol.StreamID(10)).Return(stream10, nil) + q.AddStream(10) + q.AddStream(10) + q.QueueAll() + Expect(queuedFrames).To(Equal([]wire.Frame{ + &wire.MaxStreamDataFrame{StreamID: 10, ByteOffset: 200}, + })) + }) +})